machdep_boot.c revision 331524
1/*- 2 * Copyright (c) 2004 Olivier Houchard 3 * Copyright (c) 1994-1998 Mark Brinicombe. 4 * Copyright (c) 1994 Brini. 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 "opt_platform.h" 30#include "opt_ddb.h" 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/11/sys/arm/arm/machdep_boot.c 331524 2018-03-25 02:04:44Z ian $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/ctype.h> 38#include <sys/linker.h> 39#include <sys/reboot.h> 40#include <sys/sysctl.h> 41#if defined(LINUX_BOOT_ABI) 42#include <sys/boot.h> 43#endif 44 45#include <machine/atags.h> 46#include <machine/cpu.h> 47#include <machine/machdep.h> 48#include <machine/metadata.h> 49#include <machine/physmem.h> 50#include <machine/vmparam.h> /* For KERNVIRTADDR */ 51 52#ifdef FDT 53#include <contrib/libfdt/libfdt.h> 54#include <dev/fdt/fdt_common.h> 55#endif 56 57#ifdef EFI 58#include <sys/efi.h> 59#endif 60 61#ifdef DDB 62#include <ddb/ddb.h> 63#endif 64 65#ifdef DEBUG 66#define debugf(fmt, args...) printf(fmt, ##args) 67#else 68#define debugf(fmt, args...) 69#endif 70 71extern int *end; 72 73static uint32_t board_revision; 74/* hex representation of uint64_t */ 75static char board_serial[32]; 76static char *loader_envp; 77 78#if defined(LINUX_BOOT_ABI) 79#define LBABI_MAX_BANKS 10 80#define CMDLINE_GUARD "FreeBSD:" 81static uint32_t board_id; 82static struct arm_lbabi_tag *atag_list; 83static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1]; 84static char atags[LBABI_MAX_COMMAND_LINE * 2]; 85#endif /* defined(LINUX_BOOT_ABI) */ 86 87SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes"); 88SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD, 89 &board_revision, 0, "Board revision"); 90SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD, 91 board_serial, 0, "Board serial"); 92 93int vfp_exists; 94SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, 95 &vfp_exists, 0, "Floating point support enabled"); 96 97void 98board_set_serial(uint64_t serial) 99{ 100 101 snprintf(board_serial, sizeof(board_serial)-1, 102 "%016jx", serial); 103} 104 105void 106board_set_revision(uint32_t revision) 107{ 108 109 board_revision = revision; 110} 111 112static char * 113kenv_next(char *cp) 114{ 115 116 if (cp != NULL) { 117 while (*cp != 0) 118 cp++; 119 cp++; 120 if (*cp == 0) 121 cp = NULL; 122 } 123 return (cp); 124} 125 126void 127arm_print_kenv(void) 128{ 129 char *cp; 130 131 debugf("loader passed (static) kenv:\n"); 132 if (loader_envp == NULL) { 133 debugf(" no env, null ptr\n"); 134 return; 135 } 136 debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp); 137 138 for (cp = loader_envp; cp != NULL; cp = kenv_next(cp)) 139 debugf(" %x %s\n", (uint32_t)cp, cp); 140} 141 142 143#if defined(LINUX_BOOT_ABI) 144 145/* Convert the U-Boot command line into FreeBSD kenv and boot options. */ 146static void 147cmdline_set_env(char *cmdline, const char *guard) 148{ 149 char *cmdline_next, *env; 150 size_t size, guard_len; 151 int i; 152 153 size = strlen(cmdline); 154 /* Skip leading spaces. */ 155 for (; isspace(*cmdline) && (size > 0); cmdline++) 156 size--; 157 158 /* Test and remove guard. */ 159 if (guard != NULL && guard[0] != '\0') { 160 guard_len = strlen(guard); 161 if (strncasecmp(cmdline, guard, guard_len) != 0) 162 return; 163 cmdline += guard_len; 164 size -= guard_len; 165 } 166 167 /* Skip leading spaces. */ 168 for (; isspace(*cmdline) && (size > 0); cmdline++) 169 size--; 170 171 /* Replace ',' with '\0'. */ 172 /* TODO: implement escaping for ',' character. */ 173 cmdline_next = cmdline; 174 while(strsep(&cmdline_next, ",") != NULL) 175 ; 176 init_static_kenv(cmdline, 0); 177 /* Parse boothowto. */ 178 for (i = 0; howto_names[i].ev != NULL; i++) { 179 env = kern_getenv(howto_names[i].ev); 180 if (env != NULL) { 181 if (strtoul(env, NULL, 10) != 0) 182 boothowto |= howto_names[i].mask; 183 freeenv(env); 184 } 185 } 186} 187 188void arm_parse_fdt_bootargs(void) 189{ 190 191#ifdef FDT 192 if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line, 193 LBABI_MAX_COMMAND_LINE) == 0) 194 cmdline_set_env(linux_command_line, CMDLINE_GUARD); 195#endif 196} 197 198static vm_offset_t 199linux_parse_boot_param(struct arm_boot_params *abp) 200{ 201 struct arm_lbabi_tag *walker; 202 uint32_t revision; 203 uint64_t serial; 204 int size; 205 vm_offset_t lastaddr; 206#ifdef FDT 207 struct fdt_header *dtb_ptr; 208 uint32_t dtb_size; 209#endif 210 211 /* 212 * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 213 * is atags or dtb pointer. If all of these aren't satisfied, 214 * then punt. Unfortunately, it looks like DT enabled kernels 215 * doesn't uses board type and U-Boot delivers 0 in r1 for them. 216 */ 217 if (abp->abp_r0 != 0 || abp->abp_r2 == 0) 218 return (0); 219#ifdef FDT 220 /* Test if r2 point to valid DTB. */ 221 dtb_ptr = (struct fdt_header *)abp->abp_r2; 222 if (fdt_check_header(dtb_ptr) == 0) { 223 dtb_size = fdt_totalsize(dtb_ptr); 224 return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); 225 } 226#endif 227 228 board_id = abp->abp_r1; 229 walker = (struct arm_lbabi_tag *)abp->abp_r2; 230 231 if (ATAG_TAG(walker) != ATAG_CORE) 232 return 0; 233 234 atag_list = walker; 235 while (ATAG_TAG(walker) != ATAG_NONE) { 236 switch (ATAG_TAG(walker)) { 237 case ATAG_CORE: 238 break; 239 case ATAG_MEM: 240 arm_physmem_hardware_region(walker->u.tag_mem.start, 241 walker->u.tag_mem.size); 242 break; 243 case ATAG_INITRD2: 244 break; 245 case ATAG_SERIAL: 246 serial = walker->u.tag_sn.high; 247 serial <<= 32; 248 serial |= walker->u.tag_sn.low; 249 board_set_serial(serial); 250 break; 251 case ATAG_REVISION: 252 revision = walker->u.tag_rev.rev; 253 board_set_revision(revision); 254 break; 255 case ATAG_CMDLINE: 256 size = ATAG_SIZE(walker) - 257 sizeof(struct arm_lbabi_header); 258 size = min(size, LBABI_MAX_COMMAND_LINE); 259 strncpy(linux_command_line, walker->u.tag_cmd.command, 260 size); 261 linux_command_line[size] = '\0'; 262 break; 263 default: 264 break; 265 } 266 walker = ATAG_NEXT(walker); 267 } 268 269 /* Save a copy for later */ 270 bcopy(atag_list, atags, 271 (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); 272 273 lastaddr = fake_preload_metadata(abp, NULL, 0); 274 cmdline_set_env(linux_command_line, CMDLINE_GUARD); 275 return lastaddr; 276} 277#endif 278 279#if defined(FREEBSD_BOOT_LOADER) 280static vm_offset_t 281freebsd_parse_boot_param(struct arm_boot_params *abp) 282{ 283 vm_offset_t lastaddr = 0; 284 void *mdp; 285 void *kmdp; 286#ifdef DDB 287 vm_offset_t ksym_start; 288 vm_offset_t ksym_end; 289#endif 290 291 /* 292 * Mask metadata pointer: it is supposed to be on page boundary. If 293 * the first argument (mdp) doesn't point to a valid address the 294 * bootloader must have passed us something else than the metadata 295 * ptr, so we give up. Also give up if we cannot find metadta section 296 * the loader creates that we get all this data out of. 297 */ 298 299 if ((mdp = (void *)(abp->abp_r0 & ~PAGE_MASK)) == NULL) 300 return 0; 301 preload_metadata = mdp; 302 kmdp = preload_search_by_type("elf kernel"); 303 if (kmdp == NULL) 304 return 0; 305 306 boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 307 loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); 308 init_static_kenv(loader_envp, 0); 309 lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); 310#ifdef DDB 311 ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); 312 ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); 313 db_fetch_ksymtab(ksym_start, ksym_end); 314#endif 315 return lastaddr; 316} 317#endif 318 319vm_offset_t 320default_parse_boot_param(struct arm_boot_params *abp) 321{ 322 vm_offset_t lastaddr; 323 324#if defined(LINUX_BOOT_ABI) 325 if ((lastaddr = linux_parse_boot_param(abp)) != 0) 326 return lastaddr; 327#endif 328#if defined(FREEBSD_BOOT_LOADER) 329 if ((lastaddr = freebsd_parse_boot_param(abp)) != 0) 330 return lastaddr; 331#endif 332 /* Fall back to hardcoded metadata. */ 333 lastaddr = fake_preload_metadata(abp, NULL, 0); 334 335 return lastaddr; 336} 337 338/* 339 * Stub version of the boot parameter parsing routine. We are 340 * called early in initarm, before even VM has been initialized. 341 * This routine needs to preserve any data that the boot loader 342 * has passed in before the kernel starts to grow past the end 343 * of the BSS, traditionally the place boot-loaders put this data. 344 * 345 * Since this is called so early, things that depend on the vm system 346 * being setup (including access to some SoC's serial ports), about 347 * all that can be done in this routine is to copy the arguments. 348 * 349 * This is the default boot parameter parsing routine. Individual 350 * kernels/boards can override this weak function with one of their 351 * own. We just fake metadata... 352 */ 353__weak_reference(default_parse_boot_param, parse_boot_param); 354 355 356/* 357 * Fake up a boot descriptor table 358 */ 359vm_offset_t 360fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr, 361 size_t dtb_size) 362{ 363#ifdef DDB 364 vm_offset_t zstart = 0, zend = 0; 365#endif 366 vm_offset_t lastaddr; 367 int i = 0; 368 static uint32_t fake_preload[35]; 369 370 fake_preload[i++] = MODINFO_NAME; 371 fake_preload[i++] = strlen("kernel") + 1; 372 strcpy((char*)&fake_preload[i++], "kernel"); 373 i += 1; 374 fake_preload[i++] = MODINFO_TYPE; 375 fake_preload[i++] = strlen("elf kernel") + 1; 376 strcpy((char*)&fake_preload[i++], "elf kernel"); 377 i += 2; 378 fake_preload[i++] = MODINFO_ADDR; 379 fake_preload[i++] = sizeof(vm_offset_t); 380 fake_preload[i++] = KERNVIRTADDR; 381 fake_preload[i++] = MODINFO_SIZE; 382 fake_preload[i++] = sizeof(uint32_t); 383 fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR; 384#ifdef DDB 385 if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) { 386 fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM; 387 fake_preload[i++] = sizeof(vm_offset_t); 388 fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4); 389 fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM; 390 fake_preload[i++] = sizeof(vm_offset_t); 391 fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8); 392 lastaddr = *(uint32_t *)(KERNVIRTADDR + 8); 393 zend = lastaddr; 394 zstart = *(uint32_t *)(KERNVIRTADDR + 4); 395 db_fetch_ksymtab(zstart, zend); 396 } else 397#endif 398 lastaddr = (vm_offset_t)&end; 399 if (dtb_ptr != NULL) { 400 /* Copy DTB to KVA space and insert it into module chain. */ 401 lastaddr = roundup(lastaddr, sizeof(int)); 402 fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP; 403 fake_preload[i++] = sizeof(uint32_t); 404 fake_preload[i++] = (uint32_t)lastaddr; 405 memmove((void *)lastaddr, dtb_ptr, dtb_size); 406 lastaddr += dtb_size; 407 lastaddr = roundup(lastaddr, sizeof(int)); 408 } 409 fake_preload[i++] = 0; 410 fake_preload[i] = 0; 411 preload_metadata = (void *)fake_preload; 412 413 init_static_kenv(NULL, 0); 414 415 return (lastaddr); 416} 417 418#ifdef EFI 419void 420arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr, 421 int *mrcnt) 422{ 423 struct efi_md *map, *p; 424 const char *type; 425 size_t efisz, memory_size; 426 int ndesc, i, j; 427 428 static const char *types[] = { 429 "Reserved", 430 "LoaderCode", 431 "LoaderData", 432 "BootServicesCode", 433 "BootServicesData", 434 "RuntimeServicesCode", 435 "RuntimeServicesData", 436 "ConventionalMemory", 437 "UnusableMemory", 438 "ACPIReclaimMemory", 439 "ACPIMemoryNVS", 440 "MemoryMappedIO", 441 "MemoryMappedIOPortSpace", 442 "PalCode", 443 "PersistentMemory" 444 }; 445 446 *mrcnt = 0; 447 448 /* 449 * Memory map data provided by UEFI via the GetMemoryMap 450 * Boot Services API. 451 */ 452 efisz = roundup2(sizeof(struct efi_map_header), 0x10); 453 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 454 455 if (efihdr->descriptor_size == 0) 456 return; 457 ndesc = efihdr->memory_size / efihdr->descriptor_size; 458 459 if (boothowto & RB_VERBOSE) 460 printf("%23s %12s %12s %8s %4s\n", 461 "Type", "Physical", "Virtual", "#Pages", "Attr"); 462 463 memory_size = 0; 464 for (i = 0, j = 0, p = map; i < ndesc; i++, 465 p = efi_next_descriptor(p, efihdr->descriptor_size)) { 466 if (boothowto & RB_VERBOSE) { 467 if (p->md_type < nitems(types)) 468 type = types[p->md_type]; 469 else 470 type = "<INVALID>"; 471 printf("%23s %012llx %12p %08llx ", type, p->md_phys, 472 p->md_virt, p->md_pages); 473 if (p->md_attr & EFI_MD_ATTR_UC) 474 printf("UC "); 475 if (p->md_attr & EFI_MD_ATTR_WC) 476 printf("WC "); 477 if (p->md_attr & EFI_MD_ATTR_WT) 478 printf("WT "); 479 if (p->md_attr & EFI_MD_ATTR_WB) 480 printf("WB "); 481 if (p->md_attr & EFI_MD_ATTR_UCE) 482 printf("UCE "); 483 if (p->md_attr & EFI_MD_ATTR_WP) 484 printf("WP "); 485 if (p->md_attr & EFI_MD_ATTR_RP) 486 printf("RP "); 487 if (p->md_attr & EFI_MD_ATTR_XP) 488 printf("XP "); 489 if (p->md_attr & EFI_MD_ATTR_NV) 490 printf("NV "); 491 if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE) 492 printf("MORE_RELIABLE "); 493 if (p->md_attr & EFI_MD_ATTR_RO) 494 printf("RO "); 495 if (p->md_attr & EFI_MD_ATTR_RT) 496 printf("RUNTIME"); 497 printf("\n"); 498 } 499 500 switch (p->md_type) { 501 case EFI_MD_TYPE_CODE: 502 case EFI_MD_TYPE_DATA: 503 case EFI_MD_TYPE_BS_CODE: 504 case EFI_MD_TYPE_BS_DATA: 505 case EFI_MD_TYPE_FREE: 506 /* 507 * We're allowed to use any entry with these types. 508 */ 509 break; 510 default: 511 continue; 512 } 513 514 j++; 515 if (j >= FDT_MEM_REGIONS) 516 break; 517 518 mr[j].mr_start = p->md_phys; 519 mr[j].mr_size = p->md_pages * PAGE_SIZE; 520 memory_size += mr[j].mr_size; 521 } 522 523 *mrcnt = j; 524} 525#endif /* EFI */ 526