1 /* $NetBSD: Locore.c,v 1.3 2002/09/27 15:36:49 provos 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 <lib/libsa/stand.h> 35 #include "openfirm.h" 36 37 #include <machine/cpu.h> 38 39 vaddr_t OF_claim_virt __P((vaddr_t vaddr, int len)); 40 vaddr_t OF_alloc_virt __P((int len, int align)); 41 int OF_free_virt __P((vaddr_t vaddr, int len)); 42 int OF_unmap_virt __P((vaddr_t vaddr, int len)); 43 vaddr_t OF_map_phys __P((paddr_t paddr, off_t size, vaddr_t vaddr, int mode)); 44 paddr_t OF_alloc_phys __P((int len, int align)); 45 paddr_t OF_claim_phys __P((paddr_t phys, int len)); 46 int OF_free_phys __P((paddr_t paddr, int len)); 47 48 extern int openfirmware(void *); 49 50 void setup __P((void)); 51 52 #if 0 53 #ifdef XCOFF_GLUE 54 asm (".text; .globl _entry; _entry: .long _start,0,0"); 55 #endif 56 57 __dead void 58 _start(vpd, res, openfirm, arg, argl) 59 void *vpd; 60 int res; 61 int (*openfirm)(void *); 62 char *arg; 63 int argl; 64 { 65 extern char etext[]; 66 67 #ifdef FIRMWORKSBUGS 68 syncicache((void *)RELOC, etext - (char *)RELOC); 69 #endif 70 openfirmware = openfirm; /* Save entry to Open Firmware */ 71 setup(); 72 main(arg, argl); 73 exit(0); 74 } 75 #endif 76 77 __dead void 78 _rtt() 79 { 80 struct { 81 cell_t name; 82 cell_t nargs; 83 cell_t nreturns; 84 } args; 85 86 args.name = ADR2CELL("exit"); 87 args.nargs = 0; 88 args.nreturns = 0; 89 openfirmware(&args); 90 while (1); /* just in case */ 91 } 92 93 void 94 OF_enter() 95 { 96 struct { 97 cell_t name; 98 cell_t nargs; 99 cell_t nreturns; 100 } args; 101 102 args.name = ADR2CELL("enter"); 103 args.nargs = 0; 104 args.nreturns = 0; 105 openfirmware(&args); 106 } 107 108 int 109 OF_finddevice(name) 110 char *name; 111 { 112 struct { 113 cell_t name; 114 cell_t nargs; 115 cell_t nreturns; 116 cell_t device; 117 cell_t phandle; 118 } args; 119 120 args.name = ADR2CELL("finddevice"); 121 args.nargs = 1; 122 args.nreturns = 1; 123 args.device = ADR2CELL(name); 124 if (openfirmware(&args) == -1) 125 return -1; 126 return args.phandle; 127 } 128 129 int 130 OF_instance_to_package(ihandle) 131 int ihandle; 132 { 133 struct { 134 cell_t name; 135 cell_t nargs; 136 cell_t nreturns; 137 cell_t ihandle; 138 cell_t phandle; 139 } args; 140 141 args.name = ADR2CELL("instance-to-package"); 142 args.nargs = 1; 143 args.nreturns = 1; 144 args.ihandle = HDL2CELL(ihandle); 145 if (openfirmware(&args) == -1) 146 return -1; 147 return args.phandle; 148 } 149 150 int 151 OF_getprop(handle, prop, buf, buflen) 152 int handle; 153 char *prop; 154 void *buf; 155 int buflen; 156 { 157 struct { 158 cell_t name; 159 cell_t nargs; 160 cell_t nreturns; 161 cell_t phandle; 162 cell_t prop; 163 cell_t buf; 164 cell_t buflen; 165 cell_t size; 166 } args; 167 168 args.name = ADR2CELL("getprop"); 169 args.nargs = 4; 170 args.nreturns = 1; 171 args.phandle = HDL2CELL(handle); 172 args.prop = ADR2CELL(prop); 173 args.buf = ADR2CELL(buf); 174 args.buflen = buflen; 175 if (openfirmware(&args) == -1) 176 return -1; 177 return args.size; 178 } 179 180 #ifdef __notyet__ /* Has a bug on FirePower */ 181 int 182 OF_setprop(handle, prop, buf, len) 183 u_int handle; 184 char *prop; 185 void *buf; 186 int len; 187 { 188 struct { 189 cell_t name; 190 cell_t nargs; 191 cell_t nreturns; 192 cell_t phandle; 193 cell_t prop; 194 cell_t buf; 195 cell_t len; 196 cell_t size; 197 } args; 198 199 args.name = ADR2CELL("setprop"); 200 args.nargs = 4; 201 args.nreturns = 1; 202 args.phandle = HDL2CELL(handle); 203 args.prop = ADR2CELL(prop); 204 args.buf = ADR2CELL(buf); 205 args.len = len; 206 if (openfirmware(&args) == -1) 207 return -1; 208 return args.size; 209 } 210 #endif 211 212 int 213 OF_open(dname) 214 char *dname; 215 { 216 struct { 217 cell_t name; 218 cell_t nargs; 219 cell_t nreturns; 220 cell_t dname; 221 cell_t handle; 222 } args; 223 224 args.name = ADR2CELL("open"); 225 args.nargs = 1; 226 args.nreturns = 1; 227 args.dname = ADR2CELL(dname); 228 if (openfirmware(&args) == -1 || 229 args.handle == 0) 230 return -1; 231 return args.handle; 232 } 233 234 void 235 OF_close(handle) 236 int handle; 237 { 238 struct { 239 cell_t name; 240 cell_t nargs; 241 cell_t nreturns; 242 cell_t handle; 243 } args; 244 245 args.name = ADR2CELL("close"); 246 args.nargs = 1; 247 args.nreturns = 1; 248 args.handle = HDL2CELL(handle); 249 openfirmware(&args); 250 } 251 252 int 253 OF_write(handle, addr, len) 254 int handle; 255 void *addr; 256 int len; 257 { 258 struct { 259 cell_t name; 260 cell_t nargs; 261 cell_t nreturns; 262 cell_t ihandle; 263 cell_t addr; 264 cell_t len; 265 cell_t actual; 266 } args; 267 268 args.name = ADR2CELL("write"); 269 args.nargs = 3; 270 args.nreturns = 1; 271 args.ihandle = HDL2CELL(handle); 272 args.addr = ADR2CELL(addr); 273 args.len = len; 274 if (openfirmware(&args) == -1) 275 return -1; 276 return args.actual; 277 } 278 279 int 280 OF_read(handle, addr, len) 281 int handle; 282 void *addr; 283 int len; 284 { 285 struct { 286 cell_t name; 287 cell_t nargs; 288 cell_t nreturns; 289 cell_t ihandle; 290 cell_t addr; 291 cell_t len; 292 cell_t actual; 293 } args; 294 295 args.name = ADR2CELL("read"); 296 args.nargs = 3; 297 args.nreturns = 1; 298 args.ihandle = HDL2CELL(handle); 299 args.addr = ADR2CELL(addr); 300 args.len = len; 301 if (openfirmware(&args) == -1) { 302 return -1; 303 } 304 return args.actual; 305 } 306 307 int 308 OF_seek(handle, pos) 309 int handle; 310 u_quad_t pos; 311 { 312 struct { 313 cell_t name; 314 cell_t nargs; 315 cell_t nreturns; 316 cell_t handle; 317 cell_t poshi; 318 cell_t poslo; 319 cell_t status; 320 } args; 321 322 args.name = ADR2CELL("seek"); 323 args.nargs = 3; 324 args.nreturns = 1; 325 args.handle = HDL2CELL(handle); 326 args.poshi = HDL2CELL(pos >> 32); 327 args.poslo = HDL2CELL(pos); 328 if (openfirmware(&args) == -1) { 329 return -1; 330 } 331 return args.status; 332 } 333 334 void 335 OF_release(virt, size) 336 void *virt; 337 u_int size; 338 { 339 struct { 340 cell_t name; 341 cell_t nargs; 342 cell_t nreturns; 343 cell_t virt; 344 cell_t size; 345 } args; 346 347 args.name = ADR2CELL("release"); 348 args.nargs = 2; 349 args.nreturns = 0; 350 args.virt = ADR2CELL(virt); 351 args.size = size; 352 openfirmware(&args); 353 } 354 355 int 356 OF_milliseconds() 357 { 358 struct { 359 cell_t name; 360 cell_t nargs; 361 cell_t nreturns; 362 cell_t ms; 363 } args; 364 365 args.name = ADR2CELL("milliseconds"); 366 args.nargs = 0; 367 args.nreturns = 1; 368 openfirmware(&args); 369 return args.ms; 370 } 371 372 void 373 OF_chain(virt, size, entry, arg, len) 374 void *virt; 375 u_int size; 376 void (*entry)(); 377 void *arg; 378 u_int len; 379 { 380 extern int64_t romp; 381 extern int debug; 382 struct { 383 cell_t name; 384 cell_t nargs; 385 cell_t nreturns; 386 cell_t virt; 387 cell_t size; 388 cell_t entry; 389 cell_t arg; 390 cell_t len; 391 } args; 392 393 args.name = ADR2CELL("chain"); 394 args.nargs = 5; 395 args.nreturns = 0; 396 args.virt = ADR2CELL(virt); 397 args.size = size; 398 args.entry = ADR2CELL(entry); 399 args.arg = ADR2CELL(arg); 400 args.len = len; 401 openfirmware(&args); 402 if (debug) { 403 printf("OF_chain: prom returned!\n"); 404 405 /* OK, firmware failed us. Try calling prog directly */ 406 printf("Calling entry(0, %p, %x, %lx, %lx)\n", arg, len, 407 (unsigned long)romp, (unsigned long)romp); 408 } 409 entry(0, arg, len, (unsigned long)romp, (unsigned long)romp); 410 panic("OF_chain: kernel returned!"); 411 __asm("ta 2" : :); 412 } 413 414 static u_int stdin; 415 static u_int stdout; 416 static u_int mmuh = -1; 417 static u_int memh = -1; 418 419 void 420 setup() 421 { 422 u_int chosen; 423 424 if ((chosen = OF_finddevice("/chosen")) == -1) 425 _rtt(); 426 if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) != sizeof(stdin) 427 || OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) != sizeof(stdout) 428 || OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) != sizeof(mmuh) 429 || OF_getprop(chosen, "memory", &memh, sizeof(memh)) != sizeof(memh)) 430 _rtt(); 431 } 432 433 /* 434 * The following need either the handle to memory or the handle to the MMU. 435 */ 436 437 /* 438 * Grab some address space from the prom 439 * 440 * Only works while the prom is actively mapping us. 441 */ 442 vaddr_t 443 OF_claim_virt(vaddr, len) 444 vaddr_t vaddr; 445 int len; 446 { 447 struct { 448 cell_t name; 449 cell_t nargs; 450 cell_t nreturns; 451 cell_t method; 452 cell_t ihandle; 453 cell_t align; 454 cell_t len; 455 cell_t vaddr; 456 cell_t status; 457 cell_t retaddr; 458 } args; 459 460 #ifdef __notyet 461 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 462 OF_printf("OF_claim_virt: cannot get mmuh\r\n"); 463 return -1LL; 464 } 465 #endif 466 args.name = ADR2CELL("call-method"); 467 args.nargs = 5; 468 args.nreturns = 2; 469 args.method = ADR2CELL("claim"); 470 args.ihandle = HDL2CELL(mmuh); 471 args.align = 0; 472 args.len = len; 473 args.vaddr = ADR2CELL(vaddr); 474 if(openfirmware(&args) != 0) 475 return -1LL; 476 return args.retaddr; /* Kluge till we go 64-bit */ 477 } 478 479 /* 480 * Request some address space from the prom 481 * 482 * Only works while the prom is actively mapping us. 483 */ 484 vaddr_t 485 OF_alloc_virt(len, align) 486 int len; 487 int align; 488 { 489 int retaddr=-1; 490 struct { 491 cell_t name; 492 cell_t nargs; 493 cell_t nreturns; 494 cell_t method; 495 cell_t ihandle; 496 cell_t align; 497 cell_t len; 498 cell_t status; 499 cell_t retaddr; 500 } args; 501 502 #ifdef __notyet 503 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 504 OF_printf("OF_alloc_virt: cannot get mmuh\r\n"); 505 return -1LL; 506 } 507 #endif 508 args.name = ADR2CELL("call-method"); 509 args.nargs = 4; 510 args.nreturns = 2; 511 args.method = ADR2CELL("claim"); 512 args.ihandle = mmuh; 513 args.align = align; 514 args.len = len; 515 args.retaddr = ADR2CELL(&retaddr); 516 if(openfirmware(&args) != 0) 517 return -1LL; 518 return (vaddr_t)args.retaddr; /* Kluge till we go 64-bit */ 519 } 520 521 /* 522 * Release some address space to the prom 523 * 524 * Only works while the prom is actively mapping us. 525 */ 526 int 527 OF_free_virt(vaddr, len) 528 vaddr_t vaddr; 529 int len; 530 { 531 struct { 532 cell_t name; 533 cell_t nargs; 534 cell_t nreturns; 535 cell_t method; 536 cell_t ihandle; 537 cell_t len; 538 cell_t vaddr; 539 } args; 540 541 #ifdef __notyet 542 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 543 OF_printf("OF_claim_virt: cannot get mmuh\r\n"); 544 return -1; 545 } 546 #endif 547 args.name = ADR2CELL("call-method"); 548 args.nargs = 4; 549 args.nreturns = 0; 550 args.method = ADR2CELL("release"); 551 args.ihandle = HDL2CELL(mmuh); 552 args.vaddr = ADR2CELL(vaddr); 553 args.len = len; 554 return openfirmware(&args); 555 } 556 557 558 /* 559 * Unmap some address space 560 * 561 * Only works while the prom is actively mapping us. 562 */ 563 int 564 OF_unmap_virt(vaddr, len) 565 vaddr_t vaddr; 566 int len; 567 { 568 struct { 569 cell_t name; 570 cell_t nargs; 571 cell_t nreturns; 572 cell_t method; 573 cell_t ihandle; 574 cell_t len; 575 cell_t vaddr; 576 } args; 577 578 #ifdef __notyet 579 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 580 OF_printf("OF_claim_virt: cannot get mmuh\r\n"); 581 return -1; 582 } 583 #endif 584 args.name = ADR2CELL("call-method"); 585 args.nargs = 4; 586 args.nreturns = 0; 587 args.method = ADR2CELL("unmap"); 588 args.ihandle = HDL2CELL(mmuh); 589 args.vaddr = ADR2CELL(vaddr); 590 args.len = len; 591 return openfirmware(&args); 592 } 593 594 /* 595 * Have prom map in some memory 596 * 597 * Only works while the prom is actively mapping us. 598 */ 599 vaddr_t 600 OF_map_phys(paddr, size, vaddr, mode) 601 paddr_t paddr; 602 off_t size; 603 vaddr_t vaddr; 604 int mode; 605 { 606 struct { 607 cell_t name; 608 cell_t nargs; 609 cell_t nreturns; 610 cell_t method; 611 cell_t ihandle; 612 cell_t mode; 613 cell_t size; 614 cell_t vaddr; 615 cell_t paddr_hi; 616 cell_t paddr_lo; 617 cell_t status; 618 cell_t retaddr; 619 } args; 620 621 #ifdef __notyet 622 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 623 OF_printf("OF_map_phys: cannot get mmuh\r\n"); 624 return 0LL; 625 } 626 #endif 627 args.name = ADR2CELL("call-method"); 628 args.nargs = 7; 629 args.nreturns = 1; 630 args.method = ADR2CELL("map"); 631 args.ihandle = HDL2CELL(mmuh); 632 args.mode = mode; 633 args.size = size; 634 args.vaddr = ADR2CELL(vaddr); 635 args.paddr_hi = ADR2CELL(paddr>>32); 636 args.paddr_lo = ADR2CELL(paddr); 637 638 if (openfirmware(&args) == -1) 639 return -1; 640 if (args.status) 641 return -1; 642 return (vaddr_t)args.retaddr; 643 } 644 645 646 /* 647 * Request some RAM from the prom 648 * 649 * Only works while the prom is actively mapping us. 650 */ 651 paddr_t 652 OF_alloc_phys(len, align) 653 int len; 654 int align; 655 { 656 paddr_t paddr; 657 struct { 658 cell_t name; 659 cell_t nargs; 660 cell_t nreturns; 661 cell_t method; 662 cell_t ihandle; 663 cell_t align; 664 cell_t len; 665 cell_t status; 666 cell_t phys_hi; 667 cell_t phys_lo; 668 } args; 669 670 #ifdef __notyet 671 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 672 OF_printf("OF_alloc_phys: cannot get memh\r\n"); 673 return -1LL; 674 } 675 #endif 676 args.name = ADR2CELL("call-method"); 677 args.nargs = 4; 678 args.nreturns = 3; 679 args.method = ADR2CELL("claim"); 680 args.ihandle = HDL2CELL(memh); 681 args.align = align; 682 args.len = len; 683 if(openfirmware(&args) != 0) 684 return -1LL; 685 paddr = (paddr_t)(args.phys_hi<<32)|((unsigned int)(args.phys_lo)); 686 return paddr; /* Kluge till we go 64-bit */ 687 } 688 689 /* 690 * Request some specific RAM from the prom 691 * 692 * Only works while the prom is actively mapping us. 693 */ 694 paddr_t 695 OF_claim_phys(phys, len) 696 paddr_t phys; 697 int len; 698 { 699 paddr_t paddr; 700 struct { 701 cell_t name; 702 cell_t nargs; 703 cell_t nreturns; 704 cell_t method; 705 cell_t ihandle; 706 cell_t align; 707 cell_t len; 708 cell_t phys_hi; 709 cell_t phys_lo; 710 cell_t status; 711 cell_t res; 712 cell_t rphys_hi; 713 cell_t rphys_lo; 714 } args; 715 716 #ifdef __notyet 717 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 718 OF_printf("OF_alloc_phys: cannot get memh\r\n"); 719 return 0LL; 720 } 721 #endif 722 args.name = ADR2CELL("call-method"); 723 args.nargs = 6; 724 args.nreturns = 4; 725 args.method = ADR2CELL("claim"); 726 args.ihandle = HDL2CELL(memh); 727 args.align = 0; 728 args.len = len; 729 args.phys_hi = HDL2CELL(phys>>32); 730 args.phys_lo = HDL2CELL(phys); 731 if(openfirmware(&args) != 0) 732 return 0LL; 733 paddr = (paddr_t)(args.rphys_hi<<32)|((unsigned int)(args.rphys_lo)); 734 return paddr; 735 } 736 737 /* 738 * Free some RAM to prom 739 * 740 * Only works while the prom is actively mapping us. 741 */ 742 int 743 OF_free_phys(phys, len) 744 paddr_t phys; 745 int len; 746 { 747 struct { 748 cell_t name; 749 cell_t nargs; 750 cell_t nreturns; 751 cell_t method; 752 cell_t ihandle; 753 cell_t len; 754 cell_t phys_hi; 755 cell_t phys_lo; 756 } args; 757 758 #ifdef __notyet 759 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 760 OF_printf("OF_free_phys: cannot get memh\r\n"); 761 return -1; 762 } 763 #endif 764 args.name = ADR2CELL("call-method"); 765 args.nargs = 5; 766 args.nreturns = 0; 767 args.method = ADR2CELL("release"); 768 args.ihandle = HDL2CELL(memh); 769 args.len = len; 770 args.phys_hi = HDL2CELL(phys>>32); 771 args.phys_lo = HDL2CELL(phys); 772 return openfirmware(&args); 773 } 774 775 776 /* 777 * Claim virtual memory -- does not map it in. 778 */ 779 780 void * 781 OF_claim(virt, size, align) 782 void *virt; 783 u_int size; 784 u_int align; 785 { 786 #define SUNVMOF 787 #ifndef SUNVMOF 788 struct { 789 cell_t name; 790 cell_t nargs; 791 cell_t nreturns; 792 cell_t virt; 793 cell_t size; 794 cell_t align; 795 cell_t baseaddr; 796 } args; 797 798 799 args.name = ADR2CELL("claim"); 800 args.nargs = 3; 801 args.nreturns = 1; 802 args.virt = virt; 803 args.size = size; 804 args.align = align; 805 if (openfirmware(&args) == -1) 806 return (void *)-1; 807 return args.baseaddr; 808 #else 809 /* 810 * Sun Ultra machines run the firmware with VM enabled, 811 * so you need to handle allocating and mapping both 812 * virtual and physical memory. Ugh. 813 */ 814 815 paddr_t paddr; 816 void* newvirt = NULL; 817 818 if (virt == NULL) { 819 if ((virt = (void*)OF_alloc_virt(size, align)) == (void*)-1) { 820 printf("OF_alloc_virt(%d,%d) failed w/%x\n", size, align, virt); 821 return (void *)-1; 822 } 823 } else { 824 if ((newvirt = (void*)OF_claim_virt((vaddr_t)virt, size)) == (void*)-1) { 825 printf("OF_claim_virt(%x,%d) failed w/%x\n", virt, size, newvirt); 826 return (void *)-1; 827 } 828 } 829 if ((paddr = OF_alloc_phys(size, align)) == -1) { 830 printf("OF_alloc_phys(%d,%d) failed\n", size, align); 831 OF_free_virt((vaddr_t)virt, size); 832 return (void *)-1; 833 } 834 if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) { 835 printf("OF_map_phys(%x,%d,%x,%d) failed\n", paddr, size, virt, -1); 836 OF_free_phys((paddr_t)paddr, size); 837 OF_free_virt((vaddr_t)virt, size); 838 return (void *)-1; 839 } 840 return (void *)virt; 841 #endif 842 } 843 844 845 void 846 putchar(c) 847 int c; 848 { 849 char ch = c; 850 851 if (c == '\n') 852 putchar('\r'); 853 OF_write(stdout, &ch, 1); 854 } 855 856 int 857 getchar() 858 { 859 unsigned char ch = '\0'; 860 int l; 861 862 while ((l = OF_read(stdin, &ch, 1)) != 1) 863 if (l != -2 && l != 0) 864 return -1; 865 return ch; 866 } 867