64 lines
2.0 KiB
C
64 lines
2.0 KiB
C
#include <OS/Modules.h>
|
|
#include <OS/Scheduler.h>
|
|
#include <OS/Log.h>
|
|
#include <VM/Heap.h>
|
|
#include <VM/VMM.h>
|
|
#include <Lib/String.h>
|
|
#include <Arch/CPU.h>
|
|
#include "../Common/bootinfo.h"
|
|
|
|
OSTask* ModuleLoad(BootModule* module) {
|
|
OSProcess* userProc = HeapAllocate(sizeof(OSProcess));
|
|
MemorySet(userProc, 0, sizeof(OSProcess));
|
|
userProc->id = SchedulerGetNextProcessID();
|
|
userProc->state = OSTaskStateRunning;
|
|
StringCopy(userProc->name, module->name);
|
|
|
|
Address userL0Phys = (Address)PMMAllocatePage();
|
|
Address* userL0Virt = (Address*)VMPhysToHHDM(userL0Phys);
|
|
MemorySet(userL0Virt, 0, kVMPageSize);
|
|
userProc->l0Table = userL0Virt;
|
|
|
|
for (BIUInt32 s = 0; s < module->segmentCount; s++) {
|
|
BootModuleSegment* seg = &module->segments[s];
|
|
|
|
UInt64 segFlags = kPTENormalMem | kPTEUser;
|
|
|
|
if (seg->flags & PF_W) {
|
|
// writable: AP[2]=0 (RW), which is the default
|
|
} else {
|
|
segFlags |= kPTEAccessRO;
|
|
}
|
|
|
|
if (seg->flags & PF_X) {
|
|
// executable: default is already executable
|
|
} else {
|
|
segFlags |= kPTEPrivNX | kPTEUserNX;
|
|
}
|
|
|
|
for (Size i = 0; i < seg->size; i += kVMPageSize) {
|
|
VMMMapPage((Address*)userL0Phys,
|
|
seg->physicalBase + i,
|
|
seg->virtualBase + i,
|
|
segFlags);
|
|
}
|
|
|
|
CPUCleanAndInvalidateCode((void*)VMPhysToHHDM(seg->physicalBase), seg->size);
|
|
}
|
|
|
|
Address stackPhys = (Address)PMMAllocatePage();
|
|
Address userStackVirt = 0x80000000;
|
|
UInt64 stackFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX | kPTEUserNX;
|
|
|
|
VMMMapPage((Address*)userL0Phys, stackPhys, userStackVirt, stackFlags);
|
|
|
|
void (*userEntryPoint)() = (void(*)())module->entry;
|
|
|
|
if ((Address)userEntryPoint == 0x0) {
|
|
OSLog("Skipping module %s: entry point is 0x0.\n", module->name);
|
|
return nullptr;
|
|
}
|
|
|
|
return SchedulerSpawn(userEntryPoint, userProc, true, userStackVirt + kVMPageSize);
|
|
}
|