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