Add 32 bit stivale support
diff --git a/src/lib/elf.c b/src/lib/elf.c
index dd67078c..f0ff11db 100644
--- a/src/lib/elf.c
+++ b/src/lib/elf.c
@@ -9,9 +9,10 @@
#define PT_INTERP 0x00000003
#define PT_PHDR 0x00000006
-#define ABI_SYSV 0x00
+#define ABI_SYSV 0x00
#define ARCH_X86_64 0x3e
-#define BITS_LE 0x01
+#define ARCH_X86_32 0x03
+#define BITS_LE 0x01
/* Indices into identification array */
#define EI_CLASS 4
@@ -19,8 +20,8 @@
#define EI_VERSION 6
#define EI_OSABI 7
-struct elf_hdr {
- uint8_t ident[16];
+struct elf64_hdr {
+ uint8_t ident[16];
uint16_t type;
uint16_t machine;
uint32_t version;
@@ -36,7 +37,24 @@ struct elf_hdr {
uint16_t shstrndx;
};
-struct elf_phdr {
+struct elf32_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 elf64_phdr {
uint32_t p_type;
uint32_t p_flags;
uint64_t p_offset;
@@ -47,22 +65,65 @@ struct elf_phdr {
uint64_t p_align;
};
-struct elf_shdr {
- uint32_t sh_name;
- uint32_t sh_type;
- uint64_t sh_flags;
- uint64_t sh_addr;
- uint64_t sh_offset;
- uint64_t sh_size;
- uint32_t sh_link;
- uint32_t sh_info;
- uint64_t sh_addralign;
- uint64_t sh_entsize;
+struct elf32_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;
+ uint32_t p_align;
+};
+
+struct elf64_shdr {
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint64_t sh_flags;
+ uint64_t sh_addr;
+ uint64_t sh_offset;
+ uint64_t sh_size;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ uint64_t sh_addralign;
+ uint64_t sh_entsize;
+};
+
+struct elf32_shdr {
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint32_t sh_flags;
+ uint32_t sh_addr;
+ uint32_t sh_offset;
+ uint32_t sh_size;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ uint32_t sh_addralign;
+ uint32_t sh_entsize;
};
-int elf_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
- struct elf_hdr hdr;
- fread(fd, &hdr, 0, sizeof(struct elf_hdr));
+int elf_bits(struct file_handle *fd) {
+ struct elf64_hdr hdr;
+ fread(fd, &hdr, 0, 20);
+
+ if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
+ print("elf: Not a valid ELF file.\n");
+ return -1;
+ }
+
+ switch (hdr.machine) {
+ case ARCH_X86_64:
+ return 64;
+ case ARCH_X86_32:
+ return 32;
+ default:
+ return -1;
+ }
+}
+
+int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
+ struct elf64_hdr hdr;
+ fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
print("elf: Not a valid ELF file.\n");
@@ -79,17 +140,17 @@ int elf_load_section(struct file_handle *fd, void *buffer, const char *name, siz
return 1;
}
- struct elf_shdr shstrtab;
- fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf_shdr),
- sizeof(struct elf_shdr));
+ struct elf64_shdr shstrtab;
+ fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf64_shdr),
+ sizeof(struct elf64_shdr));
char names[shstrtab.sh_size];
fread(fd, names, shstrtab.sh_offset, shstrtab.sh_size);
for (uint16_t i = 0; i < hdr.sh_num; i++) {
- struct elf_shdr section;
- fread(fd, §ion, hdr.shoff + i * sizeof(struct elf_shdr),
- sizeof(struct elf_shdr));
+ struct elf64_shdr section;
+ fread(fd, §ion, hdr.shoff + i * sizeof(struct elf64_shdr),
+ sizeof(struct elf64_shdr));
if (!strcmp(&names[section.sh_name], name)) {
if (section.sh_size > limit)
@@ -102,11 +163,53 @@ int elf_load_section(struct file_handle *fd, void *buffer, const char *name, siz
return 2;
}
-#define FIXED_HIGHER_HALF_OFFSET ((uint64_t)0xffffffff80000000)
+int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
+ struct elf32_hdr hdr;
+ fread(fd, &hdr, 0, sizeof(struct elf32_hdr));
+
+ if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
+ print("elf: Not a valid ELF file.\n");
+ return 1;
+ }
+
+ if (hdr.ident[EI_DATA] != BITS_LE) {
+ print("elf: Not a Little-endian ELF file.\n");
+ return 1;
+ }
+
+ if (hdr.machine != ARCH_X86_32) {
+ print("elf: Not an x86_32 ELF file.\n");
+ return 1;
+ }
+
+ struct elf32_shdr shstrtab;
+ fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf32_shdr),
+ sizeof(struct elf32_shdr));
+
+ char names[shstrtab.sh_size];
+ fread(fd, names, shstrtab.sh_offset, shstrtab.sh_size);
-int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
- struct elf_hdr hdr;
- fread(fd, &hdr, 0, sizeof(struct elf_hdr));
+ for (uint16_t i = 0; i < hdr.sh_num; i++) {
+ struct elf32_shdr section;
+ fread(fd, §ion, hdr.shoff + i * sizeof(struct elf32_shdr),
+ sizeof(struct elf32_shdr));
+
+ if (!strcmp(&names[section.sh_name], name)) {
+ if (section.sh_size > limit)
+ return 3;
+ fread(fd, buffer, section.sh_offset, section.sh_size);
+ return 0;
+ }
+ }
+
+ return 2;
+}
+
+#define FIXED_HIGHER_HALF_OFFSET_64 ((uint64_t)0xffffffff80000000)
+
+int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
+ struct elf64_hdr hdr;
+ fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
print("Not a valid ELF file.\n");
@@ -126,15 +229,15 @@ int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
*top = 0;
for (uint16_t i = 0; i < hdr.ph_num; i++) {
- struct elf_phdr phdr;
- fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf_phdr),
- sizeof(struct elf_phdr));
+ struct elf64_phdr phdr;
+ fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf64_phdr),
+ sizeof(struct elf64_phdr));
if (phdr.p_type != PT_LOAD)
continue;
- if (phdr.p_vaddr & (1ull << 63))
- phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET;
+ if (phdr.p_vaddr & ((uint64_t)1 << 63))
+ phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET_64;
uint64_t this_top = phdr.p_vaddr + phdr.p_memsz;
if (this_top > *top)
@@ -155,3 +258,51 @@ int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
return 0;
}
+
+int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top) {
+ struct elf32_hdr hdr;
+ fread(fd, &hdr, 0, sizeof(struct elf32_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;
+ }
+
+ if (hdr.machine != ARCH_X86_32) {
+ print("Not an x86_32 ELF file.\n");
+ return -1;
+ }
+
+ *top = 0;
+
+ for (uint16_t i = 0; i < hdr.ph_num; i++) {
+ struct elf32_phdr phdr;
+ fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf32_phdr),
+ sizeof(struct elf32_phdr));
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+
+ uint32_t this_top = phdr.p_vaddr + phdr.p_memsz;
+ if (this_top > *top)
+ *top = this_top;
+
+ fread(fd, (void *)phdr.p_paddr, 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);
+ }
+ }
+
+ *entry_point = hdr.entry;
+
+ return 0;
+}
diff --git a/src/lib/elf.h b/src/lib/elf.h
index 85b57845..0d8d4bc6 100644
--- a/src/lib/elf.h
+++ b/src/lib/elf.h
@@ -4,7 +4,12 @@
#include <stdint.h>
#include <fs/file.h>
-int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top);
-int elf_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
+int elf_bits(struct file_handle *fd);
+
+int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top);
+int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
+
+int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top);
+int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
#endif
diff --git a/src/protos/stivale.c b/src/protos/stivale.c
index 30366562..188e66f2 100644
--- a/src/protos/stivale.c
+++ b/src/protos/stivale.c
@@ -11,7 +11,9 @@
struct stivale_header {
uint64_t stack;
- uint16_t video_mode; // 0 = default at boot (CGA text mode). 1 = graphical VESA
+ // Flags
+ // bit 0 0 = text mode, 1 = graphics mode
+ uint16_t flags;
uint16_t framebuffer_width;
uint16_t framebuffer_height;
uint16_t framebuffer_bpp;
@@ -41,29 +43,44 @@ struct stivale_struct {
struct stivale_struct stivale_struct = {0};
void stivale_load(struct file_handle *fd, char *cmdline) {
- uint64_t entry_point;
-
struct stivale_header stivale_hdr;
- int ret = elf_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+
+ int bits = elf_bits(fd);
+
+ int ret;
+
+ print("stivale: %u-bit ELF file detected\n", bits);
+
+ switch (bits) {
+ case 64:
+ ret = elf64_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+ break;
+ case 32:
+ ret = elf32_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+ break;
+ }
+
switch (ret) {
case 1:
- print("stivale: File is not a valid ELF.\n");
- for (;;);
+ panic("stivale: File is not a valid ELF.\n");
case 2:
- print("stivale: Section .stivalehdr not found.\n");
- for (;;);
+ panic("stivale: Section .stivalehdr not found.\n");
case 3:
- print("stivale: Section .stivalehdr exceeds the size of the struct.\n");
- for (;;);
- default:
- break;
+ panic("stivale: Section .stivalehdr exceeds the size of the struct.\n");
}
print("stivale: Requested stack at %X\n", stivale_hdr.stack);
- print("stivale: Video mode: %u\n", stivale_hdr.video_mode);
- uint64_t top_used_addr;
- elf_load(fd, &entry_point, &top_used_addr);
+ uint64_t entry_point = 0;
+ uint64_t top_used_addr = 0;
+ switch (bits) {
+ case 64:
+ elf64_load(fd, &entry_point, &top_used_addr);
+ break;
+ case 32:
+ elf32_load(fd, (uint32_t *)&entry_point, (uint32_t *)&top_used_addr);
+ break;
+ }
print("stivale: Top used address in ELF: %X\n", top_used_addr);
@@ -115,7 +132,6 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
}
stivale_struct.rsdp = (uint64_t)(size_t)get_rsdp();
- print("stivale: RSDP at %X\n", stivale_struct.rsdp);
stivale_struct.cmdline = (uint64_t)(size_t)cmdline;
@@ -123,7 +139,7 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height;
stivale_struct.framebuffer_bpp = stivale_hdr.framebuffer_bpp;
- if (stivale_hdr.video_mode == 1) {
+ if ((stivale_hdr.flags & 1) == 1) {
init_vbe(&stivale_struct.framebuffer_addr,
&stivale_struct.framebuffer_pitch,
&stivale_struct.framebuffer_width,
@@ -131,61 +147,74 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
&stivale_struct.framebuffer_bpp);
}
- struct pagemap {
- uint64_t pml4[512];
- uint64_t pml3_lo[512];
- uint64_t pml3_hi[512];
- uint64_t pml2_0gb[512];
- uint64_t pml2_1gb[512];
- uint64_t pml2_2gb[512];
- uint64_t pml2_3gb[512];
- };
- struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
-
- // first, zero out the pagemap
- for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
- *p = 0;
-
- pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
- pagemap->pml4[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
- pagemap->pml4[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
- pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
- pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
- pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
- pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
- pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
- pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
-
- // populate the page directories
- for (size_t i = 0; i < 512 * 4; i++)
- (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
-
- asm volatile (
- "cli\n\t"
- "mov cr3, eax\n\t"
- "mov eax, cr4\n\t"
- "or eax, 1 << 5\n\t"
- "mov cr4, eax\n\t"
- "mov ecx, 0xc0000080\n\t"
- "rdmsr\n\t"
- "or eax, 1 << 8\n\t"
- "wrmsr\n\t"
- "mov eax, cr0\n\t"
- "or eax, 1 << 31\n\t"
- "mov cr0, eax\n\t"
- "jmp 0x28:1f\n\t"
- "1: .code64\n\t"
- "mov ax, 0x30\n\t"
- "mov ds, ax\n\t"
- "mov es, ax\n\t"
- "mov fs, ax\n\t"
- "mov gs, ax\n\t"
- "mov ss, ax\n\t"
- "mov rsp, [rsi]\n\t"
- "jmp [rbx]\n\t"
- ".code32\n\t"
- :
- : "a" (pagemap), "b" (&entry_point),
- "D" (&stivale_struct), "S" (&stivale_hdr.stack)
- );
+ if (bits == 64) {
+ struct pagemap {
+ uint64_t pml4[512];
+ uint64_t pml3_lo[512];
+ uint64_t pml3_hi[512];
+ uint64_t pml2_0gb[512];
+ uint64_t pml2_1gb[512];
+ uint64_t pml2_2gb[512];
+ uint64_t pml2_3gb[512];
+ };
+ struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
+
+ // first, zero out the pagemap
+ for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
+ *p = 0;
+
+ pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
+ pagemap->pml4[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
+ pagemap->pml4[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
+ pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
+ pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
+ pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
+ pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
+ pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
+ pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
+
+ // populate the page directories
+ for (size_t i = 0; i < 512 * 4; i++)
+ (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
+
+ asm volatile (
+ "cli\n\t"
+ "cld\n\t"
+ "mov cr3, eax\n\t"
+ "mov eax, cr4\n\t"
+ "or eax, 1 << 5\n\t"
+ "mov cr4, eax\n\t"
+ "mov ecx, 0xc0000080\n\t"
+ "rdmsr\n\t"
+ "or eax, 1 << 8\n\t"
+ "wrmsr\n\t"
+ "mov eax, cr0\n\t"
+ "or eax, 1 << 31\n\t"
+ "mov cr0, eax\n\t"
+ "jmp 0x28:1f\n\t"
+ "1: .code64\n\t"
+ "mov ax, 0x30\n\t"
+ "mov ds, ax\n\t"
+ "mov es, ax\n\t"
+ "mov fs, ax\n\t"
+ "mov gs, ax\n\t"
+ "mov ss, ax\n\t"
+ "mov rsp, [rsi]\n\t"
+ "call [rbx]\n\t"
+ ".code32\n\t"
+ :
+ : "a" (pagemap), "b" (&entry_point),
+ "D" (&stivale_struct), "S" (&stivale_hdr.stack)
+ );
+ } else if (bits == 32) {
+ asm volatile (
+ "cli\n\t"
+ "cld\n\t"
+ "mov esp, [esi]\n\t"
+ "push edi\n\t"
+ "call [ebx]\n\t"
+ :
+ : "b" (&entry_point), "D" (&stivale_struct), "S" (&stivale_hdr.stack)
+ );
+ }
}
diff --git a/test/qloader2.cfg b/test/qloader2.cfg
index 9afddf1b..d5799bcd 100644
--- a/test/qloader2.cfg
+++ b/test/qloader2.cfg
@@ -1,14 +1,14 @@
TIMEOUT=3
-KERNEL_PARTITION=0
+KERNEL_PARTITION=1
KERNEL_PATH=test.elf
KERNEL_PROTO=stivale
KERNEL_CMDLINE=none
-MODULE_PARTITION=0
+MODULE_PARTITION=1
MODULE_PATH=qloader2.cfg
MODULE_STRING=something here
-MODULE_PARTITION=0
+MODULE_PARTITION=1
MODULE_PATH=qloader2.cfg
MODULE_STRING=second module
