diff --git a/sys/test.cpp b/sys/test.cpp index 477a8b2..b31ae99 100644 --- a/sys/test.cpp +++ b/sys/test.cpp @@ -1,11 +1,16 @@ #include "zcall.h" +#include "zerrors.h" constexpr uint64_t prog2 = 0x00000020'00000000; int main() { ZDebug("Testing"); - ZProcessSpawn(prog2, 0x1000); - ZDebug("Return"); + uint64_t err = ZProcessSpawn(0x100, prog2, 0x1000); + if (err != Z_OK) { + ZDebug("Error"); + } else { + ZDebug("Return"); + } return 0; } diff --git a/zion/capability/capability.h b/zion/capability/capability.h new file mode 100644 index 0000000..027d937 --- /dev/null +++ b/zion/capability/capability.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include "debug/debug.h" + +class Process; + +class Capability { + public: + enum Type { + UNDEFINED, + PROCESS, + }; + Capability(void* obj, Type type, uint64_t id, uint64_t permissions) + : obj_(obj), type_(type), id_(id), permissions_(permissions) {} + + template + T& obj(); + + uint64_t id() { return id_; } + + bool CheckType(Type type) { return type_ == type; } + + uint64_t permissions() { return permissions_; } + bool HasPermissions(uint64_t requested) { + return (permissions_ & requested) == requested; + } + + private: + // FIXME: This should somehow be a shared ptr to keep the object alive. + void* obj_; + Type type_; + uint64_t id_; + uint64_t permissions_; +}; + +template +Process& Capability::obj() { + if (type_ != PROCESS) { + panic("Accessing %u cap as object.", type_); + } + return *static_cast(obj_); +} diff --git a/zion/include/cap_types.h b/zion/include/cap_types.h new file mode 100644 index 0000000..a0a3192 --- /dev/null +++ b/zion/include/cap_types.h @@ -0,0 +1,3 @@ +#pragma once + +#define ZC_PROC_SPAWN_CHILD 0x1 diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 36d28db..84f9e46 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -12,8 +12,9 @@ uint64_t ZDebug(const char* message); // TODO: Move structs into an internal header. struct ZProcessSpawnReq { + uint64_t cap_id; uint64_t elf_base; uint64_t elf_size; }; -uint64_t ZProcessSpawn(uint64_t elf_base, uint64_t elf_size); +uint64_t ZProcessSpawn(uint64_t cap_id, uint64_t elf_base, uint64_t elf_size); diff --git a/zion/include/zerrors.h b/zion/include/zerrors.h new file mode 100644 index 0000000..3d4d266 --- /dev/null +++ b/zion/include/zerrors.h @@ -0,0 +1,6 @@ +#pragma once + +#define Z_OK 0x0 +#define ZE_NOT_FOUND 0x1 +#define ZE_INVALID 0x2 +#define ZE_DENIED 0x4 diff --git a/zion/scheduler/process.cpp b/zion/scheduler/process.cpp index 8d11a79..fedb9ba 100644 --- a/zion/scheduler/process.cpp +++ b/zion/scheduler/process.cpp @@ -1,6 +1,7 @@ #include "scheduler/process.h" #include "debug/debug.h" +#include "include/cap_types.h" #include "memory/paging_util.h" #include "memory/physical_memory.h" #include "scheduler/scheduler.h" @@ -25,6 +26,8 @@ Process::Process() : id_(gNextId++), state_(RUNNING) {} void Process::CreateThread(uint64_t entry) { Thread* thread = new Thread(*this, next_thread_id_++, entry); threads_.PushBack(thread); + caps_.PushBack(new Capability(this, Capability::PROCESS, next_cap_id_++, + ZC_PROC_SPAWN_CHILD)); gScheduler->Enqueue(thread); } @@ -50,3 +53,15 @@ void Process::CheckState() { } state_ = FINISHED; } + +SharedPtr Process::GetCapability(uint64_t cid) { + auto iter = caps_.begin(); + while (iter != caps_.end()) { + if (iter->id() == cid) { + return *iter; + } + ++iter; + } + dbgln("Bad cap access"); + return {}; +} diff --git a/zion/scheduler/process.h b/zion/scheduler/process.h index 0853760..f5e73ae 100644 --- a/zion/scheduler/process.h +++ b/zion/scheduler/process.h @@ -2,6 +2,7 @@ #include +#include "capability/capability.h" #include "lib/linked_list.h" #include "lib/shared_ptr.h" #include "memory/virtual_memory.h" @@ -26,6 +27,7 @@ class Process { void CreateThread(uint64_t entry); SharedPtr GetThread(uint64_t tid); + SharedPtr GetCapability(uint64_t cid); // Checks the state of all child threads and transitions to // finished if all have finished. void CheckState(); @@ -39,6 +41,8 @@ class Process { State state_; uint64_t next_thread_id_ = 0; + uint64_t next_cap_id_ = 0x100; LinkedList> threads_; + LinkedList> caps_; }; diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 39c0fef..26f97a1 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -3,7 +3,9 @@ #include #include "debug/debug.h" +#include "include/cap_types.h" #include "include/zcall.h" +#include "include/zerrors.h" #include "loader/elf_loader.h" #include "scheduler/process.h" #include "scheduler/process_manager.h" @@ -57,6 +59,18 @@ void InitSyscall() { } uint64_t ProcessSpawn(ZProcessSpawnReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto cap = curr_proc.GetCapability(req->cap_id); + if (cap.empty()) { + return ZE_NOT_FOUND; + } + if (!cap->CheckType(Capability::PROCESS)) { + return ZE_INVALID; + } + + if (!cap->HasPermissions(ZC_PROC_SPAWN_CHILD)) { + return ZE_DENIED; + } dbgln("Proc spawn: %u:%u", req->elf_base, req->elf_size); SharedPtr proc = MakeShared(); gProcMan->InsertProcess(proc); diff --git a/zion/usr/zcall.cpp b/zion/usr/zcall.cpp index 75dbd1f..19f67f2 100644 --- a/zion/usr/zcall.cpp +++ b/zion/usr/zcall.cpp @@ -12,8 +12,9 @@ uint64_t ZDebug(const char* message) { return SysCall1(Z_DEBUG_PRINT, message); } -uint64_t ZProcessSpawn(uint64_t elf_base, uint64_t elf_size) { +uint64_t ZProcessSpawn(uint64_t cap_id, uint64_t elf_base, uint64_t elf_size) { ZProcessSpawnReq req{ + .cap_id = cap_id, .elf_base = elf_base, .elf_size = elf_size, };