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