Compare commits
2 Commits
d60b2bdc61
...
172bf51db7
Author | SHA1 | Date |
---|---|---|
|
172bf51db7 | |
|
93cf8f2740 |
|
@ -20,6 +20,8 @@ class Capability : public RefCounted<Capability> {
|
|||
template <typename T>
|
||||
RefPtr<T> obj();
|
||||
|
||||
RefPtr<KernelObject> raw_obj() { return obj_; }
|
||||
|
||||
uint64_t permissions() { return permissions_; }
|
||||
bool HasPermissions(uint64_t requested) {
|
||||
return (permissions_ & requested) == requested;
|
||||
|
@ -37,3 +39,28 @@ RefPtr<T> Capability::obj() {
|
|||
}
|
||||
return StaticCastRefPtr<T>(obj_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
z_err_t ValidateCapability(const RefPtr<Capability>& cap,
|
||||
uint64_t permissions) {
|
||||
if (!cap) {
|
||||
return Z_ERR_CAP_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (cap->raw_obj()->TypeTag() != KernelObjectTag<T>::type) {
|
||||
return Z_ERR_CAP_TYPE;
|
||||
}
|
||||
|
||||
if (!cap->HasPermissions(permissions)) {
|
||||
return Z_ERR_CAP_DENIED;
|
||||
}
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
#define RET_IF_NULL(expr) \
|
||||
{ \
|
||||
if (!expr) { \
|
||||
return Z_ERR_CAP_TYPE; \
|
||||
} \
|
||||
}
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#include "syscall/address_space.h"
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
z_err_t AddressSpaceMap(ZAddressSpaceMapReq* req) {
|
||||
auto& curr_proc = gScheduler->CurrentProcess();
|
||||
auto vmas_cap = curr_proc.GetCapability(req->vmas_cap);
|
||||
auto vmmo_cap = curr_proc.GetCapability(req->vmmo_cap);
|
||||
RET_ERR(ValidateCap(vmas_cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCap(vmmo_cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCapability<AddressSpace>(vmas_cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCapability<MemoryObject>(vmmo_cap, ZC_WRITE));
|
||||
|
||||
auto vmas = vmas_cap->obj<AddressSpace>();
|
||||
auto vmmo = vmmo_cap->obj<MemoryObject>();
|
||||
RET_IF_NULL(vmas);
|
||||
RET_IF_NULL(vmmo);
|
||||
|
||||
// FIXME: Validation necessary.
|
||||
if (req->vmas_offset != 0) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "syscall/channel.h"
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
z_err_t ChannelCreate(ZChannelCreateReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
|
@ -15,19 +15,17 @@ z_err_t ChannelCreate(ZChannelCreateReq* req) {
|
|||
z_err_t ChannelSend(ZChannelSendReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
auto chan_cap = proc.GetCapability(req->chan_cap);
|
||||
RET_ERR(ValidateCap(chan_cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCapability<Channel>(chan_cap, ZC_WRITE));
|
||||
|
||||
auto chan = chan_cap->obj<Channel>();
|
||||
RET_IF_NULL(chan);
|
||||
return chan->Write(req->num_bytes, req->data, req->num_caps, req->caps);
|
||||
}
|
||||
|
||||
z_err_t ChannelRecv(ZChannelRecvReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
auto chan_cap = proc.GetCapability(req->chan_cap);
|
||||
RET_ERR(ValidateCap(chan_cap, ZC_READ));
|
||||
RET_ERR(ValidateCapability<Channel>(chan_cap, ZC_READ));
|
||||
|
||||
auto chan = chan_cap->obj<Channel>();
|
||||
RET_IF_NULL(chan);
|
||||
return chan->Read(req->num_bytes, req->data, req->num_caps, req->caps);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "syscall/port.h"
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "interrupt/interrupt.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
z_err_t PortCreate(ZPortCreateReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
|
@ -14,20 +14,18 @@ z_err_t PortCreate(ZPortCreateReq* req) {
|
|||
z_err_t PortSend(ZPortSendReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
auto port_cap = proc.GetCapability(req->port_cap);
|
||||
RET_ERR(ValidateCap(port_cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCapability<Port>(port_cap, ZC_WRITE));
|
||||
|
||||
auto port = port_cap->obj<Port>();
|
||||
RET_IF_NULL(port);
|
||||
return port->Write(req->num_bytes, req->data, req->num_caps, req->caps);
|
||||
}
|
||||
|
||||
z_err_t PortRecv(ZPortRecvReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
auto port_cap = proc.GetCapability(req->port_cap);
|
||||
RET_ERR(ValidateCap(port_cap, ZC_READ));
|
||||
RET_ERR(ValidateCapability<Port>(port_cap, ZC_READ));
|
||||
|
||||
auto port = port_cap->obj<Port>();
|
||||
RET_IF_NULL(port);
|
||||
ZMessage message{
|
||||
.num_bytes = *req->num_bytes,
|
||||
.data = const_cast<void*>(req->data),
|
||||
|
@ -40,10 +38,9 @@ z_err_t PortRecv(ZPortRecvReq* req) {
|
|||
z_err_t PortPoll(ZPortPollReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
auto port_cap = proc.GetCapability(req->port_cap);
|
||||
RET_ERR(ValidateCap(port_cap, ZC_READ));
|
||||
RET_ERR(ValidateCapability<Port>(port_cap, ZC_READ));
|
||||
|
||||
auto port = port_cap->obj<Port>();
|
||||
RET_IF_NULL(port);
|
||||
// FIXME: Race condition here where this call could block if the last message
|
||||
// is removed between this check and the port read.
|
||||
if (!port->HasMessages()) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "syscall/process.h"
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "scheduler/process_manager.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
z_err_t ProcessExit(ZProcessExitReq* req) {
|
||||
auto curr_thread = gScheduler->CurrentThread();
|
||||
|
@ -16,7 +16,7 @@ z_err_t ProcessExit(ZProcessExitReq* req) {
|
|||
z_err_t ProcessSpawn(ZProcessSpawnReq* req) {
|
||||
auto& curr_proc = gScheduler->CurrentProcess();
|
||||
auto cap = curr_proc.GetCapability(req->proc_cap);
|
||||
RET_ERR(ValidateCap(cap, ZC_PROC_SPAWN_PROC));
|
||||
RET_ERR(ValidateCapability<Process>(cap, ZC_PROC_SPAWN_PROC));
|
||||
|
||||
RefPtr<Process> proc = Process::Create();
|
||||
gProcMan->InsertProcess(proc);
|
||||
|
|
|
@ -3,14 +3,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "common/msr.h"
|
||||
#include "debug/debug.h"
|
||||
#include "include/zcall.h"
|
||||
#include "interrupt/interrupt.h"
|
||||
#include "memory/physical_memory.h"
|
||||
#include "object/channel.h"
|
||||
#include "object/port.h"
|
||||
#include "object/process.h"
|
||||
#include "scheduler/process_manager.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/address_space.h"
|
||||
#include "syscall/capability.h"
|
||||
|
@ -20,7 +12,6 @@
|
|||
#include "syscall/port.h"
|
||||
#include "syscall/process.h"
|
||||
#include "syscall/thread.h"
|
||||
#include "usr/zcall_internal.h"
|
||||
|
||||
#define EFER 0xC0000080
|
||||
#define STAR 0xC0000081
|
||||
|
@ -52,25 +43,11 @@ void InitSyscall() {
|
|||
SetMSR(LSTAR, reinterpret_cast<uint64_t>(syscall_enter));
|
||||
}
|
||||
|
||||
z_err_t ValidateCap(const RefPtr<Capability>& cap, uint64_t permissions) {
|
||||
if (!cap) {
|
||||
return Z_ERR_CAP_NOT_FOUND;
|
||||
}
|
||||
// FIXME: Check capability type before permissions, otherwise you can
|
||||
// get a confusing error.
|
||||
if (!cap->HasPermissions(permissions)) {
|
||||
dbgln("PERM, has %x needs %x", cap->permissions(), permissions);
|
||||
return Z_ERR_CAP_DENIED;
|
||||
}
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
#define CASE(name) \
|
||||
case kZion##name: \
|
||||
return name(reinterpret_cast<Z##name##Req*>(req));
|
||||
|
||||
extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
|
||||
RefPtr<Thread> thread = gScheduler->CurrentThread();
|
||||
extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
|
||||
switch (call_id) {
|
||||
// syscall/process.h
|
||||
CASE(ProcessExit);
|
||||
|
@ -101,7 +78,8 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
|
|||
// syscall/debug.h
|
||||
CASE(Debug);
|
||||
default:
|
||||
panic("Unhandled syscall number: %x", call_id);
|
||||
dbgln("Unhandled syscall number: %x", call_id);
|
||||
return Z_ERR_UNIMPLEMENTED;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
|
|
@ -4,13 +4,3 @@
|
|||
#include "include/ztypes.h"
|
||||
|
||||
void InitSyscall();
|
||||
|
||||
// FIXME: This probably belongs in capability.h
|
||||
z_err_t ValidateCap(const RefPtr<Capability>& cap, uint64_t permissions);
|
||||
|
||||
#define RET_IF_NULL(expr) \
|
||||
{ \
|
||||
if (!expr) { \
|
||||
return Z_ERR_CAP_TYPE; \
|
||||
} \
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@ syscall_enter:
|
|||
# Restore caller registers using the userspace rsp in rbx
|
||||
mov 0x40(%rbx), %rdi
|
||||
mov 0x48(%rbx), %rsi
|
||||
mov 0x50(%rbx), %rdx
|
||||
mov 0x58(%rbx), %rcx
|
||||
# Don't push the rbp and rsp as the callee will do so.
|
||||
call SyscallHandler
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
#include "syscall/thread.h"
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
z_err_t ThreadCreate(ZThreadCreateReq* req) {
|
||||
auto& curr_proc = gScheduler->CurrentProcess();
|
||||
auto cap = curr_proc.GetCapability(req->proc_cap);
|
||||
RET_ERR(ValidateCap(cap, ZC_PROC_SPAWN_THREAD));
|
||||
RET_ERR(ValidateCapability<Process>(cap, ZC_PROC_SPAWN_THREAD));
|
||||
|
||||
auto parent_proc = cap->obj<Process>();
|
||||
RET_IF_NULL(parent_proc);
|
||||
auto thread = parent_proc->CreateThread();
|
||||
*req->thread_cap = curr_proc.AddNewCapability(thread, ZC_WRITE);
|
||||
return Z_OK;
|
||||
|
@ -18,10 +17,9 @@ z_err_t ThreadCreate(ZThreadCreateReq* req) {
|
|||
z_err_t ThreadStart(ZThreadStartReq* req) {
|
||||
auto& curr_proc = gScheduler->CurrentProcess();
|
||||
auto cap = curr_proc.GetCapability(req->thread_cap);
|
||||
RET_ERR(ValidateCap(cap, ZC_WRITE));
|
||||
RET_ERR(ValidateCapability<Thread>(cap, ZC_WRITE));
|
||||
|
||||
auto thread = cap->obj<Thread>();
|
||||
RET_IF_NULL(thread);
|
||||
// FIXME: validate entry point is in user space.
|
||||
thread->Start(req->entry, req->arg1, req->arg2);
|
||||
return Z_OK;
|
||||
|
|
Loading…
Reference in New Issue