From fb55cb1b9af5f0b51b55a1a9683539a686ac3ebe Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 18:30:49 +0400 Subject: [PATCH] feat(modules): now it loads segments with correct rights, not RWX everywhere --- Bootloader/Source/main.c | 92 +++++++++++++++-------------- Bootloader/Source/modules/elf/elf.h | 6 +- Common/bootinfo.h | 16 ++++- Kernel/Include/OS/Scheduler.h | 1 + Kernel/Source/OS/Modules.c | 33 ++++++++--- Kernel/Source/OS/Scheduler.c | 4 ++ 6 files changed, 97 insertions(+), 55 deletions(-) diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index cae6f87..be2c81a 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -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); diff --git a/Bootloader/Source/modules/elf/elf.h b/Bootloader/Source/modules/elf/elf.h index 8150d86..bae0c08 100644 --- a/Bootloader/Source/modules/elf/elf.h +++ b/Bootloader/Source/modules/elf/elf.h @@ -32,4 +32,8 @@ typedef struct { uint64_t p_align; } Elf64_Phdr; -#define PT_LOAD 1 \ No newline at end of file +#define PT_LOAD 1 + +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 \ No newline at end of file diff --git a/Common/bootinfo.h b/Common/bootinfo.h index 3e2bb32..333a1bb 100644 --- a/Common/bootinfo.h +++ b/Common/bootinfo.h @@ -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 { diff --git a/Kernel/Include/OS/Scheduler.h b/Kernel/Include/OS/Scheduler.h index 4eee84d..c2dce53 100644 --- a/Kernel/Include/OS/Scheduler.h +++ b/Kernel/Include/OS/Scheduler.h @@ -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(); diff --git a/Kernel/Source/OS/Modules.c b/Kernel/Source/OS/Modules.c index 17b3fa1..3adbb36 100644 --- a/Kernel/Source/OS/Modules.c +++ b/Kernel/Source/OS/Modules.c @@ -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; diff --git a/Kernel/Source/OS/Scheduler.c b/Kernel/Source/OS/Scheduler.c index 10b70af..0bbbe3d 100644 --- a/Kernel/Source/OS/Scheduler.c +++ b/Kernel/Source/OS/Scheduler.c @@ -122,3 +122,7 @@ void SchedulerYield(UInt64 ticks) { gOSSchedulerCurrentTask->state = OSTaskStateSleeping; CPUException(kOSSchedulerExceptionNumber); } + +UInt64 SchedulerGetNextProcessID() { + return gOSSchedulerNextProcessID++; +}