205 lines
6.9 KiB
C
205 lines
6.9 KiB
C
#include <efi.h>
|
|
#include <efilib.h>
|
|
|
|
typedef struct {
|
|
UINT8 e_ident[16];
|
|
UINT16 e_type;
|
|
UINT16 e_machine;
|
|
UINT32 e_version;
|
|
UINT64 e_entry;
|
|
UINT64 e_phoff;
|
|
UINT64 e_shoff;
|
|
UINT32 e_flags;
|
|
UINT16 e_ehsize;
|
|
UINT16 e_phentsize;
|
|
UINT16 e_phnum;
|
|
UINT16 e_shentsize;
|
|
UINT16 e_shnum;
|
|
UINT16 e_shstrndx;
|
|
} Elf64_Ehdr;
|
|
|
|
typedef struct {
|
|
UINT32 p_type;
|
|
UINT32 p_flags;
|
|
UINT64 p_offset;
|
|
UINT64 p_vaddr;
|
|
UINT64 p_paddr;
|
|
UINT64 p_filesz;
|
|
UINT64 p_memsz;
|
|
UINT64 p_align;
|
|
} Elf64_Phdr;
|
|
|
|
#define PT_LOAD 1
|
|
#define ELFMAG 0x464C457F
|
|
|
|
#define PAGE_SIZE_4K 4096
|
|
|
|
static void load_kernel(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
|
EFI_STATUS status;
|
|
EFI_GUID loadedImageGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
|
EFI_GUID fsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
|
EFI_LOADED_IMAGE_PROTOCOL *loadedImage = NULL;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs = NULL;
|
|
EFI_FILE_PROTOCOL *root = NULL;
|
|
EFI_FILE_PROTOCOL *kernelFile = NULL;
|
|
VOID *phdrBuf = NULL;
|
|
Elf64_Phdr *phdrs = NULL;
|
|
Elf64_Ehdr ehdr;
|
|
UINTN readSize;
|
|
UINT16 i;
|
|
|
|
status = uefi_call_wrapper(BS->OpenProtocol, 6,
|
|
ImageHandle, &loadedImageGuid, (void**)&loadedImage,
|
|
ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
if (EFI_ERROR(status)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: loaded_image proto\n");
|
|
goto halt;
|
|
}
|
|
|
|
status = uefi_call_wrapper(BS->OpenProtocol, 6,
|
|
loadedImage->DeviceHandle, &fsGuid, (void**)&fs,
|
|
ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
if (EFI_ERROR(status)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: file system proto\n");
|
|
goto halt;
|
|
}
|
|
|
|
status = uefi_call_wrapper(fs->OpenVolume, 1, fs, &root);
|
|
if (EFI_ERROR(status)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: open volume\n");
|
|
goto halt;
|
|
}
|
|
|
|
status = uefi_call_wrapper(root->Open, 5, root, &kernelFile, L"Kernel.elf",
|
|
EFI_FILE_MODE_READ, 0);
|
|
if (EFI_ERROR(status)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: open Kernel.elf\n");
|
|
goto close_root;
|
|
}
|
|
|
|
readSize = sizeof(ehdr);
|
|
status = uefi_call_wrapper(kernelFile->Read, 3, kernelFile, &readSize, &ehdr);
|
|
if (EFI_ERROR(status) || readSize != sizeof(ehdr)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: read ELF hdr\n");
|
|
goto close_all;
|
|
}
|
|
|
|
if (*(UINT32*)ehdr.e_ident != ELFMAG) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: bad ELF magic\n");
|
|
goto close_all;
|
|
}
|
|
|
|
{
|
|
UINTN phdrSize = ehdr.e_phnum * ehdr.e_phentsize;
|
|
phdrBuf = AllocatePool(phdrSize);
|
|
if (!phdrBuf) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: alloc PHDRs\n");
|
|
goto close_all;
|
|
}
|
|
|
|
uefi_call_wrapper(kernelFile->SetPosition, 2, kernelFile, ehdr.e_phoff);
|
|
readSize = phdrSize;
|
|
status = uefi_call_wrapper(kernelFile->Read, 3, kernelFile, &readSize, phdrBuf);
|
|
if (EFI_ERROR(status) || readSize != phdrSize) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: read PHDRs\n");
|
|
goto free_phdr;
|
|
}
|
|
phdrs = (Elf64_Phdr *)phdrBuf;
|
|
}
|
|
|
|
{
|
|
UINT64 minAddr = ~0ULL;
|
|
UINT64 maxAddr = 0;
|
|
|
|
for (i = 0; i < ehdr.e_phnum; i++) {
|
|
if (phdrs[i].p_type == PT_LOAD) {
|
|
UINT64 end = phdrs[i].p_vaddr + phdrs[i].p_memsz;
|
|
if (phdrs[i].p_vaddr < minAddr) minAddr = phdrs[i].p_vaddr;
|
|
if (end > maxAddr) maxAddr = end;
|
|
}
|
|
}
|
|
|
|
UINT64 base = minAddr & ~(PAGE_SIZE_4K - 1);
|
|
UINT64 top = (maxAddr + PAGE_SIZE_4K - 1) & ~(PAGE_SIZE_4K - 1);
|
|
UINTN numPages = (UINTN)((top - base) / PAGE_SIZE_4K);
|
|
EFI_PHYSICAL_ADDRESS allocAddr = (EFI_PHYSICAL_ADDRESS)base;
|
|
|
|
status = uefi_call_wrapper(BS->AllocatePages, 4,
|
|
AllocateAddress, EfiLoaderData, numPages, &allocAddr);
|
|
if (EFI_ERROR(status)) {
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: alloc kernel mem\n");
|
|
goto free_phdr;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ehdr.e_phnum; i++) {
|
|
if (phdrs[i].p_type != PT_LOAD) continue;
|
|
|
|
uefi_call_wrapper(kernelFile->SetPosition, 2, kernelFile, phdrs[i].p_offset);
|
|
readSize = (UINTN)phdrs[i].p_filesz;
|
|
uefi_call_wrapper(kernelFile->Read, 3, kernelFile, &readSize,
|
|
(VOID*)(UINTN)phdrs[i].p_vaddr);
|
|
|
|
if (phdrs[i].p_memsz > phdrs[i].p_filesz) {
|
|
UINT8 *bss = (UINT8*)(UINTN)(phdrs[i].p_vaddr + phdrs[i].p_filesz);
|
|
UINTN bssSize = (UINTN)(phdrs[i].p_memsz - phdrs[i].p_filesz);
|
|
for (UINTN j = 0; j < bssSize; j++) bss[j] = 0;
|
|
}
|
|
}
|
|
|
|
FreePool(phdrBuf);
|
|
phdrBuf = NULL;
|
|
uefi_call_wrapper(kernelFile->Close, 1, kernelFile);
|
|
kernelFile = NULL;
|
|
uefi_call_wrapper(root->Close, 1, root);
|
|
root = NULL;
|
|
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"* Jumping to kernel...\n");
|
|
|
|
{
|
|
typedef void (*KernelEntry)(EFI_HANDLE, EFI_SYSTEM_TABLE *);
|
|
KernelEntry entry = (KernelEntry)(UINTN)ehdr.e_entry;
|
|
entry(ImageHandle, SystemTable);
|
|
}
|
|
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
|
|
L"ERR: kernel returned\n");
|
|
goto halt;
|
|
|
|
free_phdr:
|
|
if (phdrBuf) FreePool(phdrBuf);
|
|
close_all:
|
|
if (kernelFile) uefi_call_wrapper(kernelFile->Close, 1, kernelFile);
|
|
close_root:
|
|
if (root) uefi_call_wrapper(root->Close, 1, root);
|
|
halt:
|
|
while (1) __asm__ volatile("hlt");
|
|
}
|
|
|
|
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
|
InitializeLib(ImageHandle, SystemTable);
|
|
|
|
uefi_call_wrapper(SystemTable->ConOut->ClearScreen, 1, SystemTable->ConOut);
|
|
uefi_call_wrapper(SystemTable->ConOut->SetCursorPosition, 3, SystemTable->ConOut, 0, 1);
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut, L"Welcome to SYLVA OS!\n");
|
|
uefi_call_wrapper(SystemTable->ConOut->SetCursorPosition, 3, SystemTable->ConOut, 0, 2);
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut, L"* The system has booted successfully.\n");
|
|
|
|
uefi_call_wrapper(SystemTable->ConOut->SetCursorPosition, 3, SystemTable->ConOut, 0, 3);
|
|
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut, L"* Loading kernel...\n");
|
|
|
|
load_kernel(ImageHandle, SystemTable);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|