From 23895b5c6c5fa080b9990c4d91d097defe3510bc Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 Jun 2023 00:04:53 -0700 Subject: [PATCH] Spawn Processes using memory primitives rather than and elf loader. This allows us to remove the temporary syscall for that style of process spawn. --- lib/mammoth/CMakeLists.txt | 1 + lib/mammoth/include/mammoth/debug.h | 6 ++ lib/mammoth/include/mammoth/process.h | 5 ++ lib/mammoth/src/debug.cpp | 28 +++++++- lib/mammoth/src/process.cpp | 97 +++++++++++++++++++++++++++ sys/CMakeLists.txt | 2 +- sys/test.cpp | 14 ++-- zion/capability/capability.cpp | 24 +++++-- zion/capability/capability.h | 4 +- zion/common/gdt.cpp | 10 +-- zion/include/zcall.h | 54 +++++++-------- zion/include/zerrors.h | 1 + zion/interrupt/interrupt.cpp | 4 +- zion/lib/ref_ptr.h | 3 + zion/loader/elf_loader.cpp | 2 +- zion/loader/init_loader.cpp | 2 +- zion/memory/paging_util.cpp | 2 +- zion/object/address_space.cpp | 14 +++- zion/object/address_space.h | 7 +- zion/object/process.cpp | 24 ++++++- zion/object/process.h | 7 +- zion/object/thread.cpp | 6 +- zion/syscall/syscall.cpp | 84 +++++++++++++++++------ zion/usr/crt0.s | 3 + zion/usr/zcall.cpp | 48 ++++++++++--- zion/usr/zcall_internal.h | 45 +++++++++++++ 26 files changed, 403 insertions(+), 94 deletions(-) create mode 100644 lib/mammoth/include/mammoth/process.h create mode 100644 lib/mammoth/src/process.cpp create mode 100644 zion/usr/zcall_internal.h diff --git a/lib/mammoth/CMakeLists.txt b/lib/mammoth/CMakeLists.txt index f894062..2daf8c8 100644 --- a/lib/mammoth/CMakeLists.txt +++ b/lib/mammoth/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(mammoth_lib STATIC src/debug.cpp + src/process.cpp src/thread.cpp ) diff --git a/lib/mammoth/include/mammoth/debug.h b/lib/mammoth/include/mammoth/debug.h index a8793d2..297aba2 100644 --- a/lib/mammoth/include/mammoth/debug.h +++ b/lib/mammoth/include/mammoth/debug.h @@ -1,3 +1,9 @@ #pragma once +#include + void dbgln(const char*); + +// Checks that the code is ok. +// if not exits the process. +void check(uint64_t); diff --git a/lib/mammoth/include/mammoth/process.h b/lib/mammoth/include/mammoth/process.h new file mode 100644 index 0000000..33113c6 --- /dev/null +++ b/lib/mammoth/include/mammoth/process.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +uint64_t SpawnProcessFromElfRegion(uint64_t program); diff --git a/lib/mammoth/src/debug.cpp b/lib/mammoth/src/debug.cpp index 7a5ae07..0e32139 100644 --- a/lib/mammoth/src/debug.cpp +++ b/lib/mammoth/src/debug.cpp @@ -1,5 +1,31 @@ #include "include/mammoth/debug.h" #include +#include -void dbgln(const char* str) { ZDebug(str); } +void dbgln(const char* str) { + // Safe to ignore the result since right now this doesn't throw. + uint64_t _ = ZDebug(str); +} + +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: + dbgln("crash: UNIMPLEMENTED"); + default: + dbgln("Unhandled code"); + break; + } + ZProcessExit(code); +} diff --git a/lib/mammoth/src/process.cpp b/lib/mammoth/src/process.cpp new file mode 100644 index 0000000..dcf9466 --- /dev/null +++ b/lib/mammoth/src/process.cpp @@ -0,0 +1,97 @@ +#include "include/mammoth/process.h" + +#include + +#include "include/mammoth/debug.h" + +namespace { + +typedef struct { + char ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t phoff; + uint64_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +} Elf64Header; + +typedef struct { + uint32_t name; + uint32_t type; + uint64_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t addralign; + uint64_t entsize; +} Elf64SectionHeader; + +typedef struct { + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t vaddr; + uint64_t paddr; + uint64_t filesz; + uint64_t memsz; + uint64_t align; +} Elf64ProgramHeader; + +void memcpy(uint64_t base, uint64_t len, uint64_t dest) { + uint8_t* srcptr = reinterpret_cast(base); + uint8_t* destptr = reinterpret_cast(dest); + for (uint64_t i = 0; i < len; i++) { + destptr[i] = srcptr[i]; + } +} + +uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) { + Elf64Header* header = reinterpret_cast(base); + Elf64ProgramHeader* programs = + reinterpret_cast(base + header->phoff); + for (uint64_t i = 0; i < header->phnum; i++) { + Elf64ProgramHeader& program = programs[i]; + dbgln("Create mem object"); + uint64_t mem_cap; + uint64_t size = program.filesz; + check(ZMemoryObjectCreate(size, &mem_cap)); + + dbgln("Map Local"); + uint64_t vaddr; + check(ZAddressSpaceMap(Z_INIT_AS_SELF, 0, mem_cap, &vaddr)); + + dbgln("Copy"); + memcpy(base + program.offset, program.filesz, vaddr); + + dbgln("Map Foreign"); + check(ZAddressSpaceMap(as_cap, program.vaddr, mem_cap, &vaddr)); + } + return header->entry; +} + +} // namespace + +uint64_t SpawnProcessFromElfRegion(uint64_t program) { + dbgln("Spawn"); + uint64_t proc_cap; + uint64_t as_cap; + check(ZProcessSpawn(Z_INIT_PROC_SELF, &proc_cap, &as_cap)); + + uint64_t entry_point = LoadElfProgram(program, as_cap); + dbgln("Thread Create"); + uint64_t thread_cap; + check(ZThreadCreate(proc_cap, &thread_cap)); + + dbgln("Thread start"); + check(ZThreadStart(thread_cap, entry_point, 0, 0)); +} diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index dfc6382..b76e359 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -8,7 +8,7 @@ add_executable(test ) target_link_libraries(test - zion_lib) + mammoth_lib) set_target_properties(test PROPERTIES diff --git a/sys/test.cpp b/sys/test.cpp index af1f43b..875a7d0 100644 --- a/sys/test.cpp +++ b/sys/test.cpp @@ -1,15 +1,11 @@ -#include -#include +#include +#include constexpr uint64_t prog2 = 0x00000020'00000000; int main() { - ZDebug("Testing"); - uint64_t err = ZProcessSpawnElf(Z_INIT_PROC_SELF, prog2, 0x2000); - if (err != Z_OK) { - ZDebug("Error"); - } else { - ZDebug("Return"); - } + dbgln("Testing"); + check(SpawnProcessFromElfRegion(prog2)); + dbgln("Return"); return 0; } diff --git a/zion/capability/capability.cpp b/zion/capability/capability.cpp index ced4bda..fb76cd0 100644 --- a/zion/capability/capability.cpp +++ b/zion/capability/capability.cpp @@ -4,17 +4,33 @@ #include "object/thread.h" template <> -Process& Capability::obj() { +RefPtr Capability::obj() { if (type_ != PROCESS) { panic("Accessing %u cap as object.", type_); } - return *static_cast(obj_.get()); + return StaticCastRefPtr(obj_); } template <> -Thread& Capability::obj() { +RefPtr Capability::obj() { if (type_ != THREAD) { panic("Accessing %u cap as object.", type_); } - return *static_cast(obj_.get()); + return StaticCastRefPtr(obj_); +} + +template <> +RefPtr Capability::obj() { + if (type_ != ADDRESS_SPACE) { + panic("Accessing %u cap as object.", type_); + } + return StaticCastRefPtr(obj_); +} + +template <> +RefPtr Capability::obj() { + if (type_ != MEMORY_OBJECT) { + panic("Accessing %u cap as object.", type_); + } + return StaticCastRefPtr(obj_); } diff --git a/zion/capability/capability.h b/zion/capability/capability.h index e2ad96d..14218df 100644 --- a/zion/capability/capability.h +++ b/zion/capability/capability.h @@ -14,6 +14,8 @@ class Capability { UNDEFINED, PROCESS, THREAD, + ADDRESS_SPACE, + MEMORY_OBJECT, }; Capability(const RefPtr& obj, Type type, uint64_t id, uint64_t permissions) @@ -25,7 +27,7 @@ class Capability { } template - T& obj(); + RefPtr obj(); uint64_t id() { return id_; } diff --git a/zion/common/gdt.cpp b/zion/common/gdt.cpp index b2f31a0..cc7654a 100644 --- a/zion/common/gdt.cpp +++ b/zion/common/gdt.cpp @@ -34,7 +34,7 @@ struct GdtPointer { uint64_t base; } __attribute__((packed)); -static uint64_t gGdtSegments[7]; +static uint64_t gGdtSegments[8]; static TaskStateSegment gTaskStateSegment; // Defined in load_gdt.s @@ -70,13 +70,15 @@ void InitGdt() { // User CS gGdtSegments[3] = CreateSegment(default_bits | GDT_RING3 | GDT_EXECUTABLE, GDT_FLAGS); + // Copy for the sysret function. + gGdtSegments[5] = gGdtSegments[3]; // User DS gGdtSegments[4] = CreateSegment(default_bits | GDT_RING3, GDT_FLAGS); gTaskStateSegment.iomap_base = sizeof(TaskStateSegment); - gGdtSegments[5] = CreateTssSegment(&gTaskStateSegment); - gGdtSegments[6] = reinterpret_cast(&gTaskStateSegment) >> 32; + gGdtSegments[6] = CreateTssSegment(&gTaskStateSegment); + gGdtSegments[7] = reinterpret_cast(&gTaskStateSegment) >> 32; GdtPointer gdtp{ .size = sizeof(gGdtSegments) - 1, @@ -86,7 +88,7 @@ void InitGdt() { asm volatile("lgdt %0" ::"m"(gdtp)); ReloadSegments(); asm volatile( - "mov $0x28, %%ax;" + "mov $0x30, %%ax;" "ltr %%ax;" :: : "rax"); } diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 0b8523e..b498f8a 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -12,53 +12,45 @@ #define Z_PROCESS_SPAWN 0x02 #define Z_PROCESS_START 0x03 -#define Z_PROCESS_SPAWN_ELF 0x1'00000002 - #define ZC_PROC_SPAWN_PROC 0x100 #define ZC_PROC_SPAWN_THREAD 0x101 #define Z_INIT_PROC_SELF 0x1 +#define Z_INIT_AS_SELF 0x2 // Thread Calls. #define Z_THREAD_CREATE 0x10 #define Z_THREAD_START 0x11 #define Z_THREAD_EXIT 0x12 +// Memory Calls +#define Z_ADDRESS_SPACE_MAP 0x21 +#define Z_ADDRESS_SPACE_UNMAP 0x22 + +#define Z_MEMORY_OBJECT_CREATE 0x30 + // Debugging Calls. #define Z_DEBUG_PRINT 0x10000000 -uint64_t ZDebug(const char* message); +void ZProcessExit(uint64_t code); -// TODO: Move structs into an internal header. -struct ZProcessSpawnElfReq { - uint64_t cap_id; - uint64_t elf_base; - uint64_t elf_size; -}; +[[nodiscard]] uint64_t ZProcessSpawn(uint64_t proc_cap, uint64_t* new_proc_cap, + uint64_t* new_as_cap); -// Creates a child process of the current one and -// starts its root thread from the provided ELF file. -uint64_t ZProcessSpawnElf(uint64_t cap_id, uint64_t elf_base, - uint64_t elf_size); +// 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); -struct ZThreadCreateReq { - uint64_t proc_cap; -}; +[[nodiscard]] uint64_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap); -struct ZThreadCreateResp { - uint64_t thread_cap; -}; - -uint64_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap); - -struct ZThreadStartReq { - uint64_t thread_cap; - uint64_t entry; - uint64_t arg1; - uint64_t arg2; -}; - -uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1, - uint64_t arg2); +[[nodiscard]] uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, + uint64_t arg1, uint64_t arg2); void ZThreadExit(); + +[[nodiscard]] uint64_t ZAddressSpaceMap(uint64_t as_cap, uint64_t offset, + uint64_t mem_cap, uint64_t* vaddr); +[[nodiscard]] uint64_t ZMemoryObjectCreate(uint64_t size, uint64_t* mem_cap); + +[[nodiscard]] uint64_t ZDebug(const char* message); diff --git a/zion/include/zerrors.h b/zion/include/zerrors.h index 3d4d266..9d3e160 100644 --- a/zion/include/zerrors.h +++ b/zion/include/zerrors.h @@ -4,3 +4,4 @@ #define ZE_NOT_FOUND 0x1 #define ZE_INVALID 0x2 #define ZE_DENIED 0x4 +#define ZE_UNIMPLEMENTED 0x8 diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 46a82d3..4f8d0a4 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -80,6 +80,8 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) { dbgln("GDT"); } dbgln("Index: %u", err >> 3); + dbgln("RIP: %m", frame->rip); + dbgln("RSP: %m", frame->rsp); panic("GP"); } @@ -90,7 +92,7 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) { uint64_t cr2; asm volatile("mov %%cr2, %0" : "=r"(cr2)); - if (gScheduler->CurrentProcess().vmm().HandlePageFault(cr2)) { + if (gScheduler->CurrentProcess().vmas()->HandlePageFault(cr2)) { dbgln("Handled"); return; } diff --git a/zion/lib/ref_ptr.h b/zion/lib/ref_ptr.h index 685d40a..41e5e87 100644 --- a/zion/lib/ref_ptr.h +++ b/zion/lib/ref_ptr.h @@ -1,5 +1,7 @@ #pragma once +#include "debug/debug.h" + template class RefPtr; @@ -26,6 +28,7 @@ class RefPtr { ptr_->Acquire(); } if (old && old->Release()) { + dbgln("Deleting obj %m", old); delete old; } diff --git a/zion/loader/elf_loader.cpp b/zion/loader/elf_loader.cpp index 034ed21..9b6a925 100644 --- a/zion/loader/elf_loader.cpp +++ b/zion/loader/elf_loader.cpp @@ -62,7 +62,7 @@ uint64_t LoadElfProgram(Process& dest_proc, uint64_t base, uint64_t offset) { program.paddr, program.filesz, program.memsz, program.align); auto mem_obj = MakeRefCounted(program.filesz); mem_obj->CopyBytesToObject(base + program.offset, program.filesz); - dest_proc.vmm().MapInMemoryObject(program.vaddr, mem_obj); + dest_proc.vmas()->MapInMemoryObject(program.vaddr, mem_obj); } return header->entry; } diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index 0470122..0d370af 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -58,7 +58,7 @@ void LoadInitProgram() { CopyIntoNonResidentProcess(reinterpret_cast(prog2.address), prog2.size, *proc, - proc->vmm().GetNextMemMapAddr(prog2.size)); + proc->vmas()->GetNextMemMapAddr(prog2.size)); proc->CreateThread()->Start(entry, 0, 0); } diff --git a/zion/memory/paging_util.cpp b/zion/memory/paging_util.cpp index 98267f0..9462ec5 100644 --- a/zion/memory/paging_util.cpp +++ b/zion/memory/paging_util.cpp @@ -105,7 +105,7 @@ void CopyPageIntoNonResidentProcess(uint64_t base, uint64_t size, if (dest_virt & 0xFFF) { panic("NR copy to non page aligned"); } - uint64_t phys = AllocatePageIfNecessary(dest_virt, dest_proc.vmm().cr3()); + uint64_t phys = AllocatePageIfNecessary(dest_virt, dest_proc.vmas()->cr3()); uint8_t* src = reinterpret_cast(base); uint8_t* dest = reinterpret_cast(phys + boot::GetHigherHalfDirectMap()); diff --git a/zion/object/address_space.cpp b/zion/object/address_space.cpp index 897326c..d90696a 100644 --- a/zion/object/address_space.cpp +++ b/zion/object/address_space.cpp @@ -6,10 +6,10 @@ extern KernelStackManager* gKernelStackManager; -AddressSpace AddressSpace::ForRoot() { +RefPtr AddressSpace::ForRoot() { uint64_t cr3 = 0; asm volatile("mov %%cr3, %0;" : "=r"(cr3)); - return {cr3}; + return MakeRefCounted(cr3); } AddressSpace::AddressSpace() { @@ -22,6 +22,10 @@ uint64_t AddressSpace::AllocateUserStack() { } uint64_t AddressSpace::GetNextMemMapAddr(uint64_t size) { + if (size == 0) { + panic("Zero size memmap"); + } + size = ((size - 1) & ~0xFFF) + 0x1000; uint64_t addr = next_memmap_addr_; next_memmap_addr_ += size; if (next_memmap_addr_ >= 0x30'00000000) { @@ -35,6 +39,12 @@ void AddressSpace::MapInMemoryObject(uint64_t vaddr, memory_mappings_.PushBack({.vaddr = vaddr, .mem_obj = mem_obj}); } +uint64_t AddressSpace::MapInMemoryObject(const RefPtr& mem_obj) { + uint64_t vaddr = GetNextMemMapAddr(mem_obj->size()); + memory_mappings_.PushBack({.vaddr = vaddr, .mem_obj = mem_obj}); + return vaddr; +} + uint64_t* AddressSpace::AllocateKernelStack() { return gKernelStackManager->AllocateKernelStack(); } diff --git a/zion/object/address_space.h b/zion/object/address_space.h index 5844824..20c9258 100644 --- a/zion/object/address_space.h +++ b/zion/object/address_space.h @@ -24,7 +24,7 @@ // 0xFFFFFFFF 40000000 - 0xFFFFFFFF 7FFFFFFF : KERNEL_HEAP (1 GiB) // 0xFFFFFFFF 80000000 - 0xFFFFFFFF 80FFFFFF : KERNEL_CODE (16 MiB) // 0xFFFFFFFF 90000000 - 0xFFFFFFFF 9FFFFFFF : KERNEL_STACK (256 MiB) -class AddressSpace { +class AddressSpace : public KernelObject { public: enum MemoryType { UNSPECIFIED, @@ -40,7 +40,7 @@ class AddressSpace { KERNEL_STACK, }; - static AddressSpace ForRoot(); + static RefPtr ForRoot(); AddressSpace(); AddressSpace(const AddressSpace&) = delete; @@ -56,6 +56,8 @@ class AddressSpace { // Note this is unsafe for now as it may clobber other mappings. void MapInMemoryObject(uint64_t vaddr, const RefPtr& mem_obj); + uint64_t MapInMemoryObject(const RefPtr& mem_obj); + // Kernel Mappings. uint64_t* AllocateKernelStack(); @@ -63,6 +65,7 @@ class AddressSpace { bool HandlePageFault(uint64_t vaddr); private: + friend class MakeRefCountedFriend; AddressSpace(uint64_t cr3) : cr3_(cr3) {} uint64_t cr3_ = 0; diff --git a/zion/object/process.cpp b/zion/object/process.cpp index 8e4d1e4..32bbf09 100644 --- a/zion/object/process.cpp +++ b/zion/object/process.cpp @@ -25,10 +25,13 @@ RefPtr Process::Create() { proc->caps_.PushBack( new Capability(proc, Capability::PROCESS, Z_INIT_PROC_SELF, ZC_PROC_SPAWN_PROC | ZC_PROC_SPAWN_THREAD)); + proc->caps_.PushBack(new Capability(proc->vmas(), Capability::ADDRESS_SPACE, + Z_INIT_AS_SELF, ZC_WRITE)); return proc; } -Process::Process() : id_(gNextId++), state_(RUNNING) {} +Process::Process() + : id_(gNextId++), vmm_(MakeRefCounted()), state_(RUNNING) {} RefPtr Process::CreateThread() { RefPtr thread = MakeRefCounted(*this, next_thread_id_++); @@ -77,3 +80,22 @@ uint64_t Process::AddCapability(const RefPtr& thread) { caps_.PushBack(new Capability(thread, Capability::THREAD, cap_id, ZC_WRITE)); return cap_id; } + +uint64_t Process::AddCapability(const RefPtr& p) { + uint64_t cap_id = next_cap_id_++; + caps_.PushBack(new Capability(p, Capability::PROCESS, cap_id, + ZC_WRITE | ZC_PROC_SPAWN_THREAD)); + return cap_id; +} +uint64_t Process::AddCapability(const RefPtr& as) { + uint64_t cap_id = next_cap_id_++; + caps_.PushBack( + new Capability(as, Capability::ADDRESS_SPACE, cap_id, ZC_WRITE)); + return cap_id; +} +uint64_t Process::AddCapability(const RefPtr& mo) { + uint64_t cap_id = next_cap_id_++; + caps_.PushBack( + new Capability(mo, Capability::MEMORY_OBJECT, cap_id, ZC_WRITE)); + return cap_id; +} diff --git a/zion/object/process.h b/zion/object/process.h index 3776053..00dbc51 100644 --- a/zion/object/process.h +++ b/zion/object/process.h @@ -23,13 +23,16 @@ class Process : public KernelObject { static RefPtr Create(); uint64_t id() const { return id_; } - AddressSpace& vmm() { return vmm_; } + RefPtr vmas() { return vmm_; } RefPtr CreateThread(); RefPtr GetThread(uint64_t tid); SharedPtr GetCapability(uint64_t cid); uint64_t AddCapability(const RefPtr& t); + uint64_t AddCapability(const RefPtr& p); + uint64_t AddCapability(const RefPtr& as); + uint64_t AddCapability(const RefPtr& mo); // Checks the state of all child threads and transitions to // finished if all have finished. void CheckState(); @@ -41,7 +44,7 @@ class Process : public KernelObject { Process(); Process(uint64_t id) : id_(id), vmm_(AddressSpace::ForRoot()) {} uint64_t id_; - AddressSpace vmm_; + RefPtr vmm_; State state_; uint64_t next_thread_id_ = 0; diff --git a/zion/object/thread.cpp b/zion/object/thread.cpp index 1ad6e65..af29bd3 100644 --- a/zion/object/thread.cpp +++ b/zion/object/thread.cpp @@ -29,7 +29,7 @@ RefPtr Thread::Create(Process& proc, uint64_t tid) { } Thread::Thread(Process& proc, uint64_t tid) : process_(proc), id_(tid) { - uint64_t* stack_ptr = proc.vmm().AllocateKernelStack(); + uint64_t* stack_ptr = proc.vmas()->AllocateKernelStack(); // 0: rip *(stack_ptr) = reinterpret_cast(thread_init); // 1-4: rax, rcx, rdx, rbx @@ -37,7 +37,7 @@ Thread::Thread(Process& proc, uint64_t tid) : process_(proc), id_(tid) { *(stack_ptr - 5) = reinterpret_cast(stack_ptr + 1); // 6-15: rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 // 16: cr3 - *(stack_ptr - 16) = proc.vmm().cr3(); + *(stack_ptr - 16) = proc.vmas()->cr3(); rsp0_ = reinterpret_cast(stack_ptr - 16); rsp0_start_ = reinterpret_cast(stack_ptr); } @@ -55,7 +55,7 @@ void Thread::Start(uint64_t entry, uint64_t arg1, uint64_t arg2) { void Thread::Init() { dbgln("Thread start.", pid(), id_); - uint64_t rsp = process_.vmm().AllocateUserStack(); + uint64_t rsp = process_.vmas()->AllocateUserStack(); SetRsp0(rsp0_start_); jump_user_space(rip_, rsp, arg1_, arg2_); } diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 374fe87..b190297 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -9,6 +9,7 @@ #include "object/process.h" #include "scheduler/process_manager.h" #include "scheduler/scheduler.h" +#include "usr/zcall_internal.h" #define EFER 0xC0000080 #define STAR 0xC0000081 @@ -46,36 +47,35 @@ void InitSyscall() { } uint64_t star_val = GetMSR(STAR); - // FIXME: Fix GDT such that we can properly set the user CS. - // Due to the ability to jump from a 64 bit kernel into compatibility mode, - // we set the user_cs to the kernel_cs because it adds 16 to jump to 64-bit - // mode. See AMD Manual 3.4 instruction SYSRET for more info. uint64_t kernel_cs = 0x8; - uint64_t user_cs = kernel_cs; + // Due to the ability to jump from a 64 bit kernel into compatibility mode, + // this will actually use CS 0x20 (and SS 0x18). + // See AMD Manual 3.4 instruction SYSRET for more info. + uint64_t user_cs = 0x18; star_val |= (kernel_cs << 32) | (user_cs << 48); SetMSR(STAR, star_val); SetMSR(LSTAR, reinterpret_cast(syscall_enter)); } -uint64_t ProcessSpawnElf(ZProcessSpawnElfReq* req) { +uint64_t ProcessSpawn(ZProcessSpawnReq* req, ZProcessSpawnResp* resp) { auto& curr_proc = gScheduler->CurrentProcess(); - auto cap = curr_proc.GetCapability(req->cap_id); + auto cap = curr_proc.GetCapability(req->proc_cap); if (cap.empty()) { return ZE_NOT_FOUND; } if (!cap->CheckType(Capability::PROCESS)) { return ZE_INVALID; } - if (!cap->HasPermissions(ZC_PROC_SPAWN_PROC)) { return ZE_DENIED; } - dbgln("Proc spawn: %u:%u", req->elf_base, req->elf_size); RefPtr proc = Process::Create(); gProcMan->InsertProcess(proc); - uint64_t entry = LoadElfProgram(*proc, req->elf_base, req->elf_size); - proc->CreateThread()->Start(entry, 0, 0); - return 0; + + resp->proc_cap = curr_proc.AddCapability(proc); + resp->as_cap = curr_proc.AddCapability(proc->vmas()); + + return Z_OK; } uint64_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) { @@ -92,8 +92,8 @@ uint64_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) { return ZE_DENIED; } - Process& parent_proc = cap->obj(); - auto thread = parent_proc.CreateThread(); + auto parent_proc = cap->obj(); + auto thread = parent_proc->CreateThread(); resp->thread_cap = curr_proc.AddCapability(thread); return Z_OK; @@ -113,9 +113,43 @@ uint64_t ThreadStart(ZThreadStartReq* req) { return ZE_DENIED; } - Thread& thread = cap->obj(); + auto thread = cap->obj(); // FIXME: validate entry point is in user space. - thread.Start(req->entry, req->arg1, req->arg2); + thread->Start(req->entry, req->arg1, req->arg2); + return Z_OK; +} + +uint64_t AddressSpaceMap(ZAddressSpaceMapReq* req, ZAddressSpaceMapResp* resp) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto as_cap = curr_proc.GetCapability(req->as_cap); + auto mem_cap = curr_proc.GetCapability(req->mem_cap); + if (as_cap.empty() || mem_cap.empty()) { + return ZE_NOT_FOUND; + } + if (!as_cap->CheckType(Capability::ADDRESS_SPACE) || + !mem_cap->CheckType(Capability::MEMORY_OBJECT)) { + return ZE_INVALID; + } + if (!as_cap->HasPermissions(ZC_WRITE) || !mem_cap->HasPermissions(ZC_WRITE)) { + return ZE_DENIED; + } + auto as = as_cap->obj(); + auto mo = mem_cap->obj(); + // FIXME: Validation necessary. + if (req->offset != 0) { + as->MapInMemoryObject(req->offset, mo); + resp->vaddr = req->offset; + } else { + resp->vaddr = as->MapInMemoryObject(mo); + } +} + +uint64_t MemoryObjectCreate(ZMemoryObjectCreateReq* req, + ZMemoryObjectCreateResp* resp) { + auto& curr_proc = gScheduler->CurrentProcess(); + resp->mem_cap = + curr_proc.AddCapability(MakeRefCounted(req->size)); + return Z_OK; } extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) { @@ -123,14 +157,13 @@ extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) { switch (call_id) { case Z_PROCESS_EXIT: // FIXME: kill process here. + dbgln("Exit code: %u", req); thread.Exit(); panic("Returned from thread exit"); break; - case Z_DEBUG_PRINT: - dbgln("[Debug] %s", req); - break; case Z_PROCESS_SPAWN: - return ProcessSpawnElf(reinterpret_cast(req)); + return ProcessSpawn(reinterpret_cast(req), + reinterpret_cast(resp)); case Z_THREAD_CREATE: return ThreadCreate(reinterpret_cast(req), reinterpret_cast(resp)); @@ -140,6 +173,17 @@ extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) { thread.Exit(); panic("Returned from thread exit"); break; + + case Z_ADDRESS_SPACE_MAP: + return AddressSpaceMap(reinterpret_cast(req), + reinterpret_cast(resp)); + case Z_MEMORY_OBJECT_CREATE: + return MemoryObjectCreate( + reinterpret_cast(req), + reinterpret_cast(resp)); + case Z_DEBUG_PRINT: + dbgln("[Debug] %s", req); + break; default: panic("Unhandled syscall number: %x", call_id); } diff --git a/zion/usr/crt0.s b/zion/usr/crt0.s index 530badd..8e5a49d 100644 --- a/zion/usr/crt0.s +++ b/zion/usr/crt0.s @@ -6,5 +6,8 @@ _start: call _exit _exit: + // EXIT syscall. mov $1, %rdi + // Return code as a param. + mov %rax, %rsi syscall diff --git a/zion/usr/zcall.cpp b/zion/usr/zcall.cpp index 81bc443..f89fb0f 100644 --- a/zion/usr/zcall.cpp +++ b/zion/usr/zcall.cpp @@ -2,6 +2,8 @@ #include +#include "usr/zcall_internal.h" + uint64_t SysCall0(uint64_t number) { uint64_t return_code; asm("syscall" : "=a"(return_code) : "D"(number)); @@ -23,18 +25,20 @@ uint64_t SysCall2(uint64_t number, const void* first, const void* second) { return return_code; } -uint64_t ZDebug(const char* message) { - return SysCall1(Z_DEBUG_PRINT, message); +void ZProcessExit(uint64_t code) { + SysCall1(Z_PROCESS_EXIT, reinterpret_cast(code)); } -uint64_t ZProcessSpawnElf(uint64_t cap_id, uint64_t elf_base, - uint64_t elf_size) { - ZProcessSpawnElfReq req{ - .cap_id = cap_id, - .elf_base = elf_base, - .elf_size = elf_size, +uint64_t ZProcessSpawn(uint64_t proc_cap, uint64_t* new_proc_cap, + uint64_t* new_as_cap) { + ZProcessSpawnReq req{ + .proc_cap = proc_cap, }; - return SysCall1(Z_PROCESS_SPAWN, &req); + ZProcessSpawnResp resp; + uint64_t ret = SysCall2(Z_PROCESS_SPAWN, &req, &resp); + *new_proc_cap = resp.proc_cap; + *new_as_cap = resp.as_cap; + return ret; } uint64_t ZThreadCreate(uint64_t proc_cap, uint64_t* thread_cap) { @@ -59,3 +63,29 @@ uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1, } void ZThreadExit() { SysCall0(Z_THREAD_EXIT); } + +uint64_t ZAddressSpaceMap(uint64_t as_cap, uint64_t offset, uint64_t mem_cap, + uint64_t* vaddr) { + ZAddressSpaceMapReq req{ + .as_cap = as_cap, + .offset = offset, + .mem_cap = mem_cap, + }; + ZAddressSpaceMapResp resp; + uint64_t ret = SysCall2(Z_ADDRESS_SPACE_MAP, &req, &resp); + *vaddr = resp.vaddr; + return ret; +} +uint64_t ZMemoryObjectCreate(uint64_t size, uint64_t* mem_cap) { + ZMemoryObjectCreateReq req{ + .size = size, + }; + ZMemoryObjectCreateResp resp; + uint64_t ret = SysCall2(Z_MEMORY_OBJECT_CREATE, &req, &resp); + *mem_cap = resp.mem_cap; + return ret; +} + +uint64_t ZDebug(const char* message) { + return SysCall1(Z_DEBUG_PRINT, message); +} diff --git a/zion/usr/zcall_internal.h b/zion/usr/zcall_internal.h new file mode 100644 index 0000000..96d646a --- /dev/null +++ b/zion/usr/zcall_internal.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +struct ZProcessSpawnReq { + uint64_t proc_cap; +}; + +struct ZProcessSpawnResp { + uint64_t proc_cap; + uint64_t as_cap; +}; + +struct ZThreadCreateReq { + uint64_t proc_cap; +}; + +struct ZThreadCreateResp { + uint64_t thread_cap; +}; + +struct ZThreadStartReq { + uint64_t thread_cap; + uint64_t entry; + uint64_t arg1; + uint64_t arg2; +}; + +struct ZAddressSpaceMapReq { + uint64_t as_cap; + uint64_t offset; + uint64_t mem_cap; +}; + +struct ZAddressSpaceMapResp { + uint64_t vaddr; +}; + +struct ZMemoryObjectCreateReq { + uint64_t size; +}; + +struct ZMemoryObjectCreateResp { + uint64_t mem_cap; +};