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/clock.h>
#include <zinnia/mmio.h> #include <zinnia/mmio.h>
#include <zinnia/percpu.h> #include <zinnia/percpu.h>
#include <assert.h> #include <zinnia/pmap.h>
#include <zinnia/vma.h>
#include <stdint.h> #include <stdint.h>
#include <x86_64/apic.h> #include <x86_64/apic.h>
#include <x86_64/asm.h> #include <x86_64/asm.h>
#include <x86_64/defs.h> #include <x86_64/defs.h>
static uint64_t lapic_read_reg(struct local_apic* lapic, mmio_reg32 reg) { static uint64_t lapic_read_reg(struct local_apic* lapic, uint32_t reg) {
if (lapic->xapic_regs.base) { if (lapic->xapic_regs) {
if (reg.offset == APIC_REG_ICR.offset) { if (reg == APIC_REG_ICR) {
uint64_t lo, hi; uint64_t lo, hi;
lo = mmio_load(&lapic->xapic_regs, APIC_REG_ICR); lo = mmio_read32(lapic->xapic_regs + APIC_REG_ICR);
hi = mmio_load(&lapic->xapic_regs, APIC_REG_ICR_HI); hi = mmio_read32(lapic->xapic_regs + APIC_REG_ICR_HI);
return (hi << 32) | lo; return (hi << 32) | lo;
} else { } else {
return mmio_load(&lapic->xapic_regs, reg); return mmio_read32(lapic->xapic_regs + reg);
} }
} else { } 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) { static void lapic_write_reg(struct local_apic* lapic, uint32_t reg, uint64_t value) {
if (lapic->xapic_regs.base) { if (lapic->xapic_regs) {
if (reg.offset == APIC_REG_ICR.offset) { if (reg == APIC_REG_ICR) {
mmio_store(&lapic->xapic_regs, APIC_REG_ICR_HI, value >> 32); mmio_write32(lapic->xapic_regs + APIC_REG_ICR_HI, value >> 32);
mmio_store(&lapic->xapic_regs, APIC_REG_ICR, (uint32_t)value); mmio_write32(lapic->xapic_regs + APIC_REG_ICR, (uint32_t)value);
} else { } else {
mmio_store(&lapic->xapic_regs, reg, (uint32_t)value); mmio_write32(lapic->xapic_regs + reg, (uint32_t)value);
} }
} else { } 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) if (cpuid.ecx & CPUID_1C_X2APIC)
apic_msr |= 1 << 10; apic_msr |= 1 << 10;
else { else {
lapic->xapic_regs = mmio_new(apic_msr & 0xFFFF'F000, 0x1000); uintptr_t vaddr = vm_alloc(0x1000);
assert(lapic->xapic_regs.base, "Failed to allocate virtual memory!\n"); 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); asm_wrmsr(0x1B, apic_msr);
@@ -54,7 +59,7 @@ void lapic_init(struct local_apic* lapic) {
// Enable APIC bit in the SIVR. // Enable APIC bit in the SIVR.
lapic_write_reg(lapic, APIC_REG_SIVR, lapic_read_reg(lapic, APIC_REG_SIVR) | 0x100); 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); lapic_write_reg(lapic, APIC_REG_DFR, 0xF000'0000);
// Logical destination = LAPIC ID. // Logical destination = LAPIC ID.
lapic_write_reg(lapic, APIC_REG_LDR, lapic_read_reg(lapic, APIC_REG_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 <zinnia/errno.h>
#include <arch/archctl.h>
#include <uapi/archctl.h> #include <uapi/archctl.h>
#include <x86_64/asm.h> #include <x86_64/asm.h>
#include <x86_64/defs.h> #include <x86_64/defs.h>
+17 -11
View File
@@ -1,9 +1,11 @@
#include <zinnia/assert.h>
#include <zinnia/clock.h> #include <zinnia/clock.h>
#include <zinnia/cmdline.h> #include <zinnia/cmdline.h>
#include <zinnia/mmio.h> #include <zinnia/mmio.h>
#include <zinnia/pmap.h>
#include <zinnia/print.h> #include <zinnia/print.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <assert.h> #include <zinnia/vma.h>
#include <uacpi/acpi.h> #include <uacpi/acpi.h>
#include <uacpi/status.h> #include <uacpi/status.h>
#include <uacpi/tables.h> #include <uacpi/tables.h>
@@ -17,22 +19,22 @@ CMDLINE_OPTION("hpet", hpet_option);
struct hpet { struct hpet {
struct clock clock; struct clock clock;
struct mmio_view regs; void* regs;
uint32_t period; uint32_t period;
}; };
constexpr mmio_reg32 HPET_CAP = {.offset = 0}; constexpr uint32_t HPET_CAP = 0x0;
constexpr mmio_reg32 HPET_CFG = {.offset = 0x10}; constexpr uint32_t HPET_CFG = 0x10;
constexpr mmio_reg32 HPET_COUNTER = {.offset = 0xF0}; constexpr uint32_t HPET_COUNTER = 0xF0;
static void hpet_reset(struct clock* c) { static void hpet_reset(struct clock* c) {
struct hpet* hpet = containerof(c, struct hpet, clock); 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) { static uint64_t hpet_get_elapsed_ns(struct clock* c) {
struct hpet* hpet = containerof(c, struct hpet, clock); 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); 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"); assert(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n");
struct acpi_hpet* hpet = table.ptr; 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); 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; hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF;
assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n"); 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/compiler.h>
#include <zinnia/irq.h> #include <zinnia/irq.h>
#include <zinnia/panic.h> #include <zinnia/panic.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 <assert.h>
#include <bits/sched.h> #include <bits/sched.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.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 #pragma once
#include <zinnia/irq.h>
#include <stddef.h> #include <stddef.h>
#include <x86_64/apic.h> #include <x86_64/apic.h>
#include <x86_64/gdt.h> #include <x86_64/gdt.h>
#include <x86_64/tss.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 arch_percpu {
struct gdt gdt; struct gdt gdt;
@@ -22,6 +16,3 @@ struct arch_percpu {
void (*fpu_restore)(const void*); void (*fpu_restore)(const void*);
bool can_smap; bool can_smap;
}; };
void arch_percpu_bsp_init();
void arch_percpu_init();
+2 -5
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <bits/types.h>
#include <stdint.h> #include <stdint.h>
struct arch_task_context { struct arch_task_context {
@@ -39,10 +38,8 @@ struct arch_context {
#define ARCH_CTX_A0 rdi #define ARCH_CTX_A0 rdi
#define ARCH_CTX_A1 rsi #define ARCH_CTX_A1 rsi
#define ARCH_CTX_A2 rdx #define ARCH_CTX_A2 rdx
#define ARCH_CTX_A3 r9 #define ARCH_CTX_A3 r10
#define ARCH_CTX_A4 r8 #define ARCH_CTX_A4 r8
#define ARCH_CTX_A5 r10 #define ARCH_CTX_A5 r9
#define ARCH_CTX_A6 r12
#define ARCH_CTX_A7 r13
#define ARCH_CTX_RET0 rax #define ARCH_CTX_RET0 rax
#define ARCH_CTX_RET1 rdx #define ARCH_CTX_RET1 rdx
+1 -1
View File
@@ -3,4 +3,4 @@
#include <stdint.h> #include <stdint.h>
typedef uint64_t phys_t; 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 #pragma once
#include <stdint.h> #include <stdint.h>
#include <zinnia/mmio.h>
struct local_apic { struct local_apic {
uint32_t id; uint32_t id;
uint32_t ticks_per_10ms; uint32_t ticks_per_10ms;
struct mmio_view xapic_regs; void* xapic_regs;
}; };
enum apic_delivery_mode { enum apic_delivery_mode {
@@ -38,19 +37,21 @@ enum apic_trigger_mode {
APIC_TRIGGER_LEVEL = 1, APIC_TRIGGER_LEVEL = 1,
}; };
constexpr mmio_reg32 APIC_REG_ID = {.offset = 0x20}; enum apic_regs {
constexpr mmio_reg32 APIC_REG_TPR = {.offset = 0x80}; APIC_REG_ID = 0x20,
constexpr mmio_reg32 APIC_REG_EOI = {.offset = 0xB0}; APIC_REG_TPR = 0x80,
constexpr mmio_reg32 APIC_REG_LDR = {.offset = 0xD0}; APIC_REG_EOI = 0xB0,
constexpr mmio_reg32 APIC_REG_DFR = {.offset = 0xE0}; APIC_REG_LDR = 0xD0,
constexpr mmio_reg32 APIC_REG_SIVR = {.offset = 0xF0}; APIC_REG_DFR = 0xE0,
constexpr mmio_reg32 APIC_REG_ESR = {.offset = 0x280}; APIC_REG_SIVR = 0xF0,
constexpr mmio_reg32 APIC_REG_ICR = {.offset = 0x300}; APIC_REG_ESR = 0x280,
constexpr mmio_reg32 APIC_REG_ICR_HI = {.offset = 0x310}; APIC_REG_ICR = 0x300,
constexpr mmio_reg32 APIC_REG_LVT_TR = {.offset = 0x320}; APIC_REG_ICR_HI = 0x310,
constexpr mmio_reg32 APIC_REG_ICR_TIMER = {.offset = 0x380}; APIC_REG_LVT_TR = 0x320,
constexpr mmio_reg32 APIC_REG_CCR = {.offset = 0x390}; APIC_REG_ICR_TIMER = 0x380,
constexpr mmio_reg32 APIC_REG_DCR = {.offset = 0x3E0}; APIC_REG_CCR = 0x390,
APIC_REG_DCR = 0x3E0,
};
void lapic_init(struct local_apic* lapic); void lapic_init(struct local_apic* lapic);
void lapic_eoi(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_GS_BASE (0xC0000101)
#define MSR_KERNEL_GS_BASE (0xC0000102) #define MSR_KERNEL_GS_BASE (0xC0000102)
#define CPL_USER (0b11) #define CPL_USER (0x3)
#define CPL_KERNEL (0b00) #define CPL_KERNEL (0x0)
#define IDT_PF (0xE) #define IDT_PF (0xE)
#define IDT_IPI_RESCHED (0xFF) #define IDT_IPI_RESCHED (0xFF)
@@ -1,21 +1,20 @@
#pragma once #include <arch/irq.h>
#include <stdint.h> #include <stdint.h>
#include <x86_64/defs.h> #include <x86_64/defs.h>
static inline bool arch_irq_get_state() { bool arch_irq_get_state() {
uint64_t flags; uint64_t flags;
asm volatile("pushf; pop %0" : "=r"(flags)::"memory"); asm volatile("pushf; pop %0" : "=r"(flags)::"memory");
return flags & RFLAGS_IF; return flags & RFLAGS_IF;
} }
static inline void arch_irq_set_state(bool state) { void arch_irq_set_state(bool state) {
if (state) if (state)
asm volatile("sti"); asm volatile("sti");
else else
asm volatile("cli"); asm volatile("cli");
} }
static inline void arch_irq_wait() { void arch_irq_wait() {
asm volatile("hlt"); 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', 'gdt.c',
'hpet.c', 'hpet.c',
'idt.c', 'idt.c',
'irq.c',
'mem.c',
'percpu.c', 'percpu.c',
'pmap.c', 'pmap.c',
'pmap.c',
'sched.c', 'sched.c',
'serial.c', 'serial.c',
'smp.c', 'smp.c',
+13 -1
View File
@@ -10,6 +10,12 @@
#include <x86_64/syscall.h> #include <x86_64/syscall.h>
#include <x86_64/tsc.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() { void arch_percpu_bsp_init() {
asm_wrmsr(MSR_GS_BASE, (uint64_t)&percpu_bsp); asm_wrmsr(MSR_GS_BASE, (uint64_t)&percpu_bsp);
asm_wrmsr(MSR_FS_BASE, 0); 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) { 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_GS_BASE, (uint64_t)cpu);
asm_wrmsr(MSR_FS_BASE, 0); asm_wrmsr(MSR_FS_BASE, 0);
asm_wrmsr(MSR_KERNEL_GS_BASE, 0);
gdt_load(); gdt_load();
// TODO: not if FRED
idt_load(); idt_load();
// Syscall extension. // 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_LSTAR, (uint64_t)arch_syscall_stub);
asm_wrmsr(MSR_SFMASK, RFLAGS_AC | RFLAGS_DF | RFLAGS_IF); asm_wrmsr(MSR_SFMASK, RFLAGS_AC | RFLAGS_DF | RFLAGS_IF);
// TODO: FRED
uint64_t cr0, cr4; uint64_t cr0, cr4;
asm volatile("mov %0, cr0" : "=r"(cr0)); asm volatile("mov %0, cr0" : "=r"(cr0));
asm volatile("mov %0, cr4" : "=r"(cr4)); asm volatile("mov %0, cr4" : "=r"(cr4));
+4 -4
View File
@@ -4,7 +4,7 @@
#include <zinnia/percpu.h> #include <zinnia/percpu.h>
#include <zinnia/pmap.h> #include <zinnia/pmap.h>
#include <zinnia/sched.h> #include <zinnia/sched.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <bits/sched.h> #include <bits/sched.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -119,7 +119,7 @@ errno_t arch_task_init(
if (is_user) { if (is_user) {
// Allocate FPU space. // Allocate FPU space.
const size_t fpu_size = cpu->fpu_size; 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) if (!fpu_base)
return ENOMEM; return ENOMEM;
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()) {
@@ -130,9 +130,9 @@ errno_t arch_task_init(
return s; 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->ds = asm_read_ds();
context->es = asm_read_es(); context->es = asm_read_es();
-2
View File
@@ -17,5 +17,3 @@ void _start() {
: "i"(__ld_stack_top), "r"(kernel_entry) : "i"(__ld_stack_top), "r"(kernel_entry)
); );
} }
void arch_panic() {}
+20 -19
View File
@@ -11,17 +11,17 @@
void arch_syscall_stub() { void arch_syscall_stub() {
asm volatile( asm volatile(
" swapgs\n" " swapgs\n"
"mov gs:%c0, rsp\n" " mov gs:%c0, rsp\n" // user_stack
"mov rsp, gs:%c1\n" " mov rsp, gs:%c1\n" // kernel_stack
" cld\n" " cld\n"
// We're pretending to be an interrupt, so fill the bottom fields of `Context`. "1:\n"
"push %c3\n" // SS and CS are not changed during SYSCALL. Use `gdt::user_data | CPL_USER`. " push %c3\n" // ss
" push gs:%c0\n" " push gs:%c0\n"
"push r11\n" // RFLAGS is moved into r11 by the CPU. " push r11\n" // rflags
"push %c2\n" // Same as SS. Use `gdt::user_code64 | CPL_USER` " push %c2\n" // cs
"push rcx\n" // RIP is moved into rcx by the CPU. " push rcx\n" // rip
"push 0x00\n" // arch_context::error field " push 0x00\n" // arch_context::error
"push 0x00\n" // arch_context::isr field " push 0x00\n" // arch_context::isr
" push rax\n" " push rax\n"
" push rbx\n" " push rbx\n"
" push rcx\n" " push rcx\n"
@@ -38,8 +38,8 @@ void arch_syscall_stub() {
" push r14\n" " push r14\n"
" push r15\n" " push r15\n"
" xor rbp, rbp\n" " xor rbp, rbp\n"
"mov rdi, rsp\n" // Put the trap frame struct as first argument. " mov rdi, rsp\n" // SysV ABI first argument.
"call %c4\n" // Call syscall handler " call %c4\n" // Call syscall handler.
" cli\n" " cli\n"
" pop r15\n" " pop r15\n"
" pop r14\n" " pop r14\n"
@@ -56,15 +56,16 @@ void arch_syscall_stub() {
" pop rcx\n" " pop rcx\n"
" pop rbx\n" " pop rbx\n"
" pop rax\n" " pop rax\n"
"add rsp, 0x10\n" // Skip .error and .isr fields (2 * sizeof(uint64_t)) " add rsp, 0x10\n" // Skip .error and .isr fields
"mov rsp, gs:%c0\n" // Load user stack from `percpu::user_stack`. "2:\n"
" mov rsp, gs:%c0\n" // user_stack
" swapgs\n" " swapgs\n"
"sysretq\n" // Return to user mode. " sysretq\n"
: :
: "i"(offsetof(struct percpu, user_stack)), : "i"(offsetof(struct percpu, user_stack)), // 0
"i"(offsetof(struct percpu, kernel_stack)), "i"(offsetof(struct percpu, kernel_stack)), // 1
"i"(offsetof(struct gdt, user_code64) | CPL_USER), "i"(offsetof(struct gdt, user_code64) | CPL_USER), // 2
"i"(offsetof(struct gdt, user_data) | CPL_USER), "i"(offsetof(struct gdt, user_data) | CPL_USER), // 3
"i"(syscall_dispatch) "i"(syscall_dispatch) // 4
); );
} }
+6 -6
View File
@@ -11,7 +11,7 @@ void tsc_init() {
return; return;
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) { 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; return;
} }
@@ -34,21 +34,21 @@ void tsc_init() {
// On a normal system, this should usually never be called and is a last resort // 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. // since at this point we have at least the HPET timer.
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) { 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; freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
} else { } else {
kprintf("Unable to calibrate TSC using CPUID frequency information"); log("x86_64/tsc", "Unable to calibrate TSC using CPUID frequency information");
return; return;
} }
} else { } 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; 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) { static void tsc_option(bool opt) {
use_tsc = 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 <zinnia/compiler.h>
#include <arch/usercopy.h>
extern void x86_64_read_start(); extern void x86_64_read_start();
extern void x86_64_read_end(); extern void x86_64_read_end();
+45 -30
View File
@@ -1,4 +1,5 @@
#include <zinnia/alloc.h> #include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/clock.h> #include <zinnia/clock.h>
#include <zinnia/cmdline.h> #include <zinnia/cmdline.h>
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
@@ -10,67 +11,81 @@
#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/vas.h> #include <zinnia/vma.h>
#include <zinnia/vmo.h> #include <zinnia/vmo.h>
#include <assert.h>
#include <config.h> #include <config.h>
#include <stdint.h> #include <stdint.h>
static const char zinnia_banner[] = static const char zinnia_banner[] = "Zinnia " ZINNIA_VERSION " " CONFIG_KERNEL_FLAVOR " (" ZINNIA_ARCH
"Zinnia " ZINNIA_VERSION " " CONFIG_VARIANT " (" ZINNIA_ARCH ", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")"; ", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")";
static void kernel_main_task(uintptr_t arg0) { static void kernel_main_task(uintptr_t arg0) {
struct boot_info* info = (struct boot_info*)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"); assert(info->num_files >= 1, "No init executable provided\n");
struct vas* init_space; struct vma* init_space;
assert(vma_new(&init_space) == 0, ""); 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) == 0, ""); 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 task* init_task = nullptr;
errno_t status = 0; errno_t status = 0;
assert(false, "Not implemented!");
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) {
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]] [[__init]]
void kernel_early_init() { void kernel_early_init() {
percpu_bsp_init(); percpu_bsp_init();
percpu_get()->online = true; percpu_get()->online = true;
irq_lock(); 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(); uint64_t elapsed = clock_get_elapsed_ns();
counter_base += elapsed; counter_base += elapsed;
@@ -43,7 +43,7 @@ bool clock_switch(struct clock* clock) {
void clock_spin_ns(uint64_t ns) { void clock_spin_ns(uint64_t ns) {
if (active_clock == nullptr) { 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; return;
} }
+2 -2
View File
@@ -37,7 +37,7 @@ void console_init() {
if (active) { if (active) {
if (active->init(active) == false) if (active->init(active) == false)
active = nullptr; 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/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/elf.h> #include <zinnia/elf.h>
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/percpu.h> #include <zinnia/percpu.h>
#include <zinnia/pmap.h> #include <zinnia/pmap.h>
#include <zinnia/print.h> #include <zinnia/print.h>
#include <zinnia/sched.h> #include <zinnia/sched.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <zinnia/vdso.h>
#include <zinnia/vmo.h> #include <zinnia/vmo.h>
#include <assert.h>
#include <bits/elf.h> #include <bits/elf.h>
#include <string.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 elf_load(struct exec_info* info, struct task** out) {
errno_t status; errno_t status;
@@ -40,13 +47,13 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
struct elf_phdr phdr = {}; struct elf_phdr phdr = {};
vmo_read(info->file_obj, (ehdr.e_phoff + (i * ehdr.e_phentsize)), &phdr, sizeof(phdr), &read); vmo_read(info->file_obj, (ehdr.e_phoff + (i * ehdr.e_phentsize)), &phdr, sizeof(phdr), &read);
if (phdr.p_type == PT_LOAD) { if (phdr.p_type == PT_LOAD) {
enum zn_vm_flags prot = 0; enum prot_flags prot = 0;
if (phdr.p_flags & PF_R) if (phdr.p_flags & PF_R)
prot |= PROT_READ; prot |= PROT_READ;
if (phdr.p_flags & PF_W) if (phdr.p_flags & PF_W)
prot |= ZN_VM_MAP_WRITE; prot |= PROT_WRITE;
if (phdr.p_flags & PF_X) 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, ""); 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; return status;
// We map more than we copied so the rest is filled with zeroed pages. // 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) if (status)
return 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); 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) \ #define WRITE_AUXV(auxv, value) \
do { \ do { \
stack_off -= sizeof(uintptr_t); \ 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_PHNUM, ehdr.e_phnum);
WRITE_AUXV(AT_PHENT, ehdr.e_phentsize); WRITE_AUXV(AT_PHENT, ehdr.e_phentsize);
WRITE_AUXV(AT_ENTRY, ehdr.e_entry); WRITE_AUXV(AT_ENTRY, ehdr.e_entry);
WRITE_AUXV(AT_INIT_HANDLE, init_handle);
// envp pointers. // envp pointers.
stack_off -= sizeof(uintptr_t); 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; uintptr_t argc = num_argv;
vmo_write(&stack->object, stack_off, &argc, sizeof(argc), nullptr); 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) if (status)
return status; return status;
@@ -191,7 +189,7 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
start_info->arg = 0; start_info->arg = 0;
struct task* result; 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) if (status)
return status; return status;
+14 -1
View File
@@ -1,6 +1,19 @@
#include <stdatomic.h>
#include <zinnia/irq.h> #include <zinnia/irq.h>
#include <zinnia/percpu.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() { void irq_lock() {
struct irq_percpu* cpu = &percpu_get()->irq; struct irq_percpu* cpu = &percpu_get()->irq;
View File
+20 -21
View File
@@ -1,10 +1,10 @@
#include <zinnia/alloc.h> #include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/init.h> #include <zinnia/init.h>
#include <zinnia/panic.h> #include <zinnia/panic.h>
#include <zinnia/print.h> #include <zinnia/print.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <zinnia/virt.h>
#include <string.h> #include <string.h>
extern uint8_t __ld_text_start[]; 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_data_end[];
extern uint8_t __ld_kernel_start[]; extern uint8_t __ld_kernel_start[];
struct vas kernel_vas = {0}; struct vma kernel_vma = {0};
[[__init]] [[__init]]
void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_t kernel_phys, uintptr_t tmp_hhdm) { 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(); 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++) { for (size_t i = 0; i < map_len; i++) {
if (map[i].length == 0) if (map[i].length == 0)
continue; continue;
@@ -44,7 +44,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
break; 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. // 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]; largest = &map[i];
} }
mem_phys_bootstrap(largest); mem_phys_bootstrap(largest);
kprintf( log("mem",
"Using region [%p - %p] for bootstrap allocator\n", "Using region [%p - %p] for bootstrap allocator\n",
(void*)largest->address, (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. // Set the HHDM base address to the address given by the loader.
// We must not keep any virtual addresses to this region, // We must not keep any virtual addresses to this region,
// since we're likely going to map it at a different base address. // since we're likely going to map it at a different base address.
mem_hhdm_base = tmp_hhdm; 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 // 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) { for (uint8_t* p = __ld_text_start; p <= __ld_text_end; p += pgsz) {
errno_t status = pmap_map( errno_t status = pmap_map(
&kernel_vas.pmap, &kernel_vma.pmap,
(uintptr_t)p, (uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys), (phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ | PTE_EXEC, 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 // 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) { for (uint8_t* p = __ld_rodata_start; p < __ld_rodata_end; p += pgsz) {
errno_t status = pmap_map( errno_t status = pmap_map(
&kernel_vas.pmap, &kernel_vma.pmap,
(uintptr_t)p, (uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys), (phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ, PTE_READ,
@@ -94,10 +93,10 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
} }
// data // 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) { for (uint8_t* p = __ld_data_start; p < __ld_data_end; p += pgsz) {
errno_t status = pmap_map( errno_t status = pmap_map(
&kernel_vas.pmap, &kernel_vma.pmap,
(uintptr_t)p, (uintptr_t)p,
(phys_t)(p - __ld_kernel_start + kernel_phys), (phys_t)(p - __ld_kernel_start + kernel_phys),
PTE_READ | PTE_WRITE, 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) { for (size_t p = 0; p <= map[i].length; p += pgsz) {
uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm); uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm);
phys_t paddr = (phys_t)(map[i].address + p); 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); assert(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status);
} }
} }
mem_hhdm_base = tmp_hhdm; mem_hhdm_base = tmp_hhdm;
// Switch to our own page table. // 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. // 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. // 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 num_pages = (map[i].length + pgsz - 1) / pgsz;
const size_t metadata_size = num_pages * sizeof(struct page); 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; const uintptr_t metadata_end_vaddr = metadata_start_vaddr + metadata_size;
// Find the page-aligned boundaries that contain this metadata. // 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) { for (size_t page = 0; page < length; page += pgsz) {
phys_t paddr; phys_t paddr;
assert(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n"); 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. // We don't need the bootstrap allocator from this point on.
// Initialize the real page allocator. // 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(); slab_init();
kprintf("Memory initialization complete\n"); log("mem", "Memory initialization complete\n");
} }
+2 -2
View File
@@ -1,11 +1,11 @@
kernel_sources += files( kernel_sources += files(
'fault.c',
'init.c', 'init.c',
'mmio.c',
'pmap.c', 'pmap.c',
'pmm.c', 'pmm.c',
'slab.c', 'slab.c',
'usercopy.c', 'usercopy.c',
'virt.c', 'virt.c',
'vas.c', 'vma.c',
'vmo.c', 'vmo.c',
) )
+3 -3
View File
@@ -2,10 +2,10 @@
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/pmap.h> #include <zinnia/pmap.h>
#include <zinnia/spin.h> #include <zinnia/spin.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <string.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; flags &= ~ALLOC_NOZERO;
phys_t addr; phys_t addr;
@@ -30,7 +30,7 @@ errno_t pmap_new_user(struct pmap* pt, enum alloc_flags flags) {
return status; return status;
void* user_l1_ptr = HHDM_PTR(user_l1); 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()); memcpy(user_l1_ptr, kernel_l1_ptr, arch_mem_page_size());
struct pmap result = { struct pmap result = {
+2 -2
View File
@@ -1,9 +1,9 @@
#include <zinnia/alloc.h> #include <zinnia/alloc.h>
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
#include <zinnia/page.h>
#include <zinnia/panic.h> #include <zinnia/panic.h>
#include <zinnia/print.h> #include <zinnia/print.h>
#include <zinnia/spin.h> #include <zinnia/spin.h>
#include <zinnia/virt.h>
#include <stdint.h> #include <stdint.h>
#include <string.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()); 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/percpu.h>
#include <zinnia/usercopy.h> #include <zinnia/usercopy.h>
#include <arch/usercopy.h>
bool usercopy_read(void* dst, const __user void* src, size_t len) { 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); 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/alloc.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/virt.h> #include <zinnia/virt.h>
#include <stdatomic.h>
#include <stddef.h>
struct page* vm_pfndb = nullptr; struct page* vm_pfndb = nullptr;
@@ -10,14 +10,15 @@ struct page* vm_pfndb = nullptr;
static size_t mapping_offset = 0; 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(); 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 // TODO
} }
+14 -13
View File
@@ -1,19 +1,20 @@
#include <zinnia/alloc.h> #include <zinnia/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/mman.h> #include <zinnia/mman.h>
#include <zinnia/pmap.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <assert.h>
// Try to create a new, empty virtual address space. // 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"); debug_assert(out != nullptr, "Missing out");
errno_t res; errno_t res;
if (!out) if (!out)
return EINVAL; return EINVAL;
struct vas* vmspace = mem_alloc(sizeof(struct vas), 0); struct vma* vmspace = mem_alloc(sizeof(struct vma), 0);
if (!vmspace) if (!vmspace)
return ENOMEM; return ENOMEM;
@@ -31,24 +32,24 @@ err0:
} }
// Delete a virtual address space. // 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. // Remove any mappings in the given address range.
// May fail if there is no memory and a mapping needs to be split. // 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. // Change the protection of an existing mapping.
// May fail if there is no memory and a mapping needs to be split. // 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. // 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 // TODO
return false; return false;
} }
errno_t vma_map_vmo( errno_t vma_map(
struct vas* vas, struct vma* vma,
struct vmo* vmo, struct vmo* vmo,
uintptr_t addr, uintptr_t addr,
size_t len, 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; const size_t pages = ALIGN_UP(addr_offset + len, page_size) / page_size;
size_t end_page = start_page + pages; size_t end_page = start_page + pages;
if (!vas || !vmo) if (!vma || !vmo)
return EINVAL; return EINVAL;
const size_t first_vmo_page = vmo_offset / page_size; const size_t first_vmo_page = vmo_offset / page_size;
@@ -86,10 +87,10 @@ errno_t vma_map_vmo(
pf |= PTE_WRITE; pf |= PTE_WRITE;
if (flags & PROT_EXEC) if (flags & PROT_EXEC)
pf |= PTE_EXEC; pf |= PTE_EXEC;
if (vas->pmap.is_user) if (vma->pmap.is_user)
pf |= PTE_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) if (status != 0)
return status; return status;
} }
+1 -2
View File
@@ -1,10 +1,9 @@
#include <string.h>
#include <zinnia/alloc.h> #include <zinnia/alloc.h>
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/list.h> #include <zinnia/list.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/virt.h>
#include <zinnia/vmo.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) { 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(); const size_t page_size = arch_mem_page_size();
+4 -1
View File
@@ -10,4 +10,7 @@ kernel_sources += files(
'spin.c', '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 <zinnia/print.h>
#include <stdarg.h> #include <stdarg.h>
#define panic_log(msg, ...) kprintf("[ !!!! ] \e[31m" msg "\e[0m", ##__VA_ARGS__)
[[noreturn]] [[noreturn]]
void panic(const char* msg, ...) { void panic(const char* msg, ...) {
// TODO: Stop all other CPUs with IPI. // TODO: Stop all other CPUs with IPI.
arch_irq_set_state(false); irq_set_state(false);
struct percpu* cpu = percpu_get(); struct percpu* cpu = percpu_get();
struct task* current = cpu->sched.current; struct task* current = cpu->sched.current;
kprintf( kprintf(
"----[ Kernel panic ]----\n" "[ !!!! ] \e[31m"
"In task \"%s\" (TID %zu) on CPU %zu!\n", "Kernel panic on CPU %zu (T%zu, \"%s\"): ",
current ? current->name : nullptr, cpu->id,
current ? current->id : 0, current ? current->id : 0,
cpu->id current ? current->name : nullptr
); );
va_list args; va_list args;
@@ -24,9 +26,11 @@ void panic(const char* msg, ...) {
kvprintf(msg, args); kvprintf(msg, args);
va_end(args); va_end(args);
kprintf("----[ End of panic ]----\n"); kprintf("\e[0m");
panic_log("End of panic message\n");
while (1) { while (1) {
arch_irq_wait(); irq_wait();
} }
} }
+13
View File
@@ -1,5 +1,6 @@
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
#include <zinnia/percpu.h> #include <zinnia/percpu.h>
#include <arch/percpu.h>
[[__used, __section(".percpu")]] [[__used, __section(".percpu")]]
struct percpu percpu_bsp = { struct percpu percpu_bsp = {
@@ -12,3 +13,15 @@ struct percpu* percpu_new() {
// TODO // TODO
return nullptr; 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/alloc.h>
#include <zinnia/assert.h>
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/irq.h> #include <zinnia/irq.h>
#include <zinnia/list.h> #include <zinnia/list.h>
@@ -8,17 +9,15 @@
#include <zinnia/sched.h> #include <zinnia/sched.h>
#include <zinnia/spin.h> #include <zinnia/spin.h>
#include <zinnia/tailq.h> #include <zinnia/tailq.h>
#include <zinnia/vas.h> #include <zinnia/vma.h>
#include <assert.h>
#include <bits/irq.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
static void idle_func(uintptr_t) { static void idle_func(uintptr_t) {
while (1) { while (1) {
arch_irq_set_state(true); irq_set_state(true);
arch_irq_wait(); irq_wait();
} }
} }
@@ -37,13 +36,13 @@ void sched_to_user_context(uintptr_t ctx) {
void sched_init(struct sched_percpu* sched) { void sched_init(struct sched_percpu* sched) {
struct task* idle_task; 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->idle_task = idle_task;
sched->current = idle_task; sched->current = idle_task;
tailq_init(&sched->run_queue); 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) { 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); do_reschedule(sched);
} }
errno_t task_create( errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out) {
const char* name,
struct vas* space,
struct namespace* ns,
task_fn_t entry,
uintptr_t arg0,
struct task** out
) {
if (!out) if (!out)
return EINVAL; return EINVAL;
@@ -114,7 +106,6 @@ errno_t task_create(
static size_t last_tid = 0; static size_t last_tid = 0;
new_task->id = atomic_fetch_add(&last_tid, 1); new_task->id = atomic_fetch_add(&last_tid, 1);
new_task->space = space; new_task->space = space;
new_task->namespace = ns;
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.
@@ -1,6 +1,6 @@
#include <zinnia/archctl.h>
#include <zinnia/syscall.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); 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', 'archctl.c',
'dispatch.c', 'dispatch.c',
'futex.c', 'futex.c',
'getuname.c',
) )
View File
@@ -1,7 +1,11 @@
#include <zinnia/console.h>
#include <zinnia/init.h> #include <zinnia/init.h>
#include <zinnia/mmio.h> #include <zinnia/mmio.h>
#include <zinnia/pmap.h>
#include <zinnia/print.h> #include <zinnia/print.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <zinnia/virt.h>
#include <zinnia/vma.h>
#include <stdarg.h> #include <stdarg.h>
#include <uacpi/kernel_api.h> #include <uacpi/kernel_api.h>
#include <uacpi/status.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) { 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) { 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, ...) { void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char* msg, ...) {
console_write("uacpi: ", 7);
va_list args; va_list args;
va_start(args, msg); 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_level_bits();
size_t arch_mem_num_levels(); size_t arch_mem_num_levels();
uintptr_t arch_mem_hhdm_addr(); uintptr_t arch_mem_hhdm_addr();
uintptr_t arch_vm_pfndb_addr(); uintptr_t arch_mem_pfndb_addr();
uintptr_t arch_mem_mapping_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 #pragma once
#include <stddef.h>
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
#include <zinnia/usercopy.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_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_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); 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__ #ifdef __x86_64__
#define __ARCHCTL_SET_FSBASE 1 #define __ARCHCTL_SET_FSBASE 1
#define __ARCHCTL_SET_GSBASE 2 #define __ARCHCTL_SET_GSBASE 2
#define __ARCHCTL_GET_FSBASE 3
#define __ARCHCTL_GET_GSBASE 4
#endif #endif
#endif #endif
+3 -10
View File
@@ -1,8 +1,9 @@
#pragma once #pragma once
#include <bits/mem.h>
#include <stddef.h>
#include <zinnia/errno.h> #include <zinnia/errno.h>
#include <zinnia/types.h>
#include <arch/mem.h>
#include <stddef.h>
enum alloc_flags { enum alloc_flags {
ALLOC_NOZERO = 1 << 0, // Don't zero out the allocated memory. 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_bootstrap(struct phys_mem* mem);
void mem_phys_init(struct phys_mem* map, size_t length); 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() { static inline size_t mem_high_shift() {
return arch_mem_level_bits() * arch_mem_num_levels() + arch_mem_page_bits(); 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 #pragma once
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <zinnia/alloc.h>
#include <zinnia/errno.h>
// FNV-1a hash over raw bytes. // FNV-1a hash over raw bytes.
static inline uint64_t hashmap_hash_default(const void* key, size_t len) { 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). // Ensure a hash is never zero (zero is the empty sentinel).
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h)) #define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
#define HASHMAP(K, V) \ #define hashmap(K, V) \
struct { \ struct { \
K* keys; \ K* keys; \
V* values; \ V* values; \
@@ -34,7 +34,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
size_t count; \ size_t count; \
} }
#define HASHMAP_INIT(map) \ #define hashmap_init(map) \
do { \ do { \
(map)->keys = nullptr; \ (map)->keys = nullptr; \
(map)->values = 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; \ (map)->count = 0; \
} while (0) } while (0)
#define HASHMAP_DESTROY(map) \ #define hashmap_destroy(map) \
do { \ do { \
mem_free((map)->keys); \ mem_free((map)->keys); \
mem_free((map)->values); \ 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; \ (map)->count = 0; \
} while (0) } while (0)
#define HASHMAP_COUNT(map) ((map)->count) #define hashmap_count(map) ((map)->count)
// Internal: probe distance from ideal position. // Internal: probe distance from ideal position.
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1)) #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) } while (0)
// Insert or update a key-value pair. Returns 0 or ENOMEM. // Insert or update a key-value pair. Returns 0 or ZN_ERR_NO_MEMORY.
#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \ #define hashmap_insert(map, key, val, hash_fn, eq_fn) \
({ \ ({ \
errno_t _status = 0; \ zn_status_t _status = 0; \
typeof(*(map)->keys) _k = (key); \ typeof(*(map)->keys) _k = (key); \
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \ uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
/* Check for existing key first. */ \ /* 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) { \ if ((map)->count * 4 >= (map)->capacity * 3 || (map)->capacity == 0) { \
_HASHMAP_GROW(map, hash_fn, eq_fn); \ _HASHMAP_GROW(map, hash_fn, eq_fn); \
if ((map)->keys == nullptr || (map)->values == nullptr || (map)->hashes == nullptr) { \ if ((map)->keys == nullptr || (map)->values == nullptr || (map)->hashes == nullptr) { \
_status = ENOMEM; \ _status = ZN_ERR_NO_MEMORY; \
} \ } \
} \ } \
if (_status == 0) { \ 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. // 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; \ typeof(*(map)->values)* _result = nullptr; \
if ((map)->capacity > 0) { \ 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. // Remove a key. Returns true if the key was found and removed.
// Uses backward-shift deletion to avoid tombstones. // 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; \ bool _removed = false; \
if ((map)->capacity > 0) { \ 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. // Iterate over all occupied entries. `idx` is a size_t loop variable.
// Access keys and values via (map)->keys[idx] and (map)->values[idx]. // 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++) \ for (size_t idx = 0; idx < (map)->capacity; idx++) \
if ((map)->hashes[idx] != 0) if ((map)->hashes[idx] != 0)
+6 -2
View File
@@ -2,7 +2,6 @@
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
#include <zinnia/list.h> #include <zinnia/list.h>
#include <bits/irq.h>
#include <stdint.h> #include <stdint.h>
enum irq_status : uint8_t { 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_lock();
void irq_unlock(); void irq_unlock();
bool irq_set_interrupted(bool is_interrupted); 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 #pragma once
#include <zinnia/types.h> #include <stdint.h>
#include <stddef.h>
struct mmio_view { static inline uint8_t mmio_read8(void* ptr) {
volatile void* base; return *((volatile uint8_t*)ptr);
size_t len; }
};
#define _MMIO_REG(x) \ static inline uint16_t mmio_read16(void* ptr) {
typedef struct { \ return *((volatile uint16_t*)ptr);
size_t offset; \ }
bool swapped; \
} mmio_reg##x;
_MMIO_REG(8) static inline uint32_t mmio_read32(void* ptr) {
_MMIO_REG(16) return *((volatile uint32_t*)ptr);
_MMIO_REG(32) }
_MMIO_REG(64)
#define bswap_16(x) (uint16_t)x static inline uint64_t mmio_read64(void* ptr) {
#define bswap_32(x) (uint32_t)x return *((volatile uint64_t*)ptr);
#define bswap_64(x) (uint64_t)x }
#define mmio_load(_view, _reg) \ static inline void mmio_write8(void* ptr, uint8_t value) {
({ \ *((volatile uint8_t*)ptr) = value;
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; \
})
#define mmio_store(_view, _reg, _val) \ static inline void mmio_write16(void* ptr, uint16_t value) {
({ \ *((volatile uint16_t*)ptr) = value;
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; \
})
struct mmio_view mmio_new(phys_t addr, size_t length); static inline void mmio_write32(void* ptr, uint32_t value) {
void mmio_free(struct mmio_view* view); *((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 <bits/percpu.h>
#include <stddef.h> #include <stddef.h>
ASSERT_TYPE(struct arch_percpu); ASSERT_TYPE(struct arch_percpu); // bits/percpu.h
// CPU-relative information. // CPU-relative information.
struct percpu { struct percpu {
@@ -21,23 +21,10 @@ struct percpu {
struct sched_percpu sched; // Scheduler information. 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. // Per-CPU data for the bootstrap processor.
extern struct percpu percpu_bsp; 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/errno.h>
#include <zinnia/spin.h> #include <zinnia/spin.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <bits/mmu.h> #include <bits/pmap.h>
enum pte_flags : uint8_t { enum pte_flags : uint8_t {
PTE_READ = 1 << 0, // Can read from this page. PTE_READ = 1 << 0, // Can read from this page.
@@ -28,8 +28,8 @@ struct pmap {
bool is_user; bool is_user;
}; };
errno_t pmap_kernel(struct pmap* pt, enum alloc_flags flags); errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags);
errno_t pmap_user(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_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_protect(struct pmap* pt, uintptr_t vaddr, enum pte_flags flags);
errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr); errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr);
+9
View File
@@ -7,3 +7,12 @@
void kprintf(const char* message, ...); void kprintf(const char* message, ...);
void kvprintf(const char* message, va_list args); 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 { struct task {
size_t id; size_t id;
char name[TASK_NAME_MAX]; char name[TASK_NAME_MAX];
struct vas* space; struct vma* space;
struct namespace* namespace;
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;
@@ -59,14 +58,7 @@ void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq);
typedef void (*task_fn_t)(uintptr_t arg0); typedef void (*task_fn_t)(uintptr_t arg0);
errno_t task_create( errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out);
const char* name,
struct vas* space,
struct namespace* ns,
task_fn_t entry,
uintptr_t arg0,
struct task** out
);
[[noreturn]] [[noreturn]]
void task_entry(task_fn_t entry, uintptr_t arg0); void task_entry(task_fn_t entry, uintptr_t arg0);
+7 -14
View File
@@ -2,32 +2,25 @@
#include <zinnia/sched.h> #include <zinnia/sched.h>
enum syscall_kind : uint8_t { struct syscall_ret {
SYSKIND_CALL = 0, // Regular call, returns error and/or value.
SYSKIND_CONTEXT, // Consumes the entire register image.
};
struct syscall_return {
uintptr_t value; uintptr_t value;
int errno; int errno;
}; };
struct syscall { struct syscall {
union { void* func;
struct syscall_return (*call)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); int num_args;
void (*context)(struct arch_context*);
};
enum syscall_kind kind;
}; };
struct syscall_return syscall_dispatch_call( [[gnu::no_caller_saved_registers]]
size_t num, struct syscall_ret syscall_dispatch_fast(
uintptr_t a0, uintptr_t a0,
uintptr_t a1, uintptr_t a1,
uintptr_t a2, uintptr_t a2,
uintptr_t a3, uintptr_t a3,
uintptr_t a4, uintptr_t a4,
uintptr_t a5 uintptr_t a5,
size_t num
); );
void syscall_dispatch(struct arch_context* ctx); void syscall_dispatch(struct arch_context* ctx);
+146 -150
View File
@@ -2,155 +2,151 @@
#include <zinnia/sched.h> #include <zinnia/sched.h>
#include <zinnia/syscall.h> #include <zinnia/syscall.h>
#include <stdint.h>
#define __SYSCALL_CALL(name) \ #define SYSCALL_DECLARE(name) extern void sys_##name()
struct syscall_return sys_##name(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t)
#define __SYSCALL_CONTEXT(name) void sys_##name(struct arch_context*) SYSCALL_DECLARE(exit);
SYSCALL_DECLARE(syslog);
__SYSCALL_CALL(exit); SYSCALL_DECLARE(getuname);
__SYSCALL_CALL(syslog); SYSCALL_DECLARE(setuname);
__SYSCALL_CALL(getuname); SYSCALL_DECLARE(archctl);
__SYSCALL_CALL(setuname); SYSCALL_DECLARE(reboot);
__SYSCALL_CALL(archctl); SYSCALL_DECLARE(mmap);
__SYSCALL_CALL(reboot); SYSCALL_DECLARE(munmap);
__SYSCALL_CALL(mmap); SYSCALL_DECLARE(mprotect);
__SYSCALL_CALL(munmap); SYSCALL_DECLARE(madvise);
__SYSCALL_CALL(mprotect); SYSCALL_DECLARE(sigprocmask);
__SYSCALL_CALL(madvise); SYSCALL_DECLARE(sigsuspend);
__SYSCALL_CALL(sigprocmask); SYSCALL_DECLARE(sigpending);
__SYSCALL_CALL(sigsuspend); SYSCALL_DECLARE(sigaction);
__SYSCALL_CALL(sigpending); SYSCALL_DECLARE(sigtimedwait);
__SYSCALL_CALL(sigaction); SYSCALL_DECLARE(sigaltstack);
__SYSCALL_CALL(sigtimedwait); SYSCALL_DECLARE(sigreturn);
__SYSCALL_CALL(sigaltstack); SYSCALL_DECLARE(sigqueue);
__SYSCALL_CALL(sigreturn); SYSCALL_DECLARE(execve);
__SYSCALL_CALL(sigqueue); SYSCALL_DECLARE(fexecve);
__SYSCALL_CALL(execve); SYSCALL_DECLARE(fork);
__SYSCALL_CALL(fexecve); SYSCALL_DECLARE(kill);
__SYSCALL_CONTEXT(fork); SYSCALL_DECLARE(gettid);
__SYSCALL_CALL(kill); SYSCALL_DECLARE(getpid);
__SYSCALL_CALL(gettid); SYSCALL_DECLARE(getppid);
__SYSCALL_CALL(getpid); SYSCALL_DECLARE(waitid);
__SYSCALL_CALL(getppid); SYSCALL_DECLARE(waitpid);
__SYSCALL_CALL(waitid); SYSCALL_DECLARE(pread);
__SYSCALL_CALL(waitpid); SYSCALL_DECLARE(readv);
__SYSCALL_CALL(pread); SYSCALL_DECLARE(pwrite);
__SYSCALL_CALL(readv); SYSCALL_DECLARE(writev);
__SYSCALL_CALL(pwrite); SYSCALL_DECLARE(seek);
__SYSCALL_CALL(writev); SYSCALL_DECLARE(ioctl);
__SYSCALL_CALL(seek); SYSCALL_DECLARE(openat);
__SYSCALL_CALL(ioctl); SYSCALL_DECLARE(close);
__SYSCALL_CALL(openat); SYSCALL_DECLARE(fstat);
__SYSCALL_CALL(close); SYSCALL_DECLARE(fstatat);
__SYSCALL_CALL(fstat); SYSCALL_DECLARE(statvfs);
__SYSCALL_CALL(fstatat); SYSCALL_DECLARE(fstatvfs);
__SYSCALL_CALL(statvfs); SYSCALL_DECLARE(faccessat);
__SYSCALL_CALL(fstatvfs); SYSCALL_DECLARE(fcntl);
__SYSCALL_CALL(faccessat); SYSCALL_DECLARE(ftruncate);
__SYSCALL_CALL(fcntl); SYSCALL_DECLARE(truncate);
__SYSCALL_CALL(ftruncate); SYSCALL_DECLARE(fallocate);
__SYSCALL_CALL(truncate); SYSCALL_DECLARE(fadvise);
__SYSCALL_CALL(fallocate); SYSCALL_DECLARE(utimensat);
__SYSCALL_CALL(fadvise); SYSCALL_DECLARE(mknodat);
__SYSCALL_CALL(utimensat); SYSCALL_DECLARE(getcwd);
__SYSCALL_CALL(mknodat); SYSCALL_DECLARE(chdir);
__SYSCALL_CALL(getcwd); SYSCALL_DECLARE(fchdir);
__SYSCALL_CALL(chdir); SYSCALL_DECLARE(mkdirat);
__SYSCALL_CALL(fchdir); SYSCALL_DECLARE(rmdirat);
__SYSCALL_CALL(mkdirat); SYSCALL_DECLARE(getdents);
__SYSCALL_CALL(rmdirat); SYSCALL_DECLARE(renameat);
__SYSCALL_CALL(getdents); SYSCALL_DECLARE(fchmod);
__SYSCALL_CALL(renameat); SYSCALL_DECLARE(fchmodat);
__SYSCALL_CALL(fchmod); SYSCALL_DECLARE(fchownat);
__SYSCALL_CALL(fchmodat); SYSCALL_DECLARE(linkat);
__SYSCALL_CALL(fchownat); SYSCALL_DECLARE(symlinkat);
__SYSCALL_CALL(linkat); SYSCALL_DECLARE(unlinkat);
__SYSCALL_CALL(symlinkat); SYSCALL_DECLARE(readlinkat);
__SYSCALL_CALL(unlinkat); SYSCALL_DECLARE(flock);
__SYSCALL_CALL(readlinkat); SYSCALL_DECLARE(ppoll);
__SYSCALL_CALL(flock); SYSCALL_DECLARE(dup);
__SYSCALL_CALL(ppoll); SYSCALL_DECLARE(dup3);
__SYSCALL_CALL(dup); SYSCALL_DECLARE(sync);
__SYSCALL_CALL(dup3); SYSCALL_DECLARE(fsync);
__SYSCALL_CALL(sync); SYSCALL_DECLARE(fdatasync);
__SYSCALL_CALL(fsync); SYSCALL_DECLARE(getgroups);
__SYSCALL_CALL(fdatasync); SYSCALL_DECLARE(setgroups);
__SYSCALL_CALL(getgroups); SYSCALL_DECLARE(getsid);
__SYSCALL_CALL(setgroups); SYSCALL_DECLARE(setsid);
__SYSCALL_CALL(getsid); SYSCALL_DECLARE(setuid);
__SYSCALL_CALL(setsid); SYSCALL_DECLARE(getuid);
__SYSCALL_CALL(setuid); SYSCALL_DECLARE(setgid);
__SYSCALL_CALL(getuid); SYSCALL_DECLARE(getgid);
__SYSCALL_CALL(setgid); SYSCALL_DECLARE(geteuid);
__SYSCALL_CALL(getgid); SYSCALL_DECLARE(seteuid);
__SYSCALL_CALL(geteuid); SYSCALL_DECLARE(getegid);
__SYSCALL_CALL(seteuid); SYSCALL_DECLARE(setegid);
__SYSCALL_CALL(getegid); SYSCALL_DECLARE(getpgid);
__SYSCALL_CALL(setegid); SYSCALL_DECLARE(setpgid);
__SYSCALL_CALL(getpgid); SYSCALL_DECLARE(getresuid);
__SYSCALL_CALL(setpgid); SYSCALL_DECLARE(setresuid);
__SYSCALL_CALL(getresuid); SYSCALL_DECLARE(getresgid);
__SYSCALL_CALL(setresuid); SYSCALL_DECLARE(setresgid);
__SYSCALL_CALL(getresgid); SYSCALL_DECLARE(setreuid);
__SYSCALL_CALL(setresgid); SYSCALL_DECLARE(setregid);
__SYSCALL_CALL(setreuid); SYSCALL_DECLARE(umask);
__SYSCALL_CALL(setregid); SYSCALL_DECLARE(pipe);
__SYSCALL_CALL(umask); SYSCALL_DECLARE(futex_wait);
__SYSCALL_CALL(pipe); SYSCALL_DECLARE(futex_wake);
__SYSCALL_CALL(futex_wait); SYSCALL_DECLARE(thread_create);
__SYSCALL_CALL(futex_wake); SYSCALL_DECLARE(thread_kill);
__SYSCALL_CALL(thread_create); SYSCALL_DECLARE(thread_exit);
__SYSCALL_CALL(thread_kill); SYSCALL_DECLARE(thread_setname);
__SYSCALL_CALL(thread_exit); SYSCALL_DECLARE(thread_getname);
__SYSCALL_CALL(thread_setname); SYSCALL_DECLARE(timer_create);
__SYSCALL_CALL(thread_getname); SYSCALL_DECLARE(timer_set);
__SYSCALL_CALL(timer_create); SYSCALL_DECLARE(timer_get);
__SYSCALL_CALL(timer_set); SYSCALL_DECLARE(timer_getoverrun);
__SYSCALL_CALL(timer_get); SYSCALL_DECLARE(timer_delete);
__SYSCALL_CALL(timer_getoverrun); SYSCALL_DECLARE(itimer_get);
__SYSCALL_CALL(timer_delete); SYSCALL_DECLARE(itimer_set);
__SYSCALL_CALL(itimer_get); SYSCALL_DECLARE(clock_get);
__SYSCALL_CALL(itimer_set); SYSCALL_DECLARE(clock_getres);
__SYSCALL_CALL(clock_get); SYSCALL_DECLARE(clock_set);
__SYSCALL_CALL(clock_getres); SYSCALL_DECLARE(sleep);
__SYSCALL_CALL(clock_set); SYSCALL_DECLARE(yield);
__SYSCALL_CALL(sleep); SYSCALL_DECLARE(chroot);
__SYSCALL_CALL(yield); SYSCALL_DECLARE(mount);
__SYSCALL_CALL(chroot); SYSCALL_DECLARE(umount);
__SYSCALL_CALL(mount); SYSCALL_DECLARE(socket);
__SYSCALL_CALL(umount); SYSCALL_DECLARE(socketpair);
__SYSCALL_CALL(socket); SYSCALL_DECLARE(shutdown);
__SYSCALL_CALL(socketpair); SYSCALL_DECLARE(bind);
__SYSCALL_CALL(shutdown); SYSCALL_DECLARE(connect);
__SYSCALL_CALL(bind); SYSCALL_DECLARE(accept);
__SYSCALL_CALL(connect); SYSCALL_DECLARE(listen);
__SYSCALL_CALL(accept); SYSCALL_DECLARE(getpeername);
__SYSCALL_CALL(listen); SYSCALL_DECLARE(getsockname);
__SYSCALL_CALL(getpeername); SYSCALL_DECLARE(getsockopt);
__SYSCALL_CALL(getsockname); SYSCALL_DECLARE(setsockopt);
__SYSCALL_CALL(getsockopt); SYSCALL_DECLARE(sendmsg);
__SYSCALL_CALL(setsockopt); SYSCALL_DECLARE(recvmsg);
__SYSCALL_CALL(sendmsg); SYSCALL_DECLARE(getentropy);
__SYSCALL_CALL(recvmsg); SYSCALL_DECLARE(getrusage);
__SYSCALL_CALL(getentropy); SYSCALL_DECLARE(getrlimit);
__SYSCALL_CALL(getrusage); SYSCALL_DECLARE(setrlimit);
__SYSCALL_CALL(getrlimit); SYSCALL_DECLARE(getpriority);
__SYSCALL_CALL(setrlimit); SYSCALL_DECLARE(setpriority);
__SYSCALL_CALL(getpriority); SYSCALL_DECLARE(sched_getparam);
__SYSCALL_CALL(setpriority); SYSCALL_DECLARE(sched_setparam);
__SYSCALL_CALL(sched_getparam); SYSCALL_DECLARE(module_insert);
__SYSCALL_CALL(sched_setparam); SYSCALL_DECLARE(module_remove);
__SYSCALL_CALL(module_insert); SYSCALL_DECLARE(epoll_create);
__SYSCALL_CALL(module_remove); SYSCALL_DECLARE(epoll_ctl);
__SYSCALL_CALL(epoll_create); SYSCALL_DECLARE(epoll_pwait);
__SYSCALL_CALL(epoll_ctl); SYSCALL_DECLARE(timerfd_create);
__SYSCALL_CALL(epoll_pwait); SYSCALL_DECLARE(timerfd_gettime);
__SYSCALL_CALL(timerfd_create); SYSCALL_DECLARE(timerfd_settime);
__SYSCALL_CALL(timerfd_gettime); SYSCALL_DECLARE(signalfd_create);
__SYSCALL_CALL(timerfd_settime); SYSCALL_DECLARE(eventfd_create);
__SYSCALL_CALL(signalfd_create); SYSCALL_DECLARE(msync);
__SYSCALL_CALL(eventfd_create); SYSCALL_DECLARE(sysconf);
__SYSCALL_CALL(msync);
__SYSCALL_CALL(sysconf);
+2 -3
View File
@@ -1,8 +1,7 @@
#pragma once #pragma once
#include <bits/types.h>
#include <zinnia/utils.h> #include <zinnia/utils.h>
#include <bits/types.h>
ASSERT_TYPE(phys_t); ASSERT_TYPE(phys_t);
ASSERT_TYPE(uintptr_t); ASSERT_TYPE(virt_t);
ASSERT_TYPE(reg_t);
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <stddef.h>
#include <zinnia/compiler.h> #include <zinnia/compiler.h>
#include <stddef.h>
struct usercopy_region { struct usercopy_region {
void (*start_ip)(); 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 <stdint.h>
#include <uapi/fcntl.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 { enum open_flags : uint32_t {
O_RDONLY = __O_RDONLY, O_RDONLY = __O_RDONLY,
O_WRONLY = __O_WRONLY, O_WRONLY = __O_WRONLY,
@@ -62,3 +33,34 @@ enum open_flags : uint32_t {
O_SEARCH = __O_SEARCH, O_SEARCH = __O_SEARCH,
O_ACCMODE = __O_ACCMODE, 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 #pragma once
#include <zinnia/hashmap.h>
#include <zinnia/types.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.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(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!"); 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. // Base address of the `struct page` array.
extern struct page* vm_pfndb; extern struct page* vm_pfndb;
uintptr_t vm_page_addr(struct page* page); 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/errno.h>
#include <zinnia/list.h> #include <zinnia/list.h>
#include <zinnia/page.h>
#include <zinnia/spin.h> #include <zinnia/spin.h>
#include <zinnia/virt.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.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 = [] 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( configure_file(
configuration: cfg, configuration: cfg,
output: 'config.h', 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( executable(
'zinnia', 'zinnia',
include_directories: [ include_directories: [
@@ -121,5 +116,5 @@ executable(
kernel_sources, kernel_sources,
], ],
install: true, 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);
}