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