diff --git a/Makefile b/Makefile index a6e5be1f..a31b7889 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ clean: test: $(MAKE) -C test + rm -f test.img dd if=/dev/zero bs=1M count=0 seek=64 of=test.img parted -s test.img mklabel msdos parted -s test.img mkpart primary 1 100% @@ -15,4 +16,4 @@ test: echfs-utils -m -p0 test.img import test/test.elf test.elf echfs-utils -m -p0 test.img import test/qloader2.cfg qloader2.cfg ./qloader2-install test.img - qemu-system-x86_64 -hda test.img + qemu-system-x86_64 -hda test.img -monitor stdio diff --git a/src/lib/elf.c b/src/lib/elf.c new file mode 100644 index 00000000..71e3be6b --- /dev/null +++ b/src/lib/elf.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +#define PT_LOAD 0x00000001 +#define PT_INTERP 0x00000003 +#define PT_PHDR 0x00000006 + +#define ABI_SYSV 0x00 +#define ARCH_X86_64 0x3e +#define BITS_LE 0x01 + +/* Indices into identification array */ +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 + +struct elf_hdr { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t phoff; + uint32_t shoff; + uint32_t flags; + uint16_t hdr_size; + uint16_t phdr_size; + uint16_t ph_num; + uint16_t shdr_size; + uint16_t sh_num; + uint16_t shstrndx; +}; + +struct elf_phdr { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; +}; + +int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count); + +int elf_load(struct echfs_file_handle *fd) { + struct elf_hdr hdr; + echfs_read(fd, &hdr, 0, sizeof(struct elf_hdr)); + + if (strncmp((char *)hdr.ident, "\177ELF", 4)) { + print("Not a valid ELF file.\n"); + return 1; + } + + if (hdr.ident[EI_DATA] != BITS_LE) { + print("Not a Little-endian ELF file.\n"); + return -1; + } + + for (uint16_t i = 0; i < hdr.ph_num; i++) { + struct elf_phdr phdr; + echfs_read(fd, &phdr, hdr.phoff + i * sizeof(struct elf_phdr), + sizeof(struct elf_phdr)); + + if (phdr.p_type != PT_LOAD) + continue; + + + echfs_read(fd, (void *)phdr.p_vaddr, phdr.p_offset, phdr.p_filesz); + + size_t to_zero = (size_t)(phdr.p_memsz - phdr.p_filesz); + + if (to_zero) { + void *ptr = (void *)(phdr.p_vaddr + phdr.p_filesz); + memset(ptr, 0, to_zero); + } + } + + asm volatile ( + "jmp %0\n\t" + : + : "r" (hdr.entry) + : "memory" + ); +} diff --git a/src/lib/elf.h b/src/lib/elf.h new file mode 100644 index 00000000..d3234d83 --- /dev/null +++ b/src/lib/elf.h @@ -0,0 +1,8 @@ +#ifndef __LIB__ELF_H__ +#define __LIB__ELF_H__ + +#include + +int elf_load(struct echfs_file_handle *fd); + +#endif diff --git a/src/main.c b/src/main.c index bcb4eb4d..3bc04472 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,7 @@ asm ( #include #include #include +#include #define CONFIG_NAME "qloader2.cfg" diff --git a/test/Makefile b/test/Makefile index e822929d..04d67e36 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,3 +1,3 @@ -test.elf: +test.elf: test.asm linker.ld nasm test.asm -felf32 -o test.o ../toolchain/bin/i386-elf-ld test.o -nostdlib -T ./linker.ld -o test.elf diff --git a/test/test.asm b/test/test.asm index 037d08b2..4f0bdb03 100644 --- a/test/test.asm +++ b/test/test.asm @@ -6,5 +6,7 @@ section .text ; Entry point +global _start _start: - + mov eax, 0xdeadbeef + jmp $