WIP: modules
This commit is contained in:
+175
-11
@@ -7,8 +7,10 @@
|
||||
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define WSTR(str) ((wchar_t*)L##str)
|
||||
#define MAX_MODULES 16
|
||||
|
||||
static wchar_t* kernel_path = WSTR("ksOSKernel.elf");
|
||||
static wchar_t* system_dir_path = WSTR("System");
|
||||
static efi_guid_t dtb_guid = {
|
||||
0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}
|
||||
};
|
||||
@@ -79,6 +81,8 @@ static efi_status_t open_root_volume(efi_file_handle_t** root) {
|
||||
return fs->OpenVolume(fs, root);
|
||||
}
|
||||
|
||||
static efi_status_t validate_elf(efi_physical_address_t addr);
|
||||
|
||||
static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) {
|
||||
efi_guid_t file_info_guid = EFI_FILE_INFO_GUID;
|
||||
uintn_t file_info_size = 0;
|
||||
@@ -95,6 +99,157 @@ static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** fi
|
||||
return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info);
|
||||
}
|
||||
|
||||
static efi_status_t load_modules(efi_file_handle_t* root, Bootinfo* boot_info) {
|
||||
efi_file_handle_t* sys_dir = NULL;
|
||||
efi_status_t status = root->Open(root, &sys_dir, system_dir_path, EFI_FILE_MODE_READ, 0);
|
||||
if (EFI_ERROR(status)) {
|
||||
boot_info->moduleCount = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
boot_info->moduleCount = 0;
|
||||
|
||||
uint8_t dir_buffer[8192];
|
||||
uintn_t dir_buffer_size;
|
||||
boolean_t first_entry = 1;
|
||||
|
||||
while (1) {
|
||||
dir_buffer_size = sizeof(dir_buffer);
|
||||
status = sys_dir->Read(sys_dir, &dir_buffer_size, dir_buffer);
|
||||
if (EFI_ERROR(status) || dir_buffer_size == 0) break;
|
||||
|
||||
efi_file_info_t* entry = (efi_file_info_t*)dir_buffer;
|
||||
|
||||
if (first_entry) { first_entry = 0; continue; }
|
||||
|
||||
// Only process subdirectories (skip bare files)
|
||||
if (!(entry->Attribute & 0x10)) continue;
|
||||
|
||||
// Skip . and .. entries
|
||||
if (entry->FileName[0] == L'.') continue;
|
||||
|
||||
// Build path: System\DirName\DirName (module file matches directory name)
|
||||
wchar_t file_path[FILENAME_MAX * 2 + 16];
|
||||
wchar_t* p = file_path;
|
||||
wchar_t* prefix = system_dir_path;
|
||||
while (*prefix) *p++ = *prefix++;
|
||||
*p++ = L'\\';
|
||||
wchar_t* dir_name_start = p;
|
||||
wchar_t* name = entry->FileName;
|
||||
while (*name) *p++ = *name++;
|
||||
*p++ = L'\\';
|
||||
// Copy directory name again as the inner file name
|
||||
wchar_t* inner = dir_name_start;
|
||||
while (*inner != L'\\') *p++ = *inner++;
|
||||
*p = L'\0';
|
||||
|
||||
efi_file_handle_t* module_file = NULL;
|
||||
status = root->Open(root, &module_file, file_path, EFI_FILE_MODE_READ, 0);
|
||||
if (EFI_ERROR(status)) continue;
|
||||
|
||||
efi_file_info_t* mod_info = NULL;
|
||||
status = read_file_info(module_file, &mod_info);
|
||||
if (EFI_ERROR(status)) {
|
||||
module_file->Close(module_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t file_size = mod_info->FileSize;
|
||||
gBS->FreePool(mod_info);
|
||||
|
||||
if (file_size == 0) {
|
||||
module_file->Close(module_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
uintn_t pages = (file_size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
efi_physical_address_t module_addr = 0;
|
||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, &module_addr);
|
||||
if (EFI_ERROR(status)) {
|
||||
module_file->Close(module_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
uintn_t bytes_to_read = (uintn_t)file_size;
|
||||
status = module_file->Read(module_file, &bytes_to_read, (void*)module_addr);
|
||||
module_file->Close(module_file);
|
||||
|
||||
if (EFI_ERROR(status)) {
|
||||
gBS->FreePages(module_addr, pages);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!EFI_ERROR(validate_elf(module_addr))) {
|
||||
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;
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
wchar_t wc = entry->FileName[i];
|
||||
if (wc == L'\0') { mod->name[i] = '\0'; break; }
|
||||
mod->name[i] = (wc < 128) ? (char)wc : '?';
|
||||
}
|
||||
mod->name[31] = '\0';
|
||||
|
||||
print(WSTR(" [MODULE] "));
|
||||
print(entry->FileName);
|
||||
print(WSTR("\r\n"));
|
||||
|
||||
boot_info->moduleCount++;
|
||||
}
|
||||
|
||||
gBS->FreePages(module_addr, pages);
|
||||
|
||||
if (boot_info->moduleCount >= MAX_MODULES) break;
|
||||
}
|
||||
|
||||
sys_dir->Close(sys_dir);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size, efi_file_handle_t** out_handle) {
|
||||
efi_file_handle_t* kernel_file = NULL;
|
||||
efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0);
|
||||
@@ -118,17 +273,25 @@ static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t*
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status_t validate_elf(efi_physical_address_t addr) {
|
||||
Elf64_Ehdr* elf = (Elf64_Ehdr*)addr;
|
||||
|
||||
if (elf->e_ident[0] != 0x7f || elf->e_ident[1] != 'E' ||
|
||||
elf->e_ident[2] != 'L' || elf->e_ident[3] != 'F') {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
if (elf->e_machine != 0xB7) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) {
|
||||
Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr;
|
||||
|
||||
if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' ||
|
||||
elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') {
|
||||
return fail(WSTR("Invalid ELF header\r\n"));
|
||||
efi_status_t status = validate_elf(kernel_addr);
|
||||
if (EFI_ERROR(status)) {
|
||||
return fail(WSTR("Invalid kernel ELF\r\n"));
|
||||
}
|
||||
if (elf_header->e_machine != 0xB7) { // AArch64
|
||||
return fail(WSTR("Invalid ELF machine\r\n"));
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -246,8 +409,6 @@ efi_status_t bootloader_main(void) {
|
||||
return fail(WSTR("Failed to load ksOSKernel.bin\r\n"));
|
||||
}
|
||||
|
||||
Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr;
|
||||
|
||||
status = parse_elf_headers(kernel_addr);
|
||||
if (EFI_ERROR(status)) return status;
|
||||
|
||||
@@ -271,6 +432,9 @@ efi_status_t bootloader_main(void) {
|
||||
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||
boot_info->dtb = dtb_address;
|
||||
|
||||
print(WSTR("Loading System modules...\r\n"));
|
||||
status = load_modules(root, boot_info);
|
||||
|
||||
print(WSTR("Almost ready to jump. Reading memory map\r\n"));
|
||||
status = populate_memory_map(boot_info);
|
||||
if (EFI_ERROR(status)) {
|
||||
|
||||
Reference in New Issue
Block a user