1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2004, 2006 Marcel Moolenaar 4 * Copyright (c) 2014 The FreeBSD Foundation 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <stand.h> 33 #include <string.h> 34 #include <sys/param.h> 35 #include <sys/linker.h> 36 #include <sys/reboot.h> 37 #include <sys/boot.h> 38 #include <machine/cpufunc.h> 39 #include <machine/elf.h> 40 #include <machine/metadata.h> 41 #include <machine/psl.h> 42 43 #include <efi.h> 44 #include <efilib.h> 45 46 #include "bootstrap.h" 47 #include "loader_efi.h" 48 49 #if defined(__amd64__) 50 #include <machine/specialreg.h> 51 #endif 52 53 #include "framebuffer.h" 54 55 #if defined(LOADER_FDT_SUPPORT) 56 #include <fdt_platform.h> 57 #endif 58 59 #ifdef LOADER_GELI_SUPPORT 60 #include "geliboot.h" 61 #endif 62 63 int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); 64 65 extern EFI_SYSTEM_TABLE *ST; 66 67 static int 68 bi_getboothowto(char *kargs) 69 { 70 const char *sw, *tmp; 71 char *opts; 72 char *console; 73 int howto, speed, port; 74 char buf[50]; 75 76 howto = boot_parse_cmdline(kargs); 77 howto |= boot_env_to_howto(); 78 79 console = getenv("console"); 80 if (console != NULL) { 81 if (strcmp(console, "comconsole") == 0) 82 howto |= RB_SERIAL; 83 if (strcmp(console, "nullconsole") == 0) 84 howto |= RB_MUTE; 85 if (strcmp(console, "efi") == 0) { 86 /* 87 * If we found a com port and com speed, we need to tell 88 * the kernel where the serial port is, and how 89 * fast. Ideally, we'd get the port from ACPI, but that 90 * isn't running in the loader. Do the next best thing 91 * by allowing it to be set by a loader.conf variable, 92 * either a EFI specific one, or the compatible 93 * comconsole_port if not. PCI support is needed, but 94 * for that we'd ideally refactor the 95 * libi386/comconsole.c code to have identical behavior. 96 */ 97 tmp = getenv("efi_com_speed"); 98 if (tmp != NULL) { 99 speed = strtol(tmp, NULL, 0); 100 tmp = getenv("efi_com_port"); 101 if (tmp == NULL) 102 tmp = getenv("comconsole_port"); 103 /* XXX fallback to EFI variable set in rc.d? */ 104 if (tmp != NULL) 105 port = strtol(tmp, NULL, 0); 106 else 107 port = 0x3f8; 108 snprintf(buf, sizeof(buf), "io:%d,br:%d", port, 109 speed); 110 env_setenv("hw.uart.console", EV_VOLATILE, buf, 111 NULL, NULL); 112 } 113 } 114 } 115 116 return (howto); 117 } 118 119 /* 120 * Copy the environment into the load area starting at (addr). 121 * Each variable is formatted as <name>=<value>, with a single nul 122 * separating each variable, and a double nul terminating the environment. 123 */ 124 static vm_offset_t 125 bi_copyenv(vm_offset_t start) 126 { 127 struct env_var *ep; 128 vm_offset_t addr, last; 129 size_t len; 130 131 addr = last = start; 132 133 /* Traverse the environment. */ 134 for (ep = environ; ep != NULL; ep = ep->ev_next) { 135 len = strlen(ep->ev_name); 136 if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len) 137 break; 138 addr += len; 139 if (archsw.arch_copyin("=", addr, 1) != 1) 140 break; 141 addr++; 142 if (ep->ev_value != NULL) { 143 len = strlen(ep->ev_value); 144 if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len) 145 break; 146 addr += len; 147 } 148 if (archsw.arch_copyin("", addr, 1) != 1) 149 break; 150 last = ++addr; 151 } 152 153 if (archsw.arch_copyin("", last++, 1) != 1) 154 last = start; 155 return(last); 156 } 157 158 /* 159 * Copy module-related data into the load area, where it can be 160 * used as a directory for loaded modules. 161 * 162 * Module data is presented in a self-describing format. Each datum 163 * is preceded by a 32-bit identifier and a 32-bit size field. 164 * 165 * Currently, the following data are saved: 166 * 167 * MOD_NAME (variable) module name (string) 168 * MOD_TYPE (variable) module type (string) 169 * MOD_ARGS (variable) module parameters (string) 170 * MOD_ADDR sizeof(vm_offset_t) module load address 171 * MOD_SIZE sizeof(size_t) module size 172 * MOD_METADATA (variable) type-specific metadata 173 */ 174 #define COPY32(v, a, c) { \ 175 uint32_t x = (v); \ 176 if (c) \ 177 archsw.arch_copyin(&x, a, sizeof(x)); \ 178 a += sizeof(x); \ 179 } 180 181 #define MOD_STR(t, a, s, c) { \ 182 COPY32(t, a, c); \ 183 COPY32(strlen(s) + 1, a, c); \ 184 if (c) \ 185 archsw.arch_copyin(s, a, strlen(s) + 1); \ 186 a += roundup(strlen(s) + 1, sizeof(u_long)); \ 187 } 188 189 #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 190 #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 191 #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 192 193 #define MOD_VAR(t, a, s, c) { \ 194 COPY32(t, a, c); \ 195 COPY32(sizeof(s), a, c); \ 196 if (c) \ 197 archsw.arch_copyin(&s, a, sizeof(s)); \ 198 a += roundup(sizeof(s), sizeof(u_long)); \ 199 } 200 201 #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 202 #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 203 204 #define MOD_METADATA(a, mm, c) { \ 205 COPY32(MODINFO_METADATA | mm->md_type, a, c); \ 206 COPY32(mm->md_size, a, c); \ 207 if (c) \ 208 archsw.arch_copyin(mm->md_data, a, mm->md_size); \ 209 a += roundup(mm->md_size, sizeof(u_long)); \ 210 } 211 212 #define MOD_END(a, c) { \ 213 COPY32(MODINFO_END, a, c); \ 214 COPY32(0, a, c); \ 215 } 216 217 static vm_offset_t 218 bi_copymodules(vm_offset_t addr) 219 { 220 struct preloaded_file *fp; 221 struct file_metadata *md; 222 int c; 223 uint64_t v; 224 225 c = addr != 0; 226 /* Start with the first module on the list, should be the kernel. */ 227 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 228 MOD_NAME(addr, fp->f_name, c); /* This must come first. */ 229 MOD_TYPE(addr, fp->f_type, c); 230 if (fp->f_args) 231 MOD_ARGS(addr, fp->f_args, c); 232 v = fp->f_addr; 233 #if defined(__arm__) 234 v -= __elfN(relocation_offset); 235 #endif 236 MOD_ADDR(addr, v, c); 237 v = fp->f_size; 238 MOD_SIZE(addr, v, c); 239 for (md = fp->f_metadata; md != NULL; md = md->md_next) 240 if (!(md->md_type & MODINFOMD_NOCOPY)) 241 MOD_METADATA(addr, md, c); 242 } 243 MOD_END(addr, c); 244 return(addr); 245 } 246 247 static EFI_STATUS 248 efi_do_vmap(EFI_MEMORY_DESCRIPTOR *mm, UINTN sz, UINTN mmsz, UINT32 mmver) 249 { 250 EFI_MEMORY_DESCRIPTOR *desc, *viter, *vmap; 251 EFI_STATUS ret; 252 int curr, ndesc, nset; 253 254 nset = 0; 255 desc = mm; 256 ndesc = sz / mmsz; 257 vmap = malloc(sz); 258 if (vmap == NULL) 259 /* This isn't really an EFI error case, but pretend it is */ 260 return (EFI_OUT_OF_RESOURCES); 261 viter = vmap; 262 for (curr = 0; curr < ndesc; 263 curr++, desc = NextMemoryDescriptor(desc, mmsz)) { 264 if ((desc->Attribute & EFI_MEMORY_RUNTIME) != 0) { 265 ++nset; 266 desc->VirtualStart = desc->PhysicalStart; 267 *viter = *desc; 268 viter = NextMemoryDescriptor(viter, mmsz); 269 } 270 } 271 ret = RS->SetVirtualAddressMap(nset * mmsz, mmsz, mmver, vmap); 272 free(vmap); 273 return (ret); 274 } 275 276 static int 277 bi_load_efi_data(struct preloaded_file *kfp) 278 { 279 EFI_MEMORY_DESCRIPTOR *mm; 280 EFI_PHYSICAL_ADDRESS addr; 281 EFI_STATUS status; 282 const char *efi_novmap; 283 size_t efisz; 284 UINTN efi_mapkey; 285 UINTN mmsz, pages, retry, sz; 286 UINT32 mmver; 287 struct efi_map_header *efihdr; 288 bool do_vmap; 289 290 #if defined(__amd64__) || defined(__aarch64__) 291 struct efi_fb efifb; 292 293 if (efi_find_framebuffer(&efifb) == 0) { 294 printf("EFI framebuffer information:\n"); 295 printf("addr, size 0x%jx, 0x%jx\n", efifb.fb_addr, 296 efifb.fb_size); 297 printf("dimensions %d x %d\n", efifb.fb_width, 298 efifb.fb_height); 299 printf("stride %d\n", efifb.fb_stride); 300 printf("masks 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", 301 efifb.fb_mask_red, efifb.fb_mask_green, efifb.fb_mask_blue, 302 efifb.fb_mask_reserved); 303 304 file_addmetadata(kfp, MODINFOMD_EFI_FB, sizeof(efifb), &efifb); 305 } 306 #endif 307 308 do_vmap = true; 309 efi_novmap = getenv("efi_disable_vmap"); 310 if (efi_novmap != NULL) 311 do_vmap = strcasecmp(efi_novmap, "YES") != 0; 312 313 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; 314 315 /* 316 * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with 317 * u-boot which doesn't fill this value when buffer for memory 318 * descriptors is too small (eg. 0 to obtain memory map size) 319 */ 320 mmsz = sizeof(EFI_MEMORY_DESCRIPTOR); 321 322 /* 323 * It is possible that the first call to ExitBootServices may change 324 * the map key. Fetch a new map key and retry ExitBootServices in that 325 * case. 326 */ 327 for (retry = 2; retry > 0; retry--) { 328 /* 329 * Allocate enough pages to hold the bootinfo block and the 330 * memory map EFI will return to us. The memory map has an 331 * unknown size, so we have to determine that first. Note that 332 * the AllocatePages call can itself modify the memory map, so 333 * we have to take that into account as well. The changes to 334 * the memory map are caused by splitting a range of free 335 * memory into two (AFAICT), so that one is marked as being 336 * loader data. 337 */ 338 sz = 0; 339 BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver); 340 sz += mmsz; 341 sz = (sz + 0xf) & ~0xf; 342 pages = EFI_SIZE_TO_PAGES(sz + efisz); 343 status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 344 pages, &addr); 345 if (EFI_ERROR(status)) { 346 printf("%s: AllocatePages error %lu\n", __func__, 347 EFI_ERROR_CODE(status)); 348 return (ENOMEM); 349 } 350 351 /* 352 * Read the memory map and stash it after bootinfo. Align the 353 * memory map on a 16-byte boundary (the bootinfo block is page 354 * aligned). 355 */ 356 efihdr = (struct efi_map_header *)addr; 357 mm = (void *)((uint8_t *)efihdr + efisz); 358 sz = (EFI_PAGE_SIZE * pages) - efisz; 359 360 status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); 361 if (EFI_ERROR(status)) { 362 printf("%s: GetMemoryMap error %lu\n", __func__, 363 EFI_ERROR_CODE(status)); 364 return (EINVAL); 365 } 366 status = BS->ExitBootServices(IH, efi_mapkey); 367 if (EFI_ERROR(status) == 0) { 368 /* 369 * This may be disabled by setting efi_disable_vmap in 370 * loader.conf(5). By default we will setup the virtual 371 * map entries. 372 */ 373 if (do_vmap) 374 efi_do_vmap(mm, sz, mmsz, mmver); 375 efihdr->memory_size = sz; 376 efihdr->descriptor_size = mmsz; 377 efihdr->descriptor_version = mmver; 378 file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, 379 efihdr); 380 return (0); 381 } 382 BS->FreePages(addr, pages); 383 } 384 printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); 385 return (EINVAL); 386 } 387 388 /* 389 * Load the information expected by an amd64 kernel. 390 * 391 * - The 'boothowto' argument is constructed. 392 * - The 'bootdev' argument is constructed. 393 * - The 'bootinfo' struct is constructed, and copied into the kernel space. 394 * - The kernel environment is copied into kernel space. 395 * - Module metadata are formatted and placed in kernel space. 396 */ 397 int 398 bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) 399 { 400 struct preloaded_file *xp, *kfp; 401 struct devdesc *rootdev; 402 struct file_metadata *md; 403 vm_offset_t addr; 404 uint64_t kernend; 405 uint64_t envp; 406 vm_offset_t size; 407 char *rootdevname; 408 int howto; 409 #if defined(LOADER_FDT_SUPPORT) 410 vm_offset_t dtbp; 411 int dtb_size; 412 #endif 413 #if defined(__arm__) 414 vm_offset_t vaddr; 415 size_t i; 416 /* 417 * These metadata addreses must be converted for kernel after 418 * relocation. 419 */ 420 uint32_t mdt[] = { 421 MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, 422 MODINFOMD_ENVP, 423 #if defined(LOADER_FDT_SUPPORT) 424 MODINFOMD_DTBP 425 #endif 426 }; 427 #endif 428 429 howto = bi_getboothowto(args); 430 431 /* 432 * Allow the environment variable 'rootdev' to override the supplied 433 * device. This should perhaps go to MI code and/or have $rootdev 434 * tested/set by MI code before launching the kernel. 435 */ 436 rootdevname = getenv("rootdev"); 437 archsw.arch_getdev((void**)(&rootdev), rootdevname, NULL); 438 if (rootdev == NULL) { 439 printf("Can't determine root device.\n"); 440 return(EINVAL); 441 } 442 443 /* Try reading the /etc/fstab file to select the root device */ 444 getrootmount(efi_fmtdev((void *)rootdev)); 445 446 addr = 0; 447 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 448 if (addr < (xp->f_addr + xp->f_size)) 449 addr = xp->f_addr + xp->f_size; 450 } 451 452 /* Pad to a page boundary. */ 453 addr = roundup(addr, PAGE_SIZE); 454 455 /* Copy our environment. */ 456 envp = addr; 457 addr = bi_copyenv(addr); 458 459 /* Pad to a page boundary. */ 460 addr = roundup(addr, PAGE_SIZE); 461 462 #if defined(LOADER_FDT_SUPPORT) 463 /* Handle device tree blob */ 464 dtbp = addr; 465 dtb_size = fdt_copy(addr); 466 467 /* Pad to a page boundary */ 468 if (dtb_size) 469 addr += roundup(dtb_size, PAGE_SIZE); 470 #endif 471 472 kfp = file_findfile(NULL, "elf kernel"); 473 if (kfp == NULL) 474 kfp = file_findfile(NULL, "elf64 kernel"); 475 if (kfp == NULL) 476 panic("can't find kernel file"); 477 kernend = 0; /* fill it in later */ 478 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 479 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 480 #if defined(LOADER_FDT_SUPPORT) 481 if (dtb_size) 482 file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); 483 else 484 printf("WARNING! Trying to fire up the kernel, but no " 485 "device tree blob found!\n"); 486 #endif 487 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 488 file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); 489 #ifdef LOADER_GELI_SUPPORT 490 geli_export_key_metadata(kfp); 491 #endif 492 bi_load_efi_data(kfp); 493 494 /* Figure out the size and location of the metadata. */ 495 *modulep = addr; 496 size = bi_copymodules(0); 497 kernend = roundup(addr + size, PAGE_SIZE); 498 *kernendp = kernend; 499 500 /* patch MODINFOMD_KERNEND */ 501 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 502 bcopy(&kernend, md->md_data, sizeof kernend); 503 504 #if defined(__arm__) 505 *modulep -= __elfN(relocation_offset); 506 507 /* Do relocation fixup on metadata of each module. */ 508 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 509 for (i = 0; i < nitems(mdt); i++) { 510 md = file_findmetadata(xp, mdt[i]); 511 if (md) { 512 bcopy(md->md_data, &vaddr, sizeof vaddr); 513 vaddr -= __elfN(relocation_offset); 514 bcopy(&vaddr, md->md_data, sizeof vaddr); 515 } 516 } 517 } 518 #endif 519 520 /* Copy module list and metadata. */ 521 (void)bi_copymodules(addr); 522 523 return (0); 524 } 525