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