summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/kjarna/interface.h2
-rw-r--r--kjarna/Makefile2
-rw-r--r--kjarna/efi/image.c196
-rw-r--r--kjarna/kjarna.h2
-rw-r--r--kjarna/main.c2
5 files changed, 200 insertions, 4 deletions
diff --git a/api/kjarna/interface.h b/api/kjarna/interface.h
index e0c491a..9c0d7fe 100644
--- a/api/kjarna/interface.h
+++ b/api/kjarna/interface.h
@@ -25,5 +25,5 @@ struct kjarna_entry_params
char **envp;
};
-typedef int (SYSV_ABI kjarna_runtime_entry_func)(struct kjarna_entry_params *);
+typedef int (SYSV_ABI kjarna_image_entry_func)(struct kjarna_entry_params *);
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(&params);
+ }
+
+ 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();
}