summaryrefslogtreecommitdiff
path: root/src/kernel/elf.c
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2020-09-06 00:48:07 -0400
committerBenji Dial <benji6283@gmail.com>2020-09-06 00:48:07 -0400
commite8c6577617bffa4402c07c7aa20e3c24f03c1c20 (patch)
tree2fb9230b62d2344a44453117de9e656892219788 /src/kernel/elf.c
parent7ff724fe8f709440da9c730fdb8dcbaa4f989ed5 (diff)
downloadportland-os-e8c6577617bffa4402c07c7aa20e3c24f03c1c20.tar.gz
program loading, others
big kernel additions: paging, elf loading, separate kernel and user page allocation it now properly loads and runs sd0:bin/init.elf still need to determine which disk was booted from, and start the init on that disk
Diffstat (limited to 'src/kernel/elf.c')
-rw-r--r--src/kernel/elf.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
new file mode 100644
index 0000000..8cd659c
--- /dev/null
+++ b/src/kernel/elf.c
@@ -0,0 +1,116 @@
+#include <stdint.h>
+#include "drive.h"
+#include "elf.h"
+#include "task.h"
+#include "util.h"
+#include "paging.h"
+#include "pmap.h"
+
+#define ELF_MAGIC 0x464c457f
+
+enum {
+ ELF_32 = 1,
+ ELF_64 = 2
+};
+
+enum {
+ LITTLE_ENDIAN = 1,
+ BIG_ENDIAN = 2
+};
+
+enum {
+ //...
+ ARCH_X86 = 0x03
+ //...
+};
+
+struct elf_header {
+ uint32_t magic;
+ uint8_t word_size;
+ uint8_t endianness;
+ uint8_t elf_version;
+ uint8_t target_os;//ignored
+ uint8_t os_abi_version;//should be zero
+ uint8_t reserved[7];
+ uint16_t object_type;//TODO
+ uint16_t architecture;//should be ARCH_X86
+ uint32_t elf_version_2;
+ uint32_t entry_vma;
+ uint32_t phtable_fa;
+ uint32_t shtable_fa;
+ uint32_t flags;
+ uint16_t eh_size;
+ uint16_t phentry_size;
+ uint16_t phtable_count;
+ uint16_t shentry_size;
+ uint16_t shtable_count;
+ uint16_t sh_names_entry;
+} __attribute__ ((packed));
+
+enum {
+ PT_UNUSED = 0,
+ PT_LOADME = 1,
+ PT_DYNLINK = 2,
+ PT_INTERP = 3,
+ PT_COMMENT = 4,
+ PT_SHARED = 5,
+ PT_PHTABLE = 6,
+ PT_TL_TMPL = 7
+};
+
+enum {
+ PH_WRITABLE = 0x02
+};
+
+struct ph_entry {
+ uint32_t type;
+ uint32_t fa;
+ uint32_t vma;//must be page-aligned
+ uint32_t pma;//ignored
+ uint32_t fs;
+ uint32_t vms;
+ uint32_t flags;
+ uint32_t align;
+} __attribute__ ((packed));
+
+bool try_elf_run(const struct drive *d, const char *path) {
+ file_id_t h = d->get_file(d, path);
+ if (!h)
+ return false;
+
+ struct elf_header ehead;
+
+ fmcpy(&ehead, d, h, 0, sizeof(struct elf_header));
+
+ if ((ehead.magic != ELF_MAGIC) ||
+ (ehead.word_size != ELF_32) ||
+ (ehead.endianness != LITTLE_ENDIAN) ||
+ ehead.os_abi_version) {
+ d->free_file(d, h);
+ return false;
+ }
+
+ uint32_t phtable_size = ehead.phentry_size * ehead.phtable_count;
+ uint16_t phtable_pages = (phtable_size - 1) / 4096 + 1;
+
+ void *phtable = allocate_kernel_pages(phtable_pages);
+ fmcpy(phtable, d, h, ehead.phtable_fa, phtable_size);
+
+ void *pd = new_task_pd();
+
+ for (uint32_t phi = 0; phi < ehead.phtable_count; ++phi) {
+ struct ph_entry *entry = phtable + phi * ehead.phentry_size;
+ if (entry->type != PT_LOADME)
+ continue;
+ void *pma = pd_user_allocate(pd, entry->vma, (entry->vms - 1) / 4096 + 1, entry->flags & PH_WRITABLE);
+ fmcpy(pma, d, h, entry->fa, entry->fs);
+ }
+
+ free_pages(phtable, phtable_pages);
+
+ struct task_state tstate;
+ tstate.page_directory = pd;
+ tstate.ret_addr = ehead.entry_vma;
+ new_task(tstate);
+ return true;
+} \ No newline at end of file