This commit is contained in:
2026-08-13 17:22:36 +02:00
committed by Marvin Friedrich
parent 5ee30664c5
commit 40cea4dedd
48 changed files with 622 additions and 211 deletions
+2 -2
View File
@@ -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);
}
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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;
+2 -1
View File
@@ -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',
)
+6
View File
@@ -2,6 +2,7 @@
#include <zinnia/rights.h>
#include <zinnia/status.h>
#include <kernel/alloc.h>
#include <kernel/mutex.h>
#include <kernel/namespace.h>
#include <stdatomic.h>
@@ -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;
+10
View File
@@ -0,0 +1,10 @@
#include <common/compiler.h>
#include <kernel/vdso.h>
#include <stdint.h>
[[__used, __section(".vdso")]]
const uint8_t vdso_bytes[] = {
#embed VDSO_PATH
};
const size_t vdso_length = sizeof(vdso_bytes);
+33
View File
@@ -0,0 +1,33 @@
#pragma once
typedef enum {
ZN_SYSCALL_LOG,
ZN_SYSCALL_ARCHCTL,
ZN_SYSCALL_PAGE_SIZE,
ZN_SYSCALL_TIME,
ZN_SYSCALL_HANDLE_VALIDATE,
ZN_SYSCALL_HANDLE_DROP,
ZN_SYSCALL_HANDLE_CLONE,
ZN_SYSCALL_VAS_CREATE,
ZN_SYSCALL_VMO_CREATE,
ZN_SYSCALL_VMO_CREATE_PHYS,
ZN_SYSCALL_VMO_MAP,
ZN_SYSCALL_CHANNEL_CREATE,
ZN_SYSCALL_CHANNEL_WAIT,
ZN_SYSCALL_CHANNEL_READ,
ZN_SYSCALL_CHANNEL_WRITE,
ZN_SYSCALL_THREAD_CREATE,
ZN_SYSCALL_THREAD_START,
ZN_SYSCALL_THREAD_EXIT,
ZN_SYSCALL_RANDOM_GET,
ZN_SYSCALL_RANDOM_ENTROPY,
ZN_SYSCALL_FUTEX_WAIT,
ZN_SYSCALL_FUTEX_WAKE,
} zn_syscall_t;
+246
View File
@@ -0,0 +1,246 @@
#pragma once
#include <zinnia/status.h>
#include <kernel/syscall_numbers.h>
#include <stdint.h>
#ifdef __x86_64__
typedef uint64_t zn_arg_t;
#elif defined(__aarch64__)
typedef uint64_t zn_arg_t;
#elif defined(__riscv) && (__riscv_xlen == 64)
typedef uint64_t zn_arg_t;
#elif defined(__loongarch64)
typedef uint64_t zn_arg_t;
#else
#error "Unsupported architecture!"
#endif
#ifdef __x86_64__
#define ASM_REG_NUM "rax"
#define ASM_REG_RET "rax"
#define ASM_REG_A0 "rdi"
#define ASM_REG_A1 "rsi"
#define ASM_REG_A2 "rdx"
#define ASM_REG_A3 "r9"
#define ASM_REG_A4 "r8"
#define ASM_REG_A5 "r10"
#define ASM_REG_A6 "r12"
#define ASM_REG_A7 "r13"
#define ASM_SYSCALL "syscall"
#define ASM_CLOBBER "rcx", "r11"
#elif defined(__aarch64__)
#define ASM_REG_NUM "x8"
#define ASM_REG_RET "x0"
#define ASM_REG_A0 "x0"
#define ASM_REG_A1 "x1"
#define ASM_REG_A2 "x2"
#define ASM_REG_A3 "x3"
#define ASM_REG_A4 "x4"
#define ASM_REG_A5 "x5"
#define ASM_REG_A6 "x6"
#define ASM_REG_A7 "x7"
#define ASM_SYSCALL "svc 0"
#define ASM_CLOBBER
#elif defined(__riscv) && (__riscv_xlen == 64)
#define ASM_REG_NUM "t3"
#define ASM_REG_RET "a0"
#define ASM_REG_A0 "a0"
#define ASM_REG_A1 "a1"
#define ASM_REG_A2 "a2"
#define ASM_REG_A3 "a3"
#define ASM_REG_A4 "a4"
#define ASM_REG_A5 "a5"
#define ASM_REG_A5 "a6"
#define ASM_REG_A5 "a7"
#define ASM_SYSCALL "ecall"
#define ASM_CLOBBER
#elif defined(__loongarch64)
#define ASM_REG_NUM "a7"
#define ASM_REG_RET "a0"
#define ASM_REG_A0 "a0"
#define ASM_REG_A1 "a1"
#define ASM_REG_A2 "a2"
#define ASM_REG_A3 "a3"
#define ASM_REG_A4 "a4"
#define ASM_REG_A5 "a5"
// TODO: Define ABI
#define ASM_REG_A6 TODO
#define ASM_REG_A7 TODO
#define ASM_SYSCALL "syscall 0"
#define ASM_CLOBBER
#else
#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);
asm volatile(ASM_SYSCALL : "=r"(value) : "r"(rnum) : "memory", ASM_CLOBBER);
return value;
}
static inline zn_status_t zn_syscall1(zn_arg_t a0, zn_syscall_t num) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
asm volatile(ASM_SYSCALL : "=r"(value) : "r"(rnum), "r"(r0) : "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall1(a0, num) zn_syscall1((zn_arg_t)a0, num)
static inline zn_status_t zn_syscall2(zn_arg_t a0, zn_arg_t a1, zn_syscall_t num) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
asm volatile(ASM_SYSCALL : "=r"(value) : "r"(rnum), "r"(r0), "r"(r1) : "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall2(a0, a1, num) zn_syscall2((zn_arg_t)a0, (zn_arg_t)a1, num)
static inline zn_status_t zn_syscall3(zn_arg_t a0, zn_arg_t a1, zn_arg_t a2, zn_syscall_t num) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
asm volatile(ASM_SYSCALL : "=r"(value) : "r"(rnum), "r"(r0), "r"(r1), "r"(r2) : "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall3(a0, a1, a2, num) zn_syscall3((zn_arg_t)a0, (zn_arg_t)a1, (zn_arg_t)a2, num)
static inline zn_status_t zn_syscall4(zn_arg_t a0, zn_arg_t a1, zn_arg_t a2, zn_arg_t a3, zn_syscall_t num) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
register zn_arg_t r3 asm(ASM_REG_A3) = a3;
asm volatile(ASM_SYSCALL : "=r"(value) : "r"(rnum), "r"(r0), "r"(r1), "r"(r2), "r"(r3) : "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall4(a0, a1, a2, a3, num) zn_syscall4((zn_arg_t)a0, (zn_arg_t)a1, (zn_arg_t)a2, (zn_arg_t)a3, num)
static inline zn_status_t zn_syscall5(
zn_arg_t a0,
zn_arg_t a1,
zn_arg_t a2,
zn_arg_t a3,
zn_arg_t a4,
zn_syscall_t num
) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
register zn_arg_t r3 asm(ASM_REG_A3) = a3;
register zn_arg_t r4 asm(ASM_REG_A4) = a4;
asm volatile(ASM_SYSCALL
: "=r"(value)
: "r"(rnum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)
: "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall5(a0, a1, a2, a3, a4, num) \
zn_syscall5((zn_arg_t)a0, (zn_arg_t)a1, (zn_arg_t)a2, (zn_arg_t)a3, (zn_arg_t)a4, num)
static inline zn_status_t zn_syscall6(
zn_arg_t a0,
zn_arg_t a1,
zn_arg_t a2,
zn_arg_t a3,
zn_arg_t a4,
zn_arg_t a5,
zn_syscall_t num
) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
register zn_arg_t r3 asm(ASM_REG_A3) = a3;
register zn_arg_t r4 asm(ASM_REG_A4) = a4;
register zn_arg_t r5 asm(ASM_REG_A5) = a5;
asm volatile(ASM_SYSCALL
: "=r"(value)
: "r"(rnum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)
: "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall6(a0, a1, a2, a3, a4, a5, num) \
zn_syscall6((zn_arg_t)a0, (zn_arg_t)a1, (zn_arg_t)a2, (zn_arg_t)a3, (zn_arg_t)a4, (zn_arg_t)a5, num)
static inline zn_status_t zn_syscall7(
zn_arg_t a0,
zn_arg_t a1,
zn_arg_t a2,
zn_arg_t a3,
zn_arg_t a4,
zn_arg_t a5,
zn_arg_t a6,
zn_syscall_t num
) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
register zn_arg_t r3 asm(ASM_REG_A3) = a3;
register zn_arg_t r4 asm(ASM_REG_A4) = a4;
register zn_arg_t r5 asm(ASM_REG_A5) = a5;
register zn_arg_t r6 asm(ASM_REG_A6) = a6;
asm volatile(ASM_SYSCALL
: "=r"(value)
: "r"(rnum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r6)
: "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall7(a0, a1, a2, a3, a4, a5, a6, num) \
zn_syscall7((zn_arg_t)a0, (zn_arg_t)a1, (zn_arg_t)a2, (zn_arg_t)a3, (zn_arg_t)a4, (zn_arg_t)a5, (zn_arg_t)a6, num)
static inline zn_status_t zn_syscall8(
zn_arg_t a0,
zn_arg_t a1,
zn_arg_t a2,
zn_arg_t a3,
zn_arg_t a4,
zn_arg_t a5,
zn_arg_t a6,
zn_arg_t a7,
zn_syscall_t num
) {
register zn_syscall_t rnum asm(ASM_REG_NUM) = num;
register zn_status_t value asm(ASM_REG_RET);
register zn_arg_t r0 asm(ASM_REG_A0) = a0;
register zn_arg_t r1 asm(ASM_REG_A1) = a1;
register zn_arg_t r2 asm(ASM_REG_A2) = a2;
register zn_arg_t r3 asm(ASM_REG_A3) = a3;
register zn_arg_t r4 asm(ASM_REG_A4) = a4;
register zn_arg_t r5 asm(ASM_REG_A5) = a5;
register zn_arg_t r6 asm(ASM_REG_A6) = a6;
register zn_arg_t r7 asm(ASM_REG_A7) = a7;
asm volatile(ASM_SYSCALL
: "=r"(value)
: "r"(rnum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7)
: "memory", ASM_CLOBBER);
return value;
}
#define zn_syscall8(a0, a1, a2, a3, a4, a5, a6, a7, num) \
zn_syscall8( \
(zn_arg_t)a0, \
(zn_arg_t)a1, \
(zn_arg_t)a2, \
(zn_arg_t)a3, \
(zn_arg_t)a4, \
(zn_arg_t)a5, \
(zn_arg_t)a6, \
(zn_arg_t)a7, \
num \
)
#endif
+6 -6
View File
@@ -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;
+26 -2
View File
@@ -1,6 +1,30 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
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 <kernel/syscall_numbers.h>
#include <kernel/syscall_stubs.h>
// 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
+4
View File
@@ -30,6 +30,10 @@ SECTIONS
KEEP(*(.cmdline))
__ld_cmdline_end = .;
__ld_vdso_start = .;
KEEP(*(.vdso))
__ld_vdso_end = .;
*(.rodata .rodata.*)
*(.got .got.*)
+1 -1
View File
@@ -5,7 +5,7 @@ kernel_sources += files(
'pmm.c',
'slab.c',
'usercopy.c',
'vas.c',
'virt.c',
'vma.c',
'vmo.c',
)
+6 -6
View File
@@ -5,7 +5,7 @@
#include <assert.h>
// 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,
+2 -2
View File
@@ -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;
}
+5 -3
View File
@@ -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',
)
+1 -1
View File
@@ -1,9 +1,9 @@
#include <zinnia/status.h>
#include <zinnia/syscall_numbers.h>
#include <common/compiler.h>
#include <common/utils.h>
#include <kernel/print.h>
#include <kernel/sched.h>
#include <kernel/syscall_numbers.h>
#include <kernel/syscalls.h>
#include <kernel/types.h>
+1 -1
View File
@@ -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;
}
+8
View File
@@ -0,0 +1,8 @@
#include <zinnia/archctl.h>
#include <kernel/vdso.h>
zn_status_t zn_archctl(zn_archctl_t op, void* value) {
return zn_syscall2(op, value, ZN_SYSCALL_ARCHCTL);
}
VDSO_SYMBOL(zn_archctl);
+43
View File
@@ -0,0 +1,43 @@
#include <zinnia/channel.h>
#include <kernel/vdso.h>
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);
+7
View File
@@ -0,0 +1,7 @@
#include <common/compiler.h>
#include <kernel/vdso.h>
[[__used, __section(".vdso_data")]]
const volatile struct vdso_kernel_data vdso_data = {0};
static_assert(sizeof(vdso_data) <= 0x1000);
+14
View File
@@ -0,0 +1,14 @@
#include <zinnia/futex.h>
#include <kernel/vdso.h>
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);
+20
View File
@@ -0,0 +1,20 @@
#include <zinnia/handle.h>
#include <kernel/vdso.h>
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);
+33
View File
@@ -0,0 +1,33 @@
#include <zinnia/mem.h>
#include <kernel/vdso.h>
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);
+48
View File
@@ -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() + '"']
+14
View File
@@ -0,0 +1,14 @@
#include <zinnia/namespace.h>
#include <kernel/vdso.h>
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);
+14
View File
@@ -0,0 +1,14 @@
#include <zinnia/random.h>
#include <kernel/vdso.h>
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);
+35
View File
@@ -0,0 +1,35 @@
#include <zinnia/status.h>
#include <kernel/vdso.h>
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);
+28
View File
@@ -0,0 +1,28 @@
#include <zinnia/system.h>
#include <kernel/vdso.h>
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);
+26
View File
@@ -0,0 +1,26 @@
#include <zinnia/thread.h>
#include <kernel/vdso.h>
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);
+58
View File
@@ -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)
}
}