From 0e2d4ed8c667ee5d2a6b92cb86dbebdc26c556f8 Mon Sep 17 00:00:00 2001 From: Marvin Friedrich Date: Tue, 11 Aug 2026 17:48:20 +0200 Subject: [PATCH] stuff2 --- include/common/compiler.h | 35 +++----------- include/common/elf.h | 64 +++++++++++++------------ include/zinnia/futex.h | 5 +- include/zinnia/handle.h | 5 +- include/zinnia/ipc.h | 26 ++++++++++ include/zinnia/ipc/init.h | 46 ------------------ include/zinnia/mem.h | 2 +- include/zinnia/namespace.h | 4 +- kernel/arch/x86_64/apic.c | 24 +++++----- kernel/arch/x86_64/gdt.c | 2 +- kernel/arch/x86_64/hpet.c | 4 +- kernel/arch/x86_64/idt.c | 2 +- kernel/arch/x86_64/include/bits/sched.h | 25 ++++++---- kernel/arch/x86_64/sched.c | 1 - kernel/arch/x86_64/usercopy.c | 4 +- kernel/boot/main.c | 23 ++++----- kernel/core/channel.c | 12 ++--- kernel/core/elf.c | 2 +- kernel/core/namespace.c | 14 +++--- kernel/core/sched.c | 26 +++++----- kernel/core/spin.c | 11 ++--- kernel/include/{kernel => }/assert.h | 7 +-- kernel/include/kernel/channel.h | 4 +- kernel/include/kernel/hashmap.h | 22 ++++----- kernel/include/kernel/irq.h | 4 +- kernel/include/kernel/list.h | 28 +++++------ kernel/include/kernel/namespace.h | 2 +- kernel/include/kernel/sched.h | 4 +- kernel/include/kernel/spin.h | 5 +- kernel/include/kernel/tailq.h | 18 +++---- kernel/include/kernel/vec.h | 51 ++++++++++---------- kernel/include/kernel/vmo.h | 4 +- kernel/include/kernel/wait.h | 2 +- kernel/include/stdarg.h | 5 +- kernel/include/stdatomic.h | 5 +- kernel/include/stddef.h | 6 +-- kernel/include/stdint.h | 5 +- kernel/include/stdlib.h | 5 +- kernel/include/string.h | 5 +- kernel/mem/init.c | 14 +++--- kernel/mem/meson.build | 2 +- kernel/mem/{vas.c => vma.c} | 4 +- kernel/mem/vmo.c | 4 +- kernel/syscalls/dispatch.c | 6 +-- kernel/syscalls/thread.c | 3 +- meson.build | 2 +- servers/devd/main.c | 3 +- servers/initd/main.c | 28 ++--------- servers/meson.build | 2 +- servers/{posixd => unix}/include/vfs.h | 0 servers/{posixd => unix}/main.c | 34 +++++++------ servers/{posixd => unix}/meson.build | 2 +- servers/{posixd => unix}/uname.c | 0 subprojects/.wraplock | 0 subprojects/uacpi | 2 +- 55 files changed, 279 insertions(+), 346 deletions(-) create mode 100644 include/zinnia/ipc.h delete mode 100644 include/zinnia/ipc/init.h rename kernel/include/{kernel => }/assert.h (71%) rename kernel/mem/{vas.c => vma.c} (97%) rename servers/{posixd => unix}/include/vfs.h (100%) rename servers/{posixd => unix}/main.c (62%) rename servers/{posixd => unix}/meson.build (93%) rename servers/{posixd => unix}/uname.c (100%) create mode 100644 subprojects/.wraplock diff --git a/include/common/compiler.h b/include/common/compiler.h index aad9884..942aed2 100644 --- a/include/common/compiler.h +++ b/include/common/compiler.h @@ -1,7 +1,12 @@ #pragma once -// These hints may improve code generation, but are optional and can be stubbed. -#if defined(__GNUC__) || defined(__clang__) +// Attributes that affect data layout. +#define __section(x) gnu::section(x) +#define __aligned(x) gnu::aligned(x) +#define __packed gnu::packed +#define __naked gnu::naked + +// These hints may improve code generation. #define __cold gnu::cold #define __hot gnu::hot #define __used gnu::used @@ -9,17 +14,6 @@ #define __format(like, ...) gnu::format(like, __VA_ARGS__) #define __likely(x) __builtin_expect(!!(x), 1) #define __unlikely(x) __builtin_expect(!!(x), 0) -#define __always_inline gnu::always_inline -#else -#define __cold -#define __hot -#define __used -#define __unused -#define __format(like, ...) -#define __likely(x) x -#define __unlikely(x) x -#define __always_inline -#endif // Only clang has these hints, GCC will throw a warning here. // They also don't support the C23 attribute format. @@ -30,18 +24,3 @@ #define __user #define __phys #endif - -// Attributes that affect data layout. Not optional. -#if defined(__GNUC__) || defined(__clang__) -#define __weak gnu::weak -#define __section(x) gnu::section(x) -#define __aligned(x) gnu::aligned(x) -#define __packed gnu::packed -#define __naked gnu::naked -#define __alias(x) gnu::alias(x) -#else -#error "Unsupported compiler!" -#endif - -// Intrinsics -#define __unreachable() __builtin_unreachable() diff --git a/include/common/elf.h b/include/common/elf.h index e38bac1..1b0235c 100644 --- a/include/common/elf.h +++ b/include/common/elf.h @@ -2,37 +2,6 @@ #include -#ifdef __x86_64__ -#define ELF_ARCH_CLASS ELFCLASS64 -#define ELF_ARCH_DATA ELFDATA2LSB -#define ELF_ARCH_MACHINE EM_X86_64 - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE -#define ELF_ST_BIND ELF64_ST_BIND -#define ELF_ST_TYPE ELF64_ST_TYPE - -#define elf_ehdr elf64_ehdr -#define elf_phdr elf64_phdr -#define elf_dyn elf64_dyn -#define elf_addr elf64_addr -#define elf_off elf64_off -#define elf_nhdr elf64_nhdr -#define elf_auxv elf64_auxv -#define elf_sym elf64_sym -#define elf_rela elf64_rela -#define elf_rel elf64_rel - -enum { - R_NONE = 0, - R_COPY = 5, - R_GLOB_DAT = 6, - R_JUMP_SLOT = 7, - R_RELATIVE = 8, - R_IRELATIVE = 37, -}; -#endif - constexpr char ELF_MAG[4] = {0x7F, 'E', 'L', 'F'}; typedef uint64_t elf64_addr_t; @@ -369,3 +338,36 @@ static inline uint32_t ELF64_R_SYM(uint64_t info) { static inline uint32_t ELF64_R_TYPE(uint64_t info) { return info & 0xFFFFFFFF; } + +// Architecture specific bits. + +#ifdef __x86_64__ +#define ELF_ARCH_CLASS ELFCLASS64 +#define ELF_ARCH_DATA ELFDATA2LSB +#define ELF_ARCH_MACHINE EM_X86_64 + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define elf_ehdr elf64_ehdr +#define elf_phdr elf64_phdr +#define elf_dyn elf64_dyn +#define elf_addr elf64_addr +#define elf_off elf64_off +#define elf_nhdr elf64_nhdr +#define elf_auxv elf64_auxv +#define elf_sym elf64_sym +#define elf_rela elf64_rela +#define elf_rel elf64_rel + +enum { + R_NONE = 0, + R_COPY = 5, + R_GLOB_DAT = 6, + R_JUMP_SLOT = 7, + R_RELATIVE = 8, + R_IRELATIVE = 37, +}; +#endif diff --git a/include/zinnia/futex.h b/include/zinnia/futex.h index f2fa3e8..4a5b5b7 100644 --- a/include/zinnia/futex.h +++ b/include/zinnia/futex.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -10,12 +11,12 @@ extern "C" { // Blocks the calling thread if *addr == expected. // Returns immediately if the value at addr has changed. -static inline zn_status_t zn_futex_wait(int* addr, int expected) { +static inline zn_status_t zn_futex_wait(int32_t* addr, int32_t expected) { return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT); } // Wakes up to `count` threads waiting on the given futex address. -static inline zn_status_t zn_futex_wake(int* addr, int count) { +static inline zn_status_t zn_futex_wake(int32_t* addr, int32_t count) { return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE); } diff --git a/include/zinnia/handle.h b/include/zinnia/handle.h index f773b63..affc9a8 100644 --- a/include/zinnia/handle.h +++ b/include/zinnia/handle.h @@ -24,9 +24,8 @@ static inline zn_status_t zn_handle_validate(zn_handle_t handle) { return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE); } -// Drops an object handle. -// All further references using this handle are invalid. The numerical value -// may become valid again, but it is an error to keep using it. +// Drops an object handle. All further references using this handle are invalid. +// The numerical value may become valid again, but it is an error to keep using it. // The underlying object gets freed only once no other handle references it. static inline zn_status_t zn_handle_drop(zn_handle_t handle) { return zn_syscall1(handle, ZN_SYSCALL_HANDLE_DROP); diff --git a/include/zinnia/ipc.h b/include/zinnia/ipc.h new file mode 100644 index 0000000..df25c39 --- /dev/null +++ b/include/zinnia/ipc.h @@ -0,0 +1,26 @@ +#ifndef ZINNIA_IPC_H +#define ZINNIA_IPC_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Defines an IPC window. +struct zn_ipcw { + zn_handle_t handles[16]; +}; + +static inline zn_status_t zn_ipcw_init(struct zn_ipcw** ipcw) { + return ZN_ERR_UNSUPPORTED; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/zinnia/ipc/init.h b/include/zinnia/ipc/init.h deleted file mode 100644 index 357bb85..0000000 --- a/include/zinnia/ipc/init.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include - -#define IPC_GET_STRING(data, str, buf) \ - do { \ - memcpy(buf, (data) + (str)->offset, (str)->len); \ - } while (0) - -#define IPC_SET_STRING(cursor, data, field, string) \ - do { \ - const size_t _len = strlen(string); \ - (field)->offset = cursor; \ - (field)->len = _len; \ - memcpy(data + cursor, string, _len); \ - cursor += _len; \ - } while (0) - -enum ipc_msg_id { - IPC_MSG_FOO, - IPC_MSG_BAR, - IPC_MSG_BAZ, -}; - -struct ipc_array { - uint16_t offset; - uint16_t len; -}; - -struct ipc_option { - uint16_t offset; -}; - -struct ipc_init_register_rq { - enum ipc_msg_id id; - struct ipc_array name; - char data[]; -}; - -struct ipc_kernel_msg { - enum ipc_msg_id id; - struct ipc_array name; - char data[]; -}; diff --git a/include/zinnia/mem.h b/include/zinnia/mem.h index 23b2649..faae0e9 100644 --- a/include/zinnia/mem.h +++ b/include/zinnia/mem.h @@ -25,7 +25,7 @@ enum zn_vm_flags { // Map at a fixed address, replacing whatever is in the way. ZN_VM_MAP_FIXED = 1 << 8, // Map at a fixed address, failing if anything is in the way. - ZB_VM_MAP_FIXED_NOREPLACE = 1 << 9, + ZN_VM_MAP_FIXED_NOREPLACE = 1 << 9, // Map the entire range immediately. ZN_VM_MAP_POPULATE = 1 << 10, }; diff --git a/include/zinnia/namespace.h b/include/zinnia/namespace.h index 868248d..a62c9cc 100644 --- a/include/zinnia/namespace.h +++ b/include/zinnia/namespace.h @@ -13,7 +13,9 @@ static inline zn_status_t zn_ns_create(zn_handle_t* out) { return ZN_ERR_UNSUPPORTED; } -static inline zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_namespace) { +// Moves a handle to another namespace. +// The handle must have the `ZN_RIGHT_MOVE` right. +static inline zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_ns) { return ZN_ERR_UNSUPPORTED; } diff --git a/kernel/arch/x86_64/apic.c b/kernel/arch/x86_64/apic.c index e6a22a9..7e498b0 100644 --- a/kernel/arch/x86_64/apic.c +++ b/kernel/arch/x86_64/apic.c @@ -45,7 +45,7 @@ void lapic_init(struct local_apic* lapic) { apic_msr |= 1 << 10; else { lapic->xapic_regs = mmio_new(apic_msr & 0xFFFF'F000, 0x1000); - ASSERT(lapic->xapic_regs, "Failed to allocate virtual memory!\n"); + assert(lapic->xapic_regs, "Failed to allocate virtual memory!\n"); } asm_wrmsr(0x1B, apic_msr); @@ -86,18 +86,18 @@ void lapic_eoi(struct local_apic* lapic) { #define PIC2_DATA_PORT 0xA1 void pic_disable() { - // Note: We initialize the PIC properly, but completely disable it and use the APIC in favor of it. + // We initialize the PIC properly, but completely disable it and use the APIC in favor of it. // Remap IRQs so they start at 0x20 since interrupts 0x00..0x1F are used by CPU exceptions. - asm_outb(PIC1_COMMAND_PORT, 0x11); // ICW1: Begin initialization and set cascade mode. - asm_outb(PIC1_DATA_PORT, 0x20); // ICW2: Set where interrupts should be mapped to (0x20-0x27). - asm_outb(PIC1_DATA_PORT, 0x04); // ICW3: Connect IRQ2 (0x04) to the slave PIC. - asm_outb(PIC1_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode. - asm_outb(PIC1_DATA_PORT, 0xFF); // Mask all interrupts. + asm_outb(PIC1_COMMAND_PORT, 0x11); + asm_outb(PIC1_DATA_PORT, 0x20); + asm_outb(PIC1_DATA_PORT, 0x04); + asm_outb(PIC1_DATA_PORT, 0x01); + asm_outb(PIC1_DATA_PORT, 0xFF); // Same for the slave PIC. - asm_outb(PIC2_COMMAND_PORT, 0x11); // ICW1: Begin initialization. - asm_outb(PIC2_DATA_PORT, 0x28); // ICW2: Set where interrupts should be mapped to (0x28-0x2F). - asm_outb(PIC2_DATA_PORT, 0x02); // ICW3: Connect to master PIC at IRQ2. - asm_outb(PIC2_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode. - asm_outb(PIC2_DATA_PORT, 0xFF); // Mask all interrupts. + asm_outb(PIC2_COMMAND_PORT, 0x11); + asm_outb(PIC2_DATA_PORT, 0x28); + asm_outb(PIC2_DATA_PORT, 0x02); + asm_outb(PIC2_DATA_PORT, 0x01); + asm_outb(PIC2_DATA_PORT, 0xFF); } diff --git a/kernel/arch/x86_64/gdt.c b/kernel/arch/x86_64/gdt.c index 7102118..737bfb9 100644 --- a/kernel/arch/x86_64/gdt.c +++ b/kernel/arch/x86_64/gdt.c @@ -18,7 +18,7 @@ static const struct gdt main_gdt = { .user_code64 = {.val = 0x00a0fb0000000000}, .tss = { .limit0 = sizeof(struct tss) - 1, - .access = 0x89, // Present | DPL=0 | System | 64-bit TSS + .access = 0x89, // Present | DPL = 0 | System | 64-bit TSS .limit1_flags = ((sizeof(struct tss) - 1) >> 16) & 0x0F, .reserved = 0, }, diff --git a/kernel/arch/x86_64/hpet.c b/kernel/arch/x86_64/hpet.c index 4d88d0c..a96c7f2 100644 --- a/kernel/arch/x86_64/hpet.c +++ b/kernel/arch/x86_64/hpet.c @@ -53,7 +53,7 @@ void hpet_init() { uacpi_setup_early_table_access(table_buf, sizeof(table_buf)); uacpi_table table = {0}; - ASSERT(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n"); + assert(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n"); struct acpi_hpet* hpet = table.ptr; hpet_clock.regs = mmio_new(hpet->address.address, 0x1000); @@ -65,5 +65,5 @@ void hpet_init() { uint64_t caps = hpet_clock.regs[HPET_CAP]; hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF; - ASSERT(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n"); + assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n"); } diff --git a/kernel/arch/x86_64/idt.c b/kernel/arch/x86_64/idt.c index f775791..bfb1cf9 100644 --- a/kernel/arch/x86_64/idt.c +++ b/kernel/arch/x86_64/idt.c @@ -50,7 +50,7 @@ void interrupt_handler(struct arch_context* ctx) { break; case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)): struct irq_line* line = cpu->arch.irq_lines[isr - 0x20]; - ASSERT(line, "Unhandled interrupt on ISR %lu\n", isr); + assert(line, "Unhandled interrupt on ISR %lu\n", isr); // TODO: irq_raise(line); break; default: diff --git a/kernel/arch/x86_64/include/bits/sched.h b/kernel/arch/x86_64/include/bits/sched.h index 2772d26..d92c955 100644 --- a/kernel/arch/x86_64/include/bits/sched.h +++ b/kernel/arch/x86_64/include/bits/sched.h @@ -10,22 +10,27 @@ struct arch_task_context { uint64_t fs_base, gs_base; }; +#define ARCH_ABI(typ, reg, ...) \ + union { \ + typ reg, __VA_ARGS__; \ + } + struct arch_context { uint64_t r15; uint64_t r14; - uint64_t r13; - uint64_t r12; + ARCH_ABI(uint64_t, r13, a7); + ARCH_ABI(uint64_t, r12, a6); uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rsi; - uint64_t rdi; + ARCH_ABI(uint64_t, r10, a5); + ARCH_ABI(uint64_t, r9, a3); + ARCH_ABI(uint64_t, r8, a4); + ARCH_ABI(uint64_t, rsi, a1); + ARCH_ABI(uint64_t, rdi, a0); uint64_t rbp; - uint64_t rdx; + ARCH_ABI(uint64_t, rdx, a2, ret1); uint64_t rcx; uint64_t rbx; - uint64_t rax; + ARCH_ABI(uint64_t, rax, num, ret0); uint64_t isr; // Pushed onto the stack by the interrupt handler stubs. uint64_t error; // Pushed onto the stack by the CPU if the interrupt has an error code. uint64_t rip; // The rest is pushed onto the stack by the CPU during an interrupt. @@ -35,6 +40,8 @@ struct arch_context { uint64_t ss; }; +static_assert(sizeof(struct arch_context) == 176); + #define ARCH_CTX_NUM rax #define ARCH_CTX_A0 rdi #define ARCH_CTX_A1 rsi diff --git a/kernel/arch/x86_64/sched.c b/kernel/arch/x86_64/sched.c index 40421ea..cf8b32c 100644 --- a/kernel/arch/x86_64/sched.c +++ b/kernel/arch/x86_64/sched.c @@ -14,7 +14,6 @@ // The task frame consists of registers that the C ABI marks as callee-saved. // If we don't save them, these registers are lost during a context switch. -// The order of these fields is important. struct task_frame { uint64_t rbx, rbp, r12, r13, r14, r15, rip; }; diff --git a/kernel/arch/x86_64/usercopy.c b/kernel/arch/x86_64/usercopy.c index 51de76e..6f2ffe1 100644 --- a/kernel/arch/x86_64/usercopy.c +++ b/kernel/arch/x86_64/usercopy.c @@ -11,6 +11,7 @@ static const struct usercopy_region read_region = { .fault_ip = x86_64_read_fault, }; +[[__naked]] bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region) { asm volatile( "stac\n" @@ -41,7 +42,6 @@ bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct us : "i"(&read_region) : "memory" ); - return false; } extern void x86_64_write_start(); @@ -54,6 +54,7 @@ static const struct usercopy_region write_region = { .fault_ip = x86_64_write_fault, }; +[[__naked]] bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region) { asm volatile( "stac\n" @@ -84,7 +85,6 @@ bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct u : "i"(&read_region) : "memory" ); - return false; } extern void x86_64_strlen_start(); diff --git a/kernel/boot/main.c b/kernel/boot/main.c index 4633475..090f81b 100644 --- a/kernel/boot/main.c +++ b/kernel/boot/main.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -62,22 +61,22 @@ static void kernel_main_task(uintptr_t arg0) { struct boot_info* info = (struct boot_info*)arg0; kprintf("%s\n", zinnia_banner); // Say hello! - ASSERT(info->num_files >= 1, "No init executable provided\n"); + assert(info->num_files >= 1, "No init executable provided\n"); struct channel* init_ep; struct channel* other_ep; - ASSERT(channel_create(&init_ep, &other_ep) == ZN_OK, "Failed to create init channel\n"); + assert(channel_create(&init_ep, &other_ep) == ZN_OK, "Failed to create init channel\n"); struct vas* init_space; - ASSERT(vma_new(&init_space) == ZN_OK, ""); + assert(vma_new(&init_space) == ZN_OK, ""); struct boot_file* file_data = &info->files[0]; struct paged_vmo* init_file; - ASSERT(vmo_new_phys(&init_file) == ZN_OK, ""); + assert(vmo_new_phys(&init_file) == ZN_OK, ""); vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr); struct namespace* ns; - ASSERT(namespace_new(&ns) == ZN_OK, ""); + assert(namespace_new(&ns) == ZN_OK, ""); struct namespace_desc init_ch_desc = { .type = NAMESPACE_DESC_CHANNEL, @@ -91,7 +90,7 @@ static void kernel_main_task(uintptr_t arg0) { struct task* init_task; zn_status_t status = load_server(&info->files[0], init_argv, init_envp, &init_ch_desc, &init_task); - ASSERT(status == ZN_OK, "Failed to load init process (%i)\n", status); + assert(status == ZN_OK, "Failed to load init process (%i)\n", status); sched_add_task(&percpu_get()->sched, init_task); // Load other daemons. @@ -107,16 +106,10 @@ static void kernel_main_task(uintptr_t arg0) { struct task* task; status = load_server(&info->files[i], argv, envp, &ch_desc, &task); - ASSERT(status == ZN_OK, "Failed to load server \"%s\": (%i)\n", info->files[i].path, status); + assert(status == ZN_OK, "Failed to load server \"%s\": (%i)\n", info->files[i].path, status); sched_add_task(&percpu_get()->sched, task); } - struct ipc_kernel_msg* msg = mem_alloc(0x40, 0); - msg->id = IPC_MSG_BAR; - memcpy(msg->data, "This message is from the kernel!", 33); - - channel_write(other_ep, msg, 0x40, nullptr, 0); - while (true) { arch_irq_wait(); } @@ -140,7 +133,7 @@ void kernel_main(struct boot_info* info) { irq_unlock(); sched_yield(&percpu_get()->sched); - __unreachable(); + unreachable(); } [[__init]] diff --git a/kernel/core/channel.c b/kernel/core/channel.c index 399fde9..45a8fd9 100644 --- a/kernel/core/channel.c +++ b/kernel/core/channel.c @@ -21,12 +21,12 @@ zn_status_t channel_create(struct channel** ep0, struct channel** ep1) { a->peer = b; a->lock = (struct spinlock){0}; - TAILQ_INIT(&a->messages); + tailq_init(&a->messages); wait_queue_init(&a->waiters); b->peer = a; b->lock = (struct spinlock){0}; - TAILQ_INIT(&b->messages); + tailq_init(&b->messages); wait_queue_init(&b->waiters); *ep0 = a; @@ -64,7 +64,7 @@ zn_status_t channel_write( // Enqueue on the peer's message queue and wake a waiter. spin_lock(&peer->lock); - TAILQ_INSERT_TAIL(&peer->messages, msg, next); + tailq_insert_tail(&peer->messages, msg, next); spin_unlock(&peer->lock); struct sched_percpu* sched = &percpu_get()->sched; @@ -75,10 +75,10 @@ zn_status_t channel_write( zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) { spin_lock(&ch->lock); - struct channel_msg* msg = TAILQ_FIRST(&ch->messages); + struct channel_msg* msg = tailq_first(&ch->messages); if (msg != nullptr) { - TAILQ_REMOVE(&ch->messages, msg, next); + tailq_remove(&ch->messages, msg, next); spin_unlock(&ch->lock); *msg_out = msg; return ZN_OK; @@ -97,7 +97,7 @@ zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) { zn_status_t channel_poll(struct channel* ch) { spin_lock(&ch->lock); - if (!TAILQ_EMPTY(&ch->messages)) { + if (!tailq_empty(&ch->messages)) { spin_unlock(&ch->lock); return ZN_OK; } diff --git a/kernel/core/elf.c b/kernel/core/elf.c index 8a0e9a4..0ea390f 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -49,7 +49,7 @@ zn_status_t elf_load(struct exec_info* info, struct task** out) { if (phdr.p_flags & PF_X) prot |= ZN_VM_MAP_EXEC; - ASSERT(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, ""); + assert(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, ""); const uintptr_t misalign = phdr.p_vaddr & (page_size - 1); const uintptr_t map_address = phdr.p_vaddr - misalign; diff --git a/kernel/core/namespace.c b/kernel/core/namespace.c index be751d0..1e9c2a0 100644 --- a/kernel/core/namespace.c +++ b/kernel/core/namespace.c @@ -15,7 +15,7 @@ zn_status_t namespace_new(struct namespace** out) { namespace->mutex = (struct mutex){0}; namespace->next_handle = 1; - HASHMAP_INIT(&namespace->descriptors); + hashmap_init(&namespace->descriptors); *out = namespace; return ZN_OK; @@ -31,10 +31,10 @@ zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_des handle = atomic_fetch_add_explicit(&namespace->next_handle, 1, memory_order_acq_rel); if (handle <= ZN_HANDLE_INVALID) continue; - } while (HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr); + } while (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr); zn_status_t status = - HASHMAP_INSERT(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default); + hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default); if (status != ZN_OK) return status; @@ -49,10 +49,10 @@ zn_status_t namespace_add_desc_at(struct namespace* namespace, struct namespace_ return ZN_ERR_BAD_HANDLE; // Fail if a descriptor already exists at this handle. - if (HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr) + if (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr) return ZN_ERR_ALREADY_EXISTS; - return HASHMAP_INSERT(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default); + return hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default); } zn_status_t namespace_get(struct namespace* namespace, zn_handle_t handle, struct namespace_desc* out) { @@ -65,7 +65,7 @@ zn_status_t namespace_get(struct namespace* namespace, zn_handle_t handle, struc return ZN_ERR_BAD_HANDLE; struct namespace_desc* desc = - HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default); + hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default); if (!desc) return ZN_ERR_BAD_HANDLE; @@ -80,7 +80,7 @@ zn_status_t namespace_del_desc(struct namespace* namespace, zn_handle_t handle) if (handle <= ZN_HANDLE_INVALID) return ZN_ERR_BAD_HANDLE; - if (!HASHMAP_REMOVE(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default)) + if (!hashmap_remove(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default)) return ZN_ERR_BAD_HANDLE; return ZN_OK; diff --git a/kernel/core/sched.c b/kernel/core/sched.c index 30b03b4..63b6c68 100644 --- a/kernel/core/sched.c +++ b/kernel/core/sched.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -35,30 +35,30 @@ void sched_to_user_context(uintptr_t ctx) { void sched_init(struct sched_percpu* sched) { struct task* idle_task; - ASSERT( + assert( task_create("idle", &kernel_vas, nullptr, idle_func, 0, &idle_task) == ZN_OK, "Unable to create idle task!\n" ); sched->idle_task = idle_task; sched->current = idle_task; - TAILQ_INIT(&sched->run_queue); + tailq_init(&sched->run_queue); kprintf("Scheduler initialized\n"); } void sched_add_task(struct sched_percpu* sched, struct task* task) { - ASSERT(task != nullptr, "Tried to add NULL to the run queue\n"); - TAILQ_INSERT_TAIL(&sched->run_queue, task, next); + assert(task != nullptr, "Tried to add NULL to the run queue\n"); + tailq_insert_tail(&sched->run_queue, task, next); } static struct task* next_task(struct sched_percpu* sched) { - struct task* t = TAILQ_FIRST(&sched->run_queue); + struct task* t = tailq_first(&sched->run_queue); if (t == nullptr) return sched->idle_task; - TAILQ_REMOVE(&sched->run_queue, t, next); + tailq_remove(&sched->run_queue, t, next); return t; } @@ -143,7 +143,7 @@ void task_entry(task_fn_t entry, uintptr_t arg0) { } void wait_queue_init(struct wait_queue* wq) { - TAILQ_INIT(&wq->waiters); + tailq_init(&wq->waiters); wq->lock = (struct spinlock){0}; } @@ -152,7 +152,7 @@ void sched_block(struct sched_percpu* sched, struct wait_queue* wq) { spin_lock(&wq->lock); sched->current->state = TASK_STATE_BLOCKED; - TAILQ_INSERT_TAIL(&wq->waiters, sched->current, next); + tailq_insert_tail(&wq->waiters, sched->current, next); spin_unlock(&wq->lock); do_reschedule(sched); @@ -161,9 +161,9 @@ void sched_block(struct sched_percpu* sched, struct wait_queue* wq) { void sched_wake(struct sched_percpu* sched, struct wait_queue* wq) { spin_lock(&wq->lock); - struct task* t = TAILQ_FIRST(&wq->waiters); + struct task* t = tailq_first(&wq->waiters); if (t != nullptr) { - TAILQ_REMOVE(&wq->waiters, t, next); + tailq_remove(&wq->waiters, t, next); t->state = TASK_STATE_READY; sched_add_task(sched, t); } @@ -175,8 +175,8 @@ void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq) { spin_lock(&wq->lock); struct task* t; - while ((t = TAILQ_FIRST(&wq->waiters)) != nullptr) { - TAILQ_REMOVE(&wq->waiters, t, next); + while ((t = tailq_first(&wq->waiters)) != nullptr) { + tailq_remove(&wq->waiters, t, next); t->state = TASK_STATE_READY; sched_add_task(sched, t); } diff --git a/kernel/core/spin.c b/kernel/core/spin.c index 8af43d5..331fa05 100644 --- a/kernel/core/spin.c +++ b/kernel/core/spin.c @@ -1,16 +1,15 @@ #include #include -// TODO: Ticketing system - void spin_lock(struct spinlock* spin) { - while (atomic_exchange_explicit(&spin->locked, true, memory_order_acquire)) { + uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed); + + while (atomic_load_explicit(&spin->owner, memory_order_acquire) != my) { asm volatile("pause"); } - - atomic_store_explicit(&spin->locked, true, memory_order_release); } void spin_unlock(struct spinlock* spin) { - atomic_store_explicit(&spin->locked, false, memory_order_release); + uint32_t val = atomic_load_explicit(&spin->owner, memory_order_relaxed); + atomic_store_explicit(&spin->owner, val + 1, memory_order_release); } diff --git a/kernel/include/kernel/assert.h b/kernel/include/assert.h similarity index 71% rename from kernel/include/kernel/assert.h rename to kernel/include/assert.h index 23bad3b..0162604 100644 --- a/kernel/include/kernel/assert.h +++ b/kernel/include/assert.h @@ -3,7 +3,8 @@ #include #include -#define ASSERT(expr, msg, ...) \ +// Like the standard C assert, but also active in debug builds. +#define assert(expr, msg, ...) \ ({ \ if (__unlikely(!(expr))) { \ panic( \ @@ -19,7 +20,7 @@ }) #ifndef NDEBUG -#define DEBUG_ASSERT(...) ASSERT(__VA_ARGS__) +#define debug_assert(...) assert(__VA_ARGS__) #else -#define DEBUG_ASSERT(...) ((void)0) +#define debug_assert(...) ((void)0) #endif diff --git a/kernel/include/kernel/channel.h b/kernel/include/kernel/channel.h index b16275a..70ad715 100644 --- a/kernel/include/kernel/channel.h +++ b/kernel/include/kernel/channel.h @@ -13,13 +13,13 @@ struct channel_msg { size_t num_bytes; struct namespace_desc* descs; size_t num_handles; - TAILQ_LINK(struct channel_msg) next; + tailq_link(struct channel_msg) next; }; struct channel { struct channel* peer; struct spinlock lock; - TAILQ_HEAD(struct channel_msg) messages; + tailq_head(struct channel_msg) messages; struct wait_queue waiters; }; diff --git a/kernel/include/kernel/hashmap.h b/kernel/include/kernel/hashmap.h index 32b951b..34ac9ca 100644 --- a/kernel/include/kernel/hashmap.h +++ b/kernel/include/kernel/hashmap.h @@ -25,7 +25,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) // Ensure a hash is never zero (zero is the empty sentinel). #define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h)) -#define HASHMAP(K, V) \ +#define hashmap(K, V) \ struct { \ K* keys; \ V* values; \ @@ -34,7 +34,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) size_t count; \ } -#define HASHMAP_INIT(map) \ +#define hashmap_init(map) \ do { \ (map)->keys = nullptr; \ (map)->values = nullptr; \ @@ -43,7 +43,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) (map)->count = 0; \ } while (0) -#define HASHMAP_DESTROY(map) \ +#define hashmap_destroy(map) \ do { \ mem_free((map)->keys); \ mem_free((map)->values); \ @@ -55,7 +55,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) (map)->count = 0; \ } while (0) -#define HASHMAP_COUNT(map) ((map)->count) +#define hashmap_count(map) ((map)->count) // Internal: probe distance from ideal position. #define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1)) @@ -116,10 +116,10 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) } \ } while (0) -// Insert or update a key-value pair. Returns ZN_OK or ZN_ERR_NO_MEMORY. -#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \ +// Insert or update a key-value pair. Returns 0 or ZN_ERR_NO_MEMORY. +#define hashmap_insert(map, key, val, hash_fn, eq_fn) \ ({ \ - zn_status_t _status = ZN_OK; \ + zn_status_t _status = 0; \ typeof(*(map)->keys) _k = (key); \ uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \ /* Check for existing key first. */ \ @@ -147,7 +147,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) _status = ZN_ERR_NO_MEMORY; \ } \ } \ - if (_status == ZN_OK) { \ + if (_status == 0) { \ _HASHMAP_INSERT_INNER(map, _k, (val), _h); \ } \ } \ @@ -155,7 +155,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) }) // Look up a key. Returns a pointer to the value, or nullptr if not found. -#define HASHMAP_GET(map, key, hash_fn, eq_fn) \ +#define hashmap_get(map, key, hash_fn, eq_fn) \ ({ \ typeof(*(map)->values)* _result = nullptr; \ if ((map)->capacity > 0) { \ @@ -180,7 +180,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) // Remove a key. Returns true if the key was found and removed. // Uses backward-shift deletion to avoid tombstones. -#define HASHMAP_REMOVE(map, key, hash_fn, eq_fn) \ +#define hashmap_remove(map, key, hash_fn, eq_fn) \ ({ \ bool _removed = false; \ if ((map)->capacity > 0) { \ @@ -218,6 +218,6 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) // Iterate over all occupied entries. `idx` is a size_t loop variable. // Access keys and values via (map)->keys[idx] and (map)->values[idx]. -#define HASHMAP_FOREACH(map, idx) \ +#define hashmap_foreach(map, idx) \ for (size_t idx = 0; idx < (map)->capacity; idx++) \ if ((map)->hashes[idx] != 0) diff --git a/kernel/include/kernel/irq.h b/kernel/include/kernel/irq.h index 8792ad3..9bdb287 100644 --- a/kernel/include/kernel/irq.h +++ b/kernel/include/kernel/irq.h @@ -22,7 +22,7 @@ enum irq_trigger_mode : uint8_t { struct irq_handler { enum irq_status (*handler)(void* self); - SLIST_LINK(struct irq_handler*) next; + list_link(struct irq_handler*) next; }; struct irq_line { @@ -31,7 +31,7 @@ struct irq_line { void (*unmask)(struct irq_line* self); void (*eoi)(struct irq_line* self); - SLIST_HEAD(struct irq_handler*) handlers; + list_head(struct irq_handler*) handlers; bool is_busy; }; diff --git a/kernel/include/kernel/list.h b/kernel/include/kernel/list.h index b0e8329..d7c2114 100644 --- a/kernel/include/kernel/list.h +++ b/kernel/include/kernel/list.h @@ -1,29 +1,29 @@ #pragma once -#define SLIST_HEAD(type) \ +#define list_head(type) \ struct { \ - type sl_head; \ + type _sl_head; \ } -#define SLIST_LINK(type) \ +#define list_link(type) \ struct { \ - type sl_link; \ + type _sl_link; \ } -#define SLIST_EMPTY(head) ((head)->sl_head == NULL) -#define SLIST_FIRST(head) ((head)->sl_head) -#define SLIST_NEXT(elm, field) ((elm)->field.sl_link) +#define list_is_empty(head) ((head)->_sl_head == NULL) +#define list_first(head) ((head)->_sl_head) +#define list_next(elm, field) ((elm)->field._sl_link) -#define SLIST_INSERT_END(slistelm, elm, field) \ +#define list_insert_end(slistelm, elm, field) \ do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ + list_next((elm), field) = list_next((slistelm), field); \ + list_next((slistelm), field) = (elm); \ } while (0) -#define SLIST_INSERT_HEAD(head, elm, field) \ +#define list_insert_head(head, elm, field) \ do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ + list_next((elm), field) = list_first((head)); \ + list_first((head)) = (elm); \ } while (0) -#define SLIST_FOREACH(var, head, field) for ((var) = SLIST_FIRST((head)); (var); (var) = SLIST_NEXT((var), field)) +#define list_foreach(var, head, field) for ((var) = list_first((head)); (var); (var) = list_next((var), field)) diff --git a/kernel/include/kernel/namespace.h b/kernel/include/kernel/namespace.h index 3c07293..19c985e 100644 --- a/kernel/include/kernel/namespace.h +++ b/kernel/include/kernel/namespace.h @@ -32,7 +32,7 @@ struct namespace_desc { struct namespace { zn_handle_t next_handle; struct mutex mutex; - HASHMAP(zn_handle_t, struct namespace_desc) descriptors; + hashmap(zn_handle_t, struct namespace_desc) descriptors; }; // Creates a new namespace with no contents. diff --git a/kernel/include/kernel/sched.h b/kernel/include/kernel/sched.h index 06bf79c..7cffab7 100644 --- a/kernel/include/kernel/sched.h +++ b/kernel/include/kernel/sched.h @@ -38,7 +38,7 @@ struct task { size_t time_slice; int8_t priority; - TAILQ_LINK(struct task) next; + tailq_link(struct task) next; }; // Per-CPU data for scheduling. @@ -46,7 +46,7 @@ struct sched_percpu { struct task* current; struct task* idle_task; size_t preempt_level; - TAILQ_HEAD(struct task) run_queue; + tailq_head(struct task) run_queue; }; // Blocks the current task on the given wait queue. diff --git a/kernel/include/kernel/spin.h b/kernel/include/kernel/spin.h index 41d3ef5..0372df8 100644 --- a/kernel/include/kernel/spin.h +++ b/kernel/include/kernel/spin.h @@ -1,9 +1,12 @@ #pragma once +#include + // Busy-waits in a loop until the lock is freed. // Does not put the CPU to sleep. struct spinlock { - bool locked; + uint32_t owner; + uint32_t next; }; // Attempts to lock a spinlock. If it's already locked, waits until it's freed. diff --git a/kernel/include/kernel/tailq.h b/kernel/include/kernel/tailq.h index 64a123b..bd7e4f3 100644 --- a/kernel/include/kernel/tailq.h +++ b/kernel/include/kernel/tailq.h @@ -1,30 +1,30 @@ #pragma once -#define TAILQ_HEAD(type) \ +#define tailq_head(type) \ struct { \ type* tqh_first; \ type** tqh_last; \ } -#define TAILQ_LINK(type) \ +#define tailq_link(type) \ struct { \ type* tqe_next; \ type** tqe_prev; \ } -#define TAILQ_INIT(head) \ +#define tailq_init(head) \ do { \ (head)->tqh_first = nullptr; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) -#define TAILQ_FIRST(head) ((head)->tqh_first) +#define tailq_first(head) ((head)->tqh_first) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define tailq_next(elm, field) ((elm)->field.tqe_next) -#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == nullptr) +#define tailq_empty(head) (tailq_first(head) == nullptr) -#define TAILQ_INSERT_TAIL(head, elm, field) \ +#define tailq_insert_tail(head, elm, field) \ do { \ (elm)->field.tqe_next = nullptr; \ (elm)->field.tqe_prev = (head)->tqh_last; \ @@ -32,7 +32,7 @@ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) -#define TAILQ_INSERT_HEAD(head, elm, field) \ +#define tailq_insert_head(head, elm, field) \ do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != nullptr) \ (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \ @@ -42,7 +42,7 @@ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) -#define TAILQ_REMOVE(head, elm, field) \ +#define tailq_remove(head, elm, field) \ do { \ if (((elm)->field.tqe_next) != nullptr) \ (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \ diff --git a/kernel/include/kernel/vec.h b/kernel/include/kernel/vec.h index d1d269a..407b0e6 100644 --- a/kernel/include/kernel/vec.h +++ b/kernel/include/kernel/vec.h @@ -1,25 +1,24 @@ #pragma once -#include #include -#include -#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep -#define VEC(T) \ +#define vec(T) \ struct { \ T* data; \ size_t length; \ size_t capacity; \ } -#define VEC_INIT(vec) \ +#define vec_init(vec) \ do { \ (vec)->data = nullptr; \ (vec)->length = 0; \ (vec)->capacity = 0; \ } while (0) -#define VEC_DESTROY(vec) \ +#define vec_destroy(vec) \ do { \ mem_free((vec)->data); \ (vec)->data = nullptr; \ @@ -27,13 +26,13 @@ (vec)->capacity = 0; \ } while (0) -#define VEC_LENGTH(vec) ((vec)->length) -#define VEC_CAPACITY(vec) ((vec)->capacity) -#define VEC_EMPTY(vec) ((vec)->length == 0) -#define VEC_AT(vec, i) ((vec)->data[i]) +#define vec_length(vec) ((vec)->length) +#define vec_capacity(vec) ((vec)->capacity) +#define vec_empty(vec) ((vec)->length == 0) +#define vec_at(vec, i) ((vec)->data[i]) // Internal: grow to at least `needed` capacity. -#define _VEC_GROW(vec, needed) \ +#define _vec_grow(vec, needed) \ do { \ size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \ while (_new_cap < (needed)) \ @@ -46,34 +45,34 @@ (vec)->capacity = _new_cap; \ } while (0) -// Append an element. Returns ZN_OK or ZN_ERR_NO_MEMORY. -#define VEC_PUSH(vec, val) \ +// Append an element. Returns 0 or ZN_ERR_NO_MEMORY. +#define vec_push(vec, val) \ ({ \ - zn_status_t _status = ZN_OK; \ + zn_status_t _status = 0; \ if ((vec)->length >= (vec)->capacity) { \ - _VEC_GROW(vec, (vec)->length + 1); \ + _vec_grow(vec, (vec)->length + 1); \ if ((vec)->data == nullptr) \ _status = ZN_ERR_NO_MEMORY; \ } \ - if (_status == ZN_OK) \ + if (_status == 0) \ (vec)->data[(vec)->length++] = (val); \ _status; \ }) // Remove and return the last element. Undefined if empty. -#define VEC_POP(vec) ((vec)->data[--(vec)->length]) +#define vec_pop(vec) ((vec)->data[--(vec)->length]) -// Insert at index, shifting subsequent elements right. Returns ZN_OK or ZN_ERR_NO_MEMORY. -#define VEC_INSERT(vec, i, val) \ +// Insert at index, shifting subsequent elements right. Returns 0 or ZN_ERR_NO_MEMORY. +#define vec_insert(vec, i, val) \ ({ \ - zn_status_t _status = ZN_OK; \ + zn_status_t _status = 0; \ size_t _idx = (i); \ if ((vec)->length >= (vec)->capacity) { \ - _VEC_GROW(vec, (vec)->length + 1); \ + _vec_grow(vec, (vec)->length + 1); \ if ((vec)->data == nullptr) \ _status = ZN_ERR_NO_MEMORY; \ } \ - if (_status == ZN_OK) { \ + if (_status == 0) { \ memmove(&(vec)->data[_idx + 1], &(vec)->data[_idx], ((vec)->length - _idx) * sizeof(*(vec)->data)); \ (vec)->data[_idx] = (val); \ (vec)->length++; \ @@ -82,7 +81,7 @@ }) // Remove element at index, shifting subsequent elements left. -#define VEC_REMOVE(vec, i) \ +#define vec_remove(vec, i) \ do { \ size_t _idx = (i); \ (vec)->length--; \ @@ -91,7 +90,7 @@ } while (0) // Remove element at index by swapping with the last element (O(1), unordered). -#define VEC_SWAP_REMOVE(vec, i) \ +#define vec_swap_remove(vec, i) \ do { \ size_t _idx = (i); \ (vec)->length--; \ @@ -100,6 +99,6 @@ } while (0) // Clear all elements without freeing memory. -#define VEC_CLEAR(vec) ((vec)->length = 0) +#define vec_clear(vec) ((vec)->length = 0) -#define VEC_FOREACH(vec, idx) for (size_t idx = 0; idx < (vec)->length; idx++) +#define vec_foreach(vec, idx) for (size_t idx = 0; idx < (vec)->length; idx++) diff --git a/kernel/include/kernel/vmo.h b/kernel/include/kernel/vmo.h index 854d35d..6f88646 100644 --- a/kernel/include/kernel/vmo.h +++ b/kernel/include/kernel/vmo.h @@ -30,13 +30,13 @@ struct pager_ops { struct page_list { uintptr_t offset; struct page* value; - SLIST_LINK(struct page_list*) next; + list_link(struct page_list*) next; }; struct paged_vmo { struct vmo object; struct pager_ops source; - SLIST_HEAD(struct page_list*) cache; + list_head(struct page_list*) cache; struct spinlock lock; }; diff --git a/kernel/include/kernel/wait.h b/kernel/include/kernel/wait.h index 40bbf15..ff90d58 100644 --- a/kernel/include/kernel/wait.h +++ b/kernel/include/kernel/wait.h @@ -7,7 +7,7 @@ struct task; // A queue of tasks waiting for an event. struct wait_queue { - TAILQ_HEAD(struct task) waiters; + tailq_head(struct task) waiters; struct spinlock lock; }; diff --git a/kernel/include/stdarg.h b/kernel/include/stdarg.h index e1e7566..af6bebe 100644 --- a/kernel/include/stdarg.h +++ b/kernel/include/stdarg.h @@ -1,10 +1,7 @@ -#ifndef ZINNIA_STDARG_H -#define ZINNIA_STDARG_H +#pragma once typedef __builtin_va_list va_list; #define va_start(v, l) __builtin_va_start(v, l) #define va_end(v) __builtin_va_end(v) #define va_arg(v, T) __builtin_va_arg(v, T) #define va_copy(d, s) __builtin_va_copy(d, s) - -#endif diff --git a/kernel/include/stdatomic.h b/kernel/include/stdatomic.h index 84b4f72..a34720f 100644 --- a/kernel/include/stdatomic.h +++ b/kernel/include/stdatomic.h @@ -1,5 +1,4 @@ -#ifndef ZINNIA_STDATOMIC_H -#define ZINNIA_STDATOMIC_H +#pragma once typedef enum memory_order { memory_order_relaxed = __ATOMIC_RELAXED, @@ -35,5 +34,3 @@ typedef enum memory_order { #define atomic_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST) #define atomic_thread_fence(ord) __atomic_thread_fence(ord) - -#endif diff --git a/kernel/include/stddef.h b/kernel/include/stddef.h index 3ca0f43..803d089 100644 --- a/kernel/include/stddef.h +++ b/kernel/include/stddef.h @@ -1,9 +1,7 @@ -#ifndef ZINNIA_STDDEF_H -#define ZINNIA_STDDEF_H +#pragma once typedef unsigned long size_t; typedef signed long ssize_t; #define offsetof(type, member) __builtin_offsetof(type, member) - -#endif +#define unreachable() __builtin_unreachable() diff --git a/kernel/include/stdint.h b/kernel/include/stdint.h index 996433c..ad5745c 100644 --- a/kernel/include/stdint.h +++ b/kernel/include/stdint.h @@ -1,5 +1,4 @@ -#ifndef ZINNIA_STDINT_H -#define ZINNIA_STDINT_H +#pragma once typedef __INT8_TYPE__ int8_t; typedef __UINT8_TYPE__ uint8_t; @@ -25,5 +24,3 @@ typedef __INTPTR_TYPE__ intptr_t; typedef __UINTPTR_TYPE__ uintptr_t; #define INTPTR_MAX __INTPTR_MAX__ #define UINTPTR_MAX __UINTPTR_MAX__ - -#endif diff --git a/kernel/include/stdlib.h b/kernel/include/stdlib.h index 5619463..2b7814e 100644 --- a/kernel/include/stdlib.h +++ b/kernel/include/stdlib.h @@ -1,7 +1,4 @@ -#ifndef ZINNIA_STDLIB_H -#define ZINNIA_STDLIB_H +#pragma once long atol(const char* str, int base); unsigned long atolu(const char* str, int base); - -#endif diff --git a/kernel/include/string.h b/kernel/include/string.h index 835963e..f4792eb 100644 --- a/kernel/include/string.h +++ b/kernel/include/string.h @@ -1,5 +1,4 @@ -#ifndef ZINNIA_STRING_H -#define ZINNIA_STRING_H +#pragma once #include @@ -13,5 +12,3 @@ char* strncpy(char* restrict dst, const char* restrict src, size_t len); int strcmp(const char* str1, const char* str2); int strncmp(const char* str1, const char* str2, size_t len); char* strchr(const char* c, int s); - -#endif diff --git a/kernel/mem/init.c b/kernel/mem/init.c index 94af33f..a45abd7 100644 --- a/kernel/mem/init.c +++ b/kernel/mem/init.c @@ -1,11 +1,11 @@ #include #include -#include #include #include #include #include #include +#include #include extern uint8_t __ld_text_start[]; @@ -66,7 +66,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ // since we're likely going to map it at a different base address. mem_hhdm_base = tmp_hhdm; - ASSERT(pmap_new_kernel(&kernel_vas.pmap, 0) == 0, "Unable to allocate the kernel page table\n"); + assert(pmap_new_kernel(&kernel_vas.pmap, 0) == 0, "Unable to allocate the kernel page table\n"); // text kprintf("Mapping text segment at %p\n", __ld_text_start); @@ -78,7 +78,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ PTE_READ | PTE_EXEC, CACHE_NONE ); - ASSERT(!status, "Failed to map %p with error %i\n", p, status); + assert(!status, "Failed to map %p with error %i\n", p, status); } // rodata @@ -91,7 +91,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ PTE_READ, CACHE_NONE ); - ASSERT(!status, "Failed to map %p with error %i\n", p, status); + assert(!status, "Failed to map %p with error %i\n", p, status); } // data @@ -104,7 +104,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ PTE_READ | PTE_WRITE, CACHE_NONE ); - ASSERT(!status, "Failed to map %p with error %i\n", p, status); + assert(!status, "Failed to map %p with error %i\n", p, status); } // The kernel address space is divided into 3 segments (plus kernel). @@ -122,7 +122,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm); phys_t paddr = (phys_t)(map[i].address + p); zn_status_t status = pmap_map(&kernel_vas.pmap, vaddr, paddr, PTE_READ | PTE_WRITE, CACHE_NONE); - ASSERT(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status); + assert(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status); } } mem_hhdm_base = tmp_hhdm; @@ -150,7 +150,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ for (size_t page = 0; page < length; page += pgsz) { phys_t paddr; - ASSERT(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n"); + assert(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n"); pmap_map(&kernel_vas.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_NONE); } } diff --git a/kernel/mem/meson.build b/kernel/mem/meson.build index c12d046..5bf1b93 100644 --- a/kernel/mem/meson.build +++ b/kernel/mem/meson.build @@ -6,6 +6,6 @@ kernel_sources += files( 'slab.c', 'usercopy.c', 'virt.c', - 'vas.c', + 'vma.c', 'vmo.c', ) diff --git a/kernel/mem/vas.c b/kernel/mem/vma.c similarity index 97% rename from kernel/mem/vas.c rename to kernel/mem/vma.c index d877db8..6be4e84 100644 --- a/kernel/mem/vas.c +++ b/kernel/mem/vma.c @@ -1,12 +1,12 @@ #include #include #include -#include #include +#include // Try to create a new, empty virtual address space. zn_status_t vma_new(struct vas** out) { - DEBUG_ASSERT(out != nullptr, "Missing out"); + debug_assert(out != nullptr, "Missing out"); zn_status_t res; if (!out) diff --git a/kernel/mem/vmo.c b/kernel/mem/vmo.c index 138c43d..0f6704a 100644 --- a/kernel/mem/vmo.c +++ b/kernel/mem/vmo.c @@ -105,7 +105,7 @@ static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct // Try to find the requested page in the cache. struct page_list* iter; - SLIST_FOREACH(iter, &paged->cache, next) { + list_foreach(iter, &paged->cache, next) { if (iter->offset != offset_idx) continue; @@ -128,7 +128,7 @@ static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct entry->value = new_page; // Add page to the object cache. - SLIST_INSERT_HEAD(&paged->cache, entry, next); + list_insert_head(&paged->cache, entry, next); *out = new_page; return ZN_OK; diff --git a/kernel/syscalls/dispatch.c b/kernel/syscalls/dispatch.c index d90ed19..df7f91b 100644 --- a/kernel/syscalls/dispatch.c +++ b/kernel/syscalls/dispatch.c @@ -33,12 +33,12 @@ static const syscall_fn_t dispatch_table[] = { }; void syscall_dispatch(struct arch_context* ctx) { - const size_t num = ctx->ARCH_CTX_NUM; + const size_t num = ctx->num; if (num >= ARRAY_SIZE(dispatch_table)) { - ctx->ARCH_CTX_RET0 = ZN_ERR_BAD_SYSCALL; + ctx->ret0 = ZN_ERR_BAD_SYSCALL; return; } - ctx->ARCH_CTX_RET0 = dispatch_table[num](ctx); + ctx->ret0 = dispatch_table[num](ctx); } diff --git a/kernel/syscalls/thread.c b/kernel/syscalls/thread.c index ce80663..0b82858 100644 --- a/kernel/syscalls/thread.c +++ b/kernel/syscalls/thread.c @@ -10,6 +10,7 @@ #include #include #include +#include #include zn_status_t syscall_thread_create(struct arch_context* ctx) { @@ -114,5 +115,5 @@ zn_status_t syscall_thread_exit(struct arch_context* ctx) { struct sched_percpu* sched = &percpu_get()->sched; sched->current->state = TASK_STATE_DEAD; sched_yield(sched); - __unreachable(); + unreachable(); } diff --git a/meson.build b/meson.build index bc7467a..41ae675 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'zinnia', license: 'MIT', - version: '0.1.0', + version: '0.3.0', meson_version: '>=1.1.0', default_options: [ 'c_std=gnu23', diff --git a/servers/devd/main.c b/servers/devd/main.c index 962bd41..182ef73 100644 --- a/servers/devd/main.c +++ b/servers/devd/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -22,7 +21,7 @@ static void zn_printf(const char* msg, ...) { int main(int argc, char* argv[], char* envp[]) { zn_printf("devd: starting...\n"); - zn_handle_t channel = getauxval(AT_INIT_HANDLE); + zn_handle_t channel = getauxval(0x1000); // while (true) {} uacpi_status status = uacpi_initialize(0); diff --git a/servers/initd/main.c b/servers/initd/main.c index 52fceea..ab5b195 100644 --- a/servers/initd/main.c +++ b/servers/initd/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -12,6 +11,7 @@ #include #include #include +#include #define ZN_ASSERT(expr) \ do { \ @@ -31,38 +31,18 @@ static void zn_printf(const char* msg, ...) { int32_t len = vsnprintf(buf, sizeof(buf), msg, args); va_end(args); - zn_log(buf, len); + write(1, buf, len); + // zn_log(buf, len); } int main(int argc, char* argv[], char* envp[]) { zn_printf("initd: starting...\n"); - zn_handle_t channel = getauxval(AT_INIT_HANDLE); + zn_handle_t channel = getauxval(0x1000); while (true) { static thread_local zn_handle_t handles[32]; static thread_local char buf[1024]; ZN_ASSERT(zn_channel_read(channel, handles, buf, ARRAY_SIZE(handles), ARRAY_SIZE(buf), nullptr, nullptr)); - - enum ipc_msg_id* msg = (enum ipc_msg_id*)buf; - switch (*msg) { - case IPC_MSG_FOO: { - struct ipc_init_register_rq* foo = (struct ipc_init_register_rq*)msg; - - char buf[32] = {0}; - IPC_GET_STRING(foo->data, &foo->name, buf); - - zn_printf("initd: ipc_init_register_rq, peer = \"%s\"\n", buf); - } break; - case IPC_MSG_BAR: { - struct ipc_kernel_msg* foo = (struct ipc_kernel_msg*)msg; - - char buf[32] = {0}; - IPC_GET_STRING(foo->data, &foo->name, buf); - zn_printf("initd: ipc_kernel_msg, msg = \"%s\"\n", buf); - } break; - case IPC_MSG_BAZ: - break; - } } } diff --git a/servers/meson.build b/servers/meson.build index 48cb863..a92b916 100644 --- a/servers/meson.build +++ b/servers/meson.build @@ -1,3 +1,3 @@ subdir('initd') subdir('devd') -subdir('posixd') +subdir('unix') diff --git a/servers/posixd/include/vfs.h b/servers/unix/include/vfs.h similarity index 100% rename from servers/posixd/include/vfs.h rename to servers/unix/include/vfs.h diff --git a/servers/posixd/main.c b/servers/unix/main.c similarity index 62% rename from servers/posixd/main.c rename to servers/unix/main.c index e142b3c..853d131 100644 --- a/servers/posixd/main.c +++ b/servers/unix/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -29,38 +28,45 @@ static void zn_printf(const char* msg, ...) { zn_handle_t channel; -int other_fn(void* arg) { - zn_printf("posixd: Hello from the other thread named \"%s\"!\n", (const char*)arg); - channel = getauxval(AT_INIT_HANDLE); +struct message { + size_t id; +}; - struct ipc_init_register_rq msg = { - .id = IPC_MSG_FOO, - }; +#define MSG_HI \ + IPC_START \ + IPC_STRING \ + IPC_END + +int other_fn(void* arg) { + zn_printf("unix: Hello from the other thread named \"%s\"!\n", (const char*)arg); + channel = getauxval(0x1000); + + struct message msg = {.id = 1}; char name[] = "posixd"; zn_status_t status = zn_channel_write(channel, nullptr, &msg, 0, sizeof(msg) + sizeof(name)); if (status != ZN_OK) { - zn_printf("posixd: %s\n", zn_status_to_string(status)); + zn_printf("unix: %s\n", zn_status_to_string(status)); } return 69; } int main(int argc, char* argv[], char* envp[]) { - zn_printf("posixd: starting...\n"); - const char* thread_name = "posix_second_thread"; + zn_printf("unix: starting...\n"); + const char* thread_name = "unix_second_thread"; thrd_t thread; int res = thrd_create(&thread, other_fn, (void*)thread_name); if (res != thrd_success) - zn_printf("posixd: errno: %s\n", strerror(errno)); - zn_printf("posixd: second thread created\n"); + zn_printf("unix: errno: %s\n", strerror(errno)); + zn_printf("unix: second thread created\n"); int res2; - zn_printf("posixd: waiting on second thread...\n"); + zn_printf("unix: waiting on second thread...\n"); thrd_join(thread, &res2); - zn_printf("posixd: second thread exited with: %i\n", res2); + zn_printf("unix: second thread exited with: %i\n", res2); return 0; } diff --git a/servers/posixd/meson.build b/servers/unix/meson.build similarity index 93% rename from servers/posixd/meson.build rename to servers/unix/meson.build index d2e2e6f..3569570 100644 --- a/servers/posixd/meson.build +++ b/servers/unix/meson.build @@ -1,7 +1,7 @@ configure_file(configuration: cfg, output: 'config.h') executable( - 'posixd', + 'unix', 'main.c', 'uname.c', link_args: '-static', diff --git a/servers/posixd/uname.c b/servers/unix/uname.c similarity index 100% rename from servers/posixd/uname.c rename to servers/unix/uname.c diff --git a/subprojects/.wraplock b/subprojects/.wraplock new file mode 100644 index 0000000..e69de29 diff --git a/subprojects/uacpi b/subprojects/uacpi index e05715b..9c9b26d 160000 --- a/subprojects/uacpi +++ b/subprojects/uacpi @@ -1 +1 @@ -Subproject commit e05715b2e6a3ae913aecdb86f4fd2dba30304e45 +Subproject commit 9c9b26d6291a1cdd9014cc5bb6b03e596697cbfd