1#include <sys/types.h> 2#include <sys/stat.h> 3 4#include <assert.h> 5#include <errno.h> 6#include <stdint.h> 7#include <stdio.h> 8#include <stdlib.h> 9 10#include <libelf.h> 11#include <multiboot2.h> 12 13#include "efi.h" 14 15void usage(char *name) { 16 fprintf(stderr, "usage: %s <multiboot image> <load address> " 17 "<offset of mb header>\n", name); 18 exit(EXIT_FAILURE); 19} 20 21void fail(char *name) { 22 perror(name); 23 exit(EXIT_FAILURE); 24} 25 26void elf_fail(char *name) { 27 fprintf(stderr, "%s: %s\n", name, elf_errmsg(elf_errno())); 28 exit(EXIT_FAILURE); 29} 30 31/* Read the complete contents of a file. */ 32void * 33load_file(const char *path, size_t *length) { 34 FILE *file= fopen(path, "r"); 35 if(!file) fail("fopen"); 36 37 struct stat stat; 38 if(fstat(fileno(file), &stat) < 0) fail("stat"); 39 40 char *buf= malloc(stat.st_size); 41 if(!buf) fail("malloc"); 42 43 if(fread(buf, 1, stat.st_size, file) != stat.st_size) fail("fread"); 44 45 if(fclose(file) != 0) fail("fclose"); 46 47 *length= stat.st_size; 48 return buf; 49} 50 51int 52main(int argc, char *argv[]) { 53 if(argc != 4) usage(argv[0]); 54 55 const char *infile= argv[1]; 56 57 errno= 0; 58 uint64_t load_addr= strtoul(argv[2], NULL, 0); 59 if(errno) fail("strtoul"); 60 61 errno= 0; 62 uint64_t offset= strtoul(argv[3], NULL, 0); 63 if(errno) fail("strtoul"); 64 65 if(elf_version(EV_CURRENT) == EV_NONE) elf_fail("elf_version"); 66 67 printf("Loading multiboot image \"%s\" at 0x%lx\n", infile, load_addr); 68 69 /* Load it. */ 70 size_t mb_len; 71 void *mb_data= load_file(infile, &mb_len); 72 73 /* Start walking the header. */ 74 void *cursor= mb_data + offset; 75 76 /* Check the fixed 8-byte header. */ 77 uint32_t total_size= *((uint32_t *)cursor); 78 cursor+= sizeof(uint32_t); 79 assert(*((uint32_t *)cursor) == 0); 80 cursor+= sizeof(uint32_t); 81 82 /* Read the tags. */ 83 while(cursor < mb_data + offset + total_size) { 84 uint64_t paddr= (cursor - mb_data) + load_addr; 85 struct multiboot_tag *tag= 86 (struct multiboot_tag *)cursor; 87 88 printf("Tag of %uB @ 0x%lx\n", (unsigned int)tag->size, paddr); 89 switch(tag->type) { 90 case MULTIBOOT_TAG_TYPE_CMDLINE: 91 { 92 struct multiboot_tag_string *str_tag= 93 (struct multiboot_tag_string *)cursor; 94 printf("CPU driver command line: \"%s\"\n", 95 str_tag->string); 96 break; 97 } 98 case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: 99 { 100 struct multiboot_tag_elf_sections *sect_tag= 101 (struct multiboot_tag_elf_sections *)cursor; 102 printf("CPU driver ELF section headers\n"); 103 printf("%u headers of size %u\n", 104 sect_tag->num, sect_tag->entsize); 105 printf("String table in section %u\n", 106 sect_tag->shndx); 107 108 Elf64_Shdr *shdrs= (Elf64_Shdr *)sect_tag->sections; 109 for(size_t i= 0; i < sect_tag->num; i++) { 110 printf("section %lu, type %u, address 0x%lx\n", 111 i, shdrs[i].sh_type, shdrs[i].sh_addr); 112 } 113 break; 114 } 115 case MULTIBOOT_TAG_TYPE_MODULE_64: 116 { 117 struct multiboot_tag_module_64 *mod_tag= 118 (struct multiboot_tag_module_64 *)cursor; 119 printf("64-bit ELF module @ 0x%lx-0x%lx\n", 120 (uint64_t)mod_tag->mod_start, 121 (uint64_t)mod_tag->mod_end); 122 printf("Command line: \"%s\"\n", mod_tag->cmdline); 123 124 void *elf_data= mb_data + (mod_tag->mod_start - load_addr); 125 size_t elf_size= mod_tag->mod_end - mod_tag->mod_start + 1; 126 127 Elf *elf= elf_memory(elf_data, elf_size); 128 if(!elf) elf_fail("elf_memory"); 129 130 size_t e_i_size; 131 char *e_ident= elf_getident(elf, &e_i_size); 132 if(!e_ident) elf_fail("elf_getident"); 133 134 printf("e_ident bytes:"); 135 for(int i= 0; i < e_i_size; i++) 136 printf(" %02x", e_ident[i]); 137 printf("\n"); 138 139 Elf64_Ehdr *ehdr= elf64_getehdr(elf); 140 if(!ehdr) elf_fail("elf64_getehdr"); 141 142 printf("Entry point: %lx\n", ehdr->e_entry); 143 144 if(elf_end(elf)) elf_fail("elf_end"); 145 break; 146 } 147 case MULTIBOOT_TAG_TYPE_EFI_MMAP: 148 { 149 struct multiboot_tag_efi_mmap *mmap_tag= 150 (struct multiboot_tag_efi_mmap *)cursor; 151 size_t mmap_len= mmap_tag->size / mmap_tag->descr_size; 152 print_mmap((efi_memory_descriptor *)&mmap_tag->efi_mmap, 153 mmap_len); 154 break; 155 } 156 } 157 printf("\n"); 158 159 cursor+= tag->size; 160 } 161} 162