We will need more resource-limiting compliance work done before these
[dragonfly.git] / sys / boot / pc32 / boot2 / boot2.c
CommitLineData
cacaceec
MD
1/*
2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
984263bc
MD
34 * Copyright (c) 1998 Robert Nordier
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms are freely
38 * permitted provided that the above copyright notice and this
39 * paragraph and the following disclaimer are duplicated in all
40 * such forms.
41 *
42 * This software is provided "AS IS" and without any express or
43 * implied warranties, including, without limitation, the implied
44 * warranties of merchantability and fitness for a particular
45 * purpose.
5ee58eed
MD
46 *
47 * $FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.64 2003/08/25 23:28:31 obrien Exp $
cacaceec 48 * $DragonFly: src/sys/boot/pc32/boot2/boot2.c,v 1.12 2004/07/19 23:30:32 dillon Exp $
984263bc 49 */
984263bc 50#include <sys/param.h>
984263bc 51#include <sys/disklabel.h>
5ee58eed
MD
52#include <sys/diskslice.h>
53#include <sys/diskmbr.h>
984263bc
MD
54#include <sys/dirent.h>
55#include <machine/bootinfo.h>
56#include <machine/elf.h>
57
984263bc
MD
58#include <stdarg.h>
59
60#include <a.out.h>
61
62#include <btxv86.h>
63
64#include "boot2.h"
65#include "lib.h"
409cbc03 66#include "../bootasm.h"
984263bc 67
5ee58eed
MD
68#define SECOND 18 /* Circa that many ticks in a second. */
69
984263bc
MD
70#define RBX_ASKNAME 0x0 /* -a */
71#define RBX_SINGLE 0x1 /* -s */
72#define RBX_DFLTROOT 0x5 /* -r */
73#define RBX_KDB 0x6 /* -d */
74#define RBX_CONFIG 0xa /* -c */
75#define RBX_VERBOSE 0xb /* -v */
76#define RBX_SERIAL 0xc /* -h */
77#define RBX_CDROM 0xd /* -C */
78#define RBX_GDB 0xf /* -g */
5ee58eed
MD
79#define RBX_MUTE 0x10 /* -m */
80#define RBX_PAUSE 0x12 /* -p */
81#define RBX_NOINTR 0x1c /* -n */
badbfe61 82#define RBX_VIDEO 0x1d /* -V */
984263bc 83#define RBX_PROBEKBD 0x1e /* -P */
5ee58eed 84/* 0x1f is reserved for the historical RB_BOOTINFO option */
984263bc 85
38e10dff 86#define RBF_MUTE (1 << RBX_MUTE)
badbfe61
MD
87#define RBF_SERIAL (1 << RBX_SERIAL)
88#define RBF_VIDEO (1 << RBX_VIDEO)
89
50a1695f 90/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -V */
5ee58eed 91#define RBX_MASK 0x2005ffff
984263bc
MD
92
93#define PATH_CONFIG "/boot.config"
94#define PATH_BOOT3 "/boot/loader"
95#define PATH_KERNEL "/kernel"
96
5ee58eed 97#define NDEV 3
984263bc
MD
98#define MEM_BASE 0x12
99#define MEM_EXT 0x15
100#define V86_CY(x) ((x) & 1)
101#define V86_ZR(x) ((x) & 0x40)
102
103#define DRV_HARD 0x80
104#define DRV_MASK 0x7f
105
106#define TYPE_AD 0
5ee58eed
MD
107#define TYPE_DA 1
108#define TYPE_MAXHARD TYPE_DA
109#define TYPE_FD 2
984263bc 110
badbfe61
MD
111#define NOPT 12
112
984263bc
MD
113extern uint32_t _end;
114
badbfe61 115static const char optstr[NOPT] = { "VhaCgmnPprsv" };
984263bc 116static const unsigned char flags[NOPT] = {
badbfe61 117 RBX_VIDEO,
984263bc
MD
118 RBX_SERIAL,
119 RBX_ASKNAME,
120 RBX_CDROM,
984263bc 121 RBX_GDB,
5ee58eed 122 RBX_MUTE,
984263bc
MD
123 RBX_NOINTR,
124 RBX_PROBEKBD,
5ee58eed 125 RBX_PAUSE,
984263bc
MD
126 RBX_DFLTROOT,
127 RBX_SINGLE,
128 RBX_VERBOSE
129};
130
5ee58eed
MD
131static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
132static const unsigned char dev_maj[NDEV] = {30, 4, 2};
984263bc
MD
133
134static struct dsk {
135 unsigned drive;
136 unsigned type;
137 unsigned unit;
138 unsigned slice;
139 unsigned part;
140 unsigned start;
141 int init;
984263bc
MD
142} dsk;
143static char cmd[512];
144static char kname[1024];
145static uint32_t opts;
146static struct bootinfo bootinfo;
984263bc
MD
147
148void exit(int);
5ee58eed
MD
149static void load(void);
150static int parse(void);
984263bc 151static int xfsread(ino_t, void *, size_t);
984263bc 152static int dskread(void *, unsigned, unsigned);
5ee58eed
MD
153static void printf(const char *,...);
154static void putchar(int);
155static uint32_t memsize(void);
984263bc
MD
156static int drvread(void *, unsigned, unsigned);
157static int keyhit(unsigned);
50a1695f 158static void xputc(int);
984263bc
MD
159static int xgetc(int);
160static int getc(int);
161
5ee58eed
MD
162static void
163memcpy(void *d, const void *s, int len)
984263bc 164{
5ee58eed
MD
165 char *dd = d;
166 const char *ss = s;
984263bc 167
5ee58eed
MD
168#if 0
169 if (dd < ss) {
170 while (--len >= 0)
171 *dd++ = *ss++;
172 } else {
173#endif
174 while (--len >= 0)
175 dd[len] = ss[len];
176#if 0
177 }
178#endif
984263bc
MD
179}
180
181static inline int
182strcmp(const char *s1, const char *s2)
183{
184 for (; *s1 == *s2 && *s1; s1++, s2++);
5ee58eed 185 return (unsigned char)*s1 - (unsigned char)*s2;
984263bc
MD
186}
187
5ee58eed
MD
188#include "ufsread.c"
189
190static int
191xfsread(ino_t inode, void *buf, size_t nbyte)
984263bc 192{
5ee58eed
MD
193 if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
194 printf("Invalid %s\n", "format");
195 return -1;
196 }
984263bc
MD
197 return 0;
198}
199
5ee58eed
MD
200static inline uint32_t
201memsize(void)
984263bc 202{
5ee58eed
MD
203 v86.addr = MEM_EXT;
204 v86.eax = 0x8800;
205 v86int();
206 return v86.eax;
984263bc
MD
207}
208
209static inline void
5ee58eed 210getstr(void)
984263bc
MD
211{
212 char *s;
213 int c;
214
5ee58eed
MD
215 s = cmd;
216 for (;;) {
217 switch (c = xgetc(0)) {
984263bc
MD
218 case 0:
219 break;
984263bc 220 case '\177':
5ee58eed
MD
221 case '\b':
222 if (s > cmd) {
984263bc 223 s--;
5ee58eed
MD
224 printf("\b \b");
225 }
984263bc
MD
226 break;
227 case '\n':
5ee58eed 228 case '\r':
984263bc 229 *s = 0;
5ee58eed 230 return;
984263bc 231 default:
5ee58eed 232 if (s - cmd < sizeof(cmd) - 1)
984263bc 233 *s++ = c;
984263bc 234 putchar(c);
5ee58eed
MD
235 }
236 }
984263bc
MD
237}
238
239static inline void
240putc(int c)
241{
242 v86.addr = 0x10;
243 v86.eax = 0xe00 | (c & 0xff);
244 v86.ebx = 0x7;
245 v86int();
246}
247
248int
249main(void)
250{
5ee58eed
MD
251 int autoboot;
252 ino_t ino;
984263bc 253
5ee58eed 254 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
984263bc 255 v86.ctl = V86_FLAGS;
cacaceec 256 dsk.drive = *(uint8_t *)PTOV(MEM_BTX_USR_ARG);
984263bc
MD
257 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
258 dsk.unit = dsk.drive & DRV_MASK;
cacaceec 259 dsk.slice = *(uint8_t *)PTOV(MEM_BTX_USR_ARG + 1) + 1;
984263bc
MD
260 bootinfo.bi_version = BOOTINFO_VERSION;
261 bootinfo.bi_size = sizeof(bootinfo);
262 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
5ee58eed 263 bootinfo.bi_extmem = memsize();
984263bc 264 bootinfo.bi_memsizes_valid++;
5ee58eed
MD
265
266 /* Process configuration file */
267
268 autoboot = 1;
269
270 if ((ino = lookup(PATH_CONFIG)))
271 fsread(ino, cmd, sizeof(cmd));
272
badbfe61 273 if (cmd[0]) {
984263bc 274 printf("%s: %s", PATH_CONFIG, cmd);
5ee58eed 275 if (parse())
984263bc 276 autoboot = 0;
5ee58eed 277 /* Do not process this command twice */
984263bc
MD
278 *cmd = 0;
279 }
5ee58eed 280
badbfe61 281 /*
38e10dff
MD
282 * Setup our (serial) console after processing the config file. If
283 * the initialization fails, don't try to use the serial port. This
284 * can happen if the serial port is unmaped (happens on new laptops a lot).
badbfe61 285 */
38e10dff 286 if ((opts & (RBF_MUTE|RBF_SERIAL|RBF_VIDEO)) == 0)
badbfe61 287 opts |= RBF_SERIAL|RBF_VIDEO;
38e10dff
MD
288 if (opts & RBF_SERIAL) {
289 if (sio_init())
290 opts = RBF_VIDEO;
291 }
badbfe61
MD
292
293
5ee58eed
MD
294 /*
295 * Try to exec stage 3 boot loader. If interrupted by a keypress,
296 * or in case of failure, try to load a kernel directly instead.
297 */
298
984263bc 299 if (autoboot && !*kname) {
5ee58eed
MD
300 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
301 if (!keyhit(3*SECOND)) {
302 load();
984263bc 303 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
5ee58eed 304 }
984263bc 305 }
5ee58eed
MD
306
307 /* Present the user with the boot2 prompt. */
308
984263bc 309 for (;;) {
38e10dff
MD
310 printf("\nDragonFly boot\n"
311 "%u:%s(%u,%c)%s: ",
984263bc
MD
312 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
313 'a' + dsk.part, kname);
5ee58eed
MD
314 if (!autoboot || keyhit(5*SECOND))
315 getstr();
984263bc
MD
316 else
317 putchar('\n');
318 autoboot = 0;
badbfe61 319 if (cmd[0] == 0 || parse())
5ee58eed 320 putchar('\a');
984263bc 321 else
5ee58eed 322 load();
984263bc
MD
323 }
324}
325
326/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
327void
328exit(int x)
329{
330}
331
332static void
5ee58eed 333load(void)
984263bc
MD
334{
335 union {
336 struct exec ex;
337 Elf32_Ehdr eh;
338 } hdr;
339 Elf32_Phdr ep[2];
340 Elf32_Shdr es[2];
341 caddr_t p;
342 ino_t ino;
343 uint32_t addr, x;
344 int fmt, i, j;
345
5ee58eed 346 if (!(ino = lookup(kname))) {
984263bc 347 if (!ls)
5ee58eed 348 printf("No %s\n", kname);
984263bc
MD
349 return;
350 }
351 if (xfsread(ino, &hdr, sizeof(hdr)))
352 return;
353 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
354 fmt = 0;
355 else if (IS_ELF(hdr.eh))
356 fmt = 1;
357 else {
358 printf("Invalid %s\n", "format");
359 return;
360 }
361 if (fmt == 0) {
362 addr = hdr.ex.a_entry & 0xffffff;
363 p = PTOV(addr);
364 fs_off = PAGE_SIZE;
365 if (xfsread(ino, p, hdr.ex.a_text))
366 return;
367 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
368 if (xfsread(ino, p, hdr.ex.a_data))
369 return;
370 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
371 bootinfo.bi_symtab = VTOP(p);
372 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
373 p += sizeof(hdr.ex.a_syms);
374 if (hdr.ex.a_syms) {
375 if (xfsread(ino, p, hdr.ex.a_syms))
376 return;
377 p += hdr.ex.a_syms;
378 if (xfsread(ino, p, sizeof(int)))
379 return;
380 x = *(uint32_t *)p;
381 p += sizeof(int);
382 x -= sizeof(int);
383 if (xfsread(ino, p, x))
384 return;
385 p += x;
386 }
387 } else {
388 fs_off = hdr.eh.e_phoff;
389 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
390 if (xfsread(ino, ep + j, sizeof(ep[0])))
391 return;
392 if (ep[j].p_type == PT_LOAD)
393 j++;
394 }
395 for (i = 0; i < 2; i++) {
396 p = PTOV(ep[i].p_paddr & 0xffffff);
397 fs_off = ep[i].p_offset;
398 if (xfsread(ino, p, ep[i].p_filesz))
399 return;
400 }
401 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
402 bootinfo.bi_symtab = VTOP(p);
403 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
404 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
405 (hdr.eh.e_shstrndx + 1);
406 if (xfsread(ino, &es, sizeof(es)))
407 return;
408 for (i = 0; i < 2; i++) {
409 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
410 p += sizeof(es[i].sh_size);
411 fs_off = es[i].sh_offset;
412 if (xfsread(ino, p, es[i].sh_size))
413 return;
414 p += es[i].sh_size;
415 }
416 }
417 addr = hdr.eh.e_entry & 0xffffff;
418 }
419 bootinfo.bi_esymtab = VTOP(p);
5ee58eed 420 bootinfo.bi_kernelname = VTOP(kname);
984263bc 421 bootinfo.bi_bios_dev = dsk.drive;
5ee58eed 422 __exec((caddr_t)addr, opts & RBX_MASK,
984263bc
MD
423 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
424 0, 0, 0, VTOP(&bootinfo));
425}
426
427static int
5ee58eed 428parse()
984263bc 429{
5ee58eed 430 char *arg = cmd;
984263bc 431 char *p, *q;
5ee58eed
MD
432 unsigned int drv;
433 int c, i;
984263bc
MD
434
435 while ((c = *arg++)) {
436 if (c == ' ' || c == '\t' || c == '\n')
437 continue;
badbfe61
MD
438 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
439 ;
984263bc
MD
440 if (*p)
441 *p++ = 0;
442 if (c == '-') {
443 while ((c = *arg++)) {
badbfe61
MD
444 for (i = NOPT - 1; i >= 0; --i) {
445 if (optstr[i] == c) {
446 opts ^= 1 << flags[i];
447 goto ok;
448 }
449 }
450 return(-1);
451 ok: ; /* ugly but save space */
984263bc 452 }
badbfe61 453 if (opts & (1 << RBX_PROBEKBD)) {
984263bc 454 i = *(uint8_t *)PTOV(0x496) & 0x10;
2d7f6790
MD
455 if (!i) {
456 printf("NO KB\n");
badbfe61 457 opts |= RBF_VIDEO | RBF_SERIAL;
2d7f6790 458 }
984263bc
MD
459 opts &= ~(1 << RBX_PROBEKBD);
460 }
984263bc
MD
461 } else {
462 for (q = arg--; *q && *q != '('; q++);
463 if (*q) {
464 drv = -1;
465 if (arg[1] == ':') {
984263bc 466 drv = *arg - '0';
5ee58eed
MD
467 if (drv > 9)
468 return (-1);
984263bc
MD
469 arg += 2;
470 }
471 if (q - arg != 2)
472 return -1;
473 for (i = 0; arg[0] != dev_nm[i][0] ||
474 arg[1] != dev_nm[i][1]; i++)
475 if (i == NDEV - 1)
476 return -1;
477 dsk.type = i;
478 arg += 3;
984263bc 479 dsk.unit = *arg - '0';
5ee58eed
MD
480 if (arg[1] != ',' || dsk.unit > 9)
481 return -1;
984263bc
MD
482 arg += 2;
483 dsk.slice = WHOLE_DISK_SLICE;
484 if (arg[1] == ',') {
5ee58eed
MD
485 dsk.slice = *arg - '0' + 1;
486 if (dsk.slice > NDOSPART)
984263bc 487 return -1;
984263bc
MD
488 arg += 2;
489 }
5ee58eed 490 if (arg[1] != ')')
984263bc
MD
491 return -1;
492 dsk.part = *arg - 'a';
5ee58eed
MD
493 if (dsk.part > 7)
494 return (-1);
984263bc
MD
495 arg += 2;
496 if (drv == -1)
497 drv = dsk.unit;
5ee58eed
MD
498 dsk.drive = (dsk.type <= TYPE_MAXHARD
499 ? DRV_HARD : 0) + drv;
500 dsk_meta = 0;
984263bc
MD
501 }
502 if ((i = p - arg - !*(p - 1))) {
5ee58eed 503 if ((size_t)i >= sizeof(kname))
984263bc
MD
504 return -1;
505 memcpy(kname, arg, i + 1);
506 }
507 }
508 arg = p;
509 }
510 return 0;
511}
512
984263bc
MD
513static int
514dskread(void *buf, unsigned lba, unsigned nblk)
515{
984263bc
MD
516 struct dos_partition *dp;
517 struct disklabel *d;
5ee58eed 518 char *sec;
984263bc
MD
519 unsigned sl, i;
520
5ee58eed
MD
521 if (!dsk_meta) {
522 sec = dmadat->secbuf;
984263bc
MD
523 dsk.start = 0;
524 if (drvread(sec, DOSBBSECTOR, 1))
525 return -1;
526 dp = (void *)(sec + DOSPARTOFF);
527 sl = dsk.slice;
528 if (sl < BASE_SLICE) {
529 for (i = 0; i < NDOSPART; i++)
530 if (dp[i].dp_typ == DOSPTYP_386BSD &&
531 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
532 sl = BASE_SLICE + i;
533 if (dp[i].dp_flag & 0x80 ||
534 dsk.slice == COMPATIBILITY_SLICE)
535 break;
536 }
537 if (dsk.slice == WHOLE_DISK_SLICE)
538 dsk.slice = sl;
539 }
540 if (sl != WHOLE_DISK_SLICE) {
541 if (sl != COMPATIBILITY_SLICE)
542 dp += sl - BASE_SLICE;
543 if (dp->dp_typ != DOSPTYP_386BSD) {
544 printf("Invalid %s\n", "slice");
545 return -1;
546 }
547 dsk.start = dp->dp_start;
548 }
549 if (drvread(sec, dsk.start + LABELSECTOR, 1))
550 return -1;
551 d = (void *)(sec + LABELOFFSET);
552 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
553 if (dsk.part != RAW_PART) {
554 printf("Invalid %s\n", "label");
555 return -1;
556 }
557 } else {
558 if (!dsk.init) {
559 if (d->d_type == DTYPE_SCSI)
560 dsk.type = TYPE_DA;
561 dsk.init++;
562 }
563 if (dsk.part >= d->d_npartitions ||
564 !d->d_partitions[dsk.part].p_size) {
565 printf("Invalid %s\n", "partition");
566 return -1;
567 }
5ee58eed
MD
568 dsk.start += d->d_partitions[dsk.part].p_offset;
569 dsk.start -= d->d_partitions[RAW_PART].p_offset;
984263bc
MD
570 }
571 }
572 return drvread(buf, dsk.start + lba, nblk);
573}
574
5ee58eed 575static void
984263bc
MD
576printf(const char *fmt,...)
577{
5ee58eed 578 va_list ap;
984263bc
MD
579 char buf[10];
580 char *s;
5ee58eed 581 unsigned u;
984263bc
MD
582 int c;
583
5ee58eed 584 va_start(ap, fmt);
984263bc
MD
585 while ((c = *fmt++)) {
586 if (c == '%') {
587 c = *fmt++;
588 switch (c) {
589 case 'c':
5ee58eed 590 putchar(va_arg(ap, int));
984263bc
MD
591 continue;
592 case 's':
5ee58eed 593 for (s = va_arg(ap, char *); *s; s++)
984263bc
MD
594 putchar(*s);
595 continue;
596 case 'u':
5ee58eed 597 u = va_arg(ap, unsigned);
984263bc
MD
598 s = buf;
599 do
5ee58eed
MD
600 *s++ = '0' + u % 10U;
601 while (u /= 10U);
984263bc
MD
602 while (--s >= buf)
603 putchar(*s);
604 continue;
605 }
606 }
607 putchar(c);
608 }
5ee58eed
MD
609 va_end(ap);
610 return;
984263bc
MD
611}
612
5ee58eed 613static void
984263bc
MD
614putchar(int c)
615{
616 if (c == '\n')
617 xputc('\r');
5ee58eed 618 xputc(c);
984263bc
MD
619}
620
621static int
622drvread(void *buf, unsigned lba, unsigned nblk)
623{
50a1695f 624 static unsigned c = 0x2d5c7c2f; /* twiddle */
984263bc 625
50a1695f
MD
626 c = (c << 8) | (c >> 24);
627 xputc(c);
628 xputc('\b');
984263bc
MD
629 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
630 v86.addr = XREADORG; /* call to xread in boot1 */
631 v86.es = VTOPSEG(buf);
632 v86.eax = lba;
633 v86.ebx = VTOPOFF(buf);
634 v86.ecx = lba >> 16;
635 v86.edx = nblk << 8 | dsk.drive;
636 v86int();
637 v86.ctl = V86_FLAGS;
638 if (V86_CY(v86.efl)) {
5ee58eed 639 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
984263bc
MD
640 return -1;
641 }
642 return 0;
643}
644
645static int
646keyhit(unsigned ticks)
647{
648 uint32_t t0, t1;
649
650 if (opts & 1 << RBX_NOINTR)
651 return 0;
652 t0 = 0;
653 for (;;) {
654 if (xgetc(1))
655 return 1;
656 t1 = *(uint32_t *)PTOV(0x46c);
657 if (!t0)
658 t0 = t1;
659 if (t1 < t0 || t1 >= t0 + ticks)
660 return 0;
661 }
662}
663
50a1695f 664static void
984263bc
MD
665xputc(int c)
666{
badbfe61 667 if (opts & RBF_VIDEO)
984263bc 668 putc(c);
badbfe61 669 if (opts & RBF_SERIAL)
984263bc 670 sio_putc(c);
984263bc
MD
671}
672
673static int
674xgetc(int fn)
675{
676 if (opts & 1 << RBX_NOINTR)
677 return 0;
678 for (;;) {
badbfe61 679 if ((opts & RBF_VIDEO) && getc(1))
984263bc 680 return fn ? 1 : getc(0);
badbfe61 681 if ((opts & RBF_SERIAL) && sio_ischar())
984263bc
MD
682 return fn ? 1 : sio_getc();
683 if (fn)
684 return 0;
685 }
686}
687
688static int
689getc(int fn)
690{
691 v86.addr = 0x16;
692 v86.eax = fn << 8;
693 v86int();
694 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
695}