Compare commits

...

3 Commits

14 changed files with 96 additions and 19 deletions

View File

@ -6,6 +6,7 @@
#include "glacier/container/linked_list.h"
#include "glacier/container/pair.h"
#include "glacier/status/error.h"
#include "glacier/string/str_format.h"
#include "glacier/string/string.h"
#include "glacier/util/hash.h"
@ -53,6 +54,8 @@ class HashMap {
void Resize(uint64_t new_size);
void DebugIntoStr(StringBuilder& builder) const;
private:
Array<LinkedList<Pair<K, V>>> data_;
uint64_t size_ = 0;
@ -211,4 +214,26 @@ void HashMap<K, V, H>::ResizeIfNecessary() {
}
}
template <typename K, typename V>
void StrFormatValue(StringBuilder& builder, const HashMap<K, V>& value,
StringView opts) {
value.DebugIntoStr(builder);
}
template <typename K, typename V, class H>
void HashMap<K, V, H>::DebugIntoStr(StringBuilder& builder) const {
for (uint64_t i = 0; i < data_.size(); i++) {
if (data_[i].size() == 0) {
continue;
}
StrFormatValue(builder, i, "");
builder.PushBack(": ");
auto& ll = data_[i];
for (auto& item : ll) {
StrFormatInternal(builder, "{},", item.first());
}
builder.PushBack('\n');
}
}
} // namespace glcr

View File

@ -1,5 +1,7 @@
#pragma once
#include "glacier/string/str_format.h"
namespace glcr {
template <typename T>
@ -100,4 +102,10 @@ RefPtr<T> StaticCastRefPtr(const RefPtr<U>& ref) {
return RefPtr(static_cast<T*>(ref.get()), RefPtr<T>::DontAdopt);
}
template <typename T>
void StrFormatValue(StringBuilder& builder, const RefPtr<T>& value,
StringView opts) {
StrFormatValue(builder, (uint64_t)value.get(), opts);
}
} // namespace glcr

View File

