stuff
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
#ifndef ZINNIA_ARCHCTL_H
|
||||
#define ZINNIA_ARCHCTL_H
|
||||
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
// Does nothing.
|
||||
ZN_ARCHCTL_NONE = 0,
|
||||
// On x86_64, sets the FSBASE MSR to the value.
|
||||
ZN_ARCHCTL_SET_FSBASE = 1,
|
||||
// On x86_64, sets the GSBASE MSR to the value.
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef ZINNIA_CHANNEL_H
|
||||
#define ZINNIA_CHANNEL_H
|
||||
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum zn_channel_flags {
|
||||
ZN_CHANNEL_NONE = 0,
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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_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_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
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef ZINNIA_FUTEX_H
|
||||
#define ZINNIA_FUTEX_H
|
||||
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Blocks the calling thread if *addr == expected.
|
||||
// Returns immediately if the value at addr has changed.
|
||||
static inline zn_status_t zn_futex_wait(int* addr, int expected) {
|
||||
return zn_syscall2(addr, expected, ZN_SYSCALL_FUTEX_WAIT);
|
||||
}
|
||||
|
||||
// Wakes up to `count` threads waiting on the given futex address.
|
||||
static inline zn_status_t zn_futex_wake(int* addr, int count) {
|
||||
return zn_syscall2(addr, count, ZN_SYSCALL_FUTEX_WAKE);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef ZINNIA_HANDLE_H
|
||||
#define ZINNIA_HANDLE_H
|
||||
|
||||
#include <zinnia/rights.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// A generic object handle.
|
||||
typedef int32_t zn_handle_t;
|
||||
|
||||
#define ZN_HANDLE_INVALID ((zn_handle_t)(0))
|
||||
#define ZN_HANDLE_THIS_NS ((zn_handle_t)(-1))
|
||||
#define ZN_HANDLE_THIS_VAS ((zn_handle_t)(-2))
|
||||
#define ZN_HANDLE_THIS_THREAD ((zn_handle_t)(-3))
|
||||
#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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#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[];
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef ZINNIA_MEM_H
|
||||
#define ZINNIA_MEM_H
|
||||
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Virtual memory flags.
|
||||
enum zn_vm_flags {
|
||||
// Mapping is readable.
|
||||
ZN_VM_MAP_READ = 1 << 0,
|
||||
// Mapping is writable.
|
||||
ZN_VM_MAP_WRITE = 1 << 1,
|
||||
// Mapping is executable.
|
||||
ZN_VM_MAP_EXEC = 1 << 2,
|
||||
// Shared memory (not cloned on calls to fork).
|
||||
ZN_VM_MAP_SHARED = 1 << 3,
|
||||
|
||||
// Map at a fixed address, replacing whatever is in the way.
|
||||
ZN_VM_MAP_FIXED = 1 << 8,
|
||||
// Map at a fixed address, failing if anything is in the way.
|
||||
ZB_VM_MAP_FIXED_NOREPLACE = 1 << 9,
|
||||
// Map the entire range immediately.
|
||||
ZN_VM_MAP_POPULATE = 1 << 10,
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Maps `bytes` of `vmo` at `vmo_offset` to `addr` in `vas`.
|
||||
static inline 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);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef ZINNIA_NAMESPACE_H
|
||||
#define ZINNIA_NAMESPACE_H
|
||||
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Creates a new namespace.
|
||||
static inline zn_status_t zn_ns_create(zn_handle_t* out) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static inline zn_status_t zn_ns_move(zn_handle_t handle, zn_handle_t target_namespace) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef ZINNIA_RANDOM_H
|
||||
#define ZINNIA_RANDOM_H
|
||||
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
ZN_RANDOM_MAX_ENTROPY = 0x1000
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef ZINNIA_RIGHTS_H
|
||||
#define ZINNIA_RIGHTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
// Can be read from.
|
||||
ZN_RIGHT_READ = 1u << 0,
|
||||
// Can be written to.
|
||||
ZN_RIGHT_WRITE = 1u << 1,
|
||||
// Can be executed.
|
||||
ZN_RIGHT_EXECUTE = 1u << 2,
|
||||
// Can be mapped in an address space.
|
||||
ZN_RIGHT_MAP = 1u << 3,
|
||||
// Can be moved to another universe.
|
||||
ZN_RIGHT_MOVE = 1u << 4,
|
||||
// Can be cloned.
|
||||
ZN_RIGHT_CLONE = 1u << 5,
|
||||
// Can be deleted.
|
||||
ZN_RIGHT_DELETE = 1u << 6,
|
||||
|
||||
// When cloning, use the same rights as the original.
|
||||
ZN_RIGHTS_IDENTICAL = 1u << 31,
|
||||
ZN_RIGHTS_COMMON = (ZN_RIGHT_MOVE | ZN_RIGHT_CLONE),
|
||||
ZN_RIGHTS_RW = (ZN_RIGHT_READ | ZN_RIGHT_WRITE),
|
||||
ZN_RIGHTS_ALL = ~0u,
|
||||
} zn_rights_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef ZINNIA_STATUS_H
|
||||
#define ZINNIA_STATUS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Status values that may be returned by syscalls or other calls.
|
||||
// A status value of 0 means no error occured.
|
||||
// A negative value indicates a common error, usually from the kernel.
|
||||
typedef enum {
|
||||
ZN_OK = 0,
|
||||
// An internal error occured.
|
||||
ZN_ERR_INTERNAL = -1,
|
||||
// Syscall number is not a recognized syscall.
|
||||
ZN_ERR_BAD_SYSCALL = -2,
|
||||
// This operation is not supported or implemented yet.
|
||||
ZN_ERR_UNSUPPORTED = -3,
|
||||
// System does not have enough free memory for this operation.
|
||||
ZN_ERR_NO_MEMORY = -4,
|
||||
// Process can not own any more handles.
|
||||
ZN_ERR_NO_HANDLES = -5,
|
||||
// One or more of the provided arguments is not valid.
|
||||
ZN_ERR_INVALID = -6,
|
||||
// Argument is outside of the range for valid values.
|
||||
ZN_ERR_BAD_RANGE = -7,
|
||||
// Object handle does not name a valid object or correct type.
|
||||
ZN_ERR_BAD_HANDLE = -8,
|
||||
// Object has insufficient permissions for this operation.
|
||||
ZN_ERR_BAD_PERMS = -9,
|
||||
// Buffer is not large enough or doesn't point to a valid memory region.
|
||||
ZN_ERR_BAD_BUFFER = -10,
|
||||
// The resource already exists.
|
||||
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";
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef ZINNIA_SYSCALL_NUMBERS_H
|
||||
#define ZINNIA_SYSCALL_NUMBERS_H
|
||||
|
||||
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;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,252 @@
|
||||
#ifndef ZINNIA_SYSCALL_STUBS_H
|
||||
#define ZINNIA_SYSCALL_STUBS_H
|
||||
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_numbers.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
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 \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef ZINNIA_SYSTEM_H
|
||||
#define ZINNIA_SYSTEM_H
|
||||
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline void zn_log(const char* message, size_t len) {
|
||||
zn_syscall2(message, len, ZN_SYSCALL_LOG);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
static inline zn_status_t zn_powerctl() {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static inline uint64_t zn_time() {
|
||||
uint64_t time = 0;
|
||||
zn_syscall1(&time, ZN_SYSCALL_TIME);
|
||||
return time;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef ZINNIA_THREAD_H
|
||||
#define ZINNIA_THREAD_H
|
||||
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/syscall_stubs.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum zn_thread_flags {
|
||||
ZN_THREAD_NONE = 0,
|
||||
};
|
||||
|
||||
// Creates a new thread in the given namespace.
|
||||
static inline 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);
|
||||
}
|
||||
|
||||
// Stops execution of the calling thread.
|
||||
static inline void zn_thread_exit(void) {
|
||||
zn_syscall0(ZN_SYSCALL_THREAD_EXIT);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user