Refactor error types and error reporting

This commit is contained in:
Drew Galbraith 2023-06-07 08:50:08 -07:00
parent 81b925eea0
commit a5c4d40575
8 changed files with 137 additions and 147 deletions

View File

@ -12,17 +12,17 @@ void check(uint64_t code) {
switch (code) {
case Z_OK:
return;
case ZE_NOT_FOUND:
dbgln("crash: NOT_FOUND");
break;
case ZE_INVALID:
dbgln("crash: INVALID");
break;
case ZE_DENIED:
dbgln("crash: DENIED");
break;
case ZE_UNIMPLEMENTED:
case Z_ERR_UNIMPLEMENTED:
dbgln("crash: UNIMPLEMENTED");
case Z_ERR_CAP_NOT_FOUND:
dbgln("crash: missing capability");
break;
case Z_ERR_CAP_TYPE:
dbgln("crash: capability of the wrong type");
break;
case Z_ERR_CAP_DENIED:
dbgln("crash: capability permissions error");
break;
default:
dbgln("Unhandled code");
break;

View File

@ -2,6 +2,20 @@
#include <stdarg.h>
#include "include/zerrors.h"
void dbg(const char* fmt, ...);
void dbgln(const char* str, ...);
void panic(const char* str, ...);
#define RET_ERR(expr) \
{ \
z_err_t _tmp_err = expr; \
if (_tmp_err != Z_OK) { \
return _tmp_err; \
} \
}
#define UNREACHABLE \
panic("Unreachable %s, %s", __FILE__, __LINE__); \
__builtin_unreachable();

View File

@ -2,6 +2,8 @@
#include <stdint.h>
#include "zerrors.h"
#define Z_INVALID 0x0
#define ZC_WRITE 0x01
@ -43,35 +45,35 @@
void ZProcessExit(uint64_t code);
[[nodiscard]] uint64_t ZProcessSpawn(uint64_t proc_cap, uint64_t bootstrap_cap,
[[nodiscard]] z_err_t ZProcessSpawn(uint64_t proc_cap, uint64_t bootstrap_cap,
uint64_t* new_proc_cap,
uint64_t* new_vmas_cap,
uint64_t* new_bootstrap_cap);
// UNUSED for now, I think we can get away with just starting a thread.
[[nodiscard]] uint64_t ZProcessStart(uint64_t proc_cap, uint64_t thread_cap,
[[nodiscard]] z_err_t ZProcessStart(uint64_t proc_cap, uint64_t thread_cap,
uint64_t entry, uint64_t arg1,
uint64_t arg2);
[[nodiscard]] uint64_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap);
[[nodiscard]] z_err_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap);
[[nodiscard]] uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry,
[[nodiscard]] z_err_t ZThreadStart(uint64_t thread_cap, uint64_t entry,
uint64_t arg1, uint64_t arg2);
void ZThreadExit();
[[nodiscard]] uint64_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
[[nodiscard]] z_err_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
uint64_t vmmo_cap, uint64_t* vaddr);
[[nodiscard]] uint64_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap);
[[nodiscard]] z_err_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap);
[[nodiscard]] uint64_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2);
[[nodiscard]] uint64_t ZChannelSend(uint64_t chan_cap, uint64_t type,
[[nodiscard]] z_err_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2);
[[nodiscard]] z_err_t ZChannelSend(uint64_t chan_cap, uint64_t type,
uint64_t num_bytes, const uint8_t* bytes,
uint64_t num_caps, const uint64_t* caps);
[[nodiscard]] uint64_t ZChannelRecv(uint64_t chan_cap, uint64_t num_bytes,
[[nodiscard]] z_err_t ZChannelRecv(uint64_t chan_cap, uint64_t num_bytes,
uint8_t* bytes, uint64_t num_caps,
uint64_t* caps, uint64_t* type,
uint64_t* actual_bytes,
uint64_t* actual_caps);
[[nodiscard]] uint64_t ZDebug(const char* message);
[[nodiscard]] z_err_t ZDebug(const char* message);

View File

@ -1,8 +1,16 @@
#pragma once
#include <stdint.h>
#define Z_OK 0x0
#define ZE_NOT_FOUND 0x1
#define ZE_INVALID 0x2
#define ZE_DENIED 0x4
#define ZE_UNIMPLEMENTED 0x8
#define ZE_BUFF_SIZE 0x10
#define Z_ERR_NOT_FOUND 0x1
#define Z_ERR_INVALID 0x2
#define Z_ERR_DENIED 0x3
#define Z_ERR_UNIMPLEMENTED 0x4
#define Z_ERR_BUFF_SIZE 0x05
#define Z_ERR_CAP_NOT_FOUND 0x100
#define Z_ERR_CAP_TYPE 0x101
#define Z_ERR_CAP_DENIED 0x102
typedef uint64_t z_err_t;

View File

@ -10,18 +10,18 @@ Pair<RefPtr<Channel>, RefPtr<Channel>> Channel::CreateChannelPair() {
return {c1, c2};
}
uint64_t Channel::Write(const ZMessage& msg) {
z_err_t Channel::Write(const ZMessage& msg) {
return peer_->EnqueueMessage(msg);
}
uint64_t Channel::Read(ZMessage& msg) {
z_err_t Channel::Read(ZMessage& msg) {
if (pending_messages_.size() == 0) {
dbgln("Unimplemented add blocking.");
return ZE_UNIMPLEMENTED;
return Z_ERR_UNIMPLEMENTED;
}
Message next_msg = pending_messages_.PeekFront();
if (next_msg.num_bytes > msg.num_bytes) {
return ZE_BUFF_SIZE;
return Z_ERR_BUFF_SIZE;
}
msg.type = next_msg.type;
@ -37,15 +37,15 @@ uint64_t Channel::Read(ZMessage& msg) {
return Z_OK;
}
uint64_t Channel::EnqueueMessage(const ZMessage& msg) {
z_err_t Channel::EnqueueMessage(const ZMessage& msg) {
if (msg.num_caps > 0) {
dbgln("Unimplemented passing caps on channel");
return ZE_UNIMPLEMENTED;
return Z_ERR_UNIMPLEMENTED;
}
if (msg.num_bytes > 0x1000) {
dbgln("Large message size unimplemented: %x", msg.num_bytes);
return ZE_INVALID;
return Z_ERR_INVALID;
}
Message message{

View File

@ -1,6 +1,7 @@
#pragma once
#include "capability/capability.h"
#include "include/zerrors.h"
#include "lib/linked_list.h"
#include "lib/pair.h"
#include "lib/ref_ptr.h"
@ -13,8 +14,8 @@ class Channel : public KernelObject {
RefPtr<Channel> peer() { return peer_; }
uint64_t Write(const ZMessage& msg);
uint64_t Read(ZMessage& msg);
z_err_t Write(const ZMessage& msg);
z_err_t Read(ZMessage& msg);
private:
// FIXME: We will likely never close the channel based on this
@ -36,5 +37,5 @@ class Channel : public KernelObject {
Channel() {}
void SetPeer(const RefPtr<Channel>& peer) { peer_ = peer; }
uint64_t EnqueueMessage(const ZMessage& msg);
z_err_t EnqueueMessage(const ZMessage& msg);
};

View File

@ -57,18 +57,25 @@ void InitSyscall() {
SetMSR(LSTAR, reinterpret_cast<uint64_t>(syscall_enter));
}
uint64_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) {
z_err_t ValidateCap(const RefPtr<Capability>& cap, Capability::Type type,
uint64_t permissions) {
if (!cap) {
return Z_ERR_CAP_NOT_FOUND;
}
if (!cap->CheckType(type)) {
return Z_ERR_CAP_TYPE;
}
if (!cap->HasPermissions(permissions)) {
return Z_ERR_CAP_DENIED;
}
return Z_OK;
}
z_err_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->proc_cap);
if (!cap) {
return ZE_NOT_FOUND;
}
if (!cap->CheckType(Capability::PROCESS)) {
return ZE_INVALID;
}
if (!cap->HasPermissions(ZC_PROC_SPAWN_PROC)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(cap, Capability::PROCESS, ZC_PROC_SPAWN_PROC));
RefPtr<Process> proc = Process::Create();
gProcMan->InsertProcess(proc);
@ -78,7 +85,7 @@ uint64_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) {
if (req->bootstrap_cap != 0) {
auto cap = curr_proc.ReleaseCapability(req->bootstrap_cap);
if (!cap) {
return ZE_NOT_FOUND;
return Z_ERR_CAP_NOT_FOUND;
}
// FIXME: Check permissions.
resp->bootstrap_cap = proc->AddCapability(cap);
@ -87,19 +94,10 @@ uint64_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) {
return Z_OK;
}
uint64_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) {
z_err_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->proc_cap);
if (!cap) {
return ZE_NOT_FOUND;
}
if (!cap->CheckType(Capability::PROCESS)) {
return ZE_INVALID;
}
if (!cap->HasPermissions(ZC_PROC_SPAWN_THREAD)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(cap, Capability::PROCESS, ZC_PROC_SPAWN_THREAD));
auto parent_proc = cap->obj<Process>();
auto thread = parent_proc->CreateThread();
@ -108,19 +106,10 @@ uint64_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) {
return Z_OK;
}
uint64_t ThreadStart(ZThreadStartReq* req) {
z_err_t ThreadStart(ZThreadStartReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->thread_cap);
if (!cap) {
return ZE_NOT_FOUND;
}
if (!cap->CheckType(Capability::THREAD)) {
return ZE_INVALID;
}
if (!cap->HasPermissions(ZC_WRITE)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(cap, Capability::THREAD, ZC_WRITE));
auto thread = cap->obj<Thread>();
// FIXME: validate entry point is in user space.
@ -128,21 +117,13 @@ uint64_t ThreadStart(ZThreadStartReq* req) {
return Z_OK;
}
uint64_t AddressSpaceMap(ZAddressSpaceMapReq* req, ZAddressSpaceMapResp* resp) {
z_err_t AddressSpaceMap(ZAddressSpaceMapReq* req, ZAddressSpaceMapResp* resp) {
auto& curr_proc = gScheduler->CurrentProcess();
auto vmas_cap = curr_proc.GetCapability(req->vmas_cap);
auto vmmo_cap = curr_proc.GetCapability(req->vmmo_cap);
if (!vmas_cap || !vmmo_cap) {
return ZE_NOT_FOUND;
}
if (!vmas_cap->CheckType(Capability::ADDRESS_SPACE) ||
!vmmo_cap->CheckType(Capability::MEMORY_OBJECT)) {
return ZE_INVALID;
}
if (!vmas_cap->HasPermissions(ZC_WRITE) ||
!vmmo_cap->HasPermissions(ZC_WRITE)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(vmas_cap, Capability::ADDRESS_SPACE, ZC_WRITE));
RET_ERR(ValidateCap(vmmo_cap, Capability::MEMORY_OBJECT, ZC_WRITE));
auto vmas = vmas_cap->obj<AddressSpace>();
auto vmmo = vmmo_cap->obj<MemoryObject>();
// FIXME: Validation necessary.
@ -155,7 +136,7 @@ uint64_t AddressSpaceMap(ZAddressSpaceMapReq* req, ZAddressSpaceMapResp* resp) {
return Z_OK;
}
uint64_t MemoryObjectCreate(ZMemoryObjectCreateReq* req,
z_err_t MemoryObjectCreate(ZMemoryObjectCreateReq* req,
ZMemoryObjectCreateResp* resp) {
auto& curr_proc = gScheduler->CurrentProcess();
resp->vmmo_cap =
@ -163,7 +144,7 @@ uint64_t MemoryObjectCreate(ZMemoryObjectCreateReq* req,
return Z_OK;
}
uint64_t ChannelCreate(ZChannelCreateResp* resp) {
z_err_t ChannelCreate(ZChannelCreateResp* resp) {
auto& proc = gScheduler->CurrentProcess();
auto chan_pair = Channel::CreateChannelPair();
resp->chan_cap1 = proc.AddCapability(chan_pair.first());
@ -171,41 +152,27 @@ uint64_t ChannelCreate(ZChannelCreateResp* resp) {
return Z_OK;
}
uint64_t ChannelSend(ZChannelSendReq* req) {
z_err_t ChannelSend(ZChannelSendReq* req) {
auto& proc = gScheduler->CurrentProcess();
auto chan_cap = proc.GetCapability(req->chan_cap);
if (!chan_cap) {
return ZE_NOT_FOUND;
}
if (!chan_cap->CheckType(Capability::CHANNEL)) {
return ZE_INVALID;
}
if (!chan_cap->HasPermissions(ZC_WRITE)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(chan_cap, Capability::CHANNEL, ZC_WRITE));
auto chan = chan_cap->obj<Channel>();
chan->Write(req->message);
return Z_OK;
}
uint64_t ChannelRecv(ZChannelRecvReq* req) {
z_err_t ChannelRecv(ZChannelRecvReq* req) {
auto& proc = gScheduler->CurrentProcess();
auto chan_cap = proc.GetCapability(req->chan_cap);
if (!chan_cap) {
return ZE_NOT_FOUND;
}
if (!chan_cap->CheckType(Capability::CHANNEL)) {
return ZE_INVALID;
}
if (!chan_cap->HasPermissions(ZC_READ)) {
return ZE_DENIED;
}
RET_ERR(ValidateCap(chan_cap, Capability::CHANNEL, ZC_READ));
auto chan = chan_cap->obj<Channel>();
chan->Read(req->message);
return Z_OK;
}
extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
Thread& thread = gScheduler->CurrentThread();
switch (call_id) {
case Z_PROCESS_EXIT:
@ -247,5 +214,5 @@ extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
default:
panic("Unhandled syscall number: %x", call_id);
}
return 1;
UNREACHABLE
}

View File

@ -4,8 +4,8 @@
#include "usr/zcall_internal.h"
uint64_t SysCall2(uint64_t number, const void* first, const void* second) {
uint64_t return_code;
z_err_t SysCall2(uint64_t number, const void* first, const void* second) {
z_err_t return_code;
asm("syscall"
: "=a"(return_code)
: "D"(number), "S"(first), "d"(second)
@ -13,9 +13,9 @@ uint64_t SysCall2(uint64_t number, const void* first, const void* second) {
return return_code;
}
uint64_t SysCall0(uint64_t number) { return SysCall2(number, 0, 0); }
z_err_t SysCall0(uint64_t number) { return SysCall2(number, 0, 0); }
uint64_t SysCall1(uint64_t number, const void* first) {
z_err_t SysCall1(uint64_t number, const void* first) {
return SysCall2(number, first, 0);
}
@ -23,7 +23,7 @@ void ZProcessExit(uint64_t code) {
SysCall1(Z_PROCESS_EXIT, reinterpret_cast<void*>(code));
}
uint64_t ZProcessSpawn(uint64_t proc_cap, uint64_t bootstrap_cap,
z_err_t ZProcessSpawn(uint64_t proc_cap, uint64_t bootstrap_cap,
uint64_t* new_proc_cap, uint64_t* new_vmas_cap,
uint64_t* new_bootstrap_cap) {
ZProcessSpawnReq req{
@ -31,24 +31,24 @@ uint64_t ZProcessSpawn(uint64_t proc_cap, uint64_t bootstrap_cap,
.bootstrap_cap = bootstrap_cap,
};
ZProcessSpawnResp resp;
uint64_t ret = SysCall2(Z_PROCESS_SPAWN, &req, &resp);
z_err_t ret = SysCall2(Z_PROCESS_SPAWN, &req, &resp);
*new_proc_cap = resp.proc_cap;
*new_vmas_cap = resp.vmas_cap;
*new_bootstrap_cap = resp.bootstrap_cap;
return ret;
}
uint64_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap) {
z_err_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap) {
ZThreadCreateReq req{
.proc_cap = proc_cap,
};
ZThreadCreateResp resp;
uint64_t ret = SysCall2(Z_THREAD_CREATE, &req, &resp);
z_err_t ret = SysCall2(Z_THREAD_CREATE, &req, &resp);
*thread_cap = resp.thread_cap;
return ret;
}
uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1,
z_err_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1,
uint64_t arg2) {
ZThreadStartReq req{
.thread_cap = thread_cap,
@ -61,7 +61,7 @@ uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1,
void ZThreadExit() { SysCall0(Z_THREAD_EXIT); }
uint64_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
z_err_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
uint64_t vmmo_cap, uint64_t* vaddr) {
ZAddressSpaceMapReq req{
.vmas_cap = vmas_cap,
@ -69,29 +69,29 @@ uint64_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
.vmmo_cap = vmmo_cap,
};
ZAddressSpaceMapResp resp;
uint64_t ret = SysCall2(Z_ADDRESS_SPACE_MAP, &req, &resp);
z_err_t ret = SysCall2(Z_ADDRESS_SPACE_MAP, &req, &resp);
*vaddr = resp.vaddr;
return ret;
}
uint64_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap) {
z_err_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap) {
ZMemoryObjectCreateReq req{
.size = size,
};
ZMemoryObjectCreateResp resp;
uint64_t ret = SysCall2(Z_MEMORY_OBJECT_CREATE, &req, &resp);
z_err_t ret = SysCall2(Z_MEMORY_OBJECT_CREATE, &req, &resp);
*vmmo_cap = resp.vmmo_cap;
return ret;
}
uint64_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2) {
z_err_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2) {
ZChannelCreateResp resp;
uint64_t ret = SysCall2(Z_CHANNEL_CREATE, 0, &resp);
z_err_t ret = SysCall2(Z_CHANNEL_CREATE, 0, &resp);
*channel1 = resp.chan_cap1;
*channel2 = resp.chan_cap2;
return ret;
}
uint64_t ZChannelSend(uint64_t chan_cap, uint64_t type, uint64_t num_bytes,
z_err_t ZChannelSend(uint64_t chan_cap, uint64_t type, uint64_t num_bytes,
const uint8_t* bytes, uint64_t num_caps,
const uint64_t* caps) {
ZChannelSendReq req{
@ -108,7 +108,7 @@ uint64_t ZChannelSend(uint64_t chan_cap, uint64_t type, uint64_t num_bytes,
return SysCall1(Z_CHANNEL_SEND, &req);
}
uint64_t ZChannelRecv(uint64_t chan_cap, uint64_t num_bytes, uint8_t* bytes,
z_err_t ZChannelRecv(uint64_t chan_cap, uint64_t num_bytes, uint8_t* bytes,
uint64_t num_caps, uint64_t* caps, uint64_t* type,
uint64_t* actual_bytes, uint64_t* actual_caps) {
ZChannelRecvReq req{
@ -122,13 +122,11 @@ uint64_t ZChannelRecv(uint64_t chan_cap, uint64_t num_bytes, uint8_t* bytes,
.caps = caps,
},
};
uint64_t ret = SysCall1(Z_CHANNEL_RECV, &req);
z_err_t ret = SysCall1(Z_CHANNEL_RECV, &req);
*type = req.message.type;
*actual_bytes = req.message.num_bytes;
*actual_caps = req.message.num_caps;
return ret;
}
uint64_t ZDebug(const char* message) {
return SysCall1(Z_DEBUG_PRINT, message);
}
z_err_t ZDebug(const char* message) { return SysCall1(Z_DEBUG_PRINT, message); }