1 /*        $NetBSD: Locore.c,v 1.35 2021/02/28 20:27:40 thorpej 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 <sys/param.h>
35 #include <lib/libsa/stand.h>
36 
37 #include <machine/cpu.h>
38 #include <powerpc/oea/spr.h>
39 
40 #include "openfirm.h"
41 
42 static int (*openfirmware)(void *);
43 
44 static void startup(void *, int, int (*)(void *), char *, int)
45                     __attribute__((__used__));
46 static void setup(void);
47 
48 #ifdef HEAP_VARIABLE
49 #ifndef HEAP_SIZE
50 #define HEAP_SIZE 0x20000
51 #endif
52 char *heapspace;
53 #endif
54 
55 static int stack[8192/4 + 4] __attribute__((__used__));
56 
57 #ifdef XCOFF_GLUE
58 __asm(
59 "         .text                         \n"
60 "         .globl    _entry              \n"
61 "_entry:                      \n"
62 "         .long     _start,0,0          \n"
63 );
64 #endif /* XCOFF_GLUE */
65 
66 __asm(
67 "         .text                         \n"
68 "         .globl    _start              \n"
69 "_start:                      \n"
70 "         sync                          \n"
71 "         isync                         \n"
72 "         lis       %r1,stack@ha        \n"
73 "         addi      %r1,%r1,stack@l     \n"
74 "         addi      %r1,%r1,8192        \n"
75 "                                       \n"
76 "         mfmsr     %r8                 \n"
77 "         li        %r0,0               \n"
78 "         mtmsr     %r0                 \n"
79 "         isync                         \n"
80 "                                       \n"
81 "                                       \n" /* test for 601 */
82 "         mfspr     %r0,287             \n" /* mfpvbr %r0 PVR = 287 */
83 "         srwi      %r0,%r0,0x10        \n"
84 "         cmplwi    %r0,0x02  \n" /* 601 CPU = 0x0001 */
85 "         blt       2f                  \n" /* skip over non-601 BAT setup */
86 "         cmplwi    %r0,0x39  \n" /* PPC970 */
87 "         blt       0f                  \n"
88 "         cmplwi    %r0,0x45  \n" /* PPC970GX */
89 "         ble       1f                  \n"
90           /* non PPC 601 BATs */
91 "0:       li        %r0,0               \n"
92 "         mtibatu   0,%r0               \n"
93 "         mtibatu   1,%r0               \n"
94 "         mtibatu   2,%r0               \n"
95 "         mtibatu   3,%r0               \n"
96 "         mtdbatu   0,%r0               \n"
97 "         mtdbatu   1,%r0               \n"
98 "         mtdbatu   2,%r0               \n"
99 "         mtdbatu   3,%r0               \n"
100 "                                       \n"
101 "         li        %r9,0x12  \n"       /* BATL(0, BAT_M, BAT_PP_RW) */
102 "         mtibatl   0,%r9               \n"
103 "         mtdbatl   0,%r9               \n"
104 "         li        %r9,0x1ffe          \n"       /* BATU(0, BAT_BL_256M, BAT_Vs) */
105 "         mtibatu   0,%r9               \n"
106 "         mtdbatu   0,%r9               \n"
107 "         b         3f                  \n"
108           /* 970 initialization stuff */
109 "1:                                     \n"
110           /* make sure we're in bridge mode */
111 "         clrldi    %r8,%r8,3 \n"
112 "         mtmsrd    %r8                 \n"
113 "         isync                         \n"
114            /* clear HID5 DCBZ bits (56/57), need to do this early */
115 "         mfspr     %r9,0x3f6 \n"
116 "         rldimi    %r9,0,6,56          \n"
117 "         sync                          \n"
118 "         mtspr     0x3f6,%r9 \n"
119 "         isync                         \n"
120 "         sync                          \n"
121           /* Setup HID1 features, prefetch + i-cacheability controlled by PTE */
122 "         mfspr     %r9,0x3f1 \n"
123 "         li        %r11,0x1200         \n"
124 "         sldi      %r11,%r11,44        \n"
125 "         or        %r9,%r9,%r11        \n"
126 "         mtspr     0x3f1,%r9 \n"
127 "         isync                         \n"
128 "         sync                          \n"
129 "         b         3f                  \n"
130           /* PPC 601 BATs */
131 "2:       li        %r0,0               \n"
132 "         mtibatu   0,%r0               \n"
133 "         mtibatu   1,%r0               \n"
134 "         mtibatu   2,%r0               \n"
135 "         mtibatu   3,%r0               \n"
136 "                                       \n"
137 "         li        %r9,0x7f  \n"
138 "         mtibatl   0,%r9               \n"
139 "         li        %r9,0x1a  \n"
140 "         mtibatu   0,%r9               \n"
141 "                                       \n"
142 "         lis       %r9,0x80  \n"
143 "         addi      %r9,%r9,0x7f        \n"
144 "         mtibatl   1,%r9               \n"
145 "         lis       %r9,0x80  \n"
146 "         addi      %r9,%r9,0x1a        \n"
147 "         mtibatu   1,%r9               \n"
148 "                                       \n"
149 "         lis       %r9,0x100 \n"
150 "         addi      %r9,%r9,0x7f        \n"
151 "         mtibatl   2,%r9               \n"
152 "         lis       %r9,0x100 \n"
153 "         addi      %r9,%r9,0x1a        \n"
154 "         mtibatu   2,%r9               \n"
155 "                                       \n"
156 "         lis       %r9,0x180 \n"
157 "         addi      %r9,%r9,0x7f        \n"
158 "         mtibatl   3,%r9               \n"
159 "         lis       %r9,0x180 \n"
160 "         addi      %r9,%r9,0x1a        \n"
161 "         mtibatu   3,%r9               \n"
162 "                                       \n"
163 "3:       isync                         \n"
164 "                                       \n"
165 "         mtmsr     %r8                 \n"
166 "         isync                         \n"
167 "                                       \n"
168           /*
169            * Make sure that .bss is zeroed
170            */
171 "                                       \n"
172 "         li        %r0,0               \n"
173 "         lis       %r8,_edata@ha       \n"
174 "         addi      %r8,%r8,_edata@l\n"
175 "         lis       %r9,_end@ha         \n"
176 "         addi      %r9,%r9,_end@l      \n"
177 "                                       \n"
178 "5:       cmpw      0,%r8,%r9 \n"
179 "         bge       6f                  \n"
180           /*
181            * clear by bytes to avoid ppc601 alignment exceptions
182            */
183 "         stb       %r0,0(%r8)          \n"
184 "         stb       %r0,1(%r8)          \n"
185 "         stb       %r0,2(%r8)          \n"
186 "         stb       %r0,3(%r8)          \n"
187 "         addi      %r8,%r8,4 \n"
188 "         b         5b                  \n"
189 "                                       \n"
190 "6:       b         startup             \n"
191 );
192 
193 #if 0
194 static int
195 openfirmware(void *arg)
196 {
197 
198           __asm volatile ("sync; isync");
199           openfirmware_entry(arg);
200           __asm volatile ("sync; isync");
201 }
202 #endif
203 
204 int       ofw_real_mode;
205 int       ofw_address_cells;
206 int       ofw_size_cells;
207 
208 int       ofw_root;           /* / */
209 int       ofw_options;                  /* /options */
210 int       ofw_openprom;                 /* /openprom */
211 int       ofw_chosen;                   /* /chosen (package) */
212 int       ofw_stdin;                    /* /chosen/stdin */
213 int       ofw_stdout;                   /* /chosen/stdout */
214 int       ofw_memory_ihandle; /* /chosen/memory */
215 int       ofw_mmu_ihandle;    /* /chosen/mmu */
216 
217 bool
ofw_option_truefalse(const char * prop,int proplen)218 ofw_option_truefalse(const char *prop, int proplen)
219 {
220           /* These are all supposed to be strings. */
221           switch (prop[0]) {
222           case 'y':
223           case 'Y':
224           case 't':
225           case 'T':
226           case '1':
227                     return true;
228           }
229           return false;
230 }
231 
232 static void
startup(void * vpd,int res,int (* openfirm)(void *),char * arg,int argl)233 startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
234 {
235 
236           openfirmware = openfirm;
237           setup();
238           main();
239           OF_exit();
240 }
241 
242 #if 0
243 void
244 OF_enter(void)
245 {
246           static struct {
247                     const char *name;
248                     int nargs;
249                     int nreturns;
250           } args = {
251                     "enter",
252                     0,
253                     0
254           };
255 
256           openfirmware(&args);
257 }
258 #endif    /* OF_enter */
259 
260 __dead void
OF_exit(void)261 OF_exit(void)
262 {
263           static struct {
264                     const char *name;
265                     int nargs;
266                     int nreturns;
267           } args = {
268                     "exit",
269                     0,
270                     0
271           };
272 
273           openfirmware(&args);
274           for (;;);                     /* just in case */
275 }
276 
277 int
OF_finddevice(const char * name)278 OF_finddevice(const char *name)
279 {
280           static struct {
281                     const char *name;
282                     int nargs;
283                     int nreturns;
284                     const char *device;
285                     int phandle;
286           } args = {
287                     "finddevice",
288                     1,
289                     1,
290           };
291 
292           args.device = name;
293           if (openfirmware(&args) == -1)
294                     return -1;
295           return args.phandle;
296 }
297 
298 int
OF_instance_to_package(int ihandle)299 OF_instance_to_package(int ihandle)
300 {
301           static struct {
302                     const char *name;
303                     int nargs;
304                     int nreturns;
305                     int ihandle;
306                     int phandle;
307           } args = {
308                     "instance-to-package",
309                     1,
310                     1,
311           };
312 
313           args.ihandle = ihandle;
314           if (openfirmware(&args) == -1)
315                     return -1;
316           return args.phandle;
317 }
318 
319 int
OF_getprop(int handle,const char * prop,void * buf,int buflen)320 OF_getprop(int handle, const char *prop, void *buf, int buflen)
321 {
322           static struct {
323                     const char *name;
324                     int nargs;
325                     int nreturns;
326                     int phandle;
327                     const char *prop;
328                     void *buf;
329                     int buflen;
330                     int size;
331           } args = {
332                     "getprop",
333                     4,
334                     1,
335           };
336 
337           args.phandle = handle;
338           args.prop = prop;
339           args.buf = buf;
340           args.buflen = buflen;
341           if (openfirmware(&args) == -1)
342                     return -1;
343           return args.size;
344 }
345 
346 #ifdef    __notyet__          /* Has a bug on FirePower */
347 int
OF_setprop(int handle,const char * prop,void * buf,int len)348 OF_setprop(int handle, const char *prop, void *buf, int len)
349 {
350           static struct {
351                     const char *name;
352                     int nargs;
353                     int nreturns;
354                     int phandle;
355                     const char *prop;
356                     void *buf;
357                     int len;
358                     int size;
359           } args = {
360                     "setprop",
361                     4,
362                     1,
363           };
364 
365           args.phandle = handle;
366           args.prop = prop;
367           args.buf = buf;
368           args.len = len;
369           if (openfirmware(&args) == -1)
370                     return -1;
371           return args.size;
372 }
373 #endif
374 
375 int
OF_open(const char * dname)376 OF_open(const char *dname)
377 {
378           static struct {
379                     const char *name;
380                     int nargs;
381                     int nreturns;
382                     const char *dname;
383                     int handle;
384           } args = {
385                     "open",
386                     1,
387                     1,
388           };
389 
390 #ifdef OFW_DEBUG
391           printf("OF_open(%s) -> ", dname);
392 #endif
393           args.dname = dname;
394           if (openfirmware(&args) == -1 ||
395               args.handle == 0) {
396 #ifdef OFW_DEBUG
397                     printf("lose\n");
398 #endif
399                     return -1;
400           }
401 #ifdef OFW_DEBUG
402           printf("%d\n", args.handle);
403 #endif
404           return args.handle;
405 }
406 
407 void
OF_close(int handle)408 OF_close(int handle)
409 {
410           static struct {
411                     const char *name;
412                     int nargs;
413                     int nreturns;
414                     int handle;
415           } args = {
416                     "close",
417                     1,
418                     0,
419           };
420 
421 #ifdef OFW_DEBUG
422           printf("OF_close(%d)\n", handle);
423 #endif
424           args.handle = handle;
425           openfirmware(&args);
426 }
427 
428 int
OF_write(int handle,void * addr,int len)429 OF_write(int handle, void *addr, int len)
430 {
431           static struct {
432                     const char *name;
433                     int nargs;
434                     int nreturns;
435                     int ihandle;
436                     void *addr;
437                     int len;
438                     int actual;
439           } args = {
440                     "write",
441                     3,
442                     1,
443           };
444 
445 #ifdef OFW_DEBUG
446           if (len != 1)
447                     printf("OF_write(%d, %p, %x) -> ", handle, addr, len);
448 #endif
449           args.ihandle = handle;
450           args.addr = addr;
451           args.len = len;
452           if (openfirmware(&args) == -1) {
453 #ifdef OFW_DEBUG
454                     printf("lose\n");
455 #endif
456                     return -1;
457           }
458 #ifdef OFW_DEBUG
459           if (len != 1)
460                     printf("%x\n", args.actual);
461 #endif
462           return args.actual;
463 }
464 
465 int
OF_read(int handle,void * addr,int len)466 OF_read(int handle, void *addr, int len)
467 {
468           static struct {
469                     const char *name;
470                     int nargs;
471                     int nreturns;
472                     int ihandle;
473                     void *addr;
474                     int len;
475                     int actual;
476           } args = {
477                     "read",
478                     3,
479                     1,
480           };
481 
482 #ifdef OFW_DEBUG
483           if (len != 1)
484                     printf("OF_read(%d, %p, %x) -> ", handle, addr, len);
485 #endif
486           args.ihandle = handle;
487           args.addr = addr;
488           args.len = len;
489           if (openfirmware(&args) == -1) {
490 #ifdef OFW_DEBUG
491                     printf("lose\n");
492 #endif
493                     return -1;
494           }
495 #ifdef OFW_DEBUG
496           if (len != 1)
497                     printf("%x\n", args.actual);
498 #endif
499           return args.actual;
500 }
501 
502 int
OF_seek(int handle,u_quad_t pos)503 OF_seek(int handle, u_quad_t pos)
504 {
505           static struct {
506                     const char *name;
507                     int nargs;
508                     int nreturns;
509                     int handle;
510                     int poshi;
511                     int poslo;
512                     int status;
513           } args = {
514                     "seek",
515                     3,
516                     1,
517           };
518 
519 #ifdef OFW_DEBUG
520           printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos);
521 #endif
522           args.handle = handle;
523           args.poshi = (int)(pos >> 32);
524           args.poslo = (int)pos;
525           if (openfirmware(&args) == -1) {
526 #ifdef OFW_DEBUG
527                     printf("lose\n");
528 #endif
529                     return -1;
530           }
531 #ifdef OFW_DEBUG
532           printf("%d\n", args.status);
533 #endif
534           return args.status;
535 }
536 
537 void *
OF_claim(void * virt,u_int size,u_int align)538 OF_claim(void *virt, u_int size, u_int align)
539 {
540           static struct {
541                     const char *name;
542                     int nargs;
543                     int nreturns;
544                     void *virt;
545                     u_int size;
546                     u_int align;
547                     void *baseaddr;
548           } args = {
549                     "claim",
550                     3,
551                     1,
552           };
553 
554 #ifdef OFW_DEBUG
555           printf("OF_claim(%p, %x, %x) -> ", virt, size, align);
556 #endif
557           args.virt = virt;
558           args.size = size;
559           args.align = align;
560           if (openfirmware(&args) == -1) {
561 #ifdef OFW_DEBUG
562                     printf("lose\n");
563 #endif
564                     return (void *)-1;
565           }
566 #ifdef OFW_DEBUG
567           printf("%p\n", args.baseaddr);
568 #endif
569           return args.baseaddr;
570 }
571 
572 void
OF_release(void * virt,u_int size)573 OF_release(void *virt, u_int size)
574 {
575           static struct {
576                     const char *name;
577                     int nargs;
578                     int nreturns;
579                     void *virt;
580                     u_int size;
581           } args = {
582                     "release",
583                     2,
584                     0,
585           };
586 
587 #ifdef OFW_DEBUG
588           printf("OF_release(%p, %x)\n", virt, size);
589 #endif
590           args.virt = virt;
591           args.size = size;
592           openfirmware(&args);
593 }
594 
595 int
OF_milliseconds(void)596 OF_milliseconds(void)
597 {
598           static struct {
599                     const char *name;
600                     int nargs;
601                     int nreturns;
602                     int ms;
603           } args = {
604                     "milliseconds",
605                     0,
606                     1,
607           };
608 
609           openfirmware(&args);
610           return args.ms;
611 }
612 
613 #ifdef    __notyet__
614 void
OF_chain(void * virt,u_int size,void (* entry)(),void * arg,u_int len)615 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
616 {
617           static struct {
618                     const char *name;
619                     int nargs;
620                     int nreturns;
621                     void *virt;
622                     u_int size;
623                     void (*entry)();
624                     void *arg;
625                     u_int len;
626           } args = {
627                     "chain",
628                     5,
629                     0,
630           };
631 
632           args.virt = virt;
633           args.size = size;
634           args.entry = entry;
635           args.arg = arg;
636           args.len = len;
637           openfirmware(&args);
638 }
639 #else
640 void
OF_chain(void * virt,u_int size,boot_entry_t entry,void * arg,u_int len)641 OF_chain(void *virt, u_int size, boot_entry_t entry, void *arg, u_int len)
642 {
643           /*
644            * This is a REALLY dirty hack till the firmware gets this going
645            */
646 #if 0
647           OF_release(virt, size);
648 #endif
649           entry(0, 0, openfirmware, arg, len);
650 }
651 #endif
652 
653 int
OF_call_method(const char * method,int ihandle,int nargs,int nreturns,int * cells)654 OF_call_method(const char *method, int ihandle, int nargs, int nreturns,
655     int *cells)
656 {
657           static struct {
658                     const char *name;
659                     int nargs;
660                     int nreturns;
661                     const char *method;
662                     int ihandle;
663                     int args_n_results[12];
664           } args = {
665                     "call-method",
666                     2,
667                     1,
668           };
669           int *ip, n;
670 
671           if (nargs > 6)
672                     return -1;
673 
674           args.nargs = nargs + 2;
675           args.nreturns = nreturns + 1;
676           args.method = method;
677           args.ihandle = ihandle;
678 
679           for (ip = args.args_n_results + (n = nargs); --n >= 0;)
680                     *--ip = *cells++;
681 
682           if (openfirmware(&args) == -1) {
683                     return -1;
684           }
685 
686           if (args.args_n_results[nargs]) {
687                     return args.args_n_results[nargs];
688           }
689 
690           for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
691                     *cells++ = *--ip;
692 
693           return 0;
694 }
695 
696 static void
setup(void)697 setup(void)
698 {
699           char prop[32];
700           int proplen;
701           const char *reason = NULL;
702 
703           if ((ofw_chosen = OF_finddevice("/chosen")) == -1)
704                     OF_exit();
705           if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, sizeof(ofw_stdin)) !=
706               sizeof(ofw_stdin) ||
707               OF_getprop(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) !=
708               sizeof(ofw_stdout))
709                     OF_exit();
710 
711           if (ofw_stdout == 0) {
712                     /* screen should be console, but it is not open */
713                     ofw_stdout = OF_open("screen");
714           }
715 
716 #ifdef HEAP_VARIABLE
717           uint32_t pvr, vers, hsize = HEAP_SIZE;
718 
719           __asm volatile ("mfpvr %0" : "=r"(pvr));
720           vers = pvr >> 16;
721           if (vers >= IBM970 && vers <= IBM970GX) hsize = 0x800000;
722 
723           heapspace = OF_claim(0, hsize, NBPG);
724           if (heapspace == (char *)-1) {
725                     panic("Failed to allocate heap");
726           }
727 
728           setheap(heapspace, heapspace + HEAP_SIZE);
729 #endif    /* HEAP_VARIABLE */
730 
731           ofw_root = OF_finddevice("/");
732           ofw_options = OF_finddevice("/options");
733           ofw_openprom = OF_finddevice("/openprom");
734           ofw_chosen = OF_finddevice("/chosen");
735 
736           if (ofw_root == -1) {
737                     reason = "No root node";
738                     goto bad_environment;
739           }
740           if (ofw_chosen == -1) {
741                     reason = "No chosen node";
742                     goto bad_environment;
743           }
744 
745           if (ofw_options != -1) {
746                     proplen = OF_getprop(ofw_options, "real-mode?", prop,
747                         sizeof(prop));
748                     if (proplen > 0) {
749                               ofw_real_mode = ofw_option_truefalse(prop, proplen);
750                     }
751           }
752 
753           /*
754            * Get #address-cells and #size-cells.
755            */
756           ofw_address_cells = 1;
757           ofw_size_cells = 1;
758           OF_getprop(ofw_root, "#address-cells", &ofw_address_cells,
759                        sizeof(ofw_address_cells));
760           OF_getprop(ofw_root, "#size-cells", &ofw_size_cells,
761                        sizeof(ofw_size_cells));
762 
763           /* See loadfile_machdep.c */
764           if (ofw_size_cells != 1) {
765                     printf("#size-cells = %d not yet supported\n", ofw_size_cells);
766                     reason = "unsupported #size-cells";
767                     goto bad_environment;
768           }
769 
770           /*
771            * Get the ihandle on /chosen/memory and /chosen/mmu.
772            */
773           ofw_memory_ihandle = -1;
774           ofw_mmu_ihandle = -1;
775           OF_getprop(ofw_chosen, "memory", &ofw_memory_ihandle,
776                        sizeof(ofw_memory_ihandle));
777           OF_getprop(ofw_chosen, "mmu", &ofw_mmu_ihandle,
778                        sizeof(ofw_mmu_ihandle));
779           if (ofw_memory_ihandle == -1) {
780                     reason = "no /chosen/memory";
781                     goto bad_environment;
782           }
783           if (ofw_mmu_ihandle == -1) {
784                     reason = "no /chosen/mmu";
785                     goto bad_environment;
786           }
787 
788           return;
789 
790  bad_environment:
791           if (reason == NULL) {
792                     reason = "unknown reason";
793           }
794           printf("Invalid Openfirmware environment: %s\n", reason);
795           OF_exit();
796 }
797 
798 void
putchar(int c)799 putchar(int c)
800 {
801           char ch = c;
802 
803           if (c == '\n')
804                     putchar('\r');
805           OF_write(ofw_stdout, &ch, 1);
806 }
807 
808 int
getchar(void)809 getchar(void)
810 {
811           unsigned char ch = '\0';
812           int l;
813 
814           while ((l = OF_read(ofw_stdin, &ch, 1)) != 1)
815                     if (l != -2 && l != 0)
816                               return -1;
817           return ch;
818 }
819