feat: implement new IPC layer
This commit is contained in:
@@ -52,15 +52,15 @@ namespace Sched {
|
||||
}
|
||||
|
||||
uint64_t ElfLoad(const char* vfsPath, uint64_t pml4Phys) {
|
||||
int handle = Fs::Vfs::VfsOpen(vfsPath);
|
||||
if (handle < 0) {
|
||||
Fs::Vfs::BackendFile file = {-1, -1};
|
||||
if (Fs::Vfs::OpenBackendFile(vfsPath, file) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t fileSize = Fs::Vfs::VfsGetSize(handle);
|
||||
uint64_t fileSize = Fs::Vfs::GetBackendFileSize(file);
|
||||
if (fileSize < sizeof(Elf64Header)) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "ELF") << "File too small (" << fileSize << " bytes)";
|
||||
Fs::Vfs::VfsClose(handle);
|
||||
Fs::Vfs::CloseBackendFile(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -68,12 +68,12 @@ namespace Sched {
|
||||
uint8_t* fileData = (uint8_t*)Memory::g_heap->Request(fileSize);
|
||||
if (fileData == nullptr) {
|
||||
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Failed to allocate " << fileSize << " bytes for file";
|
||||
Fs::Vfs::VfsClose(handle);
|
||||
Fs::Vfs::CloseBackendFile(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Fs::Vfs::VfsRead(handle, fileData, 0, fileSize);
|
||||
Fs::Vfs::VfsClose(handle);
|
||||
Fs::Vfs::ReadBackendFile(file, fileData, 0, fileSize);
|
||||
Fs::Vfs::CloseBackendFile(file);
|
||||
|
||||
// Prevent the optimizer from reordering the VfsRead store past the
|
||||
// header validation reads that follow.
|
||||
|
||||
+142
-76
@@ -18,6 +18,7 @@
|
||||
#include <Hal/SmpBoot.hpp>
|
||||
#include <Timekeeping/ApicTimer.hpp>
|
||||
#include <Api/WinServer.hpp>
|
||||
#include <Ipc/Ipc.hpp>
|
||||
|
||||
// Assembly: context switch with CR3 and FPU state parameters
|
||||
extern "C" void SchedContextSwitch(uint64_t* oldRsp, uint64_t newRsp, uint64_t newCR3,
|
||||
@@ -47,6 +48,45 @@ namespace Sched {
|
||||
return (uint64_t)Memory::VMM::g_paging->PML4;
|
||||
}
|
||||
|
||||
static void SwitchAwayFromBlockedCurrentLocked() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) {
|
||||
schedLock.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
int next = -1;
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Ready) {
|
||||
next = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next >= 0) {
|
||||
cpu->currentSlot = next;
|
||||
processTable[next].state = ProcessState::Running;
|
||||
readyCount--;
|
||||
processTable[next].runningOnCpu = cpu->cpuIndex;
|
||||
processTable[next].sliceRemaining = TimeSliceMs;
|
||||
|
||||
cpu->kernelRsp = processTable[next].kernelStackTop;
|
||||
cpu->tss->rsp0 = processTable[next].kernelStackTop;
|
||||
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
|
||||
processTable[next].pml4Phys,
|
||||
processTable[slot].fpuState, processTable[next].fpuState);
|
||||
schedLock.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
cpu->currentSlot = -1;
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
|
||||
GetKernelCR3(), processTable[slot].fpuState, nullptr);
|
||||
schedLock.Release();
|
||||
}
|
||||
|
||||
// Startup function for newly spawned processes.
|
||||
// SchedContextSwitch "returns" here on first schedule.
|
||||
// The schedLock is held (acquired by the switching-from CPU's Schedule).
|
||||
@@ -97,6 +137,7 @@ namespace Sched {
|
||||
processTable[i].killPending = false;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].redirected = false;
|
||||
processTable[i].parentPid = -1;
|
||||
processTable[i].outBuf = nullptr;
|
||||
@@ -109,6 +150,10 @@ namespace Sched {
|
||||
processTable[i].keyTail = 0;
|
||||
processTable[i].termCols = 0;
|
||||
processTable[i].termRows = 0;
|
||||
processTable[i].ioOutHandle = -1;
|
||||
processTable[i].ioInHandle = -1;
|
||||
processTable[i].ioKeyHandle = -1;
|
||||
processTable[i].ioWaitsetHandle = -1;
|
||||
}
|
||||
|
||||
nextPid = 0;
|
||||
@@ -276,6 +321,7 @@ namespace Sched {
|
||||
proc.killPending = false;
|
||||
proc.waitingForPid = -1;
|
||||
proc.sleepUntilTick = 0;
|
||||
proc.waitingOnObject = nullptr;
|
||||
|
||||
// Copy arguments string into process
|
||||
proc.args[0] = '\0';
|
||||
@@ -333,12 +379,18 @@ namespace Sched {
|
||||
proc.keyTail = 0;
|
||||
proc.termCols = 0;
|
||||
proc.termRows = 0;
|
||||
proc.ioOutHandle = -1;
|
||||
proc.ioInHandle = -1;
|
||||
proc.ioKeyHandle = -1;
|
||||
proc.ioWaitsetHandle = -1;
|
||||
|
||||
// Initialize FPU state: zero out, then set default FCW and MXCSR
|
||||
memset(proc.fpuState, 0, 512);
|
||||
*(uint16_t*)&proc.fpuState[0] = 0x037F; // FCW: default x87 control word
|
||||
*(uint32_t*)&proc.fpuState[24] = 0x1F80; // MXCSR: default SSE control/status
|
||||
|
||||
Ipc::ProcessStartedInSlot(slot, proc.pid);
|
||||
|
||||
int resultPid = proc.pid;
|
||||
schedLock.Release();
|
||||
|
||||
@@ -486,6 +538,8 @@ namespace Sched {
|
||||
processTable[i].sleepUntilTick != 0 &&
|
||||
now >= processTable[i].sleepUntilTick) {
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
}
|
||||
@@ -554,15 +608,30 @@ namespace Sched {
|
||||
// Clean up any windows owned by this process
|
||||
WinServer::CleanupProcess(exitingPid);
|
||||
|
||||
// Free I/O redirect buffers
|
||||
if (proc.outBuf) {
|
||||
Memory::g_pfa->Free(proc.outBuf);
|
||||
proc.outBuf = nullptr;
|
||||
}
|
||||
if (proc.inBuf) {
|
||||
Memory::g_pfa->Free(proc.inBuf);
|
||||
proc.inBuf = nullptr;
|
||||
}
|
||||
// Release process-scoped IPC handles/mappings before tearing down the address space.
|
||||
Ipc::CleanupProcessSlot(slot, exitingPid, proc.pml4Phys);
|
||||
|
||||
proc.waitingForPid = -1;
|
||||
proc.sleepUntilTick = 0;
|
||||
proc.waitingOnObject = nullptr;
|
||||
proc.redirected = false;
|
||||
proc.parentPid = -1;
|
||||
proc.outBuf = nullptr;
|
||||
proc.outHead = 0;
|
||||
proc.outTail = 0;
|
||||
proc.inBuf = nullptr;
|
||||
proc.inHead = 0;
|
||||
proc.inTail = 0;
|
||||
proc.keyHead = 0;
|
||||
proc.keyTail = 0;
|
||||
proc.termCols = 0;
|
||||
proc.termRows = 0;
|
||||
proc.ioOutHandle = -1;
|
||||
proc.ioInHandle = -1;
|
||||
proc.ioKeyHandle = -1;
|
||||
proc.ioWaitsetHandle = -1;
|
||||
|
||||
Ipc::ProcessExitedInSlot(slot, exitingPid);
|
||||
|
||||
// Free all user-space physical pages and page table structures
|
||||
Memory::VMM::Paging::FreeUserHalf(proc.pml4Phys);
|
||||
@@ -579,6 +648,8 @@ namespace Sched {
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,6 +735,9 @@ namespace Sched {
|
||||
readyCount--;
|
||||
proc.state = ProcessState::Terminated;
|
||||
proc.killPending = false;
|
||||
proc.waitingForPid = -1;
|
||||
proc.sleepUntilTick = 0;
|
||||
proc.waitingOnObject = nullptr;
|
||||
|
||||
// Wake any processes blocked on this PID
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
@@ -672,6 +746,8 @@ namespace Sched {
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,15 +755,26 @@ namespace Sched {
|
||||
|
||||
// Safe to clean up resources now -- process is not running anywhere.
|
||||
WinServer::CleanupProcess(killedPid);
|
||||
Ipc::CleanupProcessSlot(slot, killedPid, proc.pml4Phys);
|
||||
|
||||
if (proc.outBuf) {
|
||||
Memory::g_pfa->Free(proc.outBuf);
|
||||
proc.outBuf = nullptr;
|
||||
}
|
||||
if (proc.inBuf) {
|
||||
Memory::g_pfa->Free(proc.inBuf);
|
||||
proc.inBuf = nullptr;
|
||||
}
|
||||
proc.redirected = false;
|
||||
proc.parentPid = -1;
|
||||
proc.outBuf = nullptr;
|
||||
proc.outHead = 0;
|
||||
proc.outTail = 0;
|
||||
proc.inBuf = nullptr;
|
||||
proc.inHead = 0;
|
||||
proc.inTail = 0;
|
||||
proc.keyHead = 0;
|
||||
proc.keyTail = 0;
|
||||
proc.termCols = 0;
|
||||
proc.termRows = 0;
|
||||
proc.ioOutHandle = -1;
|
||||
proc.ioInHandle = -1;
|
||||
proc.ioKeyHandle = -1;
|
||||
proc.ioWaitsetHandle = -1;
|
||||
|
||||
Ipc::ProcessExitedInSlot(slot, killedPid);
|
||||
|
||||
Memory::VMM::Paging::FreeUserHalf(proc.pml4Phys);
|
||||
|
||||
@@ -727,39 +814,10 @@ namespace Sched {
|
||||
// ExitProcess will wake us when the target terminates.
|
||||
processTable[slot].state = ProcessState::Blocked;
|
||||
processTable[slot].waitingForPid = pid;
|
||||
processTable[slot].waitingOnObject = nullptr;
|
||||
processTable[slot].sleepUntilTick = 0;
|
||||
processTable[slot].runningOnCpu = -1;
|
||||
|
||||
// Find next ready process to switch to
|
||||
int next = -1;
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Ready) {
|
||||
next = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next >= 0) {
|
||||
cpu->currentSlot = next;
|
||||
processTable[next].state = ProcessState::Running;
|
||||
readyCount--;
|
||||
processTable[next].runningOnCpu = cpu->cpuIndex;
|
||||
processTable[next].sliceRemaining = TimeSliceMs;
|
||||
|
||||
cpu->kernelRsp = processTable[next].kernelStackTop;
|
||||
cpu->tss->rsp0 = processTable[next].kernelStackTop;
|
||||
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
|
||||
processTable[next].pml4Phys,
|
||||
processTable[slot].fpuState, processTable[next].fpuState);
|
||||
schedLock.Release();
|
||||
} else {
|
||||
// No ready process -- go idle
|
||||
cpu->currentSlot = -1;
|
||||
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
|
||||
GetKernelCR3(), processTable[slot].fpuState, nullptr);
|
||||
schedLock.Release();
|
||||
}
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
}
|
||||
|
||||
void BlockForSleep(uint64_t ms) {
|
||||
@@ -772,38 +830,46 @@ namespace Sched {
|
||||
schedLock.Acquire();
|
||||
|
||||
processTable[slot].state = ProcessState::Blocked;
|
||||
processTable[slot].waitingForPid = -1;
|
||||
processTable[slot].waitingOnObject = nullptr;
|
||||
processTable[slot].sleepUntilTick = Timekeeping::GetTicks() + ms;
|
||||
processTable[slot].runningOnCpu = -1;
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
}
|
||||
|
||||
int next = -1;
|
||||
void BlockOnObject(void* object, uint64_t timeoutMs) {
|
||||
if (object == nullptr) return;
|
||||
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) return;
|
||||
|
||||
schedLock.Acquire();
|
||||
processTable[slot].state = ProcessState::Blocked;
|
||||
processTable[slot].waitingForPid = -1;
|
||||
processTable[slot].waitingOnObject = object;
|
||||
processTable[slot].sleepUntilTick = (timeoutMs > 0)
|
||||
? (Timekeeping::GetTicks() + timeoutMs)
|
||||
: 0;
|
||||
processTable[slot].runningOnCpu = -1;
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
}
|
||||
|
||||
void WakeObjectWaiters(void* object) {
|
||||
if (object == nullptr) return;
|
||||
|
||||
schedLock.Acquire();
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Ready) {
|
||||
next = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next >= 0) {
|
||||
cpu->currentSlot = next;
|
||||
processTable[next].state = ProcessState::Running;
|
||||
readyCount--;
|
||||
processTable[next].runningOnCpu = cpu->cpuIndex;
|
||||
processTable[next].sliceRemaining = TimeSliceMs;
|
||||
|
||||
cpu->kernelRsp = processTable[next].kernelStackTop;
|
||||
cpu->tss->rsp0 = processTable[next].kernelStackTop;
|
||||
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
|
||||
processTable[next].pml4Phys,
|
||||
processTable[slot].fpuState, processTable[next].fpuState);
|
||||
schedLock.Release();
|
||||
} else {
|
||||
cpu->currentSlot = -1;
|
||||
|
||||
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
|
||||
GetKernelCR3(), processTable[slot].fpuState, nullptr);
|
||||
schedLock.Release();
|
||||
if (processTable[i].state != ProcessState::Blocked) continue;
|
||||
if (processTable[i].waitingOnObject != object) continue;
|
||||
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
}
|
||||
schedLock.Release();
|
||||
}
|
||||
|
||||
bool IsAlive(int pid) {
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace Sched {
|
||||
int pid;
|
||||
ProcessState state;
|
||||
int waitingForPid; // PID this process is blocked on (-1 if none)
|
||||
uint64_t sleepUntilTick; // Tick deadline for SYS_SLEEP_MS (0 = not sleeping)
|
||||
uint64_t sleepUntilTick; // Tick deadline for sleep/object wait timeout (0 = none)
|
||||
void* waitingOnObject; // IPC/scheduler object this process is blocked on (nullptr if none)
|
||||
char name[64];
|
||||
uint64_t savedRsp;
|
||||
uint64_t stackBase; // Bottom of allocated kernel stack (lowest address)
|
||||
@@ -71,6 +72,12 @@ namespace Sched {
|
||||
int termCols = 0;
|
||||
int termRows = 0;
|
||||
|
||||
// IPC-backed redirected terminal channels
|
||||
int ioOutHandle = -1;
|
||||
int ioInHandle = -1;
|
||||
int ioKeyHandle = -1;
|
||||
int ioWaitsetHandle = -1;
|
||||
|
||||
// FPU/SSE state (FXSAVE format, must be 16-byte aligned)
|
||||
uint8_t fpuState[512] __attribute__((aligned(16)));
|
||||
};
|
||||
@@ -100,6 +107,13 @@ namespace Sched {
|
||||
// Block the current process for the given number of milliseconds.
|
||||
void BlockForSleep(uint64_t ms);
|
||||
|
||||
// Block the current process until the given object is signaled or timed out.
|
||||
// timeoutMs == 0 means wait indefinitely.
|
||||
void BlockOnObject(void* object, uint64_t timeoutMs = 0);
|
||||
|
||||
// Wake any processes blocked on the given object.
|
||||
void WakeObjectWaiters(void* object);
|
||||
|
||||
// Kill a process by PID. If the process is running on another CPU,
|
||||
// sets a kill-pending flag checked on the next timer tick.
|
||||
// Returns 0 on success, -1 on failure.
|
||||
|
||||
Reference in New Issue
Block a user