1#include <libelf.h> /* FreeBSD libelf */ 2#include <multiboot2.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6 7#include "config.h" 8#include "util.h" 9 10void * 11create_multiboot2_info(struct config *cfg, Elf *elf, size_t mmap_size) { 12 size_t size; 13 struct component_config *cmp; 14 void *cursor; 15 16 size_t shnum; 17 if(elf_getshdrnum(elf, &shnum)) { 18 fprintf(stderr, "elf_getshdrnum: %s\n", 19 elf_errmsg(elf_errno())); 20 return NULL; 21 } 22 23 /* Calculate the boot information size. */ 24 /* Fixed header - there's no struct for this in multiboot.h */ 25 size= 8; 26 /* Kernel command line */ 27 size+= sizeof(struct multiboot_tag_string) 28 + cfg->kernel->args_len+1; 29 /* ELF section headers */ 30 size+= sizeof(struct multiboot_tag_elf_sections) 31 + shnum * sizeof(Elf64_Shdr); 32 /* Kernel module tag, including command line. */ 33 size+= sizeof(struct multiboot_tag_module_64) 34 + cfg->kernel->args_len+1; 35 /* All other modules */ 36 for(cmp= cfg->first_module; cmp; cmp= cmp->next) { 37 size+= sizeof(struct multiboot_tag_module_64) 38 + cmp->args_len+1; 39 } 40 /* EFI memory map */ 41 size+= sizeof(struct multiboot_tag_efi_mmap) 42 + mmap_size; 43 44 cfg->multiboot_size= size; 45 cfg->multiboot_alloc= ROUNDUP(size, PAGE_4k); 46 47 cfg->multiboot= calloc(1, cfg->multiboot_alloc); 48 if(!cfg->multiboot) { 49 perror("calloc"); 50 return NULL; 51 } 52 53 cursor= cfg->multiboot; 54 /* Write the fixed header. */ 55 *((uint32_t *)cursor)= size; /* total_size */ 56 cursor+= sizeof(uint32_t); 57 *((uint32_t *)cursor)= 0; /* reserved */ 58 cursor+= sizeof(uint32_t); 59 60 /* Add the boot command line */ 61 { 62 struct multiboot_tag_string *bootcmd= 63 (struct multiboot_tag_string *)cursor; 64 65 bootcmd->type= MULTIBOOT_TAG_TYPE_CMDLINE; 66 bootcmd->size= sizeof(struct multiboot_tag_string) 67 + cfg->kernel->args_len+1; 68 ntstring(bootcmd->string, 69 cfg->buf + cfg->kernel->args_start, 70 cfg->kernel->args_len); 71 72 cursor+= sizeof(struct multiboot_tag_string) 73 + cfg->kernel->args_len+1; 74 } 75 /* Add the ELF section headers. */ 76 { 77 struct multiboot_tag_elf_sections *sections= 78 (struct multiboot_tag_elf_sections *)cursor; 79 80 size_t shndx; 81 if(elf_getshdrstrndx(elf, &shndx)) { 82 fprintf(stderr, "elf_getshdrstrndx: %s\n", 83 elf_errmsg(elf_errno())); 84 return NULL; 85 } 86 87 sections->type= MULTIBOOT_TAG_TYPE_ELF_SECTIONS; 88 sections->size= sizeof(struct multiboot_tag_elf_sections) 89 + shnum * sizeof(Elf64_Shdr); 90 sections->num= shnum; 91 sections->entsize= sizeof(Elf64_Shdr); 92 sections->shndx= shndx; 93 94 Elf64_Shdr *shdrs= (Elf64_Shdr *)sections->sections; 95 for(size_t i= 0; i < shnum; i++) { 96 Elf_Scn *scn= elf_getscn(elf, i); 97 if(!scn) { 98 fprintf(stderr, "elf_getscn: %s\n", 99 elf_errmsg(elf_errno())); 100 return NULL; 101 } 102 103 Elf64_Shdr *shdr= elf64_getshdr(scn); 104 if(!shdr) { 105 fprintf(stderr, "elf64_getshdr: %s\n", 106 elf_errmsg(elf_errno())); 107 return NULL; 108 } 109 110 memcpy(&shdrs[i], shdr, sizeof(Elf64_Shdr)); 111 } 112 113 cursor+= sizeof(struct multiboot_tag_elf_sections) 114 + shnum * sizeof(Elf64_Shdr); 115 } 116 /* Add the kernel module. */ 117 { 118 struct multiboot_tag_module_64 *kernel= 119 (struct multiboot_tag_module_64 *)cursor; 120 121 kernel->type= MULTIBOOT_TAG_TYPE_MODULE_64; 122 kernel->size= sizeof(struct multiboot_tag_module_64) 123 + cfg->kernel->args_len+1; 124 /* Leave the addresses uninitialised until we've finished allocation, 125 * which needs the multboot image constructed first. */ 126 ntstring(kernel->cmdline, 127 cfg->buf + cfg->kernel->args_start, 128 cfg->kernel->args_len); 129 130 cfg->kernel->tag= kernel; 131 132 cursor+= sizeof(struct multiboot_tag_module_64) 133 + cfg->kernel->args_len+1; 134 } 135 /* Add the remaining modules */ 136 for(cmp= cfg->first_module; cmp; cmp= cmp->next) { 137 struct multiboot_tag_module_64 *module= 138 (struct multiboot_tag_module_64 *)cursor; 139 140 module->type= MULTIBOOT_TAG_TYPE_MODULE_64; 141 module->size= sizeof(struct multiboot_tag_module_64) 142 + cmp->args_len+1; 143 ntstring(module->cmdline, cfg->buf + cmp->args_start, cmp->args_len); 144 145 cmp->tag= module; 146 147 cursor+= sizeof(struct multiboot_tag_module_64) 148 + cmp->args_len+1; 149 } 150 /* Record the position of the memory map, to be filled in after we've 151 * finished doing allocations. */ 152 cfg->mmap_tag= (struct multiboot_tag_efi_mmap *)cursor; 153 cursor+= sizeof(struct multiboot_tag_efi_mmap); 154 cfg->mmap_start= cursor; 155 156 return cfg->multiboot; 157} 158