stuff
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
#include <zinnia/archctl.h>
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
zn_status_t arch_archctl(zn_archctl_t op, uintptr_t value);
|
||||
|
||||
zn_status_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,259 @@
|
||||
#include <zinnia/channel.h>
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/channel.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/percpu.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/usercopy.h>
|
||||
|
||||
zn_status_t syscall_channel_create(struct arch_context* ctx) {
|
||||
__user zn_handle_t* end0 = (__user zn_handle_t*)ctx->ARCH_CTX_A1;
|
||||
__user zn_handle_t* end1 = (__user zn_handle_t*)ctx->ARCH_CTX_A2;
|
||||
|
||||
struct channel* ep0;
|
||||
struct channel* ep1;
|
||||
zn_status_t status = channel_create(&ep0, &ep1);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
|
||||
struct namespace_desc desc0 = {
|
||||
.type = NAMESPACE_DESC_CHANNEL,
|
||||
.rights = ZN_RIGHTS_ALL,
|
||||
.value.channel = ep0,
|
||||
};
|
||||
struct namespace_desc desc1 = {
|
||||
.type = NAMESPACE_DESC_CHANNEL,
|
||||
.rights = ZN_RIGHTS_ALL,
|
||||
.value.channel = ep1,
|
||||
};
|
||||
|
||||
zn_handle_t h0, h1;
|
||||
status = namespace_add_desc(current->namespace, desc0, &h0);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
status = namespace_add_desc(current->namespace, desc1, &h1);
|
||||
if (status != ZN_OK) {
|
||||
namespace_del_desc(current->namespace, h0);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!usercopy_write(end0, &h0, sizeof(h0))) {
|
||||
namespace_del_desc(current->namespace, h0);
|
||||
namespace_del_desc(current->namespace, h1);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
if (!usercopy_write(end1, &h1, sizeof(h1))) {
|
||||
namespace_del_desc(current->namespace, h0);
|
||||
namespace_del_desc(current->namespace, h1);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_t syscall_channel_write(struct arch_context* ctx) {
|
||||
zn_handle_t ch_handle = ctx->ARCH_CTX_A0;
|
||||
__user zn_handle_t* handles = (__user zn_handle_t*)ctx->ARCH_CTX_A1;
|
||||
__user void* bytes = (__user void*)ctx->ARCH_CTX_A2;
|
||||
size_t num_handles = ctx->ARCH_CTX_A3;
|
||||
size_t num_bytes = ctx->ARCH_CTX_A4;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
|
||||
// Look up the channel.
|
||||
struct namespace_desc desc;
|
||||
zn_status_t status = namespace_get(current->namespace, ch_handle, &desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
if (desc.type != NAMESPACE_DESC_CHANNEL)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
|
||||
struct channel* ch = desc.value.channel;
|
||||
|
||||
// Copy byte data from userspace.
|
||||
void* msg_data = nullptr;
|
||||
if (num_bytes > 0) {
|
||||
if (!bytes)
|
||||
return ZN_ERR_INVALID;
|
||||
|
||||
msg_data = mem_alloc(num_bytes, ALLOC_NOZERO);
|
||||
if (!msg_data)
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
|
||||
if (!usercopy_read(msg_data, bytes, num_bytes)) {
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy and transfer handles (move semantics).
|
||||
struct namespace_desc* descs = nullptr;
|
||||
if (num_handles > 0) {
|
||||
if (!handles) {
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_INVALID;
|
||||
}
|
||||
|
||||
// Read handle values from userspace.
|
||||
size_t handles_size = num_handles * sizeof(zn_handle_t);
|
||||
zn_handle_t* src_handles = mem_alloc(handles_size, ALLOC_NOZERO);
|
||||
if (!src_handles) {
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!usercopy_read(src_handles, handles, handles_size)) {
|
||||
mem_free(src_handles);
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
// Resolve all handles to descriptors before removing any.
|
||||
descs = mem_alloc(num_handles * sizeof(struct namespace_desc), ALLOC_NOZERO);
|
||||
if (!descs) {
|
||||
mem_free(src_handles);
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_handles; i++) {
|
||||
status = namespace_get(current->namespace, src_handles[i], &descs[i]);
|
||||
if (status != ZN_OK) {
|
||||
mem_free(descs);
|
||||
mem_free(src_handles);
|
||||
mem_free(msg_data);
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove handles from sender's namespace.
|
||||
for (size_t i = 0; i < num_handles; i++) {
|
||||
namespace_del_desc(current->namespace, src_handles[i]);
|
||||
}
|
||||
|
||||
mem_free(src_handles);
|
||||
}
|
||||
|
||||
// Send the message through the channel.
|
||||
status = channel_write(ch, msg_data, num_bytes, descs, num_handles);
|
||||
if (status != ZN_OK) {
|
||||
mem_free(msg_data);
|
||||
mem_free(descs);
|
||||
return status;
|
||||
}
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_t syscall_channel_read(struct arch_context* ctx) {
|
||||
zn_handle_t ch_handle = ctx->ARCH_CTX_A0;
|
||||
__user zn_handle_t* handles = (__user zn_handle_t*)ctx->ARCH_CTX_A1;
|
||||
__user void* bytes = (__user void*)ctx->ARCH_CTX_A2;
|
||||
size_t num_handles = ctx->ARCH_CTX_A3;
|
||||
size_t num_bytes = ctx->ARCH_CTX_A4;
|
||||
__user size_t* read_handles = (__user size_t*)ctx->ARCH_CTX_A5;
|
||||
__user size_t* read_bytes = (__user size_t*)ctx->ARCH_CTX_A6;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
struct sched_percpu* sched = &percpu_get()->sched;
|
||||
|
||||
// Look up the channel.
|
||||
struct namespace_desc ch_desc;
|
||||
zn_status_t status = namespace_get(current->namespace, ch_handle, &ch_desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
if (ch_desc.type != NAMESPACE_DESC_CHANNEL)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
|
||||
struct channel* ch = ch_desc.value.channel;
|
||||
|
||||
// Block until a message is available.
|
||||
while (true) {
|
||||
struct channel_msg* msg;
|
||||
status = channel_read(ch, &msg);
|
||||
|
||||
if (status == ZN_OK) {
|
||||
// Copy byte data to userspace.
|
||||
size_t bytes_to_copy = msg->num_bytes < num_bytes ? msg->num_bytes : num_bytes;
|
||||
if (bytes_to_copy > 0 && bytes) {
|
||||
if (!usercopy_write(bytes, msg->data, bytes_to_copy)) {
|
||||
channel_msg_free(msg);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer handle descriptors into the reader's namespace.
|
||||
size_t handles_to_copy = msg->num_handles < num_handles ? msg->num_handles : num_handles;
|
||||
if (handles_to_copy > 0 && handles) {
|
||||
for (size_t i = 0; i < handles_to_copy; i++) {
|
||||
zn_handle_t new_handle;
|
||||
status = namespace_add_desc(current->namespace, msg->descs[i], &new_handle);
|
||||
if (status != ZN_OK) {
|
||||
channel_msg_free(msg);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!usercopy_write(&handles[i], &new_handle, sizeof(new_handle))) {
|
||||
channel_msg_free(msg);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write actual counts to userspace.
|
||||
if (read_bytes) {
|
||||
if (!usercopy_write(read_bytes, &msg->num_bytes, sizeof(msg->num_bytes))) {
|
||||
channel_msg_free(msg);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_handles) {
|
||||
if (!usercopy_write(read_handles, &msg->num_handles, sizeof(msg->num_handles))) {
|
||||
channel_msg_free(msg);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
channel_msg_free(msg);
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
if (status == ZN_ERR_BAD_HANDLE)
|
||||
return status;
|
||||
|
||||
// Empty but peer alive — block until a message arrives or peer closes.
|
||||
sched_block(sched, &ch->waiters);
|
||||
}
|
||||
}
|
||||
|
||||
zn_status_t syscall_channel_wait(struct arch_context* ctx) {
|
||||
zn_handle_t ch_handle = ctx->ARCH_CTX_A0;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
struct sched_percpu* sched = &percpu_get()->sched;
|
||||
|
||||
struct namespace_desc desc;
|
||||
zn_status_t status = namespace_get(current->namespace, ch_handle, &desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
if (desc.type != NAMESPACE_DESC_CHANNEL)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
|
||||
struct channel* ch = desc.value.channel;
|
||||
|
||||
status = channel_poll(ch);
|
||||
if (status == ZN_ERR_INVALID) {
|
||||
sched_block(sched, &ch->waiters);
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#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/syscalls.h>
|
||||
#include <kernel/types.h>
|
||||
|
||||
static const syscall_fn_t dispatch_table[] = {
|
||||
[ZN_SYSCALL_LOG] = syscall_log,
|
||||
[ZN_SYSCALL_ARCHCTL] = syscall_archctl,
|
||||
[ZN_SYSCALL_PAGE_SIZE] = syscall_page_size,
|
||||
[ZN_SYSCALL_TIME] = syscall_time,
|
||||
[ZN_SYSCALL_HANDLE_VALIDATE] = syscall_handle_validate,
|
||||
[ZN_SYSCALL_HANDLE_DROP] = syscall_handle_drop,
|
||||
[ZN_SYSCALL_HANDLE_CLONE] = syscall_handle_clone,
|
||||
[ZN_SYSCALL_VAS_CREATE] = syscall_vas_create,
|
||||
[ZN_SYSCALL_VMO_CREATE] = syscall_vmo_create,
|
||||
[ZN_SYSCALL_VMO_CREATE_PHYS] = syscall_vmo_create_phys,
|
||||
[ZN_SYSCALL_VMO_MAP] = syscall_vmo_map,
|
||||
[ZN_SYSCALL_CHANNEL_CREATE] = syscall_channel_create,
|
||||
[ZN_SYSCALL_CHANNEL_WAIT] = syscall_channel_wait,
|
||||
[ZN_SYSCALL_CHANNEL_READ] = syscall_channel_read,
|
||||
[ZN_SYSCALL_CHANNEL_WRITE] = syscall_channel_write,
|
||||
[ZN_SYSCALL_THREAD_CREATE] = syscall_thread_create,
|
||||
[ZN_SYSCALL_THREAD_START] = syscall_thread_start,
|
||||
[ZN_SYSCALL_THREAD_EXIT] = syscall_thread_exit,
|
||||
[ZN_SYSCALL_RANDOM_GET] = syscall_random_get,
|
||||
[ZN_SYSCALL_RANDOM_ENTROPY] = syscall_random_entropy,
|
||||
[ZN_SYSCALL_FUTEX_WAIT] = syscall_futex_wait,
|
||||
[ZN_SYSCALL_FUTEX_WAKE] = syscall_futex_wake,
|
||||
};
|
||||
|
||||
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 = ZN_ERR_BAD_SYSCALL;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->ARCH_CTX_RET0 = dispatch_table[num](ctx);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/futex.h>
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
zn_status_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);
|
||||
}
|
||||
|
||||
zn_status_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/handle.h>
|
||||
#include <zinnia/rights.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/percpu.h>
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/usercopy.h>
|
||||
|
||||
zn_status_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;
|
||||
zn_status_t status = namespace_get(ns, handle, &desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
zn_handle_t new_handle;
|
||||
status = namespace_clone_desc(ns, &desc, cloned_rights, &new_handle);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(cloned, &new_handle, sizeof(new_handle))) {
|
||||
namespace_del_desc(ns, new_handle);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_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);
|
||||
}
|
||||
|
||||
zn_status_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,12 @@
|
||||
kernel_sources += files(
|
||||
'archctl.c',
|
||||
'channel.c',
|
||||
'dispatch.c',
|
||||
'futex.c',
|
||||
'handle.c',
|
||||
'random.c',
|
||||
'system.c',
|
||||
'thread.c',
|
||||
'vas.c',
|
||||
'vmo.c',
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
zn_status_t syscall_random_entropy(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
zn_status_t syscall_random_get(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/clock.h>
|
||||
#include <kernel/console.h>
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/usercopy.h>
|
||||
|
||||
zn_status_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 ZN_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (usercopy_read(buf, msg, len)) {
|
||||
console_write(buf, len);
|
||||
|
||||
mem_free(buf);
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
mem_free(buf);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
zn_status_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 ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_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 ZN_OK;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/rights.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <zinnia/thread.h>
|
||||
#include <common/compiler.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/percpu.h>
|
||||
#include <kernel/print.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/usercopy.h>
|
||||
#include <string.h>
|
||||
|
||||
zn_status_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;
|
||||
zn_status_t status = namespace_get(current->namespace, ns_handle, &ns_desc);
|
||||
if (status != ZN_OK)
|
||||
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 ZN_ERR_INVALID;
|
||||
|
||||
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;
|
||||
zn_status_t status = task_create(task_name, current->space, ns, sched_to_user, 0, &new_task);
|
||||
if (status != ZN_OK)
|
||||
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 != ZN_OK)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(out, &handle, sizeof(handle))) {
|
||||
namespace_del_desc(current->namespace, handle);
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_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;
|
||||
zn_status_t status = namespace_get(current->namespace, thread_handle, &desc);
|
||||
if (status != ZN_OK)
|
||||
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 ZN_ERR_NO_MEMORY;
|
||||
|
||||
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 != ZN_OK) {
|
||||
mem_free(info);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Add to run queue.
|
||||
sched_add_task(sched, task);
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_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/status.h>
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
zn_status_t syscall_vas_create(struct arch_context* ctx) {
|
||||
return ZN_ERR_UNSUPPORTED;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#include <zinnia/handle.h>
|
||||
#include <zinnia/status.h>
|
||||
#include <common/utils.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/percpu.h>
|
||||
#include <kernel/print.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/usercopy.h>
|
||||
#include <kernel/vas.h>
|
||||
#include <kernel/vmo.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
zn_status_t syscall_vmo_create(struct arch_context* ctx) {
|
||||
size_t length = ctx->ARCH_CTX_A0;
|
||||
__user zn_handle_t* out = (__user zn_handle_t*)ctx->ARCH_CTX_A1;
|
||||
|
||||
// Allocate new VMO.
|
||||
struct paged_vmo* vmo;
|
||||
zn_status_t status = vmo_new_phys(&vmo);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
struct namespace_desc desc = {
|
||||
.type = NAMESPACE_DESC_VMO,
|
||||
.rights = ZN_RIGHTS_COMMON | ZN_RIGHT_READ | ZN_RIGHT_WRITE | ZN_RIGHT_MAP,
|
||||
.value.vmo = &vmo->object,
|
||||
};
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
zn_handle_t handle;
|
||||
status = namespace_add_desc(current->namespace, desc, &handle);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(out, &handle, sizeof(handle)))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_t syscall_vmo_create_phys(struct arch_context* ctx) {
|
||||
uintptr_t addr = ctx->ARCH_CTX_A0;
|
||||
size_t length = ctx->ARCH_CTX_A1;
|
||||
__user zn_handle_t* out = (__user zn_handle_t*)ctx->ARCH_CTX_A2;
|
||||
|
||||
struct vmo* vmo;
|
||||
zn_status_t status = vmo_new_phys_range(addr, length, &vmo);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
struct namespace_desc desc = {
|
||||
.type = NAMESPACE_DESC_VMO,
|
||||
.rights = ZN_RIGHTS_COMMON | ZN_RIGHT_READ | ZN_RIGHT_WRITE | ZN_RIGHT_MAP,
|
||||
.value.vmo = vmo,
|
||||
};
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
zn_handle_t handle;
|
||||
status = namespace_add_desc(current->namespace, desc, &handle);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
|
||||
if (!usercopy_write(out, &handle, sizeof(handle)))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_t syscall_vmo_map(struct arch_context* ctx) {
|
||||
zn_handle_t vmo_handle = ctx->ARCH_CTX_A0;
|
||||
zn_handle_t vas_handle = ctx->ARCH_CTX_A1;
|
||||
uintptr_t vmo_offset = ctx->ARCH_CTX_A2;
|
||||
__user uintptr_t* addr = (__user uintptr_t*)ctx->ARCH_CTX_A3;
|
||||
size_t bytes = ctx->ARCH_CTX_A4;
|
||||
enum zn_vm_flags flags = ctx->ARCH_CTX_A5;
|
||||
|
||||
struct task* current = percpu_get()->sched.current;
|
||||
|
||||
// Get VAS.
|
||||
struct vas* vas;
|
||||
if (vas_handle == ZN_HANDLE_THIS_VAS) {
|
||||
vas = current->space;
|
||||
} else {
|
||||
struct namespace_desc vas_desc;
|
||||
zn_status_t status = namespace_get(current->namespace, vmo_handle, &vas_desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
if (vas_desc.type != NAMESPACE_DESC_VAS)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
vas = vas_desc.value.vas;
|
||||
}
|
||||
|
||||
// Get VMO.
|
||||
struct namespace_desc vmo_desc;
|
||||
zn_status_t status = namespace_get(current->namespace, vmo_handle, &vmo_desc);
|
||||
if (status != ZN_OK)
|
||||
return status;
|
||||
if (vmo_desc.type != NAMESPACE_DESC_VMO)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
struct vmo* vmo = vmo_desc.value.vmo;
|
||||
|
||||
// Determine mapping address.
|
||||
uintptr_t target_addr = 0;
|
||||
if (addr != nullptr) {
|
||||
if (!usercopy_read(&target_addr, addr, sizeof(target_addr)))
|
||||
return ZN_ERR_BAD_BUFFER;
|
||||
}
|
||||
|
||||
// TODO: Use actual allocator for user task.
|
||||
if (target_addr == 0) {
|
||||
static uintptr_t map_offset = 0xA000'0000;
|
||||
target_addr = atomic_fetch_add(&map_offset, ALIGN_UP(bytes, arch_mem_page_size()));
|
||||
}
|
||||
|
||||
if (addr != nullptr) {
|
||||
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);
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user