From 6e92817f3f560861c255f802658c5f135479083b Mon Sep 17 00:00:00 2001 From: Marvin Friedrich Date: Fri, 25 Sep 2026 15:39:16 +0200 Subject: [PATCH] cleanup --- arch/x86_64/archctl.c | 21 +++++-- arch/x86_64/gdt.c | 7 ++- arch/x86_64/idt.c | 6 +- arch/x86_64/include/{bits => x86_64}/percpu.h | 2 + arch/x86_64/mem.c | 5 ++ arch/x86_64/percpu.c | 26 +++++--- arch/x86_64/sched.c | 5 +- arch/x86_64/syscall.c | 1 + boot/cmdline.c | 7 ++- boot/kernel.ld | 3 +- boot/limine/entry.c | 4 +- boot/main.c | 10 ++- core/lib/string.c | 8 +-- core/meson.build | 1 - core/percpu.c | 2 +- core/syscalls/archctl.c | 6 -- core/syscalls/getuname.c | 33 ---------- dev/acpi/include/zinnia/acpi.h | 8 +++ dev/acpi/init.c | 13 ++++ dev/acpi/meson.build | 19 +++--- dev/acpi/uacpi_glue.c | 8 ++- include/arch/archctl.h | 2 +- include/arch/mem.h | 16 +++++ include/uapi/utsname.h | 2 +- include/zinnia/atomic.h | 19 ++---- include/zinnia/compiler.h | 9 +-- include/zinnia/init.h | 10 ++- include/zinnia/percpu.h | 52 +++++++-------- include/zinnia/syscall_list.inc | 4 +- include/zinnia/tailq.h | 28 ++++----- meson.build | 19 +++--- syscalls/archctl.c | 6 ++ {core/syscalls => syscalls}/dispatch.c | 1 + {core/syscalls => syscalls}/meson.build | 2 +- syscalls/uname.c | 63 +++++++++++++++++++ 35 files changed, 271 insertions(+), 157 deletions(-) rename arch/x86_64/include/{bits => x86_64}/percpu.h (90%) delete mode 100644 core/syscalls/archctl.c delete mode 100644 core/syscalls/getuname.c create mode 100644 dev/acpi/include/zinnia/acpi.h create mode 100644 dev/acpi/init.c create mode 100644 syscalls/archctl.c rename {core/syscalls => syscalls}/dispatch.c (98%) rename {core/syscalls => syscalls}/meson.build (77%) create mode 100644 syscalls/uname.c diff --git a/arch/x86_64/archctl.c b/arch/x86_64/archctl.c index 730a84f..d8d863d 100644 --- a/arch/x86_64/archctl.c +++ b/arch/x86_64/archctl.c @@ -1,19 +1,32 @@ #include +#include #include +#include #include #include #include -errno_t arch_archctl(uintptr_t op, uintptr_t arg) { +struct syscall_ret arch_archctl(uintptr_t op, uintptr_t arg) { + struct syscall_ret ret = {}; + switch (op) { case __ARCHCTL_SET_FSBASE: + if (!arch_mem_addr_is_user(arg)) { + ret.errno = EINVAL; + return ret; + } asm_wrmsr(MSR_FS_BASE, arg); - return 0; + return ret; case __ARCHCTL_SET_GSBASE: + if (!arch_mem_addr_is_user(arg)) { + ret.errno = EINVAL; + return ret; + } // Update the inactive GSBASE MSR, not ours. asm_wrmsr(MSR_KERNEL_GS_BASE, arg); - return 0; + return ret; default: - return EINVAL; + ret.errno = EINVAL; + return ret; } } diff --git a/arch/x86_64/gdt.c b/arch/x86_64/gdt.c index 78e4371..bd0c333 100644 --- a/arch/x86_64/gdt.c +++ b/arch/x86_64/gdt.c @@ -4,10 +4,11 @@ #include #include #include +#include #include static const struct gdt main_gdt = { - .null = {.val = 0}, + .null = {0}, .kernel_code32 = {.val = 0x00cf9b000000ffff}, .kernel_data32 = {.val = 0x00cf93000000ffff}, .kernel_code64 = {.val = 0x00a09b0000000000}, @@ -24,10 +25,10 @@ static const struct gdt main_gdt = { }; void gdt_load() { - struct gdt* gdt = &percpu_get()->arch.gdt; + struct gdt* gdt = &percpu_ref(arch_data)->gdt; memcpy(gdt, &main_gdt, sizeof(main_gdt)); - struct tss* tss = &percpu_get()->arch.tss; + struct tss* tss = &percpu_ref(arch_data)->tss; tss->iopb = sizeof(struct tss); uintptr_t tss_addr = (uintptr_t)tss; diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c index 52aa508..43633ba 100644 --- a/arch/x86_64/idt.c +++ b/arch/x86_64/idt.c @@ -12,6 +12,7 @@ #include #include #include +#include struct [[__packed]] idt_entry { uint16_t base0; @@ -34,6 +35,7 @@ static_assert(sizeof(struct idtr) == 10); void interrupt_handler(struct arch_context* ctx) { struct percpu* cpu = percpu_get(); + struct arch_percpu* arch_cpu = percpu_ref(arch_data); bool old = irq_set_interrupted(true); uint64_t isr = ctx->isr; @@ -46,12 +48,12 @@ void interrupt_handler(struct arch_context* ctx) { case IDT_IPI_RESCHED: arch_sched_preempt_disable(); if (arch_sched_preempt_enable()) { - lapic_eoi(&cpu->arch.lapic); + lapic_eoi(&arch_cpu->lapic); sched_reschedule(&cpu->sched); } break; default: - struct irq_line* line = cpu->arch.irq_lines[isr - 0x20]; + struct irq_line* line = arch_cpu->irq_lines[isr - 0x20]; assert(line, "Unhandled interrupt on ISR %lu\n", isr); // TODO: irq_raise(line); } diff --git a/arch/x86_64/include/bits/percpu.h b/arch/x86_64/include/x86_64/percpu.h similarity index 90% rename from arch/x86_64/include/bits/percpu.h rename to arch/x86_64/include/x86_64/percpu.h index 17d4701..d0aa897 100644 --- a/arch/x86_64/include/bits/percpu.h +++ b/arch/x86_64/include/x86_64/percpu.h @@ -16,3 +16,5 @@ struct arch_percpu { void (*fpu_restore)(const void*); bool can_smap; }; + +extern struct arch_percpu arch_data; diff --git a/arch/x86_64/mem.c b/arch/x86_64/mem.c index cab4014..bf9a401 100644 --- a/arch/x86_64/mem.c +++ b/arch/x86_64/mem.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -29,3 +30,7 @@ uintptr_t arch_mem_pfndb_addr() { uintptr_t arch_mem_mapping_addr() { return 0xFFFF'C000'0000'0000; } + +bool arch_mem_addr_is_user(uintptr_t addr) { + return addr < 0x0000'8000'0000'0000; +} diff --git a/arch/x86_64/percpu.c b/arch/x86_64/percpu.c index 0d19905..49b7a99 100644 --- a/arch/x86_64/percpu.c +++ b/arch/x86_64/percpu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,16 @@ union ia32_star { static_assert(sizeof(union ia32_star) == 8); +[[__percpu]] +struct arch_percpu arch_data = {0}; + static void setup_cpu(struct percpu* cpu) { asm_wrmsr(MSR_KERNEL_GS_BASE, 0); asm_wrmsr(MSR_GS_BASE, (uint64_t)cpu); asm_wrmsr(MSR_FS_BASE, 0); + struct arch_percpu* arch_cpu = percpu_ref(arch_data); + gdt_load(); // TODO: not if FRED @@ -88,13 +94,13 @@ static void setup_cpu(struct percpu* cpu) { asm_wrxcr(0, xcr0); - cpu->arch.fpu_size = cpuid13.ecx; - cpu->arch.fpu_save = asm_xsave; - cpu->arch.fpu_restore = asm_xrstor; + arch_cpu->fpu_size = cpuid13.ecx; + arch_cpu->fpu_save = asm_xsave; + arch_cpu->fpu_restore = asm_xrstor; } else { - cpu->arch.fpu_size = 512; - cpu->arch.fpu_save = asm_fxsave; - cpu->arch.fpu_restore = asm_fxrstor; + arch_cpu->fpu_size = 512; + arch_cpu->fpu_save = asm_fxsave; + arch_cpu->fpu_restore = asm_fxrstor; } if (cpuid7.ecx & CPUID_7C_UMIP) @@ -105,16 +111,16 @@ static void setup_cpu(struct percpu* cpu) { if (cpuid7.ebx & CPUID_7B_SMAP) { cr4 |= CR4_SMAP; - cpu->arch.can_smap = true; + arch_cpu->can_smap = true; } if (cpuid7.ebx & CPUID_7B_FSGSBASE) cr4 |= CR4_FSGSBASE; - asm volatile("mov %0, cr0" : "=r"(cr0)); - asm volatile("mov %0, cr4" : "=r"(cr4)); + asm volatile("mov cr0, %0" ::"r"(cr0)); + asm volatile("mov cr4, %0" ::"r"(cr4)); - lapic_init(&cpu->arch.lapic); + lapic_init(&arch_cpu->lapic); cpu->online = true; } diff --git a/arch/x86_64/sched.c b/arch/x86_64/sched.c index c487853..babdf01 100644 --- a/arch/x86_64/sched.c +++ b/arch/x86_64/sched.c @@ -13,6 +13,7 @@ #include #include #include +#include // 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. @@ -53,7 +54,7 @@ static struct task* perform_switch(uint64_t* old_rsp, uint64_t new_rsp, struct t } struct task* arch_sched_switch(struct task* from, struct task* to) { - struct arch_percpu* cpu = &percpu_get()->arch; + struct arch_percpu* cpu = percpu_ref(arch_data); struct arch_task_context* from_ctx = &from->context; struct arch_task_context* to_ctx = &to->context; @@ -108,7 +109,7 @@ errno_t arch_task_init( uintptr_t stack_start, bool is_user ) { - struct arch_percpu* cpu = &percpu_get()->arch; + struct arch_percpu* cpu = percpu_ref(arch_data); // Prepare a dummy stack with an entry point function to return to. struct task_frame* frame = (struct task_frame*)stack_start - 1; diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c index e6c505d..7bff4e6 100644 --- a/arch/x86_64/syscall.c +++ b/arch/x86_64/syscall.c @@ -4,6 +4,7 @@ #include #include #include +#include // TODO: Refactor to only push callee-saved registers. diff --git a/boot/cmdline.c b/boot/cmdline.c index f6b9566..dac4b43 100644 --- a/boot/cmdline.c +++ b/boot/cmdline.c @@ -1,8 +1,8 @@ +#include +#include #include #include #include -#include -#include // Defined in linker script. extern const struct cmdline_option* __ld_cmdline_start[]; @@ -12,6 +12,9 @@ static char cmdline_buf[0x1000]; [[__init]] void cmdline_parse(const char* cmdline) { + if (cmdline == nullptr) + cmdline = ""; + const size_t len = strnlen(cmdline, sizeof(cmdline_buf) - 1); size_t idx = 0; memcpy(cmdline_buf, cmdline, len); diff --git a/boot/kernel.ld b/boot/kernel.ld index b136ab9..9abd38c 100644 --- a/boot/kernel.ld +++ b/boot/kernel.ld @@ -82,7 +82,8 @@ SECTIONS /* Per-CPU data block. MUST always come last. */ .percpu ALIGN(CONSTANT(MAXPAGESIZE)) : { __ld_percpu_start = .; - KEEP(*(.percpu)) + KEEP(*(.percpu.init .percpu.init*)) + KEEP(*(.percpu.data .percpu.data*)) . = ALIGN(CONSTANT(MAXPAGESIZE)); __ld_percpu_end = .; diff --git a/boot/limine/entry.c b/boot/limine/entry.c index 9a25327..31e0e7a 100644 --- a/boot/limine/entry.c +++ b/boot/limine/entry.c @@ -1,9 +1,9 @@ -#include #include #include #include #include #include +#include #include "limine.h" [[__initdata_sorted("limine.0")]] @@ -89,5 +89,3 @@ void kernel_entry() { kernel_main(&info); } - -phys_t rsdp_addr; diff --git a/boot/main.c b/boot/main.c index a8b5d98..da38e4c 100644 --- a/boot/main.c +++ b/boot/main.c @@ -15,6 +15,10 @@ #include #include +#if CONFIG_ACPI +#include +#endif + static const char zinnia_banner[] = "Zinnia " ZINNIA_VERSION " " CONFIG_KERNEL_FLAVOR " (" ZINNIA_ARCH ", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")"; @@ -74,10 +78,14 @@ void kernel_main(struct boot_info* info) { kprintf("\ec"); mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base); - rsdp_addr = info->rsdp; // TODO + percpu_init(); sched_init(&percpu_get()->sched); +#if CONFIG_ACPI + acpi_init(info); +#endif + struct task* main_task; task_create("main", &kernel_vma, kernel_main_task, (uintptr_t)info, &main_task); sched_add_task(&percpu_get()->sched, main_task); diff --git a/core/lib/string.c b/core/lib/string.c index 69ae21f..b38095a 100644 --- a/core/lib/string.c +++ b/core/lib/string.c @@ -1,8 +1,8 @@ +#include +#include #include #include #include -#include -#include [[__hot]] size_t strlen(const char* str) { @@ -25,8 +25,8 @@ size_t strnlen(const char* str, size_t len) { [[__hot]] int memcmp(const void* s1, const void* s2, size_t size) { int diff = 0; - char* s1ptr = (char*)s1; - char* s2ptr = (char*)s2; + const uint8_t* s1ptr = s1; + const uint8_t* s2ptr = s2; for (size_t i = 0; i < size; i++) { if (s1ptr[i] != s2ptr[i]) diff --git a/core/meson.build b/core/meson.build index 7c415d7..fade04c 100644 --- a/core/meson.build +++ b/core/meson.build @@ -13,4 +13,3 @@ kernel_sources += files( subdir('lib') subdir('mem') subdir('sched') -subdir('syscalls') diff --git a/core/percpu.c b/core/percpu.c index 0b73176..8fedaa3 100644 --- a/core/percpu.c +++ b/core/percpu.c @@ -2,7 +2,7 @@ #include #include -[[__percpu]] +[[__used, __section(".percpu.init")]] struct percpu percpu_bsp = { .self = &percpu_bsp, .id = 0, diff --git a/core/syscalls/archctl.c b/core/syscalls/archctl.c deleted file mode 100644 index 3573268..0000000 --- a/core/syscalls/archctl.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include - -void sys_archctl(struct arch_context* ctx) { - ctx->ARCH_CTX_RET0 = arch_archctl(ctx->ARCH_CTX_A0, ctx->ARCH_CTX_A1); -} diff --git a/core/syscalls/getuname.c b/core/syscalls/getuname.c deleted file mode 100644 index 5d5997b..0000000 --- a/core/syscalls/getuname.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include -#include - -static struct spinlock uname_lock = {}; - -static struct utsname uname_buf = { - .sysname = "Zinnia", - .release = ZINNIA_VERSION, - .version = CONFIG_KERNEL_FLAVOR, - .nodename = "localhost", - .machine = ZINNIA_ARCH, -}; - -struct syscall_ret sys_getuname(__user struct utsname* ptr) { - struct syscall_ret ret = {}; - - if (!ptr) { - ret.errno = EINVAL; - return ret; - } - - spin_lock(&uname_lock); - - if (!usercopy_write(ptr, &uname_buf, sizeof(uname_buf))) - ret.errno = EFAULT; - - spin_unlock(&uname_lock); - - return ret; -} diff --git a/dev/acpi/include/zinnia/acpi.h b/dev/acpi/include/zinnia/acpi.h new file mode 100644 index 0000000..fa642be --- /dev/null +++ b/dev/acpi/include/zinnia/acpi.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +void acpi_init(struct boot_info* info); + +extern phys_t acpi_rsdp_addr; diff --git a/dev/acpi/init.c b/dev/acpi/init.c new file mode 100644 index 0000000..8607e46 --- /dev/null +++ b/dev/acpi/init.c @@ -0,0 +1,13 @@ +#include +#include +#include + +phys_t acpi_rsdp_addr = 0; + +void acpi_init(struct boot_info* info) { + if (!info->rsdp) { + log("acpi: No RSDP was passed, unable to start ACPI subsystem!\n"); + return; + } + acpi_rsdp_addr = info->rsdp; +} diff --git a/dev/acpi/meson.build b/dev/acpi/meson.build index c41fb03..a599ebf 100644 --- a/dev/acpi/meson.build +++ b/dev/acpi/meson.build @@ -1,15 +1,16 @@ uacpi = subproject('uacpi') kernel_sources += uacpi.get_variable('sources') -kernel_includes += uacpi.get_variable('includes') -kernel_c_args += [ - '-DUACPI_FORMATTED_LOGGING', - '-DUACPI_BAREBONES_MODE', # TODO - '-DUACPI_OVERRIDE_TYPES', -] -# For uacpi_types.h -kernel_includes += include_directories('include') - kernel_sources += files( + 'init.c', 'uacpi_glue.c', ) + +kernel_includes += uacpi.get_variable('includes') +kernel_includes += include_directories('include') + +kernel_c_args += [ + '-DUACPI_FORMATTED_LOGGING', + '-DUACPI_BAREBONES_MODE', # TODO: Remove + '-DUACPI_OVERRIDE_TYPES', +] diff --git a/dev/acpi/uacpi_glue.c b/dev/acpi/uacpi_glue.c index 5cfc9b6..f1c72fc 100644 --- a/dev/acpi/uacpi_glue.c +++ b/dev/acpi/uacpi_glue.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,17 +7,22 @@ #include #include #include +#include #include #include #include #include uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr* out_rsdp_address) { - *out_rsdp_address = (uacpi_phys_addr)rsdp_addr; + *out_rsdp_address = (uacpi_phys_addr)acpi_rsdp_addr; return UACPI_STATUS_OK; } void* uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len) { + uintptr_t aligned_addr = ALIGN_DOWN(addr, arch_mem_page_size()); + uintptr_t difference = addr - aligned_addr; + size_t aligned_len = ALIGN_UP(len + difference, arch_mem_page_size()); + uintptr_t vaddr = vm_alloc(len); for (size_t i = 0; i < len; i += arch_mem_page_size()) { pmap_map(&kernel_vma.pmap, vaddr + i, addr + i, PROT_READ | PROT_WRITE, CACHE_ANY); diff --git a/include/arch/archctl.h b/include/arch/archctl.h index 26f0401..bca11c9 100644 --- a/include/arch/archctl.h +++ b/include/arch/archctl.h @@ -3,4 +3,4 @@ #include #include -errno_t arch_archctl(uintptr_t op, uintptr_t value); +struct syscall_ret arch_archctl(uintptr_t op, uintptr_t value); diff --git a/include/arch/mem.h b/include/arch/mem.h index e601b81..0a893c2 100644 --- a/include/arch/mem.h +++ b/include/arch/mem.h @@ -3,10 +3,26 @@ #include #include +[[gnu::pure]] +bool arch_mem_addr_is_user(uintptr_t addr); + +[[gnu::pure]] size_t arch_mem_page_size(); + +[[gnu::pure]] size_t arch_mem_page_bits(); + +[[gnu::pure]] size_t arch_mem_level_bits(); + +[[gnu::pure]] size_t arch_mem_num_levels(); + +[[gnu::pure]] uintptr_t arch_mem_hhdm_addr(); + +[[gnu::pure]] uintptr_t arch_mem_pfndb_addr(); + +[[gnu::pure]] uintptr_t arch_mem_mapping_addr(); diff --git a/include/uapi/utsname.h b/include/uapi/utsname.h index eb26d7c..b7c1d1e 100644 --- a/include/uapi/utsname.h +++ b/include/uapi/utsname.h @@ -2,7 +2,7 @@ #ifndef __ZINNIA_UAPI_UTSNAME_H #define __ZINNIA_UAPI_UTSNAME_H -struct utsname { +struct __utsname { char sysname[65]; char nodename[65]; char release[65]; diff --git a/include/zinnia/atomic.h b/include/zinnia/atomic.h index 1dc9323..e53e6c7 100644 --- a/include/zinnia/atomic.h +++ b/include/zinnia/atomic.h @@ -9,22 +9,13 @@ typedef enum memory_order { ATOMIC_SEQ_CST = __ATOMIC_SEQ_CST } memory_order; -#define atomic(T) _Atomic(T) - -#define atomic_store(ptr, des, order) __atomic_store_n(ptr, des, order) - -#define atomic_load(ptr, order) __atomic_load_n(ptr, order) - +#define atomic(T) _Atomic(T) +#define atomic_store(ptr, des, order) __atomic_store_n(ptr, des, order) +#define atomic_load(ptr, order) __atomic_load_n(ptr, order) #define atomic_exchange(ptr, des, order) __atomic_exchange_n(ptr, des, order) - #define atomic_fetch_add(ptr, op, order) __atomic_fetch_add(ptr, op, order) - #define atomic_fetch_sub(ptr, op, order) __atomic_fetch_sub(ptr, op, order) - -#define atomic_fetch_or(ptr, op, order) __atomic_fetch_or(ptr, op, order) - +#define atomic_fetch_or(ptr, op, order) __atomic_fetch_or(ptr, op, order) #define atomic_fetch_xor(ptr, op, order) __atomic_fetch_xor(ptr, op, order) - #define atomic_fetch_and(ptr, op, order) __atomic_fetch_and(ptr, op, order) - -#define atomic_thread_fence(order) __atomic_thread_fence(order) +#define atomic_thread_fence(order) __atomic_thread_fence(order) diff --git a/include/zinnia/compiler.h b/include/zinnia/compiler.h index 19093d5..28f5a83 100644 --- a/include/zinnia/compiler.h +++ b/include/zinnia/compiler.h @@ -12,13 +12,11 @@ #define __used gnu::used #define __unused gnu::unused #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 #define __visibility gnu::visibility -// Only clang has these hints, GCC will throw a warning here. -// They also don't support the C23 attribute format. +// Only clang has these hints, GCC would throw a warning here. +// clang::noderef also don't support the C23 attribute format. #ifdef __clang__ #define __user __attribute__((noderef, address_space(1))) #define __phys __attribute__((noderef, address_space(2))) @@ -26,3 +24,6 @@ #define __user #define __phys #endif + +#define __likely(x) __builtin_expect(!!(x), 1) +#define __unlikely(x) __builtin_expect(!!(x), 0) diff --git a/include/zinnia/init.h b/include/zinnia/init.h index 3956c2a..ee7acf6 100644 --- a/include/zinnia/init.h +++ b/include/zinnia/init.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -25,16 +26,21 @@ struct boot_info { uintptr_t hhdm_base; struct boot_file* files; size_t num_files; +#if CONFIG_OF + void* dtb; +#endif +#if CONFIG_ACPI phys_t rsdp; +#endif }; +extern struct boot_info boot_info; + [[__visibility("hidden")]] extern uint8_t __ld_stack_top[]; [[__visibility("hidden")]] extern uint8_t __ld_stack_bottom[]; -extern phys_t rsdp_addr; - // Entry point for the kernel after arch-specific setup has finished. void kernel_entry(); diff --git a/include/zinnia/percpu.h b/include/zinnia/percpu.h index 4889d6c..b9da4b3 100644 --- a/include/zinnia/percpu.h +++ b/include/zinnia/percpu.h @@ -4,41 +4,37 @@ #include #include #include -#include #include -ASSERT_TYPE(struct arch_percpu); // bits/percpu.h +// # On using per-CPU data +// +// Defining variables with `[[__percpu]]` will put them in a special section. +// This section is unique for every CPU. To access the correct memory of the +// caller's CPU, use `percpu_ref`. +// +// ## Example +// +// ``` +// [[__percpu]] +// int my_cpu_data = 0; +// +// int get_foo() { +// return *percpu_ref(my_cpu_data); +// } +// ``` -/* -On using per-CPU data ---------------------- - -Defining variables with `[[__percpu]]` will put them in a special section. -This section is unique for every CPU. To access the correct memory of the -caller's CPU, use `percpu_ref`. - -# Example - -[[__percpu]] -int my_cpu_data = 0; -int get_foo() { - return *percpu_ref(my_cpu_data); -} -*/ - -#define __percpu __used, __section(".percpu") +#define __percpu __used, __section(".percpu.data") #define percpu_ref(x) ((typeof(&(x)))((void*)percpu_get() + ((void*)&(x) - (void*)&percpu_bsp))) // CPU-relative information. struct percpu { - struct percpu* self; // A pointer to this structure. - size_t id; // The virtual ID of this CPU. - bool online; // Whether this CPU is initialized and active. - uintptr_t kernel_stack; // The kernel mode stack. - uintptr_t user_stack; // The user mode stack. - struct arch_percpu arch; // Architecture-specific fields. - struct irq_percpu irq; // IRQ information. - struct scheduler sched; // Scheduler information. + struct percpu* self; // A pointer to this structure. + size_t id; // The virtual ID of this CPU. + bool online; // Whether this CPU is initialized and active. + uintptr_t kernel_stack; // The kernel mode stack. + uintptr_t user_stack; // The user mode stack. + struct irq_percpu irq; // IRQ information. + struct scheduler sched; // Scheduler information. }; struct percpu* percpu_new(); diff --git a/include/zinnia/syscall_list.inc b/include/zinnia/syscall_list.inc index 52747b0..397f575 100644 --- a/include/zinnia/syscall_list.inc +++ b/include/zinnia/syscall_list.inc @@ -4,9 +4,9 @@ // SYSCALL_DECLARE(0, exit, -1) // SYSCALL_DECLARE(1, syslog, -1) -SYSCALL_DECLARE(2, getuname, -1) +SYSCALL_DECLARE(2, getuname, 1) // SYSCALL_DECLARE(3, setuname, -1) -SYSCALL_DECLARE(4, archctl, -1) +SYSCALL_DECLARE(4, archctl, 2) // SYSCALL_DECLARE(5, reboot, -1) // SYSCALL_DECLARE(6, mmap, -1) // SYSCALL_DECLARE(7, munmap, -1) diff --git a/include/zinnia/tailq.h b/include/zinnia/tailq.h index bd7e4f3..276debc 100644 --- a/include/zinnia/tailq.h +++ b/include/zinnia/tailq.h @@ -8,8 +8,8 @@ #define tailq_link(type) \ struct { \ - type* tqe_next; \ - type** tqe_prev; \ + type* tql_next; \ + type** tql_prev; \ } #define tailq_init(head) \ @@ -20,33 +20,33 @@ #define tailq_first(head) ((head)->tqh_first) -#define tailq_next(elm, field) ((elm)->field.tqe_next) +#define tailq_next(elm, field) ((elm)->field.tql_next) #define tailq_empty(head) (tailq_first(head) == nullptr) #define tailq_insert_tail(head, elm, field) \ do { \ - (elm)->field.tqe_next = nullptr; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ + (elm)->field.tql_next = nullptr; \ + (elm)->field.tql_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_last = &(elm)->field.tql_next; \ } while (0) #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; \ + if (((elm)->field.tql_next = (head)->tqh_first) != nullptr) \ + (head)->tqh_first->field.tql_prev = &(elm)->field.tql_next; \ else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_last = &(elm)->field.tql_next; \ (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ + (elm)->field.tql_prev = &(head)->tqh_first; \ } while (0) #define tailq_remove(head, elm, field) \ do { \ - if (((elm)->field.tqe_next) != nullptr) \ - (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \ + if (((elm)->field.tql_next) != nullptr) \ + (elm)->field.tql_next->field.tql_prev = (elm)->field.tql_prev; \ else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + (head)->tqh_last = (elm)->field.tql_prev; \ + *(elm)->field.tql_prev = (elm)->field.tql_next; \ } while (0) diff --git a/meson.build b/meson.build index c70c3a9..9b12c51 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'zinnia', license: 'ISC', version: '0.1.0', - meson_version: '>=1.3.0', + meson_version: '>=1.5.0', default_options: [ 'c_std=gnu23', 'werror=true', @@ -18,7 +18,7 @@ if get_option('headers_only') subdir_done() endif -add_languages('c', native: false) +add_languages('c', native: false, required: true) # Check if we're using a sane compiler. c_compiler = meson.get_compiler('c') @@ -77,7 +77,7 @@ foreach k, v : kconfig endif endforeach -kernel_c_args = [] +kernel_c_args = ['-DIN_KERNEL'] kernel_lds = meson.current_source_dir() / 'boot' / 'kernel.ld' kernel_link_args = [ @@ -91,10 +91,11 @@ kernel_includes = [] kernel_sources = [] modules = {} -# Goes first so we can add arch-specific flags to drivers. +# These dirs go first so we can add arch-specific flags to drivers. subdir('arch' / target_machine.cpu_family()) subdir('boot') subdir('core') +subdir('syscalls') # Device and file system drivers. subdir('dev') @@ -141,7 +142,11 @@ foreach name, v : modules kernel_link_args += mod_link_args endif - mod_summary += {name: is_modular} + if is_modular + mod_summary += {name: 'mod'} + else + mod_summary += {name: 'builtin'} + endif endforeach # Kernel @@ -151,7 +156,7 @@ executable( common_includes, kernel_includes, ], - c_args: ['-DIN_KERNEL', kernel_c_args], + c_args: [kernel_c_args], link_args: kernel_link_args, link_depends: kernel_lds, sources: kernel_sources, @@ -161,5 +166,5 @@ executable( ) # Print a summary -summary(mod_summary, bool_yn: true, section: 'Driver configuration') +summary(mod_summary, section: 'Driver configuration') summary(kconfig, bool_yn: true, section: 'Kernel configuration') diff --git a/syscalls/archctl.c b/syscalls/archctl.c new file mode 100644 index 0000000..9cc1d03 --- /dev/null +++ b/syscalls/archctl.c @@ -0,0 +1,6 @@ +#include +#include + +struct syscall_ret sys_archctl(uintptr_t op, uintptr_t arg) { + return arch_archctl(op, arg); +} diff --git a/core/syscalls/dispatch.c b/syscalls/dispatch.c similarity index 98% rename from core/syscalls/dispatch.c rename to syscalls/dispatch.c index a011f03..e935f9c 100644 --- a/core/syscalls/dispatch.c +++ b/syscalls/dispatch.c @@ -17,6 +17,7 @@ const struct syscall syscall_table[256] = { #include }; +// TODO: Implement this [[gnu::no_caller_saved_registers]] struct syscall_ret syscall_dispatch_fast( uintptr_t a0, diff --git a/core/syscalls/meson.build b/syscalls/meson.build similarity index 77% rename from core/syscalls/meson.build rename to syscalls/meson.build index a292cdf..4ed0766 100644 --- a/core/syscalls/meson.build +++ b/syscalls/meson.build @@ -1,5 +1,5 @@ kernel_sources += files( 'archctl.c', 'dispatch.c', - 'getuname.c', + 'uname.c', ) diff --git a/syscalls/uname.c b/syscalls/uname.c new file mode 100644 index 0000000..28bcaba --- /dev/null +++ b/syscalls/uname.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include + +static struct spinlock uname_lock = {}; + +static struct __utsname uname_buf = { + .sysname = "Zinnia", + .release = ZINNIA_VERSION, + .version = CONFIG_KERNEL_FLAVOR, + .nodename = "localhost", + .machine = ZINNIA_ARCH, +}; + +struct syscall_ret sys_setuname(__user const struct __utsname* ptr) { + struct syscall_ret ret = {}; + + if (!ptr) { + ret.errno = EINVAL; + return ret; + } + + // TODO: User has to be root to do this. + + struct __utsname read_buf; + if (!usercopy_read(&read_buf, ptr, sizeof(read_buf))) { + ret.errno = EFAULT; + return ret; + } + + spin_lock(&uname_lock); + + strncpy(uname_buf.sysname, read_buf.sysname, sizeof(uname_buf.sysname)); + strncpy(uname_buf.release, read_buf.release, sizeof(uname_buf.release)); + strncpy(uname_buf.version, read_buf.version, sizeof(uname_buf.version)); + strncpy(uname_buf.nodename, read_buf.nodename, sizeof(uname_buf.nodename)); + strncpy(uname_buf.machine, read_buf.machine, sizeof(uname_buf.machine)); + + spin_unlock(&uname_lock); + + return ret; +} + +struct syscall_ret sys_getuname(__user struct __utsname* ptr) { + struct syscall_ret ret = {}; + + if (!ptr) { + ret.errno = EINVAL; + return ret; + } + + spin_lock(&uname_lock); + + if (!usercopy_write(ptr, &uname_buf, sizeof(uname_buf))) + ret.errno = EFAULT; + + spin_unlock(&uname_lock); + + return ret; +}