diff --git a/arch/x86_64/hpet.c b/arch/x86_64/hpet.c index a2953c4..cf87521 100644 --- a/arch/x86_64/hpet.c +++ b/arch/x86_64/hpet.c @@ -15,7 +15,7 @@ static bool use_hpet = true; static void hpet_option(bool 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 clock clock; @@ -64,7 +64,7 @@ void hpet_init() { hpet_clock.regs = (void*)vaddr; 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); diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c index d408866..52aa508 100644 --- a/arch/x86_64/idt.c +++ b/arch/x86_64/idt.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ void interrupt_handler(struct arch_context* ctx) { bool old = irq_set_interrupted(true); uint64_t isr = ctx->isr; + switch (isr) { case IDT_PF: uint64_t cr2; @@ -48,13 +50,10 @@ void interrupt_handler(struct arch_context* ctx) { sched_reschedule(&cpu->sched); } break; - case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)): + default: struct irq_line* line = cpu->arch.irq_lines[isr - 0x20]; assert(line, "Unhandled interrupt on ISR %lu\n", isr); // TODO: irq_raise(line); - break; - default: - panic("Unhandled exception on ISR %lu\n", isr); } irq_set_interrupted(old); diff --git a/arch/x86_64/sched.c b/arch/x86_64/sched.c index 34e03c4..0ffcca2 100644 --- a/arch/x86_64/sched.c +++ b/arch/x86_64/sched.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86_64/tsc.c b/arch/x86_64/tsc.c index e8e6839..fd3b272 100644 --- a/arch/x86_64/tsc.c +++ b/arch/x86_64/tsc.c @@ -1,17 +1,52 @@ #include #include #include +#include +#include #include #include 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() { if (!use_tsc) return; 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; } @@ -22,33 +57,28 @@ void tsc_init() { tsc_leaf = asm_cpuid(0x15, 0); } - uint64_t freq = 0; if (clock_available()) { // Calibrate using existing clock. uint64_t t1 = asm_rdtsc(); clock_spin_ns(10'000'000); uint64_t t2 = asm_rdtsc(); - freq = (t2 - t1) * 100; + tsc_freq = (t2 - t1) * 100; } 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. // On a normal system, this should usually never be called and is a last resort // since at this point we have at least the HPET timer. if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) { - log("x86_64/tsc", "Calibrating TSC using CPUID 0x15"); - freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax; + log("x86_64/tsc: Calibrating TSC using CPUID 0x15"); + tsc_freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax; } 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; } } 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; } - 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); diff --git a/boot/kernel.ld b/boot/kernel.ld index 9b940c4..7d5c0d2 100644 --- a/boot/kernel.ld +++ b/boot/kernel.ld @@ -23,13 +23,15 @@ SECTIONS __ld_text_end = .; } :text - .rodata ALIGN(CONSTANT(MAXPAGESIZE)) : { + .cmdline ALIGN(CONSTANT(MAXPAGESIZE)) : { __ld_rodata_start = .; - __ld_cmdline_start = .; KEEP(*(.cmdline)) __ld_cmdline_end = .; + } :rodata + + .rodata : { *(.rodata .rodata.*) *(.got .got.*) @@ -39,15 +41,17 @@ SECTIONS .data ALIGN(CONSTANT(MAXPAGESIZE)) : { __ld_data_start = .; - __ld_console_start = .; - KEEP(*(.console)) - __ld_console_end = .; - KEEP(*(SORT_BY_NAME(.init.data.*))) KEEP(*(.init.data)) *(.data .data.*) } :data + .console : { + __ld_console_start = .; + KEEP(*(.console)) + __ld_console_end = .; + } :data + .dynsym : { __ld_dynsym_start = .; *(.dynsym) diff --git a/boot/main.c b/boot/main.c index d33ca6d..a8b5d98 100644 --- a/boot/main.c +++ b/boot/main.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,7 @@ static const char zinnia_banner[] = "Zinnia " ZINNIA_VERSION " " CONFIG_KERNEL_F static void kernel_main_task(uintptr_t 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"); @@ -36,7 +35,7 @@ static void kernel_main_task(uintptr_t arg0) { assert(vmo_new_phys(&init_file) == EOK, ""); vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr); - log("main", "%s:%i\n", __FUNCTION__, __LINE__); + log("main: %s:%i\n", __FUNCTION__, __LINE__); // Load init. 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); sched_add_task(&percpu_get()->sched, init_task); - log("main", "%s:%i\n", __FUNCTION__, __LINE__); + log("main: %s:%i\n", __FUNCTION__, __LINE__); while (true) { irq_wait(); @@ -66,19 +65,18 @@ void kernel_early_init() { [[noreturn]] 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("Command line: %s\n", info->cmdline); cmdline_parse(info->cmdline); console_init(); - kprintf("\ec"); - kprintf("Kernel command line: %s\n", info->cmdline); + mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base); rsdp_addr = info->rsdp; // TODO percpu_init(); sched_init(&percpu_get()->sched); - futex_init(); struct task* main_task; task_create("main", &kernel_vma, kernel_main_task, (uintptr_t)info, &main_task); diff --git a/core/clock.c b/core/clock.c index 5df6d9d..483cca4 100644 --- a/core/clock.c +++ b/core/clock.c @@ -1,24 +1,24 @@ +#include #include #include #include #include -#include #include static struct clock* active_clock = nullptr; static uint64_t counter_base = 0; -static spinlock_t lock = {}; +static struct spinlock lock = {}; bool clock_available() { return active_clock != nullptr; } 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)) 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) { @@ -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(); counter_base += elapsed; @@ -43,7 +43,7 @@ bool clock_switch(struct clock* clock) { void clock_spin_ns(uint64_t ns) { 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; } diff --git a/core/console.c b/core/console.c index 37a92f2..fc0d4d9 100644 --- a/core/console.c +++ b/core/console.c @@ -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() { // 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) active = nullptr; - log("console", "Logging on console \"%s\"\n", active->name); + log("console: Logging on console \"%s\"\n", active->name); } } diff --git a/core/futex.c b/core/futex.c deleted file mode 100644 index 124a457..0000000 --- a/core/futex.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -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; -} diff --git a/core/irq.c b/core/irq.c index 14c1420..24d54bf 100644 --- a/core/irq.c +++ b/core/irq.c @@ -1,7 +1,7 @@ +#include #include #include #include -#include void irq_set_state(bool state) { arch_irq_set_state(state); @@ -17,19 +17,19 @@ void irq_wait() { void irq_lock() { 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; 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() { 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; - 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 (old_level == 1) { arch_irq_set_state(true); @@ -37,5 +37,5 @@ void irq_unlock() { } 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); } diff --git a/core/lib/meson.build b/core/lib/meson.build index efb9e3f..370be91 100644 --- a/core/lib/meson.build +++ b/core/lib/meson.build @@ -1,5 +1,6 @@ # Freestanding libc functions that are needed in the kernel kernel_sources += files( + 'stdlib.c', 'string.c', ) diff --git a/core/lib/stdlib.c b/core/lib/stdlib.c new file mode 100644 index 0000000..611991c --- /dev/null +++ b/core/lib/stdlib.c @@ -0,0 +1,102 @@ +#include +#include +#include + +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; +} diff --git a/core/mem/init.c b/core/mem/init.c index 2fb47cc..d808c65 100644 --- a/core/mem/init.c +++ b/core/mem/init.c @@ -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(); - log("mem", "Memory map:\n"); + log("mem: Memory map:\n"); for (size_t i = 0; i < map_len; i++) { if (map[i].length == 0) continue; @@ -44,7 +44,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ break; } - 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. @@ -54,8 +54,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ largest = &map[i]; } mem_phys_bootstrap(largest); - log("mem", - "Using region [%p - %p] for bootstrap allocator\n", + log("mem: Using region [%p - %p] for bootstrap allocator\n", (void*)largest->address, (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"); // 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) { errno_t status = pmap_map( &kernel_vma.pmap, @@ -80,7 +79,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ } // 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) { errno_t status = pmap_map( &kernel_vma.pmap, @@ -93,7 +92,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_ } // 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) { errno_t status = pmap_map( &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(); - log("mem", "Memory initialization complete\n"); + log("mem: Memory initialization complete\n"); } diff --git a/core/mem/pmap.c b/core/mem/pmap.c index d817740..b667151 100644 --- a/core/mem/pmap.c +++ b/core/mem/pmap.c @@ -15,7 +15,7 @@ errno_t pmap_new_kernel(struct pmap* pt, enum alloc_flags flags) { struct pmap result = { .root = addr, - .lock = (spinlock_t){0}, + .lock = (struct spinlock){0}, .is_user = false, }; @@ -35,7 +35,7 @@ errno_t pmap_new_user(struct pmap* pt, enum alloc_flags flags) { struct pmap result = { .root = user_l1, - .lock = (spinlock_t){0}, + .lock = (struct spinlock){0}, .is_user = true, }; diff --git a/core/mem/pmm.c b/core/mem/pmm.c index 542e73a..9619e80 100644 --- a/core/mem/pmm.c +++ b/core/mem/pmm.c @@ -56,7 +56,7 @@ void mem_phys_bootstrap(struct phys_mem* mem) { } 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 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 (__unlikely(it->freelist.count == num_pages)) { - if (prev_it) { + if (prev_it) prev_it->freelist.next = it->freelist.next; - } else { + else pmm_head = it->freelist.next; - } it->freelist.next = nullptr; 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()); - log("pmm", "Total available memory: %zu MiB\n", free_bytes / 1024 / 1024); + log("pmm: Total available memory: %zu MiB\n", free_bytes / 1024 / 1024); } diff --git a/core/mem/slab.c b/core/mem/slab.c index c74496f..9f3d7fc 100644 --- a/core/mem/slab.c +++ b/core/mem/slab.c @@ -10,8 +10,8 @@ typedef struct { } slab_info; struct slab { - spinlock_t lock; // Access lock. - size_t ent_size; // Size of one entry. + struct spinlock lock; // Access lock. + size_t ent_size; // Size of one entry. void** head; }; @@ -24,7 +24,7 @@ typedef struct { static struct slab slabs[8] = {0}; 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. phys_t addr; diff --git a/core/mem/virt.c b/core/mem/virt.c index b60d91c..f874634 100644 --- a/core/mem/virt.c +++ b/core/mem/virt.c @@ -1,7 +1,7 @@ #include +#include #include #include -#include #include struct page* vm_pfndb = nullptr; @@ -12,8 +12,7 @@ static size_t mapping_offset = 0; uintptr_t vm_alloc(size_t length) { uintptr_t base = arch_mem_mapping_addr(); - size_t offset = - atomic_fetch_add_explicit(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()), memory_order_acquire); + size_t offset = atomic_fetch_add(&mapping_offset, ALIGN_UP(length, arch_mem_page_size()), ATOMIC_ACQUIRE); return base + offset; } diff --git a/core/meson.build b/core/meson.build index ad5a4d6..7c415d7 100644 --- a/core/meson.build +++ b/core/meson.build @@ -2,12 +2,12 @@ kernel_sources += files( 'clock.c', 'console.c', 'elf.c', - 'futex.c', 'irq.c', 'panic.c', 'percpu.c', 'print.c', 'spin.c', + 'wait.c', ) subdir('lib') diff --git a/core/percpu.c b/core/percpu.c index b0eb977..0b73176 100644 --- a/core/percpu.c +++ b/core/percpu.c @@ -2,7 +2,7 @@ #include #include -[[__used, __section(".percpu")]] +[[__percpu]] struct percpu percpu_bsp = { .self = &percpu_bsp, .id = 0, diff --git a/core/print.c b/core/print.c index 3aaa84c..331ac7f 100644 --- a/core/print.c +++ b/core/print.c @@ -5,107 +5,9 @@ #include #include #include +#include #include -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); static void do_print(log_fn_t callback, void* ctx, const char* restrict fmt, va_list args) { diff --git a/core/sched/core.c b/core/sched/core.c new file mode 100644 index 0000000..2b8fa7c --- /dev/null +++ b/core/sched/core.c @@ -0,0 +1 @@ +#include diff --git a/core/sched/meson.build b/core/sched/meson.build index 0bbd154..5245b94 100644 --- a/core/sched/meson.build +++ b/core/sched/meson.build @@ -1,3 +1,4 @@ kernel_sources += files( + 'core.c', 'sched_dumb.c', ) diff --git a/core/sched/sched_dumb.c b/core/sched/sched_dumb.c index d83ca2e..e37b835 100644 --- a/core/sched/sched_dumb.c +++ b/core/sched/sched_dumb.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -34,7 +35,7 @@ void sched_to_user_context(uintptr_t 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; assert(task_create("idle", &kernel_vma, idle_func, 0, &idle_task) == 0, "Unable to create idle task!\n"); sched->idle_task = idle_task; @@ -42,15 +43,15 @@ void sched_init(struct sched_percpu* sched) { 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"); 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); if (t == nullptr) @@ -61,17 +62,17 @@ static struct task* next_task(struct sched_percpu* sched) { return t; } -static void do_reschedule(struct sched_percpu* sched) { - struct task* from = atomic_load_explicit(&sched->current, memory_order_acquire); +static void do_reschedule(struct scheduler* sched) { + struct task* from = sched->current; struct task* to = next_task(sched); + // We'd end up on the same task, skip switching altogether. if (from == to) { irq_unlock(); return; } - atomic_store_explicit(&sched->current, to, memory_order_relaxed); - + sched->current = to; pmap_set(&to->space->pmap); struct percpu* cpu = percpu_get(); @@ -80,17 +81,17 @@ static void do_reschedule(struct sched_percpu* sched) { cpu->kernel_stack = to->kernel_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(); if (sched->current->state != TASK_STATE_DEAD) sched_add_task(sched, sched->current); do_reschedule(sched); } -void sched_yield(struct sched_percpu* sched) { +void sched_yield(struct scheduler* sched) { irq_lock(); do_reschedule(sched); } @@ -104,7 +105,7 @@ errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintpt return ENOMEM; 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; 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) { entry(arg0); - struct sched_percpu* sched = &percpu_get()->sched; + struct scheduler* sched = &percpu_get()->sched; sched->current->state = TASK_STATE_DEAD; sched_yield(sched); 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); -} diff --git a/core/spin.c b/core/spin.c index a8398e1..51127d4 100644 --- a/core/spin.c +++ b/core/spin.c @@ -1,15 +1,15 @@ +#include #include -#include -void spin_lock(spinlock_t* spin) { - uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed); +void spin_lock(struct spinlock* spin) { + 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"); } } -void spin_unlock(spinlock_t* spin) { - uint32_t val = atomic_load_explicit(&spin->owner, memory_order_relaxed); - atomic_store_explicit(&spin->owner, val + 1, memory_order_release); +void spin_unlock(struct spinlock* spin) { + uint32_t val = atomic_load(&spin->owner, ATOMIC_RELAXED); + atomic_store(&spin->owner, val + 1, ATOMIC_RELEASE); } diff --git a/core/syscalls/dispatch.c b/core/syscalls/dispatch.c index c2b5db9..a011f03 100644 --- a/core/syscalls/dispatch.c +++ b/core/syscalls/dispatch.c @@ -3,157 +3,18 @@ #include #include #include -#include #include #include #include +// Declare all syscalls. +#include +#undef SYSCALL_DECLARE + +// Define them. const struct syscall syscall_table[256] = { - // [0] = {sys_exit, 0}, - // [1] = {sys_syslog, 0}, - [2] = {sys_getuname, 0}, - // [3] = {sys_setuname, 0}, - [4] = {sys_archctl, 0}, - // [5] = {sys_reboot, 0}, - // [6] = {sys_mmap, 0}, - // [7] = {sys_munmap, 0}, - // [8] = {sys_mprotect, 0}, - // [9] = {sys_madvise, 0}, - // [10] = {sys_sigprocmask, 0}, - // [11] = {sys_sigsuspend, 0}, - // [12] = {sys_sigpending, 0}, - // [13] = {sys_sigaction, 0}, - // [14] = {sys_sigtimedwait, 0}, - // [15] = {sys_sigaltstack, 0}, - // [16] = {sys_sigreturn, 0}, - // [17] = {sys_sigqueue, 0}, - // [18] = {sys_execve, 0}, - // [19] = {sys_fexecve, 0}, - // [20] = {sys_fork, 0}, - // [21] = {sys_kill, 0}, - // [22] = {sys_gettid, 0}, - // [23] = {sys_getpid, 0}, - // [24] = {sys_getppid, 0}, - // [25] = {sys_waitid, 0}, - // [26] = {sys_waitpid, 0}, - // [27] = {sys_pread, 0}, - // [28] = {sys_readv, 0}, - // [29] = {sys_pwrite, 0}, - // [30] = {sys_writev, 0}, - // [31] = {sys_seek, 0}, - // [32] = {sys_ioctl, 0}, - // [33] = {sys_openat, 0}, - // [34] = {sys_close, 0}, - // [35] = {sys_fstat, 0}, - // [36] = {sys_fstatat, 0}, - // [37] = {sys_statvfs, 0}, - // [38] = {sys_fstatvfs, 0}, - // [39] = {sys_faccessat, 0}, - // [40] = {sys_fcntl, 0}, - // [41] = {sys_ftruncate, 0}, - // [42] = {sys_truncate, 0}, - // [43] = {sys_fallocate, 0}, - // [44] = {sys_fadvise, 0}, - // [45] = {sys_utimensat, 0}, - // [46] = {sys_mknodat, 0}, - // [47] = {sys_getcwd, 0}, - // [48] = {sys_chdir, 0}, - // [49] = {sys_fchdir, 0}, - // [50] = {sys_mkdirat, 0}, - // [51] = {sys_rmdirat, 0}, - // [52] = {sys_getdents, 0}, - // [53] = {sys_renameat, 0}, - // [54] = {sys_fchmod, 0}, - // [55] = {sys_fchmodat, 0}, - // [56] = {sys_fchownat, 0}, - // [57] = {sys_linkat, 0}, - // [58] = {sys_symlinkat, 0}, - // [59] = {sys_unlinkat, 0}, - // [60] = {sys_readlinkat, 0}, - // [61] = {sys_flock, 0}, - // [62] = {sys_ppoll, 0}, - // [63] = {sys_dup, 0}, - // [64] = {sys_dup3, 0}, - // [65] = {sys_sync, 0}, - // [66] = {sys_fsync, 0}, - // [67] = {sys_fdatasync, 0}, - // [68] = {sys_getgroups, 0}, - // [69] = {sys_setgroups, 0}, - // [70] = {sys_getsid, 0}, - // [71] = {sys_setsid, 0}, - // [72] = {sys_setuid, 0}, - // [73] = {sys_getuid, 0}, - // [74] = {sys_setgid, 0}, - // [75] = {sys_getgid, 0}, - // [76] = {sys_geteuid, 0}, - // [77] = {sys_seteuid, 0}, - // [78] = {sys_getegid, 0}, - // [79] = {sys_setegid, 0}, - // [80] = {sys_getpgid, 0}, - // [81] = {sys_setpgid, 0}, - // [82] = {sys_getresuid, 0}, - // [83] = {sys_setresuid, 0}, - // [84] = {sys_getresgid, 0}, - // [85] = {sys_setresgid, 0}, - // [86] = {sys_setreuid, 0}, - // [87] = {sys_setregid, 0}, - // [88] = {sys_umask, 0}, - // [89] = {sys_pipe, 0}, - // [90] = {sys_futex_wait, 0}, - // [91] = {sys_futex_wake, 0}, - // [92] = {sys_thread_create, 0}, - // [93] = {sys_thread_kill, 0}, - // [94] = {sys_thread_exit, 0}, - // [95] = {sys_thread_setname, 0}, - // [96] = {sys_thread_getname, 0}, - // [97] = {sys_timer_create, 0}, - // [98] = {sys_timer_set, 0}, - // [99] = {sys_timer_get, 0}, - // [100] = {sys_timer_getoverrun, 0}, - // [101] = {sys_timer_delete, 0}, - // [102] = {sys_itimer_get, 0}, - // [103] = {sys_itimer_set, 0}, - // [104] = {sys_clock_get, 0}, - // [105] = {sys_clock_getres, 0}, - // [106] = {sys_clock_set, 0}, - // [107] = {sys_sleep, 0}, - // [108] = {sys_yield, 0}, - // [109] = {sys_chroot, 0}, - // [110] = {sys_mount, 0}, - // [111] = {sys_umount, 0}, - // [112] = {sys_socket, 0}, - // [113] = {sys_socketpair, 0}, - // [114] = {sys_shutdown, 0}, - // [115] = {sys_bind, 0}, - // [116] = {sys_connect, 0}, - // [117] = {sys_accept, 0}, - // [118] = {sys_listen, 0}, - // [119] = {sys_getpeername, 0}, - // [120] = {sys_getsockname, 0}, - // [121] = {sys_getsockopt, 0}, - // [122] = {sys_setsockopt, 0}, - // [123] = {sys_sendmsg, 0}, - // [124] = {sys_recvmsg, 0}, - // [125] = {sys_getentropy, 0}, - // [126] = {sys_getrusage, 0}, - // [127] = {sys_getrlimit, 0}, - // [128] = {sys_setrlimit, 0}, - // [129] = {sys_getpriority, 0}, - // [130] = {sys_setpriority, 0}, - // [131] = {sys_sched_getparam, 0}, - // [132] = {sys_sched_setparam, 0}, - // [133] = {sys_module_insert, 0}, - // [134] = {sys_module_remove, 0}, - // [135] = {sys_epoll_create, 0}, - // [136] = {sys_epoll_ctl, 0}, - // [137] = {sys_epoll_pwait, 0}, - // [138] = {sys_timerfd_create, 0}, - // [139] = {sys_timerfd_gettime, 0}, - // [140] = {sys_timerfd_settime, 0}, - // [141] = {sys_signalfd_create, 0}, - // [142] = {sys_eventfd_create, 0}, - // [143] = {sys_msync, 0}, - // [144] = {sys_sysconf, 0}, +#define SYSCALL_DECLARE(number, name, num_args) [number] = {sys_##name, num_args}, +#include }; [[gnu::no_caller_saved_registers]] diff --git a/core/syscalls/futex.c b/core/syscalls/futex.c deleted file mode 100644 index 13d02f9..0000000 --- a/core/syscalls/futex.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include - -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); -} diff --git a/core/syscalls/getuname.c b/core/syscalls/getuname.c index b5e2303..5d5997b 100644 --- a/core/syscalls/getuname.c +++ b/core/syscalls/getuname.c @@ -4,7 +4,7 @@ #include #include -static spinlock_t uname_lock = {}; +static struct spinlock uname_lock = {}; static struct utsname uname_buf = { .sysname = "Zinnia", diff --git a/core/syscalls/meson.build b/core/syscalls/meson.build index 2227c42..a292cdf 100644 --- a/core/syscalls/meson.build +++ b/core/syscalls/meson.build @@ -1,6 +1,5 @@ kernel_sources += files( 'archctl.c', 'dispatch.c', - 'futex.c', 'getuname.c', ) diff --git a/core/wait.c b/core/wait.c new file mode 100644 index 0000000..38b6b3b --- /dev/null +++ b/core/wait.c @@ -0,0 +1,17 @@ +#include + +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 +} diff --git a/dev/acpi/uacpi_glue.c b/dev/acpi/uacpi_glue.c index fb895f9..5cfc9b6 100644 --- a/dev/acpi/uacpi_glue.c +++ b/dev/acpi/uacpi_glue.c @@ -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, ...) { - console_write("uacpi: ", 7); + log("acpi: "); va_list args; va_start(args, msg); diff --git a/dev/common/memfiles.c b/dev/common/memfiles.c index e69de29..8b13789 100644 --- a/dev/common/memfiles.c +++ b/dev/common/memfiles.c @@ -0,0 +1 @@ + diff --git a/include/stdatomic.h b/include/stdatomic.h deleted file mode 100644 index a34720f..0000000 --- a/include/stdatomic.h +++ /dev/null @@ -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) diff --git a/include/stdlib.h b/include/stdlib.h index 2b7814e..e3daf3d 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -1,4 +1,8 @@ #pragma once -long atol(const char* str, int base); -unsigned long atolu(const char* str, int base); +#include + +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); diff --git a/include/uapi/epoll.h b/include/uapi/epoll.h index 2a69387..78a50d0 100644 --- a/include/uapi/epoll.h +++ b/include/uapi/epoll.h @@ -31,7 +31,7 @@ union __epoll_data { uint64_t u64; }; -struct epoll_event { +struct __epoll_event { uint32_t events; union __epoll_data data; }; diff --git a/include/uapi/stat.h b/include/uapi/stat.h index 3eeaa68..4a0f7b5 100644 --- a/include/uapi/stat.h +++ b/include/uapi/stat.h @@ -33,19 +33,19 @@ #define __S_IEXEC __S_IXUSR struct __stat { - dev_t st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - dev_t st_rdev; - off_t st_size; - struct timespec st_atim; - struct timespec st_mtim; - struct timespec st_ctim; - blksize_t st_blksize; - blkcnt_t st_blocks; + __dev_t st_dev; + __ino_t st_ino; + __mode_t st_mode; + __nlink_t st_nlink; + __uid_t st_uid; + __gid_t st_gid; + __dev_t st_rdev; + __off_t st_size; + struct __timespec st_atim; + struct __timespec st_mtim; + struct __timespec st_ctim; + __blksize_t st_blksize; + __blkcnt_t st_blocks; }; #endif diff --git a/include/uapi/time.h b/include/uapi/time.h index 6d5a940..8bacd36 100644 --- a/include/uapi/time.h +++ b/include/uapi/time.h @@ -4,27 +4,27 @@ #include -typedef int64_t time_t; -typedef int64_t suseconds_t; +typedef int64_t __time_t; +typedef int64_t __suseconds_t; -struct timespec { - time_t tv_sec; +struct __timespec { + __time_t tv_sec; int64_t tv_nsec; }; -struct timeval { - time_t tv_sec; - suseconds_t tv_usec; +struct __timeval { + __time_t tv_sec; + __suseconds_t tv_usec; }; struct itimerval { - struct timeval it_interval; - struct timeval it_value; + struct __timeval it_interval; + struct __timeval it_value; }; struct itimerspec { - struct timespec it_interval; - struct timespec it_value; + struct __timespec it_interval; + struct __timespec it_value; }; #define __ITIMER_REAL 0 diff --git a/include/uapi/types.h b/include/uapi/types.h index 1efa32b..24495b2 100644 --- a/include/uapi/types.h +++ b/include/uapi/types.h @@ -4,21 +4,21 @@ #include -typedef int64_t off_t; -typedef off_t off64_t; -typedef uintptr_t blksize_t; -typedef uintptr_t blkcnt_t; -typedef uintptr_t clockid_t; -typedef uintptr_t dev_t; -typedef uint32_t gid_t; -typedef uintptr_t ino_t; -typedef uint32_t mode_t; -typedef uintptr_t nlink_t; -typedef int32_t pid_t; -typedef uintptr_t rlim_t; -typedef uint32_t uid_t; -typedef uintptr_t fsblkcnt_t; -typedef uintptr_t fsfilcnt_t; -typedef uintptr_t pthread_attr_t; +typedef int64_t __off_t; +typedef __off_t __off64_t; +typedef uintptr_t __blksize_t; +typedef uintptr_t __blkcnt_t; +typedef uintptr_t __clockid_t; +typedef uintptr_t __dev_t; +typedef uint32_t __gid_t; +typedef uintptr_t __ino_t; +typedef uint32_t __mode_t; +typedef uintptr_t __nlink_t; +typedef int32_t __pid_t; +typedef uintptr_t __rlim_t; +typedef uint32_t __uid_t; +typedef uintptr_t __fsblkcnt_t; +typedef uintptr_t __fsfilcnt_t; +typedef uintptr_t __pthread_attr_t; #endif diff --git a/include/zinnia/atomic.h b/include/zinnia/atomic.h new file mode 100644 index 0000000..1dc9323 --- /dev/null +++ b/include/zinnia/atomic.h @@ -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) diff --git a/include/zinnia/btree.h b/include/zinnia/btree.h deleted file mode 100644 index 6f70f09..0000000 --- a/include/zinnia/btree.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/include/zinnia/cmdline.h b/include/zinnia/cmdline.h index 307c732..0362163 100644 --- a/include/zinnia/cmdline.h +++ b/include/zinnia/cmdline.h @@ -1,12 +1,13 @@ #pragma once -#include #include #include +#include -#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 = { \ .name = opt_name, \ + .desc = opt_desc, \ .option_type = _Generic( \ (opt_func), \ void (*)(const char*): CMDLINE_STRING, \ @@ -15,11 +16,23 @@ void (*)(uintptr_t): CMDLINE_UINTPTR \ ), \ .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")]] \ - 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 { CMDLINE_STRING, @@ -28,9 +41,12 @@ enum cmdline_type { CMDLINE_UINTPTR, }; +// Describes a command line option. +// NOTE: Changing the layout of this struct requires changes in util scripts. struct cmdline_option { - // The name of this option. const char* name; + const char* desc; + enum cmdline_type option_type; // Gets called if this option is present on the command line. union { void (*func_str)(const char* value); @@ -39,8 +55,28 @@ struct cmdline_option { void (*func_uintptr)(uintptr_t value); 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. 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 + ) +); diff --git a/include/zinnia/console.h b/include/zinnia/console.h index c3ff63f..12573f1 100644 --- a/include/zinnia/console.h +++ b/include/zinnia/console.h @@ -1,13 +1,11 @@ #pragma once -#include #include #include +#include struct console { const char* name; - void* private; - // Initializes the console. bool (*init)(struct console* con); // Writes to the console. diff --git a/include/zinnia/errno.h b/include/zinnia/errno.h index aebb84f..3879405 100644 --- a/include/zinnia/errno.h +++ b/include/zinnia/errno.h @@ -4,7 +4,7 @@ #include typedef enum : int32_t { - EOK = 0, // Not really an error. + EOK = 0, // Success! Not really an error though... EPERM = __EPERM, ENOENT = __ENOENT, ESRCH = __ESRCH, diff --git a/include/zinnia/file.h b/include/zinnia/file.h new file mode 100644 index 0000000..5c9fb0a --- /dev/null +++ b/include/zinnia/file.h @@ -0,0 +1,3 @@ +#pragma once + +struct file_desc {}; diff --git a/include/zinnia/futex.h b/include/zinnia/futex.h deleted file mode 100644 index 04b9d3e..0000000 --- a/include/zinnia/futex.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include - -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); diff --git a/include/zinnia/ident.h b/include/zinnia/ident.h new file mode 100644 index 0000000..ed90f13 --- /dev/null +++ b/include/zinnia/ident.h @@ -0,0 +1,5 @@ +#pragma once + +struct ident { + // TODO +}; diff --git a/include/zinnia/percpu.h b/include/zinnia/percpu.h index d054e5b..1e3c236 100644 --- a/include/zinnia/percpu.h +++ b/include/zinnia/percpu.h @@ -9,16 +9,18 @@ ASSERT_TYPE(struct arch_percpu); // bits/percpu.h +#define __percpu __used, __section(".percpu") + // CPU-relative information. struct percpu { - struct percpu* self; // A pointer to this structure. - size_t id; // The virtual ID of this CPU. - bool online; // Whether this CPU is initialized and active. - uintptr_t kernel_stack; // The kernel mode stack. - uintptr_t user_stack; // The user mode stack. - struct arch_percpu arch; // Architecture-specific fields. - struct irq_percpu irq; // IRQ information. - struct sched_percpu sched; // Scheduler information. + struct percpu* self; // A pointer to this structure. + size_t id; // The virtual ID of this CPU. + bool online; // Whether this CPU is initialized and active. + uintptr_t kernel_stack; // The kernel mode stack. + uintptr_t user_stack; // The user mode stack. + struct arch_percpu arch; // Architecture-specific fields. + struct irq_percpu irq; // IRQ information. + struct scheduler sched; // Scheduler information. }; struct percpu* percpu_new(); diff --git a/include/zinnia/pmap.h b/include/zinnia/pmap.h index cbf3804..b6a51f8 100644 --- a/include/zinnia/pmap.h +++ b/include/zinnia/pmap.h @@ -24,7 +24,7 @@ enum cache_mode : uint8_t { struct pmap { phys_t root; - spinlock_t lock; + struct spinlock lock; bool is_user; }; diff --git a/include/zinnia/poll.h b/include/zinnia/poll.h index 197daed..82901f5 100644 --- a/include/zinnia/poll.h +++ b/include/zinnia/poll.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -16,3 +17,8 @@ enum poll_flags : uint16_t { POLLWRNORM = __POLLWRNORM, POLLWRBAND = __POLLWRBAND, }; + +struct poll_event { + // TODO + list_link(struct poll_event*) next; +}; diff --git a/include/zinnia/print.h b/include/zinnia/print.h index 6081d73..94904df 100644 --- a/include/zinnia/print.h +++ b/include/zinnia/print.h @@ -9,10 +9,12 @@ void kprintf(const char* message, ...); void kvprintf(const char* message, va_list args); #include -#include +#include -#define log(category, message, ...) \ +#define log(message, ...) \ do { \ - uint64_t _time = clock_get_elapsed_ns(); \ - kprintf("[%5lu.%06lu] \e[1;34m" category ":\e[0m " message, _time / 1'000'000'000, _time % 1'000'000, ##__VA_ARGS__); \ + auto _time = clock_get_elapsed_ns(); \ + 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) diff --git a/include/zinnia/refcount.h b/include/zinnia/refcount.h index 0620202..1797e64 100644 --- a/include/zinnia/refcount.h +++ b/include/zinnia/refcount.h @@ -1,10 +1,11 @@ #pragma once +#include #include #include struct refcount { - size_t count; + atomic(size_t) count; }; void refcount_inc(struct refcount* rc); diff --git a/include/zinnia/sched.h b/include/zinnia/sched.h index 51ce886..4d8beca 100644 --- a/include/zinnia/sched.h +++ b/include/zinnia/sched.h @@ -1,10 +1,10 @@ #pragma once +#include #include #include #include #include -#include #include #include #include @@ -39,39 +39,29 @@ struct task { }; // Per-CPU data for scheduling. -struct sched_percpu { +struct scheduler { struct task* current; struct task* idle_task; size_t preempt_level; 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); errno_t task_create(const char* name, struct vma* space, task_fn_t entry, uintptr_t arg0, struct task** out); [[noreturn]] void task_entry(task_fn_t entry, uintptr_t arg0); -void sched_init(struct sched_percpu* sched); -void sched_reschedule(struct sched_percpu* sched); -void sched_yield(struct sched_percpu* sched); -void sched_add_task(struct sched_percpu* sched, struct task* task); +void sched_init(struct scheduler* sched); +void sched_reschedule(struct scheduler* sched); +void sched_yield(struct scheduler* sched); +void sched_add_task(struct scheduler* sched, struct task* task); [[noreturn]] void sched_to_user(uintptr_t ctx); [[noreturn]] 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 { uintptr_t ip; uintptr_t sp; diff --git a/include/zinnia/spin.h b/include/zinnia/spin.h index f7728a9..0372df8 100644 --- a/include/zinnia/spin.h +++ b/include/zinnia/spin.h @@ -4,13 +4,13 @@ // Busy-waits in a loop until the lock is freed. // Does not put the CPU to sleep. -typedef struct { +struct spinlock { uint32_t owner; uint32_t next; -} spinlock_t; +}; // 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. -void spin_unlock(spinlock_t* spin); +void spin_unlock(struct spinlock* spin); diff --git a/include/zinnia/syscall_list.h b/include/zinnia/syscall_list.h deleted file mode 100644 index 0e1e608..0000000 --- a/include/zinnia/syscall_list.h +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -#include -#include - -#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); diff --git a/include/zinnia/syscall_list.inc b/include/zinnia/syscall_list.inc new file mode 100644 index 0000000..52747b0 --- /dev/null +++ b/include/zinnia/syscall_list.inc @@ -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) diff --git a/include/zinnia/types.h b/include/zinnia/types.h index 5c55828..4716ef1 100644 --- a/include/zinnia/types.h +++ b/include/zinnia/types.h @@ -2,6 +2,24 @@ #include #include +#include ASSERT_TYPE(phys_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; diff --git a/include/zinnia/vfs.h b/include/zinnia/vfs.h index 05368e4..cd82666 100644 --- a/include/zinnia/vfs.h +++ b/include/zinnia/vfs.h @@ -1,11 +1,15 @@ #pragma once #include +#include #include #include +#include +#include #include #include #include +#include enum open_flags : uint32_t { O_RDONLY = __O_RDONLY, @@ -49,18 +53,67 @@ struct vfs_path { 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_regular_ops { - errno_t (*read)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read); - errno_t (*write)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written); - errno_t (*devctl)(struct vfs_node* file); +struct vfs_node_ops { + errno_t (*sync)(); + union { + 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 refcount rc; - const struct vfs_regular_ops* ops; - struct vfs_vnode* vnode; - struct vfs_path path; - const char* abs_path; - bool has_path; + enum vfs_node_type type; + bool is_seekable; }; + +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); diff --git a/include/zinnia/vmo.h b/include/zinnia/vmo.h index fd6dae1..8c3b776 100644 --- a/include/zinnia/vmo.h +++ b/include/zinnia/vmo.h @@ -27,6 +27,7 @@ struct pager_ops { errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page); }; +// TODO: change to btree struct page_list { uintptr_t offset; struct page* value; @@ -37,7 +38,7 @@ struct paged_vmo { struct vmo object; struct pager_ops source; 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); diff --git a/include/zinnia/wait.h b/include/zinnia/wait.h deleted file mode 100644 index 8cd1758..0000000 --- a/include/zinnia/wait.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -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); diff --git a/include/zinnia/waitq.h b/include/zinnia/waitq.h new file mode 100644 index 0000000..d2f5dee --- /dev/null +++ b/include/zinnia/waitq.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +// 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); diff --git a/meson.build b/meson.build index 11a41f0..a14742d 100644 --- a/meson.build +++ b/meson.build @@ -80,6 +80,7 @@ kernel_link_args = [ '-ffreestanding', '-nostdlib', '-static', + '-lgcc', '-T' + kernel_lds, ] diff --git a/scripts/get_options.py b/scripts/get_options.py new file mode 100755 index 0000000..76d940c --- /dev/null +++ b/scripts/get_options.py @@ -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 ""}")