diff --git a/boot/limine/entry.c b/boot/limine/entry.c index 885466b..804979e 100644 --- a/boot/limine/entry.c +++ b/boot/limine/entry.c @@ -2,8 +2,8 @@ #include #include #include -#include #include +#include #include "limine.h" [[__initdata_sorted("limine.0")]] diff --git a/core/dpc.c b/core/dpc.c new file mode 100644 index 0000000..8fb7e6b --- /dev/null +++ b/core/dpc.c @@ -0,0 +1,3 @@ +#include + +// TODO diff --git a/core/lib/runtime.c b/core/lib/runtime.c index 681a13b..4aa8e75 100644 --- a/core/lib/runtime.c +++ b/core/lib/runtime.c @@ -1,5 +1,4 @@ -// Compiler runtime support like libgcc or compiler-rt. -// Extend as required. +// Compiler runtime support. #include diff --git a/core/mem/pmap.c b/core/mem/pmap.c index ec6d243..8f64beb 100644 --- a/core/mem/pmap.c +++ b/core/mem/pmap.c @@ -2,9 +2,9 @@ #include #include #include +#include #include #include -#include // 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); diff --git a/core/mem/pmm.c b/core/mem/pmm.c index 530281b..a6a66ae 100644 --- a/core/mem/pmm.c +++ b/core/mem/pmm.c @@ -3,9 +3,9 @@ #include #include #include +#include #include #include -#include uintptr_t mem_hhdm_base = 0; diff --git a/core/mem/vma.c b/core/mem/vma.c index 0bbb352..0f47df1 100644 --- a/core/mem/vma.c +++ b/core/mem/vma.c @@ -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 = diff --git a/core/mem/vmo.c b/core/mem/vmo.c index 9239056..5cc4be0 100644 --- a/core/mem/vmo.c +++ b/core/mem/vmo.c @@ -1,9 +1,9 @@ #include #include #include +#include #include #include -#include 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; diff --git a/core/meson.build b/core/meson.build index 18c343c..cfba785 100644 --- a/core/meson.build +++ b/core/meson.build @@ -1,7 +1,6 @@ kernel_sources += files( 'clock.c', 'console.c', - 'elf.c', 'irq.c', 'module.c', 'panic.c', diff --git a/core/percpu.c b/core/percpu.c index 6e01802..5ce3522 100644 --- a/core/percpu.c +++ b/core/percpu.c @@ -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; diff --git a/core/spin.c b/core/spin.c index 13d9d90..1da5ea8 100644 --- a/core/spin.c +++ b/core/spin.c @@ -1,6 +1,11 @@ #include #include +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); diff --git a/dev/meson.build b/dev/meson.build index 47f1f05..3837470 100644 --- a/dev/meson.build +++ b/dev/meson.build @@ -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' diff --git a/core/elf.c b/fs/exec/elf.c similarity index 99% rename from core/elf.c rename to fs/exec/elf.c index c1c0b6b..d073c89 100644 --- a/core/elf.c +++ b/fs/exec/elf.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/exec/meson.build b/fs/exec/meson.build new file mode 100644 index 0000000..a389904 --- /dev/null +++ b/fs/exec/meson.build @@ -0,0 +1,3 @@ +kernel_sources += files( + 'elf.c', +) diff --git a/fs/meson.build b/fs/meson.build index 7578f28..a715240 100644 --- a/fs/meson.build +++ b/fs/meson.build @@ -1 +1 @@ -subdir('tmpfs') +subdir('exec') \ No newline at end of file diff --git a/fs/tmpfs/meson.build b/fs/tmpfs/meson.build deleted file mode 100644 index 4e4da64..0000000 --- a/fs/tmpfs/meson.build +++ /dev/null @@ -1 +0,0 @@ -kernel_sources += files('tmpfs.c') diff --git a/fs/tmpfs/tmpfs.c b/fs/tmpfs/tmpfs.c deleted file mode 100644 index 70b786d..0000000 --- a/fs/tmpfs/tmpfs.c +++ /dev/null @@ -1 +0,0 @@ -// TODO diff --git a/fs/vfs/ident.c b/fs/vfs/ident.c new file mode 100644 index 0000000..24cf39d --- /dev/null +++ b/fs/vfs/ident.c @@ -0,0 +1,7 @@ +#include + +static const struct ident kernel_identity = {0}; + +const struct ident* ident_kernel() { + return &kernel_identity; +} diff --git a/fs/vfs/meson.build b/fs/vfs/meson.build new file mode 100644 index 0000000..9d4787d --- /dev/null +++ b/fs/vfs/meson.build @@ -0,0 +1,3 @@ +kernel_sources += files( + 'ident.c', +) diff --git a/include/uapi/time.h b/include/uapi/time.h index 8bacd36..04b4167 100644 --- a/include/uapi/time.h +++ b/include/uapi/time.h @@ -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; }; diff --git a/include/zinnia/alloc.h b/include/zinnia/alloc.h index fa3206c..ca62518 100644 --- a/include/zinnia/alloc.h +++ b/include/zinnia/alloc.h @@ -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`. diff --git a/include/zinnia/dpc.h b/include/zinnia/dpc.h new file mode 100644 index 0000000..d0620fc --- /dev/null +++ b/include/zinnia/dpc.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +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; diff --git a/include/zinnia/elf.h b/include/zinnia/elf.h index 03a5c23..9923a0f 100644 --- a/include/zinnia/elf.h +++ b/include/zinnia/elf.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -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); diff --git a/include/zinnia/fdt.h b/include/zinnia/fdt.h new file mode 100644 index 0000000..25e16f9 --- /dev/null +++ b/include/zinnia/fdt.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +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); diff --git a/include/zinnia/ident.h b/include/zinnia/ident.h index ed90f13..7fd3ee1 100644 --- a/include/zinnia/ident.h +++ b/include/zinnia/ident.h @@ -1,5 +1,13 @@ #pragma once +#include +#include + struct ident { - // TODO + uid_t uid, euid, suid; + gid_t gid, egid, sgid; + + vec(gid_t) groups; }; + +const struct ident* ident_kernel(void); diff --git a/include/zinnia/iovec.h b/include/zinnia/iovec.h index 72d2e1a..fea7e4a 100644 --- a/include/zinnia/iovec.h +++ b/include/zinnia/iovec.h @@ -1,12 +1,37 @@ #pragma once +#include +#include +#include +#include +#include #include 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, + }; +} diff --git a/include/zinnia/spin.h b/include/zinnia/spin.h index dfcc9f2..878afc0 100644 --- a/include/zinnia/spin.h +++ b/include/zinnia/spin.h @@ -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); diff --git a/include/zinnia/vmo.h b/include/zinnia/vmo.h index eea6465..15f879b 100644 --- a/include/zinnia/vmo.h +++ b/include/zinnia/vmo.h @@ -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); diff --git a/syscalls/uname.c b/syscalls/uname.c index f33bbb6..671da25 100644 --- a/syscalls/uname.c +++ b/syscalls/uname.c @@ -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) {