This commit is contained in:
2026-08-11 17:48:20 +02:00
committed by Marvin Friedrich
parent cf33867e68
commit 0e2d4ed8c6
55 changed files with 279 additions and 346 deletions
+7 -28
View File
@@ -1,7 +1,12 @@
#pragma once
// These hints may improve code generation, but are optional and can be stubbed.
#if defined(__GNUC__) || defined(__clang__)
// Attributes that affect data layout.
#define __section(x) gnu::section(x)
#define __aligned(x) gnu::aligned(x)
#define __packed gnu::packed
#define __naked gnu::naked
// These hints may improve code generation.
#define __cold gnu::cold
#define __hot gnu::hot
#define __used gnu::used
@@ -9,17 +14,6 @@
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
#define __likely(x) __builtin_expect(!!(x), 1)
#define __unlikely(x) __builtin_expect(!!(x), 0)
#define __always_inline gnu::always_inline
#else
#define __cold
#define __hot
#define __used
#define __unused
#define __format(like, ...)
#define __likely(x) x
#define __unlikely(x) x
#define __always_inline
#endif
// Only clang has these hints, GCC will throw a warning here.
// They also don't support the C23 attribute format.
@@ -30,18 +24,3 @@
#define __user
#define __phys
#endif
// Attributes that affect data layout. Not optional.
#if defined(__GNUC__) || defined(__clang__)
#define __weak gnu::weak
#define __section(x) gnu::section(x)
#define __aligned(x) gnu::aligned(x)
#define __packed gnu::packed
#define __naked gnu::naked
#define __alias(x) gnu::alias(x)
#else
#error "Unsupported compiler!"
#endif
// Intrinsics
#define __unreachable() __builtin_unreachable()
+33 -31
View File
@@ -2,37 +2,6 @@
#include <stdint.h>
#ifdef __x86_64__
#define ELF_ARCH_CLASS ELFCLASS64
#define ELF_ARCH_DATA ELFDATA2LSB
#define ELF_ARCH_MACHINE EM_X86_64
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define elf_ehdr elf64_ehdr
#define elf_phdr elf64_phdr
#define elf_dyn elf64_dyn
#define elf_addr elf64_addr
#define elf_off elf64_off
#define elf_nhdr elf64_nhdr
#define elf_auxv elf64_auxv
#define elf_sym elf64_sym
#define elf_rela elf64_rela
#define elf_rel elf64_rel
enum {
R_NONE = 0,
R_COPY = 5,
R_GLOB_DAT = 6,
R_JUMP_SLOT = 7,
R_RELATIVE = 8,
R_IRELATIVE = 37,
};
#endif
constexpr char ELF_MAG[4] = {0x7F, 'E', 'L', 'F'};
typedef uint64_t elf64_addr_t;
@@ -369,3 +338,36 @@ static inline uint32_t ELF64_R_SYM(uint64_t info) {
static inline uint32_t ELF64_R_TYPE(uint64_t info) {
return info & 0xFFFFFFFF;
}
// Architecture specific bits.
#ifdef __x86_64__
#define ELF_ARCH_CLASS ELFCLASS64
#define ELF_ARCH_DATA ELFDATA2LSB
#define ELF_ARCH_MACHINE EM_X86_64
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define elf_ehdr elf64_ehdr
#define elf_phdr elf64_phdr
#define elf_dyn elf64_dyn
#define elf_addr elf64_addr
#define elf_off elf64_off
#define elf_nhdr elf64_nhdr
#define elf_auxv elf64_auxv
#define elf_sym elf64_sym
#define elf_rela elf64_rela
#define elf_rel elf64_rel
enum {
R_NONE = 0,
R_COPY = 5,
R_GLOB_DAT = 6,
R_JUMP_SLOT = 7,
R_RELATIVE = 8,
R_IRELATIVE = 37,
};
#endif
+3 -2
View File
@@ -3,6 +3,7 @@
#include <zinnia/status.h>
#include <zinnia/syscall_stubs.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -10,12 +11,12 @@ extern "C" {
// Blocks the calling thread if *addr == expected.
// Returns immediately if the value at addr has changed.
static inline zn_status_t zn_futex_wait(int* addr, int expected) {
static inline zn_status_t zn_futex_wait(int32_t* addr, int32_t expected) {
return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT);
}
// Wakes up to `count` threads waiting on the given futex address.
static inline zn_status_t zn_futex_wake(int* addr, int count) {
static inline zn_status_t zn_futex_wake(int32_t* addr, int32_t count) {
return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE);
}
+2 -3
View File
@@ -24,9 +24,8 @@ static inline zn_status_t zn_handle_validate(zn_handle_t handle) {
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE);
}
// Drops an object handle.
// All further references using this handle are invalid. The numerical value
// may become valid again, but it is an error to keep using it.
// Drops an object handle. All further references using this handle are invalid.
// The numerical value may become valid again, but it is an error to keep using it.
// The underlying object gets freed only once no other handle references it.
static inline zn_status_t zn_handle_drop(zn_handle_t handle) {
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_DROP);
+26
View File
@@ -0,0 +1,26 @@
#ifndef ZINNIA_IPC_H
#define ZINNIA_IPC_H
#include <zinnia/handle.h>
#include <zinnia/rights.h>
#include <zinnia/status.h>
#include <zinnia/syscall_stubs.h>
#ifdef __cplusplus
extern "C" {
#endif
// Defines an IPC window.
struct zn_ipcw {
zn_handle_t handles[16];
};
static inline zn_status_t zn_ipcw_init(struct zn_ipcw** ipcw) {
return ZN_ERR_UNSUPPORTED;
}
#ifdef __cplusplus
}
#endif
#endif
-46
View File
@@ -1,46 +0,0 @@
#pragma once
#include <zinnia/handle.h>
#include <stddef.h>
#include <stdint.h>
#define IPC_GET_STRING(data, str, buf) \
do { \
memcpy(buf, (data) + (str)->offset, (str)->len); \
} while (0)
#define IPC_SET_STRING(cursor, data, field, string) \
do { \
const size_t _len = strlen(string); \
(field)->offset = cursor; \
(field)->len = _len; \
memcpy(data + cursor, string, _len); \
cursor += _len; \
} while (0)
enum ipc_msg_id {
IPC_MSG_FOO,
IPC_MSG_BAR,
IPC_MSG_BAZ,
};
struct ipc_array {
uint16_t offset;
uint16_t len;
};
struct ipc_option {
uint16_t offset;
};
struct ipc_init_register_rq {
enum ipc_msg_id id;
struct ipc_array name;
char data[];
};
struct ipc_kernel_msg {
enum ipc_msg_id id;
struct ipc_array name;
char data[];
};
+1 -1
View File
@@ -25,7 +25,7 @@ enum zn_vm_flags {
// Map at a fixed address, replacing whatever is in the way.
ZN_VM_MAP_FIXED = 1 << 8,
// Map at a fixed address, failing if anything is in the way.
ZB_VM_MAP_FIXED_NOREPLACE = 1 << 9,
ZN_VM_MAP_FIXED_NOREPLACE = 1 << 9,
// Map the entire range immediately.
ZN_VM_MAP_POPULATE = 1 << 10,
};
+3 -1
View File
@@ -13,7 +13,9 @@ static inline zn_status_t zn_ns_create(zn_handle_t* out) {
return ZN_ERR_UNSUPPORTED;
}
static inline zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_namespace) {
// Moves a handle to another namespace.
// The handle must have the `ZN_RIGHT_MOVE` right.
static inline zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_ns) {
return ZN_ERR_UNSUPPORTED;
}
+12 -12
View File
@@ -45,7 +45,7 @@ void lapic_init(struct local_apic* lapic) {
apic_msr |= 1 << 10;
else {
lapic->xapic_regs = mmio_new(apic_msr & 0xFFFF'F000, 0x1000);
ASSERT(lapic->xapic_regs, "Failed to allocate virtual memory!\n");
assert(lapic->xapic_regs, "Failed to allocate virtual memory!\n");
}
asm_wrmsr(0x1B, apic_msr);
@@ -86,18 +86,18 @@ void lapic_eoi(struct local_apic* lapic) {
#define PIC2_DATA_PORT 0xA1
void pic_disable() {
// Note: We initialize the PIC properly, but completely disable it and use the APIC in favor of it.
// We initialize the PIC properly, but completely disable it and use the APIC in favor of it.
// Remap IRQs so they start at 0x20 since interrupts 0x00..0x1F are used by CPU exceptions.
asm_outb(PIC1_COMMAND_PORT, 0x11); // ICW1: Begin initialization and set cascade mode.
asm_outb(PIC1_DATA_PORT, 0x20); // ICW2: Set where interrupts should be mapped to (0x20-0x27).
asm_outb(PIC1_DATA_PORT, 0x04); // ICW3: Connect IRQ2 (0x04) to the slave PIC.
asm_outb(PIC1_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode.
asm_outb(PIC1_DATA_PORT, 0xFF); // Mask all interrupts.
asm_outb(PIC1_COMMAND_PORT, 0x11);
asm_outb(PIC1_DATA_PORT, 0x20);
asm_outb(PIC1_DATA_PORT, 0x04);
asm_outb(PIC1_DATA_PORT, 0x01);
asm_outb(PIC1_DATA_PORT, 0xFF);
// Same for the slave PIC.
asm_outb(PIC2_COMMAND_PORT, 0x11); // ICW1: Begin initialization.
asm_outb(PIC2_DATA_PORT, 0x28); // ICW2: Set where interrupts should be mapped to (0x28-0x2F).
asm_outb(PIC2_DATA_PORT, 0x02); // ICW3: Connect to master PIC at IRQ2.
asm_outb(PIC2_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode.
asm_outb(PIC2_DATA_PORT, 0xFF); // Mask all interrupts.
asm_outb(PIC2_COMMAND_PORT, 0x11);
asm_outb(PIC2_DATA_PORT, 0x28);
asm_outb(PIC2_DATA_PORT, 0x02);
asm_outb(PIC2_DATA_PORT, 0x01);
asm_outb(PIC2_DATA_PORT, 0xFF);
}
+2 -2
View File
@@ -53,7 +53,7 @@ void hpet_init() {
uacpi_setup_early_table_access(table_buf, sizeof(table_buf));
uacpi_table table = {0};
ASSERT(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n");
assert(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n");
struct acpi_hpet* hpet = table.ptr;
hpet_clock.regs = mmio_new(hpet->address.address, 0x1000);
@@ -65,5 +65,5 @@ void hpet_init() {
uint64_t caps = hpet_clock.regs[HPET_CAP];
hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF;
ASSERT(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
}
+1 -1
View File
@@ -50,7 +50,7 @@ void interrupt_handler(struct arch_context* ctx) {
break;
case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)):
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);
break;
default:
+16 -9
View File
@@ -10,22 +10,27 @@ struct arch_task_context {
uint64_t fs_base, gs_base;
};
#define ARCH_ABI(typ, reg, ...) \
union { \
typ reg, __VA_ARGS__; \
}
struct arch_context {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
ARCH_ABI(uint64_t, r13, a7);
ARCH_ABI(uint64_t, r12, a6);
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rsi;
uint64_t rdi;
ARCH_ABI(uint64_t, r10, a5);
ARCH_ABI(uint64_t, r9, a3);
ARCH_ABI(uint64_t, r8, a4);
ARCH_ABI(uint64_t, rsi, a1);
ARCH_ABI(uint64_t, rdi, a0);
uint64_t rbp;
uint64_t rdx;
ARCH_ABI(uint64_t, rdx, a2, ret1);
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
ARCH_ABI(uint64_t, rax, num, ret0);
uint64_t isr; // Pushed onto the stack by the interrupt handler stubs.
uint64_t error; // Pushed onto the stack by the CPU if the interrupt has an error code.
uint64_t rip; // The rest is pushed onto the stack by the CPU during an interrupt.
@@ -35,6 +40,8 @@ struct arch_context {
uint64_t ss;
};
static_assert(sizeof(struct arch_context) == 176);
#define ARCH_CTX_NUM rax
#define ARCH_CTX_A0 rdi
#define ARCH_CTX_A1 rsi
-1
View File
@@ -14,7 +14,6 @@
// The task frame consists of registers that the C ABI marks as callee-saved.
// If we don't save them, these registers are lost during a context switch.
// The order of these fields is important.
struct task_frame {
uint64_t rbx, rbp, r12, r13, r14, r15, rip;
};
+2 -2
View File
@@ -11,6 +11,7 @@ static const struct usercopy_region read_region = {
.fault_ip = x86_64_read_fault,
};
[[__naked]]
bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region) {
asm volatile(
"stac\n"
@@ -41,7 +42,6 @@ bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct us
: "i"(&read_region)
: "memory"
);
return false;
}
extern void x86_64_write_start();
@@ -54,6 +54,7 @@ static const struct usercopy_region write_region = {
.fault_ip = x86_64_write_fault,
};
[[__naked]]
bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region) {
asm volatile(
"stac\n"
@@ -84,7 +85,6 @@ bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct u
: "i"(&read_region)
: "memory"
);
return false;
}
extern void x86_64_strlen_start();
+8 -15
View File
@@ -1,4 +1,3 @@
#include <zinnia/ipc/init.h>
#include <common/compiler.h>
#include <kernel/alloc.h>
#include <kernel/assert.h>
@@ -62,22 +61,22 @@ static void kernel_main_task(uintptr_t arg0) {
struct boot_info* info = (struct boot_info*)arg0;
kprintf("%s\n", zinnia_banner); // Say hello!
ASSERT(info->num_files >= 1, "No init executable provided\n");
assert(info->num_files >= 1, "No init executable provided\n");
struct channel* init_ep;
struct channel* other_ep;
ASSERT(channel_create(&init_ep, &other_ep) == ZN_OK, "Failed to create init channel\n");
assert(channel_create(&init_ep, &other_ep) == ZN_OK, "Failed to create init channel\n");
struct vas* init_space;
ASSERT(vma_new(&init_space) == ZN_OK, "");
assert(vma_new(&init_space) == ZN_OK, "");
struct boot_file* file_data = &info->files[0];
struct paged_vmo* init_file;
ASSERT(vmo_new_phys(&init_file) == ZN_OK, "");
assert(vmo_new_phys(&init_file) == ZN_OK, "");
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
struct namespace* ns;
ASSERT(namespace_new(&ns) == ZN_OK, "");
assert(namespace_new(&ns) == ZN_OK, "");
struct namespace_desc init_ch_desc = {
.type = NAMESPACE_DESC_CHANNEL,
@@ -91,7 +90,7 @@ static void kernel_main_task(uintptr_t arg0) {
struct task* init_task;
zn_status_t status = load_server(&info->files[0], init_argv, init_envp, &init_ch_desc, &init_task);
ASSERT(status == ZN_OK, "Failed to load init process (%i)\n", status);
assert(status == ZN_OK, "Failed to load init process (%i)\n", status);
sched_add_task(&percpu_get()->sched, init_task);
// Load other daemons.
@@ -107,16 +106,10 @@ static void kernel_main_task(uintptr_t arg0) {
struct task* task;
status = load_server(&info->files[i], argv, envp, &ch_desc, &task);
ASSERT(status == ZN_OK, "Failed to load server \"%s\": (%i)\n", info->files[i].path, status);
assert(status == ZN_OK, "Failed to load server \"%s\": (%i)\n", info->files[i].path, status);
sched_add_task(&percpu_get()->sched, task);
}
struct ipc_kernel_msg* msg = mem_alloc(0x40, 0);
msg->id = IPC_MSG_BAR;
memcpy(msg->data, "This message is from the kernel!", 33);
channel_write(other_ep, msg, 0x40, nullptr, 0);
while (true) {
arch_irq_wait();
}
@@ -140,7 +133,7 @@ void kernel_main(struct boot_info* info) {
irq_unlock();
sched_yield(&percpu_get()->sched);
__unreachable();
unreachable();
}
[[__init]]
+6 -6
View File
@@ -21,12 +21,12 @@ zn_status_t channel_create(struct channel** ep0, struct channel** ep1) {
a->peer = b;
a->lock = (struct spinlock){0};
TAILQ_INIT(&a->messages);
tailq_init(&a->messages);
wait_queue_init(&a->waiters);
b->peer = a;
b->lock = (struct spinlock){0};
TAILQ_INIT(&b->messages);
tailq_init(&b->messages);
wait_queue_init(&b->waiters);
*ep0 = a;
@@ -64,7 +64,7 @@ zn_status_t channel_write(
// Enqueue on the peer's message queue and wake a waiter.
spin_lock(&peer->lock);
TAILQ_INSERT_TAIL(&peer->messages, msg, next);
tailq_insert_tail(&peer->messages, msg, next);
spin_unlock(&peer->lock);
struct sched_percpu* sched = &percpu_get()->sched;
@@ -75,10 +75,10 @@ zn_status_t channel_write(
zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) {
spin_lock(&ch->lock);
struct channel_msg* msg = TAILQ_FIRST(&ch->messages);
struct channel_msg* msg = tailq_first(&ch->messages);
if (msg != nullptr) {
TAILQ_REMOVE(&ch->messages, msg, next);
tailq_remove(&ch->messages, msg, next);
spin_unlock(&ch->lock);
*msg_out = msg;
return ZN_OK;
@@ -97,7 +97,7 @@ zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) {
zn_status_t channel_poll(struct channel* ch) {
spin_lock(&ch->lock);
if (!TAILQ_EMPTY(&ch->messages)) {
if (!tailq_empty(&ch->messages)) {
spin_unlock(&ch->lock);
return ZN_OK;
}
+1 -1
View File
@@ -49,7 +49,7 @@ zn_status_t elf_load(struct exec_info* info, struct task** out) {
if (phdr.p_flags & PF_X)
prot |= ZN_VM_MAP_EXEC;
ASSERT(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, "");
assert(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, "");
const uintptr_t misalign = phdr.p_vaddr & (page_size - 1);
const uintptr_t map_address = phdr.p_vaddr - misalign;
+7 -7
View File
@@ -15,7 +15,7 @@ zn_status_t namespace_new(struct namespace** out) {
namespace->mutex = (struct mutex){0};
namespace->next_handle = 1;
HASHMAP_INIT(&namespace->descriptors);
hashmap_init(&namespace->descriptors);
*out = namespace;
return ZN_OK;
@@ -31,10 +31,10 @@ zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_des
handle = atomic_fetch_add_explicit(&namespace->next_handle, 1, memory_order_acq_rel);
if (handle <= ZN_HANDLE_INVALID)
continue;
} while (HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr);
} while (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr);
zn_status_t status =
HASHMAP_INSERT(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
if (status != ZN_OK)
return status;
@@ -49,10 +49,10 @@ zn_status_t namespace_add_desc_at(struct namespace* namespace, struct namespace_
return ZN_ERR_BAD_HANDLE;
// Fail if a descriptor already exists at this handle.
if (HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr)
if (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr)
return ZN_ERR_ALREADY_EXISTS;
return HASHMAP_INSERT(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
return hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
}
zn_status_t namespace_get(struct namespace* namespace, zn_handle_t handle, struct namespace_desc* out) {
@@ -65,7 +65,7 @@ zn_status_t namespace_get(struct namespace* namespace, zn_handle_t handle, struc
return ZN_ERR_BAD_HANDLE;
struct namespace_desc* desc =
HASHMAP_GET(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default);
hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default);
if (!desc)
return ZN_ERR_BAD_HANDLE;
@@ -80,7 +80,7 @@ zn_status_t namespace_del_desc(struct namespace* namespace, zn_handle_t handle)
if (handle <= ZN_HANDLE_INVALID)
return ZN_ERR_BAD_HANDLE;
if (!HASHMAP_REMOVE(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default))
if (!hashmap_remove(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default))
return ZN_ERR_BAD_HANDLE;
return ZN_OK;
+13 -13
View File
@@ -1,6 +1,5 @@
#include <zinnia/status.h>
#include <kernel/alloc.h>
#include <kernel/assert.h>
#include <kernel/irq.h>
#include <kernel/list.h>
#include <kernel/percpu.h>
@@ -8,6 +7,7 @@
#include <kernel/sched.h>
#include <kernel/spin.h>
#include <kernel/tailq.h>
#include <assert.h>
#include <bits/irq.h>
#include <stdatomic.h>
#include <stdint.h>
@@ -35,30 +35,30 @@ void sched_to_user_context(uintptr_t ctx) {
void sched_init(struct sched_percpu* sched) {
struct task* idle_task;
ASSERT(
assert(
task_create("idle", &kernel_vas, nullptr, idle_func, 0, &idle_task) == ZN_OK,
"Unable to create idle task!\n"
);
sched->idle_task = idle_task;
sched->current = idle_task;
TAILQ_INIT(&sched->run_queue);
tailq_init(&sched->run_queue);
kprintf("Scheduler initialized\n");
}
void sched_add_task(struct sched_percpu* sched, struct task* task) {
ASSERT(task != nullptr, "Tried to add NULL to the run queue\n");
TAILQ_INSERT_TAIL(&sched->run_queue, task, next);
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) {
struct task* t = TAILQ_FIRST(&sched->run_queue);
struct task* t = tailq_first(&sched->run_queue);
if (t == nullptr)
return sched->idle_task;
TAILQ_REMOVE(&sched->run_queue, t, next);
tailq_remove(&sched->run_queue, t, next);
return t;
}
@@ -143,7 +143,7 @@ void task_entry(task_fn_t entry, uintptr_t arg0) {
}
void wait_queue_init(struct wait_queue* wq) {
TAILQ_INIT(&wq->waiters);
tailq_init(&wq->waiters);
wq->lock = (struct spinlock){0};
}
@@ -152,7 +152,7 @@ void sched_block(struct sched_percpu* sched, struct wait_queue* wq) {
spin_lock(&wq->lock);
sched->current->state = TASK_STATE_BLOCKED;
TAILQ_INSERT_TAIL(&wq->waiters, sched->current, next);
tailq_insert_tail(&wq->waiters, sched->current, next);
spin_unlock(&wq->lock);
do_reschedule(sched);
@@ -161,9 +161,9 @@ void sched_block(struct sched_percpu* sched, struct wait_queue* wq) {
void sched_wake(struct sched_percpu* sched, struct wait_queue* wq) {
spin_lock(&wq->lock);
struct task* t = TAILQ_FIRST(&wq->waiters);
struct task* t = tailq_first(&wq->waiters);
if (t != nullptr) {
TAILQ_REMOVE(&wq->waiters, t, next);
tailq_remove(&wq->waiters, t, next);
t->state = TASK_STATE_READY;
sched_add_task(sched, t);
}
@@ -175,8 +175,8 @@ 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);
while ((t = tailq_first(&wq->waiters)) != nullptr) {
tailq_remove(&wq->waiters, t, next);
t->state = TASK_STATE_READY;
sched_add_task(sched, t);
}
+5 -6
View File
@@ -1,16 +1,15 @@
#include <kernel/spin.h>
#include <stdatomic.h>
// TODO: Ticketing system
void spin_lock(struct spinlock* spin) {
while (atomic_exchange_explicit(&spin->locked, true, memory_order_acquire)) {
uint32_t my = atomic_fetch_add_explicit(&spin->next, 1, memory_order_relaxed);
while (atomic_load_explicit(&spin->owner, memory_order_acquire) != my) {
asm volatile("pause");
}
atomic_store_explicit(&spin->locked, true, memory_order_release);
}
void spin_unlock(struct spinlock* spin) {
atomic_store_explicit(&spin->locked, false, memory_order_release);
uint32_t val = atomic_load_explicit(&spin->owner, memory_order_relaxed);
atomic_store_explicit(&spin->owner, val + 1, memory_order_release);
}
@@ -3,7 +3,8 @@
#include <common/compiler.h>
#include <kernel/panic.h>
#define ASSERT(expr, msg, ...) \
// Like the standard C assert, but also active in debug builds.
#define assert(expr, msg, ...) \
({ \
if (__unlikely(!(expr))) { \
panic( \
@@ -19,7 +20,7 @@
})
#ifndef NDEBUG
#define DEBUG_ASSERT(...) ASSERT(__VA_ARGS__)
#define debug_assert(...) assert(__VA_ARGS__)
#else
#define DEBUG_ASSERT(...) ((void)0)
#define debug_assert(...) ((void)0)
#endif
+2 -2
View File
@@ -13,13 +13,13 @@ struct channel_msg {
size_t num_bytes;
struct namespace_desc* descs;
size_t num_handles;
TAILQ_LINK(struct channel_msg) next;
tailq_link(struct channel_msg) next;
};
struct channel {
struct channel* peer;
struct spinlock lock;
TAILQ_HEAD(struct channel_msg) messages;
tailq_head(struct channel_msg) messages;
struct wait_queue waiters;
};
+11 -11
View File
@@ -25,7 +25,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Ensure a hash is never zero (zero is the empty sentinel).
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
#define HASHMAP(K, V) \
#define hashmap(K, V) \
struct { \
K* keys; \
V* values; \
@@ -34,7 +34,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
size_t count; \
}
#define HASHMAP_INIT(map) \
#define hashmap_init(map) \
do { \
(map)->keys = nullptr; \
(map)->values = nullptr; \
@@ -43,7 +43,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
(map)->count = 0; \
} while (0)
#define HASHMAP_DESTROY(map) \
#define hashmap_destroy(map) \
do { \
mem_free((map)->keys); \
mem_free((map)->values); \
@@ -55,7 +55,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
(map)->count = 0; \
} while (0)
#define HASHMAP_COUNT(map) ((map)->count)
#define hashmap_count(map) ((map)->count)
// Internal: probe distance from ideal position.
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1))
@@ -116,10 +116,10 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
} \
} while (0)
// Insert or update a key-value pair. Returns ZN_OK or ZN_ERR_NO_MEMORY.
#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \
// Insert or update a key-value pair. Returns 0 or ZN_ERR_NO_MEMORY.
#define hashmap_insert(map, key, val, hash_fn, eq_fn) \
({ \
zn_status_t _status = ZN_OK; \
zn_status_t _status = 0; \
typeof(*(map)->keys) _k = (key); \
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
/* Check for existing key first. */ \
@@ -147,7 +147,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
_status = ZN_ERR_NO_MEMORY; \
} \
} \
if (_status == ZN_OK) { \
if (_status == 0) { \
_HASHMAP_INSERT_INNER(map, _k, (val), _h); \
} \
} \
@@ -155,7 +155,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
})
// Look up a key. Returns a pointer to the value, or nullptr if not found.
#define HASHMAP_GET(map, key, hash_fn, eq_fn) \
#define hashmap_get(map, key, hash_fn, eq_fn) \
({ \
typeof(*(map)->values)* _result = nullptr; \
if ((map)->capacity > 0) { \
@@ -180,7 +180,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Remove a key. Returns true if the key was found and removed.
// Uses backward-shift deletion to avoid tombstones.
#define HASHMAP_REMOVE(map, key, hash_fn, eq_fn) \
#define hashmap_remove(map, key, hash_fn, eq_fn) \
({ \
bool _removed = false; \
if ((map)->capacity > 0) { \
@@ -218,6 +218,6 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
// Iterate over all occupied entries. `idx` is a size_t loop variable.
// Access keys and values via (map)->keys[idx] and (map)->values[idx].
#define HASHMAP_FOREACH(map, idx) \
#define hashmap_foreach(map, idx) \
for (size_t idx = 0; idx < (map)->capacity; idx++) \
if ((map)->hashes[idx] != 0)
+2 -2
View File
@@ -22,7 +22,7 @@ enum irq_trigger_mode : uint8_t {
struct irq_handler {
enum irq_status (*handler)(void* self);
SLIST_LINK(struct irq_handler*) next;
list_link(struct irq_handler*) next;
};
struct irq_line {
@@ -31,7 +31,7 @@ struct irq_line {
void (*unmask)(struct irq_line* self);
void (*eoi)(struct irq_line* self);
SLIST_HEAD(struct irq_handler*) handlers;
list_head(struct irq_handler*) handlers;
bool is_busy;
};
+14 -14
View File
@@ -1,29 +1,29 @@
#pragma once
#define SLIST_HEAD(type) \
#define list_head(type) \
struct { \
type sl_head; \
type _sl_head; \
}
#define SLIST_LINK(type) \
#define list_link(type) \
struct { \
type sl_link; \
type _sl_link; \
}
#define SLIST_EMPTY(head) ((head)->sl_head == NULL)
#define SLIST_FIRST(head) ((head)->sl_head)
#define SLIST_NEXT(elm, field) ((elm)->field.sl_link)
#define list_is_empty(head) ((head)->_sl_head == NULL)
#define list_first(head) ((head)->_sl_head)
#define list_next(elm, field) ((elm)->field._sl_link)
#define SLIST_INSERT_END(slistelm, elm, field) \
#define list_insert_end(slistelm, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
list_next((elm), field) = list_next((slistelm), field); \
list_next((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) \
#define list_insert_head(head, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
list_next((elm), field) = list_first((head)); \
list_first((head)) = (elm); \
} while (0)
#define SLIST_FOREACH(var, head, field) for ((var) = SLIST_FIRST((head)); (var); (var) = SLIST_NEXT((var), field))
#define list_foreach(var, head, field) for ((var) = list_first((head)); (var); (var) = list_next((var), field))
+1 -1
View File
@@ -32,7 +32,7 @@ struct namespace_desc {
struct namespace {
zn_handle_t next_handle;
struct mutex mutex;
HASHMAP(zn_handle_t, struct namespace_desc) descriptors;
hashmap(zn_handle_t, struct namespace_desc) descriptors;
};
// Creates a new namespace with no contents.
+2 -2
View File
@@ -38,7 +38,7 @@ struct task {
size_t time_slice;
int8_t priority;
TAILQ_LINK(struct task) next;
tailq_link(struct task) next;
};
// Per-CPU data for scheduling.
@@ -46,7 +46,7 @@ struct sched_percpu {
struct task* current;
struct task* idle_task;
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.
+4 -1
View File
@@ -1,9 +1,12 @@
#pragma once
#include <stdint.h>
// Busy-waits in a loop until the lock is freed.
// Does not put the CPU to sleep.
struct spinlock {
bool locked;
uint32_t owner;
uint32_t next;
};
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
+9 -9
View File
@@ -1,30 +1,30 @@
#pragma once
#define TAILQ_HEAD(type) \
#define tailq_head(type) \
struct { \
type* tqh_first; \
type** tqh_last; \
}
#define TAILQ_LINK(type) \
#define tailq_link(type) \
struct { \
type* tqe_next; \
type** tqe_prev; \
}
#define TAILQ_INIT(head) \
#define tailq_init(head) \
do { \
(head)->tqh_first = nullptr; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define tailq_first(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define tailq_next(elm, field) ((elm)->field.tqe_next)
#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == nullptr)
#define tailq_empty(head) (tailq_first(head) == nullptr)
#define TAILQ_INSERT_TAIL(head, elm, field) \
#define tailq_insert_tail(head, elm, field) \
do { \
(elm)->field.tqe_next = nullptr; \
(elm)->field.tqe_prev = (head)->tqh_last; \
@@ -32,7 +32,7 @@
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) \
#define tailq_insert_head(head, elm, field) \
do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != nullptr) \
(head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
@@ -42,7 +42,7 @@
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) \
#define tailq_remove(head, elm, field) \
do { \
if (((elm)->field.tqe_next) != nullptr) \
(elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
+25 -26
View File
@@ -1,25 +1,24 @@
#pragma once
#include <zinnia/status.h>
#include <kernel/alloc.h>
#include <stddef.h>
#include <string.h>
#include <stddef.h> // IWYU pragma: keep
#include <string.h> // IWYU pragma: keep
#define VEC(T) \
#define vec(T) \
struct { \
T* data; \
size_t length; \
size_t capacity; \
}
#define VEC_INIT(vec) \
#define vec_init(vec) \
do { \
(vec)->data = nullptr; \
(vec)->length = 0; \
(vec)->capacity = 0; \
} while (0)
#define VEC_DESTROY(vec) \
#define vec_destroy(vec) \
do { \
mem_free((vec)->data); \
(vec)->data = nullptr; \
@@ -27,13 +26,13 @@
(vec)->capacity = 0; \
} while (0)
#define VEC_LENGTH(vec) ((vec)->length)
#define VEC_CAPACITY(vec) ((vec)->capacity)
#define VEC_EMPTY(vec) ((vec)->length == 0)
#define VEC_AT(vec, i) ((vec)->data[i])
#define vec_length(vec) ((vec)->length)
#define vec_capacity(vec) ((vec)->capacity)
#define vec_empty(vec) ((vec)->length == 0)
#define vec_at(vec, i) ((vec)->data[i])
// Internal: grow to at least `needed` capacity.
#define _VEC_GROW(vec, needed) \
#define _vec_grow(vec, needed) \
do { \
size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \
while (_new_cap < (needed)) \
@@ -46,34 +45,34 @@
(vec)->capacity = _new_cap; \
} while (0)
// Append an element. Returns ZN_OK or ZN_ERR_NO_MEMORY.
#define VEC_PUSH(vec, val) \
// Append an element. Returns 0 or ZN_ERR_NO_MEMORY.
#define vec_push(vec, val) \
({ \
zn_status_t _status = ZN_OK; \
zn_status_t _status = 0; \
if ((vec)->length >= (vec)->capacity) { \
_VEC_GROW(vec, (vec)->length + 1); \
_vec_grow(vec, (vec)->length + 1); \
if ((vec)->data == nullptr) \
_status = ZN_ERR_NO_MEMORY; \
} \
if (_status == ZN_OK) \
if (_status == 0) \
(vec)->data[(vec)->length++] = (val); \
_status; \
})
// Remove and return the last element. Undefined if empty.
#define VEC_POP(vec) ((vec)->data[--(vec)->length])
#define vec_pop(vec) ((vec)->data[--(vec)->length])
// Insert at index, shifting subsequent elements right. Returns ZN_OK or ZN_ERR_NO_MEMORY.
#define VEC_INSERT(vec, i, val) \
// Insert at index, shifting subsequent elements right. Returns 0 or ZN_ERR_NO_MEMORY.
#define vec_insert(vec, i, val) \
({ \
zn_status_t _status = ZN_OK; \
zn_status_t _status = 0; \
size_t _idx = (i); \
if ((vec)->length >= (vec)->capacity) { \
_VEC_GROW(vec, (vec)->length + 1); \
_vec_grow(vec, (vec)->length + 1); \
if ((vec)->data == nullptr) \
_status = ZN_ERR_NO_MEMORY; \
} \
if (_status == ZN_OK) { \
if (_status == 0) { \
memmove(&(vec)->data[_idx + 1], &(vec)->data[_idx], ((vec)->length - _idx) * sizeof(*(vec)->data)); \
(vec)->data[_idx] = (val); \
(vec)->length++; \
@@ -82,7 +81,7 @@
})
// Remove element at index, shifting subsequent elements left.
#define VEC_REMOVE(vec, i) \
#define vec_remove(vec, i) \
do { \
size_t _idx = (i); \
(vec)->length--; \
@@ -91,7 +90,7 @@
} while (0)
// Remove element at index by swapping with the last element (O(1), unordered).
#define VEC_SWAP_REMOVE(vec, i) \
#define vec_swap_remove(vec, i) \
do { \
size_t _idx = (i); \
(vec)->length--; \
@@ -100,6 +99,6 @@
} while (0)
// Clear all elements without freeing memory.
#define VEC_CLEAR(vec) ((vec)->length = 0)
#define vec_clear(vec) ((vec)->length = 0)
#define VEC_FOREACH(vec, idx) for (size_t idx = 0; idx < (vec)->length; idx++)
#define vec_foreach(vec, idx) for (size_t idx = 0; idx < (vec)->length; idx++)
+2 -2
View File
@@ -30,13 +30,13 @@ struct pager_ops {
struct page_list {
uintptr_t offset;
struct page* value;
SLIST_LINK(struct page_list*) next;
list_link(struct page_list*) next;
};
struct paged_vmo {
struct vmo object;
struct pager_ops source;
SLIST_HEAD(struct page_list*) cache;
list_head(struct page_list*) cache;
struct spinlock lock;
};
+1 -1
View File
@@ -7,7 +7,7 @@ struct task;
// A queue of tasks waiting for an event.
struct wait_queue {
TAILQ_HEAD(struct task) waiters;
tailq_head(struct task) waiters;
struct spinlock lock;
};
+1 -4
View File
@@ -1,10 +1,7 @@
#ifndef ZINNIA_STDARG_H
#define ZINNIA_STDARG_H
#pragma once
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, T) __builtin_va_arg(v, T)
#define va_copy(d, s) __builtin_va_copy(d, s)
#endif
+1 -4
View File
@@ -1,5 +1,4 @@
#ifndef ZINNIA_STDATOMIC_H
#define ZINNIA_STDATOMIC_H
#pragma once
typedef enum memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
@@ -35,5 +34,3 @@ typedef enum memory_order {
#define atomic_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST)
#define atomic_thread_fence(ord) __atomic_thread_fence(ord)
#endif
+2 -4
View File
@@ -1,9 +1,7 @@
#ifndef ZINNIA_STDDEF_H
#define ZINNIA_STDDEF_H
#pragma once
typedef unsigned long size_t;
typedef signed long ssize_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
#define unreachable() __builtin_unreachable()
+1 -4
View File
@@ -1,5 +1,4 @@
#ifndef ZINNIA_STDINT_H
#define ZINNIA_STDINT_H
#pragma once
typedef __INT8_TYPE__ int8_t;
typedef __UINT8_TYPE__ uint8_t;
@@ -25,5 +24,3 @@ typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
#define INTPTR_MAX __INTPTR_MAX__
#define UINTPTR_MAX __UINTPTR_MAX__
#endif
+1 -4
View File
@@ -1,7 +1,4 @@
#ifndef ZINNIA_STDLIB_H
#define ZINNIA_STDLIB_H
#pragma once
long atol(const char* str, int base);
unsigned long atolu(const char* str, int base);
#endif
+1 -4
View File
@@ -1,5 +1,4 @@
#ifndef ZINNIA_STRING_H
#define ZINNIA_STRING_H
#pragma once
#include <stddef.h>
@@ -13,5 +12,3 @@ char* strncpy(char* restrict dst, const char* restrict src, size_t len);
int strcmp(const char* str1, const char* str2);
int strncmp(const char* str1, const char* str2, size_t len);
char* strchr(const char* c, int s);
#endif
+7 -7
View File
@@ -1,11 +1,11 @@
#include <common/utils.h>
#include <kernel/alloc.h>
#include <kernel/assert.h>
#include <kernel/init.h>
#include <kernel/panic.h>
#include <kernel/print.h>
#include <kernel/vas.h>
#include <kernel/virt.h>
#include <assert.h>
#include <string.h>
extern uint8_t __ld_text_start[];
@@ -66,7 +66,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
// since we're likely going to map it at a different base address.
mem_hhdm_base = tmp_hhdm;
ASSERT(pmap_new_kernel(&kernel_vas.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
assert(pmap_new_kernel(&kernel_vas.pmap, 0) == 0, "Unable to allocate the kernel page table\n");
// text
kprintf("Mapping text segment at %p\n", __ld_text_start);
@@ -78,7 +78,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
PTE_READ | PTE_EXEC,
CACHE_NONE
);
ASSERT(!status, "Failed to map %p with error %i\n", p, status);
assert(!status, "Failed to map %p with error %i\n", p, status);
}
// rodata
@@ -91,7 +91,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
PTE_READ,
CACHE_NONE
);
ASSERT(!status, "Failed to map %p with error %i\n", p, status);
assert(!status, "Failed to map %p with error %i\n", p, status);
}
// data
@@ -104,7 +104,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
PTE_READ | PTE_WRITE,
CACHE_NONE
);
ASSERT(!status, "Failed to map %p with error %i\n", p, status);
assert(!status, "Failed to map %p with error %i\n", p, status);
}
// The kernel address space is divided into 3 segments (plus kernel).
@@ -122,7 +122,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm);
phys_t paddr = (phys_t)(map[i].address + p);
zn_status_t status = pmap_map(&kernel_vas.pmap, vaddr, paddr, PTE_READ | PTE_WRITE, CACHE_NONE);
ASSERT(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status);
assert(!status, "Failed to map HHDM page %p to %p with error %i\n", (void*)vaddr, (void*)paddr, status);
}
}
mem_hhdm_base = tmp_hhdm;
@@ -150,7 +150,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
for (size_t page = 0; page < length; page += pgsz) {
phys_t paddr;
ASSERT(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n");
assert(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n");
pmap_map(&kernel_vas.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_NONE);
}
}
+1 -1
View File
@@ -6,6 +6,6 @@ kernel_sources += files(
'slab.c',
'usercopy.c',
'virt.c',
'vas.c',
'vma.c',
'vmo.c',
)
+2 -2
View File
@@ -1,12 +1,12 @@
#include <zinnia/status.h>
#include <common/utils.h>
#include <kernel/alloc.h>
#include <kernel/assert.h>
#include <kernel/vas.h>
#include <assert.h>
// Try to create a new, empty virtual address space.
zn_status_t vma_new(struct vas** out) {
DEBUG_ASSERT(out != nullptr, "Missing out");
debug_assert(out != nullptr, "Missing out");
zn_status_t res;
if (!out)
+2 -2
View File
@@ -105,7 +105,7 @@ static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct
// Try to find the requested page in the cache.
struct page_list* iter;
SLIST_FOREACH(iter, &paged->cache, next) {
list_foreach(iter, &paged->cache, next) {
if (iter->offset != offset_idx)
continue;
@@ -128,7 +128,7 @@ static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct
entry->value = new_page;
// Add page to the object cache.
SLIST_INSERT_HEAD(&paged->cache, entry, next);
list_insert_head(&paged->cache, entry, next);
*out = new_page;
return ZN_OK;
+3 -3
View File
@@ -33,12 +33,12 @@ static const syscall_fn_t dispatch_table[] = {
};
void syscall_dispatch(struct arch_context* ctx) {
const size_t num = ctx->ARCH_CTX_NUM;
const size_t num = ctx->num;
if (num >= ARRAY_SIZE(dispatch_table)) {
ctx->ARCH_CTX_RET0 = ZN_ERR_BAD_SYSCALL;
ctx->ret0 = ZN_ERR_BAD_SYSCALL;
return;
}
ctx->ARCH_CTX_RET0 = dispatch_table[num](ctx);
ctx->ret0 = dispatch_table[num](ctx);
}
+2 -1
View File
@@ -10,6 +10,7 @@
#include <kernel/sched.h>
#include <kernel/syscalls.h>
#include <kernel/usercopy.h>
#include <stddef.h>
#include <string.h>
zn_status_t syscall_thread_create(struct arch_context* ctx) {
@@ -114,5 +115,5 @@ zn_status_t syscall_thread_exit(struct arch_context* ctx) {
struct sched_percpu* sched = &percpu_get()->sched;
sched->current->state = TASK_STATE_DEAD;
sched_yield(sched);
__unreachable();
unreachable();
}
+1 -1
View File
@@ -1,7 +1,7 @@
project(
'zinnia',
license: 'MIT',
version: '0.1.0',
version: '0.3.0',
meson_version: '>=1.1.0',
default_options: [
'c_std=gnu23',
+1 -2
View File
@@ -1,6 +1,5 @@
#include <zinnia/channel.h>
#include <zinnia/handle.h>
#include <zinnia/ipc/init.h>
#include <zinnia/system.h>
#include <common/compiler.h>
#include <stdio.h>
@@ -22,7 +21,7 @@ static void zn_printf(const char* msg, ...) {
int main(int argc, char* argv[], char* envp[]) {
zn_printf("devd: starting...\n");
zn_handle_t channel = getauxval(AT_INIT_HANDLE);
zn_handle_t channel = getauxval(0x1000);
// while (true) {}
uacpi_status status = uacpi_initialize(0);
+4 -24
View File
@@ -1,6 +1,5 @@
#include <zinnia/channel.h>
#include <zinnia/handle.h>
#include <zinnia/ipc/init.h>
#include <zinnia/mem.h>
#include <zinnia/status.h>
#include <zinnia/system.h>
@@ -12,6 +11,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
#include <unistd.h>
#define ZN_ASSERT(expr) \
do { \
@@ -31,38 +31,18 @@ static void zn_printf(const char* msg, ...) {
int32_t len = vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
zn_log(buf, len);
write(1, buf, len);
// zn_log(buf, len);
}
int main(int argc, char* argv[], char* envp[]) {
zn_printf("initd: starting...\n");
zn_handle_t channel = getauxval(AT_INIT_HANDLE);
zn_handle_t channel = getauxval(0x1000);
while (true) {
static thread_local zn_handle_t handles[32];
static thread_local char buf[1024];
ZN_ASSERT(zn_channel_read(channel, handles, buf, ARRAY_SIZE(handles), ARRAY_SIZE(buf), nullptr, nullptr));
enum ipc_msg_id* msg = (enum ipc_msg_id*)buf;
switch (*msg) {
case IPC_MSG_FOO: {
struct ipc_init_register_rq* foo = (struct ipc_init_register_rq*)msg;
char buf[32] = {0};
IPC_GET_STRING(foo->data, &foo->name, buf);
zn_printf("initd: ipc_init_register_rq, peer = \"%s\"\n", buf);
} break;
case IPC_MSG_BAR: {
struct ipc_kernel_msg* foo = (struct ipc_kernel_msg*)msg;
char buf[32] = {0};
IPC_GET_STRING(foo->data, &foo->name, buf);
zn_printf("initd: ipc_kernel_msg, msg = \"%s\"\n", buf);
} break;
case IPC_MSG_BAZ:
break;
}
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
subdir('initd')
subdir('devd')
subdir('posixd')
subdir('unix')
+20 -14
View File
@@ -1,6 +1,5 @@
#include <zinnia/channel.h>
#include <zinnia/handle.h>
#include <zinnia/ipc/init.h>
#include <zinnia/mem.h>
#include <zinnia/status.h>
#include <zinnia/system.h>
@@ -29,38 +28,45 @@ static void zn_printf(const char* msg, ...) {
zn_handle_t channel;
int other_fn(void* arg) {
zn_printf("posixd: Hello from the other thread named \"%s\"!\n", (const char*)arg);
channel = getauxval(AT_INIT_HANDLE);
struct ipc_init_register_rq msg = {
.id = IPC_MSG_FOO,
struct message {
size_t id;
};
#define MSG_HI \
IPC_START \
IPC_STRING \
IPC_END
int other_fn(void* arg) {
zn_printf("unix: Hello from the other thread named \"%s\"!\n", (const char*)arg);
channel = getauxval(0x1000);
struct message msg = {.id = 1};
char name[] = "posixd";
zn_status_t status = zn_channel_write(channel, nullptr, &msg, 0, sizeof(msg) + sizeof(name));
if (status != ZN_OK) {
zn_printf("posixd: %s\n", zn_status_to_string(status));
zn_printf("unix: %s\n", zn_status_to_string(status));
}
return 69;
}
int main(int argc, char* argv[], char* envp[]) {
zn_printf("posixd: starting...\n");
const char* thread_name = "posix_second_thread";
zn_printf("unix: starting...\n");
const char* thread_name = "unix_second_thread";
thrd_t thread;
int res = thrd_create(&thread, other_fn, (void*)thread_name);
if (res != thrd_success)
zn_printf("posixd: errno: %s\n", strerror(errno));
zn_printf("posixd: second thread created\n");
zn_printf("unix: errno: %s\n", strerror(errno));
zn_printf("unix: second thread created\n");
int res2;
zn_printf("posixd: waiting on second thread...\n");
zn_printf("unix: waiting on second thread...\n");
thrd_join(thread, &res2);
zn_printf("posixd: second thread exited with: %i\n", res2);
zn_printf("unix: second thread exited with: %i\n", res2);
return 0;
}
@@ -1,7 +1,7 @@
configure_file(configuration: cfg, output: 'config.h')
executable(
'posixd',
'unix',
'main.c',
'uname.c',
link_args: '-static',
View File