feat(modules): now it loads segments with correct rights, not RWX everywhere
This commit is contained in:
+48
-44
@@ -183,49 +183,10 @@ static efi_status_t load_modules(efi_file_handle_t* root, Bootinfo* boot_info) {
|
||||
Elf64_Ehdr* mod_elf = (Elf64_Ehdr*)module_addr;
|
||||
Elf64_Phdr* phdrs = (Elf64_Phdr*)(module_addr + mod_elf->e_phoff);
|
||||
|
||||
uint64_t min_vaddr = (uint64_t)-1;
|
||||
uint64_t max_vaddr = 0;
|
||||
|
||||
for (int i = 0; i < mod_elf->e_phnum; i++) {
|
||||
if (phdrs[i].p_type == PT_LOAD) {
|
||||
if (phdrs[i].p_vaddr < min_vaddr) min_vaddr = phdrs[i].p_vaddr;
|
||||
uint64_t end = phdrs[i].p_vaddr + phdrs[i].p_memsz;
|
||||
if (end > max_vaddr) max_vaddr = end;
|
||||
}
|
||||
}
|
||||
|
||||
min_vaddr &= ~0xFFFULL;
|
||||
max_vaddr = (max_vaddr + 0xFFFULL) & ~0xFFFULL;
|
||||
uint64_t total_vsize = max_vaddr - min_vaddr;
|
||||
|
||||
uintn_t final_pages = total_vsize / PAGE_SIZE;
|
||||
efi_physical_address_t final_phys = 0;
|
||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, final_pages, &final_phys);
|
||||
|
||||
if (EFI_ERROR(status)) {
|
||||
gBS->FreePages(module_addr, pages);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset((void*)final_phys, 0, total_vsize);
|
||||
|
||||
for (int i = 0; i < mod_elf->e_phnum; i++) {
|
||||
if (phdrs[i].p_type == PT_LOAD && phdrs[i].p_filesz > 0) {
|
||||
void* dest = (void*)(final_phys + (phdrs[i].p_vaddr - min_vaddr));
|
||||
void* src = (void*)(module_addr + phdrs[i].p_offset);
|
||||
|
||||
uint8_t* d = dest;
|
||||
uint8_t* s = src;
|
||||
for (uintn_t j = 0; j < phdrs[i].p_filesz; j++) d[j] = s[j];
|
||||
}
|
||||
}
|
||||
|
||||
BootModule* mod = &boot_info->modules[boot_info->moduleCount];
|
||||
mod->physicalBase = final_phys;
|
||||
mod->virtualBase = min_vaddr;
|
||||
mod->size = total_vsize;
|
||||
mod->entry = (void*)mod_elf->e_entry;
|
||||
mod->capabilities = 0;
|
||||
mod->segmentCount = 0;
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
wchar_t wc = entry->FileName[i];
|
||||
@@ -234,11 +195,54 @@ static efi_status_t load_modules(efi_file_handle_t* root, Bootinfo* boot_info) {
|
||||
}
|
||||
mod->name[31] = '\0';
|
||||
|
||||
print(WSTR(" [MODULE] "));
|
||||
print(entry->FileName);
|
||||
print(WSTR("\r\n"));
|
||||
int alloc_failed = 0;
|
||||
|
||||
boot_info->moduleCount++;
|
||||
for (int i = 0; i < mod_elf->e_phnum && mod->segmentCount < BOOT_MODULE_MAX_SEGMENTS; i++) {
|
||||
if (phdrs[i].p_type != PT_LOAD) continue;
|
||||
|
||||
uint64_t vaddr_page = phdrs[i].p_vaddr & ~0xFFFULL;
|
||||
uint64_t offset_in_page = phdrs[i].p_vaddr & 0xFFFULL;
|
||||
uint64_t total_size = offset_in_page + phdrs[i].p_memsz;
|
||||
uint64_t aligned_size = (total_size + 0xFFFULL) & ~0xFFFULL;
|
||||
uintn_t seg_pages = aligned_size / PAGE_SIZE;
|
||||
|
||||
efi_physical_address_t seg_phys = 0;
|
||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, seg_pages, &seg_phys);
|
||||
if (EFI_ERROR(status)) {
|
||||
alloc_failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
memset((void*)seg_phys, 0, aligned_size);
|
||||
|
||||
if (phdrs[i].p_filesz > 0) {
|
||||
uint8_t* dest = (uint8_t*)(seg_phys + offset_in_page);
|
||||
uint8_t* src = (uint8_t*)(module_addr + phdrs[i].p_offset);
|
||||
for (uintn_t j = 0; j < phdrs[i].p_filesz; j++) dest[j] = src[j];
|
||||
}
|
||||
|
||||
BootModuleSegment* seg = &mod->segments[mod->segmentCount];
|
||||
seg->physicalBase = seg_phys;
|
||||
seg->virtualBase = vaddr_page;
|
||||
seg->size = aligned_size;
|
||||
seg->flags = phdrs[i].p_flags;
|
||||
|
||||
mod->segmentCount++;
|
||||
}
|
||||
|
||||
if (alloc_failed) {
|
||||
for (int i = 0; i < (int)mod->segmentCount; i++) {
|
||||
uint64_t sz = mod->segments[i].size;
|
||||
uintn_t pg = sz / PAGE_SIZE;
|
||||
gBS->FreePages(mod->segments[i].physicalBase, pg);
|
||||
}
|
||||
} else {
|
||||
print(WSTR(" [MODULE] "));
|
||||
print(entry->FileName);
|
||||
print(WSTR("\r\n"));
|
||||
|
||||
boot_info->moduleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
gBS->FreePages(module_addr, pages);
|
||||
|
||||
@@ -32,4 +32,8 @@ typedef struct {
|
||||
uint64_t p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
#define PT_LOAD 1
|
||||
#define PT_LOAD 1
|
||||
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
+15
-1
@@ -27,13 +27,27 @@ typedef struct {
|
||||
void* kernelAddress;
|
||||
} BIKernelInfo;
|
||||
|
||||
#define BOOT_MODULE_MAX_SEGMENTS 8
|
||||
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
|
||||
typedef struct {
|
||||
BIUInt64 physicalBase;
|
||||
BIUInt64 virtualBase;
|
||||
void* entry;
|
||||
BIUInt64 size;
|
||||
BIUInt32 flags;
|
||||
BIUInt32 reserved;
|
||||
} BootModuleSegment;
|
||||
|
||||
typedef struct {
|
||||
void* entry;
|
||||
char name[32];
|
||||
BIUInt64 capabilities;
|
||||
BIUInt32 segmentCount;
|
||||
BIUInt32 reserved;
|
||||
BootModuleSegment segments[BOOT_MODULE_MAX_SEGMENTS];
|
||||
} BootModule;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -45,3 +45,4 @@ void SchedulerInitialize();
|
||||
OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress);
|
||||
Address SchedulerNext(Address stackPointer);
|
||||
void SchedulerYield(UInt64 ticks);
|
||||
UInt64 SchedulerGetNextProcessID();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
void ModuleLoad(BootModule* module) {
|
||||
OSProcess* userProc = HeapAllocate(sizeof(OSProcess));
|
||||
MemorySet(userProc, 0, sizeof(OSProcess));
|
||||
userProc->id = 1; // TODO: id gen
|
||||
userProc->id = SchedulerGetNextProcessID();
|
||||
userProc->state = OSTaskStateRunning;
|
||||
StringCopy(userProc->name, module->name);
|
||||
|
||||
@@ -19,18 +19,33 @@ void ModuleLoad(BootModule* module) {
|
||||
MemorySet(userL0Virt, 0, kVMPageSize);
|
||||
userProc->l0Table = userL0Virt;
|
||||
|
||||
Address physBase = module->physicalBase;
|
||||
Address virtBase = module->virtualBase;
|
||||
Size modSize = module->size;
|
||||
for (BIUInt32 s = 0; s < module->segmentCount; s++) {
|
||||
BootModuleSegment* seg = &module->segments[s];
|
||||
|
||||
UInt64 codeFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX; // TODO: kill RWX
|
||||
UInt64 segFlags = kPTENormalMem | kPTEUser;
|
||||
|
||||
for (Size i = 0; i < modSize; i += kVMPageSize) {
|
||||
VMMMapPage((Address*)userL0Phys, physBase + i, virtBase + i, codeFlags);
|
||||
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);
|
||||
}
|
||||
|
||||
CPUCleanAndInvalidateCode((void*)VMPhysToHHDM(physBase), modSize);
|
||||
|
||||
Address stackPhys = (Address)PMMAllocatePage();
|
||||
Address userStackVirt = 0x80000000;
|
||||
UInt64 stackFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX | kPTEUserNX;
|
||||
|
||||
@@ -122,3 +122,7 @@ void SchedulerYield(UInt64 ticks) {
|
||||
gOSSchedulerCurrentTask->state = OSTaskStateSleeping;
|
||||
CPUException(kOSSchedulerExceptionNumber);
|
||||
}
|
||||
|
||||
UInt64 SchedulerGetNextProcessID() {
|
||||
return gOSSchedulerNextProcessID++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user