diff --git a/include/common/utils.h b/include/common/utils.h index 504e9f8..d1c1364 100644 --- a/include/common/utils.h +++ b/include/common/utils.h @@ -14,19 +14,19 @@ #if defined(__has_builtin) #if __has_builtin(__builtin_types_compatible_p) // Get pointer to parent object given pointer to a struct or union member. -#define CONTAINER_OF(ptr, type, member) \ +#define containerof(ptr, type, member) \ ({ \ - _Static_assert( \ - __builtin_types_compatible_p(__typeof__(*(ptr)), __typeof__(((type*)0)->member)), \ - "Incompatible types for CONTAINER_OF" \ + static_assert( \ + __builtin_types_compatible_p(typeof(*(ptr)), typeof(((type*)0)->member)), \ + "Incompatible types for containerof" \ ); \ (type*)((size_t)ptr - offsetof(type, member)); \ }) #endif #endif -#ifndef CONTAINER_OF +#ifndef containerof // Get pointer to parent object given pointer to a struct or union member. -#define CONTAINER_OF(ptr, type, member) (type*)((size_t)ptr - offsetof(type, member)) +#define containerof(ptr, type, member) (type*)((size_t)ptr - offsetof(type, member)) #endif #define CONCAT(A, B) _CONCAT(A, B) diff --git a/include/zinnia/archctl.h b/include/zinnia/archctl.h index d3d23b8..a00395e 100644 --- a/include/zinnia/archctl.h +++ b/include/zinnia/archctl.h @@ -2,7 +2,6 @@ #define ZINNIA_ARCHCTL_H #include -#include #ifdef __cplusplus extern "C" { @@ -11,16 +10,14 @@ extern "C" { typedef enum { // Does nothing. ZN_ARCHCTL_NONE = 0, - // On x86_64, sets the FSBASE MSR to the value. + // On x86_64, sets the FSBASE MSR. ZN_ARCHCTL_SET_FSBASE = 1, - // On x86_64, sets the GSBASE MSR to the value. + // On x86_64, sets the GSBASE MSR. ZN_ARCHCTL_SET_GSBASE = 2, } zn_archctl_t; // Performs an architecture-dependent operation identified by `op`. -static inline zn_status_t zn_archctl(zn_archctl_t op, void* value) { - return zn_syscall2(op, value, ZN_SYSCALL_ARCHCTL); -} +zn_status_t zn_archctl(zn_archctl_t op, void* value); #ifdef __cplusplus } diff --git a/include/zinnia/channel.h b/include/zinnia/channel.h index f2926ff..c4d7056 100644 --- a/include/zinnia/channel.h +++ b/include/zinnia/channel.h @@ -3,7 +3,6 @@ #include #include -#include #include #ifdef __cplusplus @@ -15,28 +14,20 @@ enum zn_channel_flags { }; // Creates a new channel. -static inline zn_status_t zn_channel_create( - enum zn_channel_flags flags, - zn_handle_t* endpoint0, - zn_handle_t* endpoint1 -) { - return zn_syscall3(flags, endpoint0, endpoint1, ZN_SYSCALL_CHANNEL_CREATE); -} +zn_status_t zn_channel_create(enum zn_channel_flags flags, zn_handle_t* endpoint0, zn_handle_t* endpoint1); // Notifies the peer that there is new data available. // The kernel only copies the first `num_handles` handles and `num_bytes` bytes. -static inline zn_status_t zn_channel_write( +zn_status_t zn_channel_write( zn_handle_t channel, const zn_handle_t* handles, const void* bytes, size_t num_handles, size_t num_bytes -) { - return zn_syscall5(channel, handles, bytes, num_handles, num_bytes, ZN_SYSCALL_CHANNEL_WRITE); -} +); // Waits for a new message to appear in the channel. -static inline zn_status_t zn_channel_read( +zn_status_t zn_channel_read( zn_handle_t channel, zn_handle_t* handles, void* bytes, @@ -44,18 +35,7 @@ static inline zn_status_t zn_channel_read( size_t num_bytes, size_t* read_handles, size_t* read_bytes -) { - return zn_syscall7( - channel, - handles, - bytes, - num_handles, - num_bytes, - read_handles, - read_bytes, - ZN_SYSCALL_CHANNEL_READ - ); -} +); #ifdef __cplusplus } diff --git a/include/zinnia/futex.h b/include/zinnia/futex.h index 4a5b5b7..447c3f8 100644 --- a/include/zinnia/futex.h +++ b/include/zinnia/futex.h @@ -2,7 +2,6 @@ #define ZINNIA_FUTEX_H #include -#include #include #ifdef __cplusplus @@ -11,14 +10,10 @@ 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(int32_t* addr, int32_t expected) { - return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT); -} +zn_status_t zn_futex_wait(int32_t* addr, int32_t expected); // Wakes up to `count` threads waiting on the given futex address. -static inline zn_status_t zn_futex_wake(int32_t* addr, int32_t count) { - return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE); -} +zn_status_t zn_futex_wake(int32_t* addr, int32_t count); #ifdef __cplusplus } diff --git a/include/zinnia/handle.h b/include/zinnia/handle.h index affc9a8..e7ffe5b 100644 --- a/include/zinnia/handle.h +++ b/include/zinnia/handle.h @@ -3,7 +3,6 @@ #include #include -#include #include #ifdef __cplusplus @@ -20,22 +19,16 @@ typedef int32_t zn_handle_t; #define ZN_HANDLE_ZERO_VMO ((zn_handle_t)(-4)) // Checks an object handle for validity. -static inline zn_status_t zn_handle_validate(zn_handle_t handle) { - return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE); -} +zn_status_t zn_handle_validate(zn_handle_t handle); // 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); -} +zn_status_t zn_handle_drop(zn_handle_t handle); // Creates a new handle pointing to the same object as pointed to // by the original handle. The new handle may obtain new rights. -static inline zn_status_t zn_handle_clone(zn_handle_t handle, zn_rights_t cloned_rights, zn_handle_t* cloned) { - return zn_syscall3(handle, cloned_rights, cloned, ZN_SYSCALL_HANDLE_CLONE); -} +zn_status_t zn_handle_clone(zn_handle_t handle, zn_rights_t cloned_rights, zn_handle_t* cloned); #ifdef __cplusplus } diff --git a/include/zinnia/ipc.h b/include/zinnia/ipc.h deleted file mode 100644 index df25c39..0000000 --- a/include/zinnia/ipc.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ZINNIA_IPC_H -#define ZINNIA_IPC_H - -#include -#include -#include -#include - -#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 diff --git a/include/zinnia/mem.h b/include/zinnia/mem.h index faae0e9..e102778 100644 --- a/include/zinnia/mem.h +++ b/include/zinnia/mem.h @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -19,7 +18,7 @@ enum zn_vm_flags { ZN_VM_MAP_WRITE = 1 << 1, // Mapping is executable. ZN_VM_MAP_EXEC = 1 << 2, - // Shared memory (not cloned on calls to fork). + // Shared memory. ZN_VM_MAP_SHARED = 1 << 3, // Map at a fixed address, replacing whatever is in the way. @@ -31,31 +30,23 @@ enum zn_vm_flags { }; // Creates a new virtual memory object. -static inline zn_status_t zn_vmo_create(size_t length, zn_handle_t* out) { - return zn_syscall2(length, out, ZN_SYSCALL_VMO_CREATE); -} +zn_status_t zn_vmo_create(size_t length, zn_handle_t* out); // Creates a new virtual memory object which points to a contiguous phyiscal memory region. -static inline zn_status_t zn_vmo_create_phys(uintptr_t phys_addr, size_t length, zn_handle_t* out) { - return zn_syscall3(phys_addr, length, out, ZN_SYSCALL_VMO_CREATE_PHYS); -} +zn_status_t zn_vmo_create_phys(uintptr_t phys_addr, size_t length, zn_handle_t* out); // Maps `bytes` of `vmo` at `vmo_offset` to `addr` in `vas`. -static inline zn_status_t zn_vmo_map( +zn_status_t zn_vmo_map( zn_handle_t vmo, zn_handle_t vas, uintptr_t vmo_offset, uintptr_t* addr, size_t bytes, enum zn_vm_flags flags -) { - return zn_syscall6(vmo, vas, vmo_offset, addr, bytes, flags, ZN_SYSCALL_VMO_MAP); -} +); // Creates a new virtual address space. -static inline zn_status_t zn_vas_create(zn_handle_t* out) { - return zn_syscall1(out, ZN_SYSCALL_VAS_CREATE); -} +zn_status_t zn_vas_create(zn_handle_t* out); #ifdef __cplusplus } diff --git a/include/zinnia/namespace.h b/include/zinnia/namespace.h index a62c9cc..473998b 100644 --- a/include/zinnia/namespace.h +++ b/include/zinnia/namespace.h @@ -9,15 +9,11 @@ extern "C" { #endif // Creates a new namespace. -static inline zn_status_t zn_ns_create(zn_handle_t* out) { - return ZN_ERR_UNSUPPORTED; -} +zn_status_t zn_ns_create(zn_handle_t* out); // 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; -} +zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_ns); #ifdef __cplusplus } diff --git a/include/zinnia/random.h b/include/zinnia/random.h index 6e6f3b4..0addbe2 100644 --- a/include/zinnia/random.h +++ b/include/zinnia/random.h @@ -2,7 +2,6 @@ #define ZINNIA_RANDOM_H #include -#include #include #ifdef __cplusplus @@ -14,14 +13,10 @@ enum { }; // Stores random bytes in a buffer. -static inline zn_status_t zn_random_get(void* addr, size_t len) { - return zn_syscall2(addr, len, ZN_SYSCALL_RANDOM_GET); -} +zn_status_t zn_random_get(void* addr, size_t len); // Adds entropy to the RNG. -static inline zn_status_t zn_random_entropy(const void* addr, size_t len) { - return zn_syscall2(addr, len, ZN_SYSCALL_RANDOM_ENTROPY); -} +zn_status_t zn_random_entropy(const void* addr, size_t len); #ifdef __cplusplus } diff --git a/include/zinnia/status.h b/include/zinnia/status.h index 7f60796..77cf8d6 100644 --- a/include/zinnia/status.h +++ b/include/zinnia/status.h @@ -34,36 +34,7 @@ typedef enum { ZN_ERR_ALREADY_EXISTS = -11, } zn_status_t; -static inline const char* zn_status_to_string(zn_status_t err) { - switch (err) { - case ZN_OK: - return "No error (OK)"; - case ZN_ERR_INTERNAL: - return "An internal error occured (INTERNAL)"; - case ZN_ERR_BAD_SYSCALL: - return "Syscall number is not a recognized syscall (BAD_SYSCALL)"; - case ZN_ERR_UNSUPPORTED: - return "This operation is not supported or implemented yet (UNSUPPORTED)"; - case ZN_ERR_NO_MEMORY: - return "System does not have enough free memory for this operation (NO_MEMORY)"; - case ZN_ERR_NO_HANDLES: - return "Process can not own any more handles (NO_HANDLES)"; - case ZN_ERR_INVALID: - return "One or more of the provided arguments is not valid (INVALID)"; - case ZN_ERR_BAD_RANGE: - return "Argument is outside of the range for valid values (BAD_RANGE)"; - case ZN_ERR_BAD_HANDLE: - return "Object handle does not name a valid object (BAD_HANDLE)"; - case ZN_ERR_BAD_PERMS: - return "Object has insufficient permissions for this operation (BAD_PERMS)"; - case ZN_ERR_BAD_BUFFER: - return "Buffer is not large enough or doesn't point to a valid memory region (BAD_BUFFER)"; - case ZN_ERR_ALREADY_EXISTS: - return "The resource already exists (ALREADY_EXISTS)"; - } - - return "Unknown error code"; -} +const char* zn_status_to_string(zn_status_t err); #ifdef __cplusplus } diff --git a/include/zinnia/system.h b/include/zinnia/system.h index 244f6c4..4dc23f3 100644 --- a/include/zinnia/system.h +++ b/include/zinnia/system.h @@ -2,33 +2,24 @@ #define ZINNIA_SYSTEM_H #include -#include +#include #include #ifdef __cplusplus extern "C" { #endif -static inline void zn_log(const char* message, size_t len) { - zn_syscall2(message, len, ZN_SYSCALL_LOG); -} +// Logs a message through the kernel. +// Messages longer than an unspecified size will get truncated by the kernel. +void zn_log(const char* message, size_t len); // Returns the page size of the system. -static inline size_t zn_page_size() { - size_t size = 0; - zn_syscall1(&size, ZN_SYSCALL_PAGE_SIZE); - return size; -} +size_t zn_page_size(); -static inline zn_status_t zn_powerctl() { - return ZN_ERR_UNSUPPORTED; -} +zn_status_t zn_powerctl(); -static inline uint64_t zn_time() { - uint64_t time = 0; - zn_syscall1(&time, ZN_SYSCALL_TIME); - return time; -} +// Returns the current timestamp in nanoseconds. +uint64_t zn_time(); #ifdef __cplusplus } diff --git a/include/zinnia/thread.h b/include/zinnia/thread.h index c09ab86..867ef8e 100644 --- a/include/zinnia/thread.h +++ b/include/zinnia/thread.h @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -16,25 +15,19 @@ enum zn_thread_flags { }; // Creates a new thread in the given namespace. -static inline zn_status_t zn_thread_create( +zn_status_t zn_thread_create( zn_handle_t ns, const char* name, size_t name_len, enum zn_thread_flags flags, zn_handle_t* out -) { - return zn_syscall5(ns, name, name_len, flags, out, ZN_SYSCALL_THREAD_CREATE); -} +); // Starts executing a thread. -static inline zn_status_t zn_thread_start(zn_handle_t thread, uintptr_t ip, uintptr_t sp, uintptr_t arg) { - return zn_syscall4(thread, ip, sp, arg, ZN_SYSCALL_THREAD_START); -} +zn_status_t zn_thread_start(zn_handle_t thread, uintptr_t ip, uintptr_t sp, uintptr_t arg); // Stops execution of the calling thread. -static inline void zn_thread_exit(void) { - zn_syscall0(ZN_SYSCALL_THREAD_EXIT); -} +void zn_thread_exit(void); #ifdef __cplusplus } diff --git a/kernel/arch/x86_64/hpet.c b/kernel/arch/x86_64/hpet.c index b0bc7a3..4a97836 100644 --- a/kernel/arch/x86_64/hpet.c +++ b/kernel/arch/x86_64/hpet.c @@ -26,12 +26,12 @@ struct hpet { #define HPET_COUNTER (0xF0 / sizeof(uint64_t)) static void hpet_reset(struct clock* c) { - struct hpet* hpet = CONTAINER_OF(c, struct hpet, clock); + struct hpet* hpet = containerof(c, struct hpet, clock); hpet->regs[HPET_COUNTER] = 0; } static uint64_t hpet_get_elapsed_ns(struct clock* c) { - struct hpet* hpet = CONTAINER_OF(c, struct hpet, clock); + struct hpet* hpet = containerof(c, struct hpet, clock); uint64_t counter = hpet->regs[HPET_COUNTER]; return (counter * (uint64_t)hpet->period / 1'000'000); } diff --git a/kernel/boot/main.c b/kernel/boot/main.c index 72f9dda..16022aa 100644 --- a/kernel/boot/main.c +++ b/kernel/boot/main.c @@ -26,7 +26,7 @@ static zn_status_t load_server( struct task** out ) { struct vas* space; - zn_status_t status = vma_new(&space); + zn_status_t status = vas_new(&space); if (status != ZN_OK) return status; @@ -68,7 +68,7 @@ static void kernel_main_task(uintptr_t arg0) { 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(vas_new(&init_space) == ZN_OK, ""); struct boot_file* file_data = &info->files[0]; struct paged_vmo* init_file; diff --git a/kernel/core/elf.c b/kernel/core/elf.c index c559f70..d3531ec 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -67,7 +67,7 @@ zn_status_t elf_load(struct exec_info* info, struct task** out) { return status; // We map more than we copied so the rest is filled with zeroed pages. - status = vma_map_vmo(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset); + status = vas_map_vmo(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset); if (status) return status; } @@ -182,7 +182,7 @@ zn_status_t elf_load(struct exec_info* info, struct task** out) { uintptr_t argc = num_argv; vmo_write(&stack->object, stack_off, &argc, sizeof(argc), nullptr); - status = vma_map_vmo(info->space, &stack->object, stack_start, stack_size, ZN_VM_MAP_READ | ZN_VM_MAP_WRITE, 0); + status = vas_map_vmo(info->space, &stack->object, stack_start, stack_size, ZN_VM_MAP_READ | ZN_VM_MAP_WRITE, 0); if (status) return status; diff --git a/kernel/core/meson.build b/kernel/core/meson.build index 5156b2b..01149e6 100644 --- a/kernel/core/meson.build +++ b/kernel/core/meson.build @@ -1,9 +1,9 @@ kernel_sources += files( 'channel.c', 'clock.c', - 'futex.c', 'console.c', 'elf.c', + 'futex.c', 'irq.c', 'namespace.c', 'panic.c', @@ -12,4 +12,5 @@ kernel_sources += files( 'sched.c', 'spin.c', 'uacpi_glue.c', + 'vdso.c', ) diff --git a/kernel/core/namespace.c b/kernel/core/namespace.c index 1e9c2a0..b9d209f 100644 --- a/kernel/core/namespace.c +++ b/kernel/core/namespace.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,7 @@ zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_des return ZN_ERR_INTERNAL; // Skip over handles that are already in use (e.g. hard-coded handles). + // mutex_lock(&namespace->mutex); zn_handle_t handle; do { handle = atomic_fetch_add_explicit(&namespace->next_handle, 1, memory_order_acq_rel); @@ -35,6 +37,8 @@ zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_des zn_status_t status = hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default); + // mutex_unlock(&namespace->mutex); + if (status != ZN_OK) return status; @@ -45,6 +49,8 @@ zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_des zn_status_t namespace_add_desc_at(struct namespace* namespace, struct namespace_desc desc, zn_handle_t handle) { if (!namespace) return ZN_ERR_INTERNAL; + + // Skip Invalid or reserved handles. if (handle <= ZN_HANDLE_INVALID) return ZN_ERR_BAD_HANDLE; diff --git a/kernel/core/vdso.c b/kernel/core/vdso.c new file mode 100644 index 0000000..4200d41 --- /dev/null +++ b/kernel/core/vdso.c @@ -0,0 +1,10 @@ +#include +#include +#include + +[[__used, __section(".vdso")]] +const uint8_t vdso_bytes[] = { +#embed VDSO_PATH +}; + +const size_t vdso_length = sizeof(vdso_bytes); diff --git a/include/zinnia/syscall_numbers.h b/kernel/include/kernel/syscall_numbers.h similarity index 89% rename from include/zinnia/syscall_numbers.h rename to kernel/include/kernel/syscall_numbers.h index 77bd23e..c10a138 100644 --- a/include/zinnia/syscall_numbers.h +++ b/kernel/include/kernel/syscall_numbers.h @@ -1,5 +1,4 @@ -#ifndef ZINNIA_SYSCALL_NUMBERS_H -#define ZINNIA_SYSCALL_NUMBERS_H +#pragma once typedef enum { ZN_SYSCALL_LOG, @@ -32,5 +31,3 @@ typedef enum { ZN_SYSCALL_FUTEX_WAIT, ZN_SYSCALL_FUTEX_WAKE, } zn_syscall_t; - -#endif diff --git a/include/zinnia/syscall_stubs.h b/kernel/include/kernel/syscall_stubs.h similarity index 97% rename from include/zinnia/syscall_stubs.h rename to kernel/include/kernel/syscall_stubs.h index 2b00d8d..367e226 100644 --- a/include/zinnia/syscall_stubs.h +++ b/kernel/include/kernel/syscall_stubs.h @@ -1,14 +1,9 @@ -#ifndef ZINNIA_SYSCALL_STUBS_H -#define ZINNIA_SYSCALL_STUBS_H +#pragma once #include -#include +#include #include -#ifdef __cplusplus -extern "C" { -#endif - #ifdef __x86_64__ typedef uint64_t zn_arg_t; #elif defined(__aarch64__) @@ -78,6 +73,9 @@ typedef uint64_t zn_arg_t; #error "Unsupported architecture!" #endif +// These symbols should not be used in the kernel, ever. +#ifdef IN_VDSO + static inline zn_status_t zn_syscall0(zn_syscall_t num) { register zn_syscall_t rnum asm(ASM_REG_NUM) = num; register zn_status_t value asm(ASM_REG_RET); @@ -245,8 +243,4 @@ static inline zn_status_t zn_syscall8( num \ ) -#ifdef __cplusplus -} -#endif - #endif diff --git a/kernel/include/kernel/vas.h b/kernel/include/kernel/vas.h index d5cfbbf..192634f 100644 --- a/kernel/include/kernel/vas.h +++ b/kernel/include/kernel/vas.h @@ -13,12 +13,12 @@ struct vas { }; // Try to create a new, empty virtual address space. -zn_status_t vma_new(struct vas** out); +zn_status_t vas_new(struct vas** out); // Delete a virtual address space. -void vma_delete(struct vas* vm); +void vas_delete(struct vas* vm); -zn_status_t vma_map_vmo( +zn_status_t vas_map_vmo( struct vas* vm, struct vmo* vmo, uintptr_t addr, @@ -28,12 +28,12 @@ zn_status_t vma_map_vmo( ); // Remove any mappings in the given address range. -zn_status_t vma_unmap(struct vas* vm, uintptr_t vaddr, size_t size); +zn_status_t vas_unmap(struct vas* vm, uintptr_t vaddr, size_t size); // Change the protection of an existing mapping. -zn_status_t vma_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags); +zn_status_t vas_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags); // Try to handle a page fault. -bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type); +bool vas_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type); extern struct vas kernel_vas; diff --git a/kernel/include/kernel/vdso.h b/kernel/include/kernel/vdso.h index 0a2cf5c..a229e51 100644 --- a/kernel/include/kernel/vdso.h +++ b/kernel/include/kernel/vdso.h @@ -1,6 +1,30 @@ #pragma once +#include #include -extern uint8_t __ld_vdso_start[]; -extern uint8_t __ld_vdso_end[]; +extern const uint8_t vdso_bytes[]; +extern const size_t vdso_length; + +// Data which is shared between the kernel and VAS. +// The kernel updates its contents continuously, which is visible to every VAS. +struct vdso_kernel_data { + struct { + uint64_t sec; + uint64_t nsec; + } time; +}; + +#ifdef IN_VDSO + +#include +#include + +// Export a function under the current API version. +#define VDSO_SYMBOL(fn) asm(".symver " #fn ",__vdso_" #fn "@@ZINNIA_0") +// Export a function as a symbol for an older API version. +#define VDSO_SYMBOL_LEGACY(fn, symbol, ver) asm(".symver " #fn ",__vdso_" #symbol "@ZINNIA_" ver) + +extern const volatile struct vdso_kernel_data vdso_data; + +#endif diff --git a/kernel/kernel.ld b/kernel/kernel.ld index 9b940c4..40e2fa0 100644 --- a/kernel/kernel.ld +++ b/kernel/kernel.ld @@ -30,6 +30,10 @@ SECTIONS KEEP(*(.cmdline)) __ld_cmdline_end = .; + __ld_vdso_start = .; + KEEP(*(.vdso)) + __ld_vdso_end = .; + *(.rodata .rodata.*) *(.got .got.*) diff --git a/kernel/mem/meson.build b/kernel/mem/meson.build index 5bf1b93..7500720 100644 --- a/kernel/mem/meson.build +++ b/kernel/mem/meson.build @@ -5,7 +5,7 @@ kernel_sources += files( 'pmm.c', 'slab.c', 'usercopy.c', + 'vas.c', 'virt.c', - 'vma.c', 'vmo.c', ) diff --git a/kernel/mem/vma.c b/kernel/mem/vas.c similarity index 88% rename from kernel/mem/vma.c rename to kernel/mem/vas.c index 6be4e84..d922e6b 100644 --- a/kernel/mem/vma.c +++ b/kernel/mem/vas.c @@ -5,7 +5,7 @@ #include // Try to create a new, empty virtual address space. -zn_status_t vma_new(struct vas** out) { +zn_status_t vas_new(struct vas** out) { debug_assert(out != nullptr, "Missing out"); zn_status_t res; @@ -30,23 +30,23 @@ err0: } // Delete a virtual address space. -void vma_delete(struct vas* vm) {} +void vas_delete(struct vas* vm) {} // Remove any mappings in the given address range. // May fail if there is no memory and a mapping needs to be split. -zn_status_t vma_unmap(struct vas* vm, uintptr_t vaddr, size_t size); +zn_status_t vas_unmap(struct vas* vm, uintptr_t vaddr, size_t size); // Change the protection of an existing mapping. // May fail if there is no memory and a mapping needs to be split. -zn_status_t vma_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags); +zn_status_t vas_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags); // Try to handle a page fault. -bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type) { +bool vas_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type) { // TODO return false; } -zn_status_t vma_map_vmo( +zn_status_t vas_map_vmo( struct vas* vas, struct vmo* vmo, uintptr_t addr, diff --git a/kernel/mem/vmo.c b/kernel/mem/vmo.c index 0f6704a..1694843 100644 --- a/kernel/mem/vmo.c +++ b/kernel/mem/vmo.c @@ -101,7 +101,7 @@ zn_status_t vmo_copy( } static zn_status_t paged_get_page(struct vmo* vmo, uintptr_t offset_idx, struct page** out) { - struct paged_vmo* paged = CONTAINER_OF(vmo, struct paged_vmo, object); + struct paged_vmo* paged = containerof(vmo, struct paged_vmo, object); // Try to find the requested page in the cache. struct page_list* iter; @@ -177,7 +177,7 @@ struct phys_range_vmo { }; static zn_status_t phys_range_get_page(struct vmo* vmo, uintptr_t offset_idx, struct page** out) { - struct phys_range_vmo* p = CONTAINER_OF(vmo, struct phys_range_vmo, object); + struct phys_range_vmo* p = containerof(vmo, struct phys_range_vmo, object); *out = &vm_pfndb[(p->start / arch_mem_page_size()) + offset_idx]; return ZN_OK; } diff --git a/kernel/meson.build b/kernel/meson.build index 04a7147..945bfe7 100644 --- a/kernel/meson.build +++ b/kernel/meson.build @@ -34,6 +34,7 @@ subdir('core') subdir('syscalls') subdir('klibc') +subdir('vdso') executable( 'zinnia', @@ -44,11 +45,12 @@ executable( ], c_args: kernel_c_args, link_args: kernel_link_args, - link_depends: kernel_lds, + link_depends: [ + kernel_lds, + vdso, + ], sources: [ kernel_sources, uacpi_sources, ], - install: true, - install_dir: '/boot', ) diff --git a/kernel/syscalls/dispatch.c b/kernel/syscalls/dispatch.c index df7f91b..a12d8bf 100644 --- a/kernel/syscalls/dispatch.c +++ b/kernel/syscalls/dispatch.c @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include #include #include diff --git a/kernel/syscalls/vmo.c b/kernel/syscalls/vmo.c index 116edcf..d9c1597 100644 --- a/kernel/syscalls/vmo.c +++ b/kernel/syscalls/vmo.c @@ -118,7 +118,7 @@ zn_status_t syscall_vmo_map(struct arch_context* ctx) { if (!usercopy_write(addr, &target_addr, sizeof(target_addr))) return ZN_ERR_BAD_BUFFER; } - vma_map_vmo(vas, vmo, target_addr, bytes, flags, vmo_offset); + vas_map_vmo(vas, vmo, target_addr, bytes, flags, vmo_offset); return ZN_OK; } diff --git a/kernel/vdso/archctl.c b/kernel/vdso/archctl.c new file mode 100644 index 0000000..a12ce28 --- /dev/null +++ b/kernel/vdso/archctl.c @@ -0,0 +1,8 @@ +#include +#include + +zn_status_t zn_archctl(zn_archctl_t op, void* value) { + return zn_syscall2(op, value, ZN_SYSCALL_ARCHCTL); +} + +VDSO_SYMBOL(zn_archctl); diff --git a/kernel/vdso/channel.c b/kernel/vdso/channel.c new file mode 100644 index 0000000..8784275 --- /dev/null +++ b/kernel/vdso/channel.c @@ -0,0 +1,43 @@ +#include +#include + +zn_status_t zn_channel_create(enum zn_channel_flags flags, zn_handle_t* endpoint0, zn_handle_t* endpoint1) { + return zn_syscall3(flags, endpoint0, endpoint1, ZN_SYSCALL_CHANNEL_CREATE); +} + +VDSO_SYMBOL(zn_channel_create); + +zn_status_t zn_channel_write( + zn_handle_t channel, + const zn_handle_t* handles, + const void* bytes, + size_t num_handles, + size_t num_bytes +) { + return zn_syscall5(channel, handles, bytes, num_handles, num_bytes, ZN_SYSCALL_CHANNEL_WRITE); +} + +VDSO_SYMBOL(zn_channel_write); + +zn_status_t zn_channel_read( + zn_handle_t channel, + zn_handle_t* handles, + void* bytes, + size_t num_handles, + size_t num_bytes, + size_t* read_handles, + size_t* read_bytes +) { + return zn_syscall7( + channel, + handles, + bytes, + num_handles, + num_bytes, + read_handles, + read_bytes, + ZN_SYSCALL_CHANNEL_READ + ); +} + +VDSO_SYMBOL(zn_channel_read); diff --git a/kernel/vdso/data.c b/kernel/vdso/data.c new file mode 100644 index 0000000..d665942 --- /dev/null +++ b/kernel/vdso/data.c @@ -0,0 +1,7 @@ +#include +#include + +[[__used, __section(".vdso_data")]] +const volatile struct vdso_kernel_data vdso_data = {0}; + +static_assert(sizeof(vdso_data) <= 0x1000); diff --git a/kernel/vdso/futex.c b/kernel/vdso/futex.c new file mode 100644 index 0000000..6e9880c --- /dev/null +++ b/kernel/vdso/futex.c @@ -0,0 +1,14 @@ +#include +#include + +zn_status_t zn_futex_wait(int32_t* addr, int32_t expected) { + return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT); +} + +VDSO_SYMBOL(zn_futex_wait); + +zn_status_t zn_futex_wake(int32_t* addr, int32_t count) { + return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE); +} + +VDSO_SYMBOL(zn_futex_wake); diff --git a/kernel/vdso/handle.c b/kernel/vdso/handle.c new file mode 100644 index 0000000..1cb5b08 --- /dev/null +++ b/kernel/vdso/handle.c @@ -0,0 +1,20 @@ +#include +#include + +zn_status_t zn_handle_validate(zn_handle_t handle) { + return zn_syscall1(handle, ZN_SYSCALL_HANDLE_VALIDATE); +} + +VDSO_SYMBOL(zn_handle_validate); + +zn_status_t zn_handle_drop(zn_handle_t handle) { + return zn_syscall1(handle, ZN_SYSCALL_HANDLE_DROP); +} + +VDSO_SYMBOL(zn_handle_drop); + +zn_status_t zn_handle_clone(zn_handle_t handle, zn_rights_t cloned_rights, zn_handle_t* cloned) { + return zn_syscall3(handle, cloned_rights, cloned, ZN_SYSCALL_HANDLE_CLONE); +} + +VDSO_SYMBOL(zn_handle_clone); diff --git a/kernel/vdso/mem.c b/kernel/vdso/mem.c new file mode 100644 index 0000000..4fa2219 --- /dev/null +++ b/kernel/vdso/mem.c @@ -0,0 +1,33 @@ +#include +#include + +zn_status_t zn_vmo_create(size_t length, zn_handle_t* out) { + return zn_syscall2(length, out, ZN_SYSCALL_VMO_CREATE); +} + +VDSO_SYMBOL(zn_vmo_create); + +zn_status_t zn_vmo_create_phys(uintptr_t phys_addr, size_t length, zn_handle_t* out) { + return zn_syscall3(phys_addr, length, out, ZN_SYSCALL_VMO_CREATE_PHYS); +} + +VDSO_SYMBOL(zn_vmo_create_phys); + +zn_status_t zn_vmo_map( + zn_handle_t vmo, + zn_handle_t vas, + uintptr_t vmo_offset, + uintptr_t* addr, + size_t bytes, + enum zn_vm_flags flags +) { + return zn_syscall6(vmo, vas, vmo_offset, addr, bytes, flags, ZN_SYSCALL_VMO_MAP); +} + +VDSO_SYMBOL(zn_vmo_map); + +zn_status_t zn_vas_create(zn_handle_t* out) { + return zn_syscall1(out, ZN_SYSCALL_VAS_CREATE); +} + +VDSO_SYMBOL(zn_vas_create); diff --git a/kernel/vdso/meson.build b/kernel/vdso/meson.build new file mode 100644 index 0000000..1b788d1 --- /dev/null +++ b/kernel/vdso/meson.build @@ -0,0 +1,48 @@ +vdso_c_args = [ + '-ffreestanding', + '-fno-stack-protector', + '-fno-omit-frame-pointer', + '-fPIE', + '-fPIC', + '-nostdinc', + '-DIN_VDSO', +] + +vdso_lds = meson.current_source_dir() / 'vdso.ld' + +vdso_link_args = [ + '-ffreestanding', + '-nostdlib', + '-static', + '-T' + vdso_lds, +] + +# Build a shared library, which we are going to embed next. +# TODO: We need to ensure there are no relocations inside the vDSO. +vdso = shared_library( + 'zinnia-vdso', + name_prefix: '', + c_args: vdso_c_args, + include_directories: [ + common_includes, + kernel_includes, + ], + link_args: vdso_link_args, + link_depends: vdso_lds, + sources: [ + 'archctl.c', + 'channel.c', + 'data.c', + 'futex.c', + 'handle.c', + 'mem.c', + 'namespace.c', + 'random.c', + 'status.c', + 'system.c', + 'thread.c', + ], +) + +# Tell the kernel where the built binary lives so we can #embed it. +kernel_c_args += ['-DVDSO_PATH="' + vdso.full_path() + '"'] diff --git a/kernel/vdso/namespace.c b/kernel/vdso/namespace.c new file mode 100644 index 0000000..5d0059d --- /dev/null +++ b/kernel/vdso/namespace.c @@ -0,0 +1,14 @@ +#include +#include + +zn_status_t zn_ns_create(zn_handle_t* out) { + return ZN_ERR_UNSUPPORTED; +} + +VDSO_SYMBOL(zn_ns_create); + +zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_ns) { + return ZN_ERR_UNSUPPORTED; +} + +VDSO_SYMBOL(zn_ns_move); diff --git a/kernel/vdso/random.c b/kernel/vdso/random.c new file mode 100644 index 0000000..96ac483 --- /dev/null +++ b/kernel/vdso/random.c @@ -0,0 +1,14 @@ +#include +#include + +zn_status_t zn_random_get(void* addr, size_t len) { + return zn_syscall2(addr, len, ZN_SYSCALL_RANDOM_GET); +} + +VDSO_SYMBOL(zn_random_get); + +zn_status_t zn_random_entropy(const void* addr, size_t len) { + return zn_syscall2(addr, len, ZN_SYSCALL_RANDOM_ENTROPY); +} + +VDSO_SYMBOL(zn_random_entropy); diff --git a/kernel/vdso/status.c b/kernel/vdso/status.c new file mode 100644 index 0000000..9be4d1a --- /dev/null +++ b/kernel/vdso/status.c @@ -0,0 +1,35 @@ +#include +#include + +const char* zn_status_to_string(zn_status_t err) { + switch (err) { + case ZN_OK: + return "No error (OK)"; + case ZN_ERR_INTERNAL: + return "An internal error occured (INTERNAL)"; + case ZN_ERR_BAD_SYSCALL: + return "Syscall number is not a recognized syscall (BAD_SYSCALL)"; + case ZN_ERR_UNSUPPORTED: + return "This operation is not supported or implemented yet (UNSUPPORTED)"; + case ZN_ERR_NO_MEMORY: + return "System does not have enough free memory for this operation (NO_MEMORY)"; + case ZN_ERR_NO_HANDLES: + return "Process can not own any more handles (NO_HANDLES)"; + case ZN_ERR_INVALID: + return "One or more of the provided arguments is not valid (INVALID)"; + case ZN_ERR_BAD_RANGE: + return "Argument is outside of the range for valid values (BAD_RANGE)"; + case ZN_ERR_BAD_HANDLE: + return "Object handle does not name a valid object (BAD_HANDLE)"; + case ZN_ERR_BAD_PERMS: + return "Object has insufficient permissions for this operation (BAD_PERMS)"; + case ZN_ERR_BAD_BUFFER: + return "Buffer is not large enough or doesn't point to a valid memory region (BAD_BUFFER)"; + case ZN_ERR_ALREADY_EXISTS: + return "The resource already exists (ALREADY_EXISTS)"; + } + + return "Unknown error code"; +} + +VDSO_SYMBOL(zn_status_to_string); diff --git a/kernel/vdso/system.c b/kernel/vdso/system.c new file mode 100644 index 0000000..e34d803 --- /dev/null +++ b/kernel/vdso/system.c @@ -0,0 +1,28 @@ +#include +#include + +void zn_log(const char* message, size_t len) { + zn_syscall2(message, len, ZN_SYSCALL_LOG); +} + +VDSO_SYMBOL(zn_log); + +size_t zn_page_size() { + size_t size = 0; + zn_syscall1(&size, ZN_SYSCALL_PAGE_SIZE); + return size; +} + +VDSO_SYMBOL(zn_page_size); + +zn_status_t zn_powerctl() { + return ZN_ERR_UNSUPPORTED; +} + +VDSO_SYMBOL(zn_powerctl); + +uint64_t zn_time() { + return vdso_data.time.nsec; +} + +VDSO_SYMBOL(zn_time); diff --git a/kernel/vdso/thread.c b/kernel/vdso/thread.c new file mode 100644 index 0000000..d6fd07e --- /dev/null +++ b/kernel/vdso/thread.c @@ -0,0 +1,26 @@ +#include +#include + +zn_status_t zn_thread_create( + zn_handle_t ns, + const char* name, + size_t name_len, + enum zn_thread_flags flags, + zn_handle_t* out +) { + return zn_syscall5(ns, name, name_len, flags, out, ZN_SYSCALL_THREAD_CREATE); +} + +VDSO_SYMBOL(zn_thread_create); + +zn_status_t zn_thread_start(zn_handle_t thread, uintptr_t ip, uintptr_t sp, uintptr_t arg) { + return zn_syscall4(thread, ip, sp, arg, ZN_SYSCALL_THREAD_START); +} + +VDSO_SYMBOL(zn_thread_start); + +void zn_thread_exit(void) { + zn_syscall0(ZN_SYSCALL_THREAD_EXIT); +} + +VDSO_SYMBOL(zn_thread_exit); diff --git a/kernel/vdso/vdso.ld b/kernel/vdso/vdso.ld new file mode 100644 index 0000000..b46fb96 --- /dev/null +++ b/kernel/vdso/vdso.ld @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +VERSION { + ZINNIA_0 { + global: + __vdso*; + local: *; + }; +} + +PHDRS { + text PT_LOAD FILEHDR PHDRS FLAGS(5); + dynamic PT_DYNAMIC FLAGS(4); + note PT_NOTE FLAGS(4); +} + +SECTIONS +{ + . = SIZEOF_HEADERS; + + .text : { + *(.text .text.*) + *(.plt .plt.*) + } :text + + .rodata : { + *(.rodata .rodata.*) + *(.got .got.*) + } :text + + .data ALIGN(CONSTANT(MAXPAGESIZE)) : { + *(.vdso_data) + } :text + + .dynsym : { + *(.dynsym) + } :text + + .dynstr : { + *(.dynstr) + } :text + + .dynamic : { + *(.dynamic) + } :text :dynamic + + /DISCARD/ : + { + *(.data*) + *(.bss*) + *(.comment*) + *(.eh_frame*) + *(.rel.eh_frame*) + *(.gcc_except_table*) + *(.note.gnu.property) + *(.interp) + } +} diff --git a/lib/meson.build b/lib/meson.build index e69de29..cd7d3a8 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -0,0 +1,7 @@ +libzinnia = static_library( + 'zinnia', + sources: [ + 'vdso.c', + ], + include_directories: common_includes, +) diff --git a/lib/vdso.c b/lib/vdso.c new file mode 100644 index 0000000..dd71ef6 --- /dev/null +++ b/lib/vdso.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint8_t vdso_symbol_bind(uint8_t info) { + return ELF64_ST_BIND(info); +} + +static uint8_t vdso_symbol_type(uint8_t info) { + return ELF64_ST_TYPE(info); +} + +struct vdso_info { + uintptr_t base; + const char* strings; + const struct elf64_sym* symbols; + size_t symbol_count; +}; + +static bool vdso_info_init(struct vdso_info* info) { + const uintptr_t base = getauxval(AT_SYSINFO_EHDR); + if (!base) + return false; + + const struct elf64_ehdr* ehdr = (const void*)base; + if (ehdr->e_ident[EI_MAG0] != ELF_MAG[0] || ehdr->e_ident[EI_MAG1] != ELF_MAG[1] || + ehdr->e_ident[EI_MAG2] != ELF_MAG[2] || ehdr->e_ident[EI_MAG3] != ELF_MAG[3] || + ehdr->e_ident[EI_CLASS] != ELFCLASS64 || ehdr->e_ident[EI_DATA] != ELFDATA2LSB || + ehdr->e_machine != ELF_ARCH_MACHINE) + return false; + + const struct elf64_dyn* dynamic = nullptr; + for (size_t i = 0; i < ehdr->e_phnum; i++) { + const struct elf64_phdr* phdr = (const void*)(base + ehdr->e_phoff + (i * ehdr->e_phentsize)); + if (phdr->p_type == PT_DYNAMIC) { + dynamic = (const void*)(base + phdr->p_vaddr); + break; + } + } + if (!dynamic) + return false; + + const char* strings = nullptr; + const struct elf64_sym* symbols = nullptr; + const struct elf_hash* hash = nullptr; + + for (const struct elf64_dyn* entry = dynamic; entry->d_tag != DT_NULL; entry++) { + switch (entry->d_tag) { + case DT_STRTAB: + strings = (const void*)(base + entry->d_un.d_ptr); + break; + case DT_SYMTAB: + symbols = (const void*)(base + entry->d_un.d_ptr); + break; + case DT_HASH: + hash = (const void*)(base + entry->d_un.d_ptr); + break; + default: + break; + } + } + + if (!strings || !symbols || !hash) + return false; + + *info = (struct vdso_info){ + .base = base, + .strings = strings, + .symbols = symbols, + .symbol_count = hash->n_chain, + }; + return true; +} + +static void* vdso_lookup(const char* name) { + struct vdso_info info; + if (!vdso_info_init(&info)) + return nullptr; + + for (size_t i = 0; i < info.symbol_count; i++) { + const struct elf64_sym* symbol = &info.symbols[i]; + if (vdso_symbol_bind(symbol->st_info) != STB_GLOBAL || vdso_symbol_type(symbol->st_info) != STT_FUNC) + continue; + + const char* symbol_name = info.strings + symbol->st_name; + const char* lhs = symbol_name; + const char* rhs = name; + while (*lhs && *lhs == *rhs) { + lhs++; + rhs++; + } + if (*lhs == 0 && *rhs == 0) + return (void*)(info.base + symbol->st_value); + } + + return nullptr; +} + +#define VDSO_IFUNC(name) \ + static typeof(name)* resolve_##name(void) { \ + return (typeof(name)*)vdso_lookup("__vdso_" #name); \ + } \ + typeof(name) name __attribute__((ifunc("resolve_" #name))); + +VDSO_IFUNC(zn_archctl); +VDSO_IFUNC(zn_channel_create); +VDSO_IFUNC(zn_channel_write); +VDSO_IFUNC(zn_channel_read); +VDSO_IFUNC(zn_futex_wait); +VDSO_IFUNC(zn_futex_wake); +VDSO_IFUNC(zn_handle_validate); +VDSO_IFUNC(zn_handle_drop); +VDSO_IFUNC(zn_handle_clone); +VDSO_IFUNC(zn_vmo_create); +VDSO_IFUNC(zn_vmo_create_phys); +VDSO_IFUNC(zn_vmo_map); +VDSO_IFUNC(zn_vas_create); +VDSO_IFUNC(zn_ns_create); +VDSO_IFUNC(zn_ns_move); +VDSO_IFUNC(zn_random_get); +VDSO_IFUNC(zn_random_entropy); +VDSO_IFUNC(zn_status_to_string); +VDSO_IFUNC(zn_log); +VDSO_IFUNC(zn_page_size); +VDSO_IFUNC(zn_powerctl); +VDSO_IFUNC(zn_time); +VDSO_IFUNC(zn_thread_create); +VDSO_IFUNC(zn_thread_start); +VDSO_IFUNC(zn_thread_exit); diff --git a/servers/devd/meson.build b/servers/devd/meson.build index 251c678..20143b1 100644 --- a/servers/devd/meson.build +++ b/servers/devd/meson.build @@ -11,5 +11,6 @@ executable( common_includes, uacpi_includes, ], + link_with: libzinnia, install: true, ) diff --git a/servers/initd/meson.build b/servers/initd/meson.build index 2fdc56c..8045288 100644 --- a/servers/initd/meson.build +++ b/servers/initd/meson.build @@ -3,6 +3,7 @@ executable( 'main.c', # The init process is linked statically because the dynamic loader can't be read before posixd is up. link_args: '-static', + link_with: libzinnia, include_directories: common_includes, install: true, ) diff --git a/servers/unix/main.c b/servers/unix/main.c index 853d131..c407896 100644 --- a/servers/unix/main.c +++ b/servers/unix/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -54,6 +55,7 @@ int other_fn(void* arg) { } int main(int argc, char* argv[], char* envp[]) { + zn_archctl(ZN_ARCHCTL_SET_FSBASE, nullptr); zn_printf("unix: starting...\n"); const char* thread_name = "unix_second_thread"; diff --git a/servers/unix/meson.build b/servers/unix/meson.build index 3569570..fed321e 100644 --- a/servers/unix/meson.build +++ b/servers/unix/meson.build @@ -4,7 +4,7 @@ executable( 'unix', 'main.c', 'uname.c', - link_args: '-static', + link_with: libzinnia, include_directories: [common_includes, 'include'], install: true, )