commit bad712b2a7aa5f6bfdff6470b0d06d767385d1dd
parent 01fa94c59bee5c39464a2dc4df6acd26c7a3d45a
Author: Matsuda Kenji <info@mtkn.jp>
Date: Fri, 29 Mar 2024 09:46:14 +0900
add load_elf
Diffstat:
M | loader.c | | | 21 | +++++++++++++++++---- |
M | uefi.h | | | 4 | +++- |
M | utils.c | | | 63 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | utils.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