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