diff options
Diffstat (limited to 'kjarna')
| -rw-r--r-- | kjarna/Makefile | 2 | ||||
| -rw-r--r-- | kjarna/efi/image.c | 196 | ||||
| -rw-r--r-- | kjarna/kjarna.h | 2 | ||||
| -rw-r--r-- | kjarna/main.c | 2 |
4 files changed, 199 insertions, 3 deletions
diff --git a/kjarna/Makefile b/kjarna/Makefile index b02fbe6..cdfc90b 100644 --- a/kjarna/Makefile +++ b/kjarna/Makefile @@ -18,7 +18,7 @@ all: $(IMAGE) CRT_OBJS := start.o LIB_OBJS := memcmp.o memset.o memcpy.o memmove.o string.o elf64.o -EFI_OBJS := file.o memory.o protocol.o runtime.o +EFI_OBJS := file.o memory.o protocol.o image.o APP_OBJS := main.o OBJS := $(CRT_OBJS) $(LIB_OBJS) $(EFI_OBJS) $(APP_OBJS) diff --git a/kjarna/efi/image.c b/kjarna/efi/image.c new file mode 100644 index 0000000..8af9cfd --- /dev/null +++ b/kjarna/efi/image.c @@ -0,0 +1,196 @@ +#include <posix/unistd.h> +#include <posix/fcntl.h> +#include <kjarna/interface.h> +#include <libc/string.h> +#include <lib/elf.h> + +#include "kjarna_efi.h" + +#include <efi/error.h> + +struct image_buffer +{ + char *base; + size_t length; +}; + +static ssize_t read_ehdr(int fd, Elf64_Ehdr *ehdr) +{ + ssize_t result; + + if (efi_lseek(fd, 0, SEEK_SET) == -1) + { + return -1; + } + else if ((result = efi_read(fd, ehdr, sizeof(*ehdr))) == -1) + { + return -1; + } + else if (!elf64_validate(ehdr, ET_DYN, EM_X86_64)) + { + return -1; + } + + return result; +} + +static ssize_t read_phdrs(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs) +{ + if (efi_lseek(fd, ehdr->e_phoff, SEEK_SET) != -1) + { + return efi_read(fd, phdrs, ehdr->e_phnum * ehdr->e_phentsize); + } + + return -1; +} + +static void create_image_buffer(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, struct image_buffer *buffer) +{ + buffer->length = elf64_size(ehdr, phdrs); + buffer->base = efi_mmap(nullptr, buffer->length, 0, 0, -1, 0); +} + +static ssize_t load_segment(int fd, Elf64_Phdr *phdr, char *buffer) +{ + if (efi_lseek(fd, phdr->p_offset, SEEK_SET) == -1) + { + return -1; + } + + int result = efi_read(fd, &buffer[phdr->p_offset], phdr->p_filesz); + + if (result > 0 && phdr->p_memsz > phdr->p_filesz) + { + memset(&buffer[phdr->p_offset + phdr->p_filesz], 0, phdr->p_memsz - phdr->p_filesz); + } + + return result; +} + +static ssize_t load_segments(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, char *buffer) +{ + int i; + + for (i = 0; i < ehdr->e_phnum; i++) + { + if (phdrs[i].p_type != PT_LOAD) + { + continue; + } + + if (load_segment(fd, &phdrs[i], buffer) == -1) + { + return -1; + } + } + + return i; +} + +static struct image_buffer load_image(void) +{ + const char *image_entry_path = "\\adasoft\\sophia\\efi.os"; + + int image_fd; + + struct image_buffer buffer = { nullptr, 0 }; + + if ((image_fd = efi_open(image_entry_path, O_RDONLY, 0)) == -1) + { + return buffer; + } + + Elf64_Ehdr ehdr; + + if (read_ehdr(image_fd, &ehdr) == -1) + { + return buffer; + } + + Elf64_Phdr *phdrs = efi_calloc_pool(ehdr.e_phnum, ehdr.e_phentsize); + + if (phdrs == nullptr) + { + return buffer; + } + else if(read_phdrs(image_fd, &ehdr, phdrs) != -1) + { + create_image_buffer(&ehdr, phdrs, &buffer); + } + + if (buffer.base != nullptr && load_segments(image_fd, &ehdr, phdrs, buffer.base) == -1) + { + efi_munmap(buffer.base, buffer.length); + buffer.base = nullptr; + } + + efi_close(image_fd); + efi_free_pool(phdrs); + + return buffer; +} + +kjarna_image_entry_func *image_entry_addr(struct image_buffer *buffer) +{ + if (buffer->base == nullptr) + { + return nullptr; + } + + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)buffer->base; + + return (kjarna_image_entry_func *)(buffer->base + ehdr->e_entry); +} + +int image_start(void) +{ + struct kjarna_interface interface = + { + efi_open, + efi_close, + efi_lseek, + efi_read, + efi_write, + efi_mmap, + efi_munmap + }; + + struct kjarna_entry_params params = + { + &interface, + 0, + nullptr, + nullptr + }; + + struct image_buffer buffer = load_image(); + + kjarna_image_entry_func *image_entry = nullptr; + + if (buffer.base != nullptr) + { + image_entry = image_entry_addr(&buffer); + } + + if (image_entry != nullptr) + { + image_entry(¶ms); + } + + if (efi_munmap(buffer.base, buffer.length) == -1) + { + efi_write(STDOUT_FILENO, "failed unmap\r\n", -1); + + if (efi_errno == EFI_NOT_FOUND) + { + efi_write(STDOUT_FILENO, "not found\r\n", -1); + } + else + { + efi_write(STDOUT_FILENO, "bad alignment?\r\n", -1); + } + } + + return -1; +} + diff --git a/kjarna/kjarna.h b/kjarna/kjarna.h index d9291ca..81bb79b 100644 --- a/kjarna/kjarna.h +++ b/kjarna/kjarna.h @@ -3,5 +3,5 @@ #include <kjarna/interface.h> int main(int argc, char **argv); -int runtime_start(void); +int image_start(void); diff --git a/kjarna/main.c b/kjarna/main.c index 6420e83..38c913f 100644 --- a/kjarna/main.c +++ b/kjarna/main.c @@ -4,6 +4,6 @@ int main(int argc, char **argv) { (void)argc; (void)argv; - return runtime_start(); + return image_start(); } |
