stuff2
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// These hints may improve code generation, but are optional and can be stubbed.
|
// Attributes that affect data layout.
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#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 __cold gnu::cold
|
||||||
#define __hot gnu::hot
|
#define __hot gnu::hot
|
||||||
#define __used gnu::used
|
#define __used gnu::used
|
||||||
@@ -9,17 +14,6 @@
|
|||||||
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
|
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
|
||||||
#define __likely(x) __builtin_expect(!!(x), 1)
|
#define __likely(x) __builtin_expect(!!(x), 1)
|
||||||
#define __unlikely(x) __builtin_expect(!!(x), 0)
|
#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.
|
// Only clang has these hints, GCC will throw a warning here.
|
||||||
// They also don't support the C23 attribute format.
|
// They also don't support the C23 attribute format.
|
||||||
@@ -30,18 +24,3 @@
|
|||||||
#define __user
|
#define __user
|
||||||
#define __phys
|
#define __phys
|
||||||
#endif
|
#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
@@ -2,37 +2,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#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'};
|
constexpr char ELF_MAG[4] = {0x7F, 'E', 'L', 'F'};
|
||||||
|
|
||||||
typedef uint64_t elf64_addr_t;
|
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) {
|
static inline uint32_t ELF64_R_TYPE(uint64_t info) {
|
||||||
return info & 0xFFFFFFFF;
|
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,6 +3,7 @@
|
|||||||
|
|
||||||
#include <zinnia/status.h>
|
#include <zinnia/status.h>
|
||||||
#include <zinnia/syscall_stubs.h>
|
#include <zinnia/syscall_stubs.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -10,12 +11,12 @@ extern "C" {
|
|||||||
|
|
||||||
// Blocks the calling thread if *addr == expected.
|
// Blocks the calling thread if *addr == expected.
|
||||||
// Returns immediately if the value at addr has changed.
|
// 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);
|
return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wakes up to `count` threads waiting on the given futex address.
|
// 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);
|
return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ static inline zn_status_t zn_handle_validate(zn_handle_t handle) {
|
|||||||
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE);
|
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drops an object handle.
|
// Drops an object handle. All further references using this handle are invalid.
|
||||||
// All further references using this handle are invalid. The numerical value
|
// The numerical value may become valid again, but it is an error to keep using it.
|
||||||
// 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.
|
// The underlying object gets freed only once no other handle references it.
|
||||||
static inline zn_status_t zn_handle_drop(zn_handle_t handle) {
|
static inline zn_status_t zn_handle_drop(zn_handle_t handle) {
|
||||||
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_DROP);
|
return zn_syscall1(handle, ZN_SYSCALL_HANDLE_DROP);
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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[];
|
|
||||||
};
|
|
||||||
@@ -25,7 +25,7 @@ enum zn_vm_flags {
|
|||||||
// Map at a fixed address, replacing whatever is in the way.
|
// Map at a fixed address, replacing whatever is in the way.
|
||||||
ZN_VM_MAP_FIXED = 1 << 8,
|
ZN_VM_MAP_FIXED = 1 << 8,
|
||||||
// Map at a fixed address, failing if anything is in the way.
|
// 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.
|
// Map the entire range immediately.
|
||||||
ZN_VM_MAP_POPULATE = 1 << 10,
|
ZN_VM_MAP_POPULATE = 1 << 10,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ static inline zn_status_t zn_ns_create(zn_handle_t* out) {
|
|||||||
return ZN_ERR_UNSUPPORTED;
|
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;
|
return ZN_ERR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -45,7 +45,7 @@ void lapic_init(struct local_apic* lapic) {
|
|||||||
apic_msr |= 1 << 10;
|
apic_msr |= 1 << 10;
|
||||||
else {
|
else {
|
||||||
lapic->xapic_regs = mmio_new(apic_msr & 0xFFFF'F000, 0x1000);
|
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);
|
asm_wrmsr(0x1B, apic_msr);
|
||||||
@@ -86,18 +86,18 @@ void lapic_eoi(struct local_apic* lapic) {
|
|||||||
#define PIC2_DATA_PORT 0xA1
|
#define PIC2_DATA_PORT 0xA1
|
||||||
|
|
||||||
void pic_disable() {
|
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.
|
// 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_COMMAND_PORT, 0x11);
|
||||||
asm_outb(PIC1_DATA_PORT, 0x20); // ICW2: Set where interrupts should be mapped to (0x20-0x27).
|
asm_outb(PIC1_DATA_PORT, 0x20);
|
||||||
asm_outb(PIC1_DATA_PORT, 0x04); // ICW3: Connect IRQ2 (0x04) to the slave PIC.
|
asm_outb(PIC1_DATA_PORT, 0x04);
|
||||||
asm_outb(PIC1_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode.
|
asm_outb(PIC1_DATA_PORT, 0x01);
|
||||||
asm_outb(PIC1_DATA_PORT, 0xFF); // Mask all interrupts.
|
asm_outb(PIC1_DATA_PORT, 0xFF);
|
||||||
|
|
||||||
// Same for the slave PIC.
|
// Same for the slave PIC.
|
||||||
asm_outb(PIC2_COMMAND_PORT, 0x11); // ICW1: Begin initialization.
|
asm_outb(PIC2_COMMAND_PORT, 0x11);
|
||||||
asm_outb(PIC2_DATA_PORT, 0x28); // ICW2: Set where interrupts should be mapped to (0x28-0x2F).
|
asm_outb(PIC2_DATA_PORT, 0x28);
|
||||||
asm_outb(PIC2_DATA_PORT, 0x02); // ICW3: Connect to master PIC at IRQ2.
|
asm_outb(PIC2_DATA_PORT, 0x02);
|
||||||
asm_outb(PIC2_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode.
|
asm_outb(PIC2_DATA_PORT, 0x01);
|
||||||
asm_outb(PIC2_DATA_PORT, 0xFF); // Mask all interrupts.
|
asm_outb(PIC2_DATA_PORT, 0xFF);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ static const struct gdt main_gdt = {
|
|||||||
.user_code64 = {.val = 0x00a0fb0000000000},
|
.user_code64 = {.val = 0x00a0fb0000000000},
|
||||||
.tss = {
|
.tss = {
|
||||||
.limit0 = sizeof(struct tss) - 1,
|
.limit0 = sizeof(struct tss) - 1,
|
||||||
.access = 0x89, // Present | DPL=0 | System | 64-bit TSS
|
.access = 0x89, // Present | DPL = 0 | System | 64-bit TSS
|
||||||
.limit1_flags = ((sizeof(struct tss) - 1) >> 16) & 0x0F,
|
.limit1_flags = ((sizeof(struct tss) - 1) >> 16) & 0x0F,
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ void hpet_init() {
|
|||||||
|
|
||||||
uacpi_setup_early_table_access(table_buf, sizeof(table_buf));
|
uacpi_setup_early_table_access(table_buf, sizeof(table_buf));
|
||||||
uacpi_table table = {0};
|
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;
|
struct acpi_hpet* hpet = table.ptr;
|
||||||
hpet_clock.regs = mmio_new(hpet->address.address, 0x1000);
|
hpet_clock.regs = mmio_new(hpet->address.address, 0x1000);
|
||||||
@@ -65,5 +65,5 @@ void hpet_init() {
|
|||||||
uint64_t caps = hpet_clock.regs[HPET_CAP];
|
uint64_t caps = hpet_clock.regs[HPET_CAP];
|
||||||
hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF;
|
hpet_clock.period = (caps >> 32) & 0xFFFF'FFFF;
|
||||||
|
|
||||||
ASSERT(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
|
assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void interrupt_handler(struct arch_context* ctx) {
|
|||||||
break;
|
break;
|
||||||
case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)):
|
case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)):
|
||||||
struct irq_line* line = cpu->arch.irq_lines[isr - 0x20];
|
struct irq_line* line = cpu->arch.irq_lines[isr - 0x20];
|
||||||
ASSERT(line, "Unhandled interrupt on ISR %lu\n", isr);
|
assert(line, "Unhandled interrupt on ISR %lu\n", isr);
|
||||||
// TODO: irq_raise(line);
|
// TODO: irq_raise(line);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -10,22 +10,27 @@ struct arch_task_context {
|
|||||||
uint64_t fs_base, gs_base;
|
uint64_t fs_base, gs_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ARCH_ABI(typ, reg, ...) \
|
||||||
|
union { \
|
||||||
|
typ reg, __VA_ARGS__; \
|
||||||
|
}
|
||||||
|
|
||||||
struct arch_context {
|
struct arch_context {
|
||||||
uint64_t r15;
|
uint64_t r15;
|
||||||
uint64_t r14;
|
uint64_t r14;
|
||||||
uint64_t r13;
|
ARCH_ABI(uint64_t, r13, a7);
|
||||||
uint64_t r12;
|
ARCH_ABI(uint64_t, r12, a6);
|
||||||
uint64_t r11;
|
uint64_t r11;
|
||||||
uint64_t r10;
|
ARCH_ABI(uint64_t, r10, a5);
|
||||||
uint64_t r9;
|
ARCH_ABI(uint64_t, r9, a3);
|
||||||
uint64_t r8;
|
ARCH_ABI(uint64_t, r8, a4);
|
||||||
uint64_t rsi;
|
ARCH_ABI(uint64_t, rsi, a1);
|
||||||
uint64_t rdi;
|
ARCH_ABI(uint64_t, rdi, a0);
|
||||||
uint64_t rbp;
|
uint64_t rbp;
|
||||||
uint64_t rdx;
|
ARCH_ABI(uint64_t, rdx, a2, ret1);
|
||||||
uint64_t rcx;
|
uint64_t rcx;
|
||||||
uint64_t rbx;
|
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 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 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.
|
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;
|
uint64_t ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(struct arch_context) == 176);
|
||||||
|
|
||||||
#define ARCH_CTX_NUM rax
|
#define ARCH_CTX_NUM rax
|
||||||
#define ARCH_CTX_A0 rdi
|
#define ARCH_CTX_A0 rdi
|
||||||
#define ARCH_CTX_A1 rsi
|
#define ARCH_CTX_A1 rsi
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
// The task frame consists of registers that the C ABI marks as callee-saved.
|
// 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.
|
// If we don't save them, these registers are lost during a context switch.
|
||||||
// The order of these fields is important.
|
|
||||||
struct task_frame {
|
struct task_frame {
|
||||||
uint64_t rbx, rbp, r12, r13, r14, r15, rip;
|
uint64_t rbx, rbp, r12, r13, r14, r15, rip;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ static const struct usercopy_region read_region = {
|
|||||||
.fault_ip = x86_64_read_fault,
|
.fault_ip = x86_64_read_fault,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[__naked]]
|
||||||
bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region) {
|
bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region) {
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"stac\n"
|
"stac\n"
|
||||||
@@ -41,7 +42,6 @@ bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct us
|
|||||||
: "i"(&read_region)
|
: "i"(&read_region)
|
||||||
: "memory"
|
: "memory"
|
||||||
);
|
);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void x86_64_write_start();
|
extern void x86_64_write_start();
|
||||||
@@ -54,6 +54,7 @@ static const struct usercopy_region write_region = {
|
|||||||
.fault_ip = x86_64_write_fault,
|
.fault_ip = x86_64_write_fault,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[__naked]]
|
||||||
bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region) {
|
bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region) {
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"stac\n"
|
"stac\n"
|
||||||
@@ -84,7 +85,6 @@ bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct u
|
|||||||
: "i"(&read_region)
|
: "i"(&read_region)
|
||||||
: "memory"
|
: "memory"
|
||||||
);
|
);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void x86_64_strlen_start();
|
extern void x86_64_strlen_start();
|
||||||
|
|||||||
+8
-15
@@ -1,4 +1,3 @@
|
|||||||
#include <zinnia/ipc/init.h>
|
|
||||||
#include <common/compiler.h>
|
#include <common/compiler.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <kernel/assert.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;
|
struct boot_info* info = (struct boot_info*)arg0;
|
||||||
kprintf("%s\n", zinnia_banner); // Say hello!
|
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* init_ep;
|
||||||
struct channel* other_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;
|
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 boot_file* file_data = &info->files[0];
|
||||||
struct paged_vmo* init_file;
|
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);
|
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
||||||
|
|
||||||
struct namespace* ns;
|
struct namespace* ns;
|
||||||
ASSERT(namespace_new(&ns) == ZN_OK, "");
|
assert(namespace_new(&ns) == ZN_OK, "");
|
||||||
|
|
||||||
struct namespace_desc init_ch_desc = {
|
struct namespace_desc init_ch_desc = {
|
||||||
.type = NAMESPACE_DESC_CHANNEL,
|
.type = NAMESPACE_DESC_CHANNEL,
|
||||||
@@ -91,7 +90,7 @@ static void kernel_main_task(uintptr_t arg0) {
|
|||||||
|
|
||||||
struct task* init_task;
|
struct task* init_task;
|
||||||
zn_status_t status = load_server(&info->files[0], init_argv, init_envp, &init_ch_desc, &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);
|
sched_add_task(&percpu_get()->sched, init_task);
|
||||||
|
|
||||||
// Load other daemons.
|
// Load other daemons.
|
||||||
@@ -107,16 +106,10 @@ static void kernel_main_task(uintptr_t arg0) {
|
|||||||
|
|
||||||
struct task* task;
|
struct task* task;
|
||||||
status = load_server(&info->files[i], argv, envp, &ch_desc, &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);
|
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) {
|
while (true) {
|
||||||
arch_irq_wait();
|
arch_irq_wait();
|
||||||
}
|
}
|
||||||
@@ -140,7 +133,7 @@ void kernel_main(struct boot_info* info) {
|
|||||||
irq_unlock();
|
irq_unlock();
|
||||||
sched_yield(&percpu_get()->sched);
|
sched_yield(&percpu_get()->sched);
|
||||||
|
|
||||||
__unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[__init]]
|
[[__init]]
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ zn_status_t channel_create(struct channel** ep0, struct channel** ep1) {
|
|||||||
|
|
||||||
a->peer = b;
|
a->peer = b;
|
||||||
a->lock = (struct spinlock){0};
|
a->lock = (struct spinlock){0};
|
||||||
TAILQ_INIT(&a->messages);
|
tailq_init(&a->messages);
|
||||||
wait_queue_init(&a->waiters);
|
wait_queue_init(&a->waiters);
|
||||||
|
|
||||||
b->peer = a;
|
b->peer = a;
|
||||||
b->lock = (struct spinlock){0};
|
b->lock = (struct spinlock){0};
|
||||||
TAILQ_INIT(&b->messages);
|
tailq_init(&b->messages);
|
||||||
wait_queue_init(&b->waiters);
|
wait_queue_init(&b->waiters);
|
||||||
|
|
||||||
*ep0 = a;
|
*ep0 = a;
|
||||||
@@ -64,7 +64,7 @@ zn_status_t channel_write(
|
|||||||
|
|
||||||
// Enqueue on the peer's message queue and wake a waiter.
|
// Enqueue on the peer's message queue and wake a waiter.
|
||||||
spin_lock(&peer->lock);
|
spin_lock(&peer->lock);
|
||||||
TAILQ_INSERT_TAIL(&peer->messages, msg, next);
|
tailq_insert_tail(&peer->messages, msg, next);
|
||||||
spin_unlock(&peer->lock);
|
spin_unlock(&peer->lock);
|
||||||
|
|
||||||
struct sched_percpu* sched = &percpu_get()->sched;
|
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) {
|
zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) {
|
||||||
spin_lock(&ch->lock);
|
spin_lock(&ch->lock);
|
||||||
struct channel_msg* msg = TAILQ_FIRST(&ch->messages);
|
struct channel_msg* msg = tailq_first(&ch->messages);
|
||||||
|
|
||||||
if (msg != nullptr) {
|
if (msg != nullptr) {
|
||||||
TAILQ_REMOVE(&ch->messages, msg, next);
|
tailq_remove(&ch->messages, msg, next);
|
||||||
spin_unlock(&ch->lock);
|
spin_unlock(&ch->lock);
|
||||||
*msg_out = msg;
|
*msg_out = msg;
|
||||||
return ZN_OK;
|
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) {
|
zn_status_t channel_poll(struct channel* ch) {
|
||||||
spin_lock(&ch->lock);
|
spin_lock(&ch->lock);
|
||||||
|
|
||||||
if (!TAILQ_EMPTY(&ch->messages)) {
|
if (!tailq_empty(&ch->messages)) {
|
||||||
spin_unlock(&ch->lock);
|
spin_unlock(&ch->lock);
|
||||||
return ZN_OK;
|
return ZN_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ zn_status_t elf_load(struct exec_info* info, struct task** out) {
|
|||||||
if (phdr.p_flags & PF_X)
|
if (phdr.p_flags & PF_X)
|
||||||
prot |= ZN_VM_MAP_EXEC;
|
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 misalign = phdr.p_vaddr & (page_size - 1);
|
||||||
const uintptr_t map_address = phdr.p_vaddr - misalign;
|
const uintptr_t map_address = phdr.p_vaddr - misalign;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ zn_status_t namespace_new(struct namespace** out) {
|
|||||||
|
|
||||||
namespace->mutex = (struct mutex){0};
|
namespace->mutex = (struct mutex){0};
|
||||||
namespace->next_handle = 1;
|
namespace->next_handle = 1;
|
||||||
HASHMAP_INIT(&namespace->descriptors);
|
hashmap_init(&namespace->descriptors);
|
||||||
|
|
||||||
*out = namespace;
|
*out = namespace;
|
||||||
return ZN_OK;
|
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);
|
handle = atomic_fetch_add_explicit(&namespace->next_handle, 1, memory_order_acq_rel);
|
||||||
if (handle <= ZN_HANDLE_INVALID)
|
if (handle <= ZN_HANDLE_INVALID)
|
||||||
continue;
|
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 =
|
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)
|
if (status != ZN_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ zn_status_t namespace_add_desc_at(struct namespace* namespace, struct namespace_
|
|||||||
return ZN_ERR_BAD_HANDLE;
|
return ZN_ERR_BAD_HANDLE;
|
||||||
|
|
||||||
// Fail if a descriptor already exists at this 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 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) {
|
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;
|
return ZN_ERR_BAD_HANDLE;
|
||||||
|
|
||||||
struct namespace_desc* desc =
|
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)
|
if (!desc)
|
||||||
return ZN_ERR_BAD_HANDLE;
|
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)
|
if (handle <= ZN_HANDLE_INVALID)
|
||||||
return ZN_ERR_BAD_HANDLE;
|
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_ERR_BAD_HANDLE;
|
||||||
|
|
||||||
return ZN_OK;
|
return ZN_OK;
|
||||||
|
|||||||
+13
-13
@@ -1,6 +1,5 @@
|
|||||||
#include <zinnia/status.h>
|
#include <zinnia/status.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <kernel/assert.h>
|
|
||||||
#include <kernel/irq.h>
|
#include <kernel/irq.h>
|
||||||
#include <kernel/list.h>
|
#include <kernel/list.h>
|
||||||
#include <kernel/percpu.h>
|
#include <kernel/percpu.h>
|
||||||
@@ -8,6 +7,7 @@
|
|||||||
#include <kernel/sched.h>
|
#include <kernel/sched.h>
|
||||||
#include <kernel/spin.h>
|
#include <kernel/spin.h>
|
||||||
#include <kernel/tailq.h>
|
#include <kernel/tailq.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <bits/irq.h>
|
#include <bits/irq.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -35,30 +35,30 @@ void sched_to_user_context(uintptr_t ctx) {
|
|||||||
|
|
||||||
void sched_init(struct sched_percpu* sched) {
|
void sched_init(struct sched_percpu* sched) {
|
||||||
struct task* idle_task;
|
struct task* idle_task;
|
||||||
ASSERT(
|
assert(
|
||||||
task_create("idle", &kernel_vas, nullptr, idle_func, 0, &idle_task) == ZN_OK,
|
task_create("idle", &kernel_vas, nullptr, idle_func, 0, &idle_task) == ZN_OK,
|
||||||
"Unable to create idle task!\n"
|
"Unable to create idle task!\n"
|
||||||
);
|
);
|
||||||
sched->idle_task = idle_task;
|
sched->idle_task = idle_task;
|
||||||
sched->current = idle_task;
|
sched->current = idle_task;
|
||||||
|
|
||||||
TAILQ_INIT(&sched->run_queue);
|
tailq_init(&sched->run_queue);
|
||||||
|
|
||||||
kprintf("Scheduler initialized\n");
|
kprintf("Scheduler initialized\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_add_task(struct sched_percpu* sched, struct task* task) {
|
void sched_add_task(struct sched_percpu* sched, struct task* task) {
|
||||||
ASSERT(task != nullptr, "Tried to add NULL to the run queue\n");
|
assert(task != nullptr, "Tried to add NULL to the run queue\n");
|
||||||
TAILQ_INSERT_TAIL(&sched->run_queue, task, next);
|
tailq_insert_tail(&sched->run_queue, task, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct task* next_task(struct sched_percpu* sched) {
|
static struct task* next_task(struct sched_percpu* sched) {
|
||||||
struct task* t = TAILQ_FIRST(&sched->run_queue);
|
struct task* t = tailq_first(&sched->run_queue);
|
||||||
|
|
||||||
if (t == nullptr)
|
if (t == nullptr)
|
||||||
return sched->idle_task;
|
return sched->idle_task;
|
||||||
|
|
||||||
TAILQ_REMOVE(&sched->run_queue, t, next);
|
tailq_remove(&sched->run_queue, t, next);
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ void task_entry(task_fn_t entry, uintptr_t arg0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wait_queue_init(struct wait_queue* wq) {
|
void wait_queue_init(struct wait_queue* wq) {
|
||||||
TAILQ_INIT(&wq->waiters);
|
tailq_init(&wq->waiters);
|
||||||
wq->lock = (struct spinlock){0};
|
wq->lock = (struct spinlock){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ void sched_block(struct sched_percpu* sched, struct wait_queue* wq) {
|
|||||||
spin_lock(&wq->lock);
|
spin_lock(&wq->lock);
|
||||||
|
|
||||||
sched->current->state = TASK_STATE_BLOCKED;
|
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);
|
spin_unlock(&wq->lock);
|
||||||
do_reschedule(sched);
|
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) {
|
void sched_wake(struct sched_percpu* sched, struct wait_queue* wq) {
|
||||||
spin_lock(&wq->lock);
|
spin_lock(&wq->lock);
|
||||||
|
|
||||||
struct task* t = TAILQ_FIRST(&wq->waiters);
|
struct task* t = tailq_first(&wq->waiters);
|
||||||
if (t != nullptr) {
|
if (t != nullptr) {
|
||||||
TAILQ_REMOVE(&wq->waiters, t, next);
|
tailq_remove(&wq->waiters, t, next);
|
||||||
t->state = TASK_STATE_READY;
|
t->state = TASK_STATE_READY;
|
||||||
sched_add_task(sched, t);
|
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);
|
spin_lock(&wq->lock);
|
||||||
|
|
||||||
struct task* t;
|
struct task* t;
|
||||||
while ((t = TAILQ_FIRST(&wq->waiters)) != nullptr) {
|
while ((t = tailq_first(&wq->waiters)) != nullptr) {
|
||||||
TAILQ_REMOVE(&wq->waiters, t, next);
|
tailq_remove(&wq->waiters, t, next);
|
||||||
t->state = TASK_STATE_READY;
|
t->state = TASK_STATE_READY;
|
||||||
sched_add_task(sched, t);
|
sched_add_task(sched, t);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -1,16 +1,15 @@
|
|||||||
#include <kernel/spin.h>
|
#include <kernel/spin.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
// TODO: Ticketing system
|
|
||||||
|
|
||||||
void spin_lock(struct spinlock* spin) {
|
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");
|
asm volatile("pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store_explicit(&spin->locked, true, memory_order_release);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void spin_unlock(struct spinlock* spin) {
|
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 <common/compiler.h>
|
||||||
#include <kernel/panic.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))) { \
|
if (__unlikely(!(expr))) { \
|
||||||
panic( \
|
panic( \
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define DEBUG_ASSERT(...) ASSERT(__VA_ARGS__)
|
#define debug_assert(...) assert(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define DEBUG_ASSERT(...) ((void)0)
|
#define debug_assert(...) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
@@ -13,13 +13,13 @@ struct channel_msg {
|
|||||||
size_t num_bytes;
|
size_t num_bytes;
|
||||||
struct namespace_desc* descs;
|
struct namespace_desc* descs;
|
||||||
size_t num_handles;
|
size_t num_handles;
|
||||||
TAILQ_LINK(struct channel_msg) next;
|
tailq_link(struct channel_msg) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct channel {
|
struct channel {
|
||||||
struct channel* peer;
|
struct channel* peer;
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
TAILQ_HEAD(struct channel_msg) messages;
|
tailq_head(struct channel_msg) messages;
|
||||||
struct wait_queue waiters;
|
struct wait_queue waiters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
// Ensure a hash is never zero (zero is the empty sentinel).
|
// Ensure a hash is never zero (zero is the empty sentinel).
|
||||||
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
|
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
|
||||||
|
|
||||||
#define HASHMAP(K, V) \
|
#define hashmap(K, V) \
|
||||||
struct { \
|
struct { \
|
||||||
K* keys; \
|
K* keys; \
|
||||||
V* values; \
|
V* values; \
|
||||||
@@ -34,7 +34,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
size_t count; \
|
size_t count; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HASHMAP_INIT(map) \
|
#define hashmap_init(map) \
|
||||||
do { \
|
do { \
|
||||||
(map)->keys = nullptr; \
|
(map)->keys = nullptr; \
|
||||||
(map)->values = nullptr; \
|
(map)->values = nullptr; \
|
||||||
@@ -43,7 +43,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
(map)->count = 0; \
|
(map)->count = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define HASHMAP_DESTROY(map) \
|
#define hashmap_destroy(map) \
|
||||||
do { \
|
do { \
|
||||||
mem_free((map)->keys); \
|
mem_free((map)->keys); \
|
||||||
mem_free((map)->values); \
|
mem_free((map)->values); \
|
||||||
@@ -55,7 +55,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
(map)->count = 0; \
|
(map)->count = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define HASHMAP_COUNT(map) ((map)->count)
|
#define hashmap_count(map) ((map)->count)
|
||||||
|
|
||||||
// Internal: probe distance from ideal position.
|
// Internal: probe distance from ideal position.
|
||||||
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1))
|
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1))
|
||||||
@@ -116,10 +116,10 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Insert or update a key-value pair. Returns ZN_OK or ZN_ERR_NO_MEMORY.
|
// Insert or update a key-value pair. Returns 0 or ZN_ERR_NO_MEMORY.
|
||||||
#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \
|
#define hashmap_insert(map, key, val, hash_fn, eq_fn) \
|
||||||
({ \
|
({ \
|
||||||
zn_status_t _status = ZN_OK; \
|
zn_status_t _status = 0; \
|
||||||
typeof(*(map)->keys) _k = (key); \
|
typeof(*(map)->keys) _k = (key); \
|
||||||
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
|
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
|
||||||
/* Check for existing key first. */ \
|
/* Check for existing key first. */ \
|
||||||
@@ -147,7 +147,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
_status = ZN_ERR_NO_MEMORY; \
|
_status = ZN_ERR_NO_MEMORY; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
if (_status == ZN_OK) { \
|
if (_status == 0) { \
|
||||||
_HASHMAP_INSERT_INNER(map, _k, (val), _h); \
|
_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.
|
// Look up a key. Returns a pointer to the value, or nullptr if not found.
|
||||||
#define HASHMAP_GET(map, key, hash_fn, eq_fn) \
|
#define hashmap_get(map, key, hash_fn, eq_fn) \
|
||||||
({ \
|
({ \
|
||||||
typeof(*(map)->values)* _result = nullptr; \
|
typeof(*(map)->values)* _result = nullptr; \
|
||||||
if ((map)->capacity > 0) { \
|
if ((map)->capacity > 0) { \
|
||||||
@@ -180,7 +180,7 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
|
|
||||||
// Remove a key. Returns true if the key was found and removed.
|
// Remove a key. Returns true if the key was found and removed.
|
||||||
// Uses backward-shift deletion to avoid tombstones.
|
// Uses backward-shift deletion to avoid tombstones.
|
||||||
#define HASHMAP_REMOVE(map, key, hash_fn, eq_fn) \
|
#define hashmap_remove(map, key, hash_fn, eq_fn) \
|
||||||
({ \
|
({ \
|
||||||
bool _removed = false; \
|
bool _removed = false; \
|
||||||
if ((map)->capacity > 0) { \
|
if ((map)->capacity > 0) { \
|
||||||
@@ -218,6 +218,6 @@ static inline bool hashmap_eq_default(const void* a, const void* b, size_t len)
|
|||||||
|
|
||||||
// Iterate over all occupied entries. `idx` is a size_t loop variable.
|
// Iterate over all occupied entries. `idx` is a size_t loop variable.
|
||||||
// Access keys and values via (map)->keys[idx] and (map)->values[idx].
|
// Access keys and values via (map)->keys[idx] and (map)->values[idx].
|
||||||
#define HASHMAP_FOREACH(map, idx) \
|
#define hashmap_foreach(map, idx) \
|
||||||
for (size_t idx = 0; idx < (map)->capacity; idx++) \
|
for (size_t idx = 0; idx < (map)->capacity; idx++) \
|
||||||
if ((map)->hashes[idx] != 0)
|
if ((map)->hashes[idx] != 0)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ enum irq_trigger_mode : uint8_t {
|
|||||||
|
|
||||||
struct irq_handler {
|
struct irq_handler {
|
||||||
enum irq_status (*handler)(void* self);
|
enum irq_status (*handler)(void* self);
|
||||||
SLIST_LINK(struct irq_handler*) next;
|
list_link(struct irq_handler*) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct irq_line {
|
struct irq_line {
|
||||||
@@ -31,7 +31,7 @@ struct irq_line {
|
|||||||
void (*unmask)(struct irq_line* self);
|
void (*unmask)(struct irq_line* self);
|
||||||
void (*eoi)(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;
|
bool is_busy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define SLIST_HEAD(type) \
|
#define list_head(type) \
|
||||||
struct { \
|
struct { \
|
||||||
type sl_head; \
|
type _sl_head; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SLIST_LINK(type) \
|
#define list_link(type) \
|
||||||
struct { \
|
struct { \
|
||||||
type sl_link; \
|
type _sl_link; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SLIST_EMPTY(head) ((head)->sl_head == NULL)
|
#define list_is_empty(head) ((head)->_sl_head == NULL)
|
||||||
#define SLIST_FIRST(head) ((head)->sl_head)
|
#define list_first(head) ((head)->_sl_head)
|
||||||
#define SLIST_NEXT(elm, field) ((elm)->field.sl_link)
|
#define list_next(elm, field) ((elm)->field._sl_link)
|
||||||
|
|
||||||
#define SLIST_INSERT_END(slistelm, elm, field) \
|
#define list_insert_end(slistelm, elm, field) \
|
||||||
do { \
|
do { \
|
||||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
list_next((elm), field) = list_next((slistelm), field); \
|
||||||
SLIST_NEXT((slistelm), field) = (elm); \
|
list_next((slistelm), field) = (elm); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SLIST_INSERT_HEAD(head, elm, field) \
|
#define list_insert_head(head, elm, field) \
|
||||||
do { \
|
do { \
|
||||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
list_next((elm), field) = list_first((head)); \
|
||||||
SLIST_FIRST((head)) = (elm); \
|
list_first((head)) = (elm); \
|
||||||
} while (0)
|
} 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))
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ struct namespace_desc {
|
|||||||
struct namespace {
|
struct namespace {
|
||||||
zn_handle_t next_handle;
|
zn_handle_t next_handle;
|
||||||
struct mutex mutex;
|
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.
|
// Creates a new namespace with no contents.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ struct task {
|
|||||||
size_t time_slice;
|
size_t time_slice;
|
||||||
int8_t priority;
|
int8_t priority;
|
||||||
|
|
||||||
TAILQ_LINK(struct task) next;
|
tailq_link(struct task) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Per-CPU data for scheduling.
|
// Per-CPU data for scheduling.
|
||||||
@@ -46,7 +46,7 @@ struct sched_percpu {
|
|||||||
struct task* current;
|
struct task* current;
|
||||||
struct task* idle_task;
|
struct task* idle_task;
|
||||||
size_t preempt_level;
|
size_t preempt_level;
|
||||||
TAILQ_HEAD(struct task) run_queue;
|
tailq_head(struct task) run_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Blocks the current task on the given wait queue.
|
// Blocks the current task on the given wait queue.
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// Busy-waits in a loop until the lock is freed.
|
// Busy-waits in a loop until the lock is freed.
|
||||||
// Does not put the CPU to sleep.
|
// Does not put the CPU to sleep.
|
||||||
struct spinlock {
|
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.
|
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TAILQ_HEAD(type) \
|
#define tailq_head(type) \
|
||||||
struct { \
|
struct { \
|
||||||
type* tqh_first; \
|
type* tqh_first; \
|
||||||
type** tqh_last; \
|
type** tqh_last; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TAILQ_LINK(type) \
|
#define tailq_link(type) \
|
||||||
struct { \
|
struct { \
|
||||||
type* tqe_next; \
|
type* tqe_next; \
|
||||||
type** tqe_prev; \
|
type** tqe_prev; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TAILQ_INIT(head) \
|
#define tailq_init(head) \
|
||||||
do { \
|
do { \
|
||||||
(head)->tqh_first = nullptr; \
|
(head)->tqh_first = nullptr; \
|
||||||
(head)->tqh_last = &(head)->tqh_first; \
|
(head)->tqh_last = &(head)->tqh_first; \
|
||||||
} while (0)
|
} 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 { \
|
do { \
|
||||||
(elm)->field.tqe_next = nullptr; \
|
(elm)->field.tqe_next = nullptr; \
|
||||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TAILQ_INSERT_HEAD(head, elm, field) \
|
#define tailq_insert_head(head, elm, field) \
|
||||||
do { \
|
do { \
|
||||||
if (((elm)->field.tqe_next = (head)->tqh_first) != nullptr) \
|
if (((elm)->field.tqe_next = (head)->tqh_first) != nullptr) \
|
||||||
(head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
|
(head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TAILQ_REMOVE(head, elm, field) \
|
#define tailq_remove(head, elm, field) \
|
||||||
do { \
|
do { \
|
||||||
if (((elm)->field.tqe_next) != nullptr) \
|
if (((elm)->field.tqe_next) != nullptr) \
|
||||||
(elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
|
(elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||||
|
|||||||
+25
-26
@@ -1,25 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zinnia/status.h>
|
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h> // IWYU pragma: keep
|
||||||
#include <string.h>
|
#include <string.h> // IWYU pragma: keep
|
||||||
|
|
||||||
#define VEC(T) \
|
#define vec(T) \
|
||||||
struct { \
|
struct { \
|
||||||
T* data; \
|
T* data; \
|
||||||
size_t length; \
|
size_t length; \
|
||||||
size_t capacity; \
|
size_t capacity; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VEC_INIT(vec) \
|
#define vec_init(vec) \
|
||||||
do { \
|
do { \
|
||||||
(vec)->data = nullptr; \
|
(vec)->data = nullptr; \
|
||||||
(vec)->length = 0; \
|
(vec)->length = 0; \
|
||||||
(vec)->capacity = 0; \
|
(vec)->capacity = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define VEC_DESTROY(vec) \
|
#define vec_destroy(vec) \
|
||||||
do { \
|
do { \
|
||||||
mem_free((vec)->data); \
|
mem_free((vec)->data); \
|
||||||
(vec)->data = nullptr; \
|
(vec)->data = nullptr; \
|
||||||
@@ -27,13 +26,13 @@
|
|||||||
(vec)->capacity = 0; \
|
(vec)->capacity = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define VEC_LENGTH(vec) ((vec)->length)
|
#define vec_length(vec) ((vec)->length)
|
||||||
#define VEC_CAPACITY(vec) ((vec)->capacity)
|
#define vec_capacity(vec) ((vec)->capacity)
|
||||||
#define VEC_EMPTY(vec) ((vec)->length == 0)
|
#define vec_empty(vec) ((vec)->length == 0)
|
||||||
#define VEC_AT(vec, i) ((vec)->data[i])
|
#define vec_at(vec, i) ((vec)->data[i])
|
||||||
|
|
||||||
// Internal: grow to at least `needed` capacity.
|
// Internal: grow to at least `needed` capacity.
|
||||||
#define _VEC_GROW(vec, needed) \
|
#define _vec_grow(vec, needed) \
|
||||||
do { \
|
do { \
|
||||||
size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \
|
size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \
|
||||||
while (_new_cap < (needed)) \
|
while (_new_cap < (needed)) \
|
||||||
@@ -46,34 +45,34 @@
|
|||||||
(vec)->capacity = _new_cap; \
|
(vec)->capacity = _new_cap; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Append an element. Returns ZN_OK or ZN_ERR_NO_MEMORY.
|
// Append an element. Returns 0 or ZN_ERR_NO_MEMORY.
|
||||||
#define VEC_PUSH(vec, val) \
|
#define vec_push(vec, val) \
|
||||||
({ \
|
({ \
|
||||||
zn_status_t _status = ZN_OK; \
|
zn_status_t _status = 0; \
|
||||||
if ((vec)->length >= (vec)->capacity) { \
|
if ((vec)->length >= (vec)->capacity) { \
|
||||||
_VEC_GROW(vec, (vec)->length + 1); \
|
_vec_grow(vec, (vec)->length + 1); \
|
||||||
if ((vec)->data == nullptr) \
|
if ((vec)->data == nullptr) \
|
||||||
_status = ZN_ERR_NO_MEMORY; \
|
_status = ZN_ERR_NO_MEMORY; \
|
||||||
} \
|
} \
|
||||||
if (_status == ZN_OK) \
|
if (_status == 0) \
|
||||||
(vec)->data[(vec)->length++] = (val); \
|
(vec)->data[(vec)->length++] = (val); \
|
||||||
_status; \
|
_status; \
|
||||||
})
|
})
|
||||||
|
|
||||||
// Remove and return the last element. Undefined if empty.
|
// 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.
|
// Insert at index, shifting subsequent elements right. Returns 0 or ZN_ERR_NO_MEMORY.
|
||||||
#define VEC_INSERT(vec, i, val) \
|
#define vec_insert(vec, i, val) \
|
||||||
({ \
|
({ \
|
||||||
zn_status_t _status = ZN_OK; \
|
zn_status_t _status = 0; \
|
||||||
size_t _idx = (i); \
|
size_t _idx = (i); \
|
||||||
if ((vec)->length >= (vec)->capacity) { \
|
if ((vec)->length >= (vec)->capacity) { \
|
||||||
_VEC_GROW(vec, (vec)->length + 1); \
|
_vec_grow(vec, (vec)->length + 1); \
|
||||||
if ((vec)->data == nullptr) \
|
if ((vec)->data == nullptr) \
|
||||||
_status = ZN_ERR_NO_MEMORY; \
|
_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)); \
|
memmove(&(vec)->data[_idx + 1], &(vec)->data[_idx], ((vec)->length - _idx) * sizeof(*(vec)->data)); \
|
||||||
(vec)->data[_idx] = (val); \
|
(vec)->data[_idx] = (val); \
|
||||||
(vec)->length++; \
|
(vec)->length++; \
|
||||||
@@ -82,7 +81,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Remove element at index, shifting subsequent elements left.
|
// Remove element at index, shifting subsequent elements left.
|
||||||
#define VEC_REMOVE(vec, i) \
|
#define vec_remove(vec, i) \
|
||||||
do { \
|
do { \
|
||||||
size_t _idx = (i); \
|
size_t _idx = (i); \
|
||||||
(vec)->length--; \
|
(vec)->length--; \
|
||||||
@@ -91,7 +90,7 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Remove element at index by swapping with the last element (O(1), unordered).
|
// 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 { \
|
do { \
|
||||||
size_t _idx = (i); \
|
size_t _idx = (i); \
|
||||||
(vec)->length--; \
|
(vec)->length--; \
|
||||||
@@ -100,6 +99,6 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Clear all elements without freeing memory.
|
// 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++)
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ struct pager_ops {
|
|||||||
struct page_list {
|
struct page_list {
|
||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
struct page* value;
|
struct page* value;
|
||||||
SLIST_LINK(struct page_list*) next;
|
list_link(struct page_list*) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct paged_vmo {
|
struct paged_vmo {
|
||||||
struct vmo object;
|
struct vmo object;
|
||||||
struct pager_ops source;
|
struct pager_ops source;
|
||||||
SLIST_HEAD(struct page_list*) cache;
|
list_head(struct page_list*) cache;
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ struct task;
|
|||||||
|
|
||||||
// A queue of tasks waiting for an event.
|
// A queue of tasks waiting for an event.
|
||||||
struct wait_queue {
|
struct wait_queue {
|
||||||
TAILQ_HEAD(struct task) waiters;
|
tailq_head(struct task) waiters;
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
#ifndef ZINNIA_STDARG_H
|
#pragma once
|
||||||
#define ZINNIA_STDARG_H
|
|
||||||
|
|
||||||
typedef __builtin_va_list va_list;
|
typedef __builtin_va_list va_list;
|
||||||
#define va_start(v, l) __builtin_va_start(v, l)
|
#define va_start(v, l) __builtin_va_start(v, l)
|
||||||
#define va_end(v) __builtin_va_end(v)
|
#define va_end(v) __builtin_va_end(v)
|
||||||
#define va_arg(v, T) __builtin_va_arg(v, T)
|
#define va_arg(v, T) __builtin_va_arg(v, T)
|
||||||
#define va_copy(d, s) __builtin_va_copy(d, s)
|
#define va_copy(d, s) __builtin_va_copy(d, s)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef ZINNIA_STDATOMIC_H
|
#pragma once
|
||||||
#define ZINNIA_STDATOMIC_H
|
|
||||||
|
|
||||||
typedef enum memory_order {
|
typedef enum memory_order {
|
||||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
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_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
#define atomic_thread_fence(ord) __atomic_thread_fence(ord)
|
#define atomic_thread_fence(ord) __atomic_thread_fence(ord)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#ifndef ZINNIA_STDDEF_H
|
#pragma once
|
||||||
#define ZINNIA_STDDEF_H
|
|
||||||
|
|
||||||
typedef unsigned long size_t;
|
typedef unsigned long size_t;
|
||||||
typedef signed long ssize_t;
|
typedef signed long ssize_t;
|
||||||
|
|
||||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||||
|
#define unreachable() __builtin_unreachable()
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef ZINNIA_STDINT_H
|
#pragma once
|
||||||
#define ZINNIA_STDINT_H
|
|
||||||
|
|
||||||
typedef __INT8_TYPE__ int8_t;
|
typedef __INT8_TYPE__ int8_t;
|
||||||
typedef __UINT8_TYPE__ uint8_t;
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
@@ -25,5 +24,3 @@ typedef __INTPTR_TYPE__ intptr_t;
|
|||||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
#define INTPTR_MAX __INTPTR_MAX__
|
#define INTPTR_MAX __INTPTR_MAX__
|
||||||
#define UINTPTR_MAX __UINTPTR_MAX__
|
#define UINTPTR_MAX __UINTPTR_MAX__
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
#ifndef ZINNIA_STDLIB_H
|
#pragma once
|
||||||
#define ZINNIA_STDLIB_H
|
|
||||||
|
|
||||||
long atol(const char* str, int base);
|
long atol(const char* str, int base);
|
||||||
unsigned long atolu(const char* str, int base);
|
unsigned long atolu(const char* str, int base);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef ZINNIA_STRING_H
|
#pragma once
|
||||||
#define ZINNIA_STRING_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#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 strcmp(const char* str1, const char* str2);
|
||||||
int strncmp(const char* str1, const char* str2, size_t len);
|
int strncmp(const char* str1, const char* str2, size_t len);
|
||||||
char* strchr(const char* c, int s);
|
char* strchr(const char* c, int s);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
+7
-7
@@ -1,11 +1,11 @@
|
|||||||
#include <common/utils.h>
|
#include <common/utils.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <kernel/assert.h>
|
|
||||||
#include <kernel/init.h>
|
#include <kernel/init.h>
|
||||||
#include <kernel/panic.h>
|
#include <kernel/panic.h>
|
||||||
#include <kernel/print.h>
|
#include <kernel/print.h>
|
||||||
#include <kernel/vas.h>
|
#include <kernel/vas.h>
|
||||||
#include <kernel/virt.h>
|
#include <kernel/virt.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
extern uint8_t __ld_text_start[];
|
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.
|
// since we're likely going to map it at a different base address.
|
||||||
mem_hhdm_base = tmp_hhdm;
|
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
|
// text
|
||||||
kprintf("Mapping text segment at %p\n", __ld_text_start);
|
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,
|
PTE_READ | PTE_EXEC,
|
||||||
CACHE_NONE
|
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
|
// rodata
|
||||||
@@ -91,7 +91,7 @@ void mem_init(struct phys_mem* map, size_t map_len, uintptr_t kernel_virt, phys_
|
|||||||
PTE_READ,
|
PTE_READ,
|
||||||
CACHE_NONE
|
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
|
// 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,
|
PTE_READ | PTE_WRITE,
|
||||||
CACHE_NONE
|
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).
|
// 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);
|
uintptr_t vaddr = (uintptr_t)(map[i].address + p + tmp_hhdm);
|
||||||
phys_t paddr = (phys_t)(map[i].address + p);
|
phys_t paddr = (phys_t)(map[i].address + p);
|
||||||
zn_status_t status = pmap_map(&kernel_vas.pmap, vaddr, paddr, PTE_READ | PTE_WRITE, CACHE_NONE);
|
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;
|
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) {
|
for (size_t page = 0; page < length; page += pgsz) {
|
||||||
phys_t paddr;
|
phys_t paddr;
|
||||||
ASSERT(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n");
|
assert(!mem_phys_alloc(1, 0, &paddr), "Failed to allocate memory for PFNDB!\n");
|
||||||
pmap_map(&kernel_vas.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_NONE);
|
pmap_map(&kernel_vas.pmap, vaddr + page, paddr, PTE_READ | PTE_WRITE, CACHE_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ kernel_sources += files(
|
|||||||
'slab.c',
|
'slab.c',
|
||||||
'usercopy.c',
|
'usercopy.c',
|
||||||
'virt.c',
|
'virt.c',
|
||||||
'vas.c',
|
'vma.c',
|
||||||
'vmo.c',
|
'vmo.c',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include <zinnia/status.h>
|
#include <zinnia/status.h>
|
||||||
#include <common/utils.h>
|
#include <common/utils.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <kernel/assert.h>
|
|
||||||
#include <kernel/vas.h>
|
#include <kernel/vas.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
// Try to create a new, empty virtual address space.
|
// Try to create a new, empty virtual address space.
|
||||||
zn_status_t vma_new(struct vas** out) {
|
zn_status_t vma_new(struct vas** out) {
|
||||||
DEBUG_ASSERT(out != nullptr, "Missing out");
|
debug_assert(out != nullptr, "Missing out");
|
||||||
|
|
||||||
zn_status_t res;
|
zn_status_t res;
|
||||||
if (!out)
|
if (!out)
|
||||||
+2
-2
@@ -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.
|
// Try to find the requested page in the cache.
|
||||||
struct page_list* iter;
|
struct page_list* iter;
|
||||||
SLIST_FOREACH(iter, &paged->cache, next) {
|
list_foreach(iter, &paged->cache, next) {
|
||||||
if (iter->offset != offset_idx)
|
if (iter->offset != offset_idx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct
|
|||||||
entry->value = new_page;
|
entry->value = new_page;
|
||||||
|
|
||||||
// Add page to the object cache.
|
// Add page to the object cache.
|
||||||
SLIST_INSERT_HEAD(&paged->cache, entry, next);
|
list_insert_head(&paged->cache, entry, next);
|
||||||
|
|
||||||
*out = new_page;
|
*out = new_page;
|
||||||
return ZN_OK;
|
return ZN_OK;
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ static const syscall_fn_t dispatch_table[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void syscall_dispatch(struct arch_context* ctx) {
|
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)) {
|
if (num >= ARRAY_SIZE(dispatch_table)) {
|
||||||
ctx->ARCH_CTX_RET0 = ZN_ERR_BAD_SYSCALL;
|
ctx->ret0 = ZN_ERR_BAD_SYSCALL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->ARCH_CTX_RET0 = dispatch_table[num](ctx);
|
ctx->ret0 = dispatch_table[num](ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <kernel/sched.h>
|
#include <kernel/sched.h>
|
||||||
#include <kernel/syscalls.h>
|
#include <kernel/syscalls.h>
|
||||||
#include <kernel/usercopy.h>
|
#include <kernel/usercopy.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
zn_status_t syscall_thread_create(struct arch_context* ctx) {
|
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;
|
struct sched_percpu* sched = &percpu_get()->sched;
|
||||||
sched->current->state = TASK_STATE_DEAD;
|
sched->current->state = TASK_STATE_DEAD;
|
||||||
sched_yield(sched);
|
sched_yield(sched);
|
||||||
__unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
project(
|
project(
|
||||||
'zinnia',
|
'zinnia',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
version: '0.1.0',
|
version: '0.3.0',
|
||||||
meson_version: '>=1.1.0',
|
meson_version: '>=1.1.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=gnu23',
|
'c_std=gnu23',
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
#include <zinnia/channel.h>
|
#include <zinnia/channel.h>
|
||||||
#include <zinnia/handle.h>
|
#include <zinnia/handle.h>
|
||||||
#include <zinnia/ipc/init.h>
|
|
||||||
#include <zinnia/system.h>
|
#include <zinnia/system.h>
|
||||||
#include <common/compiler.h>
|
#include <common/compiler.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -22,7 +21,7 @@ static void zn_printf(const char* msg, ...) {
|
|||||||
|
|
||||||
int main(int argc, char* argv[], char* envp[]) {
|
int main(int argc, char* argv[], char* envp[]) {
|
||||||
zn_printf("devd: starting...\n");
|
zn_printf("devd: starting...\n");
|
||||||
zn_handle_t channel = getauxval(AT_INIT_HANDLE);
|
zn_handle_t channel = getauxval(0x1000);
|
||||||
|
|
||||||
// while (true) {}
|
// while (true) {}
|
||||||
uacpi_status status = uacpi_initialize(0);
|
uacpi_status status = uacpi_initialize(0);
|
||||||
|
|||||||
+4
-24
@@ -1,6 +1,5 @@
|
|||||||
#include <zinnia/channel.h>
|
#include <zinnia/channel.h>
|
||||||
#include <zinnia/handle.h>
|
#include <zinnia/handle.h>
|
||||||
#include <zinnia/ipc/init.h>
|
|
||||||
#include <zinnia/mem.h>
|
#include <zinnia/mem.h>
|
||||||
#include <zinnia/status.h>
|
#include <zinnia/status.h>
|
||||||
#include <zinnia/system.h>
|
#include <zinnia/system.h>
|
||||||
@@ -12,6 +11,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define ZN_ASSERT(expr) \
|
#define ZN_ASSERT(expr) \
|
||||||
do { \
|
do { \
|
||||||
@@ -31,38 +31,18 @@ static void zn_printf(const char* msg, ...) {
|
|||||||
int32_t len = vsnprintf(buf, sizeof(buf), msg, args);
|
int32_t len = vsnprintf(buf, sizeof(buf), msg, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
zn_log(buf, len);
|
write(1, buf, len);
|
||||||
|
// zn_log(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[], char* envp[]) {
|
int main(int argc, char* argv[], char* envp[]) {
|
||||||
zn_printf("initd: starting...\n");
|
zn_printf("initd: starting...\n");
|
||||||
zn_handle_t channel = getauxval(AT_INIT_HANDLE);
|
zn_handle_t channel = getauxval(0x1000);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
static thread_local zn_handle_t handles[32];
|
static thread_local zn_handle_t handles[32];
|
||||||
static thread_local char buf[1024];
|
static thread_local char buf[1024];
|
||||||
|
|
||||||
ZN_ASSERT(zn_channel_read(channel, handles, buf, ARRAY_SIZE(handles), ARRAY_SIZE(buf), nullptr, nullptr));
|
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
@@ -1,3 +1,3 @@
|
|||||||
subdir('initd')
|
subdir('initd')
|
||||||
subdir('devd')
|
subdir('devd')
|
||||||
subdir('posixd')
|
subdir('unix')
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <zinnia/channel.h>
|
#include <zinnia/channel.h>
|
||||||
#include <zinnia/handle.h>
|
#include <zinnia/handle.h>
|
||||||
#include <zinnia/ipc/init.h>
|
|
||||||
#include <zinnia/mem.h>
|
#include <zinnia/mem.h>
|
||||||
#include <zinnia/status.h>
|
#include <zinnia/status.h>
|
||||||
#include <zinnia/system.h>
|
#include <zinnia/system.h>
|
||||||
@@ -29,38 +28,45 @@ static void zn_printf(const char* msg, ...) {
|
|||||||
|
|
||||||
zn_handle_t channel;
|
zn_handle_t channel;
|
||||||
|
|
||||||
int other_fn(void* arg) {
|
struct message {
|
||||||
zn_printf("posixd: Hello from the other thread named \"%s\"!\n", (const char*)arg);
|
size_t id;
|
||||||
channel = getauxval(AT_INIT_HANDLE);
|
};
|
||||||
|
|
||||||
struct ipc_init_register_rq msg = {
|
#define MSG_HI \
|
||||||
.id = IPC_MSG_FOO,
|
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";
|
char name[] = "posixd";
|
||||||
|
|
||||||
zn_status_t status = zn_channel_write(channel, nullptr, &msg, 0, sizeof(msg) + sizeof(name));
|
zn_status_t status = zn_channel_write(channel, nullptr, &msg, 0, sizeof(msg) + sizeof(name));
|
||||||
|
|
||||||
if (status != ZN_OK) {
|
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;
|
return 69;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[], char* envp[]) {
|
int main(int argc, char* argv[], char* envp[]) {
|
||||||
zn_printf("posixd: starting...\n");
|
zn_printf("unix: starting...\n");
|
||||||
const char* thread_name = "posix_second_thread";
|
const char* thread_name = "unix_second_thread";
|
||||||
|
|
||||||
thrd_t thread;
|
thrd_t thread;
|
||||||
int res = thrd_create(&thread, other_fn, (void*)thread_name);
|
int res = thrd_create(&thread, other_fn, (void*)thread_name);
|
||||||
if (res != thrd_success)
|
if (res != thrd_success)
|
||||||
zn_printf("posixd: errno: %s\n", strerror(errno));
|
zn_printf("unix: errno: %s\n", strerror(errno));
|
||||||
zn_printf("posixd: second thread created\n");
|
zn_printf("unix: second thread created\n");
|
||||||
|
|
||||||
int res2;
|
int res2;
|
||||||
zn_printf("posixd: waiting on second thread...\n");
|
zn_printf("unix: waiting on second thread...\n");
|
||||||
thrd_join(thread, &res2);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
configure_file(configuration: cfg, output: 'config.h')
|
configure_file(configuration: cfg, output: 'config.h')
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'posixd',
|
'unix',
|
||||||
'main.c',
|
'main.c',
|
||||||
'uname.c',
|
'uname.c',
|
||||||
link_args: '-static',
|
link_args: '-static',
|
||||||
+1
-1
Submodule subprojects/uacpi updated: e05715b2e6...9c9b26d629
Reference in New Issue
Block a user