more fixes
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+24
-3
@@ -1,4 +1,5 @@
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/assert.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/percpu.h>
|
||||
@@ -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(
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
+7
-1
@@ -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 = .;
|
||||
|
||||
+15
-10
@@ -7,9 +7,11 @@
|
||||
#include <zinnia/elf.h>
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/irq.h>
|
||||
#include <zinnia/module.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <zinnia/vma.h>
|
||||
#include <zinnia/vmo.h>
|
||||
#include <config.h>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,6 @@
|
||||
#include <bits/elf.h>
|
||||
#include <stdckdint.h>
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ kernel_sources += files(
|
||||
'init.c',
|
||||
'pmm.c',
|
||||
'slab.c',
|
||||
'stack.c',
|
||||
'usercopy.c',
|
||||
'virt.c',
|
||||
'vma.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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/pmap.h>
|
||||
#include <zinnia/stack.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <zinnia/virt.h>
|
||||
#include <zinnia/vma.h>
|
||||
#include <arch/mem.h>
|
||||
|
||||
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};
|
||||
}
|
||||
@@ -3,6 +3,7 @@ kernel_sources += files(
|
||||
'console.c',
|
||||
'elf.c',
|
||||
'irq.c',
|
||||
'module.c',
|
||||
'panic.c',
|
||||
'percpu.c',
|
||||
'print.c',
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <zinnia/assert.h>
|
||||
#include <zinnia/module.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
+13
-2
@@ -2,11 +2,12 @@
|
||||
#include <zinnia/console.h>
|
||||
#include <zinnia/panic.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <zinnia/stdlib.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <zinnia/stdlib.h>
|
||||
#include <zinnia/string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+23
-8
@@ -8,6 +8,7 @@
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <zinnia/stack.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <zinnia/tailq.h>
|
||||
#include <zinnia/vma.h>
|
||||
@@ -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,
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
#include <zinnia/acpi.h>
|
||||
#include <zinnia/cmdline.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/types.h>
|
||||
|
||||
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;
|
||||
|
||||
+15
-4
@@ -2,11 +2,22 @@
|
||||
#include <zinnia/module.h>
|
||||
#include <zinnia/print.h>
|
||||
|
||||
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");
|
||||
|
||||
+14
-6
@@ -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 */
|
||||
|
||||
@@ -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]]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <bits/elf.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -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);
|
||||
|
||||
+23
-9
@@ -1,24 +1,38 @@
|
||||
#pragma once
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/stack.h>
|
||||
#include <zinnia/tailq.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <bits/sched.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <zinnia/panic.h>
|
||||
#include <zinnia/syscall.h>
|
||||
|
||||
struct syscall_ret sys_exit(int err) {
|
||||
struct syscall_ret ret = {};
|
||||
|
||||
ret.errno = ENOSYS;
|
||||
|
||||
panic("sys::exit() not implemented!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
kernel_sources += files(
|
||||
'archctl.c',
|
||||
'dispatch.c',
|
||||
'exit.c',
|
||||
'syslog.c',
|
||||
'uname.c',
|
||||
)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/panic.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/syscall.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user