Compare commits
5 Commits
e3661e7848
...
174d4b10fb
Author | SHA1 | Date |
---|---|---|
|
174d4b10fb | |
|
b0c2a6732b | |
|
ef8eb5d993 | |
|
e2aad55a8a | |
|
a092a57483 |
|
@ -10,6 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS True)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS True)
|
||||||
|
|
||||||
add_subdirectory(zion)
|
add_subdirectory(zion)
|
||||||
|
add_subdirectory(lib)
|
||||||
add_subdirectory(sys)
|
add_subdirectory(sys)
|
||||||
|
|
||||||
set(QEMU_CMD qemu-system-x86_64 -d guest_errors -m 1G -serial stdio -hda disk.img)
|
set(QEMU_CMD qemu-system-x86_64 -d guest_errors -m 1G -serial stdio -hda disk.img)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory(mammoth)
|
|
@ -0,0 +1,16 @@
|
||||||
|
add_library(mammoth_lib STATIC
|
||||||
|
src/debug.cpp
|
||||||
|
src/thread.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(mammoth_lib
|
||||||
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
target_link_libraries(mammoth_lib
|
||||||
|
zion_lib)
|
||||||
|
|
||||||
|
set(_COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -c -ffreestanding -fno-rtti -fno-exceptions -nostdlib -mabi=sysv -mgeneral-regs-only")
|
||||||
|
|
||||||
|
set_target_properties(mammoth_lib PROPERTIES
|
||||||
|
COMPILE_FLAGS "${_COMPILE_FLAGS}")
|
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void dbgln(const char*);
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class Thread {
|
||||||
|
public:
|
||||||
|
typedef void (*Entry)(void*);
|
||||||
|
|
||||||
|
Thread(Entry e, const void* arg1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t thread_cap_;
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "include/mammoth/debug.h"
|
||||||
|
|
||||||
|
#include "zcall.h"
|
||||||
|
|
||||||
|
void dbgln(const char* str) { ZDebug(str); }
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include "include/mammoth/thread.h"
|
||||||
|
|
||||||
|
#include "zcall.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
extern "C" void thread_entry(Thread::Entry entry, void* arg1) {
|
||||||
|
entry(arg1);
|
||||||
|
|
||||||
|
ZThreadExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Thread::Thread(Entry e, const void* arg1) {
|
||||||
|
ZThreadCreate(Z_INIT_PROC_SELF, &thread_cap_);
|
||||||
|
ZThreadStart(thread_cap_, reinterpret_cast<uint64_t>(thread_entry),
|
||||||
|
reinterpret_cast<uint64_t>(e), reinterpret_cast<uint64_t>(arg1));
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ add_executable(test2
|
||||||
test2.cpp)
|
test2.cpp)
|
||||||
|
|
||||||
target_link_libraries(test2
|
target_link_libraries(test2
|
||||||
zion_lib)
|
mammoth_lib)
|
||||||
|
|
||||||
set_target_properties(test2
|
set_target_properties(test2
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
|
|
|
@ -6,7 +6,7 @@ constexpr uint64_t prog2 = 0x00000020'00000000;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
ZDebug("Testing");
|
ZDebug("Testing");
|
||||||
uint64_t err = ZProcessSpawn(0x100, prog2, 0x1000);
|
uint64_t err = ZProcessSpawnElf(Z_INIT_PROC_SELF, prog2, 0x2000);
|
||||||
if (err != Z_OK) {
|
if (err != Z_OK) {
|
||||||
ZDebug("Error");
|
ZDebug("Error");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,8 +1,28 @@
|
||||||
|
#include "mammoth/debug.h"
|
||||||
|
#include "mammoth/thread.h"
|
||||||
|
|
||||||
|
#define CHECK(expr) \
|
||||||
|
{ \
|
||||||
|
uint64_t code = expr; \
|
||||||
|
if (code != Z_OK) { \
|
||||||
|
ZDebug("crash!"); \
|
||||||
|
return 1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#include "zcall.h"
|
void thread_entry(void* a) {
|
||||||
|
dbgln("In thread");
|
||||||
|
dbgln(static_cast<const char*>(a));
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
ZDebug("Testing");
|
dbgln("Main thread");
|
||||||
|
|
||||||
|
const char* a = "a";
|
||||||
|
const char* b = "bee";
|
||||||
|
const char* c = "cee";
|
||||||
|
const char* d = "dee";
|
||||||
|
Thread t1(thread_entry, a);
|
||||||
|
Thread t2(thread_entry, b);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
add_executable(zion
|
add_executable(zion
|
||||||
boot/boot_info.cpp
|
boot/boot_info.cpp
|
||||||
|
capability/capability.cpp
|
||||||
common/gdt.cpp
|
common/gdt.cpp
|
||||||
common/load_gdt.s
|
common/load_gdt.s
|
||||||
debug/debug.cpp
|
debug/debug.cpp
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "capability/capability.h"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
Process& Capability::obj<Process>() {
|
||||||
|
if (type_ != PROCESS) {
|
||||||
|
panic("Accessing %u cap as object.", type_);
|
||||||
|
}
|
||||||
|
return *static_cast<Process*>(obj_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
Thread& Capability::obj<Thread>() {
|
||||||
|
if (type_ != THREAD) {
|
||||||
|
panic("Accessing %u cap as object.", type_);
|
||||||
|
}
|
||||||
|
return *static_cast<Thread*>(obj_);
|
||||||
|
}
|
|
@ -5,12 +5,14 @@
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
|
|
||||||
class Process;
|
class Process;
|
||||||
|
class Thread;
|
||||||
|
|
||||||
class Capability {
|
class Capability {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
PROCESS,
|
PROCESS,
|
||||||
|
THREAD,
|
||||||
};
|
};
|
||||||
Capability(void* obj, Type type, uint64_t id, uint64_t permissions)
|
Capability(void* obj, Type type, uint64_t id, uint64_t permissions)
|
||||||
: obj_(obj), type_(type), id_(id), permissions_(permissions) {}
|
: obj_(obj), type_(type), id_(id), permissions_(permissions) {}
|
||||||
|
@ -34,11 +36,3 @@ class Capability {
|
||||||
uint64_t id_;
|
uint64_t id_;
|
||||||
uint64_t permissions_;
|
uint64_t permissions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Process>
|
|
||||||
Process& Capability::obj() {
|
|
||||||
if (type_ != PROCESS) {
|
|
||||||
panic("Accessing %u cap as object.", type_);
|
|
||||||
}
|
|
||||||
return *static_cast<Process*>(obj_);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define ZC_PROC_SPAWN_CHILD 0x1
|
|
|
@ -2,19 +2,63 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define Z_THREAD_EXIT 0x01
|
#define Z_INVALID 0x0
|
||||||
|
|
||||||
#define Z_PROCESS_SPAWN 0x10
|
#define ZC_WRITE 0x01
|
||||||
|
#define ZC_READ 0x02
|
||||||
|
|
||||||
#define Z_DEBUG_PRINT 0x100
|
// Process Calls.
|
||||||
|
#define Z_PROCESS_EXIT 0x01
|
||||||
|
#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
|
||||||
|
|
||||||
|
// Thread Calls.
|
||||||
|
#define Z_THREAD_CREATE 0x10
|
||||||
|
#define Z_THREAD_START 0x11
|
||||||
|
#define Z_THREAD_EXIT 0x12
|
||||||
|
|
||||||
|
// Debugging Calls.
|
||||||
|
#define Z_DEBUG_PRINT 0x10000000
|
||||||
|
|
||||||
uint64_t ZDebug(const char* message);
|
uint64_t ZDebug(const char* message);
|
||||||
|
|
||||||
// TODO: Move structs into an internal header.
|
// TODO: Move structs into an internal header.
|
||||||
struct ZProcessSpawnReq {
|
struct ZProcessSpawnElfReq {
|
||||||
uint64_t cap_id;
|
uint64_t cap_id;
|
||||||
uint64_t elf_base;
|
uint64_t elf_base;
|
||||||
uint64_t elf_size;
|
uint64_t elf_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t ZProcessSpawn(uint64_t cap_id, uint64_t elf_base, uint64_t elf_size);
|
// 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);
|
||||||
|
|
||||||
|
struct ZThreadCreateReq {
|
||||||
|
uint64_t proc_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);
|
||||||
|
|
||||||
|
void ZThreadExit();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "memory/paging_util.h"
|
#include "memory/paging_util.h"
|
||||||
#include "scheduler/process.h"
|
#include "scheduler/process.h"
|
||||||
#include "scheduler/process_manager.h"
|
#include "scheduler/process_manager.h"
|
||||||
|
#include "scheduler/thread.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -23,12 +24,19 @@ bool streq(const char* a, const char* b) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const limine_file& GetInitProgram(const char* path) {
|
void DumpModules() {
|
||||||
|
const limine_module_response& resp = boot::GetModules();
|
||||||
|
dbgln("[boot] Dumping bootloader modules.");
|
||||||
|
for (uint64_t i = 0; i < resp.module_count; i++) {
|
||||||
|
const limine_file& file = *resp.modules[i];
|
||||||
|
dbgln(" %s,%m,%x", file.path, file.address, file.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const limine_file& GetInitProgram(const char* path) {
|
||||||
const limine_module_response& resp = boot::GetModules();
|
const limine_module_response& resp = boot::GetModules();
|
||||||
dbgln("Dumping modules");
|
|
||||||
for (uint64_t i = 0; i < resp.module_count; i++) {
|
for (uint64_t i = 0; i < resp.module_count; i++) {
|
||||||
const limine_file& file = *resp.modules[i];
|
const limine_file& file = *resp.modules[i];
|
||||||
dbgln("%s,%m,%x", file.path, file.address, file.size);
|
|
||||||
if (streq(file.path, path)) return file;
|
if (streq(file.path, path)) return file;
|
||||||
}
|
}
|
||||||
panic("Program not found: %s", path);
|
panic("Program not found: %s", path);
|
||||||
|
@ -37,6 +45,7 @@ const limine_file& GetInitProgram(const char* path) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void LoadInitProgram() {
|
void LoadInitProgram() {
|
||||||
|
DumpModules();
|
||||||
const limine_file& init_prog = GetInitProgram("/sys/test");
|
const limine_file& init_prog = GetInitProgram("/sys/test");
|
||||||
const limine_file& prog2 = GetInitProgram("/sys/test2");
|
const limine_file& prog2 = GetInitProgram("/sys/test2");
|
||||||
|
|
||||||
|
@ -50,5 +59,5 @@ void LoadInitProgram() {
|
||||||
prog2.size, *proc,
|
prog2.size, *proc,
|
||||||
proc->vmm().GetNextMemMapAddr(prog2.size));
|
proc->vmm().GetNextMemMapAddr(prog2.size));
|
||||||
|
|
||||||
proc->CreateThread(entry);
|
proc->CreateThread()->Start(entry, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,22 @@ uint64_t CurrCr3() {
|
||||||
return pml4_addr;
|
return pml4_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CopyPageIntoNonResidentProcess(uint64_t base, uint64_t size,
|
||||||
|
Process& dest_proc, uint64_t dest_virt) {
|
||||||
|
if (size > 0x1000) {
|
||||||
|
panic("NR copy > 1 page");
|
||||||
|
}
|
||||||
|
if (dest_virt & 0xFFF) {
|
||||||
|
panic("NR copy to non page aligned");
|
||||||
|
}
|
||||||
|
uint64_t phys = AllocatePageIfNecessary(dest_virt, dest_proc.vmm().cr3());
|
||||||
|
uint8_t* src = reinterpret_cast<uint8_t*>(base);
|
||||||
|
uint8_t* dest =
|
||||||
|
reinterpret_cast<uint8_t*>(phys + boot::GetHigherHalfDirectMap());
|
||||||
|
for (uint64_t i = 0; i < size; i++) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void InitializePml4(uint64_t pml4_physical_addr) {
|
void InitializePml4(uint64_t pml4_physical_addr) {
|
||||||
|
@ -176,18 +192,13 @@ void EnsureResident(uint64_t addr, uint64_t size) {
|
||||||
|
|
||||||
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size,
|
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size,
|
||||||
Process& dest_proc, uint64_t dest_virt) {
|
Process& dest_proc, uint64_t dest_virt) {
|
||||||
if (size > 0x1000) {
|
while (size > 0) {
|
||||||
panic("Unimplemented NR copy > 1 page");
|
uint64_t to_copy = size > 0x1000 ? 0x1000 : size;
|
||||||
}
|
|
||||||
if (dest_virt & 0xFFF) {
|
|
||||||
panic("Unimplemented NR copy to non page aligned");
|
|
||||||
}
|
|
||||||
uint64_t phys = AllocatePageIfNecessary(dest_virt, dest_proc.vmm().cr3());
|
|
||||||
uint8_t* src = reinterpret_cast<uint8_t*>(base);
|
|
||||||
uint8_t* dest =
|
|
||||||
reinterpret_cast<uint8_t*>(phys + boot::GetHigherHalfDirectMap());
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < size; i++) {
|
CopyPageIntoNonResidentProcess(base, to_copy, dest_proc, dest_virt);
|
||||||
dest[i] = src[i];
|
|
||||||
|
size -= to_copy;
|
||||||
|
base += 0x1000;
|
||||||
|
dest_virt += 0x1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,6 @@ jump_user_space:
|
||||||
pushf # Can we just push 0 for flags?
|
pushf # Can we just push 0 for flags?
|
||||||
pushq $0x1B # cs
|
pushq $0x1B # cs
|
||||||
pushq %rdi
|
pushq %rdi
|
||||||
|
mov %rdx, %rdi
|
||||||
|
mov %rcx, %rsi
|
||||||
iretq
|
iretq
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "scheduler/process.h"
|
#include "scheduler/process.h"
|
||||||
|
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "include/cap_types.h"
|
#include "include/zcall.h"
|
||||||
#include "memory/paging_util.h"
|
#include "memory/paging_util.h"
|
||||||
#include "memory/physical_memory.h"
|
#include "memory/physical_memory.h"
|
||||||
#include "scheduler/scheduler.h"
|
#include "scheduler/scheduler.h"
|
||||||
|
@ -21,14 +21,15 @@ SharedPtr<Process> Process::RootProcess() {
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process() : id_(gNextId++), state_(RUNNING) {}
|
Process::Process() : id_(gNextId++), state_(RUNNING) {
|
||||||
|
caps_.PushBack(new Capability(this, Capability::PROCESS, Z_INIT_PROC_SELF,
|
||||||
|
ZC_PROC_SPAWN_PROC | ZC_PROC_SPAWN_THREAD));
|
||||||
|
}
|
||||||
|
|
||||||
void Process::CreateThread(uint64_t entry) {
|
SharedPtr<Thread> Process::CreateThread() {
|
||||||
Thread* thread = new Thread(*this, next_thread_id_++, entry);
|
SharedPtr<Thread> thread{new Thread(*this, next_thread_id_++, 0)};
|
||||||
threads_.PushBack(thread);
|
threads_.PushBack(thread);
|
||||||
caps_.PushBack(new Capability(this, Capability::PROCESS, next_cap_id_++,
|
return thread;
|
||||||
ZC_PROC_SPAWN_CHILD));
|
|
||||||
gScheduler->Enqueue(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> Process::GetThread(uint64_t tid) {
|
SharedPtr<Thread> Process::GetThread(uint64_t tid) {
|
||||||
|
@ -65,3 +66,10 @@ SharedPtr<Capability> Process::GetCapability(uint64_t cid) {
|
||||||
dbgln("Bad cap access");
|
dbgln("Bad cap access");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Process::AddCapability(SharedPtr<Thread>& thread) {
|
||||||
|
uint64_t cap_id = next_cap_id_++;
|
||||||
|
caps_.PushBack(
|
||||||
|
new Capability(thread.ptr(), Capability::THREAD, cap_id, ZC_WRITE));
|
||||||
|
return cap_id;
|
||||||
|
}
|
||||||
|
|
|
@ -24,10 +24,11 @@ class Process {
|
||||||
uint64_t id() const { return id_; }
|
uint64_t id() const { return id_; }
|
||||||
VirtualMemory& vmm() { return vmm_; }
|
VirtualMemory& vmm() { return vmm_; }
|
||||||
|
|
||||||
void CreateThread(uint64_t entry);
|
SharedPtr<Thread> CreateThread();
|
||||||
SharedPtr<Thread> GetThread(uint64_t tid);
|
SharedPtr<Thread> GetThread(uint64_t tid);
|
||||||
|
|
||||||
SharedPtr<Capability> GetCapability(uint64_t cid);
|
SharedPtr<Capability> GetCapability(uint64_t cid);
|
||||||
|
uint64_t AddCapability(SharedPtr<Thread>& t);
|
||||||
// Checks the state of all child threads and transitions to
|
// Checks the state of all child threads and transitions to
|
||||||
// finished if all have finished.
|
// finished if all have finished.
|
||||||
void CheckState();
|
void CheckState();
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
extern "C" void jump_user_space(uint64_t rip, uint64_t rsp);
|
extern "C" void jump_user_space(uint64_t rip, uint64_t rsp, uint64_t arg1,
|
||||||
|
uint64_t arg2);
|
||||||
|
|
||||||
extern "C" void thread_init() {
|
extern "C" void thread_init() {
|
||||||
asm("sti");
|
asm("sti");
|
||||||
|
@ -40,11 +41,20 @@ Thread::Thread(Process& proc, uint64_t tid, uint64_t entry)
|
||||||
|
|
||||||
uint64_t Thread::pid() const { return process_.id(); }
|
uint64_t Thread::pid() const { return process_.id(); }
|
||||||
|
|
||||||
|
void Thread::Start(uint64_t entry, uint64_t arg1, uint64_t arg2) {
|
||||||
|
rip_ = entry;
|
||||||
|
arg1_ = arg1;
|
||||||
|
arg2_ = arg2;
|
||||||
|
state_ = RUNNABLE;
|
||||||
|
// Get from parent to avoid creating a new shared ptr.
|
||||||
|
gScheduler->Enqueue(process_.GetThread(id_));
|
||||||
|
}
|
||||||
|
|
||||||
void Thread::Init() {
|
void Thread::Init() {
|
||||||
dbgln("Thread start.", pid(), id_);
|
dbgln("Thread start.", pid(), id_);
|
||||||
uint64_t rsp = process_.vmm().AllocateUserStack();
|
uint64_t rsp = process_.vmm().AllocateUserStack();
|
||||||
SetRsp0(rsp0_start_);
|
SetRsp0(rsp0_start_);
|
||||||
jump_user_space(rip_, rsp);
|
jump_user_space(rip_, rsp, arg1_, arg2_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::Exit() {
|
void Thread::Exit() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Thread {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
UNSPECIFIED,
|
UNSPECIFIED,
|
||||||
|
CREATED,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
RUNNABLE,
|
RUNNABLE,
|
||||||
FINISHED,
|
FINISHED,
|
||||||
|
@ -27,6 +28,9 @@ class Thread {
|
||||||
uint64_t* Rsp0Ptr() { return &rsp0_; }
|
uint64_t* Rsp0Ptr() { return &rsp0_; }
|
||||||
uint64_t Rsp0Start() { return rsp0_start_; }
|
uint64_t Rsp0Start() { return rsp0_start_; }
|
||||||
|
|
||||||
|
// Switches the thread's state to runnable and enqueues it.
|
||||||
|
void Start(uint64_t entry, uint64_t arg1, uint64_t arg2);
|
||||||
|
|
||||||
// Called the first time the thread starts up.
|
// Called the first time the thread starts up.
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
@ -40,10 +44,12 @@ class Thread {
|
||||||
Thread(Process& proc) : process_(proc), id_(0) {}
|
Thread(Process& proc) : process_(proc), id_(0) {}
|
||||||
Process& process_;
|
Process& process_;
|
||||||
uint64_t id_;
|
uint64_t id_;
|
||||||
State state_ = RUNNABLE;
|
State state_ = CREATED;
|
||||||
|
|
||||||
// Startup Context for the thread.
|
// Startup Context for the thread.
|
||||||
uint64_t rip_;
|
uint64_t rip_;
|
||||||
|
uint64_t arg1_;
|
||||||
|
uint64_t arg2_;
|
||||||
|
|
||||||
// Stack pointer to take on resume.
|
// Stack pointer to take on resume.
|
||||||
// Stack will contain the full thread context.
|
// Stack will contain the full thread context.
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "include/cap_types.h"
|
|
||||||
#include "include/zcall.h"
|
#include "include/zcall.h"
|
||||||
#include "include/zerrors.h"
|
#include "include/zerrors.h"
|
||||||
#include "loader/elf_loader.h"
|
#include "loader/elf_loader.h"
|
||||||
|
@ -58,7 +57,7 @@ void InitSyscall() {
|
||||||
SetMSR(LSTAR, reinterpret_cast<uint64_t>(syscall_enter));
|
SetMSR(LSTAR, reinterpret_cast<uint64_t>(syscall_enter));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ProcessSpawn(ZProcessSpawnReq* req) {
|
uint64_t ProcessSpawnElf(ZProcessSpawnElfReq* req) {
|
||||||
auto& curr_proc = gScheduler->CurrentProcess();
|
auto& curr_proc = gScheduler->CurrentProcess();
|
||||||
auto cap = curr_proc.GetCapability(req->cap_id);
|
auto cap = curr_proc.GetCapability(req->cap_id);
|
||||||
if (cap.empty()) {
|
if (cap.empty()) {
|
||||||
|
@ -68,31 +67,81 @@ uint64_t ProcessSpawn(ZProcessSpawnReq* req) {
|
||||||
return ZE_INVALID;
|
return ZE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cap->HasPermissions(ZC_PROC_SPAWN_CHILD)) {
|
if (!cap->HasPermissions(ZC_PROC_SPAWN_PROC)) {
|
||||||
return ZE_DENIED;
|
return ZE_DENIED;
|
||||||
}
|
}
|
||||||
dbgln("Proc spawn: %u:%u", req->elf_base, req->elf_size);
|
dbgln("Proc spawn: %u:%u", req->elf_base, req->elf_size);
|
||||||
SharedPtr<Process> proc = MakeShared<Process>();
|
SharedPtr<Process> proc = MakeShared<Process>();
|
||||||
gProcMan->InsertProcess(proc);
|
gProcMan->InsertProcess(proc);
|
||||||
uint64_t entry = LoadElfProgram(*proc, req->elf_base, req->elf_size);
|
uint64_t entry = LoadElfProgram(*proc, req->elf_base, req->elf_size);
|
||||||
proc->CreateThread(entry);
|
proc->CreateThread()->Start(entry, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" uint64_t SyscallHandler(uint64_t call_id, char* message) {
|
uint64_t ThreadCreate(ZThreadCreateReq* req, ZThreadCreateResp* resp) {
|
||||||
|
auto& curr_proc = gScheduler->CurrentProcess();
|
||||||
|
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_THREAD)) {
|
||||||
|
return ZE_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process& parent_proc = cap->obj<Process>();
|
||||||
|
auto thread = parent_proc.CreateThread();
|
||||||
|
resp->thread_cap = curr_proc.AddCapability(thread);
|
||||||
|
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ThreadStart(ZThreadStartReq* req) {
|
||||||
|
auto& curr_proc = gScheduler->CurrentProcess();
|
||||||
|
auto cap = curr_proc.GetCapability(req->thread_cap);
|
||||||
|
if (cap.empty()) {
|
||||||
|
return ZE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if (!cap->CheckType(Capability::THREAD)) {
|
||||||
|
return ZE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cap->HasPermissions(ZC_WRITE)) {
|
||||||
|
return ZE_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread& thread = cap->obj<Thread>();
|
||||||
|
// FIXME: validate entry point is in user space.
|
||||||
|
thread.Start(req->entry, req->arg1, req->arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" uint64_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
|
||||||
Thread& thread = gScheduler->CurrentThread();
|
Thread& thread = gScheduler->CurrentThread();
|
||||||
switch (call_id) {
|
switch (call_id) {
|
||||||
case Z_THREAD_EXIT:
|
case Z_PROCESS_EXIT:
|
||||||
|
// FIXME: kill process here.
|
||||||
thread.Exit();
|
thread.Exit();
|
||||||
panic("Returned from thread exit");
|
panic("Returned from thread exit");
|
||||||
break;
|
break;
|
||||||
case Z_DEBUG_PRINT:
|
case Z_DEBUG_PRINT:
|
||||||
dbgln("[Debug] %s", message);
|
dbgln("[Debug] %s", req);
|
||||||
break;
|
break;
|
||||||
case Z_PROCESS_SPAWN:
|
case Z_PROCESS_SPAWN:
|
||||||
return ProcessSpawn(reinterpret_cast<ZProcessSpawnReq*>(message));
|
return ProcessSpawnElf(reinterpret_cast<ZProcessSpawnElfReq*>(req));
|
||||||
|
case Z_THREAD_CREATE:
|
||||||
|
return ThreadCreate(reinterpret_cast<ZThreadCreateReq*>(req),
|
||||||
|
reinterpret_cast<ZThreadCreateResp*>(resp));
|
||||||
|
case Z_THREAD_START:
|
||||||
|
return ThreadStart(reinterpret_cast<ZThreadStartReq*>(req));
|
||||||
|
case Z_THREAD_EXIT:
|
||||||
|
thread.Exit();
|
||||||
|
panic("Returned from thread exit");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled syscall number: %u", call_id);
|
panic("Unhandled syscall number: %x", call_id);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,60 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint64_t SysCall0(uint64_t number) {
|
||||||
|
uint64_t return_code;
|
||||||
|
asm("syscall" : "=a"(return_code) : "D"(number));
|
||||||
|
return return_code;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t SysCall1(uint64_t number, const void* first) {
|
uint64_t SysCall1(uint64_t number, const void* first) {
|
||||||
uint64_t return_code;
|
uint64_t return_code;
|
||||||
asm("syscall" : "=a"(return_code) : "D"(number), "S"(first) : "rcx", "r11");
|
asm("syscall" : "=a"(return_code) : "D"(number), "S"(first) : "rcx", "r11");
|
||||||
return return_code;
|
return return_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t SysCall2(uint64_t number, const void* first, const void* second) {
|
||||||
|
uint64_t return_code;
|
||||||
|
asm("syscall"
|
||||||
|
: "=a"(return_code)
|
||||||
|
: "D"(number), "S"(first), "d"(second)
|
||||||
|
: "rcx", "r11");
|
||||||
|
return return_code;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t ZDebug(const char* message) {
|
uint64_t ZDebug(const char* message) {
|
||||||
return SysCall1(Z_DEBUG_PRINT, message);
|
return SysCall1(Z_DEBUG_PRINT, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ZProcessSpawn(uint64_t cap_id, uint64_t elf_base, uint64_t elf_size) {
|
uint64_t ZProcessSpawnElf(uint64_t cap_id, uint64_t elf_base,
|
||||||
ZProcessSpawnReq req{
|
uint64_t elf_size) {
|
||||||
|
ZProcessSpawnElfReq req{
|
||||||
.cap_id = cap_id,
|
.cap_id = cap_id,
|
||||||
.elf_base = elf_base,
|
.elf_base = elf_base,
|
||||||
.elf_size = elf_size,
|
.elf_size = elf_size,
|
||||||
};
|
};
|
||||||
return SysCall1(Z_PROCESS_SPAWN, &req);
|
return SysCall1(Z_PROCESS_SPAWN, &req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_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);
|
||||||
|
*thread_cap = resp.thread_cap;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ZThreadStart(uint64_t thread_cap, uint64_t entry, uint64_t arg1,
|
||||||
|
uint64_t arg2) {
|
||||||
|
ZThreadStartReq req{
|
||||||
|
.thread_cap = thread_cap,
|
||||||
|
.entry = entry,
|
||||||
|
.arg1 = arg1,
|
||||||
|
.arg2 = arg2,
|
||||||
|
};
|
||||||
|
return SysCall1(Z_THREAD_START, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZThreadExit() { SysCall0(Z_THREAD_EXIT); }
|
||||||
|
|
Loading…
Reference in New Issue