[kernel] Pass objects not handles to syscall impls
This commit contains a couple large, interdependent changes: - In preparation for capability checking, the _syscall_verify_* functions now load most handles passed in, and verify that they exist and are of the correct type. Lists and out-handles are not converted to objects. - Also in preparation for capability checking, the internal representation of handles has changed. j6_handle_t is now 32 bits, and a new j6_cap_t (also 32 bits) is added. Handles of a process are now a util::map<j6_handle_t, handle> where handle is a new struct containing the id, capabilities, and object pointer. - The kernel object definition DSL gained a few changes to support auto generating the handle -> object conversion in the _syscall_verify_* functions, mostly knowing the object type, and an optional "cname" attribute on objects where their names differ from C++ code. (Specifically vma/vm_area) - Kernel object code and other code under kernel/objects is now in a new obj:: namespace, because fuck you <cstdlib> for putting "system" in the global namespace. Why even have that header then? - Kernel object types constructed with the construct_handle helper now have a creation_caps static member to declare what capabilities a newly created object's handle should have.
This commit is contained in:
@@ -4,29 +4,27 @@
|
||||
#include "objects/channel.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
channel_create(j6_handle_t *handle)
|
||||
channel_create(j6_handle_t *self)
|
||||
{
|
||||
construct_handle<channel>(handle);
|
||||
construct_handle<channel>(self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
channel_send(j6_handle_t handle, size_t *len, void *data)
|
||||
channel_send(channel *self, size_t *len, void *data)
|
||||
{
|
||||
channel *c = get_handle<channel>(handle);
|
||||
if (!c) return j6_err_invalid_arg;
|
||||
return c->enqueue(len, data);
|
||||
return self->enqueue(len, data);
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
channel_receive(j6_handle_t handle, size_t *len, void *data)
|
||||
channel_receive(channel *self, size_t *len, void *data)
|
||||
{
|
||||
channel *c = get_handle<channel>(handle);
|
||||
if (!c) return j6_err_invalid_arg;
|
||||
return c->dequeue(len, data);
|
||||
return self->dequeue(len, data);
|
||||
}
|
||||
|
||||
} // namespace syscalls
|
||||
|
||||
@@ -5,62 +5,61 @@
|
||||
#include "objects/endpoint.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
endpoint_create(j6_handle_t *handle)
|
||||
endpoint_create(j6_handle_t *self)
|
||||
{
|
||||
construct_handle<endpoint>(handle);
|
||||
construct_handle<endpoint>(self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
endpoint_send(j6_handle_t handle, uint64_t tag, const void * data, size_t data_len)
|
||||
endpoint_send(endpoint *self, uint64_t tag, const void * data, size_t data_len)
|
||||
{
|
||||
if (tag & j6_tag_system_flag)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
return e->send(tag, data, data_len);
|
||||
return self->send(tag, data, data_len);
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
endpoint_receive(j6_handle_t handle, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
|
||||
endpoint_receive(endpoint *self, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
|
||||
{
|
||||
// Data is marked optional, but we need the length, and if length > 0,
|
||||
// data is not optional.
|
||||
if (!data_len || (*data_len && !data))
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
// Use local variables instead of the passed-in pointers, since
|
||||
// they may get filled in when the sender is running, which means
|
||||
// a different user VM space would be active.
|
||||
j6_tag_t out_tag = j6_tag_invalid;
|
||||
size_t out_len = *data_len;
|
||||
j6_status_t s = e->receive(&out_tag, data, &out_len, timeout);
|
||||
j6_status_t s = self->receive(&out_tag, data, &out_len, timeout);
|
||||
*tag = out_tag;
|
||||
*data_len = out_len;
|
||||
return s;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
endpoint_sendrecv(j6_handle_t handle, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
|
||||
endpoint_sendrecv(endpoint *self, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
|
||||
{
|
||||
if (*tag & j6_tag_system_flag)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
j6_status_t status = e->send(*tag, data, *data_len);
|
||||
j6_status_t status = self->send(*tag, data, *data_len);
|
||||
if (status != j6_status_ok)
|
||||
return status;
|
||||
|
||||
// Use local variables instead of the passed-in pointers, since
|
||||
// they may get filled in when the sender is running, which means
|
||||
// a different user VM space would be active.
|
||||
j6_tag_t out_tag = j6_tag_invalid;
|
||||
size_t out_len = *data_len;
|
||||
j6_status_t s = e->receive(&out_tag, data, &out_len, timeout);
|
||||
j6_status_t s = self->receive(&out_tag, data, &out_len, timeout);
|
||||
*tag = out_tag;
|
||||
*data_len = out_len;
|
||||
return s;
|
||||
|
||||
@@ -10,38 +10,41 @@
|
||||
namespace syscalls {
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T * construct_handle(j6_handle_t *handle, Args... args)
|
||||
T * construct_handle(j6_handle_t *id, Args... args)
|
||||
{
|
||||
process &p = process::current();
|
||||
obj::process &p = obj::process::current();
|
||||
T *o = new T {args...};
|
||||
*handle = p.add_handle(o);
|
||||
*id = p.add_handle(o, T::creation_caps);
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T * get_handle(j6_handle_t handle)
|
||||
obj::handle * get_handle(j6_handle_t id)
|
||||
{
|
||||
process &p = process::current();
|
||||
kobject *o = p.lookup_handle(handle);
|
||||
if (!o || o->get_type() != T::type)
|
||||
obj::process &p = obj::process::current();
|
||||
obj::handle *h = p.lookup_handle(id);
|
||||
if (!h || h->type() != T::type)
|
||||
return nullptr;
|
||||
return static_cast<T*>(o);
|
||||
return h;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline kobject * get_handle<kobject>(j6_handle_t handle)
|
||||
inline obj::handle * get_handle<obj::kobject>(j6_handle_t id)
|
||||
{
|
||||
process &p = process::current();
|
||||
return p.lookup_handle(handle);
|
||||
obj::process &p = obj::process::current();
|
||||
return p.lookup_handle(id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T * remove_handle(j6_handle_t handle)
|
||||
T * remove_handle(j6_handle_t id)
|
||||
{
|
||||
T *o = get_handle<T>(handle);
|
||||
if (o) {
|
||||
process &p = process::current();
|
||||
p.remove_handle(handle);
|
||||
obj::handle *h = get_handle<T>(id);
|
||||
T *o = nullptr;
|
||||
|
||||
if (h) {
|
||||
o = h->object;
|
||||
obj::process &p = obj::process::current();
|
||||
p.remove_handle(id);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -8,34 +8,28 @@
|
||||
#include "objects/thread.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
kobject_koid(j6_handle_t handle, j6_koid_t *koid)
|
||||
kobject_koid(kobject *self, j6_koid_t *koid)
|
||||
{
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
*koid = obj->koid();
|
||||
*koid = self->koid();
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
kobject_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs)
|
||||
kobject_wait(kobject *self, j6_signal_t mask, j6_signal_t *sigs)
|
||||
{
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
j6_signal_t current = obj->signals();
|
||||
j6_signal_t current = self->signals();
|
||||
if ((current & mask) != 0) {
|
||||
*sigs = current;
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
thread &th = thread::current();
|
||||
obj->add_blocked_thread(&th);
|
||||
self->add_blocked_thread(&th);
|
||||
th.wait_on_signals(mask);
|
||||
|
||||
j6_status_t result = th.get_wait_result();
|
||||
@@ -46,23 +40,24 @@ kobject_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs)
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6_handle_t * handle, uint64_t * signals)
|
||||
kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6_handle_t * woken, uint64_t * signals)
|
||||
{
|
||||
util::vector<kobject*> objects {uint32_t(handles_count)};
|
||||
|
||||
for (unsigned i = 0; i < handles_count; ++i) {
|
||||
j6_handle_t h = handles[i];
|
||||
if (h == j6_handle_invalid)
|
||||
j6_handle_t hid = handles[i];
|
||||
if (hid == j6_handle_invalid)
|
||||
continue;
|
||||
|
||||
kobject *obj = get_handle<kobject>(h);
|
||||
if (!obj)
|
||||
handle *h = get_handle<kobject>(hid);
|
||||
if (!h || !h->object)
|
||||
return j6_err_invalid_arg;
|
||||
kobject *obj = h->object;
|
||||
|
||||
j6_signal_t current = obj->signals();
|
||||
if ((current & mask) != 0) {
|
||||
*signals = current;
|
||||
*handle = h;
|
||||
*woken = hid;
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
@@ -79,43 +74,35 @@ kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
*handle = j6_handle_invalid;
|
||||
*woken = j6_handle_invalid;
|
||||
*signals = th.get_wait_data();
|
||||
j6_koid_t koid = th.get_wait_object();
|
||||
for (unsigned i = 0; i < handles_count; ++i) {
|
||||
if (koid == objects[i]->koid())
|
||||
*handle = handles[i];
|
||||
*woken = handles[i];
|
||||
else
|
||||
objects[i]->remove_blocked_thread(&th);
|
||||
}
|
||||
|
||||
kassert(*handle != j6_handle_invalid,
|
||||
kassert(*woken != j6_handle_invalid,
|
||||
"Somehow woke on a handle that was not waited on");
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
kobject_signal(j6_handle_t handle, j6_signal_t signals)
|
||||
kobject_signal(kobject *self, j6_signal_t signals)
|
||||
{
|
||||
if ((signals & j6_signal_user_mask) != signals)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
obj->assert_signal(signals);
|
||||
self->assert_signal(signals);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
kobject_close(j6_handle_t handle)
|
||||
kobject_close(kobject *self)
|
||||
{
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
obj->close();
|
||||
self->close();
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,41 +5,25 @@
|
||||
#include "objects/process.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
process_create(j6_handle_t *handle)
|
||||
process_create(j6_handle_t *self)
|
||||
{
|
||||
process *child = construct_handle<process>(handle);
|
||||
log::debug(logs::task, "Process %llx created", child->koid());
|
||||
process *p = construct_handle<process>(self);
|
||||
log::debug(logs::task, "Process %llx created", p->koid());
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
process_start(j6_handle_t handle, uintptr_t entrypoint, j6_handle_t * handles, size_t handles_count)
|
||||
process_kill(process *self)
|
||||
{
|
||||
process &p = process::current();
|
||||
process *c = get_handle<process>(handle);
|
||||
if (handles_count && !handles)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
for (size_t i = 0; i < handles_count; ++i) {
|
||||
kobject *o = p.lookup_handle(handles[i]);
|
||||
if (o) c->add_handle(o);
|
||||
}
|
||||
|
||||
return j6_err_nyi;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
process_kill(j6_handle_t handle)
|
||||
{
|
||||
process &p = process::current();
|
||||
process *c = get_handle<process>(handle);
|
||||
if (!c) return j6_err_invalid_arg;
|
||||
|
||||
log::debug(logs::task, "Process %llx killed by process %llx", c->koid(), p.koid());
|
||||
c->exit(-1u);
|
||||
log::debug(logs::task, "Process %llx killed by process %llx", self->koid(), p.koid());
|
||||
self->exit(-1u);
|
||||
|
||||
return j6_status_ok;
|
||||
}
|
||||
@@ -57,16 +41,13 @@ process_exit(int32_t status)
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
process_give_handle(j6_handle_t handle, j6_handle_t sender, j6_handle_t *receiver)
|
||||
process_give_handle(process *self, j6_handle_t target, j6_handle_t *received)
|
||||
{
|
||||
process *dest = get_handle<process>(handle);
|
||||
if (!dest) return j6_err_invalid_arg;
|
||||
handle *target_handle = get_handle<kobject>(target);
|
||||
j6_handle_t out = self->add_handle(target_handle->object, target_handle->caps);
|
||||
|
||||
kobject *o = get_handle<kobject>(sender);
|
||||
j6_handle_t out = dest->add_handle(o);
|
||||
|
||||
if (receiver)
|
||||
*receiver = out;
|
||||
if (received)
|
||||
*received = out;
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
|
||||
extern log::logger &g_logger;
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
using system = class ::system;
|
||||
|
||||
j6_status_t
|
||||
log(const char *message)
|
||||
{
|
||||
@@ -33,7 +37,7 @@ noop()
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_get_log(j6_handle_t sys, void *buffer, size_t *buffer_len)
|
||||
system_get_log(system *self, void *buffer, size_t *buffer_len)
|
||||
{
|
||||
// Buffer is marked optional, but we need the length, and if length > 0,
|
||||
// buffer is not optional.
|
||||
@@ -43,25 +47,22 @@ system_get_log(j6_handle_t sys, void *buffer, size_t *buffer_len)
|
||||
size_t orig_size = *buffer_len;
|
||||
*buffer_len = g_logger.get_entry(buffer, *buffer_len);
|
||||
if (!g_logger.has_log())
|
||||
system::get().deassert_signal(j6_signal_system_has_log);
|
||||
self->deassert_signal(j6_signal_system_has_log);
|
||||
|
||||
return (*buffer_len > orig_size) ? j6_err_insufficient : j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_bind_irq(j6_handle_t sys, j6_handle_t endp, unsigned irq)
|
||||
system_bind_irq(system *self, endpoint *endp, unsigned irq)
|
||||
{
|
||||
endpoint *e = get_handle<endpoint>(endp);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
if (device_manager::get().bind_irq(irq, e))
|
||||
if (device_manager::get().bind_irq(irq, endp))
|
||||
return j6_status_ok;
|
||||
|
||||
return j6_err_invalid_arg;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_map_phys(j6_handle_t handle, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
|
||||
system_map_phys(system *self, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
|
||||
{
|
||||
// TODO: check to see if frames are already used? How would that collide with
|
||||
// the bootloader's allocated pages already being marked used?
|
||||
@@ -75,7 +76,7 @@ system_map_phys(j6_handle_t handle, j6_handle_t * area, uintptr_t phys, size_t s
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_request_iopl(j6_handle_t handle, unsigned iopl)
|
||||
system_request_iopl(system *self, unsigned iopl)
|
||||
{
|
||||
if (iopl != 0 && iopl != 3)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
@@ -6,25 +6,24 @@
|
||||
#include "objects/thread.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
thread_create(j6_handle_t *handle, j6_handle_t proc, uintptr_t stack_top, uintptr_t entrypoint)
|
||||
thread_create(j6_handle_t *self, process *proc, uintptr_t stack_top, uintptr_t entrypoint)
|
||||
{
|
||||
thread &parent_th = thread::current();
|
||||
process &parent_pr = parent_th.parent();
|
||||
|
||||
process *owner = get_handle<process>(proc);
|
||||
if (!owner) return j6_err_invalid_arg;
|
||||
|
||||
thread *child = owner->create_thread(stack_top);
|
||||
thread *child = proc->create_thread(stack_top);
|
||||
child->add_thunk_user(entrypoint);
|
||||
*handle = child->self_handle();
|
||||
*self = child->self_handle();
|
||||
child->clear_state(thread::state::loading);
|
||||
child->set_state(thread::state::ready);
|
||||
|
||||
log::debug(logs::task, "Thread %llx:%llx spawned new thread %llx:%llx",
|
||||
parent_pr.koid(), parent_th.koid(), owner->koid(), child->koid());
|
||||
parent_pr.koid(), parent_th.koid(), proc->koid(), child->koid());
|
||||
|
||||
return j6_status_ok;
|
||||
}
|
||||
@@ -41,14 +40,10 @@ thread_exit(int32_t status)
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
thread_kill(j6_handle_t handle)
|
||||
thread_kill(thread *self)
|
||||
{
|
||||
thread *th = get_handle<thread>(handle);
|
||||
if (!th)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
log::debug(logs::task, "Killing thread %llx", th->koid());
|
||||
th->exit(-1);
|
||||
log::debug(logs::task, "Killing thread %llx", self->koid());
|
||||
self->exit(-1);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,58 +8,45 @@
|
||||
#include "syscalls/helpers.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
vma_create(j6_handle_t *handle, size_t size, uint32_t flags)
|
||||
vma_create(j6_handle_t *self, size_t size, uint32_t flags)
|
||||
{
|
||||
vm_flags f = vm_flags::user_mask & flags;
|
||||
construct_handle<vm_area_open>(handle, size, f);
|
||||
construct_handle<vm_area_open>(self, size, f);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
vma_create_map(j6_handle_t *handle, size_t size, uintptr_t base, uint32_t flags)
|
||||
vma_create_map(j6_handle_t *self, size_t size, uintptr_t base, uint32_t flags)
|
||||
{
|
||||
vm_flags f = vm_flags::user_mask & flags;
|
||||
vm_area *a = construct_handle<vm_area_open>(handle, size, f);
|
||||
vm_area *a = construct_handle<vm_area_open>(self, size, f);
|
||||
process::current().space().add(base, a);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
vma_map(j6_handle_t handle, j6_handle_t proc, uintptr_t base)
|
||||
vma_map(vm_area *self, process *proc, uintptr_t base)
|
||||
{
|
||||
vm_area *a = get_handle<vm_area>(handle);
|
||||
if (!a) return j6_err_invalid_arg;
|
||||
|
||||
process *p = get_handle<process>(proc);
|
||||
if (!p) return j6_err_invalid_arg;
|
||||
|
||||
p->space().add(base, a);
|
||||
proc->space().add(base, self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
vma_unmap(j6_handle_t handle, j6_handle_t proc)
|
||||
vma_unmap(vm_area *self, process *proc)
|
||||
{
|
||||
vm_area *a = get_handle<vm_area>(handle);
|
||||
if (!a) return j6_err_invalid_arg;
|
||||
|
||||
process *p = get_handle<process>(proc);
|
||||
if (!p) return j6_err_invalid_arg;
|
||||
|
||||
p->space().remove(a);
|
||||
proc->space().remove(self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
vma_resize(j6_handle_t handle, size_t *size)
|
||||
vma_resize(vm_area *self, size_t *size)
|
||||
{
|
||||
vm_area *a = get_handle<vm_area>(handle);
|
||||
if (!a) return j6_err_invalid_arg;
|
||||
|
||||
*size = a->resize(*size);
|
||||
*size = self->resize(*size);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user