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