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