diff --git a/arch/x86_64/include/bits/sched.h b/arch/x86_64/include/bits/sched.h index 775a57d..1d4f571 100644 --- a/arch/x86_64/include/bits/sched.h +++ b/arch/x86_64/include/bits/sched.h @@ -1,10 +1,12 @@ #pragma once +#include #include struct arch_task_context { uint64_t rsp; uint8_t* fpu_region; + phys_t fpu_phys; uint16_t ds, es, fs, gs; uint64_t fs_base, gs_base; }; diff --git a/arch/x86_64/include/x86_64/defs.h b/arch/x86_64/include/x86_64/defs.h index b1782e7..54501bd 100644 --- a/arch/x86_64/include/x86_64/defs.h +++ b/arch/x86_64/include/x86_64/defs.h @@ -185,6 +185,7 @@ #define MSR_EFER_FFXSR (1 << 14) #define MSR_EFER_TCE (1 << 15) +#define MSR_PAT (0x277) #define MSR_EFER (0xC0000080) #define MSR_STAR (0xC0000081) #define MSR_LSTAR (0xC0000082) @@ -194,6 +195,13 @@ #define MSR_GS_BASE (0xC0000101) #define MSR_KERNEL_GS_BASE (0xC0000102) +#define PAT_UC (0x0) +#define PAT_WC (0x1) +#define PAT_WT (0x4) +#define PAT_WP (0x5) +#define PAT_WB (0x6) +#define PAT_UCM (0x7) + #define CPL_USER (0x3) #define CPL_KERNEL (0x0) diff --git a/arch/x86_64/include/x86_64/pmap.h b/arch/x86_64/include/x86_64/pmap.h index 70ba4ed..d4b3d92 100644 --- a/arch/x86_64/include/x86_64/pmap.h +++ b/arch/x86_64/include/x86_64/pmap.h @@ -12,7 +12,7 @@ enum : pte_t { ARCH_FLAG_SIZE = 1 << 7, ARCH_FLAG_GLOBAL = 1 << 8, ARCH_FLAG_AVAILABLE = 1 << 9, - ARCH_FLAG_ATTRIBUTE_TABLE = 1 << 10, + ARCH_FLAG_ATTRIBUTE_TABLE = 1 << 7, ARCH_FLAG_EXECUTE_DISABLE = 1LU << 63, ARCH_PTE_ADDR_MASK = 0x000F'FFFF'FFFF'F000, diff --git a/arch/x86_64/percpu.c b/arch/x86_64/percpu.c index ff16028..a669013 100644 --- a/arch/x86_64/percpu.c +++ b/arch/x86_64/percpu.c @@ -56,6 +56,12 @@ void x86_64_cpu_setup(struct percpu* cpu) { // TODO: not if FRED idt_load(); + asm_wrmsr( + MSR_PAT, + PAT_WB | PAT_WT << 8 | PAT_UCM << 16 | PAT_UC << 24 | (uint64_t)PAT_WP << 32 | (uint64_t)PAT_WC << 40 | + (uint64_t)PAT_UCM << 48 | (uint64_t)PAT_UC << 56 + ); + // Syscall extension. asm_wrmsr(MSR_EFER, asm_rdmsr(MSR_EFER) | MSR_EFER_SCE); union ia32_star star = {0}; diff --git a/arch/x86_64/pmap.c b/arch/x86_64/pmap.c index 94194af..d5418a1 100644 --- a/arch/x86_64/pmap.c +++ b/arch/x86_64/pmap.c @@ -6,6 +6,10 @@ void pte_clear(pte_t* pte) { *pte = 0; } +void pte_flush(uintptr_t vaddr) { + asm volatile("invlpg [%0]" ::"r"(vaddr) : "memory"); +} + pte_t pte_build(phys_t addr, enum pte_flags flags, enum cache_mode cache) { pte_t result = ((pte_t)addr & ARCH_PTE_ADDR_MASK) | ARCH_FLAG_PRESENT; @@ -19,6 +23,21 @@ pte_t pte_build(phys_t addr, enum pte_flags flags, enum cache_mode cache) { result |= ARCH_FLAG_READ_WRITE; if (!(flags & PTE_EXEC)) result |= ARCH_FLAG_EXECUTE_DISABLE; + + switch (cache) { + case CACHE_ANY: + case CACHE_WRITE_BACK: + break; + case CACHE_WRITE_THROUGH: + result |= ARCH_FLAG_WRITE_THROUGH; + break; + case CACHE_MMIO: + result |= ARCH_FLAG_CACHE_DISABLE | ARCH_FLAG_WRITE_THROUGH; + break; + case CACHE_WRITE_COMBINE: + result |= ARCH_FLAG_ATTRIBUTE_TABLE | ARCH_FLAG_WRITE_THROUGH; + break; + } } return result; } diff --git a/arch/x86_64/sched.c b/arch/x86_64/sched.c index 1ea6dd5..5782456 100644 --- a/arch/x86_64/sched.c +++ b/arch/x86_64/sched.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -58,7 +59,7 @@ struct task* arch_sched_switch(struct task* from, struct task* to) { struct arch_task_context* from_ctx = &from->context; struct arch_task_context* to_ctx = &to->context; - cpu->tss.rsp0 = to->kernel_stack + KERNEL_STACK_SIZE; + cpu->tss.rsp0 = kernel_stack_top(&to->kernel_stack); if (from_ctx->fpu_region != nullptr) { cpu->fpu_save(from_ctx->fpu_region); @@ -90,15 +91,17 @@ struct task* arch_sched_switch(struct task* from, struct task* to) { return perform_switch(&from_ctx->rsp, to_ctx->rsp, from); } +// Calls task_entry with the correct parameters. [[__naked]] void task_entry_thunk() { asm volatile( "mov rdi, rbx\n" "mov rsi, r12\n" + "mov rdx, rax\n" "jmp %0" : : "r"(task_entry) - : "memory" + : "memory", "rdi", "rsi", "rdx" ); } @@ -111,8 +114,10 @@ errno_t arch_task_init( ) { struct arch_percpu* cpu = percpu_ref(arch_data); + assert((stack_start & 0xF) == 0, "Task stack is not 16-byte aligned!\n"); + // Prepare a dummy stack with an entry point function to return to. - struct task_frame* frame = (struct task_frame*)stack_start - 1; + struct task_frame* frame = (struct task_frame*)(stack_start - sizeof(uint64_t)) - 1; frame->rbx = (uint64_t)entry; frame->r12 = arg0; frame->rip = (uint64_t)task_entry_thunk; @@ -133,6 +138,7 @@ errno_t arch_task_init( for (size_t i = 0; i < fpu_size; i += arch_mem_page_size()) pmap_map(&kernel_vma.pmap, fpu_base + i, pages + i, PTE_WRITE | PTE_READ, CACHE_WRITE_BACK); context->fpu_region = (void*)fpu_base; + context->fpu_phys = pages; context->ds = asm_read_ds(); context->es = asm_read_es(); @@ -145,6 +151,21 @@ errno_t arch_task_init( return 0; } +void arch_task_fini(struct arch_task_context* context) { + if (context->fpu_region == nullptr) + return; + + const size_t page_size = arch_mem_page_size(); + const size_t fpu_size = percpu_ref(arch_data)->fpu_size; + const uintptr_t fpu_base = (uintptr_t)context->fpu_region; + for (size_t i = 0; i < fpu_size; i += page_size) + pmap_unmap(&kernel_vma.pmap, fpu_base + i); + mem_phys_free(context->fpu_phys, ALIGN_UP(fpu_size, page_size) / page_size); + vm_free(fpu_base, fpu_size); + + context->fpu_region = nullptr; +} + [[__naked]] void arch_sched_preempt_disable() { asm volatile( diff --git a/arch/x86_64/smp.c b/arch/x86_64/smp.c index 5b311ef..40df9c9 100644 --- a/arch/x86_64/smp.c +++ b/arch/x86_64/smp.c @@ -192,7 +192,7 @@ static bool start_ap(phys_t trampoline, uint32_t temp_cr3, uint32_t lapic_id) { return false; } - log("smp: Starting CPU %zu (LAPIC %u)\n", cpu->id, lapic_id); + log("smp: Starting CPU %zu\n", cpu->id); memcpy(HHDM_PTR(trampoline), smp_trampoline_start, trampoline_size); diff --git a/boot/kernel.ld b/boot/kernel.ld index 9abd38c..287a800 100644 --- a/boot/kernel.ld +++ b/boot/kernel.ld @@ -28,11 +28,17 @@ SECTIONS __ld_cmdline_start = .; KEEP(*(.cmdline)) __ld_cmdline_end = .; - } :rodata .rodata : { *(.rodata .rodata.*) + + /* Builtin module entry points */ + . = ALIGN(8); + __ld_mod_entry_start = .; + KEEP(*(.mod.entry .mod.entry.*)) + __ld_mod_entry_end = .; + *(.got .got.*) __ld_rodata_end = .; diff --git a/boot/main.c b/boot/main.c index 2440256..5dc0154 100644 --- a/boot/main.c +++ b/boot/main.c @@ -7,9 +7,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -27,34 +29,37 @@ static void kernel_main_task(uintptr_t arg0) { log("main: Hello from main task!\n"); - assert(info->num_files >= 1, "No init executable provided\n"); + // Initialize built-in modules. + module_init(); + + assert(info->num_files >= 1, "No init executable provided"); struct vma* init_space; assert(vma_new(&init_space) == EOK, ""); - assert(false, "TODO!"); - struct boot_file* file_data = &info->files[0]; struct paged_vmo* init_file; assert(vmo_new_phys(&init_file) == EOK, ""); vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr); - log("main: %s:%i\n", __FUNCTION__, __LINE__); - // Load init. const char* init_argv[] = {"init", nullptr}; const char* init_envp[] = {nullptr}; - struct task* init_task = nullptr; - errno_t status = 0; + struct exec_info exec = { + .space = init_space, + .file_obj = &init_file->object, + .argv = init_argv, + .envp = init_envp, + }; - assert(false, "Not implemented!"); + struct task* init_task = nullptr; + errno_t status = elf_load(&exec, &init_task); + vmo_unref(&init_file->object); assert(status == 0, "Failed to load init process (%i)\n", status); sched_add_task(&percpu_get()->sched, init_task); - log("main: %s:%i\n", __FUNCTION__, __LINE__); - while (true) { irq_wait(); } diff --git a/core/clock.c b/core/clock.c index 17d63a8..07658e0 100644 --- a/core/clock.c +++ b/core/clock.c @@ -39,8 +39,6 @@ bool clock_switch(struct clock* clock) { } } - log("clock: Switching to clock source \"%s\"\n", clock->name); - uint64_t elapsed = clock_get_elapsed_ns_locked(); clock->reset(clock); @@ -48,6 +46,8 @@ bool clock_switch(struct clock* clock) { active_clock = clock; spin_unlock(&lock); + + log("clock: Switching to clock source \"%s\"\n", clock->name); return true; } diff --git a/core/elf.c b/core/elf.c index 4a8b341..c1c0b6b 100644 --- a/core/elf.c +++ b/core/elf.c @@ -14,13 +14,6 @@ #include #include -struct exec_info { - struct vma* space; - struct vmo* file_obj; - const char** argv; - const char** envp; -}; - errno_t elf_load(struct exec_info* info, struct task** out) { errno_t err; diff --git a/core/mem/meson.build b/core/mem/meson.build index db3cf91..a510624 100644 --- a/core/mem/meson.build +++ b/core/mem/meson.build @@ -3,6 +3,7 @@ kernel_sources += files( 'init.c', 'pmm.c', 'slab.c', + 'stack.c', 'usercopy.c', 'virt.c', 'vma.c', diff --git a/core/mem/pmap.c b/core/mem/pmap.c index 6e5e6b7..ec6d243 100644 --- a/core/mem/pmap.c +++ b/core/mem/pmap.c @@ -116,3 +116,21 @@ fail: spin_unlock(&pt->lock); return status; } + +errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr) { + spin_lock(&pt->lock); + + errno_t status = 0; + pte_t* pte = get_pte(pt, vaddr, false, true); + if (pte == nullptr || !pte_is_present(pte)) { + status = ENOENT; + goto fail; + } + + pte_clear(pte); + pte_flush(vaddr); + +fail: + spin_unlock(&pt->lock); + return status; +} diff --git a/core/mem/stack.c b/core/mem/stack.c new file mode 100644 index 0000000..96c55fe --- /dev/null +++ b/core/mem/stack.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +errno_t stack_init(struct stack* ks, size_t size) { + if (!ks || size == 0) + return EINVAL; + + const size_t page_size = arch_mem_page_size(); + size = ALIGN_UP(size, page_size); + + uintptr_t va = vm_alloc(size + page_size); + if (!va) + return ENOMEM; + + phys_t phys; + errno_t status = mem_phys_alloc(size / page_size, 0, &phys); + if (status) + goto err_vm; + + const uintptr_t base = va + page_size; + size_t mapped = 0; + for (; mapped < size; mapped += page_size) { + status = pmap_map(&kernel_vma.pmap, base + mapped, phys + mapped, PTE_READ | PTE_WRITE, CACHE_WRITE_BACK); + if (status) + goto err_map; + } + + ks->base = base; + ks->phys = phys; + ks->size = size; + return 0; + +err_map: + for (size_t i = 0; i < mapped; i += page_size) + pmap_unmap(&kernel_vma.pmap, base + i); + mem_phys_free(phys, size / page_size); +err_vm: + vm_free(va, size + page_size); + return status; +} + +void stack_destroy(struct stack* ks) { + if (!ks || !ks->base) + return; + + const size_t page_size = arch_mem_page_size(); + for (size_t i = 0; i < ks->size; i += page_size) + pmap_unmap(&kernel_vma.pmap, ks->base + i); + + mem_phys_free(ks->phys, ks->size / page_size); + vm_free(ks->base - page_size, ks->size + page_size); + + *ks = (struct stack){0}; +} diff --git a/core/meson.build b/core/meson.build index fade04c..18c343c 100644 --- a/core/meson.build +++ b/core/meson.build @@ -3,6 +3,7 @@ kernel_sources += files( 'console.c', 'elf.c', 'irq.c', + 'module.c', 'panic.c', 'percpu.c', 'print.c', diff --git a/core/module.c b/core/module.c new file mode 100644 index 0000000..005f9da --- /dev/null +++ b/core/module.c @@ -0,0 +1,12 @@ +#include +#include + +extern errno_t (*__ld_mod_entry_start[])(struct module*); +extern errno_t (*__ld_mod_entry_end[])(struct module*); + +void module_init() { + for (auto start = __ld_mod_entry_start; start < __ld_mod_entry_end; start += 1) { + errno_t mod_status = (*start)(nullptr); + assert(mod_status == EOK, "Built-in entry point returned %i", mod_status); + } +} diff --git a/core/print.c b/core/print.c index 19ecd71..9946979 100644 --- a/core/print.c +++ b/core/print.c @@ -2,11 +2,12 @@ #include #include #include +#include +#include +#include #include #include #include -#include -#include typedef void (*log_fn_t)(void* ctx, const char* buf, size_t len); @@ -312,13 +313,23 @@ static void printf_console(void*, const char* msg, size_t len) { console_write(msg, len); } +static struct spinlock print_lock = {}; + void kprintf(const char* message, ...) { + spin_lock(&print_lock); + va_list args; va_start(args, message); do_print(printf_console, nullptr, message, args); va_end(args); + + spin_unlock(&print_lock); } void kvprintf(const char* message, va_list args) { + spin_lock(&print_lock); + do_print(printf_console, nullptr, message, args); + + spin_unlock(&print_lock); } diff --git a/core/sched/sched_dumb.c b/core/sched/sched_dumb.c index 3f1ddd9..4a7b600 100644 --- a/core/sched/sched_dumb.c +++ b/core/sched/sched_dumb.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,11 @@ static struct task* next_task(struct scheduler* sched) { return t; } +static void finish_switch(struct task* prev) { + if (prev->state == TASK_STATE_DEAD) + task_destroy(prev); +} + static void do_reschedule(struct scheduler* sched) { struct task* from = sched->current; struct task* to = next_task(sched); @@ -82,12 +88,13 @@ static void do_reschedule(struct scheduler* sched) { struct percpu* cpu = percpu_get(); from->user_stack = cpu->user_stack; - cpu->kernel_stack = to->kernel_stack + KERNEL_STACK_SIZE; + cpu->kernel_stack = kernel_stack_top(&to->kernel_stack); cpu->user_stack = to->user_stack; struct irq_percpu irq_state = *percpu_ref(irq_data); - arch_sched_switch(from, to); + struct task* prev = arch_sched_switch(from, to); *percpu_ref(irq_data) = irq_state; + finish_switch(prev); irq_unlock(); } @@ -117,17 +124,17 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt strncpy(new_task->name, name, sizeof(new_task->name)); // Allocate a kernel stack. - new_task->kernel_stack = (uintptr_t)mem_alloc(KERNEL_STACK_SIZE, 0); - if (!new_task->kernel_stack) { + errno_t s = stack_init(&new_task->kernel_stack, KERNEL_STACK_SIZE); + if (s != 0) { mem_free(new_task); - return ENOMEM; + return s; } new_task->user_stack = 0; // Initialize the arch-dependent parts. - errno_t s = arch_task_init(&new_task->context, entry, arg0, new_task->kernel_stack + KERNEL_STACK_SIZE, true); + s = arch_task_init(&new_task->context, entry, arg0, kernel_stack_top(&new_task->kernel_stack), true); if (s != 0) { - mem_free((void*)new_task->kernel_stack); + stack_destroy(&new_task->kernel_stack); mem_free(new_task); return s; } @@ -136,7 +143,15 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt return 0; } -void task_entry(task_fn_t entry, uintptr_t arg0) { +void task_destroy(struct task* task) { + arch_task_fini(&task->context); + stack_destroy(&task->kernel_stack); + mem_free(task); +} + +void task_entry(task_fn_t entry, uintptr_t arg0, struct task* prev) { + finish_switch(prev); + *percpu_ref(irq_data) = (struct irq_percpu){ .depth = 1, .saved_state = true, diff --git a/dev/acpi/init.c b/dev/acpi/init.c index 8607e46..c308026 100644 --- a/dev/acpi/init.c +++ b/dev/acpi/init.c @@ -1,10 +1,22 @@ #include +#include #include #include phys_t acpi_rsdp_addr = 0; +static bool use_acpi = true; +void use_acpi_option(bool use) { + use_acpi = use; +} +CMDLINE_OPTION("acpi", "Enable ACPI firmware subsystem", use_acpi_option); + void acpi_init(struct boot_info* info) { + if (!use_acpi) { + log("acpi: ACPI disabled on the command line!\n"); + return; + } + if (!info->rsdp) { log("acpi: No RSDP was passed, unable to start ACPI subsystem!\n"); return; diff --git a/dev/block/nvme/core.c b/dev/block/nvme/core.c index a7e564b..ddfde80 100644 --- a/dev/block/nvme/core.c +++ b/dev/block/nvme/core.c @@ -2,11 +2,22 @@ #include #include -void nvme_init(struct module* mod) { +errno_t nvme_init(struct module* mod) { log("Hello world from NVMe!\n"); + + return 0; } -void do_nvme(bool on) {} -CMDLINE_OPTION("nvme_on", "My description", do_nvme); +errno_t nvme_exit(struct module* mod) { + log("Good bye from NVMe!\n"); -MODULE("NVME", "Marvin Friedrich", "ISC", "1.0", nvme_init); + return 0; +} + +MODULE_ENTRY(nvme_init); +MODULE_EXIT(nvme_exit); + +MODULE_DESC("NVMe Block Devices"); +MODULE_AUTHOR("Marvin Friedrich"); +MODULE_LICENSE("ISC"); +MODULE_VERSION("1.0"); diff --git a/dev/module.ld b/dev/module.ld index 0545f6a..0993655 100644 --- a/dev/module.ld +++ b/dev/module.ld @@ -1,7 +1,5 @@ /* Linker script for kernel modules */ -ENTRY(__module_start) - PHDRS { text PT_LOAD FLAGS(5); @@ -13,6 +11,8 @@ PHDRS moddesc 0x60000003; modlicense 0x60000004; modcmdline 0x60000005; + modentry 0x60000006; + modexit 0x60000007; } SECTIONS @@ -37,10 +37,6 @@ SECTIONS *(.got.plt .got.plt.*) } :rodata - .cmdline : { - KEEP(*(.cmdline)) - } :rodata :modcmdline - .mod.version : { KEEP(*(.mod.version)) } :rodata :modversion @@ -57,6 +53,18 @@ SECTIONS KEEP(*(.mod.license)) } :rodata :modlicense + .cmdline : { + KEEP(*(.cmdline)) + } :rodata :modcmdline + + .mod.entry : { + KEEP(*(.mod.entry)) + } :rodata :modentry + + .mod.exit : { + KEEP(*(.mod.exit)) + } :rodata :modexit + . = ALIGN(CONSTANT(MAXPAGESIZE)); /* Read-Write data */ diff --git a/include/arch/sched.h b/include/arch/sched.h index 99ac429..889efb4 100644 --- a/include/arch/sched.h +++ b/include/arch/sched.h @@ -13,6 +13,7 @@ errno_t arch_task_init( uintptr_t stack_start, bool is_user ); +void arch_task_fini(struct arch_task_context* context); [[noreturn]] void arch_sched_jump_to_context(struct arch_context* context); [[noreturn]] diff --git a/include/zinnia/compiler.h b/include/zinnia/compiler.h index 82a4b33..b253792 100644 --- a/include/zinnia/compiler.h +++ b/include/zinnia/compiler.h @@ -14,7 +14,15 @@ #define __format(like, ...) gnu::format(like, __VA_ARGS__) #define __always_inline gnu::always_inline #define __visibility gnu::visibility -#define __pure gnu::pure + +// TODO: Workaround for clang which doesn't have these C23 standard attributes yet. +#if !__has_c_attribute(unsequenced) +#define unsequenced gnu::const +#endif + +#if !__has_c_attribute(reproducible) +#define reproducible gnu::pure +#endif // Only clang has these hints, GCC would throw a warning here. // clang::noderef also don't support the C23 attribute format. diff --git a/include/zinnia/elf.h b/include/zinnia/elf.h index 9808027..03a5c23 100644 --- a/include/zinnia/elf.h +++ b/include/zinnia/elf.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -339,3 +340,16 @@ static inline uint32_t ELF64_R_SYM(uint64_t info) { static inline uint32_t ELF64_R_TYPE(uint64_t info) { return info & 0xFFFFFFFF; } + +struct vma; +struct vmo; +struct task; + +struct exec_info { + struct vma* space; + struct vmo* file_obj; + const char** argv; + const char** envp; +}; + +errno_t elf_load(struct exec_info* info, struct task** out); diff --git a/include/zinnia/module.h b/include/zinnia/module.h index 690047e..8998ee9 100644 --- a/include/zinnia/module.h +++ b/include/zinnia/module.h @@ -1,24 +1,38 @@ #pragma once #include +#include #include #include #define MODULE_PROPERTY(name, data) \ [[__used, __section(".mod." name)]] \ - static const char UNIQUE_IDENT(_name)[] = data; + static const char UNIQUE_IDENT(_name)[] = data -#define MODULE(desc, author, license, version, entry) \ - void __module_start(struct module* _module) { \ - entry(_module); \ +#define MODULE_AUTHOR(author) MODULE_PROPERTY("author", author) +#define MODULE_DESC(desc) MODULE_PROPERTY("desc", desc) +#define MODULE_VERSION(version) MODULE_PROPERTY("version", version) +#define MODULE_LICENSE(license) MODULE_PROPERTY("license", license) + +#define MODULE_ENTRY(func) \ + [[__used]] \ + errno_t __module_entry(struct module* __module) { \ + return func(__module); \ } \ - MODULE_PROPERTY("author", author); \ - MODULE_PROPERTY("desc", desc); \ - MODULE_PROPERTY("version", version); \ - MODULE_PROPERTY("license", license); + [[__used, __section(".mod.entry")]] \ + static const void* __entry_fn = &__module_entry + +#define MODULE_EXIT(func) \ + [[__used]] \ + errno_t __module_exit(struct module* __module) { \ + return func(__module); \ + } \ + [[__used, __section(".mod.exit")]] \ + static const void* __exit_fn = &__module_exit struct module { const char* name; - struct module* owner; }; #define THIS_MODULE (struct module*)nullptr + +void module_init(); diff --git a/include/zinnia/pmap.h b/include/zinnia/pmap.h index b6a51f8..4c19d05 100644 --- a/include/zinnia/pmap.h +++ b/include/zinnia/pmap.h @@ -36,6 +36,7 @@ errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr); void pmap_set(struct pmap* pt); void pte_clear(pte_t* pte); +void pte_flush(uintptr_t vaddr); pte_t pte_build(phys_t addr, enum pte_flags flags, enum cache_mode cache); bool pte_is_present(pte_t* pte); bool pte_is_dir(pte_t* pte); diff --git a/include/zinnia/sched.h b/include/zinnia/sched.h index 4dda92c..dcaf3d9 100644 --- a/include/zinnia/sched.h +++ b/include/zinnia/sched.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,7 @@ struct task { enum task_state state; struct arch_task_context context; struct usercopy_region* usercopy_region; - uintptr_t kernel_stack; + struct stack kernel_stack; uintptr_t user_stack; size_t time_slice; int8_t priority; @@ -48,8 +49,9 @@ struct scheduler { typedef void (*task_fn_t)(uintptr_t arg0); errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out); +void task_destroy(struct task* task); [[noreturn]] -void task_entry(task_fn_t entry, uintptr_t arg0); +void task_entry(task_fn_t entry, uintptr_t arg0, struct task* prev); void sched_init(struct scheduler* sched); void sched_reschedule(struct scheduler* sched); diff --git a/include/zinnia/stack.h b/include/zinnia/stack.h new file mode 100644 index 0000000..b7da6f6 --- /dev/null +++ b/include/zinnia/stack.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include +#include + +struct stack { + uintptr_t base; + phys_t phys; + size_t size; +}; + +errno_t stack_init(struct stack* ks, size_t size); +void stack_destroy(struct stack* ks); + +static inline uintptr_t kernel_stack_top(struct stack* ks) { + return ks->base + ks->size; +} diff --git a/include/zinnia/syscall_list.inc b/include/zinnia/syscall_list.inc index 332b342..ed02b54 100644 --- a/include/zinnia/syscall_list.inc +++ b/include/zinnia/syscall_list.inc @@ -2,8 +2,8 @@ #define SYSCALL_DECLARE(number, name, num_args) extern void sys_##name(...); #endif -// SYSCALL_DECLARE(0, exit, -1) -// SYSCALL_DECLARE(1, syslog, -1) +SYSCALL_DECLARE(0, exit, 1) +SYSCALL_DECLARE(1, syslog, 3) SYSCALL_DECLARE(2, getuname, 1) SYSCALL_DECLARE(3, setuname, 1) SYSCALL_DECLARE(4, archctl, 2) diff --git a/syscalls/exit.c b/syscalls/exit.c new file mode 100644 index 0000000..1b21b6c --- /dev/null +++ b/syscalls/exit.c @@ -0,0 +1,12 @@ +#include +#include + +struct syscall_ret sys_exit(int err) { + struct syscall_ret ret = {}; + + ret.errno = ENOSYS; + + panic("sys::exit() not implemented!\n"); + + return ret; +} diff --git a/syscalls/meson.build b/syscalls/meson.build index 4ed0766..c7af383 100644 --- a/syscalls/meson.build +++ b/syscalls/meson.build @@ -1,5 +1,7 @@ kernel_sources += files( 'archctl.c', 'dispatch.c', + 'exit.c', + 'syslog.c', 'uname.c', ) diff --git a/syscalls/syslog.c b/syscalls/syslog.c new file mode 100644 index 0000000..86cc658 --- /dev/null +++ b/syscalls/syslog.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +enum syslog_kind : uintptr_t { + SYSLOG_EMERG = 0, + SYSLOG_ALERT = 1, + SYSLOG_CRIT = 2, + SYSLOG_ERR = 3, + SYSLOG_WARNING = 4, + SYSLOG_NOTICE = 5, + SYSLOG_INFO = 6, + SYSLOG_DEBUG = 7, +}; + +struct syscall_ret sys_syslog(enum syslog_kind kind, __user char* message, size_t len) { + struct syscall_ret ret = {}; + + const size_t buf_len = MIN(len + 1, 0x1000); + char* buf = mem_alloc(buf_len, ALLOC_NOZERO); + usercopy_read(buf, message, buf_len - 1); + buf[buf_len] = 0; + + const char* log_level; + switch (kind) { + case SYSLOG_EMERG: + log_level = "emerg"; + break; + case SYSLOG_ALERT: + log_level = "alert"; + break; + case SYSLOG_CRIT: + log_level = "crit"; + break; + case SYSLOG_ERR: + log_level = "err"; + break; + case SYSLOG_WARNING: + log_level = "warning"; + break; + case SYSLOG_NOTICE: + log_level = "notice"; + break; + case SYSLOG_INFO: + log_level = "info"; + break; + case SYSLOG_DEBUG: + log_level = "debug"; + break; + default: + log_level = "invalid"; + } + + log("syslog(%s): %s\n", log_level, buf); + + mem_free(buf); + + return ret; +}