1 /* $NetBSD: ofw.c,v 1.13 2002/04/05 16:58:11 thorpej Exp $ */ 2 3 /* 4 * Copyright 1997 5 * Digital Equipment Corporation. All rights reserved. 6 * 7 * This software is furnished under license and may be used and 8 * copied only in accordance with the following terms and conditions. 9 * Subject to these conditions, you may download, copy, install, 10 * use, modify and distribute this software in source and/or binary 11 * form. No title or ownership is transferred hereby. 12 * 13 * 1) Any source code used, modified or distributed must reproduce 14 * and retain this copyright notice and list of conditions as 15 * they appear in the source file. 16 * 17 * 2) No right is granted to use any trade name, trademark, or logo of 18 * Digital Equipment Corporation. Neither the "Digital Equipment 19 * Corporation" name nor any trademark or logo of Digital Equipment 20 * Corporation may be used to endorse or promote products derived 21 * from this software without the prior written permission of 22 * Digital Equipment Corporation. 23 * 24 * 3) This software is provided "AS-IS" and any express or implied 25 * warranties, including but not limited to, any implied warranties 26 * of merchantability, fitness for a particular purpose, or 27 * non-infringement are disclaimed. In no event shall DIGITAL be 28 * liable for any damages whatsoever, and in particular, DIGITAL 29 * shall not be liable for special, indirect, consequential, or 30 * incidental damages or damages for lost profits, loss of 31 * revenue or loss of use, whether such damages arise in contract, 32 * negligence, tort, under statute, in equity, at law or otherwise, 33 * even if advised of the possibility of such damage. 34 */ 35 36 /* 37 * Routines for interfacing between NetBSD and OFW. 38 * 39 * Parts of this could be moved to an MI file in time. -JJK 40 * 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/reboot.h> 47 #include <sys/mbuf.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #include <dev/cons.h> 52 53 #include <machine/bus.h> 54 #include <machine/frame.h> 55 #include <machine/bootconfig.h> 56 #include <machine/cpu.h> 57 #include <machine/intr.h> 58 59 #include <dev/ofw/openfirm.h> 60 #include <machine/ofw.h> 61 62 #include <netinet/in.h> 63 64 #if BOOT_FW_DHCP 65 #include <nfs/bootdata.h> 66 #endif 67 68 #ifdef SHARK 69 #include "machine/pio.h" 70 #include "machine/isa_machdep.h" 71 #endif 72 73 #include "pc.h" 74 #include "isadma.h" 75 76 #define IO_VIRT_BASE (OFW_VIRT_BASE + OFW_VIRT_SIZE) 77 #define IO_VIRT_SIZE 0x01000000 78 79 #define KERNEL_IMG_PTS 2 80 #define KERNEL_VMDATA_PTS (KERNEL_VM_SIZE >> (L1_S_SHIFT + 2)) 81 #define KERNEL_OFW_PTS 4 82 #define KERNEL_IO_PTS 4 83 84 /* 85 * Imported variables 86 */ 87 extern BootConfig bootconfig; /* temporary, I hope */ 88 89 #ifdef DIAGNOSTIC 90 /* NOTE: These variables will be removed, well some of them */ 91 extern u_int spl_mask; 92 extern u_int current_mask; 93 #endif 94 95 extern int ofw_handleticks; 96 97 98 /* 99 * Imported routines 100 */ 101 extern void dump_spl_masks __P((void)); 102 extern void dumpsys __P((void)); 103 extern void dotickgrovelling __P((vm_offset_t)); 104 #if defined(SHARK) && (NPC > 0) 105 extern void shark_screen_cleanup __P((int)); 106 #endif 107 108 #define WriteWord(a, b) \ 109 *((volatile unsigned int *)(a)) = (b) 110 111 #define ReadWord(a) \ 112 (*((volatile unsigned int *)(a))) 113 114 115 /* 116 * Exported variables 117 */ 118 /* These should all be in a meminfo structure. */ 119 vm_offset_t physical_start; 120 vm_offset_t physical_freestart; 121 vm_offset_t physical_freeend; 122 vm_offset_t physical_end; 123 u_int free_pages; 124 int physmem; 125 pv_addr_t systempage; 126 #ifndef OFWGENCFG 127 pv_addr_t irqstack; 128 #endif 129 pv_addr_t undstack; 130 pv_addr_t abtstack; 131 pv_addr_t kernelstack; 132 133 vm_offset_t msgbufphys; 134 135 /* for storage allocation, used to be local to ofw_construct_proc0_addrspace */ 136 static vm_offset_t virt_freeptr; 137 138 int ofw_callbacks = 0; /* debugging counter */ 139 140 /**************************************************************/ 141 142 143 /* 144 * Declarations and definitions private to this module 145 * 146 */ 147 148 struct mem_region { 149 vm_offset_t start; 150 vm_size_t size; 151 }; 152 153 struct mem_translation { 154 vm_offset_t virt; 155 vm_size_t size; 156 vm_offset_t phys; 157 unsigned int mode; 158 }; 159 160 struct isa_range { 161 vm_offset_t isa_phys_hi; 162 vm_offset_t isa_phys_lo; 163 vm_offset_t parent_phys_start; 164 vm_size_t isa_size; 165 }; 166 167 struct vl_range { 168 vm_offset_t vl_phys_hi; 169 vm_offset_t vl_phys_lo; 170 vm_offset_t parent_phys_start; 171 vm_size_t vl_size; 172 }; 173 174 struct vl_isa_range { 175 vm_offset_t isa_phys_hi; 176 vm_offset_t isa_phys_lo; 177 vm_offset_t parent_phys_hi; 178 vm_offset_t parent_phys_lo; 179 vm_size_t isa_size; 180 }; 181 182 struct dma_range { 183 vm_offset_t start; 184 vm_size_t size; 185 }; 186 187 struct ofw_cbargs { 188 char *name; 189 int nargs; 190 int nreturns; 191 int args_n_results[12]; 192 }; 193 194 195 /* Memory info */ 196 static int nOFphysmem; 197 static struct mem_region *OFphysmem; 198 static int nOFphysavail; 199 static struct mem_region *OFphysavail; 200 static int nOFtranslations; 201 static struct mem_translation *OFtranslations; 202 static int nOFdmaranges; 203 static struct dma_range *OFdmaranges; 204 205 /* The OFW client services handle. */ 206 /* Initialized by ofw_init(). */ 207 static ofw_handle_t ofw_client_services_handle; 208 209 210 static void ofw_callbackhandler __P((struct ofw_cbargs *)); 211 static void ofw_construct_proc0_addrspace __P((pv_addr_t *, pv_addr_t *)); 212 static void ofw_getphysmeminfo __P((void)); 213 static void ofw_getvirttranslations __P((void)); 214 static void *ofw_malloc(vm_size_t size); 215 static void ofw_claimpages __P((vm_offset_t *, pv_addr_t *, vm_size_t)); 216 static void ofw_discardmappings __P ((vm_offset_t, vm_offset_t, vm_size_t)); 217 static int ofw_mem_ihandle __P((void)); 218 static int ofw_mmu_ihandle __P((void)); 219 static vm_offset_t ofw_claimphys __P((vm_offset_t, vm_size_t, vm_offset_t)); 220 #if 0 221 static vm_offset_t ofw_releasephys __P((vm_offset_t, vm_size_t)); 222 #endif 223 static vm_offset_t ofw_claimvirt __P((vm_offset_t, vm_size_t, vm_offset_t)); 224 static void ofw_settranslation __P ((vm_offset_t, vm_offset_t, vm_size_t, int)); 225 static void ofw_initallocator __P((void)); 226 static void ofw_configisaonly __P((vm_offset_t *, vm_offset_t *)); 227 static void ofw_configvl __P((int, vm_offset_t *, vm_offset_t *)); 228 static vm_offset_t ofw_valloc __P((vm_offset_t, vm_offset_t)); 229 230 231 /* 232 * DHCP hooks. For a first cut, we look to see if there is a DHCP 233 * packet that was saved by the firmware. If not, we proceed as before, 234 * getting hand-configured data from NVRAM. If there is one, we get the 235 * packet, and extract the data from it. For now, we hand that data up 236 * in the boot_args string as before. 237 */ 238 239 240 /**************************************************************/ 241 242 243 /* 244 * 245 * Support routines for xxx_machdep.c 246 * 247 * The intent is that all OFW-based configurations use the 248 * exported routines in this file to do their business. If 249 * they need to override some function they are free to do so. 250 * 251 * The exported routines are: 252 * 253 * openfirmware 254 * ofw_init 255 * ofw_boot 256 * ofw_getbootinfo 257 * ofw_configmem 258 * ofw_configisa 259 * ofw_configisadma 260 * ofw_gettranslation 261 * ofw_map 262 * ofw_getcleaninfo 263 */ 264 265 266 int 267 openfirmware(args) 268 void *args; 269 { 270 int ofw_result; 271 u_int saved_irq_state; 272 273 /* OFW is not re-entrant, so we wrap a mutex around the call. */ 274 saved_irq_state = disable_interrupts(I32_bit); 275 ofw_result = ofw_client_services_handle(args); 276 (void)restore_interrupts(saved_irq_state); 277 278 return(ofw_result); 279 } 280 281 282 void 283 ofw_init(ofw_handle) 284 ofw_handle_t ofw_handle; 285 { 286 ofw_client_services_handle = ofw_handle; 287 288 /* Everything we allocate in the remainder of this block is 289 * constrained to be in the "kernel-static" portion of the 290 * virtual address space (i.e., 0xF0000000 - 0xF1000000). 291 * This is because all such objects are expected to be in 292 * that range by NetBSD, or the objects will be re-mapped 293 * after the page-table-switch to other specific locations. 294 * In the latter case, it's simplest if our pre-switch handles 295 * on those objects are in regions that are already "well- 296 * known." (Otherwise, the cloning of the OFW-managed address- 297 * space becomes more awkward.) To minimize the number of L2 298 * page tables that we use, we are further restricting the 299 * remaining allocations in this block to the bottom quarter of 300 * the legal range. OFW will have loaded the kernel text+data+bss 301 * starting at the bottom of the range, and we will allocate 302 * objects from the top, moving downwards. The two sub-regions 303 * will collide if their total sizes hit 8MB. The current total 304 * is <1.5MB, but INSTALL kernels are > 4MB, so hence the 8MB 305 * limit. The variable virt-freeptr represents the next free va 306 * (moving downwards). 307 */ 308 virt_freeptr = KERNEL_BASE + (0x00400000 * KERNEL_IMG_PTS); 309 } 310 311 312 void 313 ofw_boot(howto, bootstr) 314 int howto; 315 char *bootstr; 316 { 317 318 #ifdef DIAGNOSTIC 319 printf("boot: howto=%08x curproc=%p\n", howto, curproc); 320 printf("current_mask=%08x spl_mask=%08x\n", current_mask, spl_mask); 321 322 printf("ipl_bio=%08x ipl_net=%08x ipl_tty=%08x ipl_imp=%08x\n", 323 irqmasks[IPL_BIO], irqmasks[IPL_NET], irqmasks[IPL_TTY], 324 irqmasks[IPL_IMP]); 325 printf("ipl_audio=%08x ipl_clock=%08x ipl_none=%08x\n", 326 irqmasks[IPL_AUDIO], irqmasks[IPL_CLOCK], irqmasks[IPL_NONE]); 327 328 dump_spl_masks(); 329 #endif 330 331 /* 332 * If we are still cold then hit the air brakes 333 * and crash to earth fast 334 */ 335 if (cold) { 336 doshutdownhooks(); 337 printf("Halted while still in the ICE age.\n"); 338 printf("The operating system has halted.\n"); 339 goto ofw_exit; 340 /*NOTREACHED*/ 341 } 342 343 /* 344 * If RB_NOSYNC was not specified sync the discs. 345 * Note: Unless cold is set to 1 here, syslogd will die during the unmount. 346 * It looks like syslogd is getting woken up only to find that it cannot 347 * page part of the binary in as the filesystem has been unmounted. 348 */ 349 if (!(howto & RB_NOSYNC)) 350 bootsync(); 351 352 /* Say NO to interrupts */ 353 splhigh(); 354 355 /* Do a dump if requested. */ 356 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 357 dumpsys(); 358 359 /* Run any shutdown hooks */ 360 doshutdownhooks(); 361 362 /* Make sure IRQ's are disabled */ 363 IRQdisable; 364 365 if (howto & RB_HALT) { 366 printf("The operating system has halted.\n"); 367 goto ofw_exit; 368 } 369 370 /* Tell the user we are booting */ 371 printf("rebooting...\n"); 372 373 /* Jump into the OFW boot routine. */ 374 { 375 static char str[256]; 376 char *ap = str, *ap1 = ap; 377 378 if (bootstr && *bootstr) { 379 if (strlen(bootstr) > sizeof str - 5) 380 printf("boot string too large, ignored\n"); 381 else { 382 strcpy(str, bootstr); 383 ap1 = ap = str + strlen(str); 384 *ap++ = ' '; 385 } 386 } 387 *ap++ = '-'; 388 if (howto & RB_SINGLE) 389 *ap++ = 's'; 390 if (howto & RB_KDB) 391 *ap++ = 'd'; 392 *ap++ = 0; 393 if (ap[-2] == '-') 394 *ap1 = 0; 395 #if defined(SHARK) && (NPC > 0) 396 shark_screen_cleanup(0); 397 #endif 398 OF_boot(str); 399 /*NOTREACHED*/ 400 } 401 402 ofw_exit: 403 printf("Calling OF_exit...\n"); 404 #if defined(SHARK) && (NPC > 0) 405 shark_screen_cleanup(1); 406 #endif 407 OF_exit(); 408 /*NOTREACHED*/ 409 } 410 411 412 #if BOOT_FW_DHCP 413 414 extern char *ip2dotted __P((struct in_addr)); 415 416 /* 417 * Get DHCP data from OFW 418 */ 419 420 void 421 get_fw_dhcp_data(bdp) 422 struct bootdata *bdp; 423 { 424 int chosen; 425 int dhcplen; 426 427 bzero((char *)bdp, sizeof(*bdp)); 428 if ((chosen = OF_finddevice("/chosen")) == -1) 429 panic("no /chosen from OFW"); 430 if ((dhcplen = OF_getproplen(chosen, "bootp-response")) > 0) { 431 u_char *cp; 432 int dhcp_type = 0; 433 char *ip; 434 435 /* 436 * OFW saved a DHCP (or BOOTP) packet for us. 437 */ 438 if (dhcplen > sizeof(bdp->dhcp_packet)) 439 panic("DHCP packet too large"); 440 OF_getprop(chosen, "bootp-response", &bdp->dhcp_packet, 441 sizeof(bdp->dhcp_packet)); 442 SANITY(bdp->dhcp_packet.op == BOOTREPLY, "bogus DHCP packet"); 443 /* 444 * Collect the interesting data from DHCP into 445 * the bootdata structure. 446 */ 447 bdp->ip_address = bdp->dhcp_packet.yiaddr; 448 ip = ip2dotted(bdp->ip_address); 449 if (bcmp(bdp->dhcp_packet.options, DHCP_OPTIONS_COOKIE, 4) == 0) 450 parse_dhcp_options(&bdp->dhcp_packet, 451 bdp->dhcp_packet.options + 4, 452 &bdp->dhcp_packet.options[dhcplen 453 - DHCP_FIXED_NON_UDP], bdp, ip); 454 if (bdp->root_ip.s_addr == 0) 455 bdp->root_ip = bdp->dhcp_packet.siaddr; 456 if (bdp->swap_ip.s_addr == 0) 457 bdp->swap_ip = bdp->dhcp_packet.siaddr; 458 } 459 /* 460 * If the DHCP packet did not contain all the necessary data, 461 * look in NVRAM for the missing parts. 462 */ 463 { 464 int options; 465 int proplen; 466 #define BOOTJUNKV_SIZE 256 467 char bootjunkv[BOOTJUNKV_SIZE]; /* minimize stack usage */ 468 469 470 if ((options = OF_finddevice("/options")) == -1) 471 panic("can't find /options"); 472 if (bdp->ip_address.s_addr == 0 && 473 (proplen = OF_getprop(options, "ipaddr", 474 bootjunkv, BOOTJUNKV_SIZE - 1)) > 0) { 475 bootjunkv[proplen] = '\0'; 476 if (dotted2ip(bootjunkv, &bdp->ip_address.s_addr) == 0) 477 bdp->ip_address.s_addr = 0; 478 } 479 if (bdp->ip_mask.s_addr == 0 && 480 (proplen = OF_getprop(options, "netmask", 481 bootjunkv, BOOTJUNKV_SIZE - 1)) > 0) { 482 bootjunkv[proplen] = '\0'; 483 if (dotted2ip(bootjunkv, &bdp->ip_mask.s_addr) == 0) 484 bdp->ip_mask.s_addr = 0; 485 } 486 if (bdp->hostname[0] == '\0' && 487 (proplen = OF_getprop(options, "hostname", 488 bdp->hostname, sizeof(bdp->hostname) - 1)) > 0) { 489 bdp->hostname[proplen] = '\0'; 490 } 491 if (bdp->root[0] == '\0' && 492 (proplen = OF_getprop(options, "rootfs", 493 bootjunkv, BOOTJUNKV_SIZE - 1)) > 0) { 494 bootjunkv[proplen] = '\0'; 495 parse_server_path(bootjunkv, &bdp->root_ip, bdp->root); 496 } 497 if (bdp->swap[0] == '\0' && 498 (proplen = OF_getprop(options, "swapfs", 499 bootjunkv, BOOTJUNKV_SIZE - 1)) > 0) { 500 bootjunkv[proplen] = '\0'; 501 parse_server_path(bootjunkv, &bdp->swap_ip, bdp->swap); 502 } 503 } 504 } 505 506 #endif /* BOOT_FW_DHCP */ 507 508 void 509 ofw_getbootinfo(bp_pp, ba_pp) 510 char **bp_pp; 511 char **ba_pp; 512 { 513 int chosen; 514 int bp_len; 515 int ba_len; 516 char *bootpathv; 517 char *bootargsv; 518 519 /* Read the bootpath and bootargs out of OFW. */ 520 /* XXX is bootpath still interesting? --emg */ 521 if ((chosen = OF_finddevice("/chosen")) == -1) 522 panic("no /chosen from OFW"); 523 bp_len = OF_getproplen(chosen, "bootpath"); 524 ba_len = OF_getproplen(chosen, "bootargs"); 525 if (bp_len < 0 || ba_len < 0) 526 panic("can't get boot data from OFW"); 527 528 bootpathv = (char *)ofw_malloc(bp_len); 529 bootargsv = (char *)ofw_malloc(ba_len); 530 531 if (bp_len) 532 OF_getprop(chosen, "bootpath", bootpathv, bp_len); 533 else 534 bootpathv[0] = '\0'; 535 536 if (ba_len) 537 OF_getprop(chosen, "bootargs", bootargsv, ba_len); 538 else 539 bootargsv[0] = '\0'; 540 541 *bp_pp = bootpathv; 542 *ba_pp = bootargsv; 543 #ifdef DIAGNOSTIC 544 printf("bootpath=<%s>, bootargs=<%s>\n", bootpathv, bootargsv); 545 #endif 546 } 547 548 vm_offset_t 549 ofw_getcleaninfo(void) 550 { 551 int cpu; 552 vm_offset_t vclean, pclean; 553 554 if ((cpu = OF_finddevice("/cpu")) == -1) 555 panic("no /cpu from OFW"); 556 557 if ((OF_getprop(cpu, "d-cache-flush-address", &vclean, 558 sizeof(vclean))) != sizeof(vclean)) { 559 #ifdef DEBUG 560 printf("no OFW d-cache-flush-address property\n"); 561 #endif 562 return -1; 563 } 564 565 if ((pclean = ofw_gettranslation( 566 of_decode_int((unsigned char *)&vclean))) == -1) 567 panic("OFW failed to translate cache flush address"); 568 569 return pclean; 570 } 571 572 void 573 ofw_configisa(pio, pmem) 574 vm_offset_t *pio; 575 vm_offset_t *pmem; 576 { 577 int vl; 578 579 if ((vl = OF_finddevice("/vlbus")) == -1) /* old style OFW dev info tree */ 580 ofw_configisaonly(pio, pmem); 581 else /* old style OFW dev info tree */ 582 ofw_configvl(vl, pio, pmem); 583 } 584 585 static void 586 ofw_configisaonly(pio, pmem) 587 vm_offset_t *pio; 588 vm_offset_t *pmem; 589 { 590 int isa; 591 int rangeidx; 592 int size; 593 vm_offset_t hi, start; 594 struct isa_range ranges[2]; 595 596 if ((isa = OF_finddevice("/isa")) == -1) 597 panic("OFW has no /isa device node"); 598 599 /* expect to find two isa ranges: IO/data and memory/data */ 600 if ((size = OF_getprop(isa, "ranges", ranges, sizeof(ranges))) 601 != sizeof(ranges)) 602 panic("unexpected size of OFW /isa ranges property: %d", size); 603 604 *pio = *pmem = -1; 605 606 for (rangeidx = 0; rangeidx < 2; ++rangeidx) { 607 hi = of_decode_int((unsigned char *) 608 &ranges[rangeidx].isa_phys_hi); 609 start = of_decode_int((unsigned char *) 610 &ranges[rangeidx].parent_phys_start); 611 612 if (hi & 1) { /* then I/O space */ 613 *pio = start; 614 } else { 615 *pmem = start; 616 } 617 } /* END for */ 618 619 if ((*pio == -1) || (*pmem == -1)) 620 panic("bad OFW /isa ranges property"); 621 622 } 623 624 static void 625 ofw_configvl(vl, pio, pmem) 626 int vl; 627 vm_offset_t *pio; 628 vm_offset_t *pmem; 629 { 630 int isa; 631 int ir, vr; 632 int size; 633 vm_offset_t hi, start; 634 struct vl_isa_range isa_ranges[2]; 635 struct vl_range vl_ranges[2]; 636 637 if ((isa = OF_finddevice("/vlbus/isa")) == -1) 638 panic("OFW has no /vlbus/isa device node"); 639 640 /* expect to find two isa ranges: IO/data and memory/data */ 641 if ((size = OF_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges))) 642 != sizeof(isa_ranges)) 643 panic("unexpected size of OFW /vlbus/isa ranges property: %d", 644 size); 645 646 /* expect to find two vl ranges: IO/data and memory/data */ 647 if ((size = OF_getprop(vl, "ranges", vl_ranges, sizeof(vl_ranges))) 648 != sizeof(vl_ranges)) 649 panic("unexpected size of OFW /vlbus ranges property: %d", size); 650 651 *pio = -1; 652 *pmem = -1; 653 654 for (ir = 0; ir < 2; ++ir) { 655 for (vr = 0; vr < 2; ++vr) { 656 if ((isa_ranges[ir].parent_phys_hi 657 == vl_ranges[vr].vl_phys_hi) && 658 (isa_ranges[ir].parent_phys_lo 659 == vl_ranges[vr].vl_phys_lo)) { 660 hi = of_decode_int((unsigned char *) 661 &isa_ranges[ir].isa_phys_hi); 662 start = of_decode_int((unsigned char *) 663 &vl_ranges[vr].parent_phys_start); 664 665 if (hi & 1) { /* then I/O space */ 666 *pio = start; 667 } else { 668 *pmem = start; 669 } 670 } /* END if */ 671 } /* END for */ 672 } /* END for */ 673 674 if ((*pio == -1) || (*pmem == -1)) 675 panic("bad OFW /isa ranges property"); 676 } 677 678 void 679 ofw_configisadma(pdma) 680 vm_offset_t *pdma; 681 { 682 int root; 683 int rangeidx; 684 int size; 685 struct dma_range *dr; 686 #if NISADMA > 0 687 extern bus_dma_segment_t *pmap_isa_dma_ranges; 688 extern int pmap_isa_dma_nranges; 689 #endif 690 691 if ((root = OF_finddevice("/")) == -1 || 692 (size = OF_getproplen(root, "dma-ranges")) <= 0 || 693 (OFdmaranges = (struct dma_range *)ofw_malloc(size)) == 0 || 694 OF_getprop(root, "dma-ranges", OFdmaranges, size) != size) 695 panic("bad / dma-ranges property"); 696 697 nOFdmaranges = size / sizeof(struct dma_range); 698 699 #if NISADMA > 0 700 /* Allocate storage for non-OFW representation of the range. */ 701 pmap_isa_dma_ranges = ofw_malloc(nOFdmaranges * 702 sizeof(bus_dma_segment_t)); 703 if (pmap_isa_dma_ranges == NULL) 704 panic("unable to allocate pmap_isa_dma_ranges"); 705 pmap_isa_dma_nranges = nOFdmaranges; 706 #endif 707 708 for (rangeidx = 0, dr = OFdmaranges; rangeidx < nOFdmaranges; 709 ++rangeidx, ++dr) { 710 dr->start = of_decode_int((unsigned char *)&dr->start); 711 dr->size = of_decode_int((unsigned char *)&dr->size); 712 #if NISADMA > 0 713 pmap_isa_dma_ranges[rangeidx].ds_addr = dr->start; 714 pmap_isa_dma_ranges[rangeidx].ds_len = dr->size; 715 #endif 716 } 717 718 #ifdef DEBUG 719 printf("dma ranges size = %d\n", size); 720 721 for (rangeidx = 0; rangeidx < nOFdmaranges; ++rangeidx) { 722 printf("%08lx %08lx\n", 723 (u_long)OFdmaranges[rangeidx].start, 724 (u_long)OFdmaranges[rangeidx].size); 725 } 726 #endif 727 } 728 729 /* 730 * Memory configuration: 731 * 732 * We start off running in the environment provided by OFW. 733 * This has the MMU turned on, the kernel code and data 734 * mapped-in at KERNEL_BASE (0xF0000000), OFW's text and 735 * data mapped-in at OFW_VIRT_BASE (0xF7000000), and (possibly) 736 * page0 mapped-in at 0x0. 737 * 738 * The strategy is to set-up the address space for proc0 -- 739 * including the allocation of space for new page tables -- while 740 * memory is still managed by OFW. We then effectively create a 741 * copy of the address space by dumping all of OFW's translations 742 * and poking them into the new page tables. We then notify OFW 743 * that we are assuming control of memory-management by installing 744 * our callback-handler, and switch to the NetBSD-managed page 745 * tables with the setttb() call. 746 * 747 * This scheme may cause some amount of memory to be wasted within 748 * OFW as dead page tables, but it shouldn't be more than about 749 * 20-30KB. (It's also possible that OFW will re-use the space.) 750 */ 751 void 752 ofw_configmem(void) 753 { 754 pv_addr_t proc0_ttbbase; 755 pv_addr_t proc0_ptpt; 756 757 /* Set-up proc0 address space. */ 758 ofw_construct_proc0_addrspace(&proc0_ttbbase, &proc0_ptpt); 759 760 /* 761 * Get a dump of OFW's picture of physical memory. 762 * This is used below to initialize a load of variables used by pmap. 763 * We get it now rather than later because we are about to 764 * tell OFW to stop managing memory. 765 */ 766 ofw_getphysmeminfo(); 767 768 /* We are about to take control of memory-management from OFW. 769 * Establish callbacks for OFW to use for its future memory needs. 770 * This is required for us to keep using OFW services. 771 */ 772 773 /* First initialize our callback memory allocator. */ 774 ofw_initallocator(); 775 776 OF_set_callback((void(*)())ofw_callbackhandler); 777 778 /* Switch to the proc0 pagetables. */ 779 setttb(proc0_ttbbase.pv_pa); 780 781 /* Aaaaaaaah, running in the proc0 address space! */ 782 /* I feel good... */ 783 784 /* Set-up the various globals which describe physical memory for pmap. */ 785 { 786 struct mem_region *mp; 787 int totalcnt; 788 int availcnt; 789 int i; 790 791 /* physmem, physical_start, physical_end */ 792 physmem = 0; 793 for (totalcnt = 0, mp = OFphysmem; totalcnt < nOFphysmem; 794 totalcnt++, mp++) { 795 #ifdef OLDPRINTFS 796 printf("physmem: %x, %x\n", mp->start, mp->size); 797 #endif 798 physmem += btoc(mp->size); 799 } 800 physical_start = OFphysmem[0].start; 801 mp--; 802 physical_end = mp->start + mp->size; 803 804 /* free_pages, physical_freestart, physical_freeend */ 805 free_pages = 0; 806 for (availcnt = 0, mp = OFphysavail; availcnt < nOFphysavail; 807 availcnt++, mp++) { 808 #ifdef OLDPRINTFS 809 printf("physavail: %x, %x\n", mp->start, mp->size); 810 #endif 811 free_pages += btoc(mp->size); 812 } 813 physical_freestart = OFphysavail[0].start; 814 mp--; 815 physical_freeend = mp->start + mp->size; 816 #ifdef OLDPRINTFS 817 printf("pmap_bootstrap: physmem = %x, free_pages = %x\n", 818 physmem, free_pages); 819 #endif 820 821 /* 822 * This is a hack to work with the existing pmap code. 823 * That code depends on a RiscPC BootConfig structure 824 * containing, among other things, an array describing 825 * the regions of physical memory. So, for now, we need 826 * to stuff our OFW-derived physical memory info into a 827 * "fake" BootConfig structure. 828 * 829 * An added twist is that we initialize the BootConfig 830 * structure with our "available" physical memory regions 831 * rather than the "total" physical memory regions. Why? 832 * Because: 833 * 834 * (a) the VM code requires that the "free" pages it is 835 * initialized with have consecutive indices. This 836 * allows it to use more efficient data structures 837 * (presumably). 838 * (b) the current pmap routines which report the initial 839 * set of free page indices (pmap_next_page) and 840 * which map addresses to indices (pmap_page_index) 841 * assume that the free pages are consecutive across 842 * memory region boundaries. 843 * 844 * This means that memory which is "stolen" at startup time 845 * (say, for page descriptors) MUST come from either the 846 * bottom of the first region or the top of the last. 847 * 848 * This requirement doesn't mesh well with OFW (or at least 849 * our use of it). We can get around it for the time being 850 * by pretending that our "available" region array describes 851 * all of our physical memory. This may cause some important 852 * information to be excluded from a dump file, but so far 853 * I haven't come across any other negative effects. 854 * 855 * In the long-run we should fix the index 856 * generation/translation code in the pmap module. 857 */ 858 859 if (DRAM_BLOCKS < (availcnt + 1)) 860 panic("more ofw memory regions than bootconfig blocks"); 861 862 for (i = 0, mp = OFphysavail; i < nOFphysavail; i++, mp++) { 863 bootconfig.dram[i].address = mp->start; 864 bootconfig.dram[i].pages = btoc(mp->size); 865 } 866 bootconfig.dramblocks = availcnt; 867 } 868 869 /* Initialize pmap module. */ 870 pmap_bootstrap((pd_entry_t *)proc0_ttbbase.pv_va, proc0_ptpt); 871 } 872 873 874 /* 875 ************************************************************ 876 877 Routines private to this module 878 879 ************************************************************ 880 */ 881 882 /* N.B. Not supposed to call printf in callback-handler! Could deadlock! */ 883 static void 884 ofw_callbackhandler(args) 885 struct ofw_cbargs *args; 886 { 887 char *name = args->name; 888 int nargs = args->nargs; 889 int nreturns = args->nreturns; 890 int *args_n_results = args->args_n_results; 891 892 ofw_callbacks++; 893 894 #if defined(OFWGENCFG) 895 /* Check this first, so that we don't waste IRQ time parsing. */ 896 if (strcmp(name, "tick") == 0) { 897 vm_offset_t frame; 898 899 /* Check format. */ 900 if (nargs != 1 || nreturns < 1) { 901 args_n_results[nargs] = -1; 902 args->nreturns = 1; 903 return; 904 } 905 args_n_results[nargs] = 0; /* properly formatted request */ 906 907 /* 908 * Note that we are running in the IRQ frame, with interrupts 909 * disabled. 910 * 911 * We need to do two things here: 912 * - copy a few words out of the input frame into a global 913 * area, for later use by our real tick-handling code 914 * - patch a few words in the frame so that when OFW returns 915 * from the interrupt it will resume with our handler 916 * rather than the code that was actually interrupted. 917 * Our handler will resume when it finishes with the code 918 * that was actually interrupted. 919 * 920 * It's simplest to do this in assembler, since it requires 921 * switching frames and grovelling about with registers. 922 */ 923 frame = (vm_offset_t)args_n_results[0]; 924 if (ofw_handleticks) 925 dotickgrovelling(frame); 926 args_n_results[nargs + 1] = frame; 927 args->nreturns = 1; 928 } else 929 #endif 930 931 if (strcmp(name, "map") == 0) { 932 vm_offset_t va; 933 vm_offset_t pa; 934 vm_size_t size; 935 int mode; 936 int ap_bits; 937 int dom_bits; 938 int cb_bits; 939 940 /* Check format. */ 941 if (nargs != 4 || nreturns < 2) { 942 args_n_results[nargs] = -1; 943 args->nreturns = 1; 944 return; 945 } 946 args_n_results[nargs] = 0; /* properly formatted request */ 947 948 pa = (vm_offset_t)args_n_results[0]; 949 va = (vm_offset_t)args_n_results[1]; 950 size = (vm_size_t)args_n_results[2]; 951 mode = args_n_results[3]; 952 ap_bits = (mode & 0x00000C00); 953 dom_bits = (mode & 0x000001E0); 954 cb_bits = (mode & 0x000000C0); 955 956 /* Sanity checks. */ 957 if ((va & PGOFSET) != 0 || va < OFW_VIRT_BASE || 958 (va + size) > (OFW_VIRT_BASE + OFW_VIRT_SIZE) || 959 (pa & PGOFSET) != 0 || (size & PGOFSET) != 0 || 960 size == 0 || (dom_bits >> 5) != 0) { 961 args_n_results[nargs + 1] = -1; 962 args->nreturns = 1; 963 return; 964 } 965 966 /* Write-back anything stuck in the cache. */ 967 cpu_idcache_wbinv_all(); 968 969 /* Install new mappings. */ 970 { 971 pt_entry_t *pte = vtopte(va); 972 int npages = size >> PGSHIFT; 973 974 ap_bits >>= 10; 975 for (; npages > 0; pte++, pa += NBPG, npages--) 976 *pte = (pa | L2_AP(ap_bits) | L2_TYPE_S | cb_bits); 977 } 978 979 /* Clean out tlb. */ 980 tlb_flush(); 981 982 args_n_results[nargs + 1] = 0; 983 args->nreturns = 2; 984 } else if (strcmp(name, "unmap") == 0) { 985 vm_offset_t va; 986 vm_size_t size; 987 988 /* Check format. */ 989 if (nargs != 2 || nreturns < 1) { 990 args_n_results[nargs] = -1; 991 args->nreturns = 1; 992 return; 993 } 994 args_n_results[nargs] = 0; /* properly formatted request */ 995 996 va = (vm_offset_t)args_n_results[0]; 997 size = (vm_size_t)args_n_results[1]; 998 999 /* Sanity checks. */ 1000 if ((va & PGOFSET) != 0 || va < OFW_VIRT_BASE || 1001 (va + size) > (OFW_VIRT_BASE + OFW_VIRT_SIZE) || 1002 (size & PGOFSET) != 0 || size == 0) { 1003 args_n_results[nargs + 1] = -1; 1004 args->nreturns = 1; 1005 return; 1006 } 1007 1008 /* Write-back anything stuck in the cache. */ 1009 cpu_idcache_wbinv_all(); 1010 1011 /* Zero the mappings. */ 1012 { 1013 pt_entry_t *pte = vtopte(va); 1014 int npages = size >> PGSHIFT; 1015 1016 for (; npages > 0; pte++, npages--) 1017 *pte = 0; 1018 } 1019 1020 /* Clean out tlb. */ 1021 tlb_flush(); 1022 1023 args->nreturns = 1; 1024 } else if (strcmp(name, "translate") == 0) { 1025 vm_offset_t va; 1026 vm_offset_t pa; 1027 int mode; 1028 pt_entry_t pte; 1029 1030 /* Check format. */ 1031 if (nargs != 1 || nreturns < 4) { 1032 args_n_results[nargs] = -1; 1033 args->nreturns = 1; 1034 return; 1035 } 1036 args_n_results[nargs] = 0; /* properly formatted request */ 1037 1038 va = (vm_offset_t)args_n_results[0]; 1039 1040 /* Sanity checks. 1041 * For now, I am only willing to translate va's in the 1042 * "ofw range." Eventually, I may be more generous. -JJK 1043 */ 1044 if ((va & PGOFSET) != 0 || va < OFW_VIRT_BASE || 1045 va >= (OFW_VIRT_BASE + OFW_VIRT_SIZE)) { 1046 args_n_results[nargs + 1] = -1; 1047 args->nreturns = 1; 1048 return; 1049 } 1050 1051 /* Lookup mapping. */ 1052 pte = *vtopte(va); 1053 if (pte == 0) { 1054 /* No mapping. */ 1055 args_n_results[nargs + 1] = -1; 1056 args->nreturns = 2; 1057 } else { 1058 /* Existing mapping. */ 1059 pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); 1060 mode = (pte & 0x0C00) | (0 << 5) | (pte & 0x000C); /* AP | DOM | CB */ 1061 1062 args_n_results[nargs + 1] = 0; 1063 args_n_results[nargs + 2] = pa; 1064 args_n_results[nargs + 3] = mode; 1065 args->nreturns = 4; 1066 } 1067 } else if (strcmp(name, "claim-phys") == 0) { 1068 struct pglist alloclist = TAILQ_HEAD_INITIALIZER(alloclist); 1069 vm_offset_t low, high; 1070 vm_size_t align, size; 1071 1072 /* 1073 * XXX 1074 * XXX THIS IS A GROSS HACK AND NEEDS TO BE REWRITTEN. -- cgd 1075 * XXX 1076 */ 1077 1078 /* Check format. */ 1079 if (nargs != 4 || nreturns < 3) { 1080 args_n_results[nargs] = -1; 1081 args->nreturns = 1; 1082 return; 1083 } 1084 args_n_results[nargs] = 0; /* properly formatted request */ 1085 1086 low = args_n_results[0]; 1087 size = args_n_results[2]; 1088 align = args_n_results[3]; 1089 high = args_n_results[1] + size; 1090 1091 #if 0 1092 printf("claim-phys: low = 0x%x, size = 0x%x, align = 0x%x, high = 0x%x\n", 1093 low, size, align, high); 1094 align = size; 1095 printf("forcing align to be 0x%x\n", align); 1096 #endif 1097 1098 args_n_results[nargs + 1] = 1099 uvm_pglistalloc(size, low, high, align, 0, &alloclist, 1, 0); 1100 #if 0 1101 printf(" -> 0x%lx", args_n_results[nargs + 1]); 1102 #endif 1103 if (args_n_results[nargs + 1] != 0) { 1104 #if 0 1105 printf("(failed)\n"); 1106 #endif 1107 args_n_results[nargs + 1] = -1; 1108 args->nreturns = 2; 1109 return; 1110 } 1111 args_n_results[nargs + 2] = alloclist.tqh_first->phys_addr; 1112 #if 0 1113 printf("(succeeded: pa = 0x%lx)\n", args_n_results[nargs + 2]); 1114 #endif 1115 args->nreturns = 3; 1116 1117 } else if (strcmp(name, "release-phys") == 0) { 1118 printf("unimplemented ofw callback - %s\n", name); 1119 args_n_results[nargs] = -1; 1120 args->nreturns = 1; 1121 } else if (strcmp(name, "claim-virt") == 0) { 1122 vm_offset_t va; 1123 vm_size_t size; 1124 vm_offset_t align; 1125 1126 /* XXX - notyet */ 1127 /* printf("unimplemented ofw callback - %s\n", name);*/ 1128 args_n_results[nargs] = -1; 1129 args->nreturns = 1; 1130 return; 1131 1132 /* Check format. */ 1133 if (nargs != 2 || nreturns < 3) { 1134 args_n_results[nargs] = -1; 1135 args->nreturns = 1; 1136 return; 1137 } 1138 args_n_results[nargs] = 0; /* properly formatted request */ 1139 1140 /* Allocate size bytes with specified alignment. */ 1141 size = (vm_size_t)args_n_results[0]; 1142 align = (vm_offset_t)args_n_results[1]; 1143 if (align % NBPG != 0) { 1144 args_n_results[nargs + 1] = -1; 1145 args->nreturns = 2; 1146 return; 1147 } 1148 1149 if (va == 0) { 1150 /* Couldn't allocate. */ 1151 args_n_results[nargs + 1] = -1; 1152 args->nreturns = 2; 1153 } else { 1154 /* Successful allocation. */ 1155 args_n_results[nargs + 1] = 0; 1156 args_n_results[nargs + 2] = va; 1157 args->nreturns = 3; 1158 } 1159 } else if (strcmp(name, "release-virt") == 0) { 1160 vm_offset_t va; 1161 vm_size_t size; 1162 1163 /* XXX - notyet */ 1164 printf("unimplemented ofw callback - %s\n", name); 1165 args_n_results[nargs] = -1; 1166 args->nreturns = 1; 1167 return; 1168 1169 /* Check format. */ 1170 if (nargs != 2 || nreturns < 1) { 1171 args_n_results[nargs] = -1; 1172 args->nreturns = 1; 1173 return; 1174 } 1175 args_n_results[nargs] = 0; /* properly formatted request */ 1176 1177 /* Release bytes. */ 1178 va = (vm_offset_t)args_n_results[0]; 1179 size = (vm_size_t)args_n_results[1]; 1180 1181 args->nreturns = 1; 1182 } else { 1183 args_n_results[nargs] = -1; 1184 args->nreturns = 1; 1185 } 1186 } 1187 1188 static void 1189 ofw_construct_proc0_addrspace(proc0_ttbbase, proc0_ptpt) 1190 pv_addr_t *proc0_ttbbase; 1191 pv_addr_t *proc0_ptpt; 1192 { 1193 int i, oft; 1194 pv_addr_t proc0_pagedir; 1195 pv_addr_t proc0_pt_pte; 1196 pv_addr_t proc0_pt_sys; 1197 pv_addr_t proc0_pt_kernel[KERNEL_IMG_PTS]; 1198 pv_addr_t proc0_pt_vmdata[KERNEL_VMDATA_PTS]; 1199 pv_addr_t proc0_pt_ofw[KERNEL_OFW_PTS]; 1200 pv_addr_t proc0_pt_io[KERNEL_IO_PTS]; 1201 pv_addr_t msgbuf; 1202 vm_offset_t L1pagetable; 1203 struct mem_translation *tp; 1204 1205 /* Set-up the system page. */ 1206 KASSERT(vector_page == 0); /* XXX for now */ 1207 systempage.pv_va = ofw_claimvirt(vector_page, NBPG, 0); 1208 if (systempage.pv_va == -1) { 1209 /* Something was already mapped to vector_page's VA. */ 1210 systempage.pv_va = vector_page; 1211 systempage.pv_pa = ofw_gettranslation(vector_page); 1212 if (systempage.pv_pa == -1) 1213 panic("bogus result from gettranslation(vector_page)"); 1214 } else { 1215 /* We were just allocated the page-length range at VA 0. */ 1216 if (systempage.pv_va != vector_page) 1217 panic("bogus result from claimvirt(vector_page, NBPG, 0)"); 1218 1219 /* Now allocate a physical page, and establish the mapping. */ 1220 systempage.pv_pa = ofw_claimphys(0, NBPG, NBPG); 1221 if (systempage.pv_pa == -1) 1222 panic("bogus result from claimphys(0, NBPG, NBPG)"); 1223 ofw_settranslation(systempage.pv_va, systempage.pv_pa, 1224 NBPG, -1); /* XXX - mode? -JJK */ 1225 1226 /* Zero the memory. */ 1227 bzero((char *)systempage.pv_va, NBPG); 1228 } 1229 1230 /* Allocate/initialize space for the proc0, NetBSD-managed */ 1231 /* page tables that we will be switching to soon. */ 1232 ofw_claimpages(&virt_freeptr, &proc0_pagedir, L1_TABLE_SIZE); 1233 ofw_claimpages(&virt_freeptr, &proc0_pt_pte, L2_TABLE_SIZE); 1234 ofw_claimpages(&virt_freeptr, &proc0_pt_sys, L2_TABLE_SIZE); 1235 for (i = 0; i < KERNEL_IMG_PTS; i++) 1236 ofw_claimpages(&virt_freeptr, &proc0_pt_kernel[i], L2_TABLE_SIZE); 1237 for (i = 0; i < KERNEL_VMDATA_PTS; i++) 1238 ofw_claimpages(&virt_freeptr, &proc0_pt_vmdata[i], L2_TABLE_SIZE); 1239 for (i = 0; i < KERNEL_OFW_PTS; i++) 1240 ofw_claimpages(&virt_freeptr, &proc0_pt_ofw[i], L2_TABLE_SIZE); 1241 for (i = 0; i < KERNEL_IO_PTS; i++) 1242 ofw_claimpages(&virt_freeptr, &proc0_pt_io[i], L2_TABLE_SIZE); 1243 1244 /* Allocate/initialize space for stacks. */ 1245 #ifndef OFWGENCFG 1246 ofw_claimpages(&virt_freeptr, &irqstack, NBPG); 1247 #endif 1248 ofw_claimpages(&virt_freeptr, &undstack, NBPG); 1249 ofw_claimpages(&virt_freeptr, &abtstack, NBPG); 1250 ofw_claimpages(&virt_freeptr, &kernelstack, UPAGES * NBPG); 1251 1252 /* Allocate/initialize space for msgbuf area. */ 1253 ofw_claimpages(&virt_freeptr, &msgbuf, MSGBUFSIZE); 1254 msgbufphys = msgbuf.pv_pa; 1255 1256 /* Construct the proc0 L1 pagetable. */ 1257 L1pagetable = proc0_pagedir.pv_va; 1258 1259 pmap_link_l2pt(L1pagetable, 0x0, &proc0_pt_sys); 1260 for (i = 0; i < KERNEL_IMG_PTS; i++) 1261 pmap_link_l2pt(L1pagetable, KERNEL_BASE + i * 0x00400000, 1262 &proc0_pt_kernel[i]); 1263 pmap_link_l2pt(L1pagetable, PTE_BASE, 1264 &proc0_pt_pte); 1265 for (i = 0; i < KERNEL_VMDATA_PTS; i++) 1266 pmap_link_l2pt(L1pagetable, KERNEL_VM_BASE + i * 0x00400000, 1267 &proc0_pt_vmdata[i]); 1268 for (i = 0; i < KERNEL_OFW_PTS; i++) 1269 pmap_link_l2pt(L1pagetable, OFW_VIRT_BASE + i * 0x00400000, 1270 &proc0_pt_ofw[i]); 1271 for (i = 0; i < KERNEL_IO_PTS; i++) 1272 pmap_link_l2pt(L1pagetable, IO_VIRT_BASE + i * 0x00400000, 1273 &proc0_pt_io[i]); 1274 1275 /* 1276 * OK, we're done allocating. 1277 * Get a dump of OFW's translations, and make the appropriate 1278 * entries in the L2 pagetables that we just allocated. 1279 */ 1280 1281 ofw_getvirttranslations(); 1282 1283 for (oft = 0, tp = OFtranslations; oft < nOFtranslations; 1284 oft++, tp++) { 1285 1286 vm_offset_t va, pa; 1287 int npages = tp->size / NBPG; 1288 1289 /* Size must be an integral number of pages. */ 1290 if (npages == 0 || tp->size % NBPG != 0) 1291 panic("illegal ofw translation (size)"); 1292 1293 /* Make an entry for each page in the appropriate table. */ 1294 for (va = tp->virt, pa = tp->phys; npages > 0; 1295 va += NBPG, pa += NBPG, npages--) { 1296 /* 1297 * Map the top bits to the appropriate L2 pagetable. 1298 * The only allowable regions are page0, the 1299 * kernel-static area, and the ofw area. 1300 */ 1301 switch (va >> (L1_S_SHIFT + 2)) { 1302 case 0: 1303 /* page0 */ 1304 break; 1305 1306 #if KERNEL_IMG_PTS != 2 1307 #error "Update ofw translation range list" 1308 #endif 1309 case ( KERNEL_BASE >> (L1_S_SHIFT + 2)): 1310 case ((KERNEL_BASE + 0x00400000) >> (L1_S_SHIFT + 2)): 1311 /* kernel static area */ 1312 break; 1313 1314 case ( OFW_VIRT_BASE >> (L1_S_SHIFT + 2)): 1315 case ((OFW_VIRT_BASE + 0x00400000) >> (L1_S_SHIFT + 2)): 1316 case ((OFW_VIRT_BASE + 0x00800000) >> (L1_S_SHIFT + 2)): 1317 case ((OFW_VIRT_BASE + 0x00C00000) >> (L1_S_SHIFT + 2)): 1318 /* ofw area */ 1319 break; 1320 1321 case ( IO_VIRT_BASE >> (L1_S_SHIFT + 2)): 1322 case ((IO_VIRT_BASE + 0x00400000) >> (L1_S_SHIFT + 2)): 1323 case ((IO_VIRT_BASE + 0x00800000) >> (L1_S_SHIFT + 2)): 1324 case ((IO_VIRT_BASE + 0x00C00000) >> (L1_S_SHIFT + 2)): 1325 /* io area */ 1326 break; 1327 1328 default: 1329 /* illegal */ 1330 panic("illegal ofw translation (addr) %#lx", 1331 va); 1332 } 1333 1334 /* Make the entry. */ 1335 pmap_map_entry(L1pagetable, va, pa, 1336 VM_PROT_READ|VM_PROT_WRITE, 1337 (tp->mode & 0xC) == 0xC ? PTE_CACHE 1338 : PTE_NOCACHE); 1339 } 1340 } 1341 1342 /* 1343 * We don't actually want some of the mappings that we just 1344 * set up to appear in proc0's address space. In particular, 1345 * we don't want aliases to physical addresses that the kernel 1346 * has-mapped/will-map elsewhere. 1347 */ 1348 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1349 proc0_pt_sys.pv_va, L2_TABLE_SIZE); 1350 for (i = 0; i < KERNEL_IMG_PTS; i++) 1351 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1352 proc0_pt_kernel[i].pv_va, L2_TABLE_SIZE); 1353 for (i = 0; i < KERNEL_VMDATA_PTS; i++) 1354 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1355 proc0_pt_vmdata[i].pv_va, L2_TABLE_SIZE); 1356 for (i = 0; i < KERNEL_OFW_PTS; i++) 1357 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1358 proc0_pt_ofw[i].pv_va, L2_TABLE_SIZE); 1359 for (i = 0; i < KERNEL_IO_PTS; i++) 1360 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1361 proc0_pt_io[i].pv_va, L2_TABLE_SIZE); 1362 ofw_discardmappings(proc0_pt_kernel[KERNEL_IMG_PTS - 1].pv_va, 1363 msgbuf.pv_va, MSGBUFSIZE); 1364 1365 /* 1366 * We did not throw away the proc0_pt_pte and proc0_pagedir 1367 * mappings as well still want them. However we don't want them 1368 * cached ... 1369 * Really these should be uncached when allocated. 1370 */ 1371 pmap_map_entry(L1pagetable, proc0_pt_pte.pv_va, 1372 proc0_pt_pte.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1373 for (i = 0; i < (L1_TABLE_SIZE / NBPG); ++i) 1374 pmap_map_entry(L1pagetable, 1375 proc0_pagedir.pv_va + NBPG * i, 1376 proc0_pagedir.pv_pa + NBPG * i, 1377 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1378 1379 /* 1380 * Construct the proc0 L2 pagetables that map page tables. 1381 */ 1382 1383 /* Map entries in the L2pagetable used to map L2PTs. */ 1384 pmap_map_entry(L1pagetable, 1385 PTE_BASE + (0x00000000 >> (PGSHIFT-2)), 1386 proc0_pt_sys.pv_pa, 1387 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1388 for (i = 0; i < KERNEL_IMG_PTS; i++) 1389 pmap_map_entry(L1pagetable, 1390 PTE_BASE + ((KERNEL_BASE + i * 0x00400000) >> (PGSHIFT-2)), 1391 proc0_pt_kernel[i].pv_pa, 1392 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1393 pmap_map_entry(L1pagetable, 1394 PTE_BASE + (PTE_BASE >> (PGSHIFT-2)), 1395 proc0_pt_pte.pv_pa, 1396 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1397 for (i = 0; i < KERNEL_VMDATA_PTS; i++) 1398 pmap_map_entry(L1pagetable, 1399 PTE_BASE + ((KERNEL_VM_BASE + i * 0x00400000) 1400 >> (PGSHIFT-2)), proc0_pt_vmdata[i].pv_pa, 1401 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1402 for (i = 0; i < KERNEL_OFW_PTS; i++) 1403 pmap_map_entry(L1pagetable, 1404 PTE_BASE + ((OFW_VIRT_BASE + i * 0x00400000) 1405 >> (PGSHIFT-2)), proc0_pt_ofw[i].pv_pa, 1406 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1407 for (i = 0; i < KERNEL_IO_PTS; i++) 1408 pmap_map_entry(L1pagetable, 1409 PTE_BASE + ((IO_VIRT_BASE + i * 0x00400000) 1410 >> (PGSHIFT-2)), proc0_pt_io[i].pv_pa, 1411 VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 1412 1413 /* update the top of the kernel VM */ 1414 pmap_curmaxkvaddr = 1415 KERNEL_VM_BASE + (KERNEL_VMDATA_PTS * 0x00400000); 1416 1417 /* 1418 * gross hack for the sake of not thrashing the TLB and making 1419 * cache flush more efficient: blast l1 ptes for sections. 1420 */ 1421 for (oft = 0, tp = OFtranslations; oft < nOFtranslations; oft++, tp++) { 1422 vm_offset_t va = tp->virt; 1423 vm_offset_t pa = tp->phys; 1424 1425 if (((va | pa) & L1_S_OFFSET) == 0) { 1426 int nsections = tp->size / L1_S_SIZE; 1427 1428 while (nsections--) { 1429 /* XXXJRT prot?? */ 1430 pmap_map_section(L1pagetable, va, pa, 1431 VM_PROT_READ|VM_PROT_WRITE, 1432 (tp->mode & 0xC) == 0xC ? PTE_CACHE 1433 : PTE_NOCACHE); 1434 va += L1_S_SIZE; 1435 pa += L1_S_SIZE; 1436 } 1437 } 1438 } 1439 1440 /* OUT parameters are the new ttbbase and the pt which maps pts. */ 1441 *proc0_ttbbase = proc0_pagedir; 1442 *proc0_ptpt = proc0_pt_pte; 1443 } 1444 1445 1446 static void 1447 ofw_getphysmeminfo() 1448 { 1449 int phandle; 1450 int mem_len; 1451 int avail_len; 1452 int i; 1453 1454 if ((phandle = OF_finddevice("/memory")) == -1 || 1455 (mem_len = OF_getproplen(phandle, "reg")) <= 0 || 1456 (OFphysmem = (struct mem_region *)ofw_malloc(mem_len)) == 0 || 1457 OF_getprop(phandle, "reg", OFphysmem, mem_len) != mem_len || 1458 (avail_len = OF_getproplen(phandle, "available")) <= 0 || 1459 (OFphysavail = (struct mem_region *)ofw_malloc(avail_len)) == 0 || 1460 OF_getprop(phandle, "available", OFphysavail, avail_len) 1461 != avail_len) 1462 panic("can't get physmeminfo from OFW"); 1463 1464 nOFphysmem = mem_len / sizeof(struct mem_region); 1465 nOFphysavail = avail_len / sizeof(struct mem_region); 1466 1467 /* 1468 * Sort the blocks in each array into ascending address order. 1469 * Also, page-align all blocks. 1470 */ 1471 for (i = 0; i < 2; i++) { 1472 struct mem_region *tmp = (i == 0) ? OFphysmem : OFphysavail; 1473 struct mem_region *mp; 1474 int cnt = (i == 0) ? nOFphysmem : nOFphysavail; 1475 int j; 1476 1477 #ifdef OLDPRINTFS 1478 printf("ofw_getphysmeminfo: %d blocks\n", cnt); 1479 #endif 1480 1481 /* XXX - Convert all the values to host order. -JJK */ 1482 for (j = 0, mp = tmp; j < cnt; j++, mp++) { 1483 mp->start = of_decode_int((unsigned char *)&mp->start); 1484 mp->size = of_decode_int((unsigned char *)&mp->size); 1485 } 1486 1487 for (j = 0, mp = tmp; j < cnt; j++, mp++) { 1488 u_int s, sz; 1489 struct mem_region *mp1; 1490 1491 /* Page-align start of the block. */ 1492 s = mp->start % NBPG; 1493 if (s != 0) { 1494 s = (NBPG - s); 1495 1496 if (mp->size >= s) { 1497 mp->start += s; 1498 mp->size -= s; 1499 } 1500 } 1501 1502 /* Page-align the size. */ 1503 mp->size -= mp->size % NBPG; 1504 1505 /* Handle empty block. */ 1506 if (mp->size == 0) { 1507 bcopy(mp + 1, mp, (cnt - (mp - tmp)) 1508 * sizeof(struct mem_region)); 1509 cnt--; 1510 mp--; 1511 continue; 1512 } 1513 1514 /* Bubble sort. */ 1515 s = mp->start; 1516 sz = mp->size; 1517 for (mp1 = tmp; mp1 < mp; mp1++) 1518 if (s < mp1->start) 1519 break; 1520 if (mp1 < mp) { 1521 bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1); 1522 mp1->start = s; 1523 mp1->size = sz; 1524 } 1525 } 1526 1527 #ifdef OLDPRINTFS 1528 for (mp = tmp; mp->size; mp++) { 1529 printf("%x, %x\n", mp->start, mp->size); 1530 } 1531 #endif 1532 } 1533 } 1534 1535 1536 static void 1537 ofw_getvirttranslations(void) 1538 { 1539 int mmu_phandle; 1540 int mmu_ihandle; 1541 int trans_len; 1542 int over, len; 1543 int i; 1544 struct mem_translation *tp; 1545 1546 mmu_ihandle = ofw_mmu_ihandle(); 1547 1548 /* overallocate to avoid increases during allocation */ 1549 over = 4 * sizeof(struct mem_translation); 1550 if ((mmu_phandle = OF_instance_to_package(mmu_ihandle)) == -1 || 1551 (len = OF_getproplen(mmu_phandle, "translations")) <= 0 || 1552 (OFtranslations = ofw_malloc(len + over)) == 0 || 1553 (trans_len = OF_getprop(mmu_phandle, "translations", 1554 OFtranslations, len + over)) > (len + over)) 1555 panic("can't get virttranslations from OFW"); 1556 1557 /* XXX - Convert all the values to host order. -JJK */ 1558 nOFtranslations = trans_len / sizeof(struct mem_translation); 1559 #ifdef OLDPRINTFS 1560 printf("ofw_getvirtmeminfo: %d blocks\n", nOFtranslations); 1561 #endif 1562 for (i = 0, tp = OFtranslations; i < nOFtranslations; i++, tp++) { 1563 tp->virt = of_decode_int((unsigned char *)&tp->virt); 1564 tp->size = of_decode_int((unsigned char *)&tp->size); 1565 tp->phys = of_decode_int((unsigned char *)&tp->phys); 1566 tp->mode = of_decode_int((unsigned char *)&tp->mode); 1567 } 1568 } 1569 1570 /* 1571 * ofw_valloc: allocate blocks of VM for IO and other special purposes 1572 */ 1573 typedef struct _vfree { 1574 struct _vfree *pNext; 1575 vm_offset_t start; 1576 vm_size_t size; 1577 } VFREE, *PVFREE; 1578 1579 static VFREE vfinitial = { NULL, IO_VIRT_BASE, IO_VIRT_SIZE }; 1580 1581 static PVFREE vflist = &vfinitial; 1582 1583 static vm_offset_t 1584 ofw_valloc(size, align) 1585 vm_offset_t size; 1586 vm_offset_t align; 1587 { 1588 PVFREE *ppvf; 1589 PVFREE pNew; 1590 vm_offset_t new; 1591 vm_offset_t lead; 1592 1593 for (ppvf = &vflist; *ppvf; ppvf = &((*ppvf)->pNext)) { 1594 if (align == 0) { 1595 new = (*ppvf)->start; 1596 lead = 0; 1597 } else { 1598 new = ((*ppvf)->start + (align - 1)) & ~(align - 1); 1599 lead = new - (*ppvf)->start; 1600 } 1601 1602 if (((*ppvf)->size - lead) >= size) { 1603 if (lead == 0) { 1604 /* using whole block */ 1605 if (size == (*ppvf)->size) { 1606 /* splice out of list */ 1607 (*ppvf) = (*ppvf)->pNext; 1608 } else { /* tail of block is free */ 1609 (*ppvf)->start = new + size; 1610 (*ppvf)->size -= size; 1611 } 1612 } else { 1613 vm_size_t tail = ((*ppvf)->start 1614 + (*ppvf)->size) - (new + size); 1615 /* free space at beginning */ 1616 (*ppvf)->size = lead; 1617 1618 if (tail != 0) { 1619 /* free space at tail */ 1620 pNew = ofw_malloc(sizeof(VFREE)); 1621 pNew->pNext = (*ppvf)->pNext; 1622 (*ppvf)->pNext = pNew; 1623 pNew->start = new + size; 1624 pNew->size = tail; 1625 } 1626 } 1627 return new; 1628 } /* END if */ 1629 } /* END for */ 1630 1631 return -1; 1632 } 1633 1634 vm_offset_t 1635 ofw_map(pa, size, cb_bits) 1636 vm_offset_t pa; 1637 vm_size_t size; 1638 int cb_bits; 1639 { 1640 vm_offset_t va; 1641 1642 if ((va = ofw_valloc(size, size)) == -1) 1643 panic("cannot alloc virtual memory for %#lx", pa); 1644 1645 ofw_claimvirt(va, size, 0); /* make sure OFW knows about the memory */ 1646 1647 ofw_settranslation(va, pa, size, L2_AP(AP_KRW) | cb_bits); 1648 1649 return va; 1650 } 1651 1652 static int 1653 ofw_mem_ihandle(void) 1654 { 1655 static int mem_ihandle = 0; 1656 int chosen; 1657 1658 if (mem_ihandle != 0) 1659 return(mem_ihandle); 1660 1661 if ((chosen = OF_finddevice("/chosen")) == -1 || 1662 OF_getprop(chosen, "memory", &mem_ihandle, sizeof(int)) < 0) 1663 panic("ofw_mem_ihandle"); 1664 1665 mem_ihandle = of_decode_int((unsigned char *)&mem_ihandle); 1666 1667 return(mem_ihandle); 1668 } 1669 1670 1671 static int 1672 ofw_mmu_ihandle(void) 1673 { 1674 static int mmu_ihandle = 0; 1675 int chosen; 1676 1677 if (mmu_ihandle != 0) 1678 return(mmu_ihandle); 1679 1680 if ((chosen = OF_finddevice("/chosen")) == -1 || 1681 OF_getprop(chosen, "mmu", &mmu_ihandle, sizeof(int)) < 0) 1682 panic("ofw_mmu_ihandle"); 1683 1684 mmu_ihandle = of_decode_int((unsigned char *)&mmu_ihandle); 1685 1686 return(mmu_ihandle); 1687 } 1688 1689 1690 /* Return -1 on failure. */ 1691 static vm_offset_t 1692 ofw_claimphys(pa, size, align) 1693 vm_offset_t pa; 1694 vm_size_t size; 1695 vm_offset_t align; 1696 { 1697 int mem_ihandle = ofw_mem_ihandle(); 1698 1699 /* printf("ofw_claimphys (%x, %x, %x) --> ", pa, size, align);*/ 1700 if (align == 0) { 1701 /* Allocate at specified base; alignment is ignored. */ 1702 pa = OF_call_method_1("claim", mem_ihandle, 3, pa, size, align); 1703 } else { 1704 /* Allocate anywhere, with specified alignment. */ 1705 pa = OF_call_method_1("claim", mem_ihandle, 2, size, align); 1706 } 1707 1708 /* printf("%x\n", pa);*/ 1709 return(pa); 1710 } 1711 1712 1713 #if 0 1714 /* Return -1 on failure. */ 1715 static vm_offset_t 1716 ofw_releasephys(pa, size) 1717 vm_offset_t pa; 1718 vm_size_t size; 1719 { 1720 int mem_ihandle = ofw_mem_ihandle(); 1721 1722 /* printf("ofw_releasephys (%x, %x)\n", pa, size);*/ 1723 1724 return (OF_call_method_1("release", mem_ihandle, 2, pa, size)); 1725 } 1726 #endif 1727 1728 /* Return -1 on failure. */ 1729 static vm_offset_t 1730 ofw_claimvirt(va, size, align) 1731 vm_offset_t va; 1732 vm_size_t size; 1733 vm_offset_t align; 1734 { 1735 int mmu_ihandle = ofw_mmu_ihandle(); 1736 1737 /*printf("ofw_claimvirt (%x, %x, %x) --> ", va, size, align);*/ 1738 if (align == 0) { 1739 /* Allocate at specified base; alignment is ignored. */ 1740 va = OF_call_method_1("claim", mmu_ihandle, 3, va, size, align); 1741 } else { 1742 /* Allocate anywhere, with specified alignment. */ 1743 va = OF_call_method_1("claim", mmu_ihandle, 2, size, align); 1744 } 1745 1746 /*printf("%x\n", va);*/ 1747 return(va); 1748 } 1749 1750 1751 /* Return -1 if no mapping. */ 1752 vm_offset_t 1753 ofw_gettranslation(va) 1754 vm_offset_t va; 1755 { 1756 int mmu_ihandle = ofw_mmu_ihandle(); 1757 vm_offset_t pa; 1758 int mode; 1759 int exists; 1760 1761 /*printf("ofw_gettranslation (%x) --> ", va);*/ 1762 exists = 0; /* gets set to true if translation exists */ 1763 if (OF_call_method("translate", mmu_ihandle, 1, 3, va, &pa, &mode, 1764 &exists) != 0) 1765 return(-1); 1766 1767 /*printf("%x\n", exists ? pa : -1);*/ 1768 return(exists ? pa : -1); 1769 } 1770 1771 1772 static void 1773 ofw_settranslation(va, pa, size, mode) 1774 vm_offset_t va; 1775 vm_offset_t pa; 1776 vm_size_t size; 1777 int mode; 1778 { 1779 int mmu_ihandle = ofw_mmu_ihandle(); 1780 1781 /*printf("ofw_settranslation (%x, %x, %x, %x) --> void", va, pa, size, mode);*/ 1782 if (OF_call_method("map", mmu_ihandle, 4, 0, pa, va, size, mode) != 0) 1783 panic("ofw_settranslation failed"); 1784 } 1785 1786 /* 1787 * Allocation routine used before the kernel takes over memory. 1788 * Use this for efficient storage for things that aren't rounded to 1789 * page size. 1790 * 1791 * The point here is not necessarily to be very efficient (even though 1792 * that's sort of nice), but to do proper dynamic allocation to avoid 1793 * size-limitation errors. 1794 * 1795 */ 1796 1797 typedef struct _leftover { 1798 struct _leftover *pNext; 1799 vm_size_t size; 1800 } LEFTOVER, *PLEFTOVER; 1801 1802 /* leftover bits of pages. first word is pointer to next. 1803 second word is size of leftover */ 1804 static PLEFTOVER leftovers = NULL; 1805 1806 static void * 1807 ofw_malloc(size) 1808 vm_size_t size; 1809 { 1810 PLEFTOVER *ppLeftover; 1811 PLEFTOVER pLeft; 1812 pv_addr_t new; 1813 vm_size_t newSize, claim_size; 1814 1815 /* round and set minimum size */ 1816 size = max(sizeof(LEFTOVER), 1817 ((size + (sizeof(LEFTOVER) - 1)) & ~(sizeof(LEFTOVER) - 1))); 1818 1819 for (ppLeftover = &leftovers; *ppLeftover; 1820 ppLeftover = &((*ppLeftover)->pNext)) 1821 if ((*ppLeftover)->size >= size) 1822 break; 1823 1824 if (*ppLeftover) { /* have a leftover of the right size */ 1825 /* remember the leftover */ 1826 new.pv_va = (vm_offset_t)*ppLeftover; 1827 if ((*ppLeftover)->size < (size + sizeof(LEFTOVER))) { 1828 /* splice out of chain */ 1829 *ppLeftover = (*ppLeftover)->pNext; 1830 } else { 1831 /* remember the next pointer */ 1832 pLeft = (*ppLeftover)->pNext; 1833 newSize = (*ppLeftover)->size - size; /* reduce size */ 1834 /* move pointer */ 1835 *ppLeftover = (PLEFTOVER)(((vm_offset_t)*ppLeftover) 1836 + size); 1837 (*ppLeftover)->pNext = pLeft; 1838 (*ppLeftover)->size = newSize; 1839 } 1840 } else { 1841 claim_size = (size + NBPG - 1) & ~(NBPG - 1); 1842 ofw_claimpages(&virt_freeptr, &new, claim_size); 1843 if ((size + sizeof(LEFTOVER)) <= claim_size) { 1844 pLeft = (PLEFTOVER)(new.pv_va + size); 1845 pLeft->pNext = leftovers; 1846 pLeft->size = claim_size - size; 1847 leftovers = pLeft; 1848 } 1849 } 1850 1851 return (void *)(new.pv_va); 1852 } 1853 1854 /* 1855 * Here is a really, really sleazy free. It's not used right now, 1856 * because it's not worth the extra complexity for just a few bytes. 1857 * 1858 */ 1859 #if 0 1860 static void 1861 ofw_free(addr, size) 1862 vm_offset_t addr; 1863 vm_size_t size; 1864 { 1865 PLEFTOVER pLeftover = (PLEFTOVER)addr; 1866 1867 /* splice right into list without checks or compaction */ 1868 pLeftover->pNext = leftovers; 1869 pLeftover->size = size; 1870 leftovers = pLeftover; 1871 } 1872 #endif 1873 1874 /* 1875 * Allocate and zero round(size)/NBPG pages of memory. 1876 * We guarantee that the allocated memory will be 1877 * aligned to a boundary equal to the smallest power of 1878 * 2 greater than or equal to size. 1879 * free_pp is an IN/OUT parameter which points to the 1880 * last allocated virtual address in an allocate-downwards 1881 * stack. pv_p is an OUT parameter which contains the 1882 * virtual and physical base addresses of the allocated 1883 * memory. 1884 */ 1885 static void 1886 ofw_claimpages(free_pp, pv_p, size) 1887 vm_offset_t *free_pp; 1888 pv_addr_t *pv_p; 1889 vm_size_t size; 1890 { 1891 /* round-up to page boundary */ 1892 vm_size_t alloc_size = (size + NBPG - 1) & ~(NBPG - 1); 1893 vm_size_t aligned_size; 1894 vm_offset_t va, pa; 1895 1896 if (alloc_size == 0) 1897 panic("ofw_claimpages zero"); 1898 1899 for (aligned_size = 1; aligned_size < alloc_size; aligned_size <<= 1) 1900 ; 1901 1902 /* The only way to provide the alignment guarantees is to 1903 * allocate the virtual and physical ranges separately, 1904 * then do an explicit map call. 1905 */ 1906 va = (*free_pp & ~(aligned_size - 1)) - aligned_size; 1907 if (ofw_claimvirt(va, alloc_size, 0) != va) 1908 panic("ofw_claimpages va alloc"); 1909 pa = ofw_claimphys(0, alloc_size, aligned_size); 1910 if (pa == -1) 1911 panic("ofw_claimpages pa alloc"); 1912 /* XXX - what mode? -JJK */ 1913 ofw_settranslation(va, pa, alloc_size, -1); 1914 1915 /* The memory's mapped-in now, so we can zero it. */ 1916 bzero((char *)va, alloc_size); 1917 1918 /* Set OUT parameters. */ 1919 *free_pp = va; 1920 pv_p->pv_va = va; 1921 pv_p->pv_pa = pa; 1922 } 1923 1924 1925 static void 1926 ofw_discardmappings(L2pagetable, va, size) 1927 vm_offset_t L2pagetable; 1928 vm_offset_t va; 1929 vm_size_t size; 1930 { 1931 /* round-up to page boundary */ 1932 vm_size_t alloc_size = (size + NBPG - 1) & ~(NBPG - 1); 1933 int npages = alloc_size / NBPG; 1934 1935 if (npages == 0) 1936 panic("ofw_discardmappings zero"); 1937 1938 /* Discard each mapping. */ 1939 for (; npages > 0; va += NBPG, npages--) { 1940 /* Sanity. The current entry should be non-null. */ 1941 if (ReadWord(L2pagetable + ((va >> 10) & 0x00000FFC)) == 0) 1942 panic("ofw_discardmappings zero entry"); 1943 1944 /* Clear the entry. */ 1945 WriteWord(L2pagetable + ((va >> 10) & 0x00000FFC), 0); 1946 } 1947 } 1948 1949 1950 static void 1951 ofw_initallocator(void) 1952 { 1953 1954 } 1955