1 /* $NetBSD: exec_multiboot1.c,v 1.3 2019/10/18 01:09:46 manu Exp $ */ 2 3 /* 4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/reboot.h> 31 32 #include <i386/multiboot.h> 33 34 #include <lib/libsa/stand.h> 35 #include <lib/libkern/libkern.h> 36 37 #include "loadfile.h" 38 #include "libi386.h" 39 #include "bootinfo.h" 40 #include "bootmod.h" 41 #include "vbe.h" 42 43 extern struct btinfo_modulelist *btinfo_modulelist; 44 45 void 46 ksyms_addr_set(void *ehdr, void *shdr, void *symbase) 47 { 48 int class; 49 Elf32_Ehdr *ehdr32 = NULL; 50 Elf64_Ehdr *ehdr64 = NULL; 51 uint64_t shnum; 52 int i; 53 54 class = ((Elf_Ehdr *)ehdr)->e_ident[EI_CLASS]; 55 56 switch (class) { 57 case ELFCLASS32: 58 ehdr32 = (Elf32_Ehdr *)ehdr; 59 shnum = ehdr32->e_shnum; 60 break; 61 case ELFCLASS64: 62 ehdr64 = (Elf64_Ehdr *)ehdr; 63 shnum = ehdr64->e_shnum; 64 break; 65 default: 66 panic("Unexpected ELF class"); 67 break; 68 } 69 70 for (i = 0; i < shnum; i++) { 71 Elf64_Shdr *shdrp64 = NULL; 72 Elf32_Shdr *shdrp32 = NULL; 73 uint64_t shtype, shaddr, shsize, shoffset; 74 75 switch(class) { 76 case ELFCLASS64: 77 shdrp64 = &((Elf64_Shdr *)shdr)[i]; 78 shtype = shdrp64->sh_type; 79 shaddr = shdrp64->sh_addr; 80 shsize = shdrp64->sh_size; 81 shoffset = shdrp64->sh_offset; 82 break; 83 case ELFCLASS32: 84 shdrp32 = &((Elf32_Shdr *)shdr)[i]; 85 shtype = shdrp32->sh_type; 86 shaddr = shdrp32->sh_addr; 87 shsize = shdrp32->sh_size; 88 shoffset = shdrp32->sh_offset; 89 break; 90 default: 91 panic("Unexpected ELF class"); 92 break; 93 } 94 95 if (shtype != SHT_SYMTAB && shtype != SHT_STRTAB) 96 continue; 97 98 if (shaddr != 0 || shsize == 0) 99 continue; 100 101 shaddr = (uint64_t)(uintptr_t)(symbase + shoffset); 102 103 switch(class) { 104 case ELFCLASS64: 105 shdrp64->sh_addr = shaddr; 106 break; 107 case ELFCLASS32: 108 shdrp32->sh_addr = shaddr; 109 break; 110 default: 111 panic("Unexpected ELF class"); 112 break; 113 } 114 } 115 116 return; 117 } 118 119 static int 120 exec_multiboot1(struct multiboot_package *mbp) 121 { 122 struct multiboot_info *mbi; 123 struct multiboot_module *mbm; 124 int i, len; 125 char *cmdline; 126 struct bi_modulelist_entry *bim; 127 128 mbi = alloc(sizeof(struct multiboot_info)); 129 mbi->mi_flags = MULTIBOOT_INFO_HAS_MEMORY; 130 131 mbi->mi_mem_upper = mbp->mbp_extmem; 132 mbi->mi_mem_lower = mbp->mbp_basemem; 133 134 if (mbp->mbp_args) { 135 mbi->mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE; 136 len = strlen(mbp->mbp_file) + 1 + strlen(mbp->mbp_args) + 1; 137 cmdline = alloc(len); 138 snprintf(cmdline, len, "%s %s", mbp->mbp_file, mbp->mbp_args); 139 mbi->mi_cmdline = (char *) vtophys(cmdline); 140 } 141 142 /* pull in any modules if necessary */ 143 if (btinfo_modulelist) { 144 mbm = alloc(sizeof(struct multiboot_module) * 145 btinfo_modulelist->num); 146 147 bim = (struct bi_modulelist_entry *) 148 (((char *) btinfo_modulelist) + 149 sizeof(struct btinfo_modulelist)); 150 for (i = 0; i < btinfo_modulelist->num; i++) { 151 mbm[i].mmo_start = bim->base; 152 mbm[i].mmo_end = bim->base + bim->len; 153 mbm[i].mmo_string = (char *)vtophys(bim->path); 154 mbm[i].mmo_reserved = 0; 155 bim++; 156 } 157 mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS; 158 mbi->mi_mods_count = btinfo_modulelist->num; 159 mbi->mi_mods_addr = vtophys(mbm); 160 } 161 162 if (mbp->mbp_marks[MARK_SYM] != 0) { 163 Elf32_Ehdr ehdr; 164 void *shbuf; 165 size_t shlen; 166 u_long shaddr; 167 168 pvbcopy((void *)mbp->mbp_marks[MARK_SYM], &ehdr, sizeof(ehdr)); 169 170 if (memcmp(&ehdr.e_ident, ELFMAG, SELFMAG) != 0) 171 goto skip_ksyms; 172 173 shaddr = mbp->mbp_marks[MARK_SYM] + ehdr.e_shoff; 174 175 shlen = ehdr.e_shnum * ehdr.e_shentsize; 176 shbuf = alloc(shlen); 177 178 pvbcopy((void *)shaddr, shbuf, shlen); 179 ksyms_addr_set(&ehdr, shbuf, 180 (void *)(KERNBASE + mbp->mbp_marks[MARK_SYM])); 181 vpbcopy(shbuf, (void *)shaddr, shlen); 182 183 dealloc(shbuf, shlen); 184 185 mbi->mi_elfshdr_num = ehdr.e_shnum; 186 mbi->mi_elfshdr_size = ehdr.e_shentsize; 187 mbi->mi_elfshdr_addr = shaddr; 188 mbi->mi_elfshdr_shndx = ehdr.e_shstrndx; 189 190 mbi->mi_flags |= MULTIBOOT_INFO_HAS_ELF_SYMS; 191 } 192 skip_ksyms: 193 194 #ifdef DEBUG 195 printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", 196 mbp->mbp_marks[MARK_ENTRY], 197 mbp->mbp_marks[MARK_NSYM], 198 mbp->mbp_marks[MARK_SYM], 199 mbp->mbp_marks[MARK_END]); 200 #endif 201 202 /* Does not return */ 203 multiboot(mbp->mbp_marks[MARK_ENTRY], vtophys(mbi), 204 x86_trunc_page(mbi->mi_mem_lower * 1024), MULTIBOOT_INFO_MAGIC); 205 206 return 0; 207 } 208 209 static void 210 cleanup_multiboot1(struct multiboot_package *mbp) 211 { 212 dealloc(mbp->mbp_header, sizeof(*mbp->mbp_header)); 213 dealloc(mbp, sizeof(*mbp)); 214 215 return; 216 } 217 218 219 struct multiboot_package * 220 probe_multiboot1(const char *path) 221 { 222 int fd = -1; 223 size_t i; 224 char buf[8192 + sizeof(struct multiboot_header)]; 225 ssize_t readen; 226 struct multiboot_package *mbp = NULL; 227 228 if ((fd = open(path, 0)) == -1) 229 goto out; 230 231 readen = read(fd, buf, sizeof(buf)); 232 if (readen < sizeof(struct multiboot_header)) 233 goto out; 234 235 for (i = 0; i < readen; i += 4) { 236 struct multiboot_header *mbh; 237 238 mbh = (struct multiboot_header *)(buf + i); 239 240 if (mbh->mh_magic != MULTIBOOT_HEADER_MAGIC) 241 continue; 242 243 if (mbh->mh_magic + mbh->mh_flags + mbh->mh_checksum) 244 continue; 245 246 mbp = alloc(sizeof(*mbp)); 247 mbp->mbp_version = 1; 248 mbp->mbp_file = path; 249 mbp->mbp_header = alloc(sizeof(*mbp->mbp_header)); 250 mbp->mbp_probe = *probe_multiboot1; 251 mbp->mbp_exec = *exec_multiboot1; 252 mbp->mbp_cleanup = *cleanup_multiboot1; 253 254 memcpy(mbp->mbp_header, mbh, sizeof(*mbp->mbp_header)); 255 256 goto out; 257 258 } 259 260 out: 261 if (fd != -1) 262 close(fd); 263 264 return mbp; 265 } 266