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