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