1 /* $NetBSD: openfirm.c,v 1.20 2008/04/08 02:33:03 garbled Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "opt_multiprocessor.h" 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.20 2008/04/08 02:33:03 garbled Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/psl.h> 45 #include <machine/stdarg.h> 46 47 #include <dev/ofw/openfirm.h> 48 49 char *OF_buf; 50 51 void ofw_stack(void); 52 void ofbcopy(const void *, void *, size_t); 53 #ifdef MULTIPROCESSOR 54 void OF_start_cpu(int, u_int, int); 55 #endif 56 57 int 58 OF_peer(int phandle) 59 { 60 static struct { 61 const char *name; 62 int nargs; 63 int nreturns; 64 int phandle; 65 int sibling; 66 } args = { 67 "peer", 68 1, 69 1, 70 }; 71 72 ofw_stack(); 73 args.phandle = phandle; 74 if (openfirmware(&args) == -1) 75 return 0; 76 return args.sibling; 77 } 78 79 int 80 OF_child(int phandle) 81 { 82 static struct { 83 const char *name; 84 int nargs; 85 int nreturns; 86 int phandle; 87 int child; 88 } args = { 89 "child", 90 1, 91 1, 92 }; 93 94 ofw_stack(); 95 args.phandle = phandle; 96 if (openfirmware(&args) == -1) 97 return 0; 98 return args.child; 99 } 100 101 int 102 OF_parent(int phandle) 103 { 104 static struct { 105 const char *name; 106 int nargs; 107 int nreturns; 108 int phandle; 109 int parent; 110 } args = { 111 "parent", 112 1, 113 1, 114 }; 115 116 ofw_stack(); 117 args.phandle = phandle; 118 if (openfirmware(&args) == -1) 119 return 0; 120 return args.parent; 121 } 122 123 int 124 OF_instance_to_package(int ihandle) 125 { 126 static struct { 127 const char *name; 128 int nargs; 129 int nreturns; 130 int ihandle; 131 int phandle; 132 } args = { 133 "instance-to-package", 134 1, 135 1, 136 }; 137 138 ofw_stack(); 139 args.ihandle = ihandle; 140 if (openfirmware(&args) == -1) 141 return -1; 142 return args.phandle; 143 } 144 145 int 146 OF_getproplen(int handle, const char *prop) 147 { 148 static struct { 149 const char *name; 150 int nargs; 151 int nreturns; 152 int phandle; 153 const char *prop; 154 int proplen; 155 } args = { 156 "getproplen", 157 2, 158 1, 159 }; 160 161 ofw_stack(); 162 args.phandle = handle; 163 args.prop = prop; 164 if (openfirmware(&args) == -1) 165 return -1; 166 return args.proplen; 167 } 168 169 int 170 OF_getprop(int handle, const char *prop, void *buf, int buflen) 171 { 172 static struct { 173 const char *name; 174 int nargs; 175 int nreturns; 176 int phandle; 177 const char *prop; 178 void *buf; 179 int buflen; 180 int size; 181 } args = { 182 "getprop", 183 4, 184 1, 185 }; 186 187 ofw_stack(); 188 if (buflen > PAGE_SIZE) 189 return -1; 190 args.phandle = handle; 191 args.prop = prop; 192 args.buf = OF_buf; 193 args.buflen = buflen; 194 if (openfirmware(&args) == -1) 195 return -1; 196 if (args.size > buflen) 197 args.size = buflen; 198 if (args.size > 0) 199 ofbcopy(OF_buf, buf, args.size); 200 return args.size; 201 } 202 203 int 204 OF_setprop(int handle, const char *prop, const void *buf, int buflen) 205 { 206 struct { 207 const char *name; 208 int nargs; 209 int nreturns; 210 int phandle; 211 const char *prop; 212 const void *buf; 213 int buflen; 214 int size; 215 } args = { 216 "setprop", 217 4, 218 1 219 }; 220 ofw_stack(); 221 222 if (buflen > NBPG) 223 return -1; 224 225 ofbcopy(buf, OF_buf, buflen); 226 args.phandle = handle; 227 args.prop = prop; 228 args.buf = OF_buf; 229 args.buflen = buflen; 230 if (openfirmware(&args) == -1) 231 return -1; 232 return args.size; 233 } 234 235 int 236 OF_nextprop(int handle, const char *prop, void *nextprop) 237 { 238 static struct { 239 const char *name; 240 int nargs; 241 int nreturns; 242 int phandle; 243 const char *prop; 244 char *buf; 245 int flag; 246 } args = { 247 "nextprop", 248 3, 249 1, 250 }; 251 252 ofw_stack(); 253 args.phandle = handle; 254 args.prop = prop; 255 args.buf = OF_buf; 256 if (openfirmware(&args) == -1) 257 return -1; 258 strncpy(nextprop, OF_buf, 32); 259 return args.flag; 260 } 261 262 int 263 OF_finddevice(const char *name) 264 { 265 static struct { 266 const char *name; 267 int nargs; 268 int nreturns; 269 const char *device; 270 int phandle; 271 } args = { 272 "finddevice", 273 1, 274 1, 275 }; 276 277 ofw_stack(); 278 args.device = name; 279 if (openfirmware(&args) == -1) 280 return -1; 281 return args.phandle; 282 } 283 284 int 285 OF_instance_to_path(int ihandle, char *buf, int buflen) 286 { 287 static struct { 288 const char *name; 289 int nargs; 290 int nreturns; 291 int ihandle; 292 char *buf; 293 int buflen; 294 int length; 295 } args = { 296 "instance-to-path", 297 3, 298 1, 299 }; 300 301 if (buflen > PAGE_SIZE) 302 return -1; 303 args.ihandle = ihandle; 304 args.buf = OF_buf; 305 args.buflen = buflen; 306 if (openfirmware(&args) < 0) 307 return -1; 308 if (args.length > buflen) 309 args.length = buflen; 310 if (args.length > 0) 311 ofbcopy(OF_buf, buf, args.length); 312 return args.length; 313 } 314 315 int 316 OF_package_to_path(int phandle, char *buf, int buflen) 317 { 318 static struct { 319 const char *name; 320 int nargs; 321 int nreturns; 322 int phandle; 323 char *buf; 324 int buflen; 325 int length; 326 } args = { 327 "package-to-path", 328 3, 329 1, 330 }; 331 332 ofw_stack(); 333 if (buflen > PAGE_SIZE) 334 return -1; 335 args.phandle = phandle; 336 args.buf = OF_buf; 337 args.buflen = buflen; 338 if (openfirmware(&args) < 0) 339 return -1; 340 if (args.length > buflen) 341 args.length = buflen; 342 if (args.length > 0) 343 ofbcopy(OF_buf, buf, args.length); 344 return args.length; 345 } 346 347 int 348 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...) 349 { 350 va_list ap; 351 static struct { 352 const char *name; 353 int nargs; 354 int nreturns; 355 const char *method; 356 int ihandle; 357 int args_n_results[12]; 358 } args = { 359 "call-method", 360 2, 361 1, 362 }; 363 int *ip, n; 364 365 if (nargs > 6) 366 return -1; 367 args.nargs = nargs + 2; 368 args.nreturns = nreturns + 1; 369 args.method = method; 370 args.ihandle = ihandle; 371 va_start(ap, nreturns); 372 for (ip = args.args_n_results + (n = nargs); --n >= 0;) 373 *--ip = va_arg(ap, int); 374 ofw_stack(); 375 if (openfirmware(&args) == -1) { 376 va_end(ap); 377 return -1; 378 } 379 if (args.args_n_results[nargs]) { 380 va_end(ap); 381 return args.args_n_results[nargs]; 382 } 383 for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) 384 *va_arg(ap, int *) = *--ip; 385 va_end(ap); 386 return 0; 387 } 388 389 int 390 OF_call_method_1(const char *method, int ihandle, int nargs, ...) 391 { 392 va_list ap; 393 static struct { 394 const char *name; 395 int nargs; 396 int nreturns; 397 const char *method; 398 int ihandle; 399 int args_n_results[8]; 400 } args = { 401 "call-method", 402 2, 403 2, 404 }; 405 int *ip, n; 406 407 if (nargs > 6) 408 return -1; 409 args.nargs = nargs + 2; 410 args.method = method; 411 args.ihandle = ihandle; 412 va_start(ap, nargs); 413 for (ip = args.args_n_results + (n = nargs); --n >= 0;) 414 *--ip = va_arg(ap, int); 415 va_end(ap); 416 ofw_stack(); 417 if (openfirmware(&args) == -1) 418 return -1; 419 if (args.args_n_results[nargs]) 420 return -1; 421 return args.args_n_results[nargs + 1]; 422 } 423 424 int 425 OF_open(const char *dname) 426 { 427 static struct { 428 const char *name; 429 int nargs; 430 int nreturns; 431 const char *dname; 432 int handle; 433 } args = { 434 "open", 435 1, 436 1, 437 }; 438 int l; 439 440 ofw_stack(); 441 if ((l = strlen(dname)) >= PAGE_SIZE) 442 return -1; 443 ofbcopy(dname, OF_buf, l + 1); 444 args.dname = OF_buf; 445 if (openfirmware(&args) == -1) 446 return -1; 447 return args.handle; 448 } 449 450 void 451 OF_close(int handle) 452 { 453 static struct { 454 const char *name; 455 int nargs; 456 int nreturns; 457 int handle; 458 } args = { 459 "close", 460 1, 461 0, 462 }; 463 464 ofw_stack(); 465 args.handle = handle; 466 openfirmware(&args); 467 } 468 469 /* 470 * This assumes that character devices don't read in multiples of PAGE_SIZE. 471 */ 472 int 473 OF_read(int handle, void *addr, int len) 474 { 475 static struct { 476 const char *name; 477 int nargs; 478 int nreturns; 479 int ihandle; 480 void *addr; 481 int len; 482 int actual; 483 } args = { 484 "read", 485 3, 486 1, 487 }; 488 int l, act = 0; 489 char *p = addr; 490 491 ofw_stack(); 492 args.ihandle = handle; 493 args.addr = OF_buf; 494 for (; len > 0; len -= l, p += l) { 495 l = min(PAGE_SIZE, len); 496 args.len = l; 497 if (openfirmware(&args) == -1) 498 return -1; 499 if (args.actual > 0) { 500 ofbcopy(OF_buf, p, args.actual); 501 act += args.actual; 502 } 503 if (args.actual < l) { 504 if (act) 505 return act; 506 else 507 return args.actual; 508 } 509 } 510 return act; 511 } 512 513 int 514 OF_write(int handle, const void *addr, int len) 515 { 516 static struct { 517 const char *name; 518 int nargs; 519 int nreturns; 520 int ihandle; 521 void *addr; 522 int len; 523 int actual; 524 } args = { 525 "write", 526 3, 527 1, 528 }; 529 int l, act = 0; 530 const char *p = addr; 531 532 ofw_stack(); 533 args.ihandle = handle; 534 args.addr = OF_buf; 535 for (; len > 0; len -= l, p += l) { 536 l = min(PAGE_SIZE, len); 537 ofbcopy(p, OF_buf, l); 538 args.len = l; 539 args.actual = l; /* work around a PIBS bug */ 540 if (openfirmware(&args) == -1) 541 return -1; 542 l = args.actual; 543 act += l; 544 } 545 return act; 546 } 547 548 int 549 OF_seek(int handle, u_quad_t pos) 550 { 551 static struct { 552 const char *name; 553 int nargs; 554 int nreturns; 555 int handle; 556 int poshi; 557 int poslo; 558 int status; 559 } args = { 560 "seek", 561 3, 562 1, 563 }; 564 565 ofw_stack(); 566 args.handle = handle; 567 args.poshi = (int)(pos >> 32); 568 args.poslo = (int)pos; 569 if (openfirmware(&args) == -1) 570 return -1; 571 return args.status; 572 } 573 574 #ifdef MULTIPROCESSOR 575 void 576 OF_start_cpu(int phandle, u_int pc, int arg) 577 { 578 static struct { 579 const char *name; 580 int nargs; 581 int nreturns; 582 int phandle; 583 u_int pc; 584 int arg; 585 } args = { 586 "start-cpu", 587 3, 588 0, 589 }; 590 ofw_stack(); 591 args.phandle = phandle; 592 args.pc = pc; 593 args.arg = arg; 594 if (openfirmware(&args) == -1) 595 panic("WTF?"); 596 } 597 #endif 598 599 void 600 OF_boot(const char *bootspec) 601 { 602 static struct { 603 const char *name; 604 int nargs; 605 int nreturns; 606 char *bootspec; 607 } args = { 608 "boot", 609 1, 610 0, 611 }; 612 int l; 613 614 if ((l = strlen(bootspec)) >= PAGE_SIZE) 615 panic("OF_boot"); 616 ofw_stack(); 617 ofbcopy(bootspec, OF_buf, l + 1); 618 args.bootspec = OF_buf; 619 openfirmware(&args); 620 while (1); /* just in case */ 621 } 622 623 void 624 OF_enter(void) 625 { 626 static struct { 627 const char *name; 628 int nargs; 629 int nreturns; 630 } args = { 631 "enter", 632 0, 633 0, 634 }; 635 636 ofw_stack(); 637 openfirmware(&args); 638 } 639 640 void 641 OF_exit(void) 642 { 643 static struct { 644 const char *name; 645 int nargs; 646 int nreturns; 647 } args = { 648 "exit", 649 0, 650 0, 651 }; 652 653 ofw_stack(); 654 openfirmware(&args); 655 while (1); /* just in case */ 656 } 657 658 void 659 (*OF_set_callback (void (*newfunc)(void *))) (void *) 660 { 661 static struct { 662 const char *name; 663 int nargs; 664 int nreturns; 665 void (*newfunc)(void *); 666 void (*oldfunc)(void *); 667 } args = { 668 "set-callback", 669 1, 670 1, 671 }; 672 673 ofw_stack(); 674 args.newfunc = newfunc; 675 if (openfirmware(&args) == -1) 676 return 0; 677 return args.oldfunc; 678 } 679 680 int 681 OF_interpret(const char *cmd, int nargs, int nreturns, ...) 682 { 683 va_list ap; 684 int i, len, status; 685 static struct { 686 const char *name; 687 uint32_t nargs; 688 uint32_t nreturns; 689 uint32_t slots[16]; 690 } args = { 691 "interpret", 692 1, 693 2, 694 }; 695 696 ofw_stack(); 697 if (nreturns > 8) 698 return -1; 699 if ((len = strlen(cmd)) >= PAGE_SIZE) 700 return -1; 701 ofbcopy(cmd, OF_buf, len + 1); 702 i = 0; 703 args.slots[i] = (uint32_t)OF_buf; 704 args.nargs = nargs + 1; 705 args.nreturns = nreturns + 1; 706 va_start(ap, nreturns); 707 i++; 708 while (i < args.nargs) { 709 args.slots[i] = (uint32_t)va_arg(ap, uint32_t *); 710 i++; 711 } 712 713 if (openfirmware(&args) == -1) 714 return -1; 715 status = args.slots[i]; 716 i++; 717 718 while (i < args.nargs + args.nreturns) { 719 *va_arg(ap, uint32_t *) = args.slots[i]; 720 i++; 721 } 722 va_end(ap); 723 return status; 724 } 725 726 /* 727 * This version of bcopy doesn't work for overlapping regions! 728 */ 729 void 730 ofbcopy(const void *src, void *dst, size_t len) 731 { 732 const char *sp = src; 733 char *dp = dst; 734 735 if (src == dst) 736 return; 737 738 /* 739 * Do some optimization? XXX 740 */ 741 while (len-- > 0) 742 *dp++ = *sp++; 743 } 744