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
116 lines
No EOL
2.4 KiB
C
116 lines
No EOL
2.4 KiB
C
#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;
|
|
} |