From a5c4d40575cb1fc65108a5783d7274773f3528d6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 Jun 2023 08:50:08 -0700 Subject: [PATCH] Refactor error types and error reporting --- lib/mammoth/src/debug.cpp | 20 +++---- zion/debug/debug.h | 14 +++++ zion/include/zcall.h | 48 +++++++++-------- zion/include/zerrors.h | 18 +++++-- zion/object/channel.cpp | 14 ++--- zion/object/channel.h | 7 +-- zion/syscall/syscall.cpp | 107 +++++++++++++------------------------- zion/usr/zcall.cpp | 56 ++++++++++---------- 8 files changed, 137 insertions(+), 147 deletions(-) diff --git a/lib/mammoth/src/debug.cpp b/lib/mammoth/src/debug.cpp index 0e32139..e28f29d 100644 --- a/lib/mammoth/src/debug.cpp +++ b/lib/mammoth/src/debug.cpp @@ -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; diff --git a/zion/debug/debug.h b/zion/debug/debug.h index de65aca..45fa5f7 100644 --- a/zion/debug/debug.h +++ b/zion/debug/debug.h @@ -2,6 +2,20 @@ #include +#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(); diff --git a/zion/include/zcall.h b/zion/include/zcall.h index aa504b4..5e59907 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -2,6 +2,8 @@ #include +#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, - uint64_t* new_proc_cap, - uint64_t* new_vmas_cap, - uint64_t* new_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, - uint64_t entry, uint64_t arg1, - uint64_t arg2); +[[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, - uint64_t arg1, uint64_t arg2); +[[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, - uint64_t vmmo_cap, uint64_t* vaddr); -[[nodiscard]] uint64_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap); +[[nodiscard]] z_err_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset, + uint64_t vmmo_cap, uint64_t* vaddr); +[[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, - 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, - uint8_t* bytes, uint64_t num_caps, - uint64_t* caps, uint64_t* type, - uint64_t* actual_bytes, - uint64_t* actual_caps); +[[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]] 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); diff --git a/zion/include/zerrors.h b/zion/include/zerrors.h index 4dcf6fb..96c0c4c 100644 --- a/zion/include/zerrors.h +++ b/zion/include/zerrors.h @@ -1,8 +1,16 @@ #pragma once +#include + #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; diff --git a/zion/object/channel.cpp b/zion/object/channel.cpp index b9ec308..890ae7a 100644 --- a/zion/object/channel.cpp +++ b/zion/object/channel.cpp @@ -10,18 +10,18 @@ Pair, RefPtr> 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{ diff --git a/zion/object/channel.h b/zion/object/channel.h index ac6b3cc..3f9a12c 100644 --- a/zion/object/channel.h +++ b/zion/object/channel.h @@ -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 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& peer) { peer_ = peer; } - uint64_t EnqueueMessage(const ZMessage& msg); + z_err_t EnqueueMessage(const ZMessage& msg); }; diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 0342482..bee188f 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -57,18 +57,25 @@ void InitSyscall() { SetMSR(LSTAR, reinterpret_cast(syscall_enter)); } -uint64_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) { +z_err_t ValidateCap(const RefPtr& 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 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(); 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(); // 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(); auto vmmo = vmmo_cap->obj(); // FIXME: Validation necessary. @@ -155,15 +136,15 @@ uint64_t AddressSpaceMap(ZAddressSpaceMapReq* req, ZAddressSpaceMapResp* resp) { return Z_OK; } -uint64_t MemoryObjectCreate(ZMemoryObjectCreateReq* req, - ZMemoryObjectCreateResp* resp) { +z_err_t MemoryObjectCreate(ZMemoryObjectCreateReq* req, + ZMemoryObjectCreateResp* resp) { auto& curr_proc = gScheduler->CurrentProcess(); resp->vmmo_cap = curr_proc.AddCapability(MakeRefCounted(req->size)); 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(); 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(); 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 } diff --git a/zion/usr/zcall.cpp b/zion/usr/zcall.cpp index 3f809b0..5429719 100644 --- a/zion/usr/zcall.cpp +++ b/zion/usr/zcall.cpp @@ -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,33 +23,33 @@ void ZProcessExit(uint64_t code) { SysCall1(Z_PROCESS_EXIT, reinterpret_cast(code)); } -uint64_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) { +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{ .proc_cap = proc_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, - uint64_t arg2) { +z_err_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1, + uint64_t arg2) { ZThreadStartReq req{ .thread_cap = thread_cap, .entry = entry, @@ -61,39 +61,39 @@ 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, - uint64_t vmmo_cap, uint64_t* vaddr) { +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, .vmas_offset = 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, - const uint8_t* bytes, uint64_t num_caps, - const uint64_t* caps) { +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{ .chan_cap = chan_cap, .message = @@ -108,9 +108,9 @@ 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, - uint64_t num_caps, uint64_t* caps, uint64_t* type, - uint64_t* actual_bytes, uint64_t* actual_caps) { +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{ .chan_cap = chan_cap, .message = @@ -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); }