more stuff
This commit is contained in:
+2
-2
@@ -15,7 +15,7 @@ static bool use_hpet = true;
|
|||||||
static void hpet_option(bool use) {
|
static void hpet_option(bool use) {
|
||||||
use_hpet = use;
|
use_hpet = use;
|
||||||
}
|
}
|
||||||
CMDLINE_OPTION("hpet", hpet_option);
|
CMDLINE_OPTION("x86_64.hpet", "Enable High Precision Event Timer clock", hpet_option);
|
||||||
|
|
||||||
struct hpet {
|
struct hpet {
|
||||||
struct clock clock;
|
struct clock clock;
|
||||||
@@ -64,7 +64,7 @@ void hpet_init() {
|
|||||||
hpet_clock.regs = (void*)vaddr;
|
hpet_clock.regs = (void*)vaddr;
|
||||||
|
|
||||||
uacpi_table_unref(&table);
|
uacpi_table_unref(&table);
|
||||||
log("x86_64/hpet", "HPET registers mapped at %p\n", hpet_clock.regs);
|
log("x86_64/hpet: HPET registers mapped at %p\n", hpet_clock.regs);
|
||||||
|
|
||||||
mmio_write64(hpet_clock.regs + HPET_CFG, mmio_read64(hpet_clock.regs + HPET_CFG) | 1);
|
mmio_write64(hpet_clock.regs + HPET_CFG, mmio_read64(hpet_clock.regs + HPET_CFG) | 1);
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -5,6 +5,7 @@
|
|||||||
#include <zinnia/percpu.h>
|
#include <zinnia/percpu.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
|
#include <arch/sched.h>
|
||||||
#include <bits/sched.h>
|
#include <bits/sched.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -36,6 +37,7 @@ void interrupt_handler(struct arch_context* ctx) {
|
|||||||
bool old = irq_set_interrupted(true);
|
bool old = irq_set_interrupted(true);
|
||||||
|
|
||||||
uint64_t isr = ctx->isr;
|
uint64_t isr = ctx->isr;
|
||||||
|
|
||||||
switch (isr) {
|
switch (isr) {
|
||||||
case IDT_PF:
|
case IDT_PF:
|
||||||
uint64_t cr2;
|
uint64_t cr2;
|
||||||
@@ -48,13 +50,10 @@ void interrupt_handler(struct arch_context* ctx) {
|
|||||||
sched_reschedule(&cpu->sched);
|
sched_reschedule(&cpu->sched);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)):
|
default:
|
||||||
struct irq_line* line = cpu->arch.irq_lines[isr - 0x20];
|
struct irq_line* line = cpu->arch.irq_lines[isr - 0x20];
|
||||||
assert(line, "Unhandled interrupt on ISR %lu\n", isr);
|
assert(line, "Unhandled interrupt on ISR %lu\n", isr);
|
||||||
// TODO: irq_raise(line);
|
// TODO: irq_raise(line);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unhandled exception on ISR %lu\n", isr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_set_interrupted(old);
|
irq_set_interrupted(old);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <zinnia/pmap.h>
|
#include <zinnia/pmap.h>
|
||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
|
#include <arch/sched.h>
|
||||||
#include <bits/sched.h>
|
#include <bits/sched.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
+43
-13
@@ -1,17 +1,52 @@
|
|||||||
#include <zinnia/clock.h>
|
#include <zinnia/clock.h>
|
||||||
#include <zinnia/cmdline.h>
|
#include <zinnia/cmdline.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
|
#include <zinnia/utils.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <x86_64/asm.h>
|
#include <x86_64/asm.h>
|
||||||
#include <x86_64/defs.h>
|
#include <x86_64/defs.h>
|
||||||
|
|
||||||
static bool use_tsc = true;
|
static bool use_tsc = true;
|
||||||
|
static void tsc_option(bool opt) {
|
||||||
|
use_tsc = opt;
|
||||||
|
}
|
||||||
|
CMDLINE_OPTION("x86_64.tsc", "Enable timestamp counter", tsc_option);
|
||||||
|
|
||||||
|
constexpr uint64_t nanos_per_sec = 1'000'000'000;
|
||||||
|
static uint64_t tsc_freq = 0;
|
||||||
|
static uint64_t tsc_base_cycles = 0;
|
||||||
|
|
||||||
|
static uint64_t cycles_to_ns(uint64_t cycles, uint64_t freq) {
|
||||||
|
uint64_t seconds = cycles / freq;
|
||||||
|
uint64_t remaining_cycles = cycles % freq;
|
||||||
|
uint64_t fractional_ns = (uint64_t)((__uint128_t)remaining_cycles * (__uint128_t)nanos_per_sec / (__uint128_t)freq);
|
||||||
|
uint64_t ns = seconds * nanos_per_sec + fractional_ns;
|
||||||
|
|
||||||
|
return MIN(ns, UINT64_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tsc_reset(struct clock* clock) {
|
||||||
|
tsc_base_cycles = asm_rdtsc();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t tsc_get_elapsed_ns(struct clock* clock) {
|
||||||
|
uint64_t cycles = asm_rdtsc() - tsc_base_cycles;
|
||||||
|
return cycles_to_ns(cycles, tsc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clock tsc_clock = {
|
||||||
|
.name = "tsc",
|
||||||
|
.priority = 255,
|
||||||
|
.reset = tsc_reset,
|
||||||
|
.get_elapsed_ns = tsc_get_elapsed_ns,
|
||||||
|
};
|
||||||
|
|
||||||
void tsc_init() {
|
void tsc_init() {
|
||||||
if (!use_tsc)
|
if (!use_tsc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) {
|
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) {
|
||||||
log("x86_64/tsc", "No invariant TSC detected!\n");
|
log("x86_64/tsc: No invariant TSC detected!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,33 +57,28 @@ void tsc_init() {
|
|||||||
tsc_leaf = asm_cpuid(0x15, 0);
|
tsc_leaf = asm_cpuid(0x15, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t freq = 0;
|
|
||||||
if (clock_available()) {
|
if (clock_available()) {
|
||||||
// Calibrate using existing clock.
|
// Calibrate using existing clock.
|
||||||
uint64_t t1 = asm_rdtsc();
|
uint64_t t1 = asm_rdtsc();
|
||||||
clock_spin_ns(10'000'000);
|
clock_spin_ns(10'000'000);
|
||||||
uint64_t t2 = asm_rdtsc();
|
uint64_t t2 = asm_rdtsc();
|
||||||
freq = (t2 - t1) * 100;
|
tsc_freq = (t2 - t1) * 100;
|
||||||
} else if (has_tsc_leaf) {
|
} else if (has_tsc_leaf) {
|
||||||
// If we have no timer (yet), the only way we can calibrate the TSC is if CPUID gives us the frequency.
|
// If we have no timer (yet), the only way we can calibrate the TSC is if CPUID gives us the frequency.
|
||||||
// On a normal system, this should usually never be called and is a last resort
|
// On a normal system, this should usually never be called and is a last resort
|
||||||
// since at this point we have at least the HPET timer.
|
// since at this point we have at least the HPET timer.
|
||||||
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) {
|
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) {
|
||||||
log("x86_64/tsc", "Calibrating TSC using CPUID 0x15");
|
log("x86_64/tsc: Calibrating TSC using CPUID 0x15");
|
||||||
freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
|
tsc_freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
|
||||||
} else {
|
} else {
|
||||||
log("x86_64/tsc", "Unable to calibrate TSC using CPUID frequency information");
|
log("x86_64/tsc: Unable to calibrate TSC using CPUID frequency information");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log("x86_64/tsc", "Unable to calibrate the TSC without a clock or static frequency info!\n");
|
log("x86_64/tsc: Unable to calibrate the TSC without a clock or static frequency info!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("x86_64/tsc", "Timer frequency is %lu MHz\n", freq / 1'000'000);
|
log("x86_64/tsc: Timer frequency is %lu MHz\n", tsc_freq / 1'000'000);
|
||||||
|
clock_switch(&tsc_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsc_option(bool opt) {
|
|
||||||
use_tsc = opt;
|
|
||||||
}
|
|
||||||
CMDLINE_OPTION("x86_64.tsc", tsc_option);
|
|
||||||
|
|||||||
+10
-6
@@ -23,13 +23,15 @@ SECTIONS
|
|||||||
__ld_text_end = .;
|
__ld_text_end = .;
|
||||||
} :text
|
} :text
|
||||||
|
|
||||||
.rodata ALIGN(CONSTANT(MAXPAGESIZE)) : {
|
.cmdline ALIGN(CONSTANT(MAXPAGESIZE)) : {
|
||||||
__ld_rodata_start = .;
|
__ld_rodata_start = .;
|
||||||
|
|
||||||
__ld_cmdline_start = .;
|
__ld_cmdline_start = .;
|
||||||
KEEP(*(.cmdline))
|
KEEP(*(.cmdline))
|
||||||
__ld_cmdline_end = .;
|
__ld_cmdline_end = .;
|
||||||
|
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
*(.got .got.*)
|
*(.got .got.*)
|
||||||
|
|
||||||
@@ -39,15 +41,17 @@ SECTIONS
|
|||||||
.data ALIGN(CONSTANT(MAXPAGESIZE)) : {
|
.data ALIGN(CONSTANT(MAXPAGESIZE)) : {
|
||||||
__ld_data_start = .;
|
__ld_data_start = .;
|
||||||
|
|
||||||
__ld_console_start = .;
|
|
||||||
KEEP(*(.console))
|
|
||||||
__ld_console_end = .;
|
|
||||||
|
|
||||||
KEEP(*(SORT_BY_NAME(.init.data.*)))
|
KEEP(*(SORT_BY_NAME(.init.data.*)))
|
||||||
KEEP(*(.init.data))
|
KEEP(*(.init.data))
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
|
.console : {
|
||||||
|
__ld_console_start = .;
|
||||||
|
KEEP(*(.console))
|
||||||
|
__ld_console_end = .;
|
||||||
|
} :data
|
||||||
|
|
||||||
.dynsym : {
|
.dynsym : {
|
||||||
__ld_dynsym_start = .;
|
__ld_dynsym_start = .;
|
||||||
*(.dynsym)
|
*(.dynsym)
|
||||||
|
|||||||
+6
-8
@@ -5,7 +5,6 @@
|
|||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
#include <zinnia/console.h>
|
#include <zinnia/console.h>
|
||||||
#include <zinnia/elf.h>
|
#include <zinnia/elf.h>
|
||||||
#include <zinnia/futex.h>
|
|
||||||
#include <zinnia/init.h>
|
#include <zinnia/init.h>
|
||||||
#include <zinnia/irq.h>
|
#include <zinnia/irq.h>
|
||||||
#include <zinnia/percpu.h>
|
#include <zinnia/percpu.h>
|
||||||
@@ -22,7 +21,7 @@ static const char zinnia_banner[] = "Zinnia " ZINNIA_VERSION " " CONFIG_KERNEL_F
|
|||||||
static void kernel_main_task(uintptr_t arg0) {
|
static void kernel_main_task(uintptr_t arg0) {
|
||||||
struct boot_info* info = (struct boot_info*)arg0;
|
struct boot_info* info = (struct boot_info*)arg0;
|
||||||
|
|
||||||
log("main", "Hello from main task!\n");
|
log("main: Hello from main task!\n");
|
||||||
|
|
||||||
assert(info->num_files >= 1, "No init executable provided\n");
|
assert(info->num_files >= 1, "No init executable provided\n");
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ static void kernel_main_task(uintptr_t arg0) {
|
|||||||
assert(vmo_new_phys(&init_file) == EOK, "");
|
assert(vmo_new_phys(&init_file) == EOK, "");
|
||||||
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
||||||
|
|
||||||
log("main", "%s:%i\n", __FUNCTION__, __LINE__);
|
log("main: %s:%i\n", __FUNCTION__, __LINE__);
|
||||||
|
|
||||||
// Load init.
|
// Load init.
|
||||||
const char* init_argv[] = {"init", nullptr};
|
const char* init_argv[] = {"init", nullptr};
|
||||||
@@ -50,7 +49,7 @@ static void kernel_main_task(uintptr_t arg0) {
|
|||||||
assert(status == 0, "Failed to load init process (%i)\n", status);
|
assert(status == 0, "Failed to load init process (%i)\n", status);
|
||||||
sched_add_task(&percpu_get()->sched, init_task);
|
sched_add_task(&percpu_get()->sched, init_task);
|
||||||
|
|
||||||
log("main", "%s:%i\n", __FUNCTION__, __LINE__);
|
log("main: %s:%i\n", __FUNCTION__, __LINE__);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
irq_wait();
|
irq_wait();
|
||||||
@@ -66,19 +65,18 @@ void kernel_early_init() {
|
|||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void kernel_main(struct boot_info* info) {
|
void kernel_main(struct boot_info* info) {
|
||||||
// TODO: Initialize log ring.
|
// TODO: Initialize in-memory log ring.
|
||||||
kprintf("%s\n", zinnia_banner); // Say hello!
|
kprintf("%s\n", zinnia_banner); // Say hello!
|
||||||
|
kprintf("Command line: %s\n", info->cmdline);
|
||||||
|
|
||||||
cmdline_parse(info->cmdline);
|
cmdline_parse(info->cmdline);
|
||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
kprintf("\ec");
|
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);
|
mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base);
|
||||||
rsdp_addr = info->rsdp; // TODO
|
rsdp_addr = info->rsdp; // TODO
|
||||||
percpu_init();
|
percpu_init();
|
||||||
sched_init(&percpu_get()->sched);
|
sched_init(&percpu_get()->sched);
|
||||||
futex_init();
|
|
||||||
|
|
||||||
struct task* main_task;
|
struct task* main_task;
|
||||||
task_create("main", &kernel_vma, kernel_main_task, (uintptr_t)info, &main_task);
|
task_create("main", &kernel_vma, kernel_main_task, (uintptr_t)info, &main_task);
|
||||||
|
|||||||
+6
-6
@@ -1,24 +1,24 @@
|
|||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/clock.h>
|
#include <zinnia/clock.h>
|
||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
#include <stdatomic.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
static struct clock* active_clock = nullptr;
|
static struct clock* active_clock = nullptr;
|
||||||
static uint64_t counter_base = 0;
|
static uint64_t counter_base = 0;
|
||||||
static spinlock_t lock = {};
|
static struct spinlock lock = {};
|
||||||
|
|
||||||
bool clock_available() {
|
bool clock_available() {
|
||||||
return active_clock != nullptr;
|
return active_clock != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t clock_get_elapsed_ns() {
|
uint64_t clock_get_elapsed_ns() {
|
||||||
struct clock* active = atomic_load(&active_clock);
|
struct clock* active = atomic_load(&active_clock, ATOMIC_RELAXED);
|
||||||
if (__unlikely(!active))
|
if (__unlikely(!active))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return atomic_load(&counter_base) + active->get_elapsed_ns(active);
|
return atomic_load(&counter_base, ATOMIC_RELAXED) + active->get_elapsed_ns(active);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool clock_switch(struct clock* clock) {
|
bool clock_switch(struct clock* clock) {
|
||||||
@@ -31,7 +31,7 @@ bool clock_switch(struct clock* clock) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log("clock", "Switching to clock source \"%s\"\n", clock->name);
|
log("clock: Switching to clock source \"%s\"\n", clock->name);
|
||||||
|
|
||||||
uint64_t elapsed = clock_get_elapsed_ns();
|
uint64_t elapsed = clock_get_elapsed_ns();
|
||||||
counter_base += elapsed;
|
counter_base += elapsed;
|
||||||
@@ -43,7 +43,7 @@ bool clock_switch(struct clock* clock) {
|
|||||||
|
|
||||||
void clock_spin_ns(uint64_t ns) {
|
void clock_spin_ns(uint64_t ns) {
|
||||||
if (active_clock == nullptr) {
|
if (active_clock == nullptr) {
|
||||||
log("clock", "Unable to sleep for %lu ns, no clock available!\n", ns);
|
log("clock: Unable to sleep for %lu ns, no clock available!\n", ns);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -27,7 +27,7 @@ static void console_setup(const char* value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CMDLINE_OPTION("console", console_setup);
|
CMDLINE_OPTION("console", "Set a default console", console_setup);
|
||||||
|
|
||||||
void console_init() {
|
void console_init() {
|
||||||
// If we have no console set and at least one set, use that as a default.
|
// If we have no console set and at least one set, use that as a default.
|
||||||
@@ -38,6 +38,6 @@ void console_init() {
|
|||||||
if (active->init(active) == false)
|
if (active->init(active) == false)
|
||||||
active = nullptr;
|
active = nullptr;
|
||||||
|
|
||||||
log("console", "Logging on console \"%s\"\n", active->name);
|
log("console: Logging on console \"%s\"\n", active->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-120
@@ -1,120 +0,0 @@
|
|||||||
#include <zinnia/errno.h>
|
|
||||||
#include <zinnia/futex.h>
|
|
||||||
#include <zinnia/percpu.h>
|
|
||||||
#include <zinnia/print.h>
|
|
||||||
#include <zinnia/sched.h>
|
|
||||||
#include <zinnia/spin.h>
|
|
||||||
#include <zinnia/usercopy.h>
|
|
||||||
|
|
||||||
struct futex_bucket {
|
|
||||||
struct wait_queue wq;
|
|
||||||
uintptr_t key; // Virtual address used as the futex key.
|
|
||||||
bool in_use;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FUTEX_BUCKET_COUNT 64
|
|
||||||
|
|
||||||
static struct futex_bucket futex_table[FUTEX_BUCKET_COUNT];
|
|
||||||
static spinlock_t futex_table_lock;
|
|
||||||
|
|
||||||
void futex_init(void) {
|
|
||||||
futex_table_lock = (spinlock_t){0};
|
|
||||||
for (size_t i = 0; i < FUTEX_BUCKET_COUNT; i++) {
|
|
||||||
wait_queue_init(&futex_table[i].wq);
|
|
||||||
futex_table[i].key = 0;
|
|
||||||
futex_table[i].in_use = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t futex_hash(uintptr_t addr) {
|
|
||||||
// Simple hash: mix the address bits and mod by bucket count.
|
|
||||||
addr = (addr >> 2) ^ (addr >> 12);
|
|
||||||
return addr % FUTEX_BUCKET_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct futex_bucket* futex_bucket_get(uintptr_t addr) {
|
|
||||||
size_t idx = futex_hash(addr);
|
|
||||||
// Linear probing to find a matching or free bucket.
|
|
||||||
for (size_t i = 0; i < FUTEX_BUCKET_COUNT; i++) {
|
|
||||||
size_t slot = (idx + i) % FUTEX_BUCKET_COUNT;
|
|
||||||
struct futex_bucket* b = &futex_table[slot];
|
|
||||||
if (b->in_use && b->key == addr)
|
|
||||||
return b;
|
|
||||||
if (!b->in_use) {
|
|
||||||
b->key = addr;
|
|
||||||
b->in_use = true;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno_t futex_wait(__user int* addr, int expected) {
|
|
||||||
uintptr_t key = (uintptr_t)addr;
|
|
||||||
|
|
||||||
spin_lock(&futex_table_lock);
|
|
||||||
|
|
||||||
// Read the current value at the userspace address.
|
|
||||||
int current;
|
|
||||||
if (!usercopy_read(¤t, addr, sizeof(*addr))) {
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
return EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the value has already changed, don't block.
|
|
||||||
if (current != expected) {
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct futex_bucket* bucket = futex_bucket_get(key);
|
|
||||||
if (!bucket) {
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
|
|
||||||
// Block on the bucket's wait queue.
|
|
||||||
struct sched_percpu* sched = &percpu_get()->sched;
|
|
||||||
sched_block(sched, &bucket->wq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno_t futex_wake(__user int* addr, int count) {
|
|
||||||
uintptr_t key = (uintptr_t)addr;
|
|
||||||
|
|
||||||
spin_lock(&futex_table_lock);
|
|
||||||
|
|
||||||
size_t idx = futex_hash(key);
|
|
||||||
struct futex_bucket* bucket = nullptr;
|
|
||||||
for (size_t i = 0; i < FUTEX_BUCKET_COUNT; i++) {
|
|
||||||
size_t slot = (idx + i) % FUTEX_BUCKET_COUNT;
|
|
||||||
struct futex_bucket* b = &futex_table[slot];
|
|
||||||
if (b->in_use && b->key == key) {
|
|
||||||
bucket = b;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!b->in_use)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bucket) {
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
return 0; // No waiters, nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&futex_table_lock);
|
|
||||||
|
|
||||||
struct sched_percpu* sched = &percpu_get()->sched;
|
|
||||||
if (count == INT32_MAX) {
|
|
||||||
sched_wake_all(sched, &bucket->wq);
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
sched_wake(sched, &bucket->wq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/irq.h>
|
#include <zinnia/irq.h>
|
||||||
#include <zinnia/percpu.h>
|
#include <zinnia/percpu.h>
|
||||||
#include <arch/irq.h>
|
#include <arch/irq.h>
|
||||||
#include <stdatomic.h>
|
|
||||||
|
|
||||||
void irq_set_state(bool state) {
|
void irq_set_state(bool state) {
|
||||||
arch_irq_set_state(state);
|
arch_irq_set_state(state);
|
||||||
@@ -17,19 +17,19 @@ void irq_wait() {
|
|||||||
|
|
||||||
void irq_lock() {
|
void irq_lock() {
|
||||||
struct irq_percpu* cpu = &percpu_get()->irq;
|
struct irq_percpu* cpu = &percpu_get()->irq;
|
||||||
if (atomic_load_explicit(&cpu->in_interrupt, memory_order_acquire))
|
if (atomic_load(&cpu->in_interrupt, ATOMIC_ACQUIRE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
arch_irq_set_state(false);
|
arch_irq_set_state(false);
|
||||||
atomic_fetch_add_explicit(&percpu_get()->irq.level, 1, memory_order_acq_rel);
|
atomic_fetch_add(&percpu_get()->irq.level, 1, ATOMIC_ACQ_REL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_unlock() {
|
void irq_unlock() {
|
||||||
struct irq_percpu* cpu = &percpu_get()->irq;
|
struct irq_percpu* cpu = &percpu_get()->irq;
|
||||||
if (atomic_load_explicit(&cpu->in_interrupt, memory_order_acquire))
|
if (atomic_load(&cpu->in_interrupt, ATOMIC_ACQUIRE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t old_level = atomic_fetch_sub_explicit(&cpu->level, 1, memory_order_acq_rel);
|
uint32_t old_level = atomic_fetch_sub(&cpu->level, 1, ATOMIC_ACQ_REL);
|
||||||
// If it was 1, the new IRQ level is now 0.
|
// If it was 1, the new IRQ level is now 0.
|
||||||
if (old_level == 1) {
|
if (old_level == 1) {
|
||||||
arch_irq_set_state(true);
|
arch_irq_set_state(true);
|
||||||
@@ -37,5 +37,5 @@ void irq_unlock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool irq_set_interrupted(bool is_interrupted) {
|
bool irq_set_interrupted(bool is_interrupted) {
|
||||||
return atomic_exchange_explicit(&percpu_get()->irq.in_interrupt, is_interrupted, memory_order_release);
|
return atomic_exchange(&percpu_get()->irq.in_interrupt, is_interrupted, ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Freestanding libc functions that are needed in the kernel
|
# Freestanding libc functions that are needed in the kernel
|
||||||
|
|
||||||
kernel_sources += files(
|
kernel_sources += files(
|
||||||
|
'stdlib.c',
|
||||||
'string.c',
|
'string.c',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void reverse(char* s) {
|
||||||
|
int i, j;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
|
||||||
|
c = s[i];
|
||||||
|
s[i] = s[j];
|
||||||
|
s[j] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int char_to_digit(char c) {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long atolu(const char* str, int base) {
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
if (base == 16 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
||||||
|
str += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
int digit = char_to_digit(*str++);
|
||||||
|
if (digit < 0 || digit >= base)
|
||||||
|
break;
|
||||||
|
|
||||||
|
result = result * base + digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
long atol(const char* str, int base) {
|
||||||
|
int neg = 0;
|
||||||
|
|
||||||
|
if (*str == '-') {
|
||||||
|
neg = 1;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long val = atolu(str, base);
|
||||||
|
return neg ? -(long)val : (long)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* lutoa(uint64_t value, char* str, int base) {
|
||||||
|
if (base < 2 || base > 36)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint64_t digit = value % base;
|
||||||
|
str[i++] = (digit < 10) ? '0' + digit : 'a' + (digit - 10);
|
||||||
|
value /= base;
|
||||||
|
} while (value);
|
||||||
|
|
||||||
|
str[i] = '\0';
|
||||||
|
reverse(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ltoa(int64_t value, char* str, int base) {
|
||||||
|
if (base < 2 || base > 36)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
uint64_t magnitude;
|
||||||
|
int negative = 0;
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
negative = 1;
|
||||||
|
magnitude = (uint64_t)(-(value + 1)) + 1;
|
||||||
|
// avoids INT64_MIN overflow
|
||||||
|
} else {
|
||||||
|
magnitude = (uint64_t)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint64_t digit = magnitude % base;
|
||||||
|
str[i++] = (digit < 10) ? '0' + digit : 'a' + (digit - 10);
|
||||||
|
magnitude /= base;
|
||||||
|
} while (magnitude);
|
||||||
|
|
||||||
|
if (negative)
|
||||||
|
str[i++] = '-';
|
||||||
|
|
||||||
|
str[i] = '\0';
|
||||||
|
reverse(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
+7
-8
@@ -23,7 +23,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
|
|
||||||
const size_t pgsz = arch_mem_page_size();
|
const size_t pgsz = arch_mem_page_size();
|
||||||
|
|
||||||
log("mem", "Memory map:\n");
|
log("mem: Memory map:\n");
|
||||||
for (size_t i = 0; i < map_len; i++) {
|
for (size_t i = 0; i < map_len; i++) {
|
||||||
if (map[i].length == 0)
|
if (map[i].length == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -44,7 +44,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("mem", "[%p - %p] %s\n", (void*)map[i].address, (void*)(map[i].address + map[i].length - 1), label);
|
log("mem: [%p - %p] %s\n", (void*)map[i].address, (void*)(map[i].address + map[i].length - 1), label);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the bootstrap allocator.
|
// Set up the bootstrap allocator.
|
||||||
@@ -54,8 +54,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
largest = &map[i];
|
largest = &map[i];
|
||||||
}
|
}
|
||||||
mem_phys_bootstrap(largest);
|
mem_phys_bootstrap(largest);
|
||||||
log("mem",
|
log("mem: Using region [%p - %p] for bootstrap allocator\n",
|
||||||
"Using region [%p - %p] for bootstrap allocator\n",
|
|
||||||
(void*)largest->address,
|
(void*)largest->address,
|
||||||
(void*)(largest->address + largest->length - 1));
|
(void*)(largest->address + largest->length - 1));
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
assert(pmap_new_kernel(&kernel_vma.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
|
assert(pmap_new_kernel(&kernel_vma.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
|
||||||
|
|
||||||
// text
|
// text
|
||||||
log("mem", "Mapping text segment at %p\n", __ld_text_start);
|
log("mem: Mapping text segment at %p\n", __ld_text_start);
|
||||||
for (uint8_t* p = __ld_text_start; p <= __ld_text_end; p += pgsz) {
|
for (uint8_t* p = __ld_text_start; p <= __ld_text_end; p += pgsz) {
|
||||||
errno_t status = pmap_map(
|
errno_t status = pmap_map(
|
||||||
&kernel_vma.pmap,
|
&kernel_vma.pmap,
|
||||||
@@ -80,7 +79,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rodata
|
// rodata
|
||||||
log("mem", "Mapping rodata segment at %p\n", __ld_rodata_start);
|
log("mem: Mapping rodata segment at %p\n", __ld_rodata_start);
|
||||||
for (uint8_t* p = __ld_rodata_start; p < __ld_rodata_end; p += pgsz) {
|
for (uint8_t* p = __ld_rodata_start; p < __ld_rodata_end; p += pgsz) {
|
||||||
errno_t status = pmap_map(
|
errno_t status = pmap_map(
|
||||||
&kernel_vma.pmap,
|
&kernel_vma.pmap,
|
||||||
@@ -93,7 +92,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// data
|
// data
|
||||||
log("mem", "Mapping data segment at %p\n", __ld_data_start);
|
log("mem: Mapping data segment at %p\n", __ld_data_start);
|
||||||
for (uint8_t* p = __ld_data_start; p < __ld_data_end; p += pgsz) {
|
for (uint8_t* p = __ld_data_start; p < __ld_data_end; p += pgsz) {
|
||||||
errno_t status = pmap_map(
|
errno_t status = pmap_map(
|
||||||
&kernel_vma.pmap,
|
&kernel_vma.pmap,
|
||||||
@@ -161,5 +160,5 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
|
|
||||||
slab_init();
|
slab_init();
|
||||||
|
|
||||||
log("mem", "Memory initialization complete\n");
|
log("mem: Memory initialization complete\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags) {
|
|||||||
|
|
||||||
struct pmap result = {
|
struct pmap result = {
|
||||||
.root = addr,
|
.root = addr,
|
||||||
.lock = (spinlock_t){0},
|
.lock = (struct spinlock){0},
|
||||||
.is_user = false,
|
.is_user = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ errno_t pmap_new_user(struct pmap* pt, enum alloc_flags flags) {
|
|||||||
|
|
||||||
struct pmap result = {
|
struct pmap result = {
|
||||||
.root = user_l1,
|
.root = user_l1,
|
||||||
.lock = (spinlock_t){0},
|
.lock = (struct spinlock){0},
|
||||||
.is_user = true,
|
.is_user = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -56,7 +56,7 @@ void mem_phys_bootstrap(struct phys_mem* mem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct page* pmm_head = nullptr;
|
static struct page* pmm_head = nullptr;
|
||||||
static spinlock_t pmm_lock = {0};
|
static struct spinlock pmm_lock = {0};
|
||||||
static size_t pmm_total_free = 0;
|
static size_t pmm_total_free = 0;
|
||||||
|
|
||||||
static errno_t freelist_alloc(size_t num_pages, enum alloc_flags flags, phys_t* out) {
|
static errno_t freelist_alloc(size_t num_pages, enum alloc_flags flags, phys_t* out) {
|
||||||
@@ -84,11 +84,10 @@ static errno_t freelist_alloc(size_t num_pages, enum alloc_flags flags, phys_t*
|
|||||||
|
|
||||||
// If the current block has exactly enough pages left, consume it entirely.
|
// If the current block has exactly enough pages left, consume it entirely.
|
||||||
if (__unlikely(it->freelist.count == num_pages)) {
|
if (__unlikely(it->freelist.count == num_pages)) {
|
||||||
if (prev_it) {
|
if (prev_it)
|
||||||
prev_it->freelist.next = it->freelist.next;
|
prev_it->freelist.next = it->freelist.next;
|
||||||
} else {
|
else
|
||||||
pmm_head = it->freelist.next;
|
pmm_head = it->freelist.next;
|
||||||
}
|
|
||||||
|
|
||||||
it->freelist.next = nullptr;
|
it->freelist.next = nullptr;
|
||||||
it->freelist.count = 0;
|
it->freelist.count = 0;
|
||||||
@@ -150,5 +149,5 @@ void mem_phys_init(struct phys_mem* map, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const size_t free_bytes = (pmm_total_free * arch_mem_page_size());
|
const size_t free_bytes = (pmm_total_free * arch_mem_page_size());
|
||||||
log("pmm", "Total available memory: %zu MiB\n", free_bytes / 1024 / 1024);
|
log("pmm: Total available memory: %zu MiB\n", free_bytes / 1024 / 1024);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ typedef struct {
|
|||||||
} slab_info;
|
} slab_info;
|
||||||
|
|
||||||
struct slab {
|
struct slab {
|
||||||
spinlock_t lock; // Access lock.
|
struct spinlock lock; // Access lock.
|
||||||
size_t ent_size; // Size of one entry.
|
size_t ent_size; // Size of one entry.
|
||||||
void** head;
|
void** head;
|
||||||
};
|
};
|
||||||
@@ -24,7 +24,7 @@ typedef struct {
|
|||||||
static struct slab slabs[8] = {0};
|
static struct slab slabs[8] = {0};
|
||||||
|
|
||||||
static errno_t slab_new(struct slab* slab, size_t size) {
|
static errno_t slab_new(struct slab* slab, size_t size) {
|
||||||
slab->lock = (spinlock_t){0};
|
slab->lock = (struct spinlock){0};
|
||||||
|
|
||||||
// Allocate a new page for the head.
|
// Allocate a new page for the head.
|
||||||
phys_t addr;
|
phys_t addr;
|
||||||
|
|||||||
+2
-3
@@ -1,7 +1,7 @@
|
|||||||
#include <zinnia/alloc.h>
|
#include <zinnia/alloc.h>
|
||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <zinnia/virt.h>
|
#include <zinnia/virt.h>
|
||||||
#include <stdatomic.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct page* vm_pfndb = nullptr;
|
struct page* vm_pfndb = nullptr;
|
||||||
@@ -12,8 +12,7 @@ static size_t mapping_offset = 0;
|
|||||||
|
|
||||||
uintptr_t vm_alloc(size_t length) {
|
uintptr_t vm_alloc(size_t length) {
|
||||||
uintptr_t base = arch_mem_mapping_addr();
|
uintptr_t base = arch_mem_mapping_addr();
|
||||||
size_t offset =
|
size_t offset = atomic_fetch_add(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()), ATOMIC_ACQUIRE);
|
||||||
atomic_fetch_add_explicit(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()), memory_order_acquire);
|
|
||||||
|
|
||||||
return base + offset;
|
return base + offset;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -2,12 +2,12 @@ kernel_sources += files(
|
|||||||
'clock.c',
|
'clock.c',
|
||||||
'console.c',
|
'console.c',
|
||||||
'elf.c',
|
'elf.c',
|
||||||
'futex.c',
|
|
||||||
'irq.c',
|
'irq.c',
|
||||||
'panic.c',
|
'panic.c',
|
||||||
'percpu.c',
|
'percpu.c',
|
||||||
'print.c',
|
'print.c',
|
||||||
'spin.c',
|
'spin.c',
|
||||||
|
'wait.c',
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('lib')
|
subdir('lib')
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
#include <zinnia/percpu.h>
|
#include <zinnia/percpu.h>
|
||||||
#include <arch/percpu.h>
|
#include <arch/percpu.h>
|
||||||
|
|
||||||
[[__used, __section(".percpu")]]
|
[[__percpu]]
|
||||||
struct percpu percpu_bsp = {
|
struct percpu percpu_bsp = {
|
||||||
.self = &percpu_bsp,
|
.self = &percpu_bsp,
|
||||||
.id = 0,
|
.id = 0,
|
||||||
|
|||||||
+1
-99
@@ -5,107 +5,9 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void reverse(char* s) {
|
|
||||||
int i, j;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
|
|
||||||
c = s[i];
|
|
||||||
s[i] = s[j];
|
|
||||||
s[j] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int char_to_digit(char c) {
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
return c - '0';
|
|
||||||
if (c >= 'a' && c <= 'z')
|
|
||||||
return c - 'a' + 10;
|
|
||||||
if (c >= 'A' && c <= 'Z')
|
|
||||||
return c - 'A' + 10;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long atolu(const char* str, int base) {
|
|
||||||
unsigned long result = 0;
|
|
||||||
|
|
||||||
if (base == 16 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
|
||||||
str += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*str) {
|
|
||||||
int digit = char_to_digit(*str++);
|
|
||||||
if (digit < 0 || digit >= base)
|
|
||||||
break;
|
|
||||||
|
|
||||||
result = result * base + digit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
long atol(const char* str, int base) {
|
|
||||||
int neg = 0;
|
|
||||||
|
|
||||||
if (*str == '-') {
|
|
||||||
neg = 1;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long val = atolu(str, base);
|
|
||||||
return neg ? -(long)val : (long)val;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* lutoa(uint64_t value, char* str, int base) {
|
|
||||||
if (base < 2 || base > 36)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
uint64_t digit = value % base;
|
|
||||||
str[i++] = (digit < 10) ? '0' + digit : 'a' + (digit - 10);
|
|
||||||
value /= base;
|
|
||||||
} while (value);
|
|
||||||
|
|
||||||
str[i] = '\0';
|
|
||||||
reverse(str);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ltoa(int64_t value, char* str, int base) {
|
|
||||||
if (base < 2 || base > 36)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
uint64_t magnitude;
|
|
||||||
int negative = 0;
|
|
||||||
|
|
||||||
if (value < 0) {
|
|
||||||
negative = 1;
|
|
||||||
magnitude = (uint64_t)(-(value + 1)) + 1;
|
|
||||||
// avoids INT64_MIN overflow
|
|
||||||
} else {
|
|
||||||
magnitude = (uint64_t)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
uint64_t digit = magnitude % base;
|
|
||||||
str[i++] = (digit < 10) ? '0' + digit : 'a' + (digit - 10);
|
|
||||||
magnitude /= base;
|
|
||||||
} while (magnitude);
|
|
||||||
|
|
||||||
if (negative)
|
|
||||||
str[i++] = '-';
|
|
||||||
|
|
||||||
str[i] = '\0';
|
|
||||||
reverse(str);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*log_fn_t)(void* ctx, const char* buf, size_t len);
|
typedef void (*log_fn_t)(void* ctx, const char* buf, size_t len);
|
||||||
|
|
||||||
static void do_print(log_fn_t callback, void* ctx, const char* restrict fmt, va_list args) {
|
static void do_print(log_fn_t callback, void* ctx, const char* restrict fmt, va_list args) {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <zinnia/sched.h>
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
kernel_sources += files(
|
kernel_sources += files(
|
||||||
|
'core.c',
|
||||||
'sched_dumb.c',
|
'sched_dumb.c',
|
||||||
)
|
)
|
||||||
|
|||||||
+15
-56
@@ -1,5 +1,6 @@
|
|||||||
#include <zinnia/alloc.h>
|
#include <zinnia/alloc.h>
|
||||||
#include <zinnia/assert.h>
|
#include <zinnia/assert.h>
|
||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/irq.h>
|
#include <zinnia/irq.h>
|
||||||
#include <zinnia/list.h>
|
#include <zinnia/list.h>
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
#include <zinnia/tailq.h>
|
#include <zinnia/tailq.h>
|
||||||
#include <zinnia/vma.h>
|
#include <zinnia/vma.h>
|
||||||
#include <stdatomic.h>
|
#include <arch/sched.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ void sched_to_user_context(uintptr_t ctx) {
|
|||||||
arch_sched_jump_to_context((struct arch_context*)ctx);
|
arch_sched_jump_to_context((struct arch_context*)ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_init(struct sched_percpu* sched) {
|
void sched_init(struct scheduler* sched) {
|
||||||
struct task* idle_task;
|
struct task* idle_task;
|
||||||
assert(task_create("idle", &kernel_vma, idle_func, 0, &idle_task) == 0, "Unable to create idle task!\n");
|
assert(task_create("idle", &kernel_vma, idle_func, 0, &idle_task) == 0, "Unable to create idle task!\n");
|
||||||
sched->idle_task = idle_task;
|
sched->idle_task = idle_task;
|
||||||
@@ -42,15 +43,15 @@ void sched_init(struct sched_percpu* sched) {
|
|||||||
|
|
||||||
tailq_init(&sched->run_queue);
|
tailq_init(&sched->run_queue);
|
||||||
|
|
||||||
log("sched", "Scheduler initialized\n");
|
log("sched: Scheduler initialized\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_add_task(struct sched_percpu* sched, struct task* task) {
|
void sched_add_task(struct scheduler* sched, struct task* task) {
|
||||||
assert(task != nullptr, "Tried to add NULL to the run queue\n");
|
assert(task != nullptr, "Tried to add NULL to the run queue\n");
|
||||||
tailq_insert_tail(&sched->run_queue, task, next);
|
tailq_insert_tail(&sched->run_queue, task, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct task* next_task(struct sched_percpu* sched) {
|
static struct task* next_task(struct scheduler* sched) {
|
||||||
struct task* t = tailq_first(&sched->run_queue);
|
struct task* t = tailq_first(&sched->run_queue);
|
||||||
|
|
||||||
if (t == nullptr)
|
if (t == nullptr)
|
||||||
@@ -61,17 +62,17 @@ static struct task* next_task(struct sched_percpu* sched) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_reschedule(struct sched_percpu* sched) {
|
static void do_reschedule(struct scheduler* sched) {
|
||||||
struct task* from = atomic_load_explicit(&sched->current, memory_order_acquire);
|
struct task* from = sched->current;
|
||||||
struct task* to = next_task(sched);
|
struct task* to = next_task(sched);
|
||||||
|
|
||||||
|
// We'd end up on the same task, skip switching altogether.
|
||||||
if (from == to) {
|
if (from == to) {
|
||||||
irq_unlock();
|
irq_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store_explicit(&sched->current, to, memory_order_relaxed);
|
sched->current = to;
|
||||||
|
|
||||||
pmap_set(&to->space->pmap);
|
pmap_set(&to->space->pmap);
|
||||||
|
|
||||||
struct percpu* cpu = percpu_get();
|
struct percpu* cpu = percpu_get();
|
||||||
@@ -80,17 +81,17 @@ static void do_reschedule(struct sched_percpu* sched) {
|
|||||||
cpu->kernel_stack = to->kernel_stack;
|
cpu->kernel_stack = to->kernel_stack;
|
||||||
cpu->user_stack = to->user_stack;
|
cpu->user_stack = to->user_stack;
|
||||||
|
|
||||||
arch_sched_switch(from, to);
|
struct task* old = arch_sched_switch(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_reschedule(struct sched_percpu* sched) {
|
void sched_reschedule(struct scheduler* sched) {
|
||||||
irq_lock();
|
irq_lock();
|
||||||
if (sched->current->state != TASK_STATE_DEAD)
|
if (sched->current->state != TASK_STATE_DEAD)
|
||||||
sched_add_task(sched, sched->current);
|
sched_add_task(sched, sched->current);
|
||||||
do_reschedule(sched);
|
do_reschedule(sched);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_yield(struct sched_percpu* sched) {
|
void sched_yield(struct scheduler* sched) {
|
||||||
irq_lock();
|
irq_lock();
|
||||||
do_reschedule(sched);
|
do_reschedule(sched);
|
||||||
}
|
}
|
||||||
@@ -104,7 +105,7 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt
|
|||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
static size_t last_tid = 0;
|
static size_t last_tid = 0;
|
||||||
new_task->id = atomic_fetch_add(&last_tid, 1);
|
new_task->id = atomic_fetch_add(&last_tid, 1, ATOMIC_ACQUIRE);
|
||||||
new_task->space = space;
|
new_task->space = space;
|
||||||
strncpy(new_task->name, name, sizeof(new_task->name));
|
strncpy(new_task->name, name, sizeof(new_task->name));
|
||||||
|
|
||||||
@@ -126,50 +127,8 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt
|
|||||||
void task_entry(task_fn_t entry, uintptr_t arg0) {
|
void task_entry(task_fn_t entry, uintptr_t arg0) {
|
||||||
entry(arg0);
|
entry(arg0);
|
||||||
|
|
||||||
struct sched_percpu* sched = &percpu_get()->sched;
|
struct scheduler* sched = &percpu_get()->sched;
|
||||||
sched->current->state = TASK_STATE_DEAD;
|
sched->current->state = TASK_STATE_DEAD;
|
||||||
sched_yield(sched);
|
sched_yield(sched);
|
||||||
panic("unreachable");
|
panic("unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_queue_init(struct wait_queue* wq) {
|
|
||||||
tailq_init(&wq->waiters);
|
|
||||||
wq->lock = (spinlock_t){0};
|
|
||||||
}
|
|
||||||
|
|
||||||
void sched_block(struct sched_percpu* sched, struct wait_queue* wq) {
|
|
||||||
irq_lock();
|
|
||||||
spin_lock(&wq->lock);
|
|
||||||
|
|
||||||
sched->current->state = TASK_STATE_BLOCKED;
|
|
||||||
tailq_insert_tail(&wq->waiters, sched->current, next);
|
|
||||||
|
|
||||||
spin_unlock(&wq->lock);
|
|
||||||
do_reschedule(sched);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sched_wake(struct sched_percpu* sched, struct wait_queue* wq) {
|
|
||||||
spin_lock(&wq->lock);
|
|
||||||
|
|
||||||
struct task* t = tailq_first(&wq->waiters);
|
|
||||||
if (t != nullptr) {
|
|
||||||
tailq_remove(&wq->waiters, t, next);
|
|
||||||
t->state = TASK_STATE_READY;
|
|
||||||
sched_add_task(sched, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&wq->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq) {
|
|
||||||
spin_lock(&wq->lock);
|
|
||||||
|
|
||||||
struct task* t;
|
|
||||||
while ((t = tailq_first(&wq->waiters)) != nullptr) {
|
|
||||||
tailq_remove(&wq->waiters, t, next);
|
|
||||||
t->state = TASK_STATE_READY;
|
|
||||||
sched_add_task(sched, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&wq->lock);
|
|
||||||
}
|
|
||||||
|
|||||||
+7
-7
@@ -1,15 +1,15 @@
|
|||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/spin.h>
|
#include <zinnia/spin.h>
|
||||||
#include <stdatomic.h>
|
|
||||||
|
|
||||||
void spin_lock(spinlock_t* spin) {
|
void spin_lock(struct spinlock* spin) {
|
||||||
uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed);
|
uint32_t my = atomic_fetch_add(&spin->next, 1, ATOMIC_RELAXED);
|
||||||
|
|
||||||
while (atomic_load_explicit(&spin->owner, memory_order_acquire) != my) {
|
while (atomic_load(&spin->owner, ATOMIC_ACQUIRE) != my) {
|
||||||
asm volatile("pause");
|
asm volatile("pause");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spin_unlock(spinlock_t* spin) {
|
void spin_unlock(struct spinlock* spin) {
|
||||||
uint32_t val = atomic_load_explicit(&spin->owner, memory_order_relaxed);
|
uint32_t val = atomic_load(&spin->owner, ATOMIC_RELAXED);
|
||||||
atomic_store_explicit(&spin->owner, val + 1, memory_order_release);
|
atomic_store(&spin->owner, val + 1, ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-146
@@ -3,157 +3,18 @@
|
|||||||
#include <zinnia/print.h>
|
#include <zinnia/print.h>
|
||||||
#include <zinnia/sched.h>
|
#include <zinnia/sched.h>
|
||||||
#include <zinnia/syscall.h>
|
#include <zinnia/syscall.h>
|
||||||
#include <zinnia/syscall_list.h>
|
|
||||||
#include <zinnia/types.h>
|
#include <zinnia/types.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <bits/sched.h>
|
#include <bits/sched.h>
|
||||||
|
|
||||||
|
// Declare all syscalls.
|
||||||
|
#include <zinnia/syscall_list.inc>
|
||||||
|
#undef SYSCALL_DECLARE
|
||||||
|
|
||||||
|
// Define them.
|
||||||
const struct syscall syscall_table[256] = {
|
const struct syscall syscall_table[256] = {
|
||||||
// [0] = {sys_exit, 0},
|
#define SYSCALL_DECLARE(number, name, num_args) [number] = {sys_##name, num_args},
|
||||||
// [1] = {sys_syslog, 0},
|
#include <zinnia/syscall_list.inc>
|
||||||
[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]]
|
[[gnu::no_caller_saved_registers]]
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
#include <zinnia/errno.h>
|
|
||||||
#include <zinnia/futex.h>
|
|
||||||
#include <zinnia/syscall.h>
|
|
||||||
|
|
||||||
errno_t syscall_futex_wait(struct arch_context* ctx) {
|
|
||||||
__user int* addr = (__user int*)ctx->ARCH_CTX_A0;
|
|
||||||
int expected = (int)ctx->ARCH_CTX_A1;
|
|
||||||
|
|
||||||
return futex_wait(addr, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
errno_t syscall_futex_wake(struct arch_context* ctx) {
|
|
||||||
__user int* addr = (__user int*)ctx->ARCH_CTX_A0;
|
|
||||||
int count = (int)ctx->ARCH_CTX_A1;
|
|
||||||
|
|
||||||
return futex_wake(addr, count);
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <uapi/utsname.h>
|
#include <uapi/utsname.h>
|
||||||
|
|
||||||
static spinlock_t uname_lock = {};
|
static struct spinlock uname_lock = {};
|
||||||
|
|
||||||
static struct utsname uname_buf = {
|
static struct utsname uname_buf = {
|
||||||
.sysname = "Zinnia",
|
.sysname = "Zinnia",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
kernel_sources += files(
|
kernel_sources += files(
|
||||||
'archctl.c',
|
'archctl.c',
|
||||||
'dispatch.c',
|
'dispatch.c',
|
||||||
'futex.c',
|
|
||||||
'getuname.c',
|
'getuname.c',
|
||||||
)
|
)
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#include <zinnia/waitq.h>
|
||||||
|
|
||||||
|
void waitq_init(struct waitq* wq) {
|
||||||
|
tailq_init(&wq->waiters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitq_wait(struct waitq* wq) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitq_wake_one(struct waitq* wq) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitq_wake_all(struct waitq* wq) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ void uacpi_kernel_unmap(void* addr, uacpi_size len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char* msg, ...) {
|
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char* msg, ...) {
|
||||||
console_write("uacpi: ", 7);
|
log("acpi: ");
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
typedef enum memory_order {
|
|
||||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
|
||||||
memory_order_consume = __ATOMIC_CONSUME,
|
|
||||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
|
||||||
memory_order_release = __ATOMIC_RELEASE,
|
|
||||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
|
||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
|
||||||
} memory_order;
|
|
||||||
|
|
||||||
#define atomic_store_explicit(ptr, des, ord) __atomic_store_n(ptr, des, ord)
|
|
||||||
#define atomic_store(ptr, des) atomic_store_explicit(ptr, des, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_load_explicit(ptr, ord) __atomic_load_n(ptr, ord)
|
|
||||||
#define atomic_load(ptr) atomic_load_explicit(ptr, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_exchange_explicit(ptr, des, ord) __atomic_exchange_n(ptr, des, ord)
|
|
||||||
#define atomic_exchange(ptr, des) atomic_exchange_explicit(ptr, des, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_add_explicit(ptr, op, ord) __atomic_fetch_add(ptr, op, ord)
|
|
||||||
#define atomic_fetch_add(ptr, op) atomic_fetch_add_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_sub_explicit(ptr, op, ord) __atomic_fetch_sub(ptr, op, ord)
|
|
||||||
#define atomic_fetch_sub(ptr, op) atomic_fetch_sub_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_or_explicit(ptr, op, ord) __atomic_fetch_or(ptr, op, ord)
|
|
||||||
#define atomic_fetch_or(ptr, op) atomic_fetch_or_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_xor_explicit(ptr, op, ord) __atomic_fetch_xor(ptr, op, ord)
|
|
||||||
#define atomic_fetch_xor(ptr, op) atomic_fetch_xor_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_and_explicit(ptr, op, ord) __atomic_fetch_and(ptr, op, ord)
|
|
||||||
#define atomic_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_thread_fence(ord) __atomic_thread_fence(ord)
|
|
||||||
+6
-2
@@ -1,4 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
long atol(const char* str, int base);
|
#include <stdint.h>
|
||||||
unsigned long atolu(const char* str, int base);
|
|
||||||
|
int64_t atol(const char* str, int base);
|
||||||
|
uint64_t atolu(const char* str, int base);
|
||||||
|
char* lutoa(uint64_t value, char* str, int base);
|
||||||
|
char* ltoa(int64_t value, char* str, int base);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ union __epoll_data {
|
|||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct epoll_event {
|
struct __epoll_event {
|
||||||
uint32_t events;
|
uint32_t events;
|
||||||
union __epoll_data data;
|
union __epoll_data data;
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-13
@@ -33,19 +33,19 @@
|
|||||||
#define __S_IEXEC __S_IXUSR
|
#define __S_IEXEC __S_IXUSR
|
||||||
|
|
||||||
struct __stat {
|
struct __stat {
|
||||||
dev_t st_dev;
|
__dev_t st_dev;
|
||||||
ino_t st_ino;
|
__ino_t st_ino;
|
||||||
mode_t st_mode;
|
__mode_t st_mode;
|
||||||
nlink_t st_nlink;
|
__nlink_t st_nlink;
|
||||||
uid_t st_uid;
|
__uid_t st_uid;
|
||||||
gid_t st_gid;
|
__gid_t st_gid;
|
||||||
dev_t st_rdev;
|
__dev_t st_rdev;
|
||||||
off_t st_size;
|
__off_t st_size;
|
||||||
struct timespec st_atim;
|
struct __timespec st_atim;
|
||||||
struct timespec st_mtim;
|
struct __timespec st_mtim;
|
||||||
struct timespec st_ctim;
|
struct __timespec st_ctim;
|
||||||
blksize_t st_blksize;
|
__blksize_t st_blksize;
|
||||||
blkcnt_t st_blocks;
|
__blkcnt_t st_blocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+11
-11
@@ -4,27 +4,27 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int64_t time_t;
|
typedef int64_t __time_t;
|
||||||
typedef int64_t suseconds_t;
|
typedef int64_t __suseconds_t;
|
||||||
|
|
||||||
struct timespec {
|
struct __timespec {
|
||||||
time_t tv_sec;
|
__time_t tv_sec;
|
||||||
int64_t tv_nsec;
|
int64_t tv_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct timeval {
|
struct __timeval {
|
||||||
time_t tv_sec;
|
__time_t tv_sec;
|
||||||
suseconds_t tv_usec;
|
__suseconds_t tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct itimerval {
|
struct itimerval {
|
||||||
struct timeval it_interval;
|
struct __timeval it_interval;
|
||||||
struct timeval it_value;
|
struct __timeval it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct itimerspec {
|
struct itimerspec {
|
||||||
struct timespec it_interval;
|
struct __timespec it_interval;
|
||||||
struct timespec it_value;
|
struct __timespec it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define __ITIMER_REAL 0
|
#define __ITIMER_REAL 0
|
||||||
|
|||||||
+16
-16
@@ -4,21 +4,21 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int64_t off_t;
|
typedef int64_t __off_t;
|
||||||
typedef off_t off64_t;
|
typedef __off_t __off64_t;
|
||||||
typedef uintptr_t blksize_t;
|
typedef uintptr_t __blksize_t;
|
||||||
typedef uintptr_t blkcnt_t;
|
typedef uintptr_t __blkcnt_t;
|
||||||
typedef uintptr_t clockid_t;
|
typedef uintptr_t __clockid_t;
|
||||||
typedef uintptr_t dev_t;
|
typedef uintptr_t __dev_t;
|
||||||
typedef uint32_t gid_t;
|
typedef uint32_t __gid_t;
|
||||||
typedef uintptr_t ino_t;
|
typedef uintptr_t __ino_t;
|
||||||
typedef uint32_t mode_t;
|
typedef uint32_t __mode_t;
|
||||||
typedef uintptr_t nlink_t;
|
typedef uintptr_t __nlink_t;
|
||||||
typedef int32_t pid_t;
|
typedef int32_t __pid_t;
|
||||||
typedef uintptr_t rlim_t;
|
typedef uintptr_t __rlim_t;
|
||||||
typedef uint32_t uid_t;
|
typedef uint32_t __uid_t;
|
||||||
typedef uintptr_t fsblkcnt_t;
|
typedef uintptr_t __fsblkcnt_t;
|
||||||
typedef uintptr_t fsfilcnt_t;
|
typedef uintptr_t __fsfilcnt_t;
|
||||||
typedef uintptr_t pthread_attr_t;
|
typedef uintptr_t __pthread_attr_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum memory_order {
|
||||||
|
ATOMIC_RELAXED = __ATOMIC_RELAXED,
|
||||||
|
ATOMIC_CONSUME = __ATOMIC_CONSUME,
|
||||||
|
ATOMIC_ACQUIRE = __ATOMIC_ACQUIRE,
|
||||||
|
ATOMIC_RELEASE = __ATOMIC_RELEASE,
|
||||||
|
ATOMIC_ACQ_REL = __ATOMIC_ACQ_REL,
|
||||||
|
ATOMIC_SEQ_CST = __ATOMIC_SEQ_CST
|
||||||
|
} memory_order;
|
||||||
|
|
||||||
|
#define atomic(T) _Atomic(T)
|
||||||
|
|
||||||
|
#define atomic_store(ptr, des, order) __atomic_store_n(ptr, des, order)
|
||||||
|
|
||||||
|
#define atomic_load(ptr, order) __atomic_load_n(ptr, order)
|
||||||
|
|
||||||
|
#define atomic_exchange(ptr, des, order) __atomic_exchange_n(ptr, des, order)
|
||||||
|
|
||||||
|
#define atomic_fetch_add(ptr, op, order) __atomic_fetch_add(ptr, op, order)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(ptr, op, order) __atomic_fetch_sub(ptr, op, order)
|
||||||
|
|
||||||
|
#define atomic_fetch_or(ptr, op, order) __atomic_fetch_or(ptr, op, order)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor(ptr, op, order) __atomic_fetch_xor(ptr, op, order)
|
||||||
|
|
||||||
|
#define atomic_fetch_and(ptr, op, order) __atomic_fetch_and(ptr, op, order)
|
||||||
|
|
||||||
|
#define atomic_thread_fence(order) __atomic_thread_fence(order)
|
||||||
@@ -1 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define _CMDLINE_OPTION(x, opt_name, opt_func) \
|
#define _CMDLINE_OPTION(x, opt_name, opt_desc, opt_func, opt_limit) \
|
||||||
static const struct cmdline_option x = { \
|
static const struct cmdline_option x = { \
|
||||||
.name = opt_name, \
|
.name = opt_name, \
|
||||||
|
.desc = opt_desc, \
|
||||||
.option_type = _Generic( \
|
.option_type = _Generic( \
|
||||||
(opt_func), \
|
(opt_func), \
|
||||||
void (*)(const char*): CMDLINE_STRING, \
|
void (*)(const char*): CMDLINE_STRING, \
|
||||||
@@ -15,11 +16,23 @@
|
|||||||
void (*)(uintptr_t): CMDLINE_UINTPTR \
|
void (*)(uintptr_t): CMDLINE_UINTPTR \
|
||||||
), \
|
), \
|
||||||
.func = (void*)(opt_func), \
|
.func = (void*)(opt_func), \
|
||||||
|
.limit = (void*)(opt_limit) \
|
||||||
}; \
|
}; \
|
||||||
|
static_assert(_Generic( \
|
||||||
|
(opt_limit), \
|
||||||
|
const char**: true, \
|
||||||
|
const struct cmdline_option_limit_int*: true, \
|
||||||
|
const struct cmdline_option_limit_uint*: true, \
|
||||||
|
void*: true \
|
||||||
|
)); \
|
||||||
[[__used, __section(".cmdline")]] \
|
[[__used, __section(".cmdline")]] \
|
||||||
static const struct cmdline_option* CONCAT(x, _ptr) = &x;
|
static const struct cmdline_option* CONCAT(x, _ptr) = &x
|
||||||
|
|
||||||
#define CMDLINE_OPTION(opt_name, opt_func) _CMDLINE_OPTION(UNIQUE_IDENT(cmdline_option), opt_name, opt_func)
|
#define CMDLINE_OPTION(opt_name, opt_desc, opt_func) \
|
||||||
|
_CMDLINE_OPTION(UNIQUE_IDENT(cmdline_option), opt_name, opt_desc, opt_func, (void*)nullptr)
|
||||||
|
|
||||||
|
#define CMDLINE_OPTION_RANGE(opt_name, opt_desc, opt_func, opt_values) \
|
||||||
|
_CMDLINE_OPTION(UNIQUE_IDENT(cmdline_option), opt_name, opt_desc, opt_func, opt_values)
|
||||||
|
|
||||||
enum cmdline_type {
|
enum cmdline_type {
|
||||||
CMDLINE_STRING,
|
CMDLINE_STRING,
|
||||||
@@ -28,9 +41,12 @@ enum cmdline_type {
|
|||||||
CMDLINE_UINTPTR,
|
CMDLINE_UINTPTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Describes a command line option.
|
||||||
|
// NOTE: Changing the layout of this struct requires changes in util scripts.
|
||||||
struct cmdline_option {
|
struct cmdline_option {
|
||||||
// The name of this option.
|
|
||||||
const char* name;
|
const char* name;
|
||||||
|
const char* desc;
|
||||||
|
enum cmdline_type option_type;
|
||||||
// Gets called if this option is present on the command line.
|
// Gets called if this option is present on the command line.
|
||||||
union {
|
union {
|
||||||
void (*func_str)(const char* value);
|
void (*func_str)(const char* value);
|
||||||
@@ -39,8 +55,28 @@ struct cmdline_option {
|
|||||||
void (*func_uintptr)(uintptr_t value);
|
void (*func_uintptr)(uintptr_t value);
|
||||||
void* func;
|
void* func;
|
||||||
};
|
};
|
||||||
enum cmdline_type option_type;
|
union {
|
||||||
|
const char** str_limit;
|
||||||
|
struct cmdline_option_limit_int {
|
||||||
|
intptr_t min, max;
|
||||||
|
}* intptr_limit;
|
||||||
|
struct cmdline_option_limit_uint {
|
||||||
|
uintptr_t min, max;
|
||||||
|
}* uintptr_limit;
|
||||||
|
void* limit;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parses the command line and invokes all options.
|
// Parses the command line and invokes all options.
|
||||||
void cmdline_parse(const char* cmdline);
|
void cmdline_parse(const char* cmdline);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
0 ==
|
||||||
|
_Generic(
|
||||||
|
(cmdline_parse),
|
||||||
|
void (*)(const char*): CMDLINE_STRING,
|
||||||
|
void (*)(bool): CMDLINE_BOOL,
|
||||||
|
void (*)(intptr_t): CMDLINE_INTPTR,
|
||||||
|
void (*)(uintptr_t): CMDLINE_UINTPTR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <zinnia/compiler.h>
|
#include <zinnia/compiler.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
struct console {
|
struct console {
|
||||||
const char* name;
|
const char* name;
|
||||||
void* private;
|
|
||||||
|
|
||||||
// Initializes the console.
|
// Initializes the console.
|
||||||
bool (*init)(struct console* con);
|
bool (*init)(struct console* con);
|
||||||
// Writes to the console.
|
// Writes to the console.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <uapi/errno.h>
|
#include <uapi/errno.h>
|
||||||
|
|
||||||
typedef enum : int32_t {
|
typedef enum : int32_t {
|
||||||
EOK = 0, // Not really an error.
|
EOK = 0, // Success! Not really an error though...
|
||||||
EPERM = __EPERM,
|
EPERM = __EPERM,
|
||||||
ENOENT = __ENOENT,
|
ENOENT = __ENOENT,
|
||||||
ESRCH = __ESRCH,
|
ESRCH = __ESRCH,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct file_desc {};
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <zinnia/compiler.h>
|
|
||||||
#include <zinnia/errno.h>
|
|
||||||
#include <zinnia/wait.h>
|
|
||||||
|
|
||||||
struct futex {};
|
|
||||||
|
|
||||||
// Initializes the global futex table.
|
|
||||||
void futex_init(void);
|
|
||||||
|
|
||||||
// Blocks the calling task if *addr == expected.
|
|
||||||
errno_t futex_wait(__user int* addr, int expected);
|
|
||||||
|
|
||||||
// Wakes up to `count` tasks waiting on the given address.
|
|
||||||
// Returns the number of tasks woken.
|
|
||||||
errno_t futex_wake(__user int* addr, int count);
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct ident {
|
||||||
|
// TODO
|
||||||
|
};
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
ASSERT_TYPE(struct arch_percpu); // bits/percpu.h
|
ASSERT_TYPE(struct arch_percpu); // bits/percpu.h
|
||||||
|
|
||||||
|
#define __percpu __used, __section(".percpu")
|
||||||
|
|
||||||
// CPU-relative information.
|
// CPU-relative information.
|
||||||
struct percpu {
|
struct percpu {
|
||||||
struct percpu* self; // A pointer to this structure.
|
struct percpu* self; // A pointer to this structure.
|
||||||
@@ -18,7 +20,7 @@ struct percpu {
|
|||||||
uintptr_t user_stack; // The user mode stack.
|
uintptr_t user_stack; // The user mode stack.
|
||||||
struct arch_percpu arch; // Architecture-specific fields.
|
struct arch_percpu arch; // Architecture-specific fields.
|
||||||
struct irq_percpu irq; // IRQ information.
|
struct irq_percpu irq; // IRQ information.
|
||||||
struct sched_percpu sched; // Scheduler information.
|
struct scheduler sched; // Scheduler information.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct percpu* percpu_new();
|
struct percpu* percpu_new();
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ enum cache_mode : uint8_t {
|
|||||||
|
|
||||||
struct pmap {
|
struct pmap {
|
||||||
phys_t root;
|
phys_t root;
|
||||||
spinlock_t lock;
|
struct spinlock lock;
|
||||||
bool is_user;
|
bool is_user;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/list.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <uapi/poll.h>
|
#include <uapi/poll.h>
|
||||||
|
|
||||||
@@ -16,3 +17,8 @@ enum poll_flags : uint16_t {
|
|||||||
POLLWRNORM = __POLLWRNORM,
|
POLLWRNORM = __POLLWRNORM,
|
||||||
POLLWRBAND = __POLLWRBAND,
|
POLLWRBAND = __POLLWRBAND,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct poll_event {
|
||||||
|
// TODO
|
||||||
|
list_link(struct poll_event*) next;
|
||||||
|
};
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ void kprintf(const char* message, ...);
|
|||||||
void kvprintf(const char* message, va_list args);
|
void kvprintf(const char* message, va_list args);
|
||||||
|
|
||||||
#include <zinnia/clock.h>
|
#include <zinnia/clock.h>
|
||||||
#include <stdint.h>
|
#include <zinnia/percpu.h>
|
||||||
|
|
||||||
#define log(category, message, ...) \
|
#define log(message, ...) \
|
||||||
do { \
|
do { \
|
||||||
uint64_t _time = clock_get_elapsed_ns(); \
|
auto _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__); \
|
auto _cur = percpu_get()->sched.current; \
|
||||||
|
auto _tid = _cur ? _cur->id : 0; \
|
||||||
|
kprintf("[%5lu.%06lu] [%5lu] " message, _time / 1'000'000'000, _time % 1'000'000, _tid, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct refcount {
|
struct refcount {
|
||||||
size_t count;
|
atomic(size_t) count;
|
||||||
};
|
};
|
||||||
|
|
||||||
void refcount_inc(struct refcount* rc);
|
void refcount_inc(struct refcount* rc);
|
||||||
|
|||||||
+7
-17
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/atomic.h>
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
#include <zinnia/init.h>
|
#include <zinnia/init.h>
|
||||||
#include <zinnia/tailq.h>
|
#include <zinnia/tailq.h>
|
||||||
#include <zinnia/types.h>
|
#include <zinnia/types.h>
|
||||||
#include <zinnia/wait.h>
|
|
||||||
#include <bits/sched.h>
|
#include <bits/sched.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -39,39 +39,29 @@ struct task {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Per-CPU data for scheduling.
|
// Per-CPU data for scheduling.
|
||||||
struct sched_percpu {
|
struct scheduler {
|
||||||
struct task* current;
|
struct task* current;
|
||||||
struct task* idle_task;
|
struct task* idle_task;
|
||||||
size_t preempt_level;
|
size_t preempt_level;
|
||||||
tailq_head(struct task) run_queue;
|
tailq_head(struct task) run_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Blocks the current task on the given wait queue.
|
|
||||||
// The caller must NOT hold any spinlocks. Returns after the task is woken.
|
|
||||||
void sched_block(struct sched_percpu* sched, struct wait_queue* wq);
|
|
||||||
|
|
||||||
// Wakes the first task blocked on the given wait queue, if any.
|
|
||||||
void sched_wake(struct sched_percpu* sched, struct wait_queue* wq);
|
|
||||||
|
|
||||||
// Wakes all tasks blocked on the given wait queue.
|
|
||||||
void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq);
|
|
||||||
|
|
||||||
typedef void (*task_fn_t)(uintptr_t arg0);
|
typedef void (*task_fn_t)(uintptr_t arg0);
|
||||||
|
|
||||||
errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out);
|
errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out);
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void task_entry(task_fn_t entry, uintptr_t arg0);
|
void task_entry(task_fn_t entry, uintptr_t arg0);
|
||||||
|
|
||||||
void sched_init(struct sched_percpu* sched);
|
void sched_init(struct scheduler* sched);
|
||||||
void sched_reschedule(struct sched_percpu* sched);
|
void sched_reschedule(struct scheduler* sched);
|
||||||
void sched_yield(struct sched_percpu* sched);
|
void sched_yield(struct scheduler* sched);
|
||||||
void sched_add_task(struct sched_percpu* sched, struct task* task);
|
void sched_add_task(struct scheduler* sched, struct task* task);
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void sched_to_user(uintptr_t ctx);
|
void sched_to_user(uintptr_t ctx);
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void sched_to_user_context(uintptr_t ctx);
|
void sched_to_user_context(uintptr_t ctx);
|
||||||
|
|
||||||
// Info block for sched_to_user. Heap-allocated by the caller, freed by sched_to_user_arg.
|
// Info block for sched_to_user.
|
||||||
struct task_start_info {
|
struct task_start_info {
|
||||||
uintptr_t ip;
|
uintptr_t ip;
|
||||||
uintptr_t sp;
|
uintptr_t sp;
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
// Busy-waits in a loop until the lock is freed.
|
// Busy-waits in a loop until the lock is freed.
|
||||||
// Does not put the CPU to sleep.
|
// Does not put the CPU to sleep.
|
||||||
typedef struct {
|
struct spinlock {
|
||||||
uint32_t owner;
|
uint32_t owner;
|
||||||
uint32_t next;
|
uint32_t next;
|
||||||
} spinlock_t;
|
};
|
||||||
|
|
||||||
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
||||||
void spin_lock(spinlock_t* spin);
|
void spin_lock(struct spinlock* spin);
|
||||||
|
|
||||||
// Unlocks a spinlock.
|
// Unlocks a spinlock.
|
||||||
void spin_unlock(spinlock_t* spin);
|
void spin_unlock(struct spinlock* spin);
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <zinnia/sched.h>
|
|
||||||
#include <zinnia/syscall.h>
|
|
||||||
|
|
||||||
#define SYSCALL_DECLARE(name) extern void sys_##name()
|
|
||||||
|
|
||||||
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);
|
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
#ifndef SYSCALL_DECLARE
|
||||||
|
#define SYSCALL_DECLARE(number, name, num_args) extern void sys_##name();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SYSCALL_DECLARE(0, exit, -1)
|
||||||
|
// SYSCALL_DECLARE(1, syslog, -1)
|
||||||
|
SYSCALL_DECLARE(2, getuname, -1)
|
||||||
|
// SYSCALL_DECLARE(3, setuname, -1)
|
||||||
|
SYSCALL_DECLARE(4, archctl, -1)
|
||||||
|
// SYSCALL_DECLARE(5, reboot, -1)
|
||||||
|
// SYSCALL_DECLARE(6, mmap, -1)
|
||||||
|
// SYSCALL_DECLARE(7, munmap, -1)
|
||||||
|
// SYSCALL_DECLARE(8, mprotect, -1)
|
||||||
|
// SYSCALL_DECLARE(9, madvise, -1)
|
||||||
|
// SYSCALL_DECLARE(10, sigprocmask, -1)
|
||||||
|
// SYSCALL_DECLARE(11, sigsuspend, -1)
|
||||||
|
// SYSCALL_DECLARE(12, sigpending, -1)
|
||||||
|
// SYSCALL_DECLARE(13, sigaction, -1)
|
||||||
|
// SYSCALL_DECLARE(14, sigtimedwait, -1)
|
||||||
|
// SYSCALL_DECLARE(15, sigaltstack, -1)
|
||||||
|
// SYSCALL_DECLARE(16, sigreturn, -1)
|
||||||
|
// SYSCALL_DECLARE(17, sigqueue, -1)
|
||||||
|
// SYSCALL_DECLARE(18, execve, -1)
|
||||||
|
// SYSCALL_DECLARE(19, fexecve, -1)
|
||||||
|
// SYSCALL_DECLARE(20, fork, -1)
|
||||||
|
// SYSCALL_DECLARE(21, kill, -1)
|
||||||
|
// SYSCALL_DECLARE(22, gettid, -1)
|
||||||
|
// SYSCALL_DECLARE(23, getpid, -1)
|
||||||
|
// SYSCALL_DECLARE(24, getppid, -1)
|
||||||
|
// SYSCALL_DECLARE(25, waitid, -1)
|
||||||
|
// SYSCALL_DECLARE(26, waitpid, -1)
|
||||||
|
// SYSCALL_DECLARE(27, pread, -1)
|
||||||
|
// SYSCALL_DECLARE(28, readv, -1)
|
||||||
|
// SYSCALL_DECLARE(29, pwrite, -1)
|
||||||
|
// SYSCALL_DECLARE(30, writev, -1)
|
||||||
|
// SYSCALL_DECLARE(31, seek, -1)
|
||||||
|
// SYSCALL_DECLARE(32, ioctl, -1)
|
||||||
|
// SYSCALL_DECLARE(33, openat, -1)
|
||||||
|
// SYSCALL_DECLARE(34, close, -1)
|
||||||
|
// SYSCALL_DECLARE(35, fstat, -1)
|
||||||
|
// SYSCALL_DECLARE(36, fstatat, -1)
|
||||||
|
// SYSCALL_DECLARE(37, statvfs, -1)
|
||||||
|
// SYSCALL_DECLARE(38, fstatvfs, -1)
|
||||||
|
// SYSCALL_DECLARE(39, faccessat, -1)
|
||||||
|
// SYSCALL_DECLARE(40, fcntl, -1)
|
||||||
|
// SYSCALL_DECLARE(41, ftruncate, -1)
|
||||||
|
// SYSCALL_DECLARE(42, truncate, -1)
|
||||||
|
// SYSCALL_DECLARE(43, fallocate, -1)
|
||||||
|
// SYSCALL_DECLARE(44, fadvise, -1)
|
||||||
|
// SYSCALL_DECLARE(45, utimensat, -1)
|
||||||
|
// SYSCALL_DECLARE(46, mknodat, -1)
|
||||||
|
// SYSCALL_DECLARE(47, getcwd, -1)
|
||||||
|
// SYSCALL_DECLARE(48, chdir, -1)
|
||||||
|
// SYSCALL_DECLARE(49, fchdir, -1)
|
||||||
|
// SYSCALL_DECLARE(50, mkdirat, -1)
|
||||||
|
// SYSCALL_DECLARE(51, rmdirat, -1)
|
||||||
|
// SYSCALL_DECLARE(52, getdents, -1)
|
||||||
|
// SYSCALL_DECLARE(53, renameat, -1)
|
||||||
|
// SYSCALL_DECLARE(54, fchmod, -1)
|
||||||
|
// SYSCALL_DECLARE(55, fchmodat, -1)
|
||||||
|
// SYSCALL_DECLARE(56, fchownat, -1)
|
||||||
|
// SYSCALL_DECLARE(57, linkat, -1)
|
||||||
|
// SYSCALL_DECLARE(58, symlinkat, -1)
|
||||||
|
// SYSCALL_DECLARE(59, unlinkat, -1)
|
||||||
|
// SYSCALL_DECLARE(60, readlinkat, -1)
|
||||||
|
// SYSCALL_DECLARE(61, flock, -1)
|
||||||
|
// SYSCALL_DECLARE(62, ppoll, -1)
|
||||||
|
// SYSCALL_DECLARE(63, dup, -1)
|
||||||
|
// SYSCALL_DECLARE(64, dup3, -1)
|
||||||
|
// SYSCALL_DECLARE(65, sync, -1)
|
||||||
|
// SYSCALL_DECLARE(66, fsync, -1)
|
||||||
|
// SYSCALL_DECLARE(67, fdatasync, -1)
|
||||||
|
// SYSCALL_DECLARE(68, getgroups, -1)
|
||||||
|
// SYSCALL_DECLARE(69, setgroups, -1)
|
||||||
|
// SYSCALL_DECLARE(70, getsid, -1)
|
||||||
|
// SYSCALL_DECLARE(71, setsid, -1)
|
||||||
|
// SYSCALL_DECLARE(72, setuid, -1)
|
||||||
|
// SYSCALL_DECLARE(73, getuid, -1)
|
||||||
|
// SYSCALL_DECLARE(74, setgid, -1)
|
||||||
|
// SYSCALL_DECLARE(75, getgid, -1)
|
||||||
|
// SYSCALL_DECLARE(76, geteuid, -1)
|
||||||
|
// SYSCALL_DECLARE(77, seteuid, -1)
|
||||||
|
// SYSCALL_DECLARE(78, getegid, -1)
|
||||||
|
// SYSCALL_DECLARE(79, setegid, -1)
|
||||||
|
// SYSCALL_DECLARE(80, getpgid, -1)
|
||||||
|
// SYSCALL_DECLARE(81, setpgid, -1)
|
||||||
|
// SYSCALL_DECLARE(82, getresuid, -1)
|
||||||
|
// SYSCALL_DECLARE(83, setresuid, -1)
|
||||||
|
// SYSCALL_DECLARE(84, getresgid, -1)
|
||||||
|
// SYSCALL_DECLARE(85, setresgid, -1)
|
||||||
|
// SYSCALL_DECLARE(86, setreuid, -1)
|
||||||
|
// SYSCALL_DECLARE(87, setregid, -1)
|
||||||
|
// SYSCALL_DECLARE(88, umask, -1)
|
||||||
|
// SYSCALL_DECLARE(89, pipe, -1)
|
||||||
|
// SYSCALL_DECLARE(90, futex_wait, -1)
|
||||||
|
// SYSCALL_DECLARE(91, futex_wake, -1)
|
||||||
|
// SYSCALL_DECLARE(92, thread_create, -1)
|
||||||
|
// SYSCALL_DECLARE(93, thread_kill, -1)
|
||||||
|
// SYSCALL_DECLARE(94, thread_exit, -1)
|
||||||
|
// SYSCALL_DECLARE(95, thread_setname, -1)
|
||||||
|
// SYSCALL_DECLARE(96, thread_getname, -1)
|
||||||
|
// SYSCALL_DECLARE(97, timer_create, -1)
|
||||||
|
// SYSCALL_DECLARE(98, timer_set, -1)
|
||||||
|
// SYSCALL_DECLARE(99, timer_get, -1)
|
||||||
|
// SYSCALL_DECLARE(100, timer_getoverrun, -1)
|
||||||
|
// SYSCALL_DECLARE(101, timer_delete, -1)
|
||||||
|
// SYSCALL_DECLARE(102, itimer_get, -1)
|
||||||
|
// SYSCALL_DECLARE(103, itimer_set, -1)
|
||||||
|
// SYSCALL_DECLARE(104, clock_get, -1)
|
||||||
|
// SYSCALL_DECLARE(105, clock_getres, -1)
|
||||||
|
// SYSCALL_DECLARE(106, clock_set, -1)
|
||||||
|
// SYSCALL_DECLARE(107, sleep, -1)
|
||||||
|
// SYSCALL_DECLARE(108, yield, -1)
|
||||||
|
// SYSCALL_DECLARE(109, chroot, -1)
|
||||||
|
// SYSCALL_DECLARE(110, mount, -1)
|
||||||
|
// SYSCALL_DECLARE(111, umount, -1)
|
||||||
|
// SYSCALL_DECLARE(112, socket, -1)
|
||||||
|
// SYSCALL_DECLARE(113, socketpair, -1)
|
||||||
|
// SYSCALL_DECLARE(114, shutdown, -1)
|
||||||
|
// SYSCALL_DECLARE(115, bind, -1)
|
||||||
|
// SYSCALL_DECLARE(116, connect, -1)
|
||||||
|
// SYSCALL_DECLARE(117, accept, -1)
|
||||||
|
// SYSCALL_DECLARE(118, listen, -1)
|
||||||
|
// SYSCALL_DECLARE(119, getpeername, -1)
|
||||||
|
// SYSCALL_DECLARE(120, getsockname, -1)
|
||||||
|
// SYSCALL_DECLARE(121, getsockopt, -1)
|
||||||
|
// SYSCALL_DECLARE(122, setsockopt, -1)
|
||||||
|
// SYSCALL_DECLARE(123, sendmsg, -1)
|
||||||
|
// SYSCALL_DECLARE(124, recvmsg, -1)
|
||||||
|
// SYSCALL_DECLARE(125, getentropy, -1)
|
||||||
|
// SYSCALL_DECLARE(126, getrusage, -1)
|
||||||
|
// SYSCALL_DECLARE(127, getrlimit, -1)
|
||||||
|
// SYSCALL_DECLARE(128, setrlimit, -1)
|
||||||
|
// SYSCALL_DECLARE(129, getpriority, -1)
|
||||||
|
// SYSCALL_DECLARE(130, setpriority, -1)
|
||||||
|
// SYSCALL_DECLARE(131, sched_getparam, -1)
|
||||||
|
// SYSCALL_DECLARE(132, sched_setparam, -1)
|
||||||
|
// SYSCALL_DECLARE(133, module_insert, -1)
|
||||||
|
// SYSCALL_DECLARE(134, module_remove, -1)
|
||||||
|
// SYSCALL_DECLARE(135, epoll_create, -1)
|
||||||
|
// SYSCALL_DECLARE(136, epoll_ctl, -1)
|
||||||
|
// SYSCALL_DECLARE(137, epoll_pwait, -1)
|
||||||
|
// SYSCALL_DECLARE(138, timerfd_create, -1)
|
||||||
|
// SYSCALL_DECLARE(139, timerfd_gettime, -1)
|
||||||
|
// SYSCALL_DECLARE(140, timerfd_settime, -1)
|
||||||
|
// SYSCALL_DECLARE(141, signalfd_create, -1)
|
||||||
|
// SYSCALL_DECLARE(142, eventfd_create, -1)
|
||||||
|
// SYSCALL_DECLARE(143, msync, -1)
|
||||||
|
// SYSCALL_DECLARE(144, sysconf, -1)
|
||||||
@@ -2,6 +2,24 @@
|
|||||||
|
|
||||||
#include <zinnia/utils.h>
|
#include <zinnia/utils.h>
|
||||||
#include <bits/types.h>
|
#include <bits/types.h>
|
||||||
|
#include <uapi/types.h>
|
||||||
|
|
||||||
ASSERT_TYPE(phys_t);
|
ASSERT_TYPE(phys_t);
|
||||||
ASSERT_TYPE(virt_t);
|
ASSERT_TYPE(virt_t);
|
||||||
|
|
||||||
|
typedef __off_t off_t;
|
||||||
|
typedef __off64_t off64_t;
|
||||||
|
typedef __blksize_t blksize_t;
|
||||||
|
typedef __blkcnt_t blkcnt_t;
|
||||||
|
typedef __clockid_t clockid_t;
|
||||||
|
typedef __dev_t dev_t;
|
||||||
|
typedef __gid_t gid_t;
|
||||||
|
typedef __ino_t ino_t;
|
||||||
|
typedef __mode_t mode_t;
|
||||||
|
typedef __nlink_t nlink_t;
|
||||||
|
typedef __pid_t pid_t;
|
||||||
|
typedef __rlim_t rlim_t;
|
||||||
|
typedef __uid_t uid_t;
|
||||||
|
typedef __fsblkcnt_t fsblkcnt_t;
|
||||||
|
typedef __fsfilcnt_t fsfilcnt_t;
|
||||||
|
typedef __pthread_attr_t pthread_attr_t;
|
||||||
|
|||||||
+63
-10
@@ -1,11 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zinnia/errno.h>
|
#include <zinnia/errno.h>
|
||||||
|
#include <zinnia/ident.h>
|
||||||
#include <zinnia/iovec.h>
|
#include <zinnia/iovec.h>
|
||||||
#include <zinnia/refcount.h>
|
#include <zinnia/refcount.h>
|
||||||
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/types.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <uapi/fcntl.h>
|
#include <uapi/fcntl.h>
|
||||||
|
#include <uapi/stat.h>
|
||||||
|
|
||||||
enum open_flags : uint32_t {
|
enum open_flags : uint32_t {
|
||||||
O_RDONLY = __O_RDONLY,
|
O_RDONLY = __O_RDONLY,
|
||||||
@@ -49,18 +53,67 @@ struct vfs_path {
|
|||||||
struct vfs_entry* entry;
|
struct vfs_entry* entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
errno_t vfs_path_mount();
|
||||||
|
errno_t vfs_path_lookup(struct vfs_path);
|
||||||
|
|
||||||
|
enum vfs_node_type {
|
||||||
|
VNODE_REGULAR,
|
||||||
|
VNODE_DIRECTORY,
|
||||||
|
VNODE_SYMLINK,
|
||||||
|
VNODE_FIFO,
|
||||||
|
VNODE_BLOCKDEV,
|
||||||
|
VNODE_CHARDEV,
|
||||||
|
VNODE_SOCKET,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_file;
|
||||||
struct vfs_node;
|
struct vfs_node;
|
||||||
struct vfs_regular_ops {
|
struct vfs_node_ops {
|
||||||
errno_t (*read)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
errno_t (*sync)();
|
||||||
errno_t (*write)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
union {
|
||||||
errno_t (*devctl)(struct vfs_node* file);
|
struct {
|
||||||
|
errno_t (*truncate)(struct vfs_node*, uint64_t new_length);
|
||||||
|
} regular;
|
||||||
|
struct {
|
||||||
|
errno_t (*read_link)(struct vfs_node*, char* buf, size_t len, size_t* out_written);
|
||||||
|
} symlink;
|
||||||
|
struct {
|
||||||
|
errno_t (*lookup)(struct vfs_node*, struct vfs_path entry);
|
||||||
|
errno_t (*open)(
|
||||||
|
struct vfs_node*,
|
||||||
|
struct vfs_path entry,
|
||||||
|
enum open_flags flags,
|
||||||
|
const struct ident* identity,
|
||||||
|
struct vfs_file* out_file
|
||||||
|
);
|
||||||
|
errno_t (*create)(struct vfs_node*, const struct ident* identity);
|
||||||
|
} dir;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_node {
|
struct vfs_node {
|
||||||
struct refcount rc;
|
enum vfs_node_type type;
|
||||||
const struct vfs_regular_ops* ops;
|
bool is_seekable;
|
||||||
struct vfs_vnode* vnode;
|
|
||||||
struct vfs_path path;
|
|
||||||
const char* abs_path;
|
|
||||||
bool has_path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vfs_file;
|
||||||
|
struct vfs_file_ops {
|
||||||
|
errno_t (*read)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
||||||
|
errno_t (*write)(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
||||||
|
errno_t (*ioctl)(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vfs_file {
|
||||||
|
struct refcount rc;
|
||||||
|
const struct vfs_file_ops* ops; // vtable for operations on this open file.
|
||||||
|
struct vfs_node* vnode; // The opened vnode.
|
||||||
|
const char* abs_path; // Absolute path resolved during `open()`.
|
||||||
|
struct spinlock lock;
|
||||||
|
|
||||||
|
struct vfs_path path; // The cached entry pointing to this node.
|
||||||
|
bool has_path; // If this file has a path.
|
||||||
|
};
|
||||||
|
|
||||||
|
errno_t vfs_file_read(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
||||||
|
errno_t vfs_file_write(struct vfs_file* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
||||||
|
errno_t vfs_file_ioctl(struct vfs_file* file, uintptr_t request, uintptr_t arg, uintptr_t* out_result);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ struct pager_ops {
|
|||||||
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
|
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: change to btree
|
||||||
struct page_list {
|
struct page_list {
|
||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
struct page* value;
|
struct page* value;
|
||||||
@@ -37,7 +38,7 @@ struct paged_vmo {
|
|||||||
struct vmo object;
|
struct vmo object;
|
||||||
struct pager_ops source;
|
struct pager_ops source;
|
||||||
list_head(struct page_list*) cache;
|
list_head(struct page_list*) cache;
|
||||||
spinlock_t lock;
|
struct spinlock lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
|
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <zinnia/spin.h>
|
|
||||||
#include <zinnia/tailq.h>
|
|
||||||
|
|
||||||
struct task;
|
|
||||||
|
|
||||||
// A queue of tasks waiting for an event.
|
|
||||||
struct wait_queue {
|
|
||||||
tailq_head(struct task) waiters;
|
|
||||||
spinlock_t lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
void wait_queue_init(struct wait_queue* wq);
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zinnia/atomic.h>
|
||||||
|
#include <zinnia/sched.h>
|
||||||
|
#include <zinnia/spin.h>
|
||||||
|
#include <zinnia/tailq.h>
|
||||||
|
|
||||||
|
// A queue of tasks waiting for an event.
|
||||||
|
struct waitq {
|
||||||
|
tailq_head(atomic(struct task)) waiters;
|
||||||
|
atomic(bool) woken;
|
||||||
|
};
|
||||||
|
|
||||||
|
void waitq_init(struct waitq* wq);
|
||||||
|
void waitq_wait(struct waitq* wq);
|
||||||
|
void waitq_wake_one(struct waitq* wq);
|
||||||
|
void waitq_wake_all(struct waitq* wq);
|
||||||
@@ -80,6 +80,7 @@ kernel_link_args = [
|
|||||||
'-ffreestanding',
|
'-ffreestanding',
|
||||||
'-nostdlib',
|
'-nostdlib',
|
||||||
'-static',
|
'-static',
|
||||||
|
'-lgcc',
|
||||||
'-T' + kernel_lds,
|
'-T' + kernel_lds,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Executable
+108
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Small script to print all options available inside a built kernel.
|
||||||
|
# fmt: off
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
|
||||||
|
SIZEOF_PTR = 8
|
||||||
|
SIZEOF_STRUCT = 40
|
||||||
|
ENDIAN = "little"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Provide a path to the kernel binary to use")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(sys.argv[1], "rb") as elffile:
|
||||||
|
file = ELFFile(elffile)
|
||||||
|
section = file.get_section_by_name(".cmdline")
|
||||||
|
if section == None:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cmdline_data = section.data()
|
||||||
|
num_options = int(section.data_size / SIZEOF_PTR)
|
||||||
|
|
||||||
|
print(f"Kernel contains {num_options} options:")
|
||||||
|
|
||||||
|
for i in range(num_options):
|
||||||
|
# Read "struct cmdline_option*"
|
||||||
|
addr = int.from_bytes(cmdline_data[(i * SIZEOF_PTR) :][:SIZEOF_PTR], byteorder=ENDIAN)
|
||||||
|
elffile.seek(next(file.address_offsets(start=addr)))
|
||||||
|
option = elffile.read(SIZEOF_STRUCT)
|
||||||
|
|
||||||
|
# Name
|
||||||
|
name = ""
|
||||||
|
name_ptr = int.from_bytes(option[0:][:SIZEOF_PTR], byteorder=ENDIAN)
|
||||||
|
elffile.seek(next(file.address_offsets(start=name_ptr)))
|
||||||
|
while True:
|
||||||
|
b = int.from_bytes(elffile.read(1))
|
||||||
|
if b == 0:
|
||||||
|
break
|
||||||
|
name += chr(b)
|
||||||
|
|
||||||
|
# Description
|
||||||
|
desc = ""
|
||||||
|
desc_ptr = int.from_bytes(option[8:][:SIZEOF_PTR], byteorder=ENDIAN)
|
||||||
|
elffile.seek(next(file.address_offsets(start=desc_ptr)))
|
||||||
|
while True:
|
||||||
|
b = int.from_bytes(elffile.read(1))
|
||||||
|
if b == 0:
|
||||||
|
break
|
||||||
|
desc += chr(b)
|
||||||
|
|
||||||
|
# Type
|
||||||
|
kind_str = "unknown"
|
||||||
|
kind = int.from_bytes(option[16:][:4], byteorder=ENDIAN)
|
||||||
|
match kind:
|
||||||
|
case 0:
|
||||||
|
kind_str = "string"
|
||||||
|
case 1:
|
||||||
|
kind_str = "bool"
|
||||||
|
case 2:
|
||||||
|
kind_str = "integer"
|
||||||
|
case 2:
|
||||||
|
kind_str = "unsigned integer"
|
||||||
|
|
||||||
|
# Skip function pointer
|
||||||
|
|
||||||
|
# Allowed values
|
||||||
|
limit = ""
|
||||||
|
limit_ptr = int.from_bytes(option[32:][:SIZEOF_PTR], byteorder=ENDIAN)
|
||||||
|
|
||||||
|
if limit_ptr != 0:
|
||||||
|
elffile.seek(next(file.address_offsets(start=limit_ptr)))
|
||||||
|
match kind:
|
||||||
|
case 0:
|
||||||
|
limit = []
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
ptr = next(file.address_offsets(start=limit_ptr + i * SIZEOF_PTR))
|
||||||
|
elffile.seek(ptr)
|
||||||
|
str_ptr = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
|
||||||
|
if str_ptr == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
strstr_off = next(file.address_offsets(start=str_ptr))
|
||||||
|
val = ""
|
||||||
|
elffile.seek(strstr_off)
|
||||||
|
while True:
|
||||||
|
b = int.from_bytes(elffile.read(1))
|
||||||
|
if b == 0:
|
||||||
|
break
|
||||||
|
val += chr(b)
|
||||||
|
i += 1
|
||||||
|
limit.append(val)
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN, signed=True)
|
||||||
|
max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
|
||||||
|
limit = f"[{min}, {max}]"
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
|
||||||
|
max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
|
||||||
|
limit = f"[{min}, {max}]"
|
||||||
|
|
||||||
|
print(f"- {name}:\t{desc} ({kind_str}) {limit if len(limit) != 0 else ""}")
|
||||||
Reference in New Issue
Block a user