1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include "opt_platform.h" 40 #include <sys/param.h> 41 #include <sys/bus.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/disk.h> 45 #include <sys/fcntl.h> 46 #include <sys/malloc.h> 47 #include <sys/smp.h> 48 #include <sys/stat.h> 49 #include <sys/endian.h> 50 51 #include <net/ethernet.h> 52 53 #include <dev/fdt/fdt_common.h> 54 #include <dev/ofw/openfirm.h> 55 #include <dev/ofw/ofw_pci.h> 56 #include <dev/ofw/ofw_bus.h> 57 #include <dev/ofw/ofw_subr.h> 58 59 #include <vm/vm.h> 60 #include <vm/vm_param.h> 61 #include <vm/vm_page.h> 62 63 #include <machine/bus.h> 64 #include <machine/cpu.h> 65 #include <machine/md_var.h> 66 #include <machine/platform.h> 67 #include <machine/ofw_machdep.h> 68 #include <machine/trap.h> 69 70 #include <contrib/libfdt/libfdt.h> 71 72 static void *fdt; 73 int ofw_real_mode; 74 75 #ifdef AIM 76 extern register_t ofmsr[5]; 77 extern void *openfirmware_entry; 78 char save_trap_init[0x2f00]; /* EXC_LAST */ 79 char save_trap_of[0x2f00]; /* EXC_LAST */ 80 81 int ofwcall(void *); 82 static int openfirmware(void *args); 83 84 __inline void 85 ofw_save_trap_vec(char *save_trap_vec) 86 { 87 if (!ofw_real_mode) 88 return; 89 90 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 91 } 92 93 static __inline void 94 ofw_restore_trap_vec(char *restore_trap_vec) 95 { 96 if (!ofw_real_mode) 97 return; 98 99 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 100 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 101 } 102 103 /* 104 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 105 */ 106 register_t ofw_sprg0_save; 107 108 static __inline void 109 ofw_sprg_prepare(void) 110 { 111 if (ofw_real_mode) 112 return; 113 114 /* 115 * Assume that interrupt are disabled at this point, or 116 * SPRG1-3 could be trashed 117 */ 118 #ifdef __powerpc64__ 119 __asm __volatile("mtsprg1 %0\n\t" 120 "mtsprg2 %1\n\t" 121 "mtsprg3 %2\n\t" 122 : 123 : "r"(ofmsr[2]), 124 "r"(ofmsr[3]), 125 "r"(ofmsr[4])); 126 #else 127 __asm __volatile("mfsprg0 %0\n\t" 128 "mtsprg0 %1\n\t" 129 "mtsprg1 %2\n\t" 130 "mtsprg2 %3\n\t" 131 "mtsprg3 %4\n\t" 132 : "=&r"(ofw_sprg0_save) 133 : "r"(ofmsr[1]), 134 "r"(ofmsr[2]), 135 "r"(ofmsr[3]), 136 "r"(ofmsr[4])); 137 #endif 138 } 139 140 static __inline void 141 ofw_sprg_restore(void) 142 { 143 if (ofw_real_mode) 144 return; 145 146 /* 147 * Note that SPRG1-3 contents are irrelevant. They are scratch 148 * registers used in the early portion of trap handling when 149 * interrupts are disabled. 150 * 151 * PCPU data cannot be used until this routine is called ! 152 */ 153 #ifndef __powerpc64__ 154 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 155 #endif 156 } 157 #endif 158 159 static int 160 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 161 { 162 cell_t address_cells, size_cells; 163 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 164 int sz, i, j; 165 phandle_t phandle; 166 167 sz = 0; 168 169 /* 170 * Get #address-cells from root node, defaulting to 1 if it cannot 171 * be found. 172 */ 173 phandle = OF_finddevice("/"); 174 if (OF_getencprop(phandle, "#address-cells", &address_cells, 175 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 176 address_cells = 1; 177 if (OF_getencprop(phandle, "#size-cells", &size_cells, 178 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 179 size_cells = 1; 180 181 /* 182 * Get memory. 183 */ 184 if (node == -1 || (sz = OF_getencprop(node, prop, 185 OFmem, sizeof(OFmem))) <= 0) 186 panic("Physical memory map not found"); 187 188 i = 0; 189 j = 0; 190 while (i < sz/sizeof(cell_t)) { 191 output[j].mr_start = OFmem[i++]; 192 if (address_cells == 2) { 193 output[j].mr_start <<= 32; 194 output[j].mr_start += OFmem[i++]; 195 } 196 197 output[j].mr_size = OFmem[i++]; 198 if (size_cells == 2) { 199 output[j].mr_size <<= 32; 200 output[j].mr_size += OFmem[i++]; 201 } 202 203 if (output[j].mr_start > BUS_SPACE_MAXADDR) 204 continue; 205 206 /* 207 * Constrain memory to that which we can access. 208 * 32-bit AIM can only reference 32 bits of address currently, 209 * but Book-E can access 36 bits. 210 */ 211 if (((uint64_t)output[j].mr_start + 212 (uint64_t)output[j].mr_size - 1) > 213 BUS_SPACE_MAXADDR) { 214 output[j].mr_size = BUS_SPACE_MAXADDR - 215 output[j].mr_start + 1; 216 } 217 218 j++; 219 } 220 sz = j*sizeof(output[0]); 221 222 return (sz); 223 } 224 225 static int 226 excise_fdt_reserved(struct mem_region *avail, int asz) 227 { 228 struct { 229 uint64_t address; 230 uint64_t size; 231 } fdtmap[16]; 232 ssize_t fdtmapsize; 233 phandle_t chosen; 234 int i, j, k; 235 236 chosen = OF_finddevice("/chosen"); 237 fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 238 239 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 240 fdtmap[j].address = be64toh(fdtmap[j].address) & ~PAGE_MASK; 241 fdtmap[j].size = round_page(be64toh(fdtmap[j].size)); 242 } 243 244 KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), 245 ("Exceeded number of FDT reservations")); 246 /* Add a virtual entry for the FDT itself */ 247 if (fdt != NULL) { 248 fdtmap[j].address = (vm_offset_t)fdt & ~PAGE_MASK; 249 fdtmap[j].size = round_page(fdt_totalsize(fdt)); 250 fdtmapsize += sizeof(fdtmap[0]); 251 } 252 253 for (i = 0; i < asz; i++) { 254 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 255 /* 256 * Case 1: Exclusion region encloses complete 257 * available entry. Drop it and move on. 258 */ 259 if (fdtmap[j].address <= avail[i].mr_start && 260 fdtmap[j].address + fdtmap[j].size >= 261 avail[i].mr_start + avail[i].mr_size) { 262 for (k = i+1; k < asz; k++) 263 avail[k-1] = avail[k]; 264 asz--; 265 i--; /* Repeat some entries */ 266 continue; 267 } 268 269 /* 270 * Case 2: Exclusion region starts in available entry. 271 * Trim it to where the entry begins and append 272 * a new available entry with the region after 273 * the excluded region, if any. 274 */ 275 if (fdtmap[j].address >= avail[i].mr_start && 276 fdtmap[j].address < avail[i].mr_start + 277 avail[i].mr_size) { 278 if (fdtmap[j].address + fdtmap[j].size < 279 avail[i].mr_start + avail[i].mr_size) { 280 avail[asz].mr_start = 281 fdtmap[j].address + fdtmap[j].size; 282 avail[asz].mr_size = avail[i].mr_start + 283 avail[i].mr_size - 284 avail[asz].mr_start; 285 asz++; 286 } 287 288 avail[i].mr_size = fdtmap[j].address - 289 avail[i].mr_start; 290 } 291 292 /* 293 * Case 3: Exclusion region ends in available entry. 294 * Move start point to where the exclusion zone ends. 295 * The case of a contained exclusion zone has already 296 * been caught in case 2. 297 */ 298 if (fdtmap[j].address + fdtmap[j].size >= 299 avail[i].mr_start && fdtmap[j].address + 300 fdtmap[j].size < avail[i].mr_start + 301 avail[i].mr_size) { 302 avail[i].mr_size += avail[i].mr_start; 303 avail[i].mr_start = 304 fdtmap[j].address + fdtmap[j].size; 305 avail[i].mr_size -= avail[i].mr_start; 306 } 307 } 308 } 309 310 return (asz); 311 } 312 313 /* 314 * This is called during powerpc_init, before the system is really initialized. 315 * It shall provide the total and the available regions of RAM. 316 * The available regions need not take the kernel into account. 317 */ 318 void 319 ofw_mem_regions(struct mem_region *memp, int *memsz, 320 struct mem_region *availp, int *availsz) 321 { 322 phandle_t phandle; 323 int asz, msz; 324 int res; 325 char name[31]; 326 327 asz = msz = 0; 328 329 /* 330 * Get memory from all the /memory nodes. 331 */ 332 for (phandle = OF_child(OF_peer(0)); phandle != 0; 333 phandle = OF_peer(phandle)) { 334 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 335 continue; 336 if (strncmp(name, "memory", sizeof(name)) != 0 && 337 strncmp(name, "memory@", strlen("memory@")) != 0) 338 continue; 339 340 res = parse_ofw_memory(phandle, "reg", &memp[msz]); 341 msz += res/sizeof(struct mem_region); 342 if (OF_getproplen(phandle, "available") >= 0) 343 res = parse_ofw_memory(phandle, "available", 344 &availp[asz]); 345 else 346 res = parse_ofw_memory(phandle, "reg", &availp[asz]); 347 asz += res/sizeof(struct mem_region); 348 } 349 350 phandle = OF_finddevice("/chosen"); 351 if (OF_hasprop(phandle, "fdtmemreserv")) 352 asz = excise_fdt_reserved(availp, asz); 353 354 *memsz = msz; 355 *availsz = asz; 356 } 357 358 void 359 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 360 { 361 #ifdef AIM 362 ofmsr[0] = mfmsr(); 363 #ifdef __powerpc64__ 364 ofmsr[0] &= ~PSL_SF; 365 #else 366 __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 367 #endif 368 __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 369 __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 370 __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 371 openfirmware_entry = openfirm; 372 373 if (ofmsr[0] & PSL_DR) 374 ofw_real_mode = 0; 375 else 376 ofw_real_mode = 1; 377 378 ofw_save_trap_vec(save_trap_init); 379 #else 380 ofw_real_mode = 1; 381 #endif 382 383 fdt = fdt_ptr; 384 385 #ifdef FDT_DTB_STATIC 386 /* Check for a statically included blob */ 387 if (fdt == NULL) 388 fdt = &fdt_static_dtb; 389 #endif 390 } 391 392 boolean_t 393 OF_bootstrap() 394 { 395 boolean_t status = FALSE; 396 int err = 0; 397 398 #ifdef AIM 399 if (openfirmware_entry != NULL) { 400 if (ofw_real_mode) { 401 status = OF_install(OFW_STD_REAL, 0); 402 } else { 403 #ifdef __powerpc64__ 404 status = OF_install(OFW_STD_32BIT, 0); 405 #else 406 status = OF_install(OFW_STD_DIRECT, 0); 407 #endif 408 } 409 410 if (status != TRUE) 411 return status; 412 413 err = OF_init(openfirmware); 414 } else 415 #endif 416 if (fdt != NULL) { 417 status = OF_install(OFW_FDT, 0); 418 419 if (status != TRUE) 420 return status; 421 422 err = OF_init(fdt); 423 } 424 425 if (err != 0) { 426 OF_install(NULL, 0); 427 status = FALSE; 428 } 429 430 return (status); 431 } 432 433 #ifdef AIM 434 void 435 ofw_quiesce(void) 436 { 437 struct { 438 cell_t name; 439 cell_t nargs; 440 cell_t nreturns; 441 } args; 442 443 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 444 445 args.name = (cell_t)(uintptr_t)"quiesce"; 446 args.nargs = 0; 447 args.nreturns = 0; 448 openfirmware(&args); 449 } 450 451 static int 452 openfirmware_core(void *args) 453 { 454 int result; 455 register_t oldmsr; 456 457 if (openfirmware_entry == NULL) 458 return (-1); 459 460 /* 461 * Turn off exceptions - we really don't want to end up 462 * anywhere unexpected with PCPU set to something strange 463 * or the stack pointer wrong. 464 */ 465 oldmsr = intr_disable(); 466 467 ofw_sprg_prepare(); 468 469 /* Save trap vectors */ 470 ofw_save_trap_vec(save_trap_of); 471 472 /* Restore initially saved trap vectors */ 473 ofw_restore_trap_vec(save_trap_init); 474 475 #ifndef __powerpc64__ 476 /* 477 * Clear battable[] translations 478 */ 479 if (!(cpu_features & PPC_FEATURE_64)) 480 __asm __volatile("mtdbatu 2, %0\n" 481 "mtdbatu 3, %0" : : "r" (0)); 482 isync(); 483 #endif 484 485 result = ofwcall(args); 486 487 /* Restore trap vecotrs */ 488 ofw_restore_trap_vec(save_trap_of); 489 490 ofw_sprg_restore(); 491 492 intr_restore(oldmsr); 493 494 return (result); 495 } 496 497 #ifdef SMP 498 struct ofw_rv_args { 499 void *args; 500 int retval; 501 volatile int in_progress; 502 }; 503 504 static void 505 ofw_rendezvous_dispatch(void *xargs) 506 { 507 struct ofw_rv_args *rv_args = xargs; 508 509 /* NOTE: Interrupts are disabled here */ 510 511 if (PCPU_GET(cpuid) == 0) { 512 /* 513 * Execute all OF calls on CPU 0 514 */ 515 rv_args->retval = openfirmware_core(rv_args->args); 516 rv_args->in_progress = 0; 517 } else { 518 /* 519 * Spin with interrupts off on other CPUs while OF has 520 * control of the machine. 521 */ 522 while (rv_args->in_progress) 523 cpu_spinwait(); 524 } 525 } 526 #endif 527 528 static int 529 openfirmware(void *args) 530 { 531 int result; 532 #ifdef SMP 533 struct ofw_rv_args rv_args; 534 #endif 535 536 if (openfirmware_entry == NULL) 537 return (-1); 538 539 #ifdef SMP 540 if (cold) { 541 result = openfirmware_core(args); 542 } else { 543 rv_args.args = args; 544 rv_args.in_progress = 1; 545 smp_rendezvous(smp_no_rendezvous_barrier, 546 ofw_rendezvous_dispatch, smp_no_rendezvous_barrier, 547 &rv_args); 548 result = rv_args.retval; 549 } 550 #else 551 result = openfirmware_core(args); 552 #endif 553 554 return (result); 555 } 556 557 void 558 OF_reboot() 559 { 560 struct { 561 cell_t name; 562 cell_t nargs; 563 cell_t nreturns; 564 cell_t arg; 565 } args; 566 567 args.name = (cell_t)(uintptr_t)"interpret"; 568 args.nargs = 1; 569 args.nreturns = 0; 570 args.arg = (cell_t)(uintptr_t)"reset-all"; 571 openfirmware_core(&args); /* Don't do rendezvous! */ 572 573 for (;;); /* just in case */ 574 } 575 576 #endif /* AIM */ 577 578 void 579 OF_getetheraddr(device_t dev, u_char *addr) 580 { 581 phandle_t node; 582 583 node = ofw_bus_get_node(dev); 584 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 585 } 586 587 /* 588 * Return a bus handle and bus tag that corresponds to the register 589 * numbered regno for the device referenced by the package handle 590 * dev. This function is intended to be used by console drivers in 591 * early boot only. It works by mapping the address of the device's 592 * register in the address space of its parent and recursively walk 593 * the device tree upward this way. 594 */ 595 int 596 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 597 bus_space_handle_t *handle, bus_size_t *sz) 598 { 599 bus_addr_t addr; 600 bus_size_t size; 601 pcell_t pci_hi; 602 int flags, res; 603 604 res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 605 if (res < 0) 606 return (res); 607 608 if (pci_hi == OFW_PADDR_NOT_PCI) { 609 *tag = &bs_be_tag; 610 flags = 0; 611 } else { 612 *tag = &bs_le_tag; 613 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 614 BUS_SPACE_MAP_PREFETCHABLE: 0; 615 } 616 617 if (sz != NULL) 618 *sz = size; 619 620 return (bus_space_map(*tag, addr, size, flags, handle)); 621 } 622 623