This commit is contained in:
2026-09-17 03:19:43 +02:00
parent 6719239036
commit 27fe15f83d
85 changed files with 945 additions and 901 deletions
+23 -18
View File
@@ -1,37 +1,40 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/clock.h>
#include <zinnia/mmio.h>
#include <zinnia/percpu.h>
#include <assert.h>
#include <zinnia/pmap.h>
#include <zinnia/vma.h>
#include <stdint.h>
#include <x86_64/apic.h>
#include <x86_64/asm.h>
#include <x86_64/defs.h>
static uint64_t lapic_read_reg(struct local_apic* lapic, mmio_reg32 reg) {
if (lapic->xapic_regs.base) {
if (reg.offset == APIC_REG_ICR.offset) {
static uint64_t lapic_read_reg(struct local_apic* lapic, uint32_t reg) {
if (lapic->xapic_regs) {
if (reg == APIC_REG_ICR) {
uint64_t lo, hi;
lo = mmio_load(&lapic->xapic_regs, APIC_REG_ICR);
hi = mmio_load(&lapic->xapic_regs, APIC_REG_ICR_HI);
lo = mmio_read32(lapic->xapic_regs + APIC_REG_ICR);
hi = mmio_read32(lapic->xapic_regs + APIC_REG_ICR_HI);
return (hi << 32) | lo;
} else {
return mmio_load(&lapic->xapic_regs, reg);
return mmio_read32(lapic->xapic_regs + reg);
}
} else {
return asm_rdmsr(0x800 + (reg.offset >> 4));
return asm_rdmsr(0x800 + (reg >> 4));
}
}
static void lapic_write_reg(struct local_apic* lapic, mmio_reg32 reg, uint64_t value) {
if (lapic->xapic_regs.base) {
if (reg.offset == APIC_REG_ICR.offset) {
mmio_store(&lapic->xapic_regs, APIC_REG_ICR_HI, value >> 32);
mmio_store(&lapic->xapic_regs, APIC_REG_ICR, (uint32_t)value);
static void lapic_write_reg(struct local_apic* lapic, uint32_t reg, uint64_t value) {
if (lapic->xapic_regs) {
if (reg == APIC_REG_ICR) {
mmio_write32(lapic->xapic_regs + APIC_REG_ICR_HI, value >> 32);
mmio_write32(lapic->xapic_regs + APIC_REG_ICR, (uint32_t)value);
} else {
mmio_store(&lapic->xapic_regs, reg, (uint32_t)value);
mmio_write32(lapic->xapic_regs + reg, (uint32_t)value);
}
} else {
asm_wrmsr(0x800 + (reg.offset >> 4), value);
asm_wrmsr(0x800 + (reg >> 4), value);
}
}
@@ -43,8 +46,10 @@ void lapic_init(struct local_apic* lapic) {
if (cpuid.ecx & CPUID_1C_X2APIC)
apic_msr |= 1 << 10;
else {
lapic->xapic_regs = mmio_new(apic_msr & 0xFFFF'F000, 0x1000);
assert(lapic->xapic_regs.base, "Failed to allocate virtual memory!\n");
uintptr_t vaddr = vm_alloc(0x1000);
pmap_map(&kernel_vma.pmap, vaddr, apic_msr & 0xFFFF'F000, PTE_READ | PTE_WRITE, CACHE_MMIO);
lapic->xapic_regs = (void*)vaddr;
assert(lapic->xapic_regs, "Failed to allocate virtual memory!\n");
}
asm_wrmsr(0x1B, apic_msr);
@@ -54,7 +59,7 @@ void lapic_init(struct local_apic* lapic) {
// Enable APIC bit in the SIVR.
lapic_write_reg(lapic, APIC_REG_SIVR, lapic_read_reg(lapic, APIC_REG_SIVR) | 0x100);
if (lapic->xapic_regs.base) {
if (lapic->xapic_regs) {
lapic_write_reg(lapic, APIC_REG_DFR, 0xF000'0000);
// Logical destination = LAPIC ID.
lapic_write_reg(lapic, APIC_REG_LDR, lapic_read_reg(lapic, APIC_REG_ID));
+1
View File
@@ -1,4 +1,5 @@
#include <zinnia/errno.h>
#include <arch/archctl.h>
#include <uapi/archctl.h>
#include <x86_64/asm.h>
#include <x86_64/defs.h>
+17 -11
View File
@@ -1,9 +1,11 @@
#include <zinnia/assert.h>
#include <zinnia/clock.h>
#include <zinnia/cmdline.h>
#include <zinnia/mmio.h>
#include <zinnia/pmap.h>
#include <zinnia/print.h>
#include <zinnia/utils.h>
#include <assert.h>
#include <zinnia/vma.h>
#include <uacpi/acpi.h>
#include <uacpi/status.h>
#include <uacpi/tables.h>
@@ -17,22 +19,22 @@ CMDLINE_OPTION("hpet", hpet_option);
struct hpet {
struct clock clock;
struct mmio_view regs;
void* regs;
uint32_t period;
};
constexpr mmio_reg32 HPET_CAP = {.offset = 0};
constexpr mmio_reg32 HPET_CFG = {.offset = 0x10};
constexpr mmio_reg32 HPET_COUNTER = {.offset = 0xF0};
constexpr uint32_t HPET_CAP = 0x0;
constexpr uint32_t HPET_CFG = 0x10;
constexpr uint32_t HPET_COUNTER = 0xF0;
static void hpet_reset(struct clock* c) {
struct hpet* hpet = containerof(c, struct hpet, clock);
mmio_store(&hpet->regs, HPET_COUNTER, 0u);
mmio_write64(hpet->regs + HPET_COUNTER, 0);
}
static uint64_t hpet_get_elapsed_ns(struct clock* c) {
struct hpet* hpet = containerof(c, struct hpet, clock);
uint64_t counter = mmio_load(&hpet->regs, HPET_COUNTER);
uint64_t counter = mmio_read64(hpet->regs + HPET_COUNTER);
return (counter * (uint64_t)hpet->period / 1'000'000);
}
@@ -56,13 +58,17 @@ void hpet_init() {
assert(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n");
struct acpi_hpet* hpet = table.ptr;
hpet_clock.regs = mmio_new(hpet->address.address, 0x1000);
uintptr_t vaddr = vm_alloc(0x1000);
pmap_map(&kernel_vma.pmap, vaddr, hpet->address.address, PTE_READ | PTE_WRITE, CACHE_MMIO);
hpet_clock.regs = (void*)vaddr;
uacpi_table_unref(&table);
kprintf("HPET regs at %p\n", hpet_clock.regs.base);
log("x86_64/hpet", "HPET registers mapped at %p\n", hpet_clock.regs);
mmio_store(&hpet_clock.regs, HPET_CFG, mmio_load(&hpet_clock.regs, HPET_CFG) | 1);
mmio_write64(hpet_clock.regs + HPET_CFG, mmio_read64(hpet_clock.regs + HPET_CFG) | 1);
uint64_t caps = mmio_load(&hpet_clock.regs, HPET_CAP);
uint64_t caps = mmio_read64(hpet_clock.regs + HPET_CAP);
hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF;
assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
+1 -1
View File
@@ -1,10 +1,10 @@
#include <zinnia/assert.h>
#include <zinnia/compiler.h>
#include <zinnia/irq.h>
#include <zinnia/panic.h>
#include <zinnia/percpu.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <assert.h>
#include <bits/sched.h>
#include <stddef.h>
#include <stdint.h>
-33
View File
@@ -1,33 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <zinnia/types.h>
static inline size_t arch_mem_page_size() {
return 1 << 12;
}
static inline size_t arch_mem_page_bits() {
return 12;
}
static inline size_t arch_mem_level_bits() {
return 9;
}
static inline size_t arch_mem_num_levels() {
return 4;
}
static inline uintptr_t arch_mem_hhdm_addr() {
return 0xFFFF'8000'0000'0000;
}
static inline uintptr_t arch_vm_pfndb_addr() {
return 0xFFFF'A000'0000'0000;
}
static inline uintptr_t arch_mem_mapping_addr() {
return 0xFFFF'C000'0000'0000;
}
+1 -10
View File
@@ -1,16 +1,10 @@
#pragma once
#include <zinnia/irq.h>
#include <stddef.h>
#include <x86_64/apic.h>
#include <x86_64/gdt.h>
#include <x86_64/tss.h>
#include <zinnia/irq.h>
static inline struct percpu* arch_percpu_get() {
struct percpu* result;
asm volatile("mov %0, gs:0" : "=r"(result)::"memory");
return result;
}
struct arch_percpu {
struct gdt gdt;
@@ -22,6 +16,3 @@ struct arch_percpu {
void (*fpu_restore)(const void*);
bool can_smap;
};
void arch_percpu_bsp_init();
void arch_percpu_init();
+2 -5
View File
@@ -1,6 +1,5 @@
#pragma once
#include <bits/types.h>
#include <stdint.h>
struct arch_task_context {
@@ -39,10 +38,8 @@ struct arch_context {
#define ARCH_CTX_A0 rdi
#define ARCH_CTX_A1 rsi
#define ARCH_CTX_A2 rdx
#define ARCH_CTX_A3 r9
#define ARCH_CTX_A3 r10
#define ARCH_CTX_A4 r8
#define ARCH_CTX_A5 r10
#define ARCH_CTX_A6 r12
#define ARCH_CTX_A7 r13
#define ARCH_CTX_A5 r9
#define ARCH_CTX_RET0 rax
#define ARCH_CTX_RET1 rdx
+1 -1
View File
@@ -3,4 +3,4 @@
#include <stdint.h>
typedef uint64_t phys_t;
typedef uint64_t reg_t;
typedef uint64_t virt_t;
+16 -15
View File
@@ -1,12 +1,11 @@
#pragma once
#include <stdint.h>
#include <zinnia/mmio.h>
struct local_apic {
uint32_t id;
uint32_t ticks_per_10ms;
struct mmio_view xapic_regs;
void* xapic_regs;
};
enum apic_delivery_mode {
@@ -38,19 +37,21 @@ enum apic_trigger_mode {
APIC_TRIGGER_LEVEL = 1,
};
constexpr mmio_reg32 APIC_REG_ID = {.offset = 0x20};
constexpr mmio_reg32 APIC_REG_TPR = {.offset = 0x80};
constexpr mmio_reg32 APIC_REG_EOI = {.offset = 0xB0};
constexpr mmio_reg32 APIC_REG_LDR = {.offset = 0xD0};
constexpr mmio_reg32 APIC_REG_DFR = {.offset = 0xE0};
constexpr mmio_reg32 APIC_REG_SIVR = {.offset = 0xF0};
constexpr mmio_reg32 APIC_REG_ESR = {.offset = 0x280};
constexpr mmio_reg32 APIC_REG_ICR = {.offset = 0x300};
constexpr mmio_reg32 APIC_REG_ICR_HI = {.offset = 0x310};
constexpr mmio_reg32 APIC_REG_LVT_TR = {.offset = 0x320};
constexpr mmio_reg32 APIC_REG_ICR_TIMER = {.offset = 0x380};
constexpr mmio_reg32 APIC_REG_CCR = {.offset = 0x390};
constexpr mmio_reg32 APIC_REG_DCR = {.offset = 0x3E0};
enum apic_regs {
APIC_REG_ID = 0x20,
APIC_REG_TPR = 0x80,
APIC_REG_EOI = 0xB0,
APIC_REG_LDR = 0xD0,
APIC_REG_DFR = 0xE0,
APIC_REG_SIVR = 0xF0,
APIC_REG_ESR = 0x280,
APIC_REG_ICR = 0x300,
APIC_REG_ICR_HI = 0x310,
APIC_REG_LVT_TR = 0x320,
APIC_REG_ICR_TIMER = 0x380,
APIC_REG_CCR = 0x390,
APIC_REG_DCR = 0x3E0,
};
void lapic_init(struct local_apic* lapic);
void lapic_eoi(struct local_apic* lapic);
+2 -2
View File
@@ -194,8 +194,8 @@
#define MSR_GS_BASE (0xC0000101)
#define MSR_KERNEL_GS_BASE (0xC0000102)
#define CPL_USER (0b11)
#define CPL_KERNEL (0b00)
#define CPL_USER (0x3)
#define CPL_KERNEL (0x0)
#define IDT_PF (0xE)
#define IDT_IPI_RESCHED (0xFF)
@@ -1,21 +1,20 @@
#pragma once
#include <arch/irq.h>
#include <stdint.h>
#include <x86_64/defs.h>
static inline bool arch_irq_get_state() {
bool arch_irq_get_state() {
uint64_t flags;
asm volatile("pushf; pop %0" : "=r"(flags)::"memory");
return flags & RFLAGS_IF;
}
static inline void arch_irq_set_state(bool state) {
void arch_irq_set_state(bool state) {
if (state)
asm volatile("sti");
else
asm volatile("cli");
}
static inline void arch_irq_wait() {
void arch_irq_wait() {
asm volatile("hlt");
}
+31
View File
@@ -0,0 +1,31 @@
#include <zinnia/types.h>
#include <stddef.h>
#include <stdint.h>
size_t arch_mem_page_size() {
return 1 << 12;
}
size_t arch_mem_page_bits() {
return 12;
}
size_t arch_mem_level_bits() {
return 9;
}
size_t arch_mem_num_levels() {
return 4;
}
uintptr_t arch_mem_hhdm_addr() {
return 0xFFFF'8000'0000'0000;
}
uintptr_t arch_mem_pfndb_addr() {
return 0xFFFF'A000'0000'0000;
}
uintptr_t arch_mem_mapping_addr() {
return 0xFFFF'C000'0000'0000;
}
+3
View File
@@ -11,8 +11,11 @@ kernel_sources += files(
'gdt.c',
'hpet.c',
'idt.c',
'irq.c',
'mem.c',
'percpu.c',
'pmap.c',
'pmap.c',
'sched.c',
'serial.c',
'smp.c',
+13 -1
View File
@@ -10,6 +10,12 @@
#include <x86_64/syscall.h>
#include <x86_64/tsc.h>
struct percpu* arch_percpu_get() {
struct percpu* result;
asm volatile("mov %0, gs:0" : "=r"(result)::"memory");
return result;
}
void arch_percpu_bsp_init() {
asm_wrmsr(MSR_GS_BASE, (uint64_t)&percpu_bsp);
asm_wrmsr(MSR_FS_BASE, 0);
@@ -30,12 +36,16 @@ union ia32_star {
};
};
static_assert(sizeof(union ia32_star) == 8);
static void setup_cpu(struct percpu* cpu) {
asm_wrmsr(MSR_KERNEL_GS_BASE, 0);
asm_wrmsr(MSR_GS_BASE, (uint64_t)cpu);
asm_wrmsr(MSR_FS_BASE, 0);
asm_wrmsr(MSR_KERNEL_GS_BASE, 0);
gdt_load();
// TODO: not if FRED
idt_load();
// Syscall extension.
@@ -47,6 +57,8 @@ static void setup_cpu(struct percpu* cpu) {
asm_wrmsr(MSR_LSTAR, (uint64_t)arch_syscall_stub);
asm_wrmsr(MSR_SFMASK, RFLAGS_AC | RFLAGS_DF | RFLAGS_IF);
// TODO: FRED
uint64_t cr0, cr4;
asm volatile("mov %0, cr0" : "=r"(cr0));
asm volatile("mov %0, cr4" : "=r"(cr4));
+4 -4
View File
@@ -4,7 +4,7 @@
#include <zinnia/percpu.h>
#include <zinnia/pmap.h>
#include <zinnia/sched.h>
#include <zinnia/vas.h>
#include <zinnia/vma.h>
#include <bits/sched.h>
#include <stddef.h>
#include <stdint.h>
@@ -119,7 +119,7 @@ errno_t arch_task_init(
if (is_user) {
// Allocate FPU space.
const size_t fpu_size = cpu->fpu_size;
void* fpu_base = vm_alloc(fpu_size);
uintptr_t fpu_base = vm_alloc(fpu_size);
if (!fpu_base)
return ENOMEM;
for (size_t i = 0; i < fpu_size; i += arch_mem_page_size()) {
@@ -130,9 +130,9 @@ errno_t arch_task_init(
return s;
}
pmap_map(&kernel_vas.pmap, (uintptr_t)fpu_base, page, PTE_WRITE | PTE_READ, CACHE_WRITE_BACK);
pmap_map(&kernel_vma.pmap, (uintptr_t)fpu_base, page, PTE_WRITE | PTE_READ, CACHE_WRITE_BACK);
}
context->fpu_region = fpu_base;
context->fpu_region = (void*)fpu_base;
context->ds = asm_read_ds();
context->es = asm_read_es();
-2
View File
@@ -17,5 +17,3 @@ void _start() {
: "i"(__ld_stack_top), "r"(kernel_entry)
);
}
void arch_panic() {}
+56 -55
View File
@@ -10,61 +10,62 @@
[[__naked]]
void arch_syscall_stub() {
asm volatile(
"swapgs\n"
"mov gs:%c0, rsp\n"
"mov rsp, gs:%c1\n"
"cld\n"
// We're pretending to be an interrupt, so fill the bottom fields of `Context`.
"push %c3\n" // SS and CS are not changed during SYSCALL. Use `gdt::user_data | CPL_USER`.
"push gs:%c0\n"
"push r11\n" // RFLAGS is moved into r11 by the CPU.
"push %c2\n" // Same as SS. Use `gdt::user_code64 | CPL_USER`
"push rcx\n" // RIP is moved into rcx by the CPU.
"push 0x00\n" // arch_context::error field
"push 0x00\n" // arch_context::isr field
"push rax\n"
"push rbx\n"
"push rcx\n"
"push rdx\n"
"push rbp\n"
"push rdi\n"
"push rsi\n"
"push r8\n"
"push r9\n"
"push r10\n"
"push r11\n"
"push r12\n"
"push r13\n"
"push r14\n"
"push r15\n"
"xor rbp, rbp\n"
"mov rdi, rsp\n" // Put the trap frame struct as first argument.
"call %c4\n" // Call syscall handler
"cli\n"
"pop r15\n"
"pop r14\n"
"pop r13\n"
"pop r12\n"
"pop r11\n"
"pop r10\n"
"pop r9\n"
"pop r8\n"
"pop rsi\n"
"pop rdi\n"
"pop rbp\n"
"pop rdx\n"
"pop rcx\n"
"pop rbx\n"
"pop rax\n"
"add rsp, 0x10\n" // Skip .error and .isr fields (2 * sizeof(uint64_t))
"mov rsp, gs:%c0\n" // Load user stack from `percpu::user_stack`.
"swapgs\n"
"sysretq\n" // Return to user mode.
" swapgs\n"
" mov gs:%c0, rsp\n" // user_stack
" mov rsp, gs:%c1\n" // kernel_stack
" cld\n"
"1:\n"
" push %c3\n" // ss
" push gs:%c0\n"
" push r11\n" // rflags
" push %c2\n" // cs
" push rcx\n" // rip
" push 0x00\n" // arch_context::error
" push 0x00\n" // arch_context::isr
" push rax\n"
" push rbx\n"
" push rcx\n"
" push rdx\n"
" push rbp\n"
" push rdi\n"
" push rsi\n"
" push r8\n"
" push r9\n"
" push r10\n"
" push r11\n"
" push r12\n"
" push r13\n"
" push r14\n"
" push r15\n"
" xor rbp, rbp\n"
" mov rdi, rsp\n" // SysV ABI first argument.
" call %c4\n" // Call syscall handler.
" cli\n"
" pop r15\n"
" pop r14\n"
" pop r13\n"
" pop r12\n"
" pop r11\n"
" pop r10\n"
" pop r9\n"
" pop r8\n"
" pop rsi\n"
" pop rdi\n"
" pop rbp\n"
" pop rdx\n"
" pop rcx\n"
" pop rbx\n"
" pop rax\n"
" add rsp, 0x10\n" // Skip .error and .isr fields
"2:\n"
" mov rsp, gs:%c0\n" // user_stack
" swapgs\n"
" sysretq\n"
:
: "i"(offsetof(struct percpu, user_stack)),
"i"(offsetof(struct percpu, kernel_stack)),
"i"(offsetof(struct gdt, user_code64) | CPL_USER),
"i"(offsetof(struct gdt, user_data) | CPL_USER),
"i"(syscall_dispatch)
: "i"(offsetof(struct percpu, user_stack)), // 0
"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
);
}
+6 -6
View File
@@ -11,7 +11,7 @@ void tsc_init() {
return;
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) {
kprintf("No invariant TSC detected!\n");
log("x86_64/tsc", "No invariant TSC detected!\n");
return;
}
@@ -34,21 +34,21 @@ void tsc_init() {
// On a normal system, this should usually never be called and is a last resort
// since at this point we have at least the HPET timer.
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) {
kprintf("Calibrating TSC using CPUID 0x15");
log("x86_64/tsc", "Calibrating TSC using CPUID 0x15");
freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
} else {
kprintf("Unable to calibrate TSC using CPUID frequency information");
log("x86_64/tsc", "Unable to calibrate TSC using CPUID frequency information");
return;
}
} else {
kprintf("Unable to calibrate the TSC without a clock or static frequency info!\n");
log("x86_64/tsc", "Unable to calibrate the TSC without a clock or static frequency info!\n");
return;
}
kprintf("Timer frequency is %lu MHz\n", freq / 1'000'000);
log("x86_64/tsc", "Timer frequency is %lu MHz\n", freq / 1'000'000);
}
static void tsc_option(bool opt) {
use_tsc = opt;
}
CMDLINE_OPTION("tsc", tsc_option);
CMDLINE_OPTION("x86_64.tsc", tsc_option);
+1 -1
View File
@@ -1,5 +1,5 @@
#include <zinnia/bits/usercopy.h>
#include <zinnia/compiler.h>
#include <arch/usercopy.h>
extern void x86_64_read_start();
extern void x86_64_read_end();
+45 -30
View File
@@ -1,4 +1,5 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/clock.h>
#include <zinnia/cmdline.h>
#include <zinnia/compiler.h>
@@ -10,67 +11,81 @@
#include <zinnia/percpu.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <zinnia/vas.h>
#include <zinnia/vma.h>
#include <zinnia/vmo.h>
#include <assert.h>
#include <config.h>
#include <stdint.h>
static const char zinnia_banner[] =
"Zinnia " ZINNIA_VERSION " " CONFIG_VARIANT " (" ZINNIA_ARCH ", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")";
static const char zinnia_banner[] = "Zinnia " ZINNIA_VERSION " " CONFIG_KERNEL_FLAVOR " (" ZINNIA_ARCH
", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")";
static void kernel_main_task(uintptr_t arg0) {
struct boot_info* info = (struct boot_info*)arg0;
kprintf("%s\n", zinnia_banner); // Say hello!
log("main", "Hello from main task!\n");
assert(info->num_files >= 1, "No init executable provided\n");
struct vas* init_space;
assert(vma_new(&init_space) == 0, "");
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) == 0, "");
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;
assert(false, "Not implemented!");
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) {
arch_irq_wait();
irq_wait();
}
}
[[noreturn]]
void kmain(struct boot_info* info) {
cmdline_parse(info->cmdline);
console_init();
mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base);
rsdp_addr = info->rsdp; // TODO
percpu_init();
sched_init(&percpu_get()->sched);
futex_init();
struct task* main_task;
task_create("main", &kernel_vas, nullptr, kernel_main_task, (uintptr_t)info, &main_task);
sched_add_task(&percpu_get()->sched, main_task);
irq_unlock();
sched_yield(&percpu_get()->sched);
unreachable();
}
[[__init]]
void kernel_early_init() {
percpu_bsp_init();
percpu_get()->online = true;
irq_lock();
}
[[noreturn]]
void kernel_main(struct boot_info* info) {
// TODO: Initialize log ring.
kprintf("%s\n", zinnia_banner); // Say hello!
cmdline_parse(info->cmdline);
console_init();
kprintf("\ec");
kprintf("Kernel command line: %s\n", info->cmdline);
mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base);
rsdp_addr = info->rsdp; // TODO
percpu_init();
sched_init(&percpu_get()->sched);
futex_init();
struct task* main_task;
task_create("main", &kernel_vma, kernel_main_task, (uintptr_t)info, &main_task);
sched_add_task(&percpu_get()->sched, main_task);
irq_unlock();
sched_yield(&percpu_get()->sched);
unreachable();
}
+2 -2
View File
@@ -31,7 +31,7 @@ bool clock_switch(struct clock* clock) {
}
}
kprintf("Switching to clock source \"%s\"\n", clock->name);
log("clock", "Switching to clock source \"%s\"\n", clock->name);
uint64_t elapsed = clock_get_elapsed_ns();
counter_base += elapsed;
@@ -43,7 +43,7 @@ bool clock_switch(struct clock* clock) {
void clock_spin_ns(uint64_t ns) {
if (active_clock == nullptr) {
kprintf("Unable to sleep for %lu ns, no clock available!\n", ns);
log("clock", "Unable to sleep for %lu ns, no clock available!\n", ns);
return;
}
+2 -2
View File
@@ -37,7 +37,7 @@ void console_init() {
if (active) {
if (active->init(active) == false)
active = nullptr;
else
kprintf("Logging on console \"%s\"\n", active->name);
log("console", "Logging on console \"%s\"\n", active->name);
}
}
+16 -18
View File
@@ -1,18 +1,25 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/elf.h>
#include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/percpu.h>
#include <zinnia/pmap.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <zinnia/utils.h>
#include <zinnia/vas.h>
#include <zinnia/vdso.h>
#include <zinnia/vma.h>
#include <zinnia/vmo.h>
#include <assert.h>
#include <bits/elf.h>
#include <string.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 status;
@@ -40,13 +47,13 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
struct elf_phdr phdr = {};
vmo_read(info->file_obj, (ehdr.e_phoff + (i * ehdr.e_phentsize)), &phdr, sizeof(phdr), &read);
if (phdr.p_type == PT_LOAD) {
enum zn_vm_flags prot = 0;
enum prot_flags prot = 0;
if (phdr.p_flags & PF_R)
prot |= PROT_READ;
if (phdr.p_flags & PF_W)
prot |= ZN_VM_MAP_WRITE;
prot |= PROT_WRITE;
if (phdr.p_flags & PF_X)
prot |= ZN_VM_MAP_EXEC;
prot |= PROT_EXEC;
assert(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, "");
@@ -66,7 +73,7 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
return status;
// We map more than we copied so the rest is filled with zeroed pages.
status = vma_map_vmo(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset);
status = vma_map(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset);
if (status)
return status;
}
@@ -130,14 +137,6 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
vmo_write(&stack->object, stack_off, &zero, sizeof(zero), nullptr);
}
// Add the init handle to the process namespace.
zn_handle_t init_handle = ZN_HANDLE_INVALID;
if (info->init_handle) {
status = namespace_add_desc(info->ns, *info->init_handle, &init_handle);
if (status)
return status;
}
#define WRITE_AUXV(auxv, value) \
do { \
stack_off -= sizeof(uintptr_t); \
@@ -154,7 +153,6 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
WRITE_AUXV(AT_PHNUM, ehdr.e_phnum);
WRITE_AUXV(AT_PHENT, ehdr.e_phentsize);
WRITE_AUXV(AT_ENTRY, ehdr.e_entry);
WRITE_AUXV(AT_INIT_HANDLE, init_handle);
// envp pointers.
stack_off -= sizeof(uintptr_t);
@@ -181,7 +179,7 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
uintptr_t argc = num_argv;
vmo_write(&stack->object, stack_off, &argc, sizeof(argc), nullptr);
status = vma_map_vmo(info->space, &stack->object, stack_start, stack_size, PROT_READ | ZN_VM_MAP_WRITE, 0);
status = vma_map(info->space, &stack->object, stack_start, stack_size, PROT_READ | PROT_WRITE, 0);
if (status)
return status;
@@ -191,7 +189,7 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
start_info->arg = 0;
struct task* result;
status = task_create(info->argv[0], info->space, info->ns, sched_to_user, (uintptr_t)start_info, &result);
status = task_create(info->argv[0], info->space, sched_to_user, (uintptr_t)start_info, &result);
if (status)
return status;
+14 -1
View File
@@ -1,6 +1,19 @@
#include <stdatomic.h>
#include <zinnia/irq.h>
#include <zinnia/percpu.h>
#include <arch/irq.h>
#include <stdatomic.h>
void irq_set_state(bool state) {
arch_irq_set_state(state);
}
bool irq_get_state() {
return arch_irq_get_state();
}
void irq_wait() {
arch_irq_wait();
}
void irq_lock() {
struct irq_percpu* cpu = &percpu_get()->irq;
View File
+20 -21
View File
@@ -1,10 +1,10 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/init.h>
#include <zinnia/panic.h>
#include <zinnia/print.h>
#include <zinnia/utils.h>
#include <zinnia/vas.h>
#include <zinnia/virt.h>
#include <zinnia/vma.h>
#include <string.h>
extern uint8_t __ld_text_start[];
@@ -15,7 +15,7 @@ extern uint8_t __ld_data_start[];
extern uint8_t __ld_data_end[];
extern uint8_t __ld_kernel_start[];
struct vas kernel_vas = {0};
struct vma kernel_vma = {0};
[[__init]]
void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_t kernel_phys, uintptr_t tmp_hhdm) {
@@ -23,7 +23,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
const size_t pgsz = arch_mem_page_size();
kprintf("Memory map:\n");
log("mem", "Memory map:\n");
for (size_t i = 0; i < map_len; i++) {
if (map[i].length == 0)
continue;
@@ -44,7 +44,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
break;
}
kprintf("[%p - %p] %s\n", (void*)map[i].address, (void*)(map[i].address + map[i].length - 1), label);
log("mem", "[%p - %p] %s\n", (void*)map[i].address, (void*)(map[i].address + map[i].length - 1), label);
}
// Set up the bootstrap allocator.
@@ -54,24 +54,23 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
largest = &map[i];
}
mem_phys_bootstrap(largest);
kprintf(
log("mem",
"Using region [%p - %p] for bootstrap allocator\n",
(void*)largest->address,
(void*)(largest->address + largest->length - 1)
);
(void*)(largest->address + largest->length - 1));
// Set the HHDM base address to the address given by the loader.
// We must not keep any virtual addresses to this region,
// since we're likely going to map it at a different base address.
mem_hhdm_base = tmp_hhdm;
kassert(pmap_new_kernel(&kernel_vas.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
assert(pmap_new_kernel(&kernel_vma.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
// text
kprintf("Mapping text segment at %p\n", __ld_text_start);
log("mem", "Mapping text segment at %p\n", __ld_text_start);
for (uint8_t* p = __ld_text_start; p <= __ld_text_end; p += pgsz) {
errno_t status = pmap_map(
&kernel_vas.pmap,
&kernel_vma.pmap,
(uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ | PTE_EXEC,
@@ -81,10 +80,10 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
}
// rodata
kprintf("Mapping rodata segment at %p\n", __ld_rodata_start);
log("mem", "Mapping rodata segment at %p\n", __ld_rodata_start);
for (uint8_t* p = __ld_rodata_start; p < __ld_rodata_end; p += pgsz) {
errno_t status = pmap_map(
&kernel_vas.pmap,
&kernel_vma.pmap,
(uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ,
@@ -94,10 +93,10 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
}
// data
kprintf("Mapping data segment at %p\n", __ld_data_start);
log("mem", "Mapping data segment at %p\n", __ld_data_start);
for (uint8_t* p = __ld_data_start; p < __ld_data_end; p += pgsz) {
errno_t status = pmap_map(
&kernel_vas.pmap,
&kernel_vma.pmap,
(uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ | PTE_WRITE,
@@ -121,14 +120,14 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
for (size_t p = 0; p <= map[i].length; p += pgsz) {
uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm);
phys_t paddr = (phys_t)(map[i].address + p);
errno_t status = pmap_map(&kernel_vas.pmap, vaddr, paddr, PTE_READ | PTE_WRITE, CACHE_ANY);
errno_t status = pmap_map(&kernel_vma.pmap, vaddr, paddr, PTE_READ | PTE_WRITE, CACHE_ANY);
assert(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status);
}
}
mem_hhdm_base = tmp_hhdm;
// Switch to our own page table.
pmap_set(&kernel_vas.pmap);
pmap_set(&kernel_vma.pmap);
// We record metadata for every single page of available memory in a large array.
// This array is contiguous in virtual memory, but is sparsely populated.
@@ -139,7 +138,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
const size_t num_pages = (map[i].length + pgsz - 1) / pgsz;
const size_t metadata_size = num_pages * sizeof(struct page);
const uintptr_t metadata_start_vaddr = arch_vm_pfndb_addr() + (map[i].address / pgsz * sizeof(struct page));
const uintptr_t metadata_start_vaddr = arch_mem_pfndb_addr() + (map[i].address / pgsz * sizeof(struct page));
const uintptr_t metadata_end_vaddr = metadata_start_vaddr + metadata_size;
// Find the page-aligned boundaries that contain this metadata.
@@ -151,10 +150,10 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
for (size_t page = 0; page < length; page += pgsz) {
phys_t paddr;
assert(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n");
pmap_map(&kernel_vas.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_ANY);
pmap_map(&kernel_vma.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_ANY);
}
}
vm_pfndb = (struct page*)arch_vm_pfndb_addr();
vm_pfndb = (struct page*)arch_mem_pfndb_addr();
// We don't need the bootstrap allocator from this point on.
// Initialize the real page allocator.
@@ -162,5 +161,5 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
slab_init();
kprintf("Memory initialization complete\n");
log("mem", "Memory initialization complete\n");
}
+2 -2
View File
@@ -1,11 +1,11 @@
kernel_sources += files(
'fault.c',
'init.c',
'mmio.c',
'pmap.c',
'pmm.c',
'slab.c',
'usercopy.c',
'virt.c',
'vas.c',
'vma.c',
'vmo.c',
)
+3 -3
View File
@@ -2,10 +2,10 @@
#include <zinnia/errno.h>
#include <zinnia/pmap.h>
#include <zinnia/spin.h>
#include <zinnia/vas.h>
#include <zinnia/vma.h>
#include <string.h>
errno_t pmap_kernel(struct pmap* pt, enum alloc_flags flags) {
errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags) {
flags &= ~ALLOC_NOZERO;
phys_t addr;
@@ -30,7 +30,7 @@ errno_t pmap_new_user(struct pmap* pt, enum alloc_flags flags) {
return status;
void* user_l1_ptr = HHDM_PTR(user_l1);
void* kernel_l1_ptr = HHDM_PTR(kernel_vas.pmap.root);
void* kernel_l1_ptr = HHDM_PTR(kernel_vma.pmap.root);
memcpy(user_l1_ptr, kernel_l1_ptr, arch_mem_page_size());
struct pmap result = {
+2 -2
View File
@@ -1,9 +1,9 @@
#include <zinnia/alloc.h>
#include <zinnia/compiler.h>
#include <zinnia/page.h>
#include <zinnia/panic.h>
#include <zinnia/print.h>
#include <zinnia/spin.h>
#include <zinnia/virt.h>
#include <stdint.h>
#include <string.h>
@@ -150,5 +150,5 @@ void mem_phys_init(struct phys_mem* map, size_t length) {
}
const size_t free_bytes = (pmm_total_free * arch_mem_page_size());
kprintf("Total available memory: %zu MiB\n", free_bytes / 1024 / 1024);
log("pmm", "Total available memory: %zu MiB\n", free_bytes / 1024 / 1024);
}
View File
+1 -1
View File
@@ -1,6 +1,6 @@
#include <zinnia/bits/usercopy.h>
#include <zinnia/percpu.h>
#include <zinnia/usercopy.h>
#include <arch/usercopy.h>
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);
+7 -6
View File
@@ -1,8 +1,8 @@
#include <stdatomic.h>
#include <stddef.h>
#include <zinnia/alloc.h>
#include <zinnia/utils.h>
#include <zinnia/virt.h>
#include <stdatomic.h>
#include <stddef.h>
struct page* vm_pfndb = nullptr;
@@ -10,14 +10,15 @@ struct page* vm_pfndb = nullptr;
static size_t mapping_offset = 0;
void* vm_alloc(size_t length) {
uintptr_t vm_alloc(size_t length) {
uintptr_t base = arch_mem_mapping_addr();
size_t offset = atomic_fetch_add(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()));
size_t offset =
atomic_fetch_add_explicit(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()), memory_order_acquire);
return (void*)(base + offset);
return base + offset;
}
void vm_free(void* ptr, size_t length) {
void vm_free(uintptr_t ptr, size_t length) {
// TODO
}
+14 -13
View File
@@ -1,19 +1,20 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/pmap.h>
#include <zinnia/utils.h>
#include <zinnia/vas.h>
#include <assert.h>
#include <zinnia/vma.h>
// Try to create a new, empty virtual address space.
errno_t vma_new(struct vas** out) {
errno_t vma_new(struct vma** out) {
debug_assert(out != nullptr, "Missing out");
errno_t res;
if (!out)
return EINVAL;
struct vas* vmspace = mem_alloc(sizeof(struct vas), 0);
struct vma* vmspace = mem_alloc(sizeof(struct vma), 0);
if (!vmspace)
return ENOMEM;
@@ -31,24 +32,24 @@ err0:
}
// Delete a virtual address space.
void vma_delete(struct vas* vm) {}
void vma_free(struct vma* v) {}
// Remove any mappings in the given address range.
// May fail if there is no memory and a mapping needs to be split.
errno_t vma_unmap(struct vas* vm, uintptr_t vaddr, size_t size);
errno_t vma_unmap(struct vma* v, uintptr_t vaddr, size_t size);
// Change the protection of an existing mapping.
// May fail if there is no memory and a mapping needs to be split.
errno_t vma_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags);
errno_t vma_protect(struct vma* v, uintptr_t vaddr, size_t size, enum prot_flags flags);
// Try to handle a page fault.
bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type) {
bool vma_page_fault(struct vma* v, const struct vma_fault_info* info) {
// TODO
return false;
}
errno_t vma_map_vmo(
struct vas* vas,
errno_t vma_map(
struct vma* vma,
struct vmo* vmo,
uintptr_t addr,
size_t len,
@@ -65,7 +66,7 @@ errno_t vma_map_vmo(
const size_t pages = ALIGN_UP(addr_offset + len, page_size) / page_size;
size_t end_page = start_page + pages;
if (!vas || !vmo)
if (!vma || !vmo)
return EINVAL;
const size_t first_vmo_page = vmo_offset / page_size;
@@ -86,10 +87,10 @@ errno_t vma_map_vmo(
pf |= PTE_WRITE;
if (flags & PROT_EXEC)
pf |= PTE_EXEC;
if (vas->pmap.is_user)
if (vma->pmap.is_user)
pf |= PTE_USER;
status = pmap_map(&vas->pmap, p * page_size, paddr, pf, CACHE_ANY);
status = pmap_map(&vma->pmap, p * page_size, paddr, pf, CACHE_ANY);
if (status != 0)
return status;
}
+1 -2
View File
@@ -1,10 +1,9 @@
#include <string.h>
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/utils.h>
#include <zinnia/virt.h>
#include <zinnia/vmo.h>
#include <string.h>
errno_t vmo_read(struct vmo* obj, uintptr_t offset, void* buf, size_t len, size_t* actual_read) {
const size_t page_size = arch_mem_page_size();
+4 -1
View File
@@ -10,4 +10,7 @@ kernel_sources += files(
'spin.c',
)
kernel_sources += files('sched_dumb.c')
subdir('lib')
subdir('mem')
subdir('sched')
subdir('syscalls')
+11 -7
View File
@@ -4,19 +4,21 @@
#include <zinnia/print.h>
#include <stdarg.h>
#define panic_log(msg, ...) kprintf("[ !!!! ] \e[31m" msg "\e[0m", ##__VA_ARGS__)
[[noreturn]]
void panic(const char* msg, ...) {
// TODO: Stop all other CPUs with IPI.
arch_irq_set_state(false);
irq_set_state(false);
struct percpu* cpu = percpu_get();
struct task* current = cpu->sched.current;
kprintf(
"----[ Kernel panic ]----\n"
"In task \"%s\" (TID %zu) on CPU %zu!\n",
current ? current->name : nullptr,
"[ !!!! ] \e[31m"
"Kernel panic on CPU %zu (T%zu, \"%s\"): ",
cpu->id,
current ? current->id : 0,
cpu->id
current ? current->name : nullptr
);
va_list args;
@@ -24,9 +26,11 @@ void panic(const char* msg, ...) {
kvprintf(msg, args);
va_end(args);
kprintf("----[ End of panic ]----\n");
kprintf("\e[0m");
panic_log("End of panic message\n");
while (1) {
arch_irq_wait();
irq_wait();
}
}
+13
View File
@@ -1,5 +1,6 @@
#include <zinnia/compiler.h>
#include <zinnia/percpu.h>
#include <arch/percpu.h>
[[__used, __section(".percpu")]]
struct percpu percpu_bsp = {
@@ -12,3 +13,15 @@ struct percpu* percpu_new() {
// TODO
return nullptr;
}
struct percpu* percpu_get() {
return arch_percpu_get();
}
void percpu_bsp_init() {
arch_percpu_bsp_init();
}
void percpu_init() {
arch_percpu_init();
}
+3
View File
@@ -0,0 +1,3 @@
kernel_sources += files(
'sched_dumb.c',
)
+7 -16
View File
@@ -1,4 +1,5 @@
#include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/errno.h>
#include <zinnia/irq.h>
#include <zinnia/list.h>
@@ -8,17 +9,15 @@
#include <zinnia/sched.h>
#include <zinnia/spin.h>
#include <zinnia/tailq.h>
#include <zinnia/vas.h>
#include <assert.h>
#include <bits/irq.h>
#include <zinnia/vma.h>
#include <stdatomic.h>
#include <stdint.h>
#include <string.h>
static void idle_func(uintptr_t) {
while (1) {
arch_irq_set_state(true);
arch_irq_wait();
irq_set_state(true);
irq_wait();
}
}
@@ -37,13 +36,13 @@ void sched_to_user_context(uintptr_t ctx) {
void sched_init(struct sched_percpu* sched) {
struct task* idle_task;
assert(task_create("idle", &kernel_vas, nullptr, idle_func, 0, &idle_task) == 0, "Unable to create idle task!\n");
assert(task_create("idle", &kernel_vma, idle_func, 0, &idle_task) == 0, "Unable to create idle task!\n");
sched->idle_task = idle_task;
sched->current = idle_task;
tailq_init(&sched->run_queue);
kprintf("Scheduler initialized\n");
log("sched", "Scheduler initialized\n");
}
void sched_add_task(struct sched_percpu* sched, struct task* task) {
@@ -96,14 +95,7 @@ void sched_yield(struct sched_percpu* sched) {
do_reschedule(sched);
}
errno_t task_create(
const char* name,
struct vas* space,
struct namespace* ns,
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) {
if (!out)
return EINVAL;
@@ -114,7 +106,6 @@ errno_t task_create(
static size_t last_tid = 0;
new_task->id = atomic_fetch_add(&last_tid, 1);
new_task->space = space;
new_task->namespace = ns;
strncpy(new_task->name, name, sizeof(new_task->name));
// Allocate a kernel stack.
@@ -1,6 +1,6 @@
#include <zinnia/archctl.h>
#include <zinnia/syscall.h>
#include <arch/archctl.h>
void syscall_archctl(struct arch_context* ctx) {
void sys_archctl(struct arch_context* ctx) {
ctx->ARCH_CTX_RET0 = arch_archctl(ctx->ARCH_CTX_A0, ctx->ARCH_CTX_A1);
}
+191
View File
@@ -0,0 +1,191 @@
#include <zinnia/compiler.h>
#include <zinnia/errno.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <zinnia/syscall.h>
#include <zinnia/syscall_list.h>
#include <zinnia/types.h>
#include <zinnia/utils.h>
#include <bits/sched.h>
const struct syscall syscall_table[256] = {
// [0] = {sys_exit, 0},
// [1] = {sys_syslog, 0},
[2] = {sys_getuname, 0},
// [3] = {sys_setuname, 0},
[4] = {sys_archctl, 0},
// [5] = {sys_reboot, 0},
// [6] = {sys_mmap, 0},
// [7] = {sys_munmap, 0},
// [8] = {sys_mprotect, 0},
// [9] = {sys_madvise, 0},
// [10] = {sys_sigprocmask, 0},
// [11] = {sys_sigsuspend, 0},
// [12] = {sys_sigpending, 0},
// [13] = {sys_sigaction, 0},
// [14] = {sys_sigtimedwait, 0},
// [15] = {sys_sigaltstack, 0},
// [16] = {sys_sigreturn, 0},
// [17] = {sys_sigqueue, 0},
// [18] = {sys_execve, 0},
// [19] = {sys_fexecve, 0},
// [20] = {sys_fork, 0},
// [21] = {sys_kill, 0},
// [22] = {sys_gettid, 0},
// [23] = {sys_getpid, 0},
// [24] = {sys_getppid, 0},
// [25] = {sys_waitid, 0},
// [26] = {sys_waitpid, 0},
// [27] = {sys_pread, 0},
// [28] = {sys_readv, 0},
// [29] = {sys_pwrite, 0},
// [30] = {sys_writev, 0},
// [31] = {sys_seek, 0},
// [32] = {sys_ioctl, 0},
// [33] = {sys_openat, 0},
// [34] = {sys_close, 0},
// [35] = {sys_fstat, 0},
// [36] = {sys_fstatat, 0},
// [37] = {sys_statvfs, 0},
// [38] = {sys_fstatvfs, 0},
// [39] = {sys_faccessat, 0},
// [40] = {sys_fcntl, 0},
// [41] = {sys_ftruncate, 0},
// [42] = {sys_truncate, 0},
// [43] = {sys_fallocate, 0},
// [44] = {sys_fadvise, 0},
// [45] = {sys_utimensat, 0},
// [46] = {sys_mknodat, 0},
// [47] = {sys_getcwd, 0},
// [48] = {sys_chdir, 0},
// [49] = {sys_fchdir, 0},
// [50] = {sys_mkdirat, 0},
// [51] = {sys_rmdirat, 0},
// [52] = {sys_getdents, 0},
// [53] = {sys_renameat, 0},
// [54] = {sys_fchmod, 0},
// [55] = {sys_fchmodat, 0},
// [56] = {sys_fchownat, 0},
// [57] = {sys_linkat, 0},
// [58] = {sys_symlinkat, 0},
// [59] = {sys_unlinkat, 0},
// [60] = {sys_readlinkat, 0},
// [61] = {sys_flock, 0},
// [62] = {sys_ppoll, 0},
// [63] = {sys_dup, 0},
// [64] = {sys_dup3, 0},
// [65] = {sys_sync, 0},
// [66] = {sys_fsync, 0},
// [67] = {sys_fdatasync, 0},
// [68] = {sys_getgroups, 0},
// [69] = {sys_setgroups, 0},
// [70] = {sys_getsid, 0},
// [71] = {sys_setsid, 0},
// [72] = {sys_setuid, 0},
// [73] = {sys_getuid, 0},
// [74] = {sys_setgid, 0},
// [75] = {sys_getgid, 0},
// [76] = {sys_geteuid, 0},
// [77] = {sys_seteuid, 0},
// [78] = {sys_getegid, 0},
// [79] = {sys_setegid, 0},
// [80] = {sys_getpgid, 0},
// [81] = {sys_setpgid, 0},
// [82] = {sys_getresuid, 0},
// [83] = {sys_setresuid, 0},
// [84] = {sys_getresgid, 0},
// [85] = {sys_setresgid, 0},
// [86] = {sys_setreuid, 0},
// [87] = {sys_setregid, 0},
// [88] = {sys_umask, 0},
// [89] = {sys_pipe, 0},
// [90] = {sys_futex_wait, 0},
// [91] = {sys_futex_wake, 0},
// [92] = {sys_thread_create, 0},
// [93] = {sys_thread_kill, 0},
// [94] = {sys_thread_exit, 0},
// [95] = {sys_thread_setname, 0},
// [96] = {sys_thread_getname, 0},
// [97] = {sys_timer_create, 0},
// [98] = {sys_timer_set, 0},
// [99] = {sys_timer_get, 0},
// [100] = {sys_timer_getoverrun, 0},
// [101] = {sys_timer_delete, 0},
// [102] = {sys_itimer_get, 0},
// [103] = {sys_itimer_set, 0},
// [104] = {sys_clock_get, 0},
// [105] = {sys_clock_getres, 0},
// [106] = {sys_clock_set, 0},
// [107] = {sys_sleep, 0},
// [108] = {sys_yield, 0},
// [109] = {sys_chroot, 0},
// [110] = {sys_mount, 0},
// [111] = {sys_umount, 0},
// [112] = {sys_socket, 0},
// [113] = {sys_socketpair, 0},
// [114] = {sys_shutdown, 0},
// [115] = {sys_bind, 0},
// [116] = {sys_connect, 0},
// [117] = {sys_accept, 0},
// [118] = {sys_listen, 0},
// [119] = {sys_getpeername, 0},
// [120] = {sys_getsockname, 0},
// [121] = {sys_getsockopt, 0},
// [122] = {sys_setsockopt, 0},
// [123] = {sys_sendmsg, 0},
// [124] = {sys_recvmsg, 0},
// [125] = {sys_getentropy, 0},
// [126] = {sys_getrusage, 0},
// [127] = {sys_getrlimit, 0},
// [128] = {sys_setrlimit, 0},
// [129] = {sys_getpriority, 0},
// [130] = {sys_setpriority, 0},
// [131] = {sys_sched_getparam, 0},
// [132] = {sys_sched_setparam, 0},
// [133] = {sys_module_insert, 0},
// [134] = {sys_module_remove, 0},
// [135] = {sys_epoll_create, 0},
// [136] = {sys_epoll_ctl, 0},
// [137] = {sys_epoll_pwait, 0},
// [138] = {sys_timerfd_create, 0},
// [139] = {sys_timerfd_gettime, 0},
// [140] = {sys_timerfd_settime, 0},
// [141] = {sys_signalfd_create, 0},
// [142] = {sys_eventfd_create, 0},
// [143] = {sys_msync, 0},
// [144] = {sys_sysconf, 0},
};
[[gnu::no_caller_saved_registers]]
struct syscall_ret syscall_dispatch_fast(
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
size_t num
) {
// No need to check the table size here. In order to get to this point,
// we already have to check if this is a fast syscall.
if (syscall_table[num].func == nullptr) {
return (struct syscall_ret){.errno = ENOSYS};
}
struct syscall_ret (*func)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t) =
syscall_table[num].func;
return func(a0, a1, a2, a3, a4, a5);
}
void syscall_dispatch(struct arch_context* ctx) {
const size_t num = ctx->ARCH_CTX_NUM;
if (num >= ARRAY_SIZE(syscall_table) || syscall_table[num].func == nullptr) {
ctx->ARCH_CTX_RET0 = ENOSYS;
return;
}
void (*func)(struct arch_context* ctx) = syscall_table[num].func;
func(ctx);
}
+33
View File
@@ -0,0 +1,33 @@
#include <zinnia/spin.h>
#include <zinnia/syscall.h>
#include <zinnia/usercopy.h>
#include <config.h>
#include <uapi/utsname.h>
static spinlock_t uname_lock = {};
static struct utsname uname_buf = {
.sysname = "Zinnia",
.release = ZINNIA_VERSION,
.version = CONFIG_KERNEL_FLAVOR,
.nodename = "localhost",
.machine = ZINNIA_ARCH,
};
struct syscall_ret sys_getuname(__user struct utsname* ptr) {
struct syscall_ret ret = {};
if (!ptr) {
ret.errno = EINVAL;
return ret;
}
spin_lock(&uname_lock);
if (!usercopy_write(ptr, &uname_buf, sizeof(uname_buf)))
ret.errno = EFAULT;
spin_unlock(&uname_lock);
return ret;
}
@@ -2,4 +2,5 @@ kernel_sources += files(
'archctl.c',
'dispatch.c',
'futex.c',
'getuname.c',
)
View File
@@ -1,7 +1,11 @@
#include <zinnia/console.h>
#include <zinnia/init.h>
#include <zinnia/mmio.h>
#include <zinnia/pmap.h>
#include <zinnia/print.h>
#include <zinnia/utils.h>
#include <zinnia/virt.h>
#include <zinnia/vma.h>
#include <stdarg.h>
#include <uacpi/kernel_api.h>
#include <uacpi/status.h>
@@ -13,7 +17,12 @@ uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr* out_rsdp_address) {
}
void* uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len) {
return (void*)mmio_new(addr, len).base;
uintptr_t vaddr = vm_alloc(len);
for (size_t i = 0; i < len; i += arch_mem_page_size()) {
pmap_map(&kernel_vma.pmap, vaddr + i, addr + i, PROT_READ | PROT_WRITE, CACHE_ANY);
}
return (void*)vaddr;
}
void uacpi_kernel_unmap(void* addr, uacpi_size len) {
@@ -21,6 +30,8 @@ void uacpi_kernel_unmap(void* addr, uacpi_size len) {
}
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char* msg, ...) {
console_write("uacpi: ", 7);
va_list args;
va_start(args, msg);
View File
@@ -8,5 +8,5 @@ size_t arch_mem_page_bits();
size_t arch_mem_level_bits();
size_t arch_mem_num_levels();
uintptr_t arch_mem_hhdm_addr();
uintptr_t arch_vm_pfndb_addr();
uintptr_t arch_mem_pfndb_addr();
uintptr_t arch_mem_mapping_addr();
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <zinnia/percpu.h>
struct percpu* arch_percpu_get();
void arch_percpu_bsp_init();
void arch_percpu_init();
@@ -1,9 +1,10 @@
#pragma once
#include <stddef.h>
#include <zinnia/compiler.h>
#include <zinnia/usercopy.h>
#include <stddef.h>
void arch_usercopy_allow(bool state);
bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region);
bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region);
bool arch_usercopy_strlen(const __user char* str, size_t max, size_t* len, struct usercopy_region** region);
-25
View File
@@ -1,25 +0,0 @@
#pragma once
#include <zinnia/compiler.h>
#include <zinnia/panic.h>
#define assert(expr, msg, ...) \
({ \
if (__unlikely(!(expr))) { \
panic( \
"In function \"%s\" (%s:%u):\n" \
"Assertion \"%s\" failed!\n" msg, \
__FUNCTION__, \
__FILE__, \
__LINE__, \
#expr, \
##__VA_ARGS__ \
); \
} \
})
#ifndef NDEBUG
#define debug_assert(...) assert(__VA_ARGS__)
#else
#define debug_assert(...) ((void)0)
#endif
+2
View File
@@ -5,6 +5,8 @@
#ifdef __x86_64__
#define __ARCHCTL_SET_FSBASE 1
#define __ARCHCTL_SET_GSBASE 2
#define __ARCHCTL_GET_FSBASE 3
#define __ARCHCTL_GET_GSBASE 4
#endif
#endif
+3 -10
View File
@@ -1,8 +1,9 @@
#pragma once
#include <bits/mem.h>
#include <stddef.h>
#include <zinnia/errno.h>
#include <zinnia/types.h>
#include <arch/mem.h>
#include <stddef.h>
enum alloc_flags {
ALLOC_NOZERO = 1 << 0, // Don't zero out the allocated memory.
@@ -44,14 +45,6 @@ void slab_init();
void mem_phys_bootstrap(struct phys_mem* mem);
void mem_phys_init(struct phys_mem* map, size_t length);
uintptr_t arch_mem_hhdm_addr();
uintptr_t arch_vm_pfndb_addr();
uintptr_t arch_mem_mapping_addr();
size_t arch_mem_page_bits();
size_t arch_mem_page_size();
size_t arch_mem_level_bits();
size_t arch_mem_num_levels();
static inline size_t mem_high_shift() {
return arch_mem_level_bits() * arch_mem_num_levels() + arch_mem_page_bits();
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <zinnia/compiler.h>
#include <zinnia/panic.h>
#define assert(expr, msg, ...) \
({ \
if (__unlikely(!(expr))) { \
panic("Assertion \"%s\" failed: \"" msg "\" @ %s:%u\n", #expr, ##__VA_ARGS__, __FILE__, __LINE__); \
} \
})
#ifndef NDEBUG
#define debug_assert(...) assert(__VA_ARGS__)
#else
#define debug_assert(...) ((void)0)
#endif
+1
View File
@@ -0,0 +1 @@
#pragma once
+13 -13
View File
@@ -1,10 +1,10 @@
#pragma once
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
// FNV-1a hash over raw bytes.
static inline uint64_t hashmap_hash_default(const void* key, size_t len) {
@@ -25,7 +25,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Ensure a hash is never zero (zero is the empty sentinel).
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
#define HASHMAP(K, V) \
#define hashmap(K, V) \
struct { \
K* keys; \
V* values; \
@@ -34,7 +34,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
size_t count; \
}
#define HASHMAP_INIT(map) \
#define hashmap_init(map) \
do { \
(map)->keys = nullptr; \
(map)->values = nullptr; \
@@ -43,7 +43,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
(map)->count = 0; \
} while (0)
#define HASHMAP_DESTROY(map) \
#define hashmap_destroy(map) \
do { \
mem_free((map)->keys); \
mem_free((map)->values); \
@@ -55,7 +55,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
(map)->count = 0; \
} while (0)
#define HASHMAP_COUNT(map) ((map)->count)
#define hashmap_count(map) ((map)->count)
// Internal: probe distance from ideal position.
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1))
@@ -116,10 +116,10 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
} \
} while (0)
// Insert or update a key-value pair. Returns 0 or ENOMEM.
#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \
// Insert or update a key-value pair. Returns 0 or ZN_ERR_NO_MEMORY.
#define hashmap_insert(map, key, val, hash_fn, eq_fn) \
({ \
errno_t _status = 0; \
zn_status_t _status = 0; \
typeof(*(map)->keys) _k = (key); \
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
/* Check for existing key first. */ \
@@ -144,7 +144,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
if ((map)->count * 4 >= (map)->capacity * 3 || (map)->capacity == 0) { \
_HASHMAP_GROW(map, hash_fn, eq_fn); \
if ((map)->keys == nullptr || (map)->values == nullptr || (map)->hashes == nullptr) { \
_status = ENOMEM; \
_status = ZN_ERR_NO_MEMORY; \
} \
} \
if (_status == 0) { \
@@ -155,7 +155,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
})
// Look up a key. Returns a pointer to the value, or nullptr if not found.
#define HASHMAP_GET(map, key, hash_fn, eq_fn) \
#define hashmap_get(map, key, hash_fn, eq_fn) \
({ \
typeof(*(map)->values)* _result = nullptr; \
if ((map)->capacity > 0) { \
@@ -180,7 +180,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Remove a key. Returns true if the key was found and removed.
// Uses backward-shift deletion to avoid tombstones.
#define HASHMAP_REMOVE(map, key, hash_fn, eq_fn) \
#define hashmap_remove(map, key, hash_fn, eq_fn) \
({ \
bool _removed = false; \
if ((map)->capacity > 0) { \
@@ -218,6 +218,6 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Iterate over all occupied entries. `idx` is a size_t loop variable.
// Access keys and values via (map)->keys[idx] and (map)->values[idx].
#define HASHMAP_FOREACH(map, idx) \
#define hashmap_foreach(map, idx) \
for (size_t idx = 0; idx < (map)->capacity; idx++) \
if ((map)->hashes[idx] != 0)
+6 -2
View File
@@ -2,7 +2,6 @@
#include <zinnia/compiler.h>
#include <zinnia/list.h>
#include <bits/irq.h>
#include <stdint.h>
enum irq_status : uint8_t {
@@ -45,4 +44,9 @@ void irq_line_attach(struct irq_line* self, struct irq_handler* handler);
void irq_lock();
void irq_unlock();
bool irq_set_interrupted(bool is_interrupted);
void irq_raise();
void irq_line_raise(struct irq_line* line);
// Hints to stop execution on this CPU until an interrupt happens.
void irq_wait();
bool irq_get_state();
void irq_set_state(bool state);
+26 -62
View File
@@ -1,71 +1,35 @@
#pragma once
#include <zinnia/types.h>
#include <stddef.h>
#include <stdint.h>
struct mmio_view {
volatile void* base;
size_t len;
};
static inline uint8_t mmio_read8(void* ptr) {
return *((volatile uint8_t*)ptr);
}
#define _MMIO_REG(x) \
typedef struct { \
size_t offset; \
bool swapped; \
} mmio_reg##x;
static inline uint16_t mmio_read16(void* ptr) {
return *((volatile uint16_t*)ptr);
}
_MMIO_REG(8)
_MMIO_REG(16)
_MMIO_REG(32)
_MMIO_REG(64)
static inline uint32_t mmio_read32(void* ptr) {
return *((volatile uint32_t*)ptr);
}
#define bswap_16(x) (uint16_t)x
#define bswap_32(x) (uint32_t)x
#define bswap_64(x) (uint64_t)x
static inline uint64_t mmio_read64(void* ptr) {
return *((volatile uint64_t*)ptr);
}
#define mmio_load(_view, _reg) \
({ \
auto _mmio_ptr = _Generic( \
(_reg), \
mmio_reg8: (volatile uint8_t*)((_view)->base + (_reg).offset), \
mmio_reg16: (volatile uint16_t*)((_view)->base + (_reg).offset), \
mmio_reg32: (volatile uint32_t*)((_view)->base + (_reg).offset), \
mmio_reg64: (volatile uint64_t*)((_view)->base + (_reg).offset) \
); \
auto _mmio_val = *_mmio_ptr; \
if ((_reg).swapped) \
_Generic( \
(_mmio_val), \
char: (void)(_mmio_val), \
uint8_t: (void)(_mmio_val), \
uint16_t: (_mmio_val = bswap_16(_mmio_val)), \
uint32_t: (_mmio_val = bswap_32(_mmio_val)), \
uint64_t: (_mmio_val = bswap_64(_mmio_val)) \
); \
_mmio_val; \
})
static inline void mmio_write8(void* ptr, uint8_t value) {
*((volatile uint8_t*)ptr) = value;
}
#define mmio_store(_view, _reg, _val) \
({ \
auto _mmio_val = _val; \
if ((_reg).swapped) \
_Generic( \
(_mmio_val), \
char: (void)(_mmio_val), \
uint8_t: (void)(_mmio_val), \
uint16_t: (_mmio_val = bswap_16(_mmio_val)), \
uint32_t: (_mmio_val = bswap_32(_mmio_val)), \
uint64_t: (_mmio_val = bswap_64(_mmio_val)) \
); \
auto _mmio_ptr = _Generic( \
(_reg), \
mmio_reg8: (volatile uint8_t*)((_view)->base + (_reg).offset), \
mmio_reg16: (volatile uint16_t*)((_view)->base + (_reg).offset), \
mmio_reg32: (volatile uint32_t*)((_view)->base + (_reg).offset), \
mmio_reg64: (volatile uint64_t*)((_view)->base + (_reg).offset) \
); \
*_mmio_ptr = _mmio_val; \
})
static inline void mmio_write16(void* ptr, uint16_t value) {
*((volatile uint16_t*)ptr) = value;
}
struct mmio_view mmio_new(phys_t addr, size_t length);
void mmio_free(struct mmio_view* view);
static inline void mmio_write32(void* ptr, uint32_t value) {
*((volatile uint32_t*)ptr) = value;
}
static inline void mmio_write64(void* ptr, uint64_t value) {
*((volatile uint64_t*)ptr) = value;
}
+6 -19
View File
@@ -7,7 +7,7 @@
#include <bits/percpu.h>
#include <stddef.h>
ASSERT_TYPE(struct arch_percpu);
ASSERT_TYPE(struct arch_percpu); // bits/percpu.h
// CPU-relative information.
struct percpu {
@@ -21,23 +21,10 @@ struct percpu {
struct sched_percpu sched; // Scheduler information.
};
struct percpu* percpu_new();
struct percpu* percpu_get();
void percpu_bsp_init();
void percpu_init();
// Per-CPU data for the bootstrap processor.
extern struct percpu percpu_bsp;
// Allocates a block of memory for a new CPU.
struct percpu* percpu_new();
// Gets the per-CPU data on the current CPU.
static inline struct percpu* percpu_get() {
return arch_percpu_get();
}
// Initializes the bootstrap processor.
static inline void percpu_bsp_init() {
arch_percpu_bsp_init();
}
// Initializes all processors.
static inline void percpu_init() {
arch_percpu_init();
}
+3 -3
View File
@@ -4,7 +4,7 @@
#include <zinnia/errno.h>
#include <zinnia/spin.h>
#include <zinnia/utils.h>
#include <bits/mmu.h>
#include <bits/pmap.h>
enum pte_flags : uint8_t {
PTE_READ = 1 << 0, // Can read from this page.
@@ -28,8 +28,8 @@ struct pmap {
bool is_user;
};
errno_t pmap_kernel(struct pmap* pt, enum alloc_flags flags);
errno_t pmap_user(struct pmap* pt, enum alloc_flags flags);
errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags);
errno_t pmap_new_user(struct pmap* pt, enum alloc_flags flags);
errno_t pmap_map(struct pmap* pt, uintptr_t vaddr, phys_t paddr, enum pte_flags flags, enum cache_mode cache);
errno_t pmap_protect(struct pmap* pt, uintptr_t vaddr, enum pte_flags flags);
errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr);
+9
View File
@@ -7,3 +7,12 @@
void kprintf(const char* message, ...);
void kvprintf(const char* message, va_list args);
#include <zinnia/clock.h>
#include <stdint.h>
#define log(category, message, ...) \
do { \
uint64_t _time = clock_get_elapsed_ns(); \
kprintf("[%5lu.%06lu] \e[1;34m" category ":\e[0m " message, _time / 1'000'000'000, _time % 1'000'000, ##__VA_ARGS__); \
} while (0)
+2 -10
View File
@@ -26,8 +26,7 @@ enum task_state {
struct task {
size_t id;
char name[TASK_NAME_MAX];
struct vas* space;
struct namespace* namespace;
struct vma* space;
enum task_state state;
struct arch_task_context context;
struct usercopy_region* usercopy_region;
@@ -59,14 +58,7 @@ void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq);
typedef void (*task_fn_t)(uintptr_t arg0);
errno_t task_create(
const char* name,
struct vas* space,
struct namespace* ns,
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);
[[noreturn]]
void task_entry(task_fn_t entry, uintptr_t arg0);
+7 -14
View File
@@ -2,32 +2,25 @@
#include <zinnia/sched.h>
enum syscall_kind : uint8_t {
SYSKIND_CALL = 0, // Regular call, returns error and/or value.
SYSKIND_CONTEXT, // Consumes the entire register image.
};
struct syscall_return {
struct syscall_ret {
uintptr_t value;
int errno;
};
struct syscall {
union {
struct syscall_return (*call)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
void (*context)(struct arch_context*);
};
enum syscall_kind kind;
void* func;
int num_args;
};
struct syscall_return syscall_dispatch_call(
size_t num,
[[gnu::no_caller_saved_registers]]
struct syscall_ret syscall_dispatch_fast(
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5
uintptr_t a5,
size_t num
);
void syscall_dispatch(struct arch_context* ctx);
+146 -150
View File
@@ -2,155 +2,151 @@
#include <zinnia/sched.h>
#include <zinnia/syscall.h>
#include <stdint.h>
#define __SYSCALL_CALL(name) \
struct syscall_return sys_##name(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t)
#define SYSCALL_DECLARE(name) extern void sys_##name()
#define __SYSCALL_CONTEXT(name) void sys_##name(struct arch_context*)
__SYSCALL_CALL(exit);
__SYSCALL_CALL(syslog);
__SYSCALL_CALL(getuname);
__SYSCALL_CALL(setuname);
__SYSCALL_CALL(archctl);
__SYSCALL_CALL(reboot);
__SYSCALL_CALL(mmap);
__SYSCALL_CALL(munmap);
__SYSCALL_CALL(mprotect);
__SYSCALL_CALL(madvise);
__SYSCALL_CALL(sigprocmask);
__SYSCALL_CALL(sigsuspend);
__SYSCALL_CALL(sigpending);
__SYSCALL_CALL(sigaction);
__SYSCALL_CALL(sigtimedwait);
__SYSCALL_CALL(sigaltstack);
__SYSCALL_CALL(sigreturn);
__SYSCALL_CALL(sigqueue);
__SYSCALL_CALL(execve);
__SYSCALL_CALL(fexecve);
__SYSCALL_CONTEXT(fork);
__SYSCALL_CALL(kill);
__SYSCALL_CALL(gettid);
__SYSCALL_CALL(getpid);
__SYSCALL_CALL(getppid);
__SYSCALL_CALL(waitid);
__SYSCALL_CALL(waitpid);
__SYSCALL_CALL(pread);
__SYSCALL_CALL(readv);
__SYSCALL_CALL(pwrite);
__SYSCALL_CALL(writev);
__SYSCALL_CALL(seek);
__SYSCALL_CALL(ioctl);
__SYSCALL_CALL(openat);
__SYSCALL_CALL(close);
__SYSCALL_CALL(fstat);
__SYSCALL_CALL(fstatat);
__SYSCALL_CALL(statvfs);
__SYSCALL_CALL(fstatvfs);
__SYSCALL_CALL(faccessat);
__SYSCALL_CALL(fcntl);
__SYSCALL_CALL(ftruncate);
__SYSCALL_CALL(truncate);
__SYSCALL_CALL(fallocate);
__SYSCALL_CALL(fadvise);
__SYSCALL_CALL(utimensat);
__SYSCALL_CALL(mknodat);
__SYSCALL_CALL(getcwd);
__SYSCALL_CALL(chdir);
__SYSCALL_CALL(fchdir);
__SYSCALL_CALL(mkdirat);
__SYSCALL_CALL(rmdirat);
__SYSCALL_CALL(getdents);
__SYSCALL_CALL(renameat);
__SYSCALL_CALL(fchmod);
__SYSCALL_CALL(fchmodat);
__SYSCALL_CALL(fchownat);
__SYSCALL_CALL(linkat);
__SYSCALL_CALL(symlinkat);
__SYSCALL_CALL(unlinkat);
__SYSCALL_CALL(readlinkat);
__SYSCALL_CALL(flock);
__SYSCALL_CALL(ppoll);
__SYSCALL_CALL(dup);
__SYSCALL_CALL(dup3);
__SYSCALL_CALL(sync);
__SYSCALL_CALL(fsync);
__SYSCALL_CALL(fdatasync);
__SYSCALL_CALL(getgroups);
__SYSCALL_CALL(setgroups);
__SYSCALL_CALL(getsid);
__SYSCALL_CALL(setsid);
__SYSCALL_CALL(setuid);
__SYSCALL_CALL(getuid);
__SYSCALL_CALL(setgid);
__SYSCALL_CALL(getgid);
__SYSCALL_CALL(geteuid);
__SYSCALL_CALL(seteuid);
__SYSCALL_CALL(getegid);
__SYSCALL_CALL(setegid);
__SYSCALL_CALL(getpgid);
__SYSCALL_CALL(setpgid);
__SYSCALL_CALL(getresuid);
__SYSCALL_CALL(setresuid);
__SYSCALL_CALL(getresgid);
__SYSCALL_CALL(setresgid);
__SYSCALL_CALL(setreuid);
__SYSCALL_CALL(setregid);
__SYSCALL_CALL(umask);
__SYSCALL_CALL(pipe);
__SYSCALL_CALL(futex_wait);
__SYSCALL_CALL(futex_wake);
__SYSCALL_CALL(thread_create);
__SYSCALL_CALL(thread_kill);
__SYSCALL_CALL(thread_exit);
__SYSCALL_CALL(thread_setname);
__SYSCALL_CALL(thread_getname);
__SYSCALL_CALL(timer_create);
__SYSCALL_CALL(timer_set);
__SYSCALL_CALL(timer_get);
__SYSCALL_CALL(timer_getoverrun);
__SYSCALL_CALL(timer_delete);
__SYSCALL_CALL(itimer_get);
__SYSCALL_CALL(itimer_set);
__SYSCALL_CALL(clock_get);
__SYSCALL_CALL(clock_getres);
__SYSCALL_CALL(clock_set);
__SYSCALL_CALL(sleep);
__SYSCALL_CALL(yield);
__SYSCALL_CALL(chroot);
__SYSCALL_CALL(mount);
__SYSCALL_CALL(umount);
__SYSCALL_CALL(socket);
__SYSCALL_CALL(socketpair);
__SYSCALL_CALL(shutdown);
__SYSCALL_CALL(bind);
__SYSCALL_CALL(connect);
__SYSCALL_CALL(accept);
__SYSCALL_CALL(listen);
__SYSCALL_CALL(getpeername);
__SYSCALL_CALL(getsockname);
__SYSCALL_CALL(getsockopt);
__SYSCALL_CALL(setsockopt);
__SYSCALL_CALL(sendmsg);
__SYSCALL_CALL(recvmsg);
__SYSCALL_CALL(getentropy);
__SYSCALL_CALL(getrusage);
__SYSCALL_CALL(getrlimit);
__SYSCALL_CALL(setrlimit);
__SYSCALL_CALL(getpriority);
__SYSCALL_CALL(setpriority);
__SYSCALL_CALL(sched_getparam);
__SYSCALL_CALL(sched_setparam);
__SYSCALL_CALL(module_insert);
__SYSCALL_CALL(module_remove);
__SYSCALL_CALL(epoll_create);
__SYSCALL_CALL(epoll_ctl);
__SYSCALL_CALL(epoll_pwait);
__SYSCALL_CALL(timerfd_create);
__SYSCALL_CALL(timerfd_gettime);
__SYSCALL_CALL(timerfd_settime);
__SYSCALL_CALL(signalfd_create);
__SYSCALL_CALL(eventfd_create);
__SYSCALL_CALL(msync);
__SYSCALL_CALL(sysconf);
SYSCALL_DECLARE(exit);
SYSCALL_DECLARE(syslog);
SYSCALL_DECLARE(getuname);
SYSCALL_DECLARE(setuname);
SYSCALL_DECLARE(archctl);
SYSCALL_DECLARE(reboot);
SYSCALL_DECLARE(mmap);
SYSCALL_DECLARE(munmap);
SYSCALL_DECLARE(mprotect);
SYSCALL_DECLARE(madvise);
SYSCALL_DECLARE(sigprocmask);
SYSCALL_DECLARE(sigsuspend);
SYSCALL_DECLARE(sigpending);
SYSCALL_DECLARE(sigaction);
SYSCALL_DECLARE(sigtimedwait);
SYSCALL_DECLARE(sigaltstack);
SYSCALL_DECLARE(sigreturn);
SYSCALL_DECLARE(sigqueue);
SYSCALL_DECLARE(execve);
SYSCALL_DECLARE(fexecve);
SYSCALL_DECLARE(fork);
SYSCALL_DECLARE(kill);
SYSCALL_DECLARE(gettid);
SYSCALL_DECLARE(getpid);
SYSCALL_DECLARE(getppid);
SYSCALL_DECLARE(waitid);
SYSCALL_DECLARE(waitpid);
SYSCALL_DECLARE(pread);
SYSCALL_DECLARE(readv);
SYSCALL_DECLARE(pwrite);
SYSCALL_DECLARE(writev);
SYSCALL_DECLARE(seek);
SYSCALL_DECLARE(ioctl);
SYSCALL_DECLARE(openat);
SYSCALL_DECLARE(close);
SYSCALL_DECLARE(fstat);
SYSCALL_DECLARE(fstatat);
SYSCALL_DECLARE(statvfs);
SYSCALL_DECLARE(fstatvfs);
SYSCALL_DECLARE(faccessat);
SYSCALL_DECLARE(fcntl);
SYSCALL_DECLARE(ftruncate);
SYSCALL_DECLARE(truncate);
SYSCALL_DECLARE(fallocate);
SYSCALL_DECLARE(fadvise);
SYSCALL_DECLARE(utimensat);
SYSCALL_DECLARE(mknodat);
SYSCALL_DECLARE(getcwd);
SYSCALL_DECLARE(chdir);
SYSCALL_DECLARE(fchdir);
SYSCALL_DECLARE(mkdirat);
SYSCALL_DECLARE(rmdirat);
SYSCALL_DECLARE(getdents);
SYSCALL_DECLARE(renameat);
SYSCALL_DECLARE(fchmod);
SYSCALL_DECLARE(fchmodat);
SYSCALL_DECLARE(fchownat);
SYSCALL_DECLARE(linkat);
SYSCALL_DECLARE(symlinkat);
SYSCALL_DECLARE(unlinkat);
SYSCALL_DECLARE(readlinkat);
SYSCALL_DECLARE(flock);
SYSCALL_DECLARE(ppoll);
SYSCALL_DECLARE(dup);
SYSCALL_DECLARE(dup3);
SYSCALL_DECLARE(sync);
SYSCALL_DECLARE(fsync);
SYSCALL_DECLARE(fdatasync);
SYSCALL_DECLARE(getgroups);
SYSCALL_DECLARE(setgroups);
SYSCALL_DECLARE(getsid);
SYSCALL_DECLARE(setsid);
SYSCALL_DECLARE(setuid);
SYSCALL_DECLARE(getuid);
SYSCALL_DECLARE(setgid);
SYSCALL_DECLARE(getgid);
SYSCALL_DECLARE(geteuid);
SYSCALL_DECLARE(seteuid);
SYSCALL_DECLARE(getegid);
SYSCALL_DECLARE(setegid);
SYSCALL_DECLARE(getpgid);
SYSCALL_DECLARE(setpgid);
SYSCALL_DECLARE(getresuid);
SYSCALL_DECLARE(setresuid);
SYSCALL_DECLARE(getresgid);
SYSCALL_DECLARE(setresgid);
SYSCALL_DECLARE(setreuid);
SYSCALL_DECLARE(setregid);
SYSCALL_DECLARE(umask);
SYSCALL_DECLARE(pipe);
SYSCALL_DECLARE(futex_wait);
SYSCALL_DECLARE(futex_wake);
SYSCALL_DECLARE(thread_create);
SYSCALL_DECLARE(thread_kill);
SYSCALL_DECLARE(thread_exit);
SYSCALL_DECLARE(thread_setname);
SYSCALL_DECLARE(thread_getname);
SYSCALL_DECLARE(timer_create);
SYSCALL_DECLARE(timer_set);
SYSCALL_DECLARE(timer_get);
SYSCALL_DECLARE(timer_getoverrun);
SYSCALL_DECLARE(timer_delete);
SYSCALL_DECLARE(itimer_get);
SYSCALL_DECLARE(itimer_set);
SYSCALL_DECLARE(clock_get);
SYSCALL_DECLARE(clock_getres);
SYSCALL_DECLARE(clock_set);
SYSCALL_DECLARE(sleep);
SYSCALL_DECLARE(yield);
SYSCALL_DECLARE(chroot);
SYSCALL_DECLARE(mount);
SYSCALL_DECLARE(umount);
SYSCALL_DECLARE(socket);
SYSCALL_DECLARE(socketpair);
SYSCALL_DECLARE(shutdown);
SYSCALL_DECLARE(bind);
SYSCALL_DECLARE(connect);
SYSCALL_DECLARE(accept);
SYSCALL_DECLARE(listen);
SYSCALL_DECLARE(getpeername);
SYSCALL_DECLARE(getsockname);
SYSCALL_DECLARE(getsockopt);
SYSCALL_DECLARE(setsockopt);
SYSCALL_DECLARE(sendmsg);
SYSCALL_DECLARE(recvmsg);
SYSCALL_DECLARE(getentropy);
SYSCALL_DECLARE(getrusage);
SYSCALL_DECLARE(getrlimit);
SYSCALL_DECLARE(setrlimit);
SYSCALL_DECLARE(getpriority);
SYSCALL_DECLARE(setpriority);
SYSCALL_DECLARE(sched_getparam);
SYSCALL_DECLARE(sched_setparam);
SYSCALL_DECLARE(module_insert);
SYSCALL_DECLARE(module_remove);
SYSCALL_DECLARE(epoll_create);
SYSCALL_DECLARE(epoll_ctl);
SYSCALL_DECLARE(epoll_pwait);
SYSCALL_DECLARE(timerfd_create);
SYSCALL_DECLARE(timerfd_gettime);
SYSCALL_DECLARE(timerfd_settime);
SYSCALL_DECLARE(signalfd_create);
SYSCALL_DECLARE(eventfd_create);
SYSCALL_DECLARE(msync);
SYSCALL_DECLARE(sysconf);
+2 -3
View File
@@ -1,8 +1,7 @@
#pragma once
#include <bits/types.h>
#include <zinnia/utils.h>
#include <bits/types.h>
ASSERT_TYPE(phys_t);
ASSERT_TYPE(uintptr_t);
ASSERT_TYPE(reg_t);
ASSERT_TYPE(virt_t);
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include <stddef.h>
#include <zinnia/compiler.h>
#include <stddef.h>
struct usercopy_region {
void (*start_ip)();
-32
View File
@@ -1,32 +0,0 @@
#pragma once
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <zinnia/mutex.h>
#include <zinnia/object.h>
#include <zinnia/pmap.h>
// Virtual address space.
struct vas {
// Architecture-specific virtual memory map implementation.
struct pmap pmap;
};
// Try to create a new, empty virtual address space.
errno_t vma_new(struct vas** out);
// Delete a virtual address space.
void vma_delete(struct vas* vm);
errno_t vma_map_vmo(struct vas* vm, struct vmo* vmo, uintptr_t addr, size_t len, enum flags, uintptr_t vmo_offset);
// Remove any mappings in the given address range.
errno_t vma_unmap(struct vas* vm, uintptr_t vaddr, size_t size);
// Change the protection of an existing mapping.
errno_t vma_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags);
// Try to handle a page fault.
bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type);
extern struct vas kernel_vas;
+31 -29
View File
@@ -7,35 +7,6 @@
#include <stdint.h>
#include <uapi/fcntl.h>
struct vfs_mount {
struct refcount rc;
};
struct vfs_entry {
struct refcount rc;
};
struct vfs_path {
struct vfs_mount* mount;
struct vfs_entry* entry;
};
struct vfs_node;
struct vfs_regular_ops {
errno_t (*read)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
errno_t (*write)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
errno_t (*devctl)(struct vfs_node* file);
};
struct vfs_node {
struct refcount rc;
const struct vfs_regular_ops* ops;
struct vfs_vnode* vnode;
struct vfs_path path;
const char* abs_path;
bool has_path;
};
enum open_flags : uint32_t {
O_RDONLY = __O_RDONLY,
O_WRONLY = __O_WRONLY,
@@ -62,3 +33,34 @@ enum open_flags : uint32_t {
O_SEARCH = __O_SEARCH,
O_ACCMODE = __O_ACCMODE,
};
struct vfs_mount {
struct refcount rc;
// TODO
};
struct vfs_entry {
struct refcount rc;
// TODO
};
struct vfs_path {
struct vfs_mount* mount;
struct vfs_entry* entry;
};
struct vfs_node;
struct vfs_regular_ops {
errno_t (*read)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
errno_t (*write)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
errno_t (*devctl)(struct vfs_node* file);
};
struct vfs_node {
struct refcount rc;
const struct vfs_regular_ops* ops;
struct vfs_vnode* vnode;
struct vfs_path path;
const char* abs_path;
bool has_path;
};
@@ -1,5 +1,7 @@
#pragma once
#include <zinnia/hashmap.h>
#include <zinnia/types.h>
#include <stddef.h>
#include <stdint.h>
@@ -21,10 +23,18 @@ struct page {
static_assert(0x1000 % sizeof(struct page) == 0, "struct must fit cleanly inside a page!");
static_assert(sizeof(struct page) <= 64, "struct must be smaller than 64 bytes!");
void* vm_alloc(size_t length);
void vm_free(void* addr, size_t length);
// Base address of the `struct page` array.
extern struct page* vm_pfndb;
uintptr_t vm_page_addr(struct page* page);
// Allocator for virtual memory.
struct vm_alloc {
virt_t start_page;
virt_t end_page;
virt_t next_fit;
hashmap(int, void);
};
uintptr_t vm_alloc(size_t length);
void vm_free(uintptr_t addr, size_t length);
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/mutex.h>
#include <zinnia/pmap.h>
#include <zinnia/vmo.h>
// Virtual address space.
struct vma {
// Architecture-specific virtual memory map implementation.
struct pmap pmap;
};
// Try to create a new, empty virtual address space.
errno_t vma_new(struct vma** out);
// Delete a virtual address space.
void vma_free(struct vma* v);
errno_t vma_map(
struct vma* vm,
struct vmo* vmo,
uintptr_t addr,
size_t len,
enum prot_flags flags,
uintptr_t vmo_offset
);
// Remove any mappings in the given address range.
errno_t vma_unmap(struct vma* v, uintptr_t vaddr, size_t size);
// Change the protection of an existing mapping.
errno_t vma_protect(struct vma* v, uintptr_t vaddr, size_t size, enum prot_flags flags);
struct vma_fault_info {
uintptr_t ip;
uintptr_t addr;
bool caused_by_user;
bool caused_by_write;
bool caused_by_fetch;
bool page_was_present;
};
// Try to handle a page fault.
bool vma_page_fault(struct vma* v, const struct vma_fault_info* info);
extern struct vma kernel_vma;
@@ -2,8 +2,8 @@
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/page.h>
#include <zinnia/spin.h>
#include <zinnia/virt.h>
#include <stddef.h>
#include <stdint.h>
-22
View File
@@ -1,22 +0,0 @@
#include <bits/mem.h>
#include <zinnia/mmio.h>
#include <zinnia/pmap.h>
#include <zinnia/vas.h>
#include <zinnia/virt.h>
void* mmio_new(phys_t addr, size_t length) {
void* ptr = vm_alloc(length);
for (size_t i = 0; i < length; i += arch_mem_page_size()) {
if (pmap_map(&kernel_vas.pmap, (uintptr_t)ptr + i, addr + i, PTE_READ | PTE_WRITE, CACHE_MMIO)) {
vm_free(ptr, length);
return nullptr;
}
}
return ptr;
}
void mmio_free(void* ptr, size_t length) {
// TODO
}
+10 -15
View File
@@ -89,25 +89,20 @@ kernel_includes = [
kernel_sources = []
# Goes first so we can add arch-specific flags to drivers.
subdir('arch' / target_machine.cpu_family())
subdir('boot')
subdir('core')
# Device and file system drivers.
subdir('dev')
subdir('fs')
configure_file(
configuration: cfg,
output: 'config.h',
depfile: get_option('config_path'),
)
# Goes first so we can add arch-specific flags to drivers.
subdir('arch' / target_machine.cpu_family())
subdir('device')
subdir('fs')
subdir('boot')
subdir('mem')
subdir('core')
subdir('syscalls')
subdir('lib')
executable(
'zinnia',
include_directories: [
@@ -121,5 +116,5 @@ executable(
kernel_sources,
],
install: true,
install_dir: '/boot',
install_dir: get_option('datadir') / 'zinnia',
)
-185
View File
@@ -1,185 +0,0 @@
#include <zinnia/compiler.h>
#include <zinnia/errno.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <zinnia/syscall.h>
#include <zinnia/syscall_list.h>
#include <zinnia/types.h>
#include <zinnia/utils.h>
const struct syscall syscall_table[256] = {
[0] = {.call = sys_exit},
[1] = {.call = sys_syslog},
[2] = {.call = sys_getuname},
[3] = {.call = sys_setuname},
[4] = {.call = sys_archctl},
[5] = {.call = sys_reboot},
[6] = {.call = sys_mmap},
[7] = {.call = sys_munmap},
[8] = {.call = sys_mprotect},
[9] = {.call = sys_madvise},
[10] = {.call = sys_sigprocmask},
[11] = {.call = sys_sigsuspend},
[12] = {.call = sys_sigpending},
[13] = {.call = sys_sigaction},
[14] = {.call = sys_sigtimedwait},
[15] = {.call = sys_sigaltstack},
[16] = {.call = sys_sigreturn},
[17] = {.call = sys_sigqueue},
[18] = {.call = sys_execve},
[19] = {.call = sys_fexecve},
[20] = {.context = sys_fork, SYSKIND_CONTEXT},
[21] = {.call = sys_kill},
[22] = {.call = sys_gettid},
[23] = {.call = sys_getpid},
[24] = {.call = sys_getppid},
[25] = {.call = sys_waitid},
[26] = {.call = sys_waitpid},
[27] = {.call = sys_pread},
[28] = {.call = sys_readv},
[29] = {.call = sys_pwrite},
[30] = {.call = sys_writev},
[31] = {.call = sys_seek},
[32] = {.call = sys_ioctl},
[33] = {.call = sys_openat},
[34] = {.call = sys_close},
[35] = {.call = sys_fstat},
[36] = {.call = sys_fstatat},
[37] = {.call = sys_statvfs},
[38] = {.call = sys_fstatvfs},
[39] = {.call = sys_faccessat},
[40] = {.call = sys_fcntl},
[41] = {.call = sys_ftruncate},
[42] = {.call = sys_truncate},
[43] = {.call = sys_fallocate},
[44] = {.call = sys_fadvise},
[45] = {.call = sys_utimensat},
[46] = {.call = sys_mknodat},
[47] = {.call = sys_getcwd},
[48] = {.call = sys_chdir},
[49] = {.call = sys_fchdir},
[50] = {.call = sys_mkdirat},
[51] = {.call = sys_rmdirat},
[52] = {.call = sys_getdents},
[53] = {.call = sys_renameat},
[54] = {.call = sys_fchmod},
[55] = {.call = sys_fchmodat},
[56] = {.call = sys_fchownat},
[57] = {.call = sys_linkat},
[58] = {.call = sys_symlinkat},
[59] = {.call = sys_unlinkat},
[60] = {.call = sys_readlinkat},
[61] = {.call = sys_flock},
[62] = {.call = sys_ppoll},
[63] = {.call = sys_dup},
[64] = {.call = sys_dup3},
[65] = {.call = sys_sync},
[66] = {.call = sys_fsync},
[67] = {.call = sys_fdatasync},
[68] = {.call = sys_getgroups},
[69] = {.call = sys_setgroups},
[70] = {.call = sys_getsid},
[71] = {.call = sys_setsid},
[72] = {.call = sys_setuid},
[73] = {.call = sys_getuid},
[74] = {.call = sys_setgid},
[75] = {.call = sys_getgid},
[76] = {.call = sys_geteuid},
[77] = {.call = sys_seteuid},
[78] = {.call = sys_getegid},
[79] = {.call = sys_setegid},
[80] = {.call = sys_getpgid},
[81] = {.call = sys_setpgid},
[82] = {.call = sys_getresuid},
[83] = {.call = sys_setresuid},
[84] = {.call = sys_getresgid},
[85] = {.call = sys_setresgid},
[86] = {.call = sys_setreuid},
[87] = {.call = sys_setregid},
[88] = {.call = sys_umask},
[89] = {.call = sys_pipe},
[90] = {.call = sys_futex_wait},
[91] = {.call = sys_futex_wake},
[92] = {.call = sys_thread_create},
[93] = {.call = sys_thread_kill},
[94] = {.call = sys_thread_exit},
[95] = {.call = sys_thread_setname},
[96] = {.call = sys_thread_getname},
[97] = {.call = sys_timer_create},
[98] = {.call = sys_timer_set},
[99] = {.call = sys_timer_get},
[100] = {.call = sys_timer_getoverrun},
[101] = {.call = sys_timer_delete},
[102] = {.call = sys_itimer_get},
[103] = {.call = sys_itimer_set},
[104] = {.call = sys_clock_get},
[105] = {.call = sys_clock_getres},
[106] = {.call = sys_clock_set},
[107] = {.call = sys_sleep},
[108] = {.call = sys_yield},
[109] = {.call = sys_chroot},
[110] = {.call = sys_mount},
[111] = {.call = sys_umount},
[112] = {.call = sys_socket},
[113] = {.call = sys_socketpair},
[114] = {.call = sys_shutdown},
[115] = {.call = sys_bind},
[116] = {.call = sys_connect},
[117] = {.call = sys_accept},
[118] = {.call = sys_listen},
[119] = {.call = sys_getpeername},
[120] = {.call = sys_getsockname},
[121] = {.call = sys_getsockopt},
[122] = {.call = sys_setsockopt},
[123] = {.call = sys_sendmsg},
[124] = {.call = sys_recvmsg},
[125] = {.call = sys_getentropy},
[126] = {.call = sys_getrusage},
[127] = {.call = sys_getrlimit},
[128] = {.call = sys_setrlimit},
[129] = {.call = sys_getpriority},
[130] = {.call = sys_setpriority},
[131] = {.call = sys_sched_getparam},
[132] = {.call = sys_sched_setparam},
[133] = {.call = sys_module_insert},
[134] = {.call = sys_module_remove},
[135] = {.call = sys_epoll_create},
[136] = {.call = sys_epoll_ctl},
[137] = {.call = sys_epoll_pwait},
[138] = {.call = sys_timerfd_create},
[139] = {.call = sys_timerfd_gettime},
[140] = {.call = sys_timerfd_settime},
[141] = {.call = sys_signalfd_create},
[142] = {.call = sys_eventfd_create},
[143] = {.call = sys_msync},
[144] = {.call = sys_sysconf},
};
struct syscall_return syscall_dispatch_call(
size_t num,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5
) {
// No need to check the table size here. In order to get to this point,
// we already have to check if this is a fast syscall.
if (syscall_table[num].call == nullptr) {
return (struct syscall_return){.errno = ENOSYS};
}
return syscall_table[num].call(a0, a1, a2, a3, a4, a5);
}
void syscall_dispatch(struct arch_context* ctx) {
const size_t num = ctx->ARCH_CTX_NUM;
if (num >= ARRAY_SIZE(syscall_table) || syscall_table[num].context == nullptr) {
ctx->ARCH_CTX_RET0 = ENOSYS;
return;
}
syscall_table[num].context(ctx);
}