setos

拙OS
Log | Files | Refs | LICENSE

commit bad712b2a7aa5f6bfdff6470b0d06d767385d1dd
parent 01fa94c59bee5c39464a2dc4df6acd26c7a3d45a
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Fri, 29 Mar 2024 09:46:14 +0900

add load_elf

Diffstat:
Mloader.c | 21+++++++++++++++++----
Muefi.h | 4+++-
Mutils.c | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mutils.h | 18+++++++++++++++---
4 files changed, 91 insertions(+), 15 deletions(-)

diff --git a/loader.c b/loader.c @@ -57,7 +57,7 @@ EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *systab) } EFI_PHYSICAL_ADDRESS kernel_base = 0x100000; UINTN fib_size = sizeof(EFI_FILE_INFO) + sizeof(CHAR16) * 11; - char fibuf[fib_size]; + char fibuf[sizeof(EFI_FILE_INFO) + sizeof(CHAR16) * 11]; // determined at compile time? EFI_FILE_INFO *fileInfo = (EFI_FILE_INFO *) fibuf; stat = kernel->GetInfo(kernel, &EFI_FILE_INFO_ID, &fib_size, (VOID *)fibuf); if (stat != EFI_SUCCESS) { @@ -66,9 +66,22 @@ EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *systab) } UINT64 kernel_size = fileInfo->FileSize; ElfHdr kernel_ehdr; - Phdr kernel_phdr; - read_elf_hdr(kernel, &kernel_ehdr, &kernel_phdr); - stat = kernel->SetPosition(kernel, kernel_ehdr.entry); + read_ehdr(kernel, &kernel_ehdr); + efi_printf("type:\t%x\nphoff:\t%x\nphentsize:\t%x\nphnum:\t%x\n", + kernel_ehdr.type, kernel_ehdr.phoff, + kernel_ehdr.phentsize, kernel_ehdr.phnum); + if (kernel_ehdr.phnum > 32) { + efi_printf("too many phdrs\n"); + return EFI_BUFFER_TOO_SMALL; + } + Phdr kernel_phdr[32]; + read_phdr(kernel, &kernel_ehdr, kernel_phdr); + for (UINT16 i = 0; i < kernel_ehdr.phnum; i++) { + efi_printf("type: %x, offset: %x, vaddr: %x\n", + kernel_phdr[i].type, kernel_phdr[i].offset, kernel_phdr[i].vaddr); + } + + stat = kernel->SetPosition(kernel, 0x1000); if (stat != EFI_SUCCESS) { efi_printf("set position of \"kernel.elf\": %d\n", stat); return stat; diff --git a/uefi.h b/uefi.h @@ -36,7 +36,9 @@ typedef struct EFI_GUID { // EFI_STATUS enum { EFI_SUCCESS = 0, - EFI_INVALID_PARAMETER = 2, + + EFI_INVALID_PARAMETER = 0x8000000000000002, + EFI_BUFFER_TOO_SMALL = 0x8000000000000005, }; typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE; diff --git a/utils.c b/utils.c @@ -125,27 +125,76 @@ efi_printf(char *fmt, ...) } EFI_STATUS -read_elf_hdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr *phdr) +read_ehdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr) { EFI_STATUS stat; - UINTN buf_size = 1024; - char buf[buf_size]; + UINTN ehdr_size = sizeof(ElfHdr); stat = elf->SetPosition(elf, 0); if (stat != EFI_SUCCESS) { efi_printf("set position: %d\n", stat); return stat; } - stat = elf->Read(elf, &buf_size, (VOID *) buf); + stat = elf->Read(elf, &ehdr_size, (VOID *) ehdr); if (stat != EFI_SUCCESS) { efi_printf("read: %d\n", stat); return stat; } - if (buf[0] != 0x7f || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') { + // TODO: check file format. + // for now, it assumes that elf is 2's complement, 64-bit little endian, + // System V ABI... + if (ehdr->ident[0] != 0x7f || ehdr->ident[1] != 'E' || + ehdr->ident[2] != 'L' || ehdr->ident[3] != 'F') { efi_printf("not an elf file\n"); return EFI_INVALID_PARAMETER; } - efi_printf("it is an elf file\n"); - ehdr->entry = 0x1000; + + return EFI_SUCCESS; +} + +EFI_STATUS +read_phdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]) +{ + EFI_STATUS stat; + UINTN n; + + stat = elf->SetPosition(elf, ehdr->phoff); + if (stat != EFI_SUCCESS) { + efi_printf("set position: %d\n", stat); + return stat; + } + // TODO: need overflow check?? + n = ehdr->phentsize * ehdr->phnum; + stat = elf->Read(elf, &n, (VOID *) phdr); + if (stat != EFI_SUCCESS) { + efi_printf("read phdr: %d\n", stat); + return stat; + } + return EFI_SUCCESS; +} + +EFI_STATUS +load_elf(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]) +{ + EFI_STATUS stat; + EFI_PHYSICAL_ADDRESS addr; + UINT64 size; + for (UINT16 i = 0; i < ehdr->phnum; i++) { + if (phdr[i].type != PT_LOAD) { + continue; + } + stat = elf->SetPosition(elf, phdr[i].offset); + if (stat != EFI_SUCCESS) { + efi_printf("set position: %d\n", stat); + return stat; + } + addr = (EFI_PHYSICAL_ADDRESS) phdr[i].vaddr; + size = phdr[i].filesz; + stat = elf->Read(elf, &size, (VOID *)addr); + if (stat != EFI_SUCCESS) { + efi_printf("read to memory: %d\n", stat); + return stat; + } + } return EFI_SUCCESS; } \ No newline at end of file diff --git a/utils.h b/utils.h @@ -47,6 +47,18 @@ typedef struct { UINT64 align; } Phdr; -// Read_elf_hdr reads elf header and populates hdr struct. +#define PT_LOAD 1 + +// Read_ehdr reads elf header and populates ehdr. +// It modifies elf's offset. +EFI_STATUS read_ehdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr); + +// Read_phdr reads elf's program headers and populates phdr. +// It uses ehdr to read phdr. // It modifies elf's offset. -EFI_STATUS read_elf_hdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr *phdr); -\ No newline at end of file +// Caller should allocate enough space in phdr. +EFI_STATUS read_phdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]); + +// Load_elf copies loadable segments of elf to the memory specified by the +// vaddr field of each Phdr. +EFI_STATUS load_elf(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]); +\ No newline at end of file