wip: IPC and Runtime
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// Copyright (c) 2026 0xKSor
|
||||
|
||||
#pragma once
|
||||
#include "Arch/Exceptions.h"
|
||||
#include <Types.h>
|
||||
|
||||
static inline void CPUYield() {
|
||||
@@ -63,7 +64,7 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) {
|
||||
// MAIR_EL1 (Memory Attribute Indirection Register)
|
||||
// kPTENormalMem is index 0 and kPTEDeviceMem is index 1
|
||||
// 0xFF = Normal, 0x00 = Device
|
||||
UInt64 mair = (0xFFULL << 0) | (0x00ULL << 8);
|
||||
UInt64 mair = (0xFFULL << 0) | (0x00ULL << 8);
|
||||
|
||||
// TCR_EL1 (Translation Control Register)
|
||||
// configures the mmu for 4kb pages and 48bit virtual addresses
|
||||
@@ -82,11 +83,11 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) {
|
||||
"msr tcr_el1, %1\n"
|
||||
"msr ttbr0_el1, %2\n" // set userspace root
|
||||
"msr ttbr1_el1, %2\n" // set kernelspace root
|
||||
"tlbi vmalle1is\n"
|
||||
"tlbi vmalle1is\n"
|
||||
"isb\n" // Instruction Synchronization Barrier
|
||||
:: "r"(mair), "r"(tcr), "r"(l0PhysicalAddress) : "memory"
|
||||
);
|
||||
|
||||
|
||||
// turn on the MMU in SCTLR_EL1 (System Control Register)
|
||||
// Bit 0 = M (MMU Enable), Bit 2 = C (Data Cache Enable), Bit 12 = I (Instruction Cache Enable)
|
||||
UInt64 sctlr;
|
||||
@@ -111,4 +112,13 @@ static inline void CPUSwitchAddressSpace(Address l0Physical) {
|
||||
);
|
||||
}
|
||||
|
||||
#define CPUException(number) __asm__ volatile ("svc %0" :: "i" (number) : "memory")
|
||||
static inline void CPUCopyIPCRegisters(ExceptionsContext* source, ExceptionsContext* destination) {
|
||||
destination->x2 = source->x2;
|
||||
destination->x3 = source->x3;
|
||||
destination->x4 = source->x4;
|
||||
destination->x5 = source->x5;
|
||||
destination->x6 = source->x6;
|
||||
destination->x7 = source->x7;
|
||||
}
|
||||
|
||||
#define CPUException(number) __asm__ volatile ("svc %0" :: "i" (number) : "memory")
|
||||
|
||||
@@ -14,4 +14,4 @@ static inline UInt32 IOAddressRead32(Address address) {
|
||||
UInt32 value = *(volatile UInt32*)address;
|
||||
__asm__ volatile ("dsb ld" ::: "memory"); // wait till my read is finished physically
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "Arch/Exceptions.h"
|
||||
#include <Types.h>
|
||||
#include <OS/Scheduler.h>
|
||||
|
||||
UInt64 IPCSend(OSTask* sender, UInt64 handleID, UInt64 data);
|
||||
void IPCReceive(ExceptionsContext* receiverFrame);
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <Types.h>
|
||||
#include "../Common/bootinfo.h"
|
||||
#include <OS/Scheduler.h>
|
||||
|
||||
void ModuleLoad(BootModule* module);
|
||||
OSTask* ModuleLoad(BootModule* module);
|
||||
|
||||
@@ -4,12 +4,31 @@
|
||||
#pragma once
|
||||
#include <Types.h>
|
||||
|
||||
typedef enum {
|
||||
kOSHandleTypeNone = 0,
|
||||
kOSHandleTypeTask
|
||||
} OSHandleType;
|
||||
|
||||
typedef struct {
|
||||
OSHandleType type;
|
||||
Pointer object;
|
||||
} OSHandle;
|
||||
|
||||
enum {
|
||||
kOSSchedulerTaskStackSize = 16 * 1024,
|
||||
kOSSchedulerExceptionNumber = 0xF0F0,
|
||||
kOSMaxHandlesPerProcess = 256,
|
||||
};
|
||||
|
||||
typedef enum OSTaskState {
|
||||
OSTaskStateDead,
|
||||
OSTaskStateRunning,
|
||||
OSTaskStateReady,
|
||||
OSTaskStateBlocked,
|
||||
OSTaskStateSleeping,
|
||||
|
||||
OSTaskStateBlockedReceive,
|
||||
OSTaskStateBlockedSend,
|
||||
} OSTaskState;
|
||||
|
||||
typedef struct OSProcess {
|
||||
@@ -20,11 +39,12 @@ typedef struct OSProcess {
|
||||
Address heapCurrent;
|
||||
struct OSProcess* parent;
|
||||
ASCII name[32];
|
||||
|
||||
OSHandle handles[kOSMaxHandlesPerProcess];
|
||||
} OSProcess;
|
||||
|
||||
typedef struct OSTask {
|
||||
Address stackPointer;
|
||||
struct OSTask* next;
|
||||
UInt32 id;
|
||||
UInt32 sleepTicks;
|
||||
OSTaskState state;
|
||||
@@ -32,12 +52,10 @@ typedef struct OSTask {
|
||||
Pointer kernelStackBase;
|
||||
OSProcess* process;
|
||||
Int32 waitingForProcessId;
|
||||
} OSTask;
|
||||
|
||||
enum {
|
||||
kOSSchedulerTaskStackSize = 16 * 1024,
|
||||
kOSSchedulerExceptionNumber = 0xF0F0
|
||||
};
|
||||
struct OSTask* next;
|
||||
struct OSTask* senderWaiting;
|
||||
} OSTask;
|
||||
|
||||
extern UInt32 gOSSchedulerNextProcessID;
|
||||
|
||||
@@ -46,3 +64,7 @@ OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Ad
|
||||
Address SchedulerNext(Address stackPointer);
|
||||
void SchedulerYield(UInt64 ticks);
|
||||
UInt64 SchedulerGetNextProcessID();
|
||||
void SchedulerBlockCurrentTask(UInt32 newState);
|
||||
OSTask* SchedulerGetCurrentTask();
|
||||
Int32 SchedulerProcessAllocateHandle(OSProcess* process, OSHandleType type, Pointer object);
|
||||
Pointer SchedulerProcessGetHandle(OSProcess* process, UInt32 handleId, OSHandleType expectedType);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <Types.h>
|
||||
#include <Arch/Exceptions.h>
|
||||
|
||||
enum Syscalls {
|
||||
kSyscallSend,
|
||||
kSyscallReceive,
|
||||
};
|
||||
|
||||
Address SyscallDispatch(ExceptionsContext* frame);
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Arch/GIC.h>
|
||||
#include <OS/Panic.h>
|
||||
#include <OS/Scheduler.h>
|
||||
#include <OS/Syscall.h>
|
||||
|
||||
Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
||||
if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(frame, type);
|
||||
@@ -13,14 +14,9 @@ Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
||||
UInt32 class = (esr >> 26) & 0x3F;
|
||||
UInt32 syndrome = esr & 0x1FFFFFF;
|
||||
|
||||
if (class == 0x11 || class == 0x15) {
|
||||
if (syndrome == kOSSchedulerExceptionNumber) {
|
||||
return SchedulerNext((Address)frame);
|
||||
}
|
||||
}
|
||||
|
||||
if (class == 0x15 && syndrome == 0) {
|
||||
OSPanic("Hi from userspace!!");
|
||||
if (class == 0x15) {
|
||||
if (syndrome == kOSSchedulerExceptionNumber) return SchedulerNext((Address)frame);
|
||||
if (syndrome == 0) return SyscallDispatch(frame);
|
||||
}
|
||||
}
|
||||
OSPanicException(frame);
|
||||
|
||||
@@ -40,8 +40,7 @@ void KernelMain(Bootinfo* bootinfo) {
|
||||
SchedulerInitialize();
|
||||
|
||||
for (UInt32 i = 0; i < bootinfo->moduleCount; i++) {
|
||||
ModuleLoad(&bootinfo->modules[i]); // TODO: make some sort of priority of loading modules
|
||||
// like init first then uart then fb ...
|
||||
ModuleLoad(&bootinfo->modules[i]); // TODO: priority
|
||||
}
|
||||
|
||||
OSLog("Kernel initialized.\n");
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <OS/IPC.h>
|
||||
#include <OS/Scheduler.h>
|
||||
#include <Arch/CPU.h>
|
||||
#include <Arch/Exceptions.h>
|
||||
|
||||
UInt64 IPCSend(OSTask* sender, UInt64 handleID, UInt64 data) {
|
||||
if (handleID == 0) return -1;
|
||||
OSProcess* currentProcess = sender->process;
|
||||
OSTask* targetTask = (OSTask*)SchedulerProcessGetHandle(currentProcess, handleID, kOSHandleTypeTask);
|
||||
if (!targetTask) return -1;
|
||||
|
||||
if (targetTask->state == OSTaskStateBlockedReceive) {
|
||||
ExceptionsContext* receiverContext = (ExceptionsContext*)targetTask->stackPointer;
|
||||
receiverContext->x1 = data;
|
||||
receiverContext->x0 = currentProcess->id;
|
||||
|
||||
targetTask->state = OSTaskStateRunning;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (targetTask->senderWaiting != nullptr) return -2;
|
||||
|
||||
targetTask->senderWaiting = sender;
|
||||
|
||||
SchedulerBlockCurrentTask(OSTaskStateBlockedSend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IPCReceive(ExceptionsContext* receiverFrame) {
|
||||
OSTask* receiver = SchedulerGetCurrentTask();
|
||||
|
||||
if (receiver->senderWaiting != nullptr) {
|
||||
OSTask* sender = receiver->senderWaiting;
|
||||
|
||||
ExceptionsContext* senderContext = (ExceptionsContext*)sender->stackPointer;
|
||||
|
||||
receiverFrame->x1 = senderContext->x1; // Data
|
||||
receiverFrame->x0 = sender->process->id; // Sender ID
|
||||
|
||||
receiver->senderWaiting = nullptr;
|
||||
sender->state = OSTaskStateRunning;
|
||||
return;
|
||||
}
|
||||
|
||||
SchedulerBlockCurrentTask(OSTaskStateBlockedReceive);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <Arch/CPU.h>
|
||||
#include "../Common/bootinfo.h"
|
||||
|
||||
void ModuleLoad(BootModule* module) {
|
||||
OSTask* ModuleLoad(BootModule* module) {
|
||||
OSProcess* userProc = HeapAllocate(sizeof(OSProcess));
|
||||
MemorySet(userProc, 0, sizeof(OSProcess));
|
||||
userProc->id = SchedulerGetNextProcessID();
|
||||
@@ -56,8 +56,8 @@ void ModuleLoad(BootModule* module) {
|
||||
|
||||
if ((Address)userEntryPoint == 0x0) {
|
||||
OSLog("Skipping module %s: entry point is 0x0.\n", module->name);
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SchedulerSpawn(userEntryPoint, userProc, true, userStackVirt + kVMPageSize);
|
||||
return SchedulerSpawn(userEntryPoint, userProc, true, userStackVirt + kVMPageSize);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Ad
|
||||
task->waitingForProcessId = -1;
|
||||
|
||||
task->next = gOSSchedulerCurrentTask->next;
|
||||
task->senderWaiting = nullptr;
|
||||
gOSSchedulerCurrentTask->next = task;
|
||||
|
||||
return task;
|
||||
@@ -126,3 +127,30 @@ void SchedulerYield(UInt64 ticks) {
|
||||
UInt64 SchedulerGetNextProcessID() {
|
||||
return gOSSchedulerNextProcessID++;
|
||||
}
|
||||
|
||||
void SchedulerBlockCurrentTask(UInt32 newState) {
|
||||
gOSSchedulerCurrentTask->state = newState;
|
||||
CPUException(kOSSchedulerExceptionNumber);
|
||||
}
|
||||
|
||||
OSTask* SchedulerGetCurrentTask() {
|
||||
return gOSSchedulerCurrentTask;
|
||||
}
|
||||
|
||||
Int32 SchedulerProcessAllocateHandle(OSProcess* process, OSHandleType type, Pointer object) {
|
||||
for (Int32 i = 1; i < kOSMaxHandlesPerProcess; i++) {
|
||||
if (process->handles[i].type == kOSHandleTypeNone) {
|
||||
process->handles[i].type = type;
|
||||
process->handles[i].object = object;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Pointer SchedulerProcessGetHandle(OSProcess* process, UInt32 handleId, OSHandleType expectedType) {
|
||||
if (handleId == 0 || handleId >= kOSMaxHandlesPerProcess) return nullptr;
|
||||
OSHandle* handle = &process->handles[handleId];
|
||||
if (handle->type != expectedType) return nullptr;
|
||||
return handle->object;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <OS/Syscall.h>
|
||||
#include <OS/IPC.h>
|
||||
#include <OS/Scheduler.h>
|
||||
#include <OS/Panic.h>
|
||||
#include <Arch/Exceptions.h>
|
||||
|
||||
Address SyscallDispatch(ExceptionsContext* frame) {
|
||||
UInt64 syscallNumber = frame->x8;
|
||||
OSTask* current = SchedulerGetCurrentTask();
|
||||
|
||||
switch (syscallNumber) {
|
||||
case kSyscallSend:
|
||||
frame->x0 = IPCSend(current, frame->x0, frame->x1);
|
||||
break;
|
||||
case kSyscallReceive:
|
||||
IPCReceive(frame);
|
||||
break;
|
||||
default:
|
||||
frame->x0 = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (current->state != OSTaskStateRunning) return SchedulerNext((Address)frame);
|
||||
return (Address)frame;
|
||||
}
|
||||
Reference in New Issue
Block a user