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 42static int (*openfirmware)(void *); 43 44static void startup(void *, int, int (*)(void *), char *, int) 45 __attribute__((__used__)); 46static void setup(void); 47 48#ifdef HEAP_VARIABLE 49#ifndef HEAP_SIZE 50#define HEAP_SIZE 0x20000 51#endif 52char *heapspace; 53#endif 54 55static 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 194static int 195openfirmware(void *arg) 196{ 197 198 __asm volatile ("sync; isync"); 199 openfirmware_entry(arg); 200 __asm volatile ("sync; isync"); 201} 202#endif 203 204int ofw_real_mode; 205int ofw_address_cells; 206int ofw_size_cells; 207 208int ofw_root; /* / */ 209int ofw_options; /* /options */ 210int ofw_openprom; /* /openprom */ 211int ofw_chosen; /* /chosen (package) */ 212int ofw_stdin; /* /chosen/stdin */ 213int ofw_stdout; /* /chosen/stdout */ 214int ofw_memory_ihandle; /* /chosen/memory */ 215int ofw_mmu_ihandle; /* /chosen/mmu */ 216 217bool 218ofw_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 232static void 233startup(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 243void 244OF_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 261OF_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 277int 278OF_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 298int 299OF_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 319int 320OF_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 */ 347int 348OF_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 375int 376OF_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 407void 408OF_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 428int 429OF_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 465int 466OF_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 502int 503OF_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 537void * 538OF_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 572void 573OF_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 595int 596OF_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__ 614void 615OF_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 640void 641OF_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 653int 654OF_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 696static void 697setup(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 798void 799putchar(int c) 800{ 801 char ch = c; 802 803 if (c == '\n') 804 putchar('\r'); 805 OF_write(ofw_stdout, &ch, 1); 806} 807 808int 809getchar(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