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