test
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
#include <zinnia/archctl.h>
|
||||
#include <zinnia/syscalls.h>
|
||||
|
||||
errno_t arch_archctl(zn_archctl_t op, uintptr_t value);
|
||||
|
||||
errno_t syscall_archctl(struct arch_context* ctx) {
|
||||
return arch_archctl((zn_archctl_t)ctx->ARCH_CTX_A0, (uintptr_t)ctx->ARCH_CTX_A1);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/syscall.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <zinnia/utils.h>
|
||||
|
||||
static const syscall_fn_t dispatch_table[] = {
|
||||
#undef __ZINNIA_UAPI_SYSCALL_NUMBERS_H // We want to include the header again
|
||||
#define __SYSCALL_DEFINE(idx, name) [idx] = syscall_##name,
|
||||
#include <uapi/syscall_numbers.h>
|
||||
#undef __SYSCALL_DEFINE
|
||||
};
|
||||
|
||||
void syscall_dispatch(struct arch_context* ctx) {
|
||||
const size_t num = ctx->ARCH_CTX_NUM;
|
||||
|
||||
if (num >= ARRAY_SIZE(dispatch_table)) {
|
||||
ctx->ARCH_CTX_RET0 = ENOSYS;
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_table[num](ctx);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/futex.h>
|
||||
#include <zinnia/syscall.h>
|
||||
|
||||
errno_t syscall_futex_wait(struct arch_context* ctx) {
|
||||
__user int* addr = (__user int*)ctx->ARCH_CTX_A0;
|
||||
int expected = (int)ctx->ARCH_CTX_A1;
|
||||
|
||||
return futex_wait(addr, expected);
|
||||
}
|
||||
|
||||
errno_t syscall_futex_wake(struct arch_context* ctx) {
|
||||
__user int* addr = (__user int*)ctx->ARCH_CTX_A0;
|
||||
int count = (int)ctx->ARCH_CTX_A1;
|
||||
|
||||
return futex_wake(addr, count);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/namespace.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/rights.h>
|
||||
#include <zinnia/syscalls.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
|
||||
errno_t syscall_handle_clone(struct arch_context* ctx) {
|
||||
zn_handle_t handle = ctx->ARCH_CTX_A0;
|
||||
zn_rights_t cloned_rights = ctx->ARCH_CTX_A1;
|
||||
__user zn_handle_t* cloned = (__user zn_handle_t*)ctx->ARCH_CTX_A2;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
struct namespace* ns = current->namespace;
|
||||
|
||||
struct namespace_desc desc;
|
||||
errno_t status = namespace_get(ns, handle, &desc);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
zn_handle_t new_handle;
|
||||
status = namespace_clone_desc(ns, &desc, cloned_rights, &new_handle);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(cloned, &new_handle, sizeof(new_handle))) {
|
||||
namespace_del_desc(ns, new_handle);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t syscall_handle_drop(struct arch_context* ctx) {
|
||||
zn_handle_t handle = ctx->ARCH_CTX_A0;
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
|
||||
return namespace_del_desc(current->namespace, handle);
|
||||
}
|
||||
|
||||
errno_t syscall_handle_validate(struct arch_context* ctx) {
|
||||
zn_handle_t handle = ctx->ARCH_CTX_A0;
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
|
||||
struct namespace_desc desc;
|
||||
return namespace_get(current->namespace, handle, &desc);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
kernel_sources += files(
|
||||
'archctl.c',
|
||||
'dispatch.c',
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/syscalls.h>
|
||||
|
||||
errno_t syscall_random_entropy(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
errno_t syscall_random_get(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/clock.h>
|
||||
#include <zinnia/console.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/syscalls.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
|
||||
errno_t syscall_log(struct arch_context* ctx) {
|
||||
__user const char* msg = (__user const char*)ctx->ARCH_CTX_A0;
|
||||
size_t len = ctx->ARCH_CTX_A1;
|
||||
|
||||
char* buf = mem_alloc(len, ALLOC_NOZERO);
|
||||
if (!buf) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (usercopy_read(buf, msg, len)) {
|
||||
console_write(buf, len);
|
||||
|
||||
mem_free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_free(buf);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
errno_t syscall_page_size(struct arch_context* ctx) {
|
||||
__user size_t* out = (__user size_t*)ctx->ARCH_CTX_A0;
|
||||
|
||||
size_t size = arch_mem_page_size();
|
||||
if (!usercopy_write(out, &size, sizeof(size)))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t syscall_time(struct arch_context* ctx) {
|
||||
__user uint64_t* out = (__user uint64_t*)ctx->ARCH_CTX_A0;
|
||||
|
||||
uint64_t time = clock_get_elapsed_ns();
|
||||
if (!usercopy_write(out, &time, sizeof(time)))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <string.h>
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/syscall.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
|
||||
errno_t syscall_thread_create(struct arch_context* ctx) {
|
||||
zn_handle_t ns_handle = ctx->ARCH_CTX_A0;
|
||||
__user const char* name = (__user const char*)ctx->ARCH_CTX_A1;
|
||||
size_t name_len = ctx->ARCH_CTX_A2;
|
||||
enum zn_thread_flags flags = ctx->ARCH_CTX_A3;
|
||||
__user zn_handle_t* out = (__user zn_handle_t*)ctx->ARCH_CTX_A4;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
// Resolve namespace.
|
||||
struct namespace* ns;
|
||||
if (ns_handle == ZN_HANDLE_THIS_NS) {
|
||||
ns = current->namespace;
|
||||
} else {
|
||||
struct namespace_desc ns_desc;
|
||||
errno_t status = namespace_get(current->namespace, ns_handle, &ns_desc);
|
||||
if (status != 0)
|
||||
return status;
|
||||
if (ns_desc.type != NAMESPACE_DESC_NS)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
ns = ns_desc.value.namespace;
|
||||
}
|
||||
|
||||
// Copy name from userspace.
|
||||
if (name_len == 0 || name_len >= TASK_NAME_MAX)
|
||||
return EINVAL;
|
||||
|
||||
char task_name[TASK_NAME_MAX] = {};
|
||||
if (!usercopy_read(task_name, name, name_len))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
|
||||
// Create the task sharing the caller's address space.
|
||||
// Uses sched_to_user as a placeholder entry — the real IP/SP come from thread_start.
|
||||
struct task* new_task;
|
||||
errno_t status = task_create(task_name, current->space, ns, sched_to_user, 0, &new_task);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
// Register the task as a handle in the caller's namespace.
|
||||
struct namespace_desc desc = {
|
||||
.type = NAMESPACE_DESC_TASK,
|
||||
.rights = ZN_RIGHTS_ALL,
|
||||
.value.task = new_task,
|
||||
};
|
||||
|
||||
zn_handle_t handle;
|
||||
status = namespace_add_desc(current->namespace, desc, &handle);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(out, &handle, sizeof(handle))) {
|
||||
namespace_del_desc(current->namespace, handle);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t syscall_thread_start(struct arch_context* ctx) {
|
||||
zn_handle_t thread_handle = ctx->ARCH_CTX_A0;
|
||||
uintptr_t ip = ctx->ARCH_CTX_A1;
|
||||
uintptr_t sp = ctx->ARCH_CTX_A2;
|
||||
uintptr_t arg = ctx->ARCH_CTX_A3;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
struct sched_percpu* sched = &percpu_get()->sched;
|
||||
|
||||
// Look up the task.
|
||||
struct namespace_desc desc;
|
||||
errno_t status = namespace_get(current->namespace, thread_handle, &desc);
|
||||
if (status != 0)
|
||||
return status;
|
||||
if (desc.type != NAMESPACE_DESC_TASK)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
|
||||
struct task* task = desc.value.task;
|
||||
|
||||
// Allocate a start info block for the thread entry.
|
||||
struct task_start_info* info = mem_alloc(sizeof(struct task_start_info), 0);
|
||||
if (!info)
|
||||
return ENOMEM;
|
||||
|
||||
info->ip = ip;
|
||||
info->sp = sp;
|
||||
info->arg = arg;
|
||||
|
||||
// Re-initialize the task's arch context to enter user mode via sched_to_user_arg.
|
||||
status =
|
||||
arch_task_init(&task->context, sched_to_user, (uintptr_t)info, task->kernel_stack + KERNEL_STACK_SIZE, true);
|
||||
if (status != 0) {
|
||||
mem_free(info);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Add to run queue.
|
||||
sched_add_task(sched, task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t syscall_thread_exit(struct arch_context* ctx) {
|
||||
struct sched_percpu* sched = &percpu_get()->sched;
|
||||
sched->current->state = TASK_STATE_DEAD;
|
||||
sched_yield(sched);
|
||||
unreachable();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/syscalls.h>
|
||||
|
||||
errno_t syscall_vas_create(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
Reference in New Issue
Block a user