diff options
Diffstat (limited to 'src/arch/amd64/mboot.c')
-rw-r--r-- | src/arch/amd64/mboot.c | 246 |
1 files changed, 201 insertions, 45 deletions
diff --git a/src/arch/amd64/mboot.c b/src/arch/amd64/mboot.c index 89fb431..7fd3f62 100644 --- a/src/arch/amd64/mboot.c +++ b/src/arch/amd64/mboot.c @@ -1,71 +1,227 @@ #include "mboot.h" +#include "serial.h" #include "shim.h" #include <lib.h> +#include <stdint.h> + +extern char symtab; +#define kaddr(addr) ((uintptr_t)(&addr)) + +typedef unsigned char mboot_uint8_t; +typedef unsigned short mboot_uint16_t; +typedef unsigned int mboot_uint32_t; +typedef unsigned long long mboot_uint64_t; + +struct mboot_info { + mboot_uint32_t total_size; + mboot_uint32_t reserved; + char tags[]; +}; + +struct mboot_tag { + mboot_uint32_t type; + mboot_uint32_t size; + char data[]; +}; enum mboot_tag_type { MBOOT_CMDLINE = 0, MBOOT_MEMORYMAP = 6, MBOOT_SYMBOLS = 9, - MBOOT_XSDP = 14 + MBOOT_RSDP = 14, + MBOOT_XSDP = 15, }; -static void read_cmdline(struct boot_info *shim_info, char *data, uint8_t len) { - if (len >= CMDLINE_MAX) - len = CMDLINE_MAX; // truncate :( - memcpy(shim_info->cmdline, data, len); - shim_info->cmdline[len] = '\0'; -} +struct mboot_elf_header_layout { + mboot_uint32_t type; + mboot_uint32_t size; + mboot_uint32_t num; + mboot_uint32_t entsize; + mboot_uint32_t shndx; + char elf_section_headers[]; +}; -static void read_memorymap(struct boot_info *shim_info, uint64_t size, uint32_t *data) { - shim_info->map = (struct memory_map *) data; - shim_info->map->size = size; -} +struct mboot_elf_section_header { + mboot_uint32_t sh_name; + mboot_uint32_t sh_type; + mboot_uint64_t sh_flags; + mboot_uint64_t sh_addr; + mboot_uint64_t sh_offset; + mboot_uint64_t sh_size; + mboot_uint32_t sh_link; + mboot_uint32_t sh_info; + mboot_uint64_t sh_addralign; + mboot_uint64_t sh_entsize; +}; -static void read_xsdp(struct boot_info *shim_info, char *data) { - shim_info->acpi_table = (void *) data; -} +struct mboot_memory_segment { + mboot_uint64_t addr; + mboot_uint64_t len; + mboot_uint32_t type; + mboot_uint32_t reserved; +}; -static uint32_t *read_tag(uint32_t *data, struct boot_info *shim_info) { +struct mboot_memory_map { + mboot_uint32_t tag; + mboot_uint32_t size; + mboot_uint32_t entry_size; + mboot_uint32_t entry_version; + struct memory_segment entries[]; +}; + +struct mboot_rsdp { + mboot_uint32_t tag; + mboot_uint32_t size; + mboot_uint8_t rsdp[]; +}; - uint16_t type = *((uint16_t *)data); - uint32_t size = data[1]; +struct mboot_xsdp { + mboot_uint32_t tag; + mboot_uint32_t size; + mboot_uint8_t xsdp[]; +}; - uint8_t data_len = size - 2 * sizeof(uint32_t); +struct mboot_cmdline { + mboot_uint32_t tag; + mboot_uint32_t size; + char cmdline[]; +}; - switch (type) { - case MBOOT_CMDLINE: - read_cmdline(shim_info, (char *)(data + 2), data_len); - break; - case MBOOT_MEMORYMAP: - read_memorymap(shim_info, size, data + 2); - break; - case MBOOT_SYMBOLS: - shim_info->symbol_table = (void *) (data + 2); - break; - case MBOOT_XSDP: - read_xsdp(shim_info, (char *) (data + 2)); - break; - default: - break; - } +static void read_symbols( + struct boot_info *shim_info, + struct mboot_elf_header_layout *layout +) { - if(size % 8 != 0) { - size += 8 - (size % 8); - } + shim_info->symbol_table = layout->elf_section_headers; - return data + size / sizeof(uint32_t); +// struct mboot_elf_section_header *section = +// (struct mboot_elf_section_header *) (layout->elf_section_headers); +// +// for (mboot_uint32_t i = 0; i < layout->num; i++) { +// char buf[20]; +// +// ultoa(i, buf, 10); +// serial_out_str("["); +// serial_out_str(buf); +// serial_out_str("]\t"); +// +// serial_out_str((char *)(kaddr(symtab) + section->sh_name)); +// serial_out('\t'); +// +// ultoa(section->sh_type, buf, 16); +// serial_out_str("type: 0x"); +// serial_out_str(buf); +// serial_out('\t'); +// +// ultoa(section->sh_addr, buf, 16); +// serial_out_str("addr: 0x"); +// serial_out_str(buf); +// serial_out('\t'); +// +// ultoa(section->sh_offset, buf, 16); +// serial_out_str("offset: 0x"); +// serial_out_str(buf); +// serial_out('\n'); +// +// section++; +// } +} + +static void read_cmdline( + struct boot_info *shim_info, + struct mboot_cmdline *cmdline +) { + mboot_uint32_t size = cmdline->size - 8; + if (size >= CMDLINE_MAX) + size = CMDLINE_MAX; // truncate :( + memcpy(shim_info->cmdline, cmdline->cmdline, size); + shim_info->cmdline[size] = '\0'; +} + +static void read_memorymap( + struct boot_info *shim_info, + struct mboot_memory_map *map +) { + int size = map->size - sizeof(mboot_uint32_t) * 4; + int count = size / map->entry_size; + + shim_info->map.entry_count = count; + shim_info->map.entry_length = map->entry_size; + shim_info->map.entries = map->entries; +} + +static void read_rsdp( + struct boot_info *shim_info, + struct mboot_rsdp *rsdp +) { + if (shim_info->acpi_table != NULL) + return; // xsdp is newer and has been loaded + shim_info->acpi_table = rsdp->rsdp; +} + +static void read_xsdp( + struct boot_info *shim_info, + struct mboot_xsdp *xsdp +) { + shim_info->acpi_table = xsdp->xsdp; } void mboot_load_info( - const void *mboot_info, + const void *mboot_data_ptr, struct boot_info *shim_info ) { - uint32_t* data = (uint32_t*) mboot_info; - uint32_t total_size = *data++; - data++; //reserved - while((uint8_t*) data < (uint8_t*) mboot_info + total_size) { - data = read_tag(data, shim_info); - } + memset(shim_info, 0, sizeof(struct boot_info)); + + struct mboot_info *mboot_info = (struct mboot_info *) mboot_data_ptr; + const char *mboot_end = ((char *) mboot_info) + mboot_info->total_size; + + char *tag_ptr = mboot_info->tags; + + while (tag_ptr < mboot_end) { + struct mboot_tag *tag = (struct mboot_tag *) tag_ptr; + + switch (tag->type) { + case MBOOT_CMDLINE: + read_cmdline( + shim_info, + (struct mboot_cmdline *) tag + ); + break; + case MBOOT_MEMORYMAP: + read_memorymap( + shim_info, + (struct mboot_memory_map *) tag + ); + break; + case MBOOT_SYMBOLS: + read_symbols( + shim_info, + (struct mboot_elf_header_layout *) tag + ); + break; + case MBOOT_RSDP: + read_rsdp( + shim_info, + (struct mboot_rsdp *) tag + ); + break; + case MBOOT_XSDP: + read_xsdp( + shim_info, + (struct mboot_xsdp *) tag + ); + break; + default: + break; + } + + int size = tag->size; + if (size % 8 != 0) { + size += 8 - (size % 8); + } + + tag_ptr += size; + } } |