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