From 77f228df11e6565e656fdacb26e2d865f56dcc98 Mon Sep 17 00:00:00 2001 From: Marvin Friedrich Date: Sun, 20 Sep 2026 05:27:41 +0200 Subject: [PATCH] modules --- .gitignore | 1 + Kconfig | 6 ++- arch/x86_64/Kconfig | 16 ++++++ arch/x86_64/meson.build | 1 - arch/x86_64/percpu.c | 3 ++ arch/x86_64/sched.c | 6 +-- arch/x86_64/sys.c | 4 +- arch/x86_64/syscall.c | 4 +- arch/x86_64/usercopy.c | 105 ++++++++++++++++++------------------- boot/kernel.ld | 14 ++--- core/Kconfig | 18 +++++++ core/mem/Kconfig | 8 +++ core/mem/meson.build | 7 ++- core/mem/pmap.c | 4 ++ core/mem/usercopy.c | 15 ++++-- core/sched/meson.build | 5 +- dev/Kconfig | 3 ++ dev/block/Kconfig | 5 ++ dev/block/meson.build | 3 ++ dev/block/nvme/Kconfig | 13 +++++ dev/block/nvme/core.c | 12 +++++ dev/block/nvme/meson.build | 12 +++++ dev/block/nvme/pci.c | 0 dev/block/nvme/spec.h | 1 + dev/meson.build | 7 ++- dev/module.ld | 101 +++++++++++++++++++++++++++++++++++ dev/pci/Kconfig | 7 +++ include/arch/archctl.h | 1 - include/arch/elf.h | 2 +- include/zinnia/cmdline.h | 15 +----- include/zinnia/compiler.h | 1 + include/zinnia/device.h | 7 +++ include/zinnia/init.h | 6 ++- include/zinnia/module.h | 24 +++++++++ include/zinnia/percpu.h | 20 ++++++- include/zinnia/vma.h | 2 +- meson.build | 84 ++++++++++++++++++++++------- scripts/get_modinfo.py | 37 +++++++++++++ 38 files changed, 465 insertions(+), 115 deletions(-) create mode 100644 arch/x86_64/Kconfig create mode 100644 core/Kconfig create mode 100644 core/mem/Kconfig create mode 100644 dev/block/Kconfig create mode 100644 dev/block/meson.build create mode 100644 dev/block/nvme/Kconfig create mode 100644 dev/block/nvme/core.c create mode 100644 dev/block/nvme/meson.build create mode 100644 dev/block/nvme/pci.c create mode 100644 dev/block/nvme/spec.h create mode 100644 dev/module.ld create mode 100644 dev/pci/Kconfig create mode 100644 include/zinnia/device.h create mode 100644 include/zinnia/module.h create mode 100755 scripts/get_modinfo.py diff --git a/.gitignore b/.gitignore index a1c8cd3..f2569d8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ *.o *.a *.so +__pycache__/ diff --git a/Kconfig b/Kconfig index 66cce9d..a3ad08e 100644 --- a/Kconfig +++ b/Kconfig @@ -1,7 +1,9 @@ mainmenu "Zinnia Kernel Configuration" -source "dev/Kconfig" - config KERNEL_FLAVOR string "Kernel flavor name" default "vanilla" + +source "arch/$(ARCH)/Kconfig" +source "core/Kconfig" +source "dev/Kconfig" diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig new file mode 100644 index 0000000..ca3d411 --- /dev/null +++ b/arch/x86_64/Kconfig @@ -0,0 +1,16 @@ +menu "x86_64 Architecture options" + +config X86_64 + bool + default y + select ACPI + select HAVE_MMU + select HAVE_MMU_GENERIC + help + 64-bit x86 CPU support for AMD and Intel CPUs. + +config TSC + bool "Invariant Timestamp Counter support" + default y + +endmenu diff --git a/arch/x86_64/meson.build b/arch/x86_64/meson.build index 070f6fb..1dfb718 100644 --- a/arch/x86_64/meson.build +++ b/arch/x86_64/meson.build @@ -1,7 +1,6 @@ kernel_c_args += [ '-mgeneral-regs-only', '-mno-red-zone', - '-mcmodel=kernel', '-masm=intel', ] diff --git a/arch/x86_64/percpu.c b/arch/x86_64/percpu.c index 9339a9d..0d19905 100644 --- a/arch/x86_64/percpu.c +++ b/arch/x86_64/percpu.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -119,7 +120,9 @@ static void setup_cpu(struct percpu* cpu) { void arch_percpu_init() { hpet_init(); +#if CONFIG_TSC tsc_init(); +#endif // Init the BSP. setup_cpu(&percpu_bsp); diff --git a/arch/x86_64/sched.c b/arch/x86_64/sched.c index 0ffcca2..c487853 100644 --- a/arch/x86_64/sched.c +++ b/arch/x86_64/sched.c @@ -94,9 +94,9 @@ void task_entry_thunk() { asm volatile( "mov rdi, rbx\n" "mov rsi, r12\n" - "jmp %c0" + "jmp %0" : - : "i"(task_entry) + : "r"(task_entry) : "memory" ); } @@ -173,7 +173,7 @@ bool arch_sched_preempt_enable() { void arch_sched_jump_to_context(struct arch_context* context) { asm volatile( "mov rsp, rdi\n" - "jmp %c0\n" ::"i"(interrupt_return) + "jmp %0\n" ::"r"(interrupt_return) ); } diff --git a/arch/x86_64/sys.c b/arch/x86_64/sys.c index d7133a0..4db3c8c 100644 --- a/arch/x86_64/sys.c +++ b/arch/x86_64/sys.c @@ -11,9 +11,9 @@ [[__init, __naked, __used]] void _start() { asm volatile( - "lea rsp, [rip + %0]\n" + "mov rsp, %0\n" "jmp %1" : - : "i"(__ld_stack_top), "r"(kernel_entry) + : "r"(__ld_stack_top), "r"(kernel_entry) ); } diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c index d31ca12..e6c505d 100644 --- a/arch/x86_64/syscall.c +++ b/arch/x86_64/syscall.c @@ -39,7 +39,7 @@ void arch_syscall_stub() { " push r15\n" " xor rbp, rbp\n" " mov rdi, rsp\n" // SysV ABI first argument. - " call %c4\n" // Call syscall handler. + " call %4\n" // Call syscall handler. " cli\n" " pop r15\n" " pop r14\n" @@ -66,6 +66,6 @@ void arch_syscall_stub() { "i"(offsetof(struct percpu, kernel_stack)), // 1 "i"(offsetof(struct gdt, user_code64) | CPL_USER), // 2 "i"(offsetof(struct gdt, user_data) | CPL_USER), // 3 - "i"(syscall_dispatch) // 4 + "r"(syscall_dispatch) // 4 ); } diff --git a/arch/x86_64/usercopy.c b/arch/x86_64/usercopy.c index da68c69..dc367ff 100644 --- a/arch/x86_64/usercopy.c +++ b/arch/x86_64/usercopy.c @@ -1,6 +1,14 @@ #include #include +void arch_usercopy_allow(bool state) { + if (state) { + asm volatile("stac" ::: "memory"); + } else { + asm volatile("clac" ::: "memory"); + } +} + extern void x86_64_read_start(); extern void x86_64_read_end(); extern void x86_64_read_fault(); @@ -11,37 +19,34 @@ 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" // Setup regs for `rep movsb`. - "xchg rcx, rdx\n" - "mov rax, [rip + %0]\n" - "xchg [rdx], rax\n" + " xchg rcx, rdx\n" + " mov rax, [rip + %0]\n" + " xchg [rdx], rax\n" ".global x86_64_read_start\n" - "x86_64_read_start:\n" - "rep movsb\n" + " x86_64_read_start:\n" + " rep movsb\n" ".global x86_64_read_end\n" "x86_64_read_end:\n" - "xor rax, rax\n" - "xchg [rdx], rax\n" - "mov rax, 1\n" - "clac\n" - "ret\n" + " xor rax, rax\n" + " xchg [rdx], rax\n" + " mov rax, 1\n" + " ret\n" ".global x86_64_read_fault\n" "x86_64_read_fault:\n" - "xor rax, rax\n" - "xchg [rdx], rax\n" - "clac\n" - "ret\n" + " xor rax, rax\n" + " xchg [rdx], rax\n" + " ret\n" : : "i"(&read_region) : "memory" ); - return false; } extern void x86_64_write_start(); @@ -54,37 +59,34 @@ 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" // Setup regs for `rep movsb`. - "xchg rcx, rdx\n" - "mov rax, [rip + %0]\n" - "mov [rdx], rax\n" + " xchg rcx, rdx\n" + " mov rax, [rip + %0]\n" + " mov [rdx], rax\n" ".global x86_64_write_start\n" - "x86_64_write_start:\n" - "rep movsb\n" + " x86_64_write_start:\n" + " rep movsb\n" ".global x86_64_write_end\n" - "x86_64_write_end:\n" - "xor rax, rax\n" - "xchg [rdx], rax\n" - "mov rax, 1\n" - "clac\n" - "ret\n" + " x86_64_write_end:\n" + " xor rax, rax\n" + " xchg [rdx], rax\n" + " mov rax, 1\n" + " ret\n" ".global x86_64_write_fault\n" "x86_64_write_fault:\n" - "xor rax, rax\n" - "xchg [rdx], rax\n" - "clac\n" - "ret\n" + " xor rax, rax\n" + " xchg [rdx], rax\n" + " ret\n" : : "i"(&write_region) : "memory" ); - return false; } extern void x86_64_strlen_start(); @@ -100,36 +102,33 @@ static const struct usercopy_region strlen_region = { [[__naked]] bool arch_usercopy_strlen(const __user char* str, size_t max, size_t* len, struct usercopy_region** region) { asm volatile( - "stac\n" - "mov rax, [rip + %0]\n" - "xchg [rcx], rax\n" + " mov rax, [rip + %0]\n" + " xchg [rcx], rax\n" ".global x86_64_strlen_start\n" - "x86_64_strlen_start:\n" - "xor r8, r8\n" + " x86_64_strlen_start:\n" + " xor r8, r8\n" ".Lloop:\n" - "cmp byte ptr [rdi + r8], 0\n" - "je .Lleave\n" - "inc r8\n" - "cmp rsi, r8\n" - "jne .Lloop\n" + " cmp byte ptr [rdi + r8], 0\n" + " je .Lleave\n" + " inc r8\n" + " cmp rsi, r8\n" + " jne .Lloop\n" ".Lleave:\n" - "mov [rdx], r8\n" + " mov [rdx], r8\n" ".global x86_64_strlen_end\n" "x86_64_strlen_end:\n" - "xor rax, rax\n" - "xchg [rcx], rax\n" - "mov rax, 1\n" - "clac\n" - "ret\n" + " xor rax, rax\n" + " xchg [rcx], rax\n" + " mov rax, 1\n" + " ret\n" ".global x86_64_strlen_fault\n" "x86_64_strlen_fault:\n" - "xor rax, rax\n" - "xchg [rcx], rax\n" - "clac\n" - "ret\n" + " xor rax, rax\n" + " xchg [rcx], rax\n" + " ret\n" : : "i"(&strlen_region) : "memory" diff --git a/boot/kernel.ld b/boot/kernel.ld index 7d5c0d2..b136ab9 100644 --- a/boot/kernel.ld +++ b/boot/kernel.ld @@ -54,27 +54,29 @@ SECTIONS .dynsym : { __ld_dynsym_start = .; - *(.dynsym) + KEEP(*(.dynsym*)) __ld_dynsym_end = .; } :data .dynstr : { __ld_dynstr_start = .; - *(.dynstr) + KEEP(*(.dynstr*)) __ld_dynstr_end = .; } :data .dynamic : { - *(.dynamic) + *(.dynamic*) } :data :dynamic - .bss : { + .bss ALIGN(CONSTANT(MAXPAGESIZE)) (NOLOAD) : { + *(.*bss .*bss.*) + *(COMMON) + /* Small stack to bootstrap the allocator */ + . = ALIGN(16); __ld_stack_bottom = .; . += 0x2000; __ld_stack_top = .; - *(.*bss .*bss.*) - *(COMMON) } :data /* Per-CPU data block. MUST always come last. */ diff --git a/core/Kconfig b/core/Kconfig new file mode 100644 index 0000000..30cdc62 --- /dev/null +++ b/core/Kconfig @@ -0,0 +1,18 @@ +menu "Kernel Core options" + +source "core/mem/Kconfig" + +choice SCHED_ALG + prompt "Scheduler algorithm" + default SCHED_DUMB + help + The algorithm to use for scheduling. + +config SCHED_DUMB + bool "Dumb Scheduler" + help + Very basic scheduler, without any priorities. + +endchoice + +endmenu diff --git a/core/mem/Kconfig b/core/mem/Kconfig new file mode 100644 index 0000000..ea463b6 --- /dev/null +++ b/core/mem/Kconfig @@ -0,0 +1,8 @@ +menu "Memory Management options" + +config HAVE_MMU + bool +config HAVE_MMU_GENERIC + bool + +endmenu diff --git a/core/mem/meson.build b/core/mem/meson.build index de68ebd..db3cf91 100644 --- a/core/mem/meson.build +++ b/core/mem/meson.build @@ -1,7 +1,6 @@ kernel_sources += files( 'fault.c', 'init.c', - 'pmap.c', 'pmm.c', 'slab.c', 'usercopy.c', @@ -9,3 +8,9 @@ kernel_sources += files( 'vma.c', 'vmo.c', ) + +if kconfig.get('CONFIG_HAVE_MMU', 'n') == 'y' + kernel_sources += files( + 'pmap.c', + ) +endif diff --git a/core/mem/pmap.c b/core/mem/pmap.c index b667151..7187c52 100644 --- a/core/mem/pmap.c +++ b/core/mem/pmap.c @@ -3,8 +3,12 @@ #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); + errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags) { flags &= ~ALLOC_NOZERO; diff --git a/core/mem/usercopy.c b/core/mem/usercopy.c index f46b3a8..3ff9ebf 100644 --- a/core/mem/usercopy.c +++ b/core/mem/usercopy.c @@ -3,13 +3,22 @@ #include bool usercopy_read(void* dst, const __user void* src, size_t len) { - return arch_usercopy_read(dst, src, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(true); + bool success = arch_usercopy_read(dst, src, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(false); + return success; } bool usercopy_write(__user void* dst, const void* src, size_t len) { - return arch_usercopy_write(dst, src, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(true); + bool success = arch_usercopy_write(dst, src, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(false); + return success; } bool usercopy_strlen(const __user char* str, size_t max, size_t* len) { - return arch_usercopy_strlen(str, max, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(true); + bool success = arch_usercopy_strlen(str, max, len, &percpu_get()->sched.current->usercopy_region); + arch_usercopy_allow(false); + return success; } diff --git a/core/sched/meson.build b/core/sched/meson.build index 5245b94..9775387 100644 --- a/core/sched/meson.build +++ b/core/sched/meson.build @@ -1,4 +1,7 @@ kernel_sources += files( 'core.c', - 'sched_dumb.c', ) + +if kconfig.get('CONFIG_SCHED_DUMB', 'n') == 'y' + kernel_sources += files('sched_dumb.c') +endif diff --git a/dev/Kconfig b/dev/Kconfig index ca4a461..20ccd65 100644 --- a/dev/Kconfig +++ b/dev/Kconfig @@ -12,4 +12,7 @@ config ACPI help Adds support for ACPI firmware, tables and devices. +source "dev/block/Kconfig" +source "dev/pci/Kconfig" + endmenu diff --git a/dev/block/Kconfig b/dev/block/Kconfig new file mode 100644 index 0000000..65fa3cb --- /dev/null +++ b/dev/block/Kconfig @@ -0,0 +1,5 @@ +menu "Block device drivers" + +source "dev/block/nvme/Kconfig" + +endmenu diff --git a/dev/block/meson.build b/dev/block/meson.build new file mode 100644 index 0000000..d99fcc7 --- /dev/null +++ b/dev/block/meson.build @@ -0,0 +1,3 @@ +if kconfig.get('CONFIG_NVME_CORE', 'n') != 'n' + subdir('nvme') +endif diff --git a/dev/block/nvme/Kconfig b/dev/block/nvme/Kconfig new file mode 100644 index 0000000..ec31431 --- /dev/null +++ b/dev/block/nvme/Kconfig @@ -0,0 +1,13 @@ +menu "NVMe Support" + +config NVME_CORE + bool + default y + +config NVME_PCI + bool "NVMe via PCI transport" + default y + depends on PCI + depends on NVME_CORE + +endmenu diff --git a/dev/block/nvme/core.c b/dev/block/nvme/core.c new file mode 100644 index 0000000..a7e564b --- /dev/null +++ b/dev/block/nvme/core.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void nvme_init(struct module* mod) { + log("Hello world from NVMe!\n"); +} + +void do_nvme(bool on) {} +CMDLINE_OPTION("nvme_on", "My description", do_nvme); + +MODULE("NVME", "Marvin Friedrich", "ISC", "1.0", nvme_init); diff --git a/dev/block/nvme/meson.build b/dev/block/nvme/meson.build new file mode 100644 index 0000000..28afd8a --- /dev/null +++ b/dev/block/nvme/meson.build @@ -0,0 +1,12 @@ +nvme_sources = files('core.c') + +if kconfig.get('CONFIG_NVME_PCI', 'n') == 'y' + nvme_sources += files('pci.c') +endif + +modules += { + 'nvme': { + 'modular': true, #kconfig.get('CONFIG_NVME_CORE') == 'm', + 'sources': nvme_sources, + }, +} diff --git a/dev/block/nvme/pci.c b/dev/block/nvme/pci.c new file mode 100644 index 0000000..e69de29 diff --git a/dev/block/nvme/spec.h b/dev/block/nvme/spec.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/dev/block/nvme/spec.h @@ -0,0 +1 @@ +#pragma once diff --git a/dev/meson.build b/dev/meson.build index 6a3d7d7..47f1f05 100644 --- a/dev/meson.build +++ b/dev/meson.build @@ -1,9 +1,12 @@ subdir('common') +subdir('block') -if cfg.get('CONFIG_ACPI', 0) == 1 +if kconfig.get('CONFIG_ACPI', 'n') == 'y' subdir('acpi') endif -if cfg.get('CONFIG_DT', 0) == 1 +if kconfig.get('CONFIG_DT', 'n') == 'y' subdir('dt') endif + +module_lds = meson.current_source_dir() / 'module.ld' diff --git a/dev/module.ld b/dev/module.ld new file mode 100644 index 0000000..0545f6a --- /dev/null +++ b/dev/module.ld @@ -0,0 +1,101 @@ +/* Linker script for kernel modules */ + +ENTRY(__module_start) + +PHDRS +{ + text PT_LOAD FLAGS(5); + rodata PT_LOAD FLAGS(4); + data PT_LOAD FLAGS(6); + dynamic PT_DYNAMIC FLAGS(6); + modversion 0x60000001; + modauthor 0x60000002; + moddesc 0x60000003; + modlicense 0x60000004; + modcmdline 0x60000005; +} + +SECTIONS +{ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + /* Code */ + .text : { + *(.init .init.*) + *(.text .text.*) + *(.fini .fini.*) + *(.plt .plt.*) + } :text + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + /* Read-only data */ + .rodata : { + *(.rodata .rodata.*) + *(.hash .hash.*) + *(.got .got.*) + *(.got.plt .got.plt.*) + } :rodata + + .cmdline : { + KEEP(*(.cmdline)) + } :rodata :modcmdline + + .mod.version : { + KEEP(*(.mod.version)) + } :rodata :modversion + + .mod.author : { + KEEP(*(.mod.author)) + } :rodata :modauthor + + .mod.desc : { + KEEP(*(.mod.desc)) + } :rodata :moddesc + + .mod.license : { + KEEP(*(.mod.license)) + } :rodata :modlicense + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + /* Read-Write data */ + .data : { + *(.data) + *(.data.*) + } :data + + /* Zero-initialized memory */ + .bss : { + *(.*bss .*bss.*) + *(COMMON) + } :data + + .dynsym : { + *(.dynsym .dynsym.*) + } :data + + .dynstr : { + *(.dynstr .dynstr.*) + } :data + + .rela.dyn : { + *(.rela.dyn .rela.dyn.*) + } :data + + /* Dynamic tags */ + .dynamic : { + *(.dynamic) + } :data :dynamic + + /DISCARD/ : + { + *(.comment*) + *(.eh_frame*) + *(.rel.eh_frame*) + *(.relr.dyn .relr.dyn.*) + *(.gcc_except_table*) + *(.note*) + *(.interp) + } +} diff --git a/dev/pci/Kconfig b/dev/pci/Kconfig new file mode 100644 index 0000000..43ee5c7 --- /dev/null +++ b/dev/pci/Kconfig @@ -0,0 +1,7 @@ +menu "PCI bus drivers" + +config PCI + bool "PCI core drivers" + default y + +endmenu diff --git a/include/arch/archctl.h b/include/arch/archctl.h index 9f4b93a..26f0401 100644 --- a/include/arch/archctl.h +++ b/include/arch/archctl.h @@ -2,6 +2,5 @@ #include #include -#include errno_t arch_archctl(uintptr_t op, uintptr_t value); diff --git a/include/arch/elf.h b/include/arch/elf.h index 371326f..83db827 100644 --- a/include/arch/elf.h +++ b/include/arch/elf.h @@ -1,3 +1,3 @@ #pragma once -#include +// TODO: Ensure bits are defining values right. diff --git a/include/zinnia/cmdline.h b/include/zinnia/cmdline.h index 0362163..dd57a29 100644 --- a/include/zinnia/cmdline.h +++ b/include/zinnia/cmdline.h @@ -57,10 +57,10 @@ struct cmdline_option { }; union { const char** str_limit; - struct cmdline_option_limit_int { + struct cmdline_limit_int { intptr_t min, max; }* intptr_limit; - struct cmdline_option_limit_uint { + struct cmdline_limit_uint { uintptr_t min, max; }* uintptr_limit; void* limit; @@ -69,14 +69,3 @@ struct cmdline_option { // Parses the command line and invokes all options. void cmdline_parse(const char* cmdline); - -static_assert( - 0 == - _Generic( - (cmdline_parse), - void (*)(const char*): CMDLINE_STRING, - void (*)(bool): CMDLINE_BOOL, - void (*)(intptr_t): CMDLINE_INTPTR, - void (*)(uintptr_t): CMDLINE_UINTPTR - ) -); diff --git a/include/zinnia/compiler.h b/include/zinnia/compiler.h index c467a05..19093d5 100644 --- a/include/zinnia/compiler.h +++ b/include/zinnia/compiler.h @@ -15,6 +15,7 @@ #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. diff --git a/include/zinnia/device.h b/include/zinnia/device.h new file mode 100644 index 0000000..775f43f --- /dev/null +++ b/include/zinnia/device.h @@ -0,0 +1,7 @@ +#pragma once +#include + +struct device { + const char* name; + struct module* owner; +}; diff --git a/include/zinnia/init.h b/include/zinnia/init.h index a5cf695..3956c2a 100644 --- a/include/zinnia/init.h +++ b/include/zinnia/init.h @@ -1,10 +1,10 @@ #pragma once -#include -#include #include #include #include +#include +#include #define __init __used, __section(".init.text"), __cold #define __initdata __used, __section(".init.data") @@ -28,7 +28,9 @@ struct boot_info { phys_t rsdp; }; +[[__visibility("hidden")]] extern uint8_t __ld_stack_top[]; +[[__visibility("hidden")]] extern uint8_t __ld_stack_bottom[]; extern phys_t rsdp_addr; diff --git a/include/zinnia/module.h b/include/zinnia/module.h new file mode 100644 index 0000000..690047e --- /dev/null +++ b/include/zinnia/module.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +#define MODULE_PROPERTY(name, data) \ + [[__used, __section(".mod." name)]] \ + static const char UNIQUE_IDENT(_name)[] = data; + +#define MODULE(desc, author, license, version, entry) \ + void __module_start(struct module* _module) { \ + entry(_module); \ + } \ + MODULE_PROPERTY("author", author); \ + MODULE_PROPERTY("desc", desc); \ + MODULE_PROPERTY("version", version); \ + MODULE_PROPERTY("license", license); + +struct module { + const char* name; + struct module* owner; +}; + +#define THIS_MODULE (struct module*)nullptr diff --git a/include/zinnia/percpu.h b/include/zinnia/percpu.h index 1e3c236..4889d6c 100644 --- a/include/zinnia/percpu.h +++ b/include/zinnia/percpu.h @@ -9,7 +9,25 @@ ASSERT_TYPE(struct arch_percpu); // bits/percpu.h -#define __percpu __used, __section(".percpu") +/* +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_ref(x) ((typeof(&(x)))((void*)percpu_get() + ((void*)&(x) - (void*)&percpu_bsp))) // CPU-relative information. struct percpu { diff --git a/include/zinnia/vma.h b/include/zinnia/vma.h index 4359fbb..3c39bae 100644 --- a/include/zinnia/vma.h +++ b/include/zinnia/vma.h @@ -19,7 +19,7 @@ errno_t vma_new(struct vma** out); void vma_free(struct vma* v); errno_t vma_map( - struct vma* vm, + struct vma* vma, struct vmo* vmo, uintptr_t addr, size_t len, diff --git a/meson.build b/meson.build index a14742d..fc6c7b2 100644 --- a/meson.build +++ b/meson.build @@ -38,57 +38,58 @@ add_project_arguments( '-fno-stack-protector', '-ffunction-sections', '-fdata-sections', + '-ffreestanding', + '-nostdinc', # We provide our own headers. + '-fno-stack-protector', language: 'c', ) add_project_link_arguments( + '-ffreestanding', + '-nostdlib', '-znoexecstack', '-Wl,--gc-sections', '-Wl,--build-id=none', language: 'c', ) -common_includes = include_directories('include') +common_includes = [ + include_directories('include'), + include_directories('arch' / target_machine.cpu_family() / 'include'), +] cfg = configuration_data() cfg.set_quoted('ZINNIA_VERSION', meson.project_version()) cfg.set_quoted('ZINNIA_ARCH', target_machine.cpu_family()) cfg.set_quoted('ZINNIA_COMPILER_ID', c_compiler.get_id() + ' ' + c_compiler.version()) cfg.set_quoted('ZINNIA_LINKER_ID', c_compiler.get_linker_id()) - +# # Parse kernel config kv = import('keyval') kconfig = kv.load(get_option('config_path')) foreach k, v : kconfig if v == 'y' cfg.set10(k, true) + elif v == 'n' + cfg.set10(k, false) else cfg.set(k, v) endif endforeach -kernel_c_args = [ - '-ffreestanding', - '-nostdinc', # We provide our own headers. - '-fno-stack-protector', - '-fno-pie', -] +kernel_c_args = [] kernel_lds = meson.current_source_dir() / 'boot' / 'kernel.ld' - kernel_link_args = [ - '-ffreestanding', - '-nostdlib', - '-static', '-lgcc', + '-static-libgcc', '-T' + kernel_lds, + '-Wl,--export-dynamic', ] -kernel_includes = [ - include_directories('arch' / target_machine.cpu_family() / 'include'), -] - +kernel_includes = [] kernel_sources = [] +modules = {} # Goes first so we can add arch-specific flags to drivers. subdir('arch' / target_machine.cpu_family()) @@ -104,18 +105,61 @@ configure_file( output: 'config.h', ) +mod_summary = {} +foreach name, v : modules + is_modular = v.get('modular', false) + mod_sources = v.get('sources') + mod_c_args = v.get('c_args', []) + mod_link_args = v.get('link_args', []) + mod_includes = v.get('include_directories', []) + mod_link = v.get('link_with', []) + + if is_modular + shared_library( + name, + sources: mod_sources, + c_args: ['-fPIC', '-fPIE', '-DIN_MODULE', mod_c_args], + link_args: [ + '-T' + module_lds, mod_link_args, + ], + link_depends: module_lds, + include_directories: [ + common_includes, + kernel_includes, # We want this, actually + mod_includes, + ], + name_prefix: '', + name_suffix: 'kso', + link_with: mod_link, + override_options: ['b_lundef=false'], + #link_depends: kernel.full_path(), + ) + else + kernel_sources += mod_sources + kernel_c_args += mod_c_args + kernel_includes += mod_includes + kernel_link_args += mod_link_args + endif + + mod_summary += {name: is_modular} +endforeach + +# Kernel executable( 'zinnia', include_directories: [ common_includes, kernel_includes, ], - c_args: kernel_c_args, + c_args: ['-DIN_KERNEL', kernel_c_args], link_args: kernel_link_args, link_depends: kernel_lds, - sources: [ - kernel_sources, - ], + sources: kernel_sources, install: true, install_dir: get_option('datadir') / 'zinnia', + pie: true, ) + +# Print a summary +summary(mod_summary, section: 'Driver configuration') +summary(kconfig, bool_yn: true, section: 'Kernel configuration') diff --git a/scripts/get_modinfo.py b/scripts/get_modinfo.py new file mode 100755 index 0000000..2f80449 --- /dev/null +++ b/scripts/get_modinfo.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# Small script to print all options available inside a built kernel. +# fmt: off +import sys + +from elftools.elf.elffile import ELFFile + +SIZEOF_PTR = 8 +SIZEOF_STRUCT = 40 +ENDIAN = "little" + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Provide a path to the kernel binary to use") + sys.exit(1) + + with open(sys.argv[1], "rb") as elffile: + file = ELFFile(elffile) + + version = "?" + author = "?" + desc = "?" + license = "?" + + for segment in file.iter_segments(): + match segment["p_type"]: + case 0x60000001: version = segment.data()[:-1].decode() + case 0x60000002: author = segment.data()[:-1].decode() + case 0x60000003: desc = segment.data()[:-1].decode() + case 0x60000004: license = segment.data()[:-1].decode() + + print(f"Module info for \"{sys.argv[1]}\"") + print(f"Description:\t{desc}") + print(f"Version:\t{version}") + print(f"Author(s):\t{author}") + print(f"License:\t{license}")