@ -103,8 +103,8 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) {
} // namespace
glcr::ErrorCode SpawnProcessFromElfRegion(uint64_t program,
z_cap_t yellowstone_client) {
glcr::ErrorOr<z_cap_t> SpawnProcessFromElfRegion(uint64_t program,
z_cap_t yellowstone_client) {
uint64_t proc_cap;
uint64_t as_cap;
uint64_t foreign_port_id;
@ -130,7 +130,9 @@ glcr::ErrorCode SpawnProcessFromElfRegion(uint64_t program,
uint64_t thread_cap;
RET_ERR(ZThreadCreate(proc_cap, &thread_cap));
RET_ERR(pclient.WriteMessage<uint64_t>(Z_INIT_SELF_PROC, proc_cap));
uint64_t dup_proc_cap;
RET_ERR(ZCapDuplicate(proc_cap, kZionPerm_All, &dup_proc_cap));
RET_ERR(pclient.WriteMessage<uint64_t>(Z_INIT_SELF_PROC, dup_proc_cap));
RET_ERR(pclient.WriteMessage<uint64_t>(Z_INIT_SELF_VMAS, as_cap));
RET_ERR(pclient.WriteMessage<uint64_t>(Z_INIT_ENDPOINT, yellowstone_client));
@ -139,7 +141,7 @@ glcr::ErrorCode SpawnProcessFromElfRegion(uint64_t program,
#endif
RET_ERR(ZThreadStart(thread_cap, entry_point, foreign_port_id, 0));
return glcr::OK;
return proc_cap;
}
} // namespace mmth

View File

@ -1,12 +1,12 @@
#pragma once
#include <glacier/status/error.h>
#include <glacier/status/error_or.h>
#include <stdint.h>
#include <ztypes.h>
namespace mmth {
glcr::ErrorCode SpawnProcessFromElfRegion(uint64_t program,
z_cap_t yellowstone_client);
glcr::ErrorOr<z_cap_t> SpawnProcessFromElfRegion(uint64_t program,
z_cap_t yellowstone_client);
} // namespace mmth

View File

@ -4,6 +4,7 @@
#include <glacier/string/str_split.h>
#include <mammoth/file/file.h>
#include <mammoth/proc/process.h>
#include <mammoth/util/debug.h>
#include <mammoth/util/init.h>
void Terminal::HandleCharacter(char c) {
@ -68,7 +69,19 @@ void Terminal::ExecuteCommand(const glcr::String& command) {
auto file = mmth::File::Open(tokens[1]);
// TODO: Wait until the process exits.
mmth::SpawnProcessFromElfRegion((uint64_t)file.raw_ptr(), gInitEndpointCap);
auto error_or_cap = mmth::SpawnProcessFromElfRegion(
(uint64_t)file.raw_ptr(), gInitEndpointCap);
if (!error_or_cap.ok()) {
console_.WriteString(
glcr::StrFormat("Error: {}\n", error_or_cap.error()));
return;
}
uint64_t err_code;
check(ZProcessWait(error_or_cap.value(), &err_code));
if (err_code != 0) {
console_.WriteString(glcr::StrFormat(
"Process Error: {}\n", static_cast<glcr::ErrorCode>(err_code)));
}
} else {
console_.WriteString("Unknown command: ");

View File

@ -15,7 +15,12 @@
glcr::ErrorCode SpawnProcess(z_cap_t vmmo_cap, z_cap_t yellowstone_cap) {
mmth::OwnedMemoryRegion region =
mmth::OwnedMemoryRegion::FromCapability(vmmo_cap);
return mmth::SpawnProcessFromElfRegion(region.vaddr(), yellowstone_cap);
auto error_or =
mmth::SpawnProcessFromElfRegion(region.vaddr(), yellowstone_cap);
if (error_or.ok()) {
return glcr::OK;
}
return error_or.error();
}
uint64_t main(uint64_t port_cap) {
@ -48,8 +53,11 @@ uint64_t main(uint64_t port_cap) {
mmth::File::Open(glcr::StrFormat("/bin/{}", files[i]));
ASSIGN_OR_RETURN(client_cap, server->CreateClientCap());
check(mmth::SpawnProcessFromElfRegion((uint64_t)binary.raw_ptr(),
client_cap));
auto error_or = mmth::SpawnProcessFromElfRegion(
(uint64_t)binary.raw_ptr(), client_cap);
if (!error_or.ok()) {
check(error_or.error());
}
}
}

View File

@ -10,6 +10,7 @@ z_err_t SysCall1(uint64_t code, const void* req);
SYS1(ProcessExit, uint64_t, code);
SYS5(ProcessSpawn, z_cap_t, proc_cap, z_cap_t, bootstrap_cap, z_cap_t*,
new_proc_cap, z_cap_t*, new_vmas_cap, z_cap_t*, new_bootstrap_cap);
SYS2(ProcessWait, z_cap_t, proc_cap, z_err_t*, exit_code);
SYS2(ThreadCreate, z_cap_t, proc_cap, z_cap_t*, thread_cap);
SYS4(ThreadStart, z_cap_t, thread_cap, uint64_t, entry, uint64_t, arg1,

View File

@ -12,6 +12,7 @@ typedef uint64_t z_err_t;
// Process Calls.
const uint64_t kZionProcessExit = 0x1;
const uint64_t kZionProcessSpawn = 0x2;
const uint64_t kZionProcessWait = 0x3;
// Thread Calls.
const uint64_t kZionThreadCreate = 0x10;

View File

@ -79,7 +79,7 @@ extern "C" void interrupt_divide_by_zero(InterruptFrame* frame) {
StackUnwind(frame->rbp);
if (IsUserSpace(frame->rip)) {
gScheduler->CurrentProcess().Exit();
gScheduler->CurrentProcess().Exit(glcr::INTERNAL);
UNREACHABLE
}
panic("DIV0");
@ -91,7 +91,7 @@ extern "C" void interrupt_invalid_opcode(InterruptFrame* frame) {
StackUnwind(frame->rbp);
if (IsUserSpace(frame->rip)) {
gScheduler->CurrentProcess().Exit();
gScheduler->CurrentProcess().Exit(glcr::INTERNAL);
UNREACHABLE
}
panic("INVALID OPCODE");
@ -117,7 +117,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
StackUnwind(frame->rbp);
if (IsUserSpace(frame->rip)) {
gScheduler->CurrentProcess().Exit();
gScheduler->CurrentProcess().Exit(glcr::INTERNAL);
UNREACHABLE
}
panic("GP");
@ -159,7 +159,7 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) {
StackUnwind(frame->rbp);
if (IsUserSpace(frame->rip)) {
gScheduler->CurrentProcess().Exit();
gScheduler->CurrentProcess().Exit(glcr::INTERNAL);
UNREACHABLE
}
@ -170,7 +170,7 @@ extern "C" void isr_fpe_fault();
extern "C" void interrupt_fpe_fault(InterruptFrame* frame) {
dbgln("Floating point exception.");
if (IsUserSpace(frame->rip)) {
gScheduler->CurrentProcess().Exit();
gScheduler->CurrentProcess().Exit(glcr::INTERNAL);
UNREACHABLE
}
panic("Floating point exception");

View File

@ -59,10 +59,11 @@ uint64_t Process::AddExistingCapability(const glcr::RefPtr<Capability>& cap) {
return caps_.AddExistingCapability(cap);
}
void Process::Exit() {
void Process::Exit(uint64_t exit_code) {
// TODO: Check this state elsewhere to ensure that we don't for instance
// create a running thread on a finished process.
state_ = CLEANUP;
exit_code_ = exit_code;
for (uint64_t i = 0; i < threads_.size(); i++) {
if (!threads_[i]->IsDying()) {

View File

@ -57,10 +57,11 @@ class Process : public KernelObject {
uint64_t AddExistingCapability(const glcr::RefPtr<Capability>& cap);
State GetState() { return state_; }
uint64_t exit_code() { return exit_code_; }
// This stops all of the processes threads (they will no longer be scheduled)
// and flags the process for cleanup.
void Exit();
void Exit(uint64_t code);
// This *should not* be called from a thread that belongs to this process.
// Rather it should be called from the cleanup thread.
@ -76,6 +77,7 @@ class Process : public KernelObject {
uint64_t id_;
glcr::RefPtr<AddressSpace> vmas_;
State state_;
uint64_t exit_code_ = -1;
uint64_t next_thread_id_ = 0;

View File

@ -9,7 +9,7 @@
z_err_t ProcessExit(ZProcessExitReq* req) {
auto curr_thread = gScheduler->CurrentThread();
dbgln("Exit code: {}", static_cast<glcr::ErrorCode>(req->code));
curr_thread->process().Exit();
curr_thread->process().Exit(req->code);
panic("Returned from thread exit");
return glcr::UNIMPLEMENTED;
}
@ -39,3 +39,17 @@ z_err_t ProcessSpawn(ZProcessSpawnReq* req) {
return glcr::OK;
}
z_err_t ProcessWait(ZProcessWaitReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->proc_cap);
RET_ERR(ValidateCapability<Process>(cap, kZionPerm_Read));
auto proc = cap->obj<Process>();
if (proc->id() == curr_proc.id()) {
return glcr::INVALID_ARGUMENT;
}
proc->GetThread(0)->Wait();
*req->exit_code = proc->exit_code();
return glcr::OK;
}

View File

@ -4,3 +4,4 @@
z_err_t ProcessExit(ZProcessExitReq* req);
z_err_t ProcessSpawn(ZProcessSpawnReq* req);
z_err_t ProcessWait(ZProcessWaitReq* req);

View File

@ -53,6 +53,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
// syscall/process.h
CASE(ProcessExit);
CASE(ProcessSpawn);
CASE(ProcessWait);
// syscall/thread.h
CASE(ThreadCreate);
CASE(ThreadStart);