Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / boot / biosboot / io.c
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992, 1991 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  *
26  *      from: Mach, Revision 2.2  92/04/04  11:35:57  rpd
27  * $FreeBSD: src/sys/i386/boot/biosboot/io.c,v 1.26 1999/08/28 00:43:13 peter Exp $
28  */
29
30 #include "boot.h"
31 #include <machine/cpufunc.h>
32 #include <sys/reboot.h>
33
34 #define K_RDWR          0x60            /* keyboard data & cmds (read/write) */
35 #define K_STATUS        0x64            /* keyboard status */
36 #define K_CMD           0x64            /* keybd ctlr command (write-only) */
37
38 #define K_OBUF_FUL      0x01            /* output buffer full */
39 #define K_IBUF_FUL      0x02            /* input buffer full */
40
41 #define KC_CMD_WIN      0xd0            /* read  output port */
42 #define KC_CMD_WOUT     0xd1            /* write output port */
43 #define KB_A20          0xdf            /* enable A20,
44                                            enable output buffer full interrupt
45                                            enable data line
46                                            enable clock line */
47
48
49 static int getchar(int in_buf);
50
51 /*
52  * Gate A20 for high memory
53  */
54 void
55 gateA20(void)
56 {
57 #ifdef  IBM_L40
58         outb(0x92, 0x2);
59 #else   /* !IBM_L40 */
60         while (inb(K_STATUS) & K_IBUF_FUL);
61         while (inb(K_STATUS) & K_OBUF_FUL)
62                 (void)inb(K_RDWR);
63
64         outb(K_CMD, KC_CMD_WOUT);
65         while (inb(K_STATUS) & K_IBUF_FUL);
66         outb(K_RDWR, KB_A20);
67         while (inb(K_STATUS) & K_IBUF_FUL);
68 #endif  /* IBM_L40 */
69 }
70
71 /* printf - only handles %d as decimal, %c as char, %s as string */
72
73 void
74 printf(const char *format, ...)
75 {
76         int *dataptr = (int *)&format;
77         char c;
78
79         dataptr++;
80         while ((c = *format++))
81                 if (c != '%')
82                         putchar(c);
83                 else
84                         switch (c = *format++) {
85                               case 'd': {
86                                       int num = *dataptr++;
87                                       char buf[10], *ptr = buf;
88                                       if (num<0) {
89                                               num = -num;
90                                               putchar('-');
91                                       }
92                                       do
93                                               *ptr++ = '0'+num%10;
94                                       while (num /= 10);
95                                       do
96                                               putchar(*--ptr);
97                                       while (ptr != buf);
98                                       break;
99                               }
100                               case 'x': {
101                                       unsigned int num = *dataptr++, dig;
102                                       char buf[8], *ptr = buf;
103                                       do
104                                               *ptr++ = (dig=(num&0xf)) > 9?
105                                                         'a' + dig - 10 :
106                                                         '0' + dig;
107                                       while (num >>= 4);
108                                       do
109                                               putchar(*--ptr);
110                                       while (ptr != buf);
111                                       break;
112                               }
113                               case 'c': putchar((*dataptr++)&0xff); break;
114                               case 's': {
115                                       char *ptr = (char *)*dataptr++;
116                                       while ((c = *ptr++))
117                                               putchar(c);
118                                       break;
119                               }
120                         }
121 }
122
123 void
124 putchar(int c)
125 {
126         if (c == '\n')
127                 putchar('\r');
128         if (loadflags & RB_DUAL) {
129                 putc(c);
130                 serial_putc(c);
131         } else if (loadflags & RB_SERIAL)
132                 serial_putc(c);
133         else
134                 putc(c);
135 }
136
137 static int
138 getchar(int in_buf)
139 {
140         int c;
141
142 loop:
143         if (loadflags & RB_DUAL) {
144                 if (ischar())
145                         c = getc();
146                 else if (serial_ischar())
147                         c = serial_getc();
148                 else
149                         goto loop;
150         } else if (loadflags & RB_SERIAL)
151                 c = serial_getc();
152         else
153                 c = getc();
154         if (c == '\r')
155                 c = '\n';
156         if (c == '\b') {
157                 if (in_buf != 0) {
158                         putchar('\b');
159                         putchar(' ');
160                 } else {
161                         goto loop;
162                 }
163         }
164         putchar(c);
165         return(c);
166 }
167
168 /*
169  * This routine uses an inb to an unused port, the time to execute that
170  * inb is approximately 1.25uS.  This value is pretty constant across
171  * all CPU's and all buses, with the exception of some PCI implentations
172  * that do not forward this I/O adress to the ISA bus as they know it
173  * is not a valid ISA bus address, those machines execute this inb in
174  * 60 nS :-(.
175  *
176  * XXX this should be converted to use bios_tick.
177  */
178 void
179 delay1ms(void)
180 {
181         int i = 800;
182         while (--i >= 0)
183                 (void)inb(0x84);
184 }
185
186 static __inline int
187 isch(void)
188 {
189         int isc;
190
191         /*
192          * Checking the keyboard has the side effect of enabling clock
193          * interrupts so that bios_tick works.  Check the keyboard to
194          * get this side effect even if we only want the serial status.
195          */
196         isc = ischar();
197
198         if (loadflags & RB_DUAL) {
199                 if (isc != 0)
200                         return (isc);
201         } else if (!(loadflags & RB_SERIAL))
202                 return (isc);
203         return (serial_ischar());
204 }
205
206 static __inline unsigned
207 pword(unsigned physaddr)
208 {
209         unsigned result;
210
211         /*
212          * Give the fs prefix separately because gas omits it for
213          * "movl %fs:0x46c, %eax".
214          */
215         __asm __volatile("fs; movl %1, %0" : "=r" (result)
216                          : "m" (*(unsigned *)physaddr));
217         return (result);
218 }
219
220 int
221 gets(char *buf)
222 {
223 #define bios_tick               pword(0x46c)
224 #define BIOS_TICK_MS            55
225         unsigned initial_bios_tick;
226         char *ptr=buf;
227
228 #if BOOTWAIT
229         for (initial_bios_tick = bios_tick;
230              bios_tick - initial_bios_tick < BOOTWAIT / BIOS_TICK_MS;)
231 #endif
232                 if (isch())
233                         for (;;) {
234                                 switch(*ptr = getchar(ptr - buf) & 0xff) {
235                                       case '\n':
236                                       case '\r':
237                                         *ptr = '\0';
238                                         return 1;
239                                       case '\b':
240                                         if (ptr > buf) ptr--;
241                                         continue;
242                                       default:
243                                         ptr++;
244                                 }
245 #if TIMEOUT + 0
246 #if !BOOTWAIT
247 #error "TIMEOUT without BOOTWAIT"
248 #endif
249                                 for (initial_bios_tick = bios_tick;;) {
250                                         if (isch())
251                                                 break;
252                                         if (bios_tick - initial_bios_tick >=
253                                             TIMEOUT / BIOS_TICK_MS)
254                                         return 0;
255                                 }
256 #endif
257                         }
258         return 0;
259 }
260
261 int
262 strcmp(const char *s1, const char *s2)
263 {
264         while (*s1 == *s2) {
265                 if (!*s1++)
266                         return 0;
267                 s2++;
268         }
269         return 1;
270 }
271
272 #ifdef CDBOOT
273 int
274 strcasecmp(const char *s1, const char *s2)
275 {
276         /*
277          * We only consider ASCII chars and don't anticipate
278          * control characters (they are invalid in filenames
279          * anyway).
280          */
281         while ((*s1 & 0x5f) == (*s2 & 0x5f)) {
282                 if (!*s1++)
283                         return 0;
284                 s2++;
285         }
286         return 1;
287 }
288 #endif /* !CDBOOT */
289
290 void
291 bcopy(const void *from, void *to, size_t len)
292 {
293         char *fp = (char *)from;
294         char *tp = (char *)to;
295
296         while (len-- > 0)
297                 *tp++ = *fp++;
298 }
299
300 /* To quote Ken: "You are not expected to understand this." :) */
301
302 void
303 twiddle(void)
304 {
305         putchar((char)tw_chars);
306         tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24);
307         putchar('\b');
308 }