1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai 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 * Copyright (C) 2000 Benno Rice. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 * 57 * $FreeBSD$ 58 */ 59 60 #include <sys/param.h> 61 #include <sys/kernel.h> 62 #include <sys/malloc.h> 63 #include <sys/systm.h> 64 65 #include <machine/stdarg.h> 66 67 #include <dev/ofw/openfirm.h> 68 69 MALLOC_DEFINE(M_OFWPROP, "openfirm", "OpenFirmware properties"); 70 71 static ihandle_t stdin; 72 static ihandle_t stdout; 73 74 char *OF_buf; 75 76 void ofbcopy(const void *, void *, size_t); 77 78 /* Initialiaser */ 79 80 void 81 OF_init(int (*openfirm)(void *)) 82 { 83 phandle_t chosen; 84 85 set_openfirm_callback(openfirm); 86 if ((chosen = OF_finddevice("/chosen")) == -1) 87 OF_exit(); 88 OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)); 89 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 90 } 91 92 void 93 OF_printf(const char *fmt, ...) 94 { 95 va_list va; 96 char buf[1024]; 97 98 va_start(va, fmt); 99 vsprintf(buf, fmt, va); 100 OF_write(stdout, buf, strlen(buf)); 101 va_end(va); 102 } 103 104 /* 105 * Generic functions 106 */ 107 108 /* Test to see if a service exists. */ 109 int 110 OF_test(char *name) 111 { 112 static struct { 113 cell_t name; 114 cell_t nargs; 115 cell_t nreturns; 116 cell_t service; 117 cell_t missing; 118 } args = { 119 (cell_t)"test", 120 1, 121 1, 122 }; 123 124 args.service = (cell_t)name; 125 if (openfirmware(&args) == -1) 126 return -1; 127 return args.missing; 128 } 129 130 /* Return firmware millisecond count. */ 131 int 132 OF_milliseconds() 133 { 134 static struct { 135 cell_t name; 136 cell_t nargs; 137 cell_t nreturns; 138 cell_t ms; 139 } args = { 140 (cell_t)"milliseconds", 141 0, 142 1, 143 }; 144 145 openfirmware(&args); 146 return args.ms; 147 } 148 149 /* 150 * Device tree functions 151 */ 152 153 /* Return the next sibling of this node or 0. */ 154 phandle_t 155 OF_peer(phandle_t node) 156 { 157 static struct { 158 cell_t name; 159 cell_t nargs; 160 cell_t nreturns; 161 cell_t node; 162 cell_t next; 163 } args = { 164 (cell_t)"peer", 165 1, 166 1, 167 }; 168 169 args.node = (cell_t)node; 170 if (openfirmware(&args) == -1) 171 return -1; 172 return args.next; 173 } 174 175 /* Return the first child of this node or 0. */ 176 phandle_t 177 OF_child(phandle_t node) 178 { 179 static struct { 180 cell_t name; 181 cell_t nargs; 182 cell_t nreturns; 183 cell_t node; 184 cell_t child; 185 } args = { 186 (cell_t)"child", 187 1, 188 1, 189 }; 190 191 args.node = (cell_t)node; 192 if (openfirmware(&args) == -1) 193 return -1; 194 return args.child; 195 } 196 197 /* Return the parent of this node or 0. */ 198 phandle_t 199 OF_parent(phandle_t node) 200 { 201 static struct { 202 cell_t name; 203 cell_t nargs; 204 cell_t nreturns; 205 cell_t node; 206 cell_t parent; 207 } args = { 208 (cell_t)"parent", 209 1, 210 1, 211 }; 212 213 args.node = (cell_t)node; 214 if (openfirmware(&args) == -1) 215 return -1; 216 return args.parent; 217 } 218 219 /* Return the package handle that corresponds to an instance handle. */ 220 phandle_t 221 OF_instance_to_package(ihandle_t instance) 222 { 223 static struct { 224 cell_t name; 225 cell_t nargs; 226 cell_t nreturns; 227 cell_t instance; 228 cell_t package; 229 } args = { 230 (cell_t)"instance-to-package", 231 1, 232 1, 233 }; 234 235 args.instance = (cell_t)instance; 236 if (openfirmware(&args) == -1) 237 return -1; 238 return args.package; 239 } 240 241 /* Get the length of a property of a package. */ 242 int 243 OF_getproplen(phandle_t package, char *propname) 244 { 245 static struct { 246 cell_t name; 247 cell_t nargs; 248 cell_t nreturns; 249 cell_t package; 250 cell_t propname; 251 cell_t proplen; 252 } args = { 253 (cell_t)"getproplen", 254 2, 255 1, 256 }; 257 258 args.package = (cell_t)package; 259 args.propname = (cell_t)propname; 260 if (openfirmware(&args) == -1) 261 return -1; 262 return args.proplen; 263 } 264 265 /* Get the value of a property of a package. */ 266 int 267 OF_getprop(phandle_t package, char *propname, void *buf, int buflen) 268 { 269 static struct { 270 cell_t name; 271 cell_t nargs; 272 cell_t nreturns; 273 cell_t package; 274 cell_t propname; 275 cell_t buf; 276 cell_t buflen; 277 cell_t size; 278 } args = { 279 (cell_t)"getprop", 280 4, 281 1, 282 }; 283 284 args.package = (cell_t)package; 285 args.propname = (cell_t)propname; 286 args.buf = (cell_t)buf; 287 args.buflen = (cell_t)buflen; 288 if (openfirmware(&args) == -1) 289 return -1; 290 return args.size; 291 } 292 293 /* 294 * Store the value of a property of a package into newly allocated memory (using 295 * the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a single element, 296 * the number of elements is return in number. 297 */ 298 int 299 OF_getprop_alloc(phandle_t package, char *propname, int elsz, void **buf) 300 { 301 int len; 302 303 *buf = NULL; 304 if ((len = OF_getproplen(package, propname)) == -1 || 305 len % elsz != 0) 306 return (-1); 307 308 *buf = malloc(len, M_OFWPROP, M_WAITOK); 309 if (OF_getprop(package, propname, *buf, len) == -1) { 310 free(*buf, M_OFWPROP); 311 *buf = NULL; 312 return (-1); 313 } 314 return (len / elsz); 315 } 316 317 /* Get the next property of a package. */ 318 int 319 OF_nextprop(phandle_t package, char *previous, char *buf) 320 { 321 static struct { 322 cell_t name; 323 cell_t nargs; 324 cell_t nreturns; 325 cell_t package; 326 cell_t previous; 327 cell_t buf; 328 cell_t flag; 329 } args = { 330 (cell_t)"nextprop", 331 3, 332 1, 333 }; 334 335 args.package = (cell_t)package; 336 args.previous = (cell_t)previous; 337 args.buf = (cell_t)buf; 338 if (openfirmware(&args) == -1) 339 return -1; 340 return args.flag; 341 } 342 343 /* Set the value of a property of a package. */ 344 /* XXX Has a bug on FirePower */ 345 int 346 OF_setprop(phandle_t package, char *propname, void *buf, int len) 347 { 348 static struct { 349 cell_t name; 350 cell_t nargs; 351 cell_t nreturns; 352 cell_t package; 353 cell_t propname; 354 cell_t buf;; 355 cell_t len; 356 cell_t size; 357 } args = { 358 (cell_t)"setprop", 359 4, 360 1, 361 }; 362 363 args.package = (cell_t)package; 364 args.propname = (cell_t)propname; 365 args.buf = (cell_t)buf; 366 args.len = (cell_t)len; 367 if (openfirmware(&args) == -1) 368 return -1; 369 return args.size; 370 } 371 372 /* Convert a device specifier to a fully qualified pathname. */ 373 int 374 OF_canon(const char *device, char *buf, int len) 375 { 376 static struct { 377 cell_t name; 378 cell_t nargs; 379 cell_t nreturns; 380 cell_t device; 381 cell_t buf; 382 cell_t len; 383 cell_t size; 384 } args = { 385 (cell_t)"canon", 386 3, 387 1, 388 }; 389 390 args.device = (cell_t)device; 391 args.buf = (cell_t)buf; 392 args.len = (cell_t)len; 393 if (openfirmware(&args) == -1) 394 return -1; 395 return args.size; 396 } 397 398 /* Return a package handle for the specified device. */ 399 phandle_t 400 OF_finddevice(const char *device) 401 { 402 static struct { 403 cell_t name; 404 cell_t nargs; 405 cell_t nreturns; 406 cell_t device; 407 cell_t package; 408 } args = { 409 (cell_t)"finddevice", 410 1, 411 1, 412 }; 413 414 args.device = (cell_t)device; 415 if (openfirmware(&args) == -1) 416 return -1; 417 return args.package; 418 } 419 420 /* Return the fully qualified pathname corresponding to an instance. */ 421 int 422 OF_instance_to_path(ihandle_t instance, char *buf, int len) 423 { 424 static struct { 425 cell_t name; 426 cell_t nargs; 427 cell_t nreturns; 428 cell_t instance; 429 cell_t buf; 430 cell_t len; 431 cell_t size; 432 } args = { 433 (cell_t)"instance-to-path", 434 3, 435 1, 436 }; 437 438 args.instance = (cell_t)instance; 439 args.buf = (cell_t)buf; 440 args.len = (cell_t)len; 441 if (openfirmware(&args) == -1) 442 return -1; 443 return(args.size); 444 } 445 446 /* Return the fully qualified pathname corresponding to a package. */ 447 int 448 OF_package_to_path(phandle_t package, char *buf, int len) 449 { 450 static struct { 451 cell_t name; 452 cell_t nargs; 453 cell_t nreturns; 454 cell_t package; 455 cell_t buf; 456 cell_t len; 457 cell_t size; 458 } args = { 459 (cell_t)"package-to-path", 460 3, 461 1, 462 }; 463 464 args.package = (cell_t)package; 465 args.buf = (cell_t)buf; 466 args.len = (cell_t)len; 467 if (openfirmware(&args) == -1) 468 return -1; 469 return(args.size); 470 } 471 472 /* Call the method in the scope of a given instance. */ 473 int 474 OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...) 475 { 476 va_list ap; 477 static struct { 478 cell_t name; 479 cell_t nargs; 480 cell_t nreturns; 481 cell_t method; 482 cell_t instance; 483 cell_t args_n_results[12]; 484 } args = { 485 (cell_t)"call-method", 486 2, 487 1, 488 }; 489 cell_t *ip; 490 int n; 491 492 if (nargs > 6) 493 return -1; 494 args.nargs = (cell_t)nargs + 2; 495 args.nreturns = (cell_t)nreturns + 1; 496 args.method = (cell_t)method; 497 args.instance = (cell_t)instance; 498 va_start(ap, nreturns); 499 for (ip = args.args_n_results + (n = (cell_t)nargs); --n >= 0;) 500 *--ip = va_arg(ap, cell_t); 501 502 if (openfirmware(&args) == -1) 503 return -1; 504 if (args.args_n_results[nargs]) 505 return args.args_n_results[nargs]; 506 for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) 507 *va_arg(ap, cell_t *) = *--ip; 508 va_end(ap); 509 return 0; 510 } 511 512 /* 513 * Device I/O functions. 514 */ 515 516 /* Open an instance for a device. */ 517 ihandle_t 518 OF_open(char *device) 519 { 520 static struct { 521 cell_t name; 522 cell_t nargs; 523 cell_t nreturns; 524 cell_t device; 525 cell_t instance; 526 } args = { 527 (cell_t)"open", 528 1, 529 1, 530 }; 531 532 args.device = (cell_t)device; 533 if (openfirmware(&args) == -1 || args.instance == 0) { 534 return -1; 535 } 536 return args.instance; 537 } 538 539 /* Close an instance. */ 540 void 541 OF_close(ihandle_t instance) 542 { 543 static struct { 544 cell_t name; 545 cell_t nargs; 546 cell_t nreturns; 547 cell_t instance; 548 } args = { 549 (cell_t)"close", 550 1, 551 0, 552 }; 553 554 args.instance = (cell_t)instance; 555 openfirmware(&args); 556 } 557 558 /* Read from an instance. */ 559 int 560 OF_read(ihandle_t instance, void *addr, int len) 561 { 562 static struct { 563 cell_t name; 564 cell_t nargs; 565 cell_t nreturns; 566 cell_t instance; 567 cell_t addr; 568 cell_t len; 569 cell_t actual; 570 } args = { 571 (cell_t)"read", 572 3, 573 1, 574 }; 575 576 args.instance = (cell_t)instance; 577 args.addr = (cell_t)addr; 578 args.len = (cell_t)len; 579 if (openfirmware(&args) == -1) 580 return -1; 581 582 return args.actual; 583 } 584 585 /* Write to an instance. */ 586 int 587 OF_write(ihandle_t instance, void *addr, int len) 588 { 589 static struct { 590 cell_t name; 591 cell_t nargs; 592 cell_t nreturns; 593 cell_t instance; 594 cell_t addr; 595 cell_t len; 596 cell_t actual; 597 } args = { 598 (cell_t)"write", 599 3, 600 1, 601 }; 602 603 args.instance = (cell_t)instance; 604 args.addr = (cell_t)addr; 605 args.len = (cell_t)len; 606 if (openfirmware(&args) == -1) 607 return -1; 608 return args.actual; 609 } 610 611 /* Seek to a position. */ 612 int 613 OF_seek(ihandle_t instance, u_int64_t pos) 614 { 615 static struct { 616 cell_t name; 617 cell_t nargs; 618 cell_t nreturns; 619 cell_t instance; 620 cell_t poshi; 621 cell_t poslo; 622 cell_t status; 623 } args = { 624 (cell_t)"seek", 625 3, 626 1, 627 }; 628 629 args.instance = (cell_t)instance; 630 args.poshi = (cell_t)(pos >> 32); 631 args.poslo = (cell_t)pos; 632 if (openfirmware(&args) == -1) 633 return -1; 634 return args.status; 635 } 636 637 /* 638 * Memory functions. 639 */ 640 641 /* Claim an area of memory. */ 642 void * 643 OF_claim(void *virt, u_int size, u_int align) 644 { 645 static struct { 646 cell_t name; 647 cell_t nargs; 648 cell_t nreturns; 649 cell_t virt; 650 cell_t size; 651 cell_t align; 652 cell_t baseaddr; 653 } args = { 654 (cell_t)"claim", 655 3, 656 1, 657 }; 658 659 args.virt = (cell_t)virt; 660 args.size = (cell_t)size; 661 args.align = (cell_t)align; 662 if (openfirmware(&args) == -1) 663 return (void *)-1; 664 return (void *)args.baseaddr; 665 } 666 667 /* Release an area of memory. */ 668 void 669 OF_release(void *virt, u_int size) 670 { 671 static struct { 672 cell_t name; 673 cell_t nargs; 674 cell_t nreturns; 675 cell_t virt; 676 cell_t size; 677 } args = { 678 (cell_t)"release", 679 2, 680 0, 681 }; 682 683 args.virt = (cell_t)virt; 684 args.size = (cell_t)size; 685 openfirmware(&args); 686 } 687 688 /* 689 * Control transfer functions. 690 */ 691 692 /* Reset the system and call "boot <bootspec>". */ 693 void 694 OF_boot(char *bootspec) 695 { 696 static struct { 697 cell_t name; 698 cell_t nargs; 699 cell_t nreturns; 700 cell_t bootspec; 701 } args = { 702 (cell_t)"boot", 703 1, 704 0, 705 }; 706 707 args.bootspec = (cell_t)bootspec; 708 openfirmware(&args); 709 for (;;); /* just in case */ 710 } 711 712 /* Suspend and drop back to the OpenFirmware interface. */ 713 void 714 OF_enter() 715 { 716 static struct { 717 cell_t name; 718 cell_t nargs; 719 cell_t nreturns; 720 } args = { 721 (cell_t)"enter", 722 0, 723 0 724 }; 725 726 openfirmware(&args); 727 return; /* We may come back. */ 728 } 729 730 /* Shut down and drop back to the OpenFirmware interface. */ 731 void 732 OF_exit() 733 { 734 static struct { 735 cell_t name; 736 cell_t nargs; 737 cell_t nreturns; 738 } args = { 739 (cell_t)"exit", 740 0, 741 0 742 }; 743 744 openfirmware(&args); 745 for (;;); /* just in case */ 746 } 747 748 /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */ 749 #ifdef __notyet__ 750 void 751 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) 752 { 753 static struct { 754 cell_t name; 755 cell_t nargs; 756 cell_t nreturns; 757 cell_t virt; 758 cell_t size; 759 call_t entry; 760 cell_t arg; 761 cell_t len; 762 } args = { 763 (cell_t)"chain", 764 5, 765 0, 766 }; 767 768 args.virt = (cell_t)virt; 769 args.size = (cell_t)size; 770 args.entry = (cell_t)entry; 771 args.arg = (cell_t)arg; 772 args.len = (cell_t)len; 773 openfirmware(&args); 774 } 775 #else 776 void 777 OF_chain(void *virt, u_int size, 778 void (*entry)(void *, u_int, void *, void *, u_int), void *arg, u_int len) 779 { 780 /* 781 * This is a REALLY dirty hack till the firmware gets this going 782 */ 783 #if 0 784 OF_release(virt, size); 785 #endif 786 entry(0, 0, openfirmware, arg, len); 787 } 788 #endif 789 790 void 791 ofbcopy(const void *src, void *dst, size_t len) 792 { 793 const char *sp = src; 794 char *dp = dst; 795 796 if (src == dst) 797 return; 798 799 while (len-- > 0) 800 *dp++ = *sp++; 801 } 802