aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/elf.c85
-rw-r--r--common/initrd.c8
-rw-r--r--common/vmem.c9
3 files changed, 92 insertions, 10 deletions
diff --git a/common/elf.c b/common/elf.c
index c6a37e0..c73d56c 100644
--- a/common/elf.c
+++ b/common/elf.c
@@ -1,12 +1,83 @@
#include <apos/elf.h>
#include <apos/vmem.h>
+#include <apos/bytes.h>
+#include <apos/string.h>
-vm_t bin_entry(vm_t bin)
+static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize)
{
- struct elf_header *e = (struct elf_header *)bin;
- /* TODO: check that address points to a valid ELF executable */
- /* oh yeah, this only works for DYN objects, fuck */
- /* eh, fuck it, I'll fix this later, today has been a decently
- * productive day as is */
- return ((vm_t)e->e_entry) + bin;
+ /* TODO: take alignment into consideration? */
+ vm_t runner = phstart;
+ for(size_t i = 0; i < phnum; ++i, runner += phsize){
+ if(program_header_prop(ei_c, runner, p_type) != PT_LOAD)
+ continue;
+
+ vm_t va = program_header_prop(ei_c, runner, p_vaddr);
+ size_t vsz = program_header_prop(ei_c, runner, p_memsz);
+
+ vm_t start = 0;
+ if(!(start = alloc_fixed_region(&t->sp_r, va, vsz, 0)))
+ return; /* out of memory or something */
+
+ uint8_t vflags = VM_V | VM_U;
+ uint8_t bflags = program_header_prop(ei_c, runner, p_flags);
+ if(bflags & PF_X)
+ vflags |= VM_X;
+
+ if(bflags & PF_W)
+ vflags |= VM_W;
+
+ if(bflags & PF_R)
+ vflags |= VM_R;
+
+ map_fill_region(t->b_r, start, vsz, VM_V | VM_X | VM_R | VM_W | VM_U);
+
+ vm_t vo = bin + program_header_prop(ei_c, runner, p_offset);
+ vm_t vfz = program_header_prop(ei_c, runner, p_filesz);
+ memcpy((void *)va, (void *)vo, vfz);
+
+ /* skip while testing
+ pm_t paddr = 0;
+ stat_vmem(t->b_r, va, &paddr, 0, 0);
+ mod_vmem(t->b_r, va, paddr, vflags);
+ */
+ }
+}
+
+static vm_t __map_dyn(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize)
+{
+ /* TODO */
+}
+
+static vm_t __prepare_proc(struct tcb *t, uint8_t ei_c, vm_t elf)
+{
+ short e_type = elf_header_prop(ei_c, elf, e_type);
+ if(e_type != ET_DYN && e_type != ET_EXEC)
+ return 0;
+
+ vm_t phstart = ptradd(elf, elf_header_prop(ei_c, elf, e_phoff));
+ size_t phnum = elf_header_prop(ei_c, elf, e_phnum);
+ size_t phsize = elf_header_prop(ei_c, elf, e_phentsize);
+
+ vm_t entry = elf_header_prop(ei_c, elf, e_entry);
+ if(e_type == ET_EXEC){
+ __map_exec(t, elf, ei_c, phstart, phnum, phsize);
+ return entry;
+ } else {
+ vm_t o = __map_dyn(t, elf, ei_c, phstart, phnum, phsize);
+ return o + entry;
+ }
+}
+
+/* sets up all memory regions etc, returns the entry address */
+vm_t prepare_proc(struct tcb *t, vm_t p)
+{
+ struct elf_ident *i = (struct elf_ident *)p;
+ if(i->ei_magic != cpu_to_be32(EI_MAGIC))
+ return 0;
+
+ if(i->ei_class != ELFCLASS32 && i->ei_class != ELFCLASS64)
+ return 0;
+
+ /* more sanity checks? */
+ return __prepare_proc(t, i->ei_class, p);
}
diff --git a/common/initrd.c b/common/initrd.c
index 61aaaff..18db836 100644
--- a/common/initrd.c
+++ b/common/initrd.c
@@ -86,6 +86,14 @@ size_t get_init_size(void *fdt)
return convnum(cp->c_filesize, 8, 16);
}
+vm_t get_init_base(void *fdt)
+{
+ char *c = (char *)get_initrdbase(fdt);
+ struct cpio_header *cp = find_file(c, init_n, init_nlen);
+ size_t name_len = convnum(cp->c_namesize, 8, 16);
+ return ((vm_t)cp) + align_up(sizeof(struct cpio_header) + name_len, 4);
+}
+
void move_init(void *fdt, void *target)
{
char *c = (char *)get_initrdbase(fdt);
diff --git a/common/vmem.c b/common/vmem.c
index 7b1fa4f..229963c 100644
--- a/common/vmem.c
+++ b/common/vmem.c
@@ -299,8 +299,11 @@ vm_t alloc_region(struct sp_reg_root *r,
vm_t alloc_fixed_region(struct sp_reg_root *r,
vm_t start, size_t size, size_t *actual_size)
{
- *actual_size = align_up(size, BASE_PAGE_SIZE);
- size_t pages = __page(*actual_size);
+ size_t asize = align_up(size, BASE_PAGE_SIZE);
+ if(actual_size)
+ *actual_size = asize;
+
+ size_t pages = __page(asize);
start = __page(start);
struct sp_mem *m = sp_find_used_closest(r, start);
@@ -309,7 +312,7 @@ vm_t alloc_fixed_region(struct sp_reg_root *r,
/* locate actual region where start is between the region start and end */
while(!((m->start <= start) && (start <= m->end))){
- if(start < m->start)
+ if(start > m->start)
m = m->next;
else
m = m->prev;