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