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