Compare commits
4 Commits
947d8931a4
...
5d672d8132
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d672d8132 | |||
| f8eb4f4e54 | |||
| 134343d2a8 | |||
| c201b43d8c |
+1
-1
@@ -2,8 +2,8 @@
|
|||||||
#include <zinnia/cmdline.h>
|
#include <zinnia/cmdline.h>
|
||||||
#include <zinnia/init.h>
|
#include <zinnia/init.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/utils.h>
|
|
||||||
#include <zinnia/string.h>
|
#include <zinnia/string.h>
|
||||||
|
#include <zinnia/utils.h>
|
||||||
#include "limine.h"
|
#include "limine.h"
|
||||||
|
|
||||||
[[__initdata_sorted("limine.0")]]
|
[[__initdata_sorted("limine.0")]]
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ bool clock_switch(struct clock* clock) {
|
|||||||
spin_unlock(&lock);
|
spin_unlock(&lock);
|
||||||
|
|
||||||
log("clock: Switching to clock source \"%s\"\n", clock->name);
|
log("clock: Switching to clock source \"%s\"\n", clock->name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include <zinnia/dpc.h>
|
||||||
|
|
||||||
|
// TODO
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
// Compiler runtime support like libgcc or compiler-rt.
|
// Compiler runtime support.
|
||||||
// Extend as required.
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,9 +2,9 @@
|
|||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/pmap.h>
|
#include <zinnia/pmap.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/string.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <zinnia/string.h>
|
|
||||||
|
|
||||||
// TODO: For now, we assume that we can do generic PTE lookups on every arch that has a MMU.
|
// TODO: For now, we assume that we can do generic PTE lookups on every arch that has a MMU.
|
||||||
static_assert(CONFIG_HAVE_MMU_GENERIC);
|
static_assert(CONFIG_HAVE_MMU_GENERIC);
|
||||||
|
|||||||
+1
-1
@@ -3,9 +3,9 @@
|
|||||||
#include <zinnia/panic.h>
|
#include <zinnia/panic.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/string.h>
|
||||||
#include <zinnia/virt.h>
|
#include <zinnia/virt.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <zinnia/string.h>
|
|
||||||
|
|
||||||
uintptr_t mem_hhdm_base = 0;
|
uintptr_t mem_hhdm_base = 0;
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -60,7 +60,7 @@ static struct vma_mapping* find_mapping(struct vma* v, size_t page) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool access_allowed(enum prot_flags prot, const struct vma_fault_info* info) {
|
static bool can_access(enum prot_flags prot, const struct vma_fault_info* info) {
|
||||||
if (info->caused_by_write)
|
if (info->caused_by_write)
|
||||||
return prot & PROT_WRITE;
|
return prot & PROT_WRITE;
|
||||||
if (info->caused_by_fetch)
|
if (info->caused_by_fetch)
|
||||||
@@ -87,7 +87,7 @@ bool vma_page_fault(struct vma* v, const struct vma_fault_info* info) {
|
|||||||
|
|
||||||
spin_lock(&v->lock);
|
spin_lock(&v->lock);
|
||||||
struct vma_mapping* mapping = find_mapping(v, faulty_page);
|
struct vma_mapping* mapping = find_mapping(v, faulty_page);
|
||||||
if (!mapping || !access_allowed(mapping->prot, info)) {
|
if (!mapping || !can_access(mapping->prot, info)) {
|
||||||
spin_unlock(&v->lock);
|
spin_unlock(&v->lock);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -107,8 +107,7 @@ bool vma_page_fault(struct vma* v, const struct vma_fault_info* info) {
|
|||||||
spin_lock(&v->lock);
|
spin_lock(&v->lock);
|
||||||
mapping = find_mapping(v, faulty_page);
|
mapping = find_mapping(v, faulty_page);
|
||||||
const bool still_valid = mapping && mapping->object == object &&
|
const bool still_valid = mapping && mapping->object == object &&
|
||||||
(faulty_page - mapping->start_page) + mapping->offset_page == object_page &&
|
(faulty_page - mapping->start_page) + mapping->offset_page == object_page && can_access(mapping->prot, info);
|
||||||
access_allowed(mapping->prot, info);
|
|
||||||
|
|
||||||
if (still_valid) {
|
if (still_valid) {
|
||||||
errno_t status =
|
errno_t status =
|
||||||
|
|||||||
+20
-1
@@ -1,9 +1,9 @@
|
|||||||
#include <zinnia/alloc.h>
|
#include <zinnia/alloc.h>
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/list.h>
|
#include <zinnia/list.h>
|
||||||
|
#include <zinnia/string.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <zinnia/vmo.h>
|
#include <zinnia/vmo.h>
|
||||||
#include <zinnia/string.h>
|
|
||||||
|
|
||||||
void vmo_ref(struct vmo* obj) {
|
void vmo_ref(struct vmo* obj) {
|
||||||
refcount_inc(&obj->rc);
|
refcount_inc(&obj->rc);
|
||||||
@@ -211,6 +211,25 @@ errno_t vmo_new_phys(struct paged_vmo** out) {
|
|||||||
return vmo_new_paged(phys_pager, out);
|
return vmo_new_paged(phys_pager, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vmo_truncate_paged(struct paged_vmo* paged, size_t length) {
|
||||||
|
const size_t page_size = arch_mem_page_size();
|
||||||
|
const size_t keep_pages = ROUND_UP(length, page_size) / page_size;
|
||||||
|
|
||||||
|
spin_lock(&paged->lock);
|
||||||
|
struct page_list** pp = &list_first(&paged->cache);
|
||||||
|
while (*pp) {
|
||||||
|
struct page_list* entry = *pp;
|
||||||
|
if (entry->offset >= keep_pages) {
|
||||||
|
*pp = list_next(entry, next);
|
||||||
|
paged->source.put_page(&paged->source, entry->offset, entry->value);
|
||||||
|
mem_free(entry);
|
||||||
|
} else {
|
||||||
|
pp = &list_next(entry, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&paged->lock);
|
||||||
|
}
|
||||||
|
|
||||||
struct phys_range_vmo {
|
struct phys_range_vmo {
|
||||||
struct vmo object;
|
struct vmo object;
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
kernel_sources += files(
|
kernel_sources += files(
|
||||||
'clock.c',
|
'clock.c',
|
||||||
'console.c',
|
'console.c',
|
||||||
'elf.c',
|
|
||||||
'irq.c',
|
'irq.c',
|
||||||
'module.c',
|
'module.c',
|
||||||
'panic.c',
|
'panic.c',
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ struct percpu* percpu_new() {
|
|||||||
const size_t size = __ld_percpu_end - __ld_percpu_start;
|
const size_t size = __ld_percpu_end - __ld_percpu_start;
|
||||||
const size_t num_pages = ALIGN_UP(size, arch_mem_page_size()) / arch_mem_page_size();
|
const size_t num_pages = ALIGN_UP(size, arch_mem_page_size()) / arch_mem_page_size();
|
||||||
|
|
||||||
|
// TODO: Map pages past the end of the kernel.
|
||||||
|
// TODO: Document how allocations work.
|
||||||
|
|
||||||
phys_t mem;
|
phys_t mem;
|
||||||
if (mem_phys_alloc(num_pages, 0, &mem))
|
if (mem_phys_alloc(num_pages, 0, &mem))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
|
void spin_init(struct spinlock* spin) {
|
||||||
|
spin->next = 0;
|
||||||
|
spin->owner = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void spin_lock(struct spinlock* spin) {
|
void spin_lock(struct spinlock* spin) {
|
||||||
uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed);
|
uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed);
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -1,12 +1,9 @@
|
|||||||
subdir('common')
|
subdir('common')
|
||||||
subdir('block')
|
subdir('block')
|
||||||
|
subdir('dt')
|
||||||
|
|
||||||
if kconfig.get('CONFIG_ACPI', 'n') == 'y'
|
if kconfig.get('CONFIG_ACPI', 'n') == 'y'
|
||||||
subdir('acpi')
|
subdir('acpi')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if kconfig.get('CONFIG_DT', 'n') == 'y'
|
|
||||||
subdir('dt')
|
|
||||||
endif
|
|
||||||
|
|
||||||
module_lds = meson.current_source_dir() / 'module.ld'
|
module_lds = meson.current_source_dir() / 'module.ld'
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
#include <zinnia/string.h>
|
#include <zinnia/string.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
|
#include <zinnia/vfs.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
#include <zinnia/vmo.h>
|
#include <zinnia/vmo.h>
|
||||||
#include <bits/elf.h>
|
#include <bits/elf.h>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
kernel_sources += files(
|
||||||
|
'elf.c',
|
||||||
|
)
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
subdir('tmpfs')
|
subdir('exec')
|
||||||
@@ -1 +0,0 @@
|
|||||||
kernel_sources += files('tmpfs.c')
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
// TODO
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include <zinnia/ident.h>
|
||||||
|
|
||||||
|
static const struct ident kernel_identity = {0};
|
||||||
|
|
||||||
|
const struct ident* ident_kernel() {
|
||||||
|
return &kernel_identity;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
kernel_sources += files(
|
||||||
|
'ident.c',
|
||||||
|
)
|
||||||
+2
-2
@@ -17,12 +17,12 @@ struct __timeval {
|
|||||||
__suseconds_t tv_usec;
|
__suseconds_t tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct itimerval {
|
struct __itimerval {
|
||||||
struct __timeval it_interval;
|
struct __timeval it_interval;
|
||||||
struct __timeval it_value;
|
struct __timeval it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct itimerspec {
|
struct __itimerspec {
|
||||||
struct __timespec it_interval;
|
struct __timespec it_interval;
|
||||||
struct __timespec it_value;
|
struct __timespec it_value;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ struct phys_mem {
|
|||||||
|
|
||||||
// Base address of the HHDM.
|
// Base address of the HHDM.
|
||||||
extern uintptr_t mem_hhdm_base;
|
extern uintptr_t mem_hhdm_base;
|
||||||
#define HHDM_PTR(paddr) (void*)(mem_hhdm_base + (paddr))
|
|
||||||
|
static inline void* HHDM_PTR(phys_t paddr) {
|
||||||
|
return (void*)(mem_hhdm_base + paddr);
|
||||||
|
}
|
||||||
|
|
||||||
// Allocates a region of memory which can be smaller than the page size.
|
// Allocates a region of memory which can be smaller than the page size.
|
||||||
// Returns `nullptr` if the allocator cannot provide an allocation for the given `length` + `flags`.
|
// Returns `nullptr` if the allocator cannot provide an allocation for the given `length` + `flags`.
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/list.h>
|
||||||
|
#include <zinnia/percpu.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
|
||||||
|
struct dpc {
|
||||||
|
void (*const callback)(struct dpc* dpc, void* data);
|
||||||
|
void* data;
|
||||||
|
atomic_bool inserted;
|
||||||
|
|
||||||
|
list_link(struct dpc*) link;
|
||||||
|
};
|
||||||
|
|
||||||
|
void dpc_dispatch();
|
||||||
|
|
||||||
|
struct dpc_percpu {};
|
||||||
|
extern struct dpc_percpu dpc_percpu_data;
|
||||||
+1
-11
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
|
#include <zinnia/vfs.h>
|
||||||
#include <bits/elf.h>
|
#include <bits/elf.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -341,15 +342,4 @@ static inline uint32_t ELF64_R_TYPE(uint64_t info) {
|
|||||||
return info & 0xFFFFFFFF;
|
return info & 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vma;
|
|
||||||
struct vmo;
|
|
||||||
struct task;
|
|
||||||
|
|
||||||
struct exec_info {
|
|
||||||
struct vma* space;
|
|
||||||
struct vmo* file_obj;
|
|
||||||
const char** argv;
|
|
||||||
const char** envp;
|
|
||||||
};
|
|
||||||
|
|
||||||
errno_t elf_load(struct exec_info* info, struct task** out);
|
errno_t elf_load(struct exec_info* info, struct task** out);
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct fdt_header {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t total_size;
|
||||||
|
uint32_t structs_offset;
|
||||||
|
uint32_t strings_offset;
|
||||||
|
uint32_t reserved_offset;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t compat_version;
|
||||||
|
uint32_t boot_cpuid;
|
||||||
|
uint32_t strings_size;
|
||||||
|
uint32_t structs_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t FDT_BEGIN_NODE = 0x00000001;
|
||||||
|
constexpr uint32_t FDT_END_NODE = 0x00000002;
|
||||||
|
constexpr uint32_t FDT_PROP = 0x00000003;
|
||||||
|
constexpr uint32_t FDT_NOP = 0x00000004;
|
||||||
|
constexpr uint32_t FDT_END = 0x00000009;
|
||||||
|
|
||||||
|
struct fdt {
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t compat_version;
|
||||||
|
uint32_t boot_cpuid;
|
||||||
|
|
||||||
|
const uint8_t* structs;
|
||||||
|
size_t structs_len;
|
||||||
|
const uint8_t* strings;
|
||||||
|
size_t strings_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_node {
|
||||||
|
struct fdt* tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_prop {
|
||||||
|
struct fdt* tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Root of the device tree.
|
||||||
|
struct fdt_node fdt_root(struct fdt* tree);
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/types.h>
|
||||||
|
#include <zinnia/vec.h>
|
||||||
|
|
||||||
struct ident {
|
struct ident {
|
||||||
// TODO
|
uid_t uid, euid, suid;
|
||||||
|
gid_t gid, egid, sgid;
|
||||||
|
|
||||||
|
vec(gid_t) groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct ident* ident_kernel(void);
|
||||||
|
|||||||
+26
-1
@@ -1,12 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/errno.h>
|
||||||
|
#include <zinnia/string.h>
|
||||||
|
#include <zinnia/usercopy.h>
|
||||||
|
#include <zinnia/utils.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <uapi/uio.h>
|
#include <uapi/uio.h>
|
||||||
|
|
||||||
struct iovec_iter {
|
struct iovec_iter {
|
||||||
struct iovec* iovecs;
|
struct __iovec* iovecs;
|
||||||
size_t iovecs_len;
|
size_t iovecs_len;
|
||||||
size_t total_len;
|
size_t total_len;
|
||||||
size_t total_offset;
|
size_t total_offset;
|
||||||
size_t current_idx;
|
size_t current_idx;
|
||||||
size_t current_offset;
|
size_t current_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline size_t iovec_iter_len(struct iovec_iter* iter) {
|
||||||
|
return iter->total_len - iter->total_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an iovec iterator over kernel memory.
|
||||||
|
static inline struct iovec_iter iovec_iter_kernel(struct __iovec* iovecs, size_t count) {
|
||||||
|
size_t total = 0;
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
total += iovecs[i].len;
|
||||||
|
|
||||||
|
return (struct iovec_iter){
|
||||||
|
.iovecs = iovecs,
|
||||||
|
.iovecs_len = count,
|
||||||
|
.total_len = total,
|
||||||
|
.total_offset = 0,
|
||||||
|
.current_idx = 0,
|
||||||
|
.current_offset = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ struct spinlock {
|
|||||||
_Atomic(uint32_t) next;
|
_Atomic(uint32_t) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void spin_init(struct spinlock* spin);
|
||||||
|
|
||||||
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
||||||
void spin_lock(struct spinlock* spin);
|
void spin_lock(struct spinlock* spin);
|
||||||
|
|
||||||
|
|||||||
+13
-3
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
#include <uapi/time.h>
|
#include <uapi/time.h>
|
||||||
|
|
||||||
struct timespec time_from_sec(uint64_t sec);
|
typedef struct __timespec timespec_t;
|
||||||
struct timespec time_from_nano(uint64_t nsec);
|
|
||||||
struct timespec time_from_milli(uint64_t msec);
|
static inline timespec_t time_from_sec(uint64_t sec) {
|
||||||
|
return (timespec_t){.tv_sec = sec, .tv_nsec = 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline timespec_t time_from_nano(uint64_t nsec) {
|
||||||
|
return (timespec_t){.tv_sec = nsec / 1'000'000'000, .tv_nsec = nsec % 1'000'000'000};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline timespec_t time_from_milli(uint64_t msec) {
|
||||||
|
return (timespec_t){.tv_sec = msec / 1'000, .tv_nsec = (msec % 1'000) * 1'000'000};
|
||||||
|
}
|
||||||
|
|||||||
+376
-31
@@ -3,13 +3,35 @@
|
|||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/ident.h>
|
#include <zinnia/ident.h>
|
||||||
#include <zinnia/iovec.h>
|
#include <zinnia/iovec.h>
|
||||||
|
#include <zinnia/mman.h>
|
||||||
|
#include <zinnia/mutex.h>
|
||||||
#include <zinnia/refcount.h>
|
#include <zinnia/refcount.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/tailq.h>
|
||||||
|
#include <zinnia/time.h>
|
||||||
#include <zinnia/types.h>
|
#include <zinnia/types.h>
|
||||||
|
#include <zinnia/vec.h>
|
||||||
|
#include <zinnia/vma.h>
|
||||||
|
#include <zinnia/vmo.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <uapi/dirent.h>
|
||||||
#include <uapi/fcntl.h>
|
#include <uapi/fcntl.h>
|
||||||
|
#include <uapi/limits.h>
|
||||||
|
#include <uapi/mount.h>
|
||||||
#include <uapi/stat.h>
|
#include <uapi/stat.h>
|
||||||
|
#include <uapi/statvfs.h>
|
||||||
|
#include <uapi/time.h>
|
||||||
|
|
||||||
|
struct vfs_mount;
|
||||||
|
struct vfs_entry;
|
||||||
|
struct vfs_path;
|
||||||
|
struct vfs_node;
|
||||||
|
struct vfs_file;
|
||||||
|
struct vfs_super_block;
|
||||||
|
struct vfs_filesystem;
|
||||||
|
struct vfs_node_ops;
|
||||||
|
struct vfs_file_ops;
|
||||||
|
|
||||||
enum open_flags : uint32_t {
|
enum open_flags : uint32_t {
|
||||||
O_RDONLY = __O_RDONLY,
|
O_RDONLY = __O_RDONLY,
|
||||||
@@ -38,24 +60,30 @@ enum open_flags : uint32_t {
|
|||||||
O_ACCMODE = __O_ACCMODE,
|
O_ACCMODE = __O_ACCMODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_mount {
|
enum mount_flags : uint32_t {
|
||||||
struct refcount rc;
|
MNT_RDONLY = __MNT_RDONLY,
|
||||||
// TODO
|
MNT_NOSUID = __MNT_NOSUID,
|
||||||
|
MNT_NOEXEC = __MNT_NOEXEC,
|
||||||
|
MNT_RELATIME = __MNT_RELATIME,
|
||||||
|
MNT_NOATIME = __MNT_NOATIME,
|
||||||
|
MNT_REMOUNT = __MNT_REMOUNT,
|
||||||
|
MNT_FORCE = __MNT_FORCE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_entry {
|
struct exec_info {
|
||||||
struct refcount rc;
|
struct vma* space;
|
||||||
// TODO
|
struct vmo* file_obj;
|
||||||
|
const char** argv;
|
||||||
|
const char** envp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_path {
|
enum vfs_lookup_flags : uint32_t {
|
||||||
struct vfs_mount* mount;
|
VFS_LOOKUP_FOLLOW_SYMLINKS = 1 << 0,
|
||||||
struct vfs_entry* entry;
|
VFS_LOOKUP_MUST_EXIST = 1 << 1,
|
||||||
|
VFS_LOOKUP_MUST_NOT_EXIST = 1 << 2,
|
||||||
|
VFS_LOOKUP_REAL_ID = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
errno_t vfs_path_mount();
|
|
||||||
errno_t vfs_path_lookup(struct vfs_path);
|
|
||||||
|
|
||||||
enum vfs_node_type {
|
enum vfs_node_type {
|
||||||
VNODE_REGULAR,
|
VNODE_REGULAR,
|
||||||
VNODE_DIRECTORY,
|
VNODE_DIRECTORY,
|
||||||
@@ -64,56 +92,373 @@ enum vfs_node_type {
|
|||||||
VNODE_BLOCKDEV,
|
VNODE_BLOCKDEV,
|
||||||
VNODE_CHARDEV,
|
VNODE_CHARDEV,
|
||||||
VNODE_SOCKET,
|
VNODE_SOCKET,
|
||||||
|
VNODE_ANONYMOUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum vfs_entry_state {
|
||||||
|
VFS_ENTRY_NOT_CACHED, // Entry hasn't been looked up yet.
|
||||||
|
VFS_ENTRY_PRESENT, // Entry is positive and contains a link to the inode.
|
||||||
|
VFS_ENTRY_NOT_PRESENT, // Entry is negative.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_entry {
|
||||||
|
struct refcount rc;
|
||||||
|
// The name of this entry.
|
||||||
|
char* name;
|
||||||
|
size_t name_len;
|
||||||
|
struct mutex lock;
|
||||||
|
|
||||||
|
enum vfs_entry_state state;
|
||||||
|
// The inode this entry points to when present.
|
||||||
|
struct vfs_node* inode;
|
||||||
|
// The parent of this entry, weak reference.
|
||||||
|
struct vfs_entry* parent;
|
||||||
|
|
||||||
|
// All cached children of this entry.
|
||||||
|
tailq_head(struct vfs_entry) children;
|
||||||
|
tailq_link(struct vfs_entry) child_link;
|
||||||
|
|
||||||
|
// A list of mounts on this entry.
|
||||||
|
vec(struct vfs_mount*) mounts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_path {
|
||||||
|
struct vfs_mount* mount;
|
||||||
|
struct vfs_entry* entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_path vfs_path_clone(struct vfs_path path);
|
||||||
|
void vfs_path_drop(struct vfs_path path);
|
||||||
|
|
||||||
|
struct vfs_mount {
|
||||||
|
struct refcount rc;
|
||||||
|
enum mount_flags flags;
|
||||||
|
struct vfs_entry* root;
|
||||||
|
struct vfs_path mount_point;
|
||||||
|
bool has_mount_point;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vfs_mount_ref(struct vfs_mount* mount);
|
||||||
|
void vfs_mount_unref(struct vfs_mount* mount);
|
||||||
|
errno_t vfs_mount(const char* fs_name, enum mount_flags flags, void* arg, struct vfs_mount** out);
|
||||||
|
errno_t vfs_unmount(struct vfs_mount* mount);
|
||||||
|
|
||||||
|
struct vfs_super_block_ops {
|
||||||
|
errno_t (*sync)(struct vfs_super_block* sb);
|
||||||
|
errno_t (*statvfs)(struct vfs_super_block* sb, struct __statvfs* out);
|
||||||
|
void (*destroy)(struct vfs_super_block* sb);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_super_block {
|
||||||
|
struct refcount rc;
|
||||||
|
const struct vfs_super_block_ops* ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Maybe not like this
|
||||||
|
struct vfs_mknod_target {
|
||||||
|
enum vfs_node_type type;
|
||||||
|
const struct vfs_node_ops* ops;
|
||||||
|
void* priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_file;
|
|
||||||
struct vfs_node;
|
|
||||||
struct vfs_node_ops {
|
struct vfs_node_ops {
|
||||||
errno_t (*sync)();
|
// Synchronizes the node metadata back to the underlying file system.
|
||||||
|
errno_t (*sync)(struct vfs_node* node);
|
||||||
|
// Destroys private state and drops references.
|
||||||
|
void (*destroy)(struct vfs_node* node);
|
||||||
|
// Operations that can be performed on an open file of this node.
|
||||||
|
const struct vfs_file_ops* file_ops;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
// VNODE_REGULAR
|
||||||
struct {
|
struct {
|
||||||
errno_t (*truncate)(struct vfs_node*, uint64_t new_length);
|
// Truncates the file down to `new_length` bytes.
|
||||||
|
errno_t (*truncate)(struct vfs_node* node, uint64_t new_length);
|
||||||
} regular;
|
} regular;
|
||||||
|
|
||||||
|
// VNODE_SYMLINK
|
||||||
struct {
|
struct {
|
||||||
errno_t (*read_link)(struct vfs_node*, char* buf, size_t len, size_t* out_written);
|
// Reads the value of the symlink into `buf`.
|
||||||
|
errno_t (*read_link)(struct vfs_node* node, struct iovec_iter* iter, size_t* out_read);
|
||||||
} symlink;
|
} symlink;
|
||||||
|
|
||||||
|
// VNODE_DIR
|
||||||
struct {
|
struct {
|
||||||
errno_t (*lookup)(struct vfs_node*, struct vfs_path entry);
|
errno_t (*lookup)(struct vfs_node* node, struct vfs_path* child);
|
||||||
errno_t (*open)(
|
errno_t (*open)(
|
||||||
struct vfs_node*,
|
struct vfs_node* node,
|
||||||
struct vfs_path entry,
|
struct vfs_path* path,
|
||||||
enum open_flags flags,
|
enum open_flags flags,
|
||||||
const struct ident* identity,
|
const struct ident* identity,
|
||||||
struct vfs_file* out_file
|
struct vfs_file** out_file
|
||||||
|
);
|
||||||
|
errno_t (*create)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
struct vfs_entry* entry,
|
||||||
|
mode_t mode,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
errno_t (*mkdir)(struct vfs_node* node, struct vfs_path* path, mode_t mode, const struct ident* identity);
|
||||||
|
errno_t (*symlink)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
struct vfs_path* path,
|
||||||
|
const char* target,
|
||||||
|
size_t target_len,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
errno_t (*link)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
struct vfs_path* path,
|
||||||
|
struct vfs_node* target,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
errno_t (*unlink)(struct vfs_node* node, struct vfs_path* path, const struct ident* identity);
|
||||||
|
errno_t (*rmdir)(struct vfs_node* node, struct vfs_path* path, const struct ident* identity);
|
||||||
|
errno_t (*rename)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
struct vfs_path* path,
|
||||||
|
struct vfs_node* target,
|
||||||
|
struct vfs_path* target_path,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
errno_t (*mknod)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
mode_t mode,
|
||||||
|
struct vfs_mknod_target* target,
|
||||||
|
const struct ident* identity,
|
||||||
|
struct vfs_node** out
|
||||||
|
);
|
||||||
|
errno_t (*get_dir_entries)(
|
||||||
|
struct vfs_node* node,
|
||||||
|
struct vfs_entry* entry,
|
||||||
|
off_t offset,
|
||||||
|
struct __dirent* buffer,
|
||||||
|
size_t buffer_len,
|
||||||
|
const struct ident* identity,
|
||||||
|
size_t* out_count
|
||||||
);
|
);
|
||||||
errno_t (*create)(struct vfs_node*, const struct ident* identity);
|
|
||||||
} dir;
|
} dir;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_node {
|
struct vfs_node {
|
||||||
|
struct refcount rc;
|
||||||
enum vfs_node_type type;
|
enum vfs_node_type type;
|
||||||
bool is_seekable;
|
bool is_seekable;
|
||||||
|
|
||||||
|
const struct vfs_node_ops* ops;
|
||||||
|
const struct vfs_file_ops* file_ops;
|
||||||
|
struct vfs_super_block* sb;
|
||||||
|
|
||||||
|
struct mutex lock;
|
||||||
|
void* priv;
|
||||||
|
|
||||||
|
ino_t id;
|
||||||
|
size_t size;
|
||||||
|
mode_t mode;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
timespec_t atime;
|
||||||
|
timespec_t mtime;
|
||||||
|
timespec_t ctime;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_file;
|
|
||||||
struct vfs_file_ops {
|
struct vfs_file_ops {
|
||||||
errno_t (*read)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
errno_t (*read)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
||||||
errno_t (*write)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
errno_t (*write)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
||||||
errno_t (*ioctl)(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
errno_t (*ioctl)(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
||||||
|
errno_t (*sync)(struct vfs_file* file, bool data_only);
|
||||||
|
errno_t (*mmap)(
|
||||||
|
struct vfs_file* file,
|
||||||
|
struct vma* vma,
|
||||||
|
uintptr_t addr,
|
||||||
|
size_t len,
|
||||||
|
enum prot_flags prot,
|
||||||
|
enum map_flags flags,
|
||||||
|
off_t offset,
|
||||||
|
uintptr_t* out_addr
|
||||||
|
);
|
||||||
|
bool (*seekable)(struct vfs_file* file);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum vfs_file_position {
|
||||||
|
VFS_POSITION_STREAM, // The file has no meaningful position.
|
||||||
|
VFS_POSITION_POSITION, // The file has a position, but accesses do not serialize the whole operation.
|
||||||
|
VFS_POSITION_ATOMIC, // Accesses through the shared file position are serialized.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum vfs_seek_anchor {
|
||||||
|
VFS_SEEK_START,
|
||||||
|
VFS_SEEK_CURRENT,
|
||||||
|
VFS_SEEK_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The kernel representation of an open file.
|
||||||
struct vfs_file {
|
struct vfs_file {
|
||||||
struct refcount rc;
|
struct refcount rc;
|
||||||
const struct vfs_file_ops* ops; // vtable for operations on this open file.
|
const struct vfs_file_ops* ops;
|
||||||
struct vfs_node* vnode; // The opened vnode.
|
struct vfs_node* vnode;
|
||||||
const char* abs_path; // Absolute path resolved during `open()`.
|
|
||||||
struct spinlock lock;
|
|
||||||
|
|
||||||
struct vfs_path path; // The cached entry pointing to this node.
|
// Absolute path resolved during open.
|
||||||
bool has_path; // If this file has a path.
|
char* absolute_path;
|
||||||
|
enum open_flags flags;
|
||||||
|
|
||||||
|
enum vfs_file_position position_kind;
|
||||||
|
off_t position;
|
||||||
|
struct mutex lock;
|
||||||
|
|
||||||
|
struct vfs_path path;
|
||||||
|
bool has_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
errno_t vfs_file_read(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
// A file system driver.
|
||||||
errno_t vfs_file_write(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
struct vfs_filesystem {
|
||||||
|
const char* name;
|
||||||
|
errno_t (*mount)(const struct vfs_filesystem* fs, enum mount_flags flags, void* arg, struct vfs_mount** out);
|
||||||
|
};
|
||||||
|
|
||||||
|
void vfs_node_ref(struct vfs_node* node);
|
||||||
|
void vfs_node_unref(struct vfs_node* node);
|
||||||
|
void vfs_entry_ref(struct vfs_entry* entry);
|
||||||
|
void vfs_entry_unref(struct vfs_entry* entry);
|
||||||
|
void vfs_file_ref(struct vfs_file* file);
|
||||||
|
void vfs_file_unref(struct vfs_file* file);
|
||||||
|
void vfs_super_block_ref(struct vfs_super_block* sb);
|
||||||
|
void vfs_super_block_unref(struct vfs_super_block* sb);
|
||||||
|
|
||||||
|
// Gets the kernel path representation of the absolute root.
|
||||||
|
struct vfs_path vfs_get_root();
|
||||||
|
|
||||||
|
void vfs_init();
|
||||||
|
|
||||||
|
errno_t vfs_register_filesystem(const struct vfs_filesystem* fs);
|
||||||
|
|
||||||
|
errno_t vfs_sync_all();
|
||||||
|
|
||||||
|
// Resolves a `path` to a VFS path, relative to `root` and `cwd`.
|
||||||
|
// Returns the result in `out` if the lookup with the given flags was successful.
|
||||||
|
errno_t vfs_path_lookup(
|
||||||
|
struct vfs_path root,
|
||||||
|
struct vfs_path cwd,
|
||||||
|
const char* path,
|
||||||
|
const struct ident* identity,
|
||||||
|
enum vfs_lookup_flags flags,
|
||||||
|
struct vfs_path* out
|
||||||
|
);
|
||||||
|
|
||||||
|
errno_t vfs_path_lookup_parent(struct vfs_path path, struct vfs_path* out);
|
||||||
|
|
||||||
|
errno_t vfs_path_lookup_child(
|
||||||
|
struct vfs_path path,
|
||||||
|
struct vfs_path* root,
|
||||||
|
const char* name,
|
||||||
|
size_t name_len,
|
||||||
|
struct vfs_path* out
|
||||||
|
);
|
||||||
|
|
||||||
|
// Builds the absolute path of `path` from `root` and stores the result in `buf`.
|
||||||
|
// Returns the amount of actually written bytes in `out_len`.
|
||||||
|
errno_t vfs_path_absolute(struct vfs_path path, struct vfs_path* root, char* buf, size_t len, size_t* out_len);
|
||||||
|
|
||||||
|
// Creates a new directory at `path`, relative to `root` and `cwd` with `mode`.
|
||||||
|
errno_t vfs_mkdir(
|
||||||
|
struct vfs_path root,
|
||||||
|
struct vfs_path cwd,
|
||||||
|
const char* path,
|
||||||
|
mode_t mode,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
|
||||||
|
// Creates a new symbolic link at `path`, relative to `root` and `cwd`, pointing to `target`.
|
||||||
|
errno_t vfs_symlink(
|
||||||
|
struct vfs_path root,
|
||||||
|
struct vfs_path cwd,
|
||||||
|
const char* path,
|
||||||
|
const char* target,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
|
||||||
|
// Unlinks a file at `path`, relative to `root` and `cwd`.
|
||||||
|
errno_t vfs_unlink(struct vfs_path root, struct vfs_path cwd, const char* path, const struct ident* identity);
|
||||||
|
|
||||||
|
// Removes a directory at `path`, relative to `root` and `cwd`.
|
||||||
|
errno_t vfs_rmdir(struct vfs_path root, struct vfs_path cwd, const char* path, const struct ident* identity);
|
||||||
|
|
||||||
|
errno_t vfs_mknod(
|
||||||
|
struct vfs_path root,
|
||||||
|
struct vfs_path cwd,
|
||||||
|
const char* path,
|
||||||
|
mode_t mode,
|
||||||
|
struct vfs_mknod_target* target,
|
||||||
|
const struct ident* identity
|
||||||
|
);
|
||||||
|
|
||||||
|
// Checks if an access to a `node` with `flags` using `identity` is allowed.
|
||||||
|
// Returns 0 if the access is allowed.
|
||||||
|
errno_t vfs_node_try_access(struct vfs_node* node, const struct ident* identity, enum open_flags flags, bool use_real);
|
||||||
|
|
||||||
|
// Opens a node at `path`, relative to `root` and `cwd`.
|
||||||
|
// Returns the opened node as a file in `out`.
|
||||||
|
errno_t vfs_file_open(
|
||||||
|
struct vfs_path root,
|
||||||
|
struct vfs_path cwd,
|
||||||
|
const char* path,
|
||||||
|
enum open_flags flags,
|
||||||
|
mode_t mode,
|
||||||
|
const struct ident* identity,
|
||||||
|
struct vfs_file** out
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reads from a `file` into a `buffer` from the current offset.
|
||||||
|
// Returns the actual bytes read in `out_read`.
|
||||||
|
errno_t vfs_file_read(struct vfs_file* file, struct iovec_iter* buffer, ssize_t* out_read);
|
||||||
|
|
||||||
|
// Same as `vfs_file_read`, but from a given offset.
|
||||||
|
errno_t vfs_file_pread(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
||||||
|
|
||||||
|
// Wites to a `file` from a `buffer` from the current offset.
|
||||||
|
// Returns the actual bytes written in `out_written`.
|
||||||
|
errno_t vfs_file_write(struct vfs_file* file, struct iovec_iter* buffer, ssize_t* out_written);
|
||||||
|
|
||||||
|
// Same as `vfs_file_write`, but from a given offset.
|
||||||
|
errno_t vfs_file_pwrite(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
||||||
|
|
||||||
|
// Performs a generic `request` on a `file`.
|
||||||
|
// Returns the result in `out_result`.
|
||||||
errno_t vfs_file_ioctl(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
errno_t vfs_file_ioctl(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
||||||
|
|
||||||
|
errno_t vfs_file_sync(struct vfs_file* file, bool data_only);
|
||||||
|
|
||||||
|
errno_t vfs_file_seek(struct vfs_file* file, enum vfs_seek_anchor anchor, off_t offset, off_t* out_position);
|
||||||
|
off_t vfs_file_tell(struct vfs_file* file);
|
||||||
|
|
||||||
|
// Maps `len` bytes of a `file` from `offset` into `vma` at `addr`.
|
||||||
|
// Returns the start of the mapped region in `out_addr`.
|
||||||
|
errno_t vfs_file_mmap(
|
||||||
|
struct vfs_file* file,
|
||||||
|
struct vma* vma,
|
||||||
|
uintptr_t addr,
|
||||||
|
size_t len,
|
||||||
|
enum prot_flags prot,
|
||||||
|
enum map_flags flags,
|
||||||
|
off_t offset,
|
||||||
|
uintptr_t* out_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Directory listing.
|
||||||
|
errno_t vfs_get_dir_entries(
|
||||||
|
struct vfs_file* file,
|
||||||
|
struct __dirent* buffer,
|
||||||
|
size_t buffer_len,
|
||||||
|
const struct ident* identity,
|
||||||
|
size_t* out_count
|
||||||
|
);
|
||||||
|
|
||||||
|
// Creates an inode belonging to the anonymous pseudo file system.
|
||||||
|
errno_t vfs_create_anon_inode(
|
||||||
|
const struct vfs_file_ops* file_ops,
|
||||||
|
enum vfs_node_type type,
|
||||||
|
mode_t mode,
|
||||||
|
const struct ident* identity,
|
||||||
|
struct vfs_node** out
|
||||||
|
);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct pager_ops {
|
|||||||
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
|
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: change to btree
|
// TODO: change to rbtree
|
||||||
struct page_list {
|
struct page_list {
|
||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
struct page* value;
|
struct page* value;
|
||||||
@@ -50,5 +50,8 @@ struct paged_vmo {
|
|||||||
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
|
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
|
||||||
errno_t vmo_new_phys(struct paged_vmo** out);
|
errno_t vmo_new_phys(struct paged_vmo** out);
|
||||||
|
|
||||||
|
// Drops all cached pages past `length` bytes.
|
||||||
|
void vmo_truncate_paged(struct paged_vmo* paged, size_t length);
|
||||||
|
|
||||||
// Creates a VMO backed by a specific physical address range (e.g. for MMIO).
|
// Creates a VMO backed by a specific physical address range (e.g. for MMIO).
|
||||||
errno_t vmo_new_phys_range(uintptr_t addr, size_t length, struct vmo** out);
|
errno_t vmo_new_phys_range(uintptr_t addr, size_t length, struct vmo** out);
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ static struct __utsname uname_buf = {
|
|||||||
.version = CONFIG_KERNEL_FLAVOR,
|
.version = CONFIG_KERNEL_FLAVOR,
|
||||||
.nodename = "localhost",
|
.nodename = "localhost",
|
||||||
.machine = ZINNIA_ARCH,
|
.machine = ZINNIA_ARCH,
|
||||||
.domainname = "none",
|
.domainname = "(none)",
|
||||||
};
|
};
|
||||||
|
|
||||||
struct syscall_ret sys_setuname(const __user struct __utsname* ptr) {
|
struct syscall_ret sys_setuname(const __user struct __utsname* ptr) {
|
||||||
|
|||||||
Reference in New Issue
Block a user