more fixes
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/types.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct arch_task_context {
|
struct arch_task_context {
|
||||||
uint64_t rsp;
|
uint64_t rsp;
|
||||||
uint8_t* fpu_region;
|
uint8_t* fpu_region;
|
||||||
|
phys_t fpu_phys;
|
||||||
uint16_t ds, es, fs, gs;
|
uint16_t ds, es, fs, gs;
|
||||||
uint64_t fs_base, gs_base;
|
uint64_t fs_base, gs_base;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -185,6 +185,7 @@
|
|||||||
#define MSR_EFER_FFXSR (1 << 14)
|
#define MSR_EFER_FFXSR (1 << 14)
|
||||||
#define MSR_EFER_TCE (1 << 15)
|
#define MSR_EFER_TCE (1 << 15)
|
||||||
|
|
||||||
|
#define MSR_PAT (0x277)
|
||||||
#define MSR_EFER (0xC0000080)
|
#define MSR_EFER (0xC0000080)
|
||||||
#define MSR_STAR (0xC0000081)
|
#define MSR_STAR (0xC0000081)
|
||||||
#define MSR_LSTAR (0xC0000082)
|
#define MSR_LSTAR (0xC0000082)
|
||||||
@@ -194,6 +195,13 @@
|
|||||||
#define MSR_GS_BASE (0xC0000101)
|
#define MSR_GS_BASE (0xC0000101)
|
||||||
#define MSR_KERNEL_GS_BASE (0xC0000102)
|
#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_USER (0x3)
|
||||||
#define CPL_KERNEL (0x0)
|
#define CPL_KERNEL (0x0)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ enum : pte_t {
|
|||||||
ARCH_FLAG_SIZE = 1 << 7,
|
ARCH_FLAG_SIZE = 1 << 7,
|
||||||
ARCH_FLAG_GLOBAL = 1 << 8,
|
ARCH_FLAG_GLOBAL = 1 << 8,
|
||||||
ARCH_FLAG_AVAILABLE = 1 << 9,
|
ARCH_FLAG_AVAILABLE = 1 << 9,
|
||||||
ARCH_FLAG_ATTRIBUTE_TABLE = 1 << 10,
|
ARCH_FLAG_ATTRIBUTE_TABLE = 1 << 7,
|
||||||
ARCH_FLAG_EXECUTE_DISABLE = 1LU << 63,
|
ARCH_FLAG_EXECUTE_DISABLE = 1LU << 63,
|
||||||
|
|
||||||
ARCH_PTE_ADDR_MASK = 0x000F'FFFF'FFFF'F000,
|
ARCH_PTE_ADDR_MASK = 0x000F'FFFF'FFFF'F000,
|
||||||
|
|||||||
@@ -56,6 +56,12 @@ void x86_64_cpu_setup(struct percpu* cpu) {
|
|||||||
// TODO: not if FRED
|
// TODO: not if FRED
|
||||||
idt_load();
|
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.
|
// Syscall extension.
|
||||||
asm_wrmsr(MSR_EFER, asm_rdmsr(MSR_EFER) | MSR_EFER_SCE);
|
asm_wrmsr(MSR_EFER, asm_rdmsr(MSR_EFER) | MSR_EFER_SCE);
|
||||||
union ia32_star star = {0};
|
union ia32_star star = {0};
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ void pte_clear(pte_t* pte) {
|
|||||||
*pte = 0;
|
*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 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;
|
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;
|
result |= ARCH_FLAG_READ_WRITE;
|
||||||
if (!(flags & PTE_EXEC))
|
if (!(flags & PTE_EXEC))
|
||||||
result |= ARCH_FLAG_EXECUTE_DISABLE;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-3
@@ -1,4 +1,5 @@
|
|||||||
#include <zinnia/alloc.h>
|
#include <zinnia/alloc.h>
|
||||||
|
#include <zinnia/assert.h>
|
||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/percpu.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* from_ctx = &from->context;
|
||||||
struct arch_task_context* to_ctx = &to->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) {
|
if (from_ctx->fpu_region != nullptr) {
|
||||||
cpu->fpu_save(from_ctx->fpu_region);
|
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);
|
return perform_switch(&from_ctx->rsp, to_ctx->rsp, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calls task_entry with the correct parameters.
|
||||||
[[__naked]]
|
[[__naked]]
|
||||||
void task_entry_thunk() {
|
void task_entry_thunk() {
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"mov rdi, rbx\n"
|
"mov rdi, rbx\n"
|
||||||
"mov rsi, r12\n"
|
"mov rsi, r12\n"
|
||||||
|
"mov rdx, rax\n"
|
||||||
"jmp %0"
|
"jmp %0"
|
||||||
:
|
:
|
||||||
: "r"(task_entry)
|
: "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);
|
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.
|
// 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->rbx = (uint64_t)entry;
|
||||||
frame->r12 = arg0;
|
frame->r12 = arg0;
|
||||||
frame->rip = (uint64_t)task_entry_thunk;
|
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())
|
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);
|
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_region = (void*)fpu_base;
|
||||||
|
context->fpu_phys = pages;
|
||||||
|
|
||||||
context->ds = asm_read_ds();
|
context->ds = asm_read_ds();
|
||||||
context->es = asm_read_es();
|
context->es = asm_read_es();
|
||||||
@@ -145,6 +151,21 @@ errno_t arch_task_init(
|
|||||||
return 0;
|
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]]
|
[[__naked]]
|
||||||
void arch_sched_preempt_disable() {
|
void arch_sched_preempt_disable() {
|
||||||
asm volatile(
|
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;
|
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);
|
memcpy(HHDM_PTR(trampoline), smp_trampoline_start, trampoline_size);
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -28,11 +28,17 @@ SECTIONS
|
|||||||
__ld_cmdline_start = .;
|
__ld_cmdline_start = .;
|
||||||
KEEP(*(.cmdline))
|
KEEP(*(.cmdline))
|
||||||
__ld_cmdline_end = .;
|
__ld_cmdline_end = .;
|
||||||
|
|
||||||
} :rodata
|
} :rodata
|
||||||
|
|
||||||
.rodata : {
|
.rodata : {
|
||||||
*(.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.*)
|
*(.got .got.*)
|
||||||
|
|
||||||
__ld_rodata_end = .;
|
__ld_rodata_end = .;
|
||||||
|
|||||||
+15
-10
@@ -7,9 +7,11 @@
|
|||||||
#include <zinnia/elf.h>
|
#include <zinnia/elf.h>
|
||||||
#include <zinnia/init.h>
|
#include <zinnia/init.h>
|
||||||
#include <zinnia/irq.h>
|
#include <zinnia/irq.h>
|
||||||
|
#include <zinnia/module.h>
|
||||||
#include <zinnia/percpu.h>
|
#include <zinnia/percpu.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
|
#include <zinnia/utils.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
#include <zinnia/vmo.h>
|
#include <zinnia/vmo.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@@ -27,34 +29,37 @@ static void kernel_main_task(uintptr_t arg0) {
|
|||||||
|
|
||||||
log("main: Hello from main task!\n");
|
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;
|
struct vma* init_space;
|
||||||
assert(vma_new(&init_space) == EOK, "");
|
assert(vma_new(&init_space) == EOK, "");
|
||||||
|
|
||||||
assert(false, "TODO!");
|
|
||||||
|
|
||||||
struct boot_file* file_data = &info->files[0];
|
struct boot_file* file_data = &info->files[0];
|
||||||
struct paged_vmo* init_file;
|
struct paged_vmo* init_file;
|
||||||
assert(vmo_new_phys(&init_file) == EOK, "");
|
assert(vmo_new_phys(&init_file) == EOK, "");
|
||||||
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
||||||
|
|
||||||
log("main: %s:%i\n", __FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
// Load init.
|
// Load init.
|
||||||
const char* init_argv[] = {"init", nullptr};
|
const char* init_argv[] = {"init", nullptr};
|
||||||
const char* init_envp[] = {nullptr};
|
const char* init_envp[] = {nullptr};
|
||||||
|
|
||||||
struct task* init_task = nullptr;
|
struct exec_info exec = {
|
||||||
errno_t status = 0;
|
.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);
|
assert(status == 0, "Failed to load init process (%i)\n", status);
|
||||||
sched_add_task(&percpu_get()->sched, init_task);
|
sched_add_task(&percpu_get()->sched, init_task);
|
||||||
|
|
||||||
log("main: %s:%i\n", __FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
irq_wait();
|
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();
|
uint64_t elapsed = clock_get_elapsed_ns_locked();
|
||||||
clock->reset(clock);
|
clock->reset(clock);
|
||||||
|
|
||||||
@@ -48,6 +46,8 @@ bool clock_switch(struct clock* clock) {
|
|||||||
active_clock = clock;
|
active_clock = clock;
|
||||||
|
|
||||||
spin_unlock(&lock);
|
spin_unlock(&lock);
|
||||||
|
|
||||||
|
log("clock: Switching to clock source \"%s\"\n", clock->name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,6 @@
|
|||||||
#include <bits/elf.h>
|
#include <bits/elf.h>
|
||||||
#include <stdckdint.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 elf_load(struct exec_info* info, struct task** out) {
|
||||||
errno_t err;
|
errno_t err;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ kernel_sources += files(
|
|||||||
'init.c',
|
'init.c',
|
||||||
'pmm.c',
|
'pmm.c',
|
||||||
'slab.c',
|
'slab.c',
|
||||||
|
'stack.c',
|
||||||
'usercopy.c',
|
'usercopy.c',
|
||||||
'virt.c',
|
'virt.c',
|
||||||
'vma.c',
|
'vma.c',
|
||||||
|
|||||||
@@ -116,3 +116,21 @@ fail:
|
|||||||
spin_unlock(&pt->lock);
|
spin_unlock(&pt->lock);
|
||||||
return status;
|
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',
|
'console.c',
|
||||||
'elf.c',
|
'elf.c',
|
||||||
'irq.c',
|
'irq.c',
|
||||||
|
'module.c',
|
||||||
'panic.c',
|
'panic.c',
|
||||||
'percpu.c',
|
'percpu.c',
|
||||||
'print.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/console.h>
|
||||||
#include <zinnia/panic.h>
|
#include <zinnia/panic.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/stdlib.h>
|
||||||
|
#include <zinnia/string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.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);
|
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);
|
console_write(msg, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct spinlock print_lock = {};
|
||||||
|
|
||||||
void kprintf(const char* message, ...) {
|
void kprintf(const char* message, ...) {
|
||||||
|
spin_lock(&print_lock);
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, message);
|
va_start(args, message);
|
||||||
do_print(printf_console, nullptr, message, args);
|
do_print(printf_console, nullptr, message, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
spin_unlock(&print_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvprintf(const char* message, va_list args) {
|
void kvprintf(const char* message, va_list args) {
|
||||||
|
spin_lock(&print_lock);
|
||||||
|
|
||||||
do_print(printf_console, nullptr, message, args);
|
do_print(printf_console, nullptr, message, args);
|
||||||
|
|
||||||
|
spin_unlock(&print_lock);
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-8
@@ -8,6 +8,7 @@
|
|||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/stack.h>
|
||||||
#include <zinnia/string.h>
|
#include <zinnia/string.h>
|
||||||
#include <zinnia/tailq.h>
|
#include <zinnia/tailq.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
@@ -67,6 +68,11 @@ static struct task* next_task(struct scheduler* sched) {
|
|||||||
return t;
|
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) {
|
static void do_reschedule(struct scheduler* sched) {
|
||||||
struct task* from = sched->current;
|
struct task* from = sched->current;
|
||||||
struct task* to = next_task(sched);
|
struct task* to = next_task(sched);
|
||||||
@@ -82,12 +88,13 @@ static void do_reschedule(struct scheduler* sched) {
|
|||||||
|
|
||||||
struct percpu* cpu = percpu_get();
|
struct percpu* cpu = percpu_get();
|
||||||
from->user_stack = cpu->user_stack;
|
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;
|
cpu->user_stack = to->user_stack;
|
||||||
|
|
||||||
struct irq_percpu irq_state = *percpu_ref(irq_data);
|
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;
|
*percpu_ref(irq_data) = irq_state;
|
||||||
|
finish_switch(prev);
|
||||||
irq_unlock();
|
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));
|
strncpy(new_task->name, name, sizeof(new_task->name));
|
||||||
|
|
||||||
// Allocate a kernel stack.
|
// Allocate a kernel stack.
|
||||||
new_task->kernel_stack = (uintptr_t)mem_alloc(KERNEL_STACK_SIZE, 0);
|
errno_t s = stack_init(&new_task->kernel_stack, KERNEL_STACK_SIZE);
|
||||||
if (!new_task->kernel_stack) {
|
if (s != 0) {
|
||||||
mem_free(new_task);
|
mem_free(new_task);
|
||||||
return ENOMEM;
|
return s;
|
||||||
}
|
}
|
||||||
new_task->user_stack = 0;
|
new_task->user_stack = 0;
|
||||||
|
|
||||||
// Initialize the arch-dependent parts.
|
// 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) {
|
if (s != 0) {
|
||||||
mem_free((void*)new_task->kernel_stack);
|
stack_destroy(&new_task->kernel_stack);
|
||||||
mem_free(new_task);
|
mem_free(new_task);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -136,7 +143,15 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt
|
|||||||
return 0;
|
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){
|
*percpu_ref(irq_data) = (struct irq_percpu){
|
||||||
.depth = 1,
|
.depth = 1,
|
||||||
.saved_state = true,
|
.saved_state = true,
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
#include <zinnia/acpi.h>
|
#include <zinnia/acpi.h>
|
||||||
|
#include <zinnia/cmdline.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/types.h>
|
#include <zinnia/types.h>
|
||||||
|
|
||||||
phys_t acpi_rsdp_addr = 0;
|
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) {
|
void acpi_init(struct boot_info* info) {
|
||||||
|
if (!use_acpi) {
|
||||||
|
log("acpi: ACPI disabled on the command line!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!info->rsdp) {
|
if (!info->rsdp) {
|
||||||
log("acpi: No RSDP was passed, unable to start ACPI subsystem!\n");
|
log("acpi: No RSDP was passed, unable to start ACPI subsystem!\n");
|
||||||
return;
|
return;
|
||||||
|
|||||||
+15
-4
@@ -2,11 +2,22 @@
|
|||||||
#include <zinnia/module.h>
|
#include <zinnia/module.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
|
|
||||||
void nvme_init(struct module* mod) {
|
errno_t nvme_init(struct module* mod) {
|
||||||
log("Hello world from NVMe!\n");
|
log("Hello world from NVMe!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_nvme(bool on) {}
|
errno_t nvme_exit(struct module* mod) {
|
||||||
CMDLINE_OPTION("nvme_on", "My description", do_nvme);
|
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 */
|
/* Linker script for kernel modules */
|
||||||
|
|
||||||
ENTRY(__module_start)
|
|
||||||
|
|
||||||
PHDRS
|
PHDRS
|
||||||
{
|
{
|
||||||
text PT_LOAD FLAGS(5);
|
text PT_LOAD FLAGS(5);
|
||||||
@@ -13,6 +11,8 @@ PHDRS
|
|||||||
moddesc 0x60000003;
|
moddesc 0x60000003;
|
||||||
modlicense 0x60000004;
|
modlicense 0x60000004;
|
||||||
modcmdline 0x60000005;
|
modcmdline 0x60000005;
|
||||||
|
modentry 0x60000006;
|
||||||
|
modexit 0x60000007;
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
@@ -37,10 +37,6 @@ SECTIONS
|
|||||||
*(.got.plt .got.plt.*)
|
*(.got.plt .got.plt.*)
|
||||||
} :rodata
|
} :rodata
|
||||||
|
|
||||||
.cmdline : {
|
|
||||||
KEEP(*(.cmdline))
|
|
||||||
} :rodata :modcmdline
|
|
||||||
|
|
||||||
.mod.version : {
|
.mod.version : {
|
||||||
KEEP(*(.mod.version))
|
KEEP(*(.mod.version))
|
||||||
} :rodata :modversion
|
} :rodata :modversion
|
||||||
@@ -57,6 +53,18 @@ SECTIONS
|
|||||||
KEEP(*(.mod.license))
|
KEEP(*(.mod.license))
|
||||||
} :rodata :modlicense
|
} :rodata :modlicense
|
||||||
|
|
||||||
|
.cmdline : {
|
||||||
|
KEEP(*(.cmdline))
|
||||||
|
} :rodata :modcmdline
|
||||||
|
|
||||||
|
.mod.entry : {
|
||||||
|
KEEP(*(.mod.entry))
|
||||||
|
} :rodata :modentry
|
||||||
|
|
||||||
|
.mod.exit : {
|
||||||
|
KEEP(*(.mod.exit))
|
||||||
|
} :rodata :modexit
|
||||||
|
|
||||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
/* Read-Write data */
|
/* Read-Write data */
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ errno_t arch_task_init(
|
|||||||
uintptr_t stack_start,
|
uintptr_t stack_start,
|
||||||
bool is_user
|
bool is_user
|
||||||
);
|
);
|
||||||
|
void arch_task_fini(struct arch_task_context* context);
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void arch_sched_jump_to_context(struct arch_context* context);
|
void arch_sched_jump_to_context(struct arch_context* context);
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
|
|||||||
@@ -14,7 +14,15 @@
|
|||||||
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
|
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
|
||||||
#define __always_inline gnu::always_inline
|
#define __always_inline gnu::always_inline
|
||||||
#define __visibility gnu::visibility
|
#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.
|
// Only clang has these hints, GCC would throw a warning here.
|
||||||
// clang::noderef also don't support the C23 attribute format.
|
// clang::noderef also don't support the C23 attribute format.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/errno.h>
|
||||||
#include <bits/elf.h>
|
#include <bits/elf.h>
|
||||||
#include <stdint.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) {
|
static inline uint32_t ELF64_R_TYPE(uint64_t info) {
|
||||||
return info & 0xFFFFFFFF;
|
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
|
#pragma once
|
||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MODULE_PROPERTY(name, data) \
|
#define MODULE_PROPERTY(name, data) \
|
||||||
[[__used, __section(".mod." name)]] \
|
[[__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) \
|
#define MODULE_AUTHOR(author) MODULE_PROPERTY("author", author)
|
||||||
void __module_start(struct module* _module) { \
|
#define MODULE_DESC(desc) MODULE_PROPERTY("desc", desc)
|
||||||
entry(_module); \
|
#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); \
|
[[__used, __section(".mod.entry")]] \
|
||||||
MODULE_PROPERTY("desc", desc); \
|
static const void* __entry_fn = &__module_entry
|
||||||
MODULE_PROPERTY("version", version); \
|
|
||||||
MODULE_PROPERTY("license", license);
|
#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 {
|
struct module {
|
||||||
const char* name;
|
const char* name;
|
||||||
struct module* owner;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define THIS_MODULE (struct module*)nullptr
|
#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 pmap_set(struct pmap* pt);
|
||||||
|
|
||||||
void pte_clear(pte_t* pte);
|
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);
|
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_present(pte_t* pte);
|
||||||
bool pte_is_dir(pte_t* pte);
|
bool pte_is_dir(pte_t* pte);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/init.h>
|
#include <zinnia/init.h>
|
||||||
|
#include <zinnia/stack.h>
|
||||||
#include <zinnia/tailq.h>
|
#include <zinnia/tailq.h>
|
||||||
#include <zinnia/types.h>
|
#include <zinnia/types.h>
|
||||||
#include <bits/sched.h>
|
#include <bits/sched.h>
|
||||||
@@ -29,7 +30,7 @@ struct task {
|
|||||||
enum task_state state;
|
enum task_state state;
|
||||||
struct arch_task_context context;
|
struct arch_task_context context;
|
||||||
struct usercopy_region* usercopy_region;
|
struct usercopy_region* usercopy_region;
|
||||||
uintptr_t kernel_stack;
|
struct stack kernel_stack;
|
||||||
uintptr_t user_stack;
|
uintptr_t user_stack;
|
||||||
size_t time_slice;
|
size_t time_slice;
|
||||||
int8_t priority;
|
int8_t priority;
|
||||||
@@ -48,8 +49,9 @@ struct scheduler {
|
|||||||
typedef void (*task_fn_t)(uintptr_t arg0);
|
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);
|
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]]
|
[[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_init(struct scheduler* sched);
|
||||||
void sched_reschedule(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(...);
|
#define SYSCALL_DECLARE(number, name, num_args) extern void sys_##name(...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// SYSCALL_DECLARE(0, exit, -1)
|
SYSCALL_DECLARE(0, exit, 1)
|
||||||
// SYSCALL_DECLARE(1, syslog, -1)
|
SYSCALL_DECLARE(1, syslog, 3)
|
||||||
SYSCALL_DECLARE(2, getuname, 1)
|
SYSCALL_DECLARE(2, getuname, 1)
|
||||||
SYSCALL_DECLARE(3, setuname, 1)
|
SYSCALL_DECLARE(3, setuname, 1)
|
||||||
SYSCALL_DECLARE(4, archctl, 2)
|
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(
|
kernel_sources += files(
|
||||||
'archctl.c',
|
'archctl.c',
|
||||||
'dispatch.c',
|
'dispatch.c',
|
||||||
|
'exit.c',
|
||||||
|
'syslog.c',
|
||||||
'uname.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