Files
Sylva/boot.c
T
2026-05-29 19:25:56 +08:00

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;
}