Catch attempts to queue to unregistered ISRs
[dragonfly.git] / sys / boot / pc32 / boot2 / boot2.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998 Robert Nordier
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are freely
6 * permitted provided that the above copyright notice and this
7 * paragraph and the following disclaimer are duplicated in all
8 * such forms.
9 *
10 * This software is provided "AS IS" and without any express or
11 * implied warranties, including, without limitation, the implied
12 * warranties of merchantability and fitness for a particular
13 * purpose.
14 */
15
16/*
17 * $FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.28.2.7 2002/10/10 15:53:24 iwasaki Exp $
18 * $DragonFly: src/sys/boot/pc32/boot2/boot2.c,v 1.4 2003/11/09 02:22:33 dillon Exp $
19 */
20
21#include <sys/param.h>
22#include <sys/reboot.h>
23#include <sys/diskslice.h>
24#include <sys/disklabel.h>
25#include <sys/dirent.h>
26#include <machine/bootinfo.h>
27#include <machine/elf.h>
28
29#include <vfs/ufs/fs.h>
30#include <vfs/ufs/dinode.h>
31
32#include <stdarg.h>
33
34#include <a.out.h>
35
36#include <btxv86.h>
37
38#include "boot2.h"
39#include "lib.h"
40
41#define RBX_ASKNAME 0x0 /* -a */
42#define RBX_SINGLE 0x1 /* -s */
43#define RBX_DFLTROOT 0x5 /* -r */
44#define RBX_KDB 0x6 /* -d */
45#define RBX_CONFIG 0xa /* -c */
46#define RBX_VERBOSE 0xb /* -v */
47#define RBX_SERIAL 0xc /* -h */
48#define RBX_CDROM 0xd /* -C */
49#define RBX_GDB 0xf /* -g */
50#define RBX_DUAL 0x1d /* -D */
51#define RBX_PROBEKBD 0x1e /* -P */
52#define RBX_NOINTR 0x1f /* -n */
53
54#define RBX_MASK 0xffff
55
56#define PATH_CONFIG "/boot.config"
57#define PATH_BOOT3 "/boot/loader"
58#define PATH_KERNEL "/kernel"
59
60#define ARGS 0x900
61#define NOPT 12
62#define BSIZEMAX 16384
63#define NDEV 5
64#define MEM_BASE 0x12
65#define MEM_EXT 0x15
66#define V86_CY(x) ((x) & 1)
67#define V86_ZR(x) ((x) & 0x40)
68
69#define DRV_HARD 0x80
70#define DRV_MASK 0x7f
71
72#define TYPE_AD 0
73#define TYPE_WD 1
74#define TYPE_WFD 2
75#define TYPE_FD 3
76#define TYPE_DA 4
77
78extern uint32_t _end;
79
80static const char optstr[NOPT] = "DhaCcdgnPrsv";
81static const unsigned char flags[NOPT] = {
82 RBX_DUAL,
83 RBX_SERIAL,
84 RBX_ASKNAME,
85 RBX_CDROM,
86 RBX_CONFIG,
87 RBX_KDB,
88 RBX_GDB,
89 RBX_NOINTR,
90 RBX_PROBEKBD,
91 RBX_DFLTROOT,
92 RBX_SINGLE,
93 RBX_VERBOSE
94};
95
96static const char *const dev_nm[] = {"ad", "wd", " ", "fd", "da"};
97static const unsigned dev_maj[] = {30, 0, 1, 2, 4};
98
99static struct dsk {
100 unsigned drive;
101 unsigned type;
102 unsigned unit;
103 unsigned slice;
104 unsigned part;
105 unsigned start;
106 int init;
107 int meta;
108} dsk;
109static char cmd[512];
110static char kname[1024];
111static uint32_t opts;
112static struct bootinfo bootinfo;
113static int ls;
114static uint32_t fs_off;
115static uint8_t ioctrl = 0x1;
116
117void exit(int);
118static void load(const char *);
119static int parse(char *);
120static ino_t lookup(const char *);
121static int xfsread(ino_t, void *, size_t);
122static ssize_t fsread(ino_t, void *, size_t);
123static int dskread(void *, unsigned, unsigned);
124static int printf(const char *,...);
125static int putchar(int);
126static void *memcpy(void *, const void *, size_t);
127static void *malloc(size_t);
128static uint32_t memsize(int);
129static int drvread(void *, unsigned, unsigned);
130static int keyhit(unsigned);
131static int xputc(int);
132static int xgetc(int);
133static int getc(int);
134
135static inline void
136readfile(const char *fname, void *buf, size_t size)
137{
138 ino_t ino;
139
140 if ((ino = lookup(fname)))
141 fsread(ino, buf, size);
142}
143
144static inline int
145strcmp(const char *s1, const char *s2)
146{
147 for (; *s1 == *s2 && *s1; s1++, s2++);
148 return (u_char)*s1 - (u_char)*s2;
149}
150
151static inline int
152fsfind(const char *name, ino_t * ino)
153{
154 char buf[DEV_BSIZE];
155 struct dirent *d;
156 char *s;
157 ssize_t n;
158
159 fs_off = 0;
160 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
161 for (s = buf; s < buf + DEV_BSIZE;) {
162 d = (void *)s;
163 if (ls)
164 printf("%s ", d->d_name);
165 else if (!strcmp(name, d->d_name)) {
166 *ino = d->d_fileno;
167 return d->d_type;
168 }
169 s += d->d_reclen;
170 }
171 if (n != -1 && ls)
172 putchar('\n');
173 return 0;
174}
175
176static inline int
177getchar(void)
178{
179 int c;
180
181 c = xgetc(0);
182 if (c == '\r')
183 c = '\n';
184 return c;
185}
186
187static inline void
188getstr(char *str, int size)
189{
190 char *s;
191 int c;
192
193 s = str;
194 do {
195 switch (c = getchar()) {
196 case 0:
197 break;
198 case '\b':
199 case '\177':
200 if (s > str) {
201 s--;
202 putchar('\b');
203 putchar(' ');
204 } else
205 c = 0;
206 break;
207 case '\n':
208 *s = 0;
209 break;
210 default:
211 if (s - str < size - 1)
212 *s++ = c;
213 }
214 if (c)
215 putchar(c);
216 } while (c != '\n');
217}
218
219static inline uint32_t
220drvinfo(int drive)
221{
222 v86.addr = 0x13;
223 v86.eax = 0x800;
224 v86.edx = DRV_HARD + drive;
225 v86int();
226 if (V86_CY(v86.efl))
227 return 0x4f010f;
228 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
229 (v86.edx & 0xff00) | (v86.ecx & 0x3f);
230}
231
232static inline void
233putc(int c)
234{
235 v86.addr = 0x10;
236 v86.eax = 0xe00 | (c & 0xff);
237 v86.ebx = 0x7;
238 v86int();
239}
240
241int
242main(void)
243{
244 int autoboot, i;
245
246 v86.ctl = V86_FLAGS;
247 dsk.drive = *(uint8_t *)PTOV(ARGS);
248 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
249 dsk.unit = dsk.drive & DRV_MASK;
250 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
251 bootinfo.bi_version = BOOTINFO_VERSION;
252 bootinfo.bi_size = sizeof(bootinfo);
253 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
254 bootinfo.bi_extmem = memsize(MEM_EXT);
255 bootinfo.bi_memsizes_valid++;
256 for (i = 0; i < N_BIOS_GEOM; i++)
257 bootinfo.bi_bios_geom[i] = drvinfo(i);
258 autoboot = 2;
259 readfile(PATH_CONFIG, cmd, sizeof(cmd));
260 if (*cmd) {
261 printf("%s: %s", PATH_CONFIG, cmd);
262 if (parse(cmd))
263 autoboot = 0;
264 *cmd = 0;
265 }
266 if (autoboot && !*kname) {
267 if (autoboot == 2) {
268 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
269 if (!keyhit(0x37)) {
270 load(kname);
271 autoboot = 1;
272 }
273 }
274 if (autoboot == 1)
275 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
276 }
277 for (;;) {
278 printf(" \n>> FreeBSD/i386 BOOT\n"
279 "Default: %u:%s(%u,%c)%s\n"
280 "boot: ",
281 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
282 'a' + dsk.part, kname);
283 if (ioctrl & 0x2)
284 sio_flush();
285 if (!autoboot || keyhit(0x5a))
286 getstr(cmd, sizeof(cmd));
287 else
288 putchar('\n');
289 autoboot = 0;
290 if (parse(cmd))
291 putchar('\a');
292 else
293 load(kname);
294 }
295}
296
297/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
298void
299exit(int x)
300{
301}
302
303static void
304load(const char *fname)
305{
306 union {
307 struct exec ex;
308 Elf32_Ehdr eh;
309 } hdr;
310 Elf32_Phdr ep[2];
311 Elf32_Shdr es[2];
312 caddr_t p;
313 ino_t ino;
314 uint32_t addr, x;
315 int fmt, i, j;
316
317 if (!(ino = lookup(fname))) {
318 if (!ls)
319 printf("No %s\n", fname);
320 return;
321 }
322 if (xfsread(ino, &hdr, sizeof(hdr)))
323 return;
324 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
325 fmt = 0;
326 else if (IS_ELF(hdr.eh))
327 fmt = 1;
328 else {
329 printf("Invalid %s\n", "format");
330 return;
331 }
332 if (fmt == 0) {
333 addr = hdr.ex.a_entry & 0xffffff;
334 p = PTOV(addr);
335 fs_off = PAGE_SIZE;
336 if (xfsread(ino, p, hdr.ex.a_text))
337 return;
338 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
339 if (xfsread(ino, p, hdr.ex.a_data))
340 return;
341 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
342 bootinfo.bi_symtab = VTOP(p);
343 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
344 p += sizeof(hdr.ex.a_syms);
345 if (hdr.ex.a_syms) {
346 if (xfsread(ino, p, hdr.ex.a_syms))
347 return;
348 p += hdr.ex.a_syms;
349 if (xfsread(ino, p, sizeof(int)))
350 return;
351 x = *(uint32_t *)p;
352 p += sizeof(int);
353 x -= sizeof(int);
354 if (xfsread(ino, p, x))
355 return;
356 p += x;
357 }
358 } else {
359 fs_off = hdr.eh.e_phoff;
360 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
361 if (xfsread(ino, ep + j, sizeof(ep[0])))
362 return;
363 if (ep[j].p_type == PT_LOAD)
364 j++;
365 }
366 for (i = 0; i < 2; i++) {
367 p = PTOV(ep[i].p_paddr & 0xffffff);
368 fs_off = ep[i].p_offset;
369 if (xfsread(ino, p, ep[i].p_filesz))
370 return;
371 }
372 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
373 bootinfo.bi_symtab = VTOP(p);
374 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
375 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
376 (hdr.eh.e_shstrndx + 1);
377 if (xfsread(ino, &es, sizeof(es)))
378 return;
379 for (i = 0; i < 2; i++) {
380 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
381 p += sizeof(es[i].sh_size);
382 fs_off = es[i].sh_offset;
383 if (xfsread(ino, p, es[i].sh_size))
384 return;
385 p += es[i].sh_size;
386 }
387 }
388 addr = hdr.eh.e_entry & 0xffffff;
389 }
390 bootinfo.bi_esymtab = VTOP(p);
391 bootinfo.bi_kernelname = VTOP(fname);
392 bootinfo.bi_bios_dev = dsk.drive;
393 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
394 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
395 0, 0, 0, VTOP(&bootinfo));
396}
397
398static int
399parse(char *arg)
400{
401 char *p, *q;
402 int drv, c, i;
403
404 while ((c = *arg++)) {
405 if (c == ' ' || c == '\t' || c == '\n')
406 continue;
407 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
408 if (*p)
409 *p++ = 0;
410 if (c == '-') {
411 while ((c = *arg++)) {
412 for (i = 0; c != optstr[i]; i++)
413 if (i == NOPT - 1)
414 return -1;
415 opts ^= 1 << flags[i];
416 }
417 if (opts & 1 << RBX_PROBEKBD) {
418 i = *(uint8_t *)PTOV(0x496) & 0x10;
419 printf("Keyboard: %s\n", i ? "yes" : "no");
420 if (!i)
421 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
422 opts &= ~(1 << RBX_PROBEKBD);
423 }
424 ioctrl = opts & 1 << RBX_DUAL ? 0x3 :
425 opts & 1 << RBX_SERIAL ? 0x2 : 0x1;
426 if (ioctrl & 0x2)
427 sio_init();
428 } else {
429 for (q = arg--; *q && *q != '('; q++);
430 if (*q) {
431 drv = -1;
432 if (arg[1] == ':') {
433 if (*arg < '0' || *arg > '9')
434 return -1;
435 drv = *arg - '0';
436 arg += 2;
437 }
438 if (q - arg != 2)
439 return -1;
440 for (i = 0; arg[0] != dev_nm[i][0] ||
441 arg[1] != dev_nm[i][1]; i++)
442 if (i == NDEV - 1)
443 return -1;
444 dsk.type = i;
445 arg += 3;
446 if (arg[1] != ',' || *arg < '0' || *arg > '9')
447 return -1;
448 dsk.unit = *arg - '0';
449 arg += 2;
450 dsk.slice = WHOLE_DISK_SLICE;
451 if (arg[1] == ',') {
452 if (*arg < '0' || *arg > '0' + NDOSPART)
453 return -1;
454 if ((dsk.slice = *arg - '0'))
455 dsk.slice++;
456 arg += 2;
457 }
458 if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
459 return -1;
460 dsk.part = *arg - 'a';
461 arg += 2;
462 if (drv == -1)
463 drv = dsk.unit;
464 dsk.drive = (dsk.type == TYPE_WD ||
465 dsk.type == TYPE_AD ||
466 dsk.type == TYPE_DA ? DRV_HARD : 0) + drv;
467 dsk.meta = 0;
468 fsread(0, NULL, 0);
469 }
470 if ((i = p - arg - !*(p - 1))) {
471 if (i >= sizeof(kname))
472 return -1;
473 memcpy(kname, arg, i + 1);
474 }
475 }
476 arg = p;
477 }
478 return 0;
479}
480
481static ino_t
482lookup(const char *path)
483{
484 char name[MAXNAMLEN + 1];
485 const char *s;
486 ino_t ino;
487 ssize_t n;
488 int dt;
489
490 ino = ROOTINO;
491 dt = DT_DIR;
492 for (;;) {
493 if (*path == '/')
494 path++;
495 if (!*path)
496 break;
497 for (s = path; *s && *s != '/'; s++);
498 if ((n = s - path) > MAXNAMLEN)
499 return 0;
500 ls = *path == '?' && n == 1 && !*s;
501 memcpy(name, path, n);
502 name[n] = 0;
503 if ((dt = fsfind(name, &ino)) <= 0)
504 break;
505 path = s;
506 }
507 return dt == DT_REG ? ino : 0;
508}
509static int
510xfsread(ino_t inode, void *buf, size_t nbyte)
511{
512 if (fsread(inode, buf, nbyte) != nbyte) {
513 printf("Invalid %s\n", "format");
514 return -1;
515 }
516 return 0;
517}
518
519static ssize_t
520fsread(ino_t inode, void *buf, size_t nbyte)
521{
522 static struct fs fs;
523 static struct dinode din;
524 static char *blkbuf;
525 static ufs_daddr_t *indbuf;
526 static ino_t inomap;
527 static ufs_daddr_t blkmap, indmap;
528 static unsigned fsblks;
529 char *s;
530 ufs_daddr_t lbn, addr;
531 size_t n, nb, off;
532
533 if (!dsk.meta) {
534 if (!blkbuf)
535 blkbuf = malloc(BSIZEMAX);
536 inomap = 0;
537 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
538 return -1;
539 memcpy(&fs, blkbuf, sizeof(fs));
540 if (fs.fs_magic != FS_MAGIC) {
541 printf("Not ufs\n");
542 return -1;
543 }
544 fsblks = fs.fs_bsize >> DEV_BSHIFT;
545 dsk.meta++;
546 }
547 if (!inode)
548 return 0;
549 if (inomap != inode) {
550 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
551 fsblks))
552 return -1;
553 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
554 inomap = inode;
555 fs_off = 0;
556 blkmap = indmap = 0;
557 }
558 s = buf;
559 if (nbyte > (n = din.di_size - fs_off))
560 nbyte = n;
561 nb = nbyte;
562 while (nb) {
563 lbn = lblkno(&fs, fs_off);
564 if (lbn < NDADDR)
565 addr = din.di_db[lbn];
566 else {
567 if (indmap != din.di_ib[0]) {
568 if (!indbuf)
569 indbuf = malloc(BSIZEMAX);
570 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
571 fsblks))
572 return -1;
573 indmap = din.di_ib[0];
574 }
575 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
576 }
577 n = dblksize(&fs, &din, lbn);
578 if (blkmap != addr) {
579 if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT))
580 return -1;
581 blkmap = addr;
582 }
583 off = blkoff(&fs, fs_off);
584 n -= off;
585 if (n > nb)
586 n = nb;
587 memcpy(s, blkbuf + off, n);
588 s += n;
589 fs_off += n;
590 nb -= n;
591 }
592 return nbyte;
593}
594
595static int
596dskread(void *buf, unsigned lba, unsigned nblk)
597{
598 static char *sec;
599 struct dos_partition *dp;
600 struct disklabel *d;
601 unsigned sl, i;
602
603 if (!dsk.meta) {
604 if (!sec)
605 sec = malloc(DEV_BSIZE);
606 dsk.start = 0;
607 if (drvread(sec, DOSBBSECTOR, 1))
608 return -1;
609 dp = (void *)(sec + DOSPARTOFF);
610 sl = dsk.slice;
611 if (sl < BASE_SLICE) {
612 for (i = 0; i < NDOSPART; i++)
613 if (dp[i].dp_typ == DOSPTYP_386BSD &&
614 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
615 sl = BASE_SLICE + i;
616 if (dp[i].dp_flag & 0x80 ||
617 dsk.slice == COMPATIBILITY_SLICE)
618 break;
619 }
620 if (dsk.slice == WHOLE_DISK_SLICE)
621 dsk.slice = sl;
622 }
623 if (sl != WHOLE_DISK_SLICE) {
624 if (sl != COMPATIBILITY_SLICE)
625 dp += sl - BASE_SLICE;
626 if (dp->dp_typ != DOSPTYP_386BSD) {
627 printf("Invalid %s\n", "slice");
628 return -1;
629 }
630 dsk.start = dp->dp_start;
631 }
632 if (drvread(sec, dsk.start + LABELSECTOR, 1))
633 return -1;
634 d = (void *)(sec + LABELOFFSET);
635 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
636 if (dsk.part != RAW_PART) {
637 printf("Invalid %s\n", "label");
638 return -1;
639 }
640 } else {
641 if (!dsk.init) {
642 if (d->d_type == DTYPE_SCSI)
643 dsk.type = TYPE_DA;
644 dsk.init++;
645 }
646 if (dsk.part >= d->d_npartitions ||
647 !d->d_partitions[dsk.part].p_size) {
648 printf("Invalid %s\n", "partition");
649 return -1;
650 }
651 dsk.start = d->d_partitions[dsk.part].p_offset;
652 }
653 }
654 return drvread(buf, dsk.start + lba, nblk);
655}
656
657static int
658printf(const char *fmt,...)
659{
660 static const char digits[16] = "0123456789abcdef";
661 __va_list ap;
662 char buf[10];
663 char *s;
664 unsigned r, u;
665 int c;
666
667 __va_start(ap, fmt);
668 while ((c = *fmt++)) {
669 if (c == '%') {
670 c = *fmt++;
671 switch (c) {
672 case 'c':
673 putchar(__va_arg(ap, int));
674 continue;
675 case 's':
676 for (s = __va_arg(ap, char *); *s; s++)
677 putchar(*s);
678 continue;
679 case 'u':
680 case 'x':
681 r = c == 'u' ? 10U : 16U;
682 u = __va_arg(ap, unsigned);
683 s = buf;
684 do
685 *s++ = digits[u % r];
686 while (u /= r);
687 while (--s >= buf)
688 putchar(*s);
689 continue;
690 }
691 }
692 putchar(c);
693 }
694 __va_end(ap);
695 return 0;
696}
697
698static int
699putchar(int c)
700{
701 if (c == '\n')
702 xputc('\r');
703 return xputc(c);
704}
705
706static void *
707memcpy(void *dst, const void *src, size_t size)
708{
709 const char *s;
710 char *d;
711
712 for (d = dst, s = src; size; size--)
713 *d++ = *s++;
714 return dst;
715}
716
717static void *
718malloc(size_t size)
719{
720 static uint32_t next;
721 void *p;
722
723 if (!next)
724 next = roundup2(__base + _end, 0x10000) - __base;
725 p = (void *)next;
726 next += size;
727 return p;
728}
729
730static uint32_t
731memsize(int type)
732{
733 v86.addr = type;
734 v86.eax = 0x8800;
735 v86int();
736 return v86.eax;
737}
738
739static int
740drvread(void *buf, unsigned lba, unsigned nblk)
741{
742 static unsigned c = 0x2d5c7c2f;
743
744 printf("%c\b", c = c << 8 | c >> 24);
745 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
746 v86.addr = XREADORG; /* call to xread in boot1 */
747 v86.es = VTOPSEG(buf);
748 v86.eax = lba;
749 v86.ebx = VTOPOFF(buf);
750 v86.ecx = lba >> 16;
751 v86.edx = nblk << 8 | dsk.drive;
752 v86int();
753 v86.ctl = V86_FLAGS;
754 if (V86_CY(v86.efl)) {
755 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
756 lba);
757 return -1;
758 }
759 return 0;
760}
761
762static int
763keyhit(unsigned ticks)
764{
765 uint32_t t0, t1;
766
767 if (opts & 1 << RBX_NOINTR)
768 return 0;
769 t0 = 0;
770 for (;;) {
771 if (xgetc(1))
772 return 1;
773 t1 = *(uint32_t *)PTOV(0x46c);
774 if (!t0)
775 t0 = t1;
776 if (t1 < t0 || t1 >= t0 + ticks)
777 return 0;
778 }
779}
780
781static int
782xputc(int c)
783{
784 if (ioctrl & 0x1)
785 putc(c);
786 if (ioctrl & 0x2)
787 sio_putc(c);
788 return c;
789}
790
791static int
792xgetc(int fn)
793{
794 if (opts & 1 << RBX_NOINTR)
795 return 0;
796 for (;;) {
797 if (ioctrl & 0x1 && getc(1))
798 return fn ? 1 : getc(0);
799 if (ioctrl & 0x2 && sio_ischar())
800 return fn ? 1 : sio_getc();
801 if (fn)
802 return 0;
803 }
804}
805
806static int
807getc(int fn)
808{
809 v86.addr = 0x16;
810 v86.eax = fn << 8;
811 v86int();
812 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
813}