Compare commits

..

4 Commits

Author SHA1 Message Date
marv7000 5d672d8132 vfs interface 2026-10-06 01:59:08 +02:00
marv7000 f8eb4f4e54 more 2026-10-06 01:34:24 +02:00
marv7000 134343d2a8 empty line 2026-10-06 00:53:46 +02:00
marv7000 c201b43d8c timespec_t 2026-10-06 00:53:38 +02:00
31 changed files with 556 additions and 70 deletions
+1 -1
View File
@@ -2,8 +2,8 @@
#include <zinnia/cmdline.h>
#include <zinnia/init.h>
#include <zinnia/print.h>
#include <zinnia/utils.h>
#include <zinnia/string.h>
#include <zinnia/utils.h>
#include "limine.h"
[[__initdata_sorted("limine.0")]]
+1
View File
@@ -48,6 +48,7 @@ bool clock_switch(struct clock* clock) {
spin_unlock(&lock);
log("clock: Switching to clock source \"%s\"\n", clock->name);
return true;
}
+3
View File
@@ -0,0 +1,3 @@
#include <zinnia/dpc.h>
// TODO
+1 -2
View File
@@ -1,5 +1,4 @@
// Compiler runtime support like libgcc or compiler-rt.
// Extend as required.
// Compiler runtime support.
#include <stdint.h>
+1 -1
View File
@@ -2,9 +2,9 @@
#include <zinnia/errno.h>
#include <zinnia/pmap.h>
#include <zinnia/spin.h>
#include <zinnia/string.h>
#include <zinnia/vma.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.
static_assert(CONFIG_HAVE_MMU_GENERIC);
+1 -1
View File
@@ -3,9 +3,9 @@
#include <zinnia/panic.h>
#include <zinnia/print.h>
#include <zinnia/spin.h>
#include <zinnia/string.h>
#include <zinnia/virt.h>
#include <stdint.h>
#include <zinnia/string.h>
uintptr_t mem_hhdm_base = 0;
+3 -4
View File
@@ -60,7 +60,7 @@ static struct vma_mapping* find_mapping(struct vma* v, size_t page) {
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)
return prot & PROT_WRITE;
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);
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);
return false;
}
@@ -107,8 +107,7 @@ bool vma_page_fault(struct vma* v, const struct vma_fault_info* info) {
spin_lock(&v->lock);
mapping = find_mapping(v, faulty_page);
const bool still_valid = mapping && mapping->object == object &&
(faulty_page - mapping->start_page) + mapping->offset_page == object_page &&
access_allowed(mapping->prot, info);
(faulty_page - mapping->start_page) + mapping->offset_page == object_page && can_access(mapping->prot, info);
if (still_valid) {
errno_t status =
+20 -1
View File
@@ -1,9 +1,9 @@
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/string.h>
#include <zinnia/utils.h>
#include <zinnia/vmo.h>
#include <zinnia/string.h>
void vmo_ref(struct vmo* obj) {
refcount_inc(&obj->rc);
@@ -211,6 +211,25 @@ errno_t vmo_new_phys(struct paged_vmo** 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 vmo object;
uintptr_t start;
-1
View File
@@ -1,7 +1,6 @@
kernel_sources += files(
'clock.c',
'console.c',
'elf.c',
'irq.c',
'module.c',
'panic.c',
+3
View File
@@ -29,6 +29,9 @@ struct percpu* percpu_new() {
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();
// TODO: Map pages past the end of the kernel.
// TODO: Document how allocations work.
phys_t mem;
if (mem_phys_alloc(num_pages, 0, &mem))
return nullptr;
+5
View File
@@ -1,6 +1,11 @@
#include <zinnia/spin.h>
#include <stdatomic.h>
void spin_init(struct spinlock* spin) {
spin->next = 0;
spin->owner = 0;
}
void spin_lock(struct spinlock* spin) {
uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed);
+1 -4
View File
@@ -1,12 +1,9 @@
subdir('common')
subdir('block')
subdir('dt')
if kconfig.get('CONFIG_ACPI', 'n') == 'y'
subdir('acpi')
endif
if kconfig.get('CONFIG_DT', 'n') == 'y'
subdir('dt')
endif
module_lds = meson.current_source_dir() / 'module.ld'
+1
View File
@@ -9,6 +9,7 @@
#include <zinnia/sched.h>
#include <zinnia/string.h>
#include <zinnia/utils.h>
#include <zinnia/vfs.h>
#include <zinnia/vma.h>
#include <zinnia/vmo.h>
#include <bits/elf.h>
+3
View File
@@ -0,0 +1,3 @@
kernel_sources += files(
'elf.c',
)
+1 -1
View File
@@ -1 +1 @@
subdir('tmpfs')
subdir('exec')
-1
View File
@@ -1 +0,0 @@
kernel_sources += files('tmpfs.c')
-1
View File
@@ -1 +0,0 @@
// TODO
+7
View File
@@ -0,0 +1,7 @@
#include <zinnia/ident.h>
static const struct ident kernel_identity = {0};
const struct ident* ident_kernel() {
return &kernel_identity;
}
+3
View File
@@ -0,0 +1,3 @@
kernel_sources += files(
'ident.c',
)
+2 -2
View File
@@ -17,12 +17,12 @@ struct __timeval {
__suseconds_t tv_usec;
};
struct itimerval {
struct __itimerval {
struct __timeval it_interval;
struct __timeval it_value;
};
struct itimerspec {
struct __itimerspec {
struct __timespec it_interval;
struct __timespec it_value;
};
+4 -1
View File
@@ -26,7 +26,10 @@ struct phys_mem {
// Base address of the HHDM.
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.
// Returns `nullptr` if the allocator cannot provide an allocation for the given `length` + `flags`.
+18
View File
@@ -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
View File
@@ -1,6 +1,7 @@
#pragma once
#include <zinnia/errno.h>
#include <zinnia/vfs.h>
#include <bits/elf.h>
#include <stdint.h>
@@ -341,15 +342,4 @@ static inline uint32_t ELF64_R_TYPE(uint64_t info) {
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);
+45
View File
@@ -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);
+9 -1
View File
@@ -1,5 +1,13 @@
#pragma once
#include <zinnia/types.h>
#include <zinnia/vec.h>
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
View File
@@ -1,12 +1,37 @@
#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>
struct iovec_iter {
struct iovec* iovecs;
struct __iovec* iovecs;
size_t iovecs_len;
size_t total_len;
size_t total_offset;
size_t current_idx;
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,
};
}
+2
View File
@@ -10,6 +10,8 @@ struct spinlock {
_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.
void spin_lock(struct spinlock* spin);
+13 -3
View File
@@ -2,6 +2,16 @@
#include <uapi/time.h>
struct timespec time_from_sec(uint64_t sec);
struct timespec time_from_nano(uint64_t nsec);
struct timespec time_from_milli(uint64_t msec);
typedef struct __timespec timespec_t;
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
View File
@@ -3,13 +3,35 @@
#include <zinnia/errno.h>
#include <zinnia/ident.h>
#include <zinnia/iovec.h>
#include <zinnia/mman.h>
#include <zinnia/mutex.h>
#include <zinnia/refcount.h>
#include <zinnia/spin.h>
#include <zinnia/tailq.h>
#include <zinnia/time.h>
#include <zinnia/types.h>
#include <zinnia/vec.h>
#include <zinnia/vma.h>
#include <zinnia/vmo.h>
#include <stddef.h>
#include <stdint.h>
#include <uapi/dirent.h>
#include <uapi/fcntl.h>
#include <uapi/limits.h>
#include <uapi/mount.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 {
O_RDONLY = __O_RDONLY,
@@ -38,24 +60,30 @@ enum open_flags : uint32_t {
O_ACCMODE = __O_ACCMODE,
};
struct vfs_mount {
struct refcount rc;
// TODO
enum mount_flags : uint32_t {
MNT_RDONLY = __MNT_RDONLY,
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 refcount rc;
// TODO
struct exec_info {
struct vma* space;
struct vmo* file_obj;
const char** argv;
const char** envp;
};
struct vfs_path {
struct vfs_mount* mount;
struct vfs_entry* entry;
enum vfs_lookup_flags : uint32_t {
VFS_LOOKUP_FOLLOW_SYMLINKS = 1 << 0,
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 {
VNODE_REGULAR,
VNODE_DIRECTORY,
@@ -64,56 +92,373 @@ enum vfs_node_type {
VNODE_BLOCKDEV,
VNODE_CHARDEV,
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 {
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 {
// VNODE_REGULAR
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;
// VNODE_SYMLINK
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;
// VNODE_DIR
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)(
struct vfs_node*,
struct vfs_path entry,
struct vfs_node* node,
struct vfs_path* path,
enum open_flags flags,
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;
};
};
struct vfs_node {
struct refcount rc;
enum vfs_node_type type;
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 {
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 (*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 refcount rc;
const struct vfs_file_ops* ops; // vtable for operations on this open file.
struct vfs_node* vnode; // The opened vnode.
const char* abs_path; // Absolute path resolved during `open()`.
struct spinlock lock;
const struct vfs_file_ops* ops;
struct vfs_node* vnode;
struct vfs_path path; // The cached entry pointing to this node.
bool has_path; // If this file has a path.
// Absolute path resolved during open.
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);
errno_t vfs_file_write(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
// A file system driver.
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_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
);
+4 -1
View File
@@ -33,7 +33,7 @@ struct pager_ops {
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 {
uintptr_t offset;
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_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).
errno_t vmo_new_phys_range(uintptr_t addr, size_t length, struct vmo** out);
+1 -1
View File
@@ -13,7 +13,7 @@ static struct __utsname uname_buf = {
.version = CONFIG_KERNEL_FLAVOR,
.nodename = "localhost",
.machine = ZINNIA_ARCH,
.domainname = "none",
.domainname = "(none)",
};
struct syscall_ret sys_setuname(const __user struct __utsname* ptr) {