machdep_boot.c revision 344383
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 344383 2019-02-20 20:34:43Z kevans $"); 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 71#ifdef LINUX_BOOT_ABI 72static char static_kenv[4096]; 73#endif 74 75extern int *end; 76 77static uint32_t board_revision; 78/* hex representation of uint64_t */ 79static char board_serial[32]; 80static char *loader_envp; 81 82#if defined(LINUX_BOOT_ABI) 83#define LBABI_MAX_BANKS 10 84#define CMDLINE_GUARD "FreeBSD:" 85static uint32_t board_id; 86static struct arm_lbabi_tag *atag_list; 87static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1]; 88static char atags[LBABI_MAX_COMMAND_LINE * 2]; 89#endif /* defined(LINUX_BOOT_ABI) */ 90 91SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes"); 92SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD, 93 &board_revision, 0, "Board revision"); 94SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD, 95 board_serial, 0, "Board serial"); 96 97int vfp_exists; 98SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, 99 &vfp_exists, 0, "Floating point support enabled"); 100 101void 102board_set_serial(uint64_t serial) 103{ 104 105 snprintf(board_serial, sizeof(board_serial)-1, 106 "%016jx", serial); 107} 108 109void 110board_set_revision(uint32_t revision) 111{ 112 113 board_revision = revision; 114} 115 116static char * 117kenv_next(char *cp) 118{ 119 120 if (cp != NULL) { 121 while (*cp != 0) 122 cp++; 123 cp++; 124 if (*cp == 0) 125 cp = NULL; 126 } 127 return (cp); 128} 129 130void 131arm_print_kenv(void) 132{ 133 char *cp; 134 135 debugf("loader passed (static) kenv:\n"); 136 if (loader_envp == NULL) { 137 debugf(" no env, null ptr\n"); 138 return; 139 } 140 debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp); 141 142 for (cp = loader_envp; cp != NULL; cp = kenv_next(cp)) 143 debugf(" %x %s\n", (uint32_t)cp, cp); 144} 145 146 147#if defined(LINUX_BOOT_ABI) 148 149/* Convert the U-Boot command line into FreeBSD kenv and boot options. */ 150static void 151cmdline_set_env(char *cmdline, const char *guard) 152{ 153 char *cmdline_next; 154 size_t size, guard_len; 155 156 size = strlen(cmdline); 157 /* Skip leading spaces. */ 158 for (; isspace(*cmdline) && (size > 0); cmdline++) 159 size--; 160 161 /* Test and remove guard. */ 162 if (guard != NULL && guard[0] != '\0') { 163 guard_len = strlen(guard); 164 if (strncasecmp(cmdline, guard, guard_len) != 0) 165 return; 166 cmdline += guard_len; 167 size -= guard_len; 168 } 169 170 boothowto |= boot_parse_cmdline(); 171} 172 173/* 174 * Called for armv6 and newer. 175 */ 176void arm_parse_fdt_bootargs(void) 177{ 178 179#ifdef FDT 180 if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line, 181 LBABI_MAX_COMMAND_LINE) == 0) { 182 init_static_kenv(static_kenv, sizeof(static_kenv)); 183 cmdline_set_env(linux_command_line, CMDLINE_GUARD); 184 } 185#endif 186} 187 188/* 189 * Called for armv[45]. 190 */ 191static vm_offset_t 192linux_parse_boot_param(struct arm_boot_params *abp) 193{ 194 struct arm_lbabi_tag *walker; 195 uint32_t revision; 196 uint64_t serial; 197 int size; 198 vm_offset_t lastaddr; 199#ifdef FDT 200 struct fdt_header *dtb_ptr; 201 uint32_t dtb_size; 202#endif 203 204 /* 205 * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 206 * is atags or dtb pointer. If all of these aren't satisfied, 207 * then punt. Unfortunately, it looks like DT enabled kernels 208 * doesn't uses board type and U-Boot delivers 0 in r1 for them. 209 */ 210 if (abp->abp_r0 != 0 || abp->abp_r2 == 0) 211 return (0); 212#ifdef FDT 213 /* Test if r2 point to valid DTB. */ 214 dtb_ptr = (struct fdt_header *)abp->abp_r2; 215 if (fdt_check_header(dtb_ptr) == 0) { 216 dtb_size = fdt_totalsize(dtb_ptr); 217 return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); 218 } 219#endif 220 221 board_id = abp->abp_r1; 222 walker = (struct arm_lbabi_tag *)abp->abp_r2; 223 224 if (ATAG_TAG(walker) != ATAG_CORE) 225 return 0; 226 227 atag_list = walker; 228 while (ATAG_TAG(walker) != ATAG_NONE) { 229 switch (ATAG_TAG(walker)) { 230 case ATAG_CORE: 231 break; 232 case ATAG_MEM: 233 arm_physmem_hardware_region(walker->u.tag_mem.start, 234 walker->u.tag_mem.size); 235 break; 236 case ATAG_INITRD2: 237 break; 238 case ATAG_SERIAL: 239 serial = walker->u.tag_sn.high; 240 serial <<= 32; 241 serial |= walker->u.tag_sn.low; 242 board_set_serial(serial); 243 break; 244 case ATAG_REVISION: 245 revision = walker->u.tag_rev.rev; 246 board_set_revision(revision); 247 break; 248 case ATAG_CMDLINE: 249 size = ATAG_SIZE(walker) - 250 sizeof(struct arm_lbabi_header); 251 size = min(size, LBABI_MAX_COMMAND_LINE); 252 strncpy(linux_command_line, walker->u.tag_cmd.command, 253 size); 254 linux_command_line[size] = '\0'; 255 break; 256 default: 257 break; 258 } 259 walker = ATAG_NEXT(walker); 260 } 261 262 /* Save a copy for later */ 263 bcopy(atag_list, atags, 264 (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); 265 266 lastaddr = fake_preload_metadata(abp, NULL, 0); 267 init_static_kenv(static_kenv, sizeof(static_kenv)); 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