feat(modules): now it loads segments with correct rights, not RWX everywhere

This commit is contained in:
karina
2026-05-03 18:30:49 +04:00
parent bedb03fc37
commit fb55cb1b9a
6 changed files with 97 additions and 55 deletions
+48 -44
View File
@@ -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_Ehdr* mod_elf = (Elf64_Ehdr*)module_addr;
Elf64_Phdr* phdrs = (Elf64_Phdr*)(module_addr + mod_elf->e_phoff); 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]; 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->entry = (void*)mod_elf->e_entry;
mod->capabilities = 0; mod->capabilities = 0;
mod->segmentCount = 0;
for (int i = 0; i < 31; i++) { for (int i = 0; i < 31; i++) {
wchar_t wc = entry->FileName[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'; mod->name[31] = '\0';
print(WSTR(" [MODULE] ")); int alloc_failed = 0;
print(entry->FileName);
print(WSTR("\r\n"));
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); gBS->FreePages(module_addr, pages);
+5 -1
View File
@@ -32,4 +32,8 @@ typedef struct {
uint64_t p_align; uint64_t p_align;
} Elf64_Phdr; } Elf64_Phdr;
#define PT_LOAD 1 #define PT_LOAD 1
#define PF_X 1
#define PF_W 2
#define PF_R 4
+15 -1
View File
@@ -27,13 +27,27 @@ typedef struct {
void* kernelAddress; void* kernelAddress;
} BIKernelInfo; } BIKernelInfo;
#define BOOT_MODULE_MAX_SEGMENTS 8
#define PF_X 1
#define PF_W 2
#define PF_R 4
typedef struct { typedef struct {
BIUInt64 physicalBase; BIUInt64 physicalBase;
BIUInt64 virtualBase; BIUInt64 virtualBase;
void* entry;
BIUInt64 size; BIUInt64 size;
BIUInt32 flags;
BIUInt32 reserved;
} BootModuleSegment;
typedef struct {
void* entry;
char name[32]; char name[32];
BIUInt64 capabilities; BIUInt64 capabilities;
BIUInt32 segmentCount;
BIUInt32 reserved;
BootModuleSegment segments[BOOT_MODULE_MAX_SEGMENTS];
} BootModule; } BootModule;
typedef struct { typedef struct {
+1
View File
@@ -45,3 +45,4 @@ void SchedulerInitialize();
OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress); OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress);
Address SchedulerNext(Address stackPointer); Address SchedulerNext(Address stackPointer);
void SchedulerYield(UInt64 ticks); void SchedulerYield(UInt64 ticks);
UInt64 SchedulerGetNextProcessID();
+24 -9
View File
@@ -10,7 +10,7 @@
void ModuleLoad(BootModule* module) { void ModuleLoad(BootModule* module) {
OSProcess* userProc = HeapAllocate(sizeof(OSProcess)); OSProcess* userProc = HeapAllocate(sizeof(OSProcess));
MemorySet(userProc, 0, sizeof(OSProcess)); MemorySet(userProc, 0, sizeof(OSProcess));
userProc->id = 1; // TODO: id gen userProc->id = SchedulerGetNextProcessID();
userProc->state = OSTaskStateRunning; userProc->state = OSTaskStateRunning;
StringCopy(userProc->name, module->name); StringCopy(userProc->name, module->name);
@@ -19,18 +19,33 @@ void ModuleLoad(BootModule* module) {
MemorySet(userL0Virt, 0, kVMPageSize); MemorySet(userL0Virt, 0, kVMPageSize);
userProc->l0Table = userL0Virt; userProc->l0Table = userL0Virt;
Address physBase = module->physicalBase; for (BIUInt32 s = 0; s < module->segmentCount; s++) {
Address virtBase = module->virtualBase; BootModuleSegment* seg = &module->segments[s];
Size modSize = module->size;
UInt64 codeFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX; // TODO: kill RWX UInt64 segFlags = kPTENormalMem | kPTEUser;
for (Size i = 0; i < modSize; i += kVMPageSize) { if (seg->flags & PF_W) {
VMMMapPage((Address*)userL0Phys, physBase + i, virtBase + i, codeFlags); // 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 stackPhys = (Address)PMMAllocatePage();
Address userStackVirt = 0x80000000; Address userStackVirt = 0x80000000;
UInt64 stackFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX | kPTEUserNX; UInt64 stackFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX | kPTEUserNX;
+4
View File
@@ -122,3 +122,7 @@ void SchedulerYield(UInt64 ticks) {
gOSSchedulerCurrentTask->state = OSTaskStateSleeping; gOSSchedulerCurrentTask->state = OSTaskStateSleeping;
CPUException(kOSSchedulerExceptionNumber); CPUException(kOSSchedulerExceptionNumber);
} }
UInt64 SchedulerGetNextProcessID() {
return gOSSchedulerNextProcessID++;
}