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