Я пытаюсь загрузить 64-битное ядро по адресу 0x1000, используя следующий код:
#include <elf.h>
EFI_FILE* LoadFile(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable){
EFI_FILE* LoadedFile;
EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage);
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem;
SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (void**)&FileSystem);
if (Directory == NULL){
FileSystem->OpenVolume(FileSystem, &Directory);
}
EFI_STATUS s = Directory->Open(Directory, &LoadedFile, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
if (s != EFI_SUCCESS){
return NULL;
}
return LoadedFile;
}
int LoadKernel() {
EFI_FILE* Kernel = LoadFile(NULL, L"kernel.elf", ImageHandle, SystemTable);
if (Kernel == NULL){
Print(L"Could not load kernel \n");
return 0;
}
else{
Elf64_Ehdr header;
Elf64_Phdr* phdrs;
{
Kernel->SetPosition(Kernel, header.e_phoff);
UINTN size = header.e_phnum * header.e_phentsize;
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&phdrs);
Kernel->Read(Kernel, &size, phdrs);
}
for (
Elf64_Phdr* phdr = phdrs;
(char*)phdr < (char*)phdrs + header.e_phnum * header.e_phentsize;
phdr = (Elf64_Phdr*)((char*)phdr + header.e_phentsize)
)
{
switch (phdr->p_type){
case PT_LOAD:
{
int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;
Elf64_Addr segment = phdr->p_paddr;
SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment);
Kernel->SetPosition(Kernel, phdr->p_offset);
UINTN size = phdr->p_filesz;
Kernel->Read(Kernel, &size, (void*)segment);
break;
}
}
}
int (*KernelStart)() = ((__attribute__((sysv_abi)) int (*)() ) header.e_entry);
Print(L"%d\r\n", KernelStart());
Print(L"Kernel loaded at 0x1000\n");
return 1;
}
}
Ядро является int-функцией, возвращающей число, с этим проблем нет. Компиляция идет следующим образом:
Компиляция ядраgcc -ffreestanding -fshort-wchar -c src/kernel.c -o tmp/kernel.o
ld -T kernel.ld -shared -Bsymbolic -nostdlib tmp/kernel.o -o bin/kernel.elf
kernel.ld
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(kmain)
SECTIONS
{
.text : ALIGN(0x1000)
{
*(.text)
}
.data : ALIGN(0x1000)
{
*(.data)
}
.rodata : ALIGN(0x1000)
{
*(.rodata)
}
.bss : ALIGN(0x1000)
{
*(COMMON)
*(.bss)
}
}
Компиляция загрузчикаgcc -I/usr/include/efi -I/usr/include/efi/x86_64 -I/usr/include/efi/protocol -fno-stack-protector -m64 -fPIE -fshort-wchar -mno-red-zone -DHAVE_USE_MS_ABI -c -o tmp/main.o src/main.c
ld -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds -shared -Bsymbolic -L /usr/lib /usr/lib/crt0-efi-x86_64.o tmp/main.o -o tmp/bootx64.so -lefi -lgnuefi
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc --target=efi-app-x86_64 tmp/bootx64.so bin/bootx64.efi
При компиляции никаких проблем и ошибок не наблюдается, но когда я пытаюсь выполнить эту строку
Print(L"%d\r\n", KernelStart());
или просто
KernelStart();
- ничего не происходит, загрузчик зависает на месте. При этом, все предыдущие части отрабатывают корректно, и без этого вызова все завершается нормально