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