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