Compare commits

..

No commits in common. "172bf51db7aa3d3e4d9ed420dde4cc49479cd145" and "d60b2bdc61898f6a72d17cc0fcde356c50641066" have entirely different histories.

9 changed files with 61 additions and 45 deletions

View File

@ -20,8 +20,6 @@ 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;
@ -39,28 +37,3 @@ 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; \
} \
}

View File

@ -1,17 +1,19 @@
#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(ValidateCapability<AddressSpace>(vmas_cap, ZC_WRITE));
RET_ERR(ValidateCapability<MemoryObject>(vmmo_cap, ZC_WRITE));
RET_ERR(ValidateCap(vmas_cap, ZC_WRITE));
RET_ERR(ValidateCap(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) {

View File

@ -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,17 +15,19 @@ 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(ValidateCapability<Channel>(chan_cap, ZC_WRITE));
RET_ERR(ValidateCap(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(ValidateCapability<Channel>(chan_cap, ZC_READ));
RET_ERR(ValidateCap(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);
}

View File

@ -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,18 +14,20 @@ 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(ValidateCapability<Port>(port_cap, ZC_WRITE));
RET_ERR(ValidateCap(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(ValidateCapability<Port>(port_cap, ZC_READ));
RET_ERR(ValidateCap(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),
@ -38,9 +40,10 @@ 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(ValidateCapability<Port>(port_cap, ZC_READ));
RET_ERR(ValidateCap(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()) {

View File

@ -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(ValidateCapability<Process>(cap, ZC_PROC_SPAWN_PROC));
RET_ERR(ValidateCap(cap, ZC_PROC_SPAWN_PROC));
RefPtr<Process> proc = Process::Create();
gProcMan->InsertProcess(proc);

View File

@ -3,6 +3,14 @@
#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"
@ -12,6 +20,7 @@
#include "syscall/port.h"
#include "syscall/process.h"
#include "syscall/thread.h"
#include "usr/zcall_internal.h"
#define EFER 0xC0000080
#define STAR 0xC0000081
@ -43,11 +52,25 @@ 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) {
extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
RefPtr<Thread> thread = gScheduler->CurrentThread();
switch (call_id) {
// syscall/process.h
CASE(ProcessExit);
@ -78,8 +101,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
// syscall/debug.h
CASE(Debug);
default:
dbgln("Unhandled syscall number: %x", call_id);
return Z_ERR_UNIMPLEMENTED;
panic("Unhandled syscall number: %x", call_id);
}
UNREACHABLE
}

View File

@ -4,3 +4,13 @@
#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; \
} \
}

View File

@ -30,6 +30,8 @@ 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

View File

@ -1,14 +1,15 @@
#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(ValidateCapability<Process>(cap, ZC_PROC_SPAWN_THREAD));
RET_ERR(ValidateCap(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;
@ -17,9 +18,10 @@ 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(ValidateCapability<Thread>(cap, ZC_WRITE));
RET_ERR(ValidateCap(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;