1 /* $NetBSD: Locore.c,v 1.35 2021/02/28 20:27:40 thorpej Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <lib/libsa/stand.h> 36 37 #include <machine/cpu.h> 38 #include <powerpc/oea/spr.h> 39 40 #include "openfirm.h" 41 42 static int (*openfirmware)(void *); 43 44 static void startup(void *, int, int (*)(void *), char *, int) 45 __attribute__((__used__)); 46 static void setup(void); 47 48 #ifdef HEAP_VARIABLE 49 #ifndef HEAP_SIZE 50 #define HEAP_SIZE 0x20000 51 #endif 52 char *heapspace; 53 #endif 54 55 static int stack[8192/4 + 4] __attribute__((__used__)); 56 57 #ifdef XCOFF_GLUE 58 __asm( 59 " .text \n" 60 " .globl _entry \n" 61 "_entry: \n" 62 " .long _start,0,0 \n" 63 ); 64 #endif /* XCOFF_GLUE */ 65 66 __asm( 67 " .text \n" 68 " .globl _start \n" 69 "_start: \n" 70 " sync \n" 71 " isync \n" 72 " lis %r1,stack@ha \n" 73 " addi %r1,%r1,stack@l \n" 74 " addi %r1,%r1,8192 \n" 75 " \n" 76 " mfmsr %r8 \n" 77 " li %r0,0 \n" 78 " mtmsr %r0 \n" 79 " isync \n" 80 " \n" 81 " \n" /* test for 601 */ 82 " mfspr %r0,287 \n" /* mfpvbr %r0 PVR = 287 */ 83 " srwi %r0,%r0,0x10 \n" 84 " cmplwi %r0,0x02 \n" /* 601 CPU = 0x0001 */ 85 " blt 2f \n" /* skip over non-601 BAT setup */ 86 " cmplwi %r0,0x39 \n" /* PPC970 */ 87 " blt 0f \n" 88 " cmplwi %r0,0x45 \n" /* PPC970GX */ 89 " ble 1f \n" 90 /* non PPC 601 BATs */ 91 "0: li %r0,0 \n" 92 " mtibatu 0,%r0 \n" 93 " mtibatu 1,%r0 \n" 94 " mtibatu 2,%r0 \n" 95 " mtibatu 3,%r0 \n" 96 " mtdbatu 0,%r0 \n" 97 " mtdbatu 1,%r0 \n" 98 " mtdbatu 2,%r0 \n" 99 " mtdbatu 3,%r0 \n" 100 " \n" 101 " li %r9,0x12 \n" /* BATL(0, BAT_M, BAT_PP_RW) */ 102 " mtibatl 0,%r9 \n" 103 " mtdbatl 0,%r9 \n" 104 " li %r9,0x1ffe \n" /* BATU(0, BAT_BL_256M, BAT_Vs) */ 105 " mtibatu 0,%r9 \n" 106 " mtdbatu 0,%r9 \n" 107 " b 3f \n" 108 /* 970 initialization stuff */ 109 "1: \n" 110 /* make sure we're in bridge mode */ 111 " clrldi %r8,%r8,3 \n" 112 " mtmsrd %r8 \n" 113 " isync \n" 114 /* clear HID5 DCBZ bits (56/57), need to do this early */ 115 " mfspr %r9,0x3f6 \n" 116 " rldimi %r9,0,6,56 \n" 117 " sync \n" 118 " mtspr 0x3f6,%r9 \n" 119 " isync \n" 120 " sync \n" 121 /* Setup HID1 features, prefetch + i-cacheability controlled by PTE */ 122 " mfspr %r9,0x3f1 \n" 123 " li %r11,0x1200 \n" 124 " sldi %r11,%r11,44 \n" 125 " or %r9,%r9,%r11 \n" 126 " mtspr 0x3f1,%r9 \n" 127 " isync \n" 128 " sync \n" 129 " b 3f \n" 130 /* PPC 601 BATs */ 131 "2: li %r0,0 \n" 132 " mtibatu 0,%r0 \n" 133 " mtibatu 1,%r0 \n" 134 " mtibatu 2,%r0 \n" 135 " mtibatu 3,%r0 \n" 136 " \n" 137 " li %r9,0x7f \n" 138 " mtibatl 0,%r9 \n" 139 " li %r9,0x1a \n" 140 " mtibatu 0,%r9 \n" 141 " \n" 142 " lis %r9,0x80 \n" 143 " addi %r9,%r9,0x7f \n" 144 " mtibatl 1,%r9 \n" 145 " lis %r9,0x80 \n" 146 " addi %r9,%r9,0x1a \n" 147 " mtibatu 1,%r9 \n" 148 " \n" 149 " lis %r9,0x100 \n" 150 " addi %r9,%r9,0x7f \n" 151 " mtibatl 2,%r9 \n" 152 " lis %r9,0x100 \n" 153 " addi %r9,%r9,0x1a \n" 154 " mtibatu 2,%r9 \n" 155 " \n" 156 " lis %r9,0x180 \n" 157 " addi %r9,%r9,0x7f \n" 158 " mtibatl 3,%r9 \n" 159 " lis %r9,0x180 \n" 160 " addi %r9,%r9,0x1a \n" 161 " mtibatu 3,%r9 \n" 162 " \n" 163 "3: isync \n" 164 " \n" 165 " mtmsr %r8 \n" 166 " isync \n" 167 " \n" 168 /* 169 * Make sure that .bss is zeroed 170 */ 171 " \n" 172 " li %r0,0 \n" 173 " lis %r8,_edata@ha \n" 174 " addi %r8,%r8,_edata@l\n" 175 " lis %r9,_end@ha \n" 176 " addi %r9,%r9,_end@l \n" 177 " \n" 178 "5: cmpw 0,%r8,%r9 \n" 179 " bge 6f \n" 180 /* 181 * clear by bytes to avoid ppc601 alignment exceptions 182 */ 183 " stb %r0,0(%r8) \n" 184 " stb %r0,1(%r8) \n" 185 " stb %r0,2(%r8) \n" 186 " stb %r0,3(%r8) \n" 187 " addi %r8,%r8,4 \n" 188 " b 5b \n" 189 " \n" 190 "6: b startup \n" 191 ); 192 193 #if 0 194 static int 195 openfirmware(void *arg) 196 { 197 198 __asm volatile ("sync; isync"); 199 openfirmware_entry(arg); 200 __asm volatile ("sync; isync"); 201 } 202 #endif 203 204 int ofw_real_mode; 205 int ofw_address_cells; 206 int ofw_size_cells; 207 208 int ofw_root; /* / */ 209 int ofw_options; /* /options */ 210 int ofw_openprom; /* /openprom */ 211 int ofw_chosen; /* /chosen (package) */ 212 int ofw_stdin; /* /chosen/stdin */ 213 int ofw_stdout; /* /chosen/stdout */ 214 int ofw_memory_ihandle; /* /chosen/memory */ 215 int ofw_mmu_ihandle; /* /chosen/mmu */ 216 217 bool 218 ofw_option_truefalse(const char *prop, int proplen) 219 { 220 /* These are all supposed to be strings. */ 221 switch (prop[0]) { 222 case 'y': 223 case 'Y': 224 case 't': 225 case 'T': 226 case '1': 227 return true; 228 } 229 return false; 230 } 231 232 static void 233 startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) 234 { 235 236 openfirmware = openfirm; 237 setup(); 238 main(); 239 OF_exit(); 240 } 241 242 #if 0 243 void 244 OF_enter(void) 245 { 246 static struct { 247 const char *name; 248 int nargs; 249 int nreturns; 250 } args = { 251 "enter", 252 0, 253 0 254 }; 255 256 openfirmware(&args); 257 } 258 #endif /* OF_enter */ 259 260 __dead void 261 OF_exit(void) 262 { 263 static struct { 264 const char *name; 265 int nargs; 266 int nreturns; 267 } args = { 268 "exit", 269 0, 270 0 271 }; 272 273 openfirmware(&args); 274 for (;;); /* just in case */ 275 } 276 277 int 278 OF_finddevice(const char *name) 279 { 280 static struct { 281 const char *name; 282 int nargs; 283 int nreturns; 284 const char *device; 285 int phandle; 286 } args = { 287 "finddevice", 288 1, 289 1, 290 }; 291 292 args.device = name; 293 if (openfirmware(&args) == -1) 294 return -1; 295 return args.phandle; 296 } 297 298 int 299 OF_instance_to_package(int ihandle) 300 { 301 static struct { 302 const char *name; 303 int nargs; 304 int nreturns; 305 int ihandle; 306 int phandle; 307 } args = { 308 "instance-to-package", 309 1, 310 1, 311 }; 312 313 args.ihandle = ihandle; 314 if (openfirmware(&args) == -1) 315 return -1; 316 return args.phandle; 317 } 318 319 int 320 OF_getprop(int handle, const char *prop, void *buf, int buflen) 321 { 322 static struct { 323 const char *name; 324 int nargs; 325 int nreturns; 326 int phandle; 327 const char *prop; 328 void *buf; 329 int buflen; 330 int size; 331 } args = { 332 "getprop", 333 4, 334 1, 335 }; 336 337 args.phandle = handle; 338 args.prop = prop; 339 args.buf = buf; 340 args.buflen = buflen; 341 if (openfirmware(&args) == -1) 342 return -1; 343 return args.size; 344 } 345 346 #ifdef __notyet__ /* Has a bug on FirePower */ 347 int 348 OF_setprop(int handle, const char *prop, void *buf, int len) 349 { 350 static struct { 351 const char *name; 352 int nargs; 353 int nreturns; 354 int phandle; 355 const char *prop; 356 void *buf; 357 int len; 358 int size; 359 } args = { 360 "setprop", 361 4, 362 1, 363 }; 364 365 args.phandle = handle; 366 args.prop = prop; 367 args.buf = buf; 368 args.len = len; 369 if (openfirmware(&args) == -1) 370 return -1; 371 return args.size; 372 } 373 #endif 374 375 int 376 OF_open(const char *dname) 377 { 378 static struct { 379 const char *name; 380 int nargs; 381 int nreturns; 382 const char *dname; 383 int handle; 384 } args = { 385 "open", 386 1, 387 1, 388 }; 389 390 #ifdef OFW_DEBUG 391 printf("OF_open(%s) -> ", dname); 392 #endif 393 args.dname = dname; 394 if (openfirmware(&args) == -1 || 395 args.handle == 0) { 396 #ifdef OFW_DEBUG 397 printf("lose\n"); 398 #endif 399 return -1; 400 } 401 #ifdef OFW_DEBUG 402 printf("%d\n", args.handle); 403 #endif 404 return args.handle; 405 } 406 407 void 408 OF_close(int handle) 409 { 410 static struct { 411 const char *name; 412 int nargs; 413 int nreturns; 414 int handle; 415 } args = { 416 "close", 417 1, 418 0, 419 }; 420 421 #ifdef OFW_DEBUG 422 printf("OF_close(%d)\n", handle); 423 #endif 424 args.handle = handle; 425 openfirmware(&args); 426 } 427 428 int 429 OF_write(int handle, void *addr, int len) 430 { 431 static struct { 432 const char *name; 433 int nargs; 434 int nreturns; 435 int ihandle; 436 void *addr; 437 int len; 438 int actual; 439 } args = { 440 "write", 441 3, 442 1, 443 }; 444 445 #ifdef OFW_DEBUG 446 if (len != 1) 447 printf("OF_write(%d, %p, %x) -> ", handle, addr, len); 448 #endif 449 args.ihandle = handle; 450 args.addr = addr; 451 args.len = len; 452 if (openfirmware(&args) == -1) { 453 #ifdef OFW_DEBUG 454 printf("lose\n"); 455 #endif 456 return -1; 457 } 458 #ifdef OFW_DEBUG 459 if (len != 1) 460 printf("%x\n", args.actual); 461 #endif 462 return args.actual; 463 } 464 465 int 466 OF_read(int handle, void *addr, int len) 467 { 468 static struct { 469 const char *name; 470 int nargs; 471 int nreturns; 472 int ihandle; 473 void *addr; 474 int len; 475 int actual; 476 } args = { 477 "read", 478 3, 479 1, 480 }; 481 482 #ifdef OFW_DEBUG 483 if (len != 1) 484 printf("OF_read(%d, %p, %x) -> ", handle, addr, len); 485 #endif 486 args.ihandle = handle; 487 args.addr = addr; 488 args.len = len; 489 if (openfirmware(&args) == -1) { 490 #ifdef OFW_DEBUG 491 printf("lose\n"); 492 #endif 493 return -1; 494 } 495 #ifdef OFW_DEBUG 496 if (len != 1) 497 printf("%x\n", args.actual); 498 #endif 499 return args.actual; 500 } 501 502 int 503 OF_seek(int handle, u_quad_t pos) 504 { 505 static struct { 506 const char *name; 507 int nargs; 508 int nreturns; 509 int handle; 510 int poshi; 511 int poslo; 512 int status; 513 } args = { 514 "seek", 515 3, 516 1, 517 }; 518 519 #ifdef OFW_DEBUG 520 printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos); 521 #endif 522 args.handle = handle; 523 args.poshi = (int)(pos >> 32); 524 args.poslo = (int)pos; 525 if (openfirmware(&args) == -1) { 526 #ifdef OFW_DEBUG 527 printf("lose\n"); 528 #endif 529 return -1; 530 } 531 #ifdef OFW_DEBUG 532 printf("%d\n", args.status); 533 #endif 534 return args.status; 535 } 536 537 void * 538 OF_claim(void *virt, u_int size, u_int align) 539 { 540 static struct { 541 const char *name; 542 int nargs; 543 int nreturns; 544 void *virt; 545 u_int size; 546 u_int align; 547 void *baseaddr; 548 } args = { 549 "claim", 550 3, 551 1, 552 }; 553 554 #ifdef OFW_DEBUG 555 printf("OF_claim(%p, %x, %x) -> ", virt, size, align); 556 #endif 557 args.virt = virt; 558 args.size = size; 559 args.align = align; 560 if (openfirmware(&args) == -1) { 561 #ifdef OFW_DEBUG 562 printf("lose\n"); 563 #endif 564 return (void *)-1; 565 } 566 #ifdef OFW_DEBUG 567 printf("%p\n", args.baseaddr); 568 #endif 569 return args.baseaddr; 570 } 571 572 void 573 OF_release(void *virt, u_int size) 574 { 575 static struct { 576 const char *name; 577 int nargs; 578 int nreturns; 579 void *virt; 580 u_int size; 581 } args = { 582 "release", 583 2, 584 0, 585 }; 586 587 #ifdef OFW_DEBUG 588 printf("OF_release(%p, %x)\n", virt, size); 589 #endif 590 args.virt = virt; 591 args.size = size; 592 openfirmware(&args); 593 } 594 595 int 596 OF_milliseconds(void) 597 { 598 static struct { 599 const char *name; 600 int nargs; 601 int nreturns; 602 int ms; 603 } args = { 604 "milliseconds", 605 0, 606 1, 607 }; 608 609 openfirmware(&args); 610 return args.ms; 611 } 612 613 #ifdef __notyet__ 614 void 615 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) 616 { 617 static struct { 618 const char *name; 619 int nargs; 620 int nreturns; 621 void *virt; 622 u_int size; 623 void (*entry)(); 624 void *arg; 625 u_int len; 626 } args = { 627 "chain", 628 5, 629 0, 630 }; 631 632 args.virt = virt; 633 args.size = size; 634 args.entry = entry; 635 args.arg = arg; 636 args.len = len; 637 openfirmware(&args); 638 } 639 #else 640 void 641 OF_chain(void *virt, u_int size, boot_entry_t entry, void *arg, u_int len) 642 { 643 /* 644 * This is a REALLY dirty hack till the firmware gets this going 645 */ 646 #if 0 647 OF_release(virt, size); 648 #endif 649 entry(0, 0, openfirmware, arg, len); 650 } 651 #endif 652 653 int 654 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, 655 int *cells) 656 { 657 static struct { 658 const char *name; 659 int nargs; 660 int nreturns; 661 const char *method; 662 int ihandle; 663 int args_n_results[12]; 664 } args = { 665 "call-method", 666 2, 667 1, 668 }; 669 int *ip, n; 670 671 if (nargs > 6) 672 return -1; 673 674 args.nargs = nargs + 2; 675 args.nreturns = nreturns + 1; 676 args.method = method; 677 args.ihandle = ihandle; 678 679 for (ip = args.args_n_results + (n = nargs); --n >= 0;) 680 *--ip = *cells++; 681 682 if (openfirmware(&args) == -1) { 683 return -1; 684 } 685 686 if (args.args_n_results[nargs]) { 687 return args.args_n_results[nargs]; 688 } 689 690 for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) 691 *cells++ = *--ip; 692 693 return 0; 694 } 695 696 static void 697 setup(void) 698 { 699 char prop[32]; 700 int proplen; 701 const char *reason = NULL; 702 703 if ((ofw_chosen = OF_finddevice("/chosen")) == -1) 704 OF_exit(); 705 if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, sizeof(ofw_stdin)) != 706 sizeof(ofw_stdin) || 707 OF_getprop(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) != 708 sizeof(ofw_stdout)) 709 OF_exit(); 710 711 if (ofw_stdout == 0) { 712 /* screen should be console, but it is not open */ 713 ofw_stdout = OF_open("screen"); 714 } 715 716 #ifdef HEAP_VARIABLE 717 uint32_t pvr, vers, hsize = HEAP_SIZE; 718 719 __asm volatile ("mfpvr %0" : "=r"(pvr)); 720 vers = pvr >> 16; 721 if (vers >= IBM970 && vers <= IBM970GX) hsize = 0x800000; 722 723 heapspace = OF_claim(0, hsize, NBPG); 724 if (heapspace == (char *)-1) { 725 panic("Failed to allocate heap"); 726 } 727 728 setheap(heapspace, heapspace + HEAP_SIZE); 729 #endif /* HEAP_VARIABLE */ 730 731 ofw_root = OF_finddevice("/"); 732 ofw_options = OF_finddevice("/options"); 733 ofw_openprom = OF_finddevice("/openprom"); 734 ofw_chosen = OF_finddevice("/chosen"); 735 736 if (ofw_root == -1) { 737 reason = "No root node"; 738 goto bad_environment; 739 } 740 if (ofw_chosen == -1) { 741 reason = "No chosen node"; 742 goto bad_environment; 743 } 744 745 if (ofw_options != -1) { 746 proplen = OF_getprop(ofw_options, "real-mode?", prop, 747 sizeof(prop)); 748 if (proplen > 0) { 749 ofw_real_mode = ofw_option_truefalse(prop, proplen); 750 } 751 } 752 753 /* 754 * Get #address-cells and #size-cells. 755 */ 756 ofw_address_cells = 1; 757 ofw_size_cells = 1; 758 OF_getprop(ofw_root, "#address-cells", &ofw_address_cells, 759 sizeof(ofw_address_cells)); 760 OF_getprop(ofw_root, "#size-cells", &ofw_size_cells, 761 sizeof(ofw_size_cells)); 762 763 /* See loadfile_machdep.c */ 764 if (ofw_size_cells != 1) { 765 printf("#size-cells = %d not yet supported\n", ofw_size_cells); 766 reason = "unsupported #size-cells"; 767 goto bad_environment; 768 } 769 770 /* 771 * Get the ihandle on /chosen/memory and /chosen/mmu. 772 */ 773 ofw_memory_ihandle = -1; 774 ofw_mmu_ihandle = -1; 775 OF_getprop(ofw_chosen, "memory", &ofw_memory_ihandle, 776 sizeof(ofw_memory_ihandle)); 777 OF_getprop(ofw_chosen, "mmu", &ofw_mmu_ihandle, 778 sizeof(ofw_mmu_ihandle)); 779 if (ofw_memory_ihandle == -1) { 780 reason = "no /chosen/memory"; 781 goto bad_environment; 782 } 783 if (ofw_mmu_ihandle == -1) { 784 reason = "no /chosen/mmu"; 785 goto bad_environment; 786 } 787 788 return; 789 790 bad_environment: 791 if (reason == NULL) { 792 reason = "unknown reason"; 793 } 794 printf("Invalid Openfirmware environment: %s\n", reason); 795 OF_exit(); 796 } 797 798 void 799 putchar(int c) 800 { 801 char ch = c; 802 803 if (c == '\n') 804 putchar('\r'); 805 OF_write(ofw_stdout, &ch, 1); 806 } 807 808 int 809 getchar(void) 810 { 811 unsigned char ch = '\0'; 812 int l; 813 814 while ((l = OF_read(ofw_stdin, &ch, 1)) != 1) 815 if (l != -2 && l != 0) 816 return -1; 817 return ch; 818 } 819