Rewrite the polling code. Instead of trying to do fancy polling enablement
[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 $
4e06dda7 48 * $DragonFly: src/sys/boot/pc32/boot2/boot2.c,v 1.13 2004/07/27 19:37:17 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
4e06dda7
MD
113#define INVALID_S "Bad %s\n"
114
984263bc
MD
115extern uint32_t _end;
116
badbfe61 117static const char optstr[NOPT] = { "VhaCgmnPprsv" };
984263bc 118static const unsigned char flags[NOPT] = {
badbfe61 119 RBX_VIDEO,
984263bc
MD
120 RBX_SERIAL,
121 RBX_ASKNAME,
122 RBX_CDROM,
984263bc 123 RBX_GDB,
5ee58eed 124 RBX_MUTE,
984263bc
MD
125 RBX_NOINTR,
126 RBX_PROBEKBD,
5ee58eed 127 RBX_PAUSE,
984263bc
MD
128 RBX_DFLTROOT,
129 RBX_SINGLE,
130 RBX_VERBOSE
131};
132
5ee58eed
MD
133static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
134static const unsigned char dev_maj[NDEV] = {30, 4, 2};
984263bc
MD
135
136static struct dsk {
137 unsigned drive;
138 unsigned type;
139 unsigned unit;
140 unsigned slice;
141 unsigned part;
142 unsigned start;
143 int init;
984263bc
MD
144} dsk;
145static char cmd[512];
146static char kname[1024];
147static uint32_t opts;
148static struct bootinfo bootinfo;
984263bc
MD
149
150void exit(int);
5ee58eed
MD
151static void load(void);
152static int parse(void);
984263bc 153static int xfsread(ino_t, void *, size_t);
984263bc 154static int dskread(void *, unsigned, unsigned);
5ee58eed
MD
155static void printf(const char *,...);
156static void putchar(int);
157static uint32_t memsize(void);
984263bc
MD
158static int drvread(void *, unsigned, unsigned);
159static int keyhit(unsigned);
50a1695f 160static void xputc(int);
984263bc
MD
161static int xgetc(int);
162static int getc(int);
163
5ee58eed
MD
164static void
165memcpy(void *d, const void *s, int len)
984263bc 166{
5ee58eed
MD
167 char *dd = d;
168 const char *ss = s;
984263bc 169
5ee58eed
MD
170#if 0
171 if (dd < ss) {
172 while (--len >= 0)
173 *dd++ = *ss++;
174 } else {
175#endif
176 while (--len >= 0)
177 dd[len] = ss[len];
178#if 0
179 }
180#endif
984263bc
MD
181}
182
183static inline int
184strcmp(const char *s1, const char *s2)
185{
186 for (; *s1 == *s2 && *s1; s1++, s2++);
5ee58eed 187 return (unsigned char)*s1 - (unsigned char)*s2;
984263bc
MD
188}
189
5ee58eed
MD
190#include "ufsread.c"
191
192static int
193xfsread(ino_t inode, void *buf, size_t nbyte)
984263bc 194{
5ee58eed 195 if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
4e06dda7 196 printf(INVALID_S, "format");
5ee58eed
MD
197 return -1;
198 }
984263bc
MD
199 return 0;
200}
201
5ee58eed
MD
202static inline uint32_t
203memsize(void)
984263bc 204{
5ee58eed
MD
205 v86.addr = MEM_EXT;
206 v86.eax = 0x8800;
207 v86int();
208 return v86.eax;
984263bc
MD
209}
210
211static inline void
5ee58eed 212getstr(void)
984263bc
MD
213{
214 char *s;
215 int c;
216
5ee58eed
MD
217 s = cmd;
218 for (;;) {
219 switch (c = xgetc(0)) {
984263bc
MD
220 case 0:
221 break;
984263bc 222 case '\177':
5ee58eed
MD
223 case '\b':
224 if (s > cmd) {
984263bc 225 s--;
5ee58eed
MD
226 printf("\b \b");
227 }
984263bc
MD
228 break;
229 case '\n':
5ee58eed 230 case '\r':
984263bc 231 *s = 0;
5ee58eed 232 return;
984263bc 233 default:
5ee58eed 234 if (s - cmd < sizeof(cmd) - 1)
984263bc 235 *s++ = c;
984263bc 236 putchar(c);
5ee58eed
MD
237 }
238 }
984263bc
MD
239}
240
241static inline void
242putc(int c)
243{
244 v86.addr = 0x10;
245 v86.eax = 0xe00 | (c & 0xff);
246 v86.ebx = 0x7;
247 v86int();
248}
249
250int
251main(void)
252{
5ee58eed
MD
253 int autoboot;
254 ino_t ino;
984263bc 255
5ee58eed 256 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
984263bc 257 v86.ctl = V86_FLAGS;
cacaceec 258 dsk.drive = *(uint8_t *)PTOV(MEM_BTX_USR_ARG);
984263bc
MD
259 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
260 dsk.unit = dsk.drive & DRV_MASK;
cacaceec 261 dsk.slice = *(uint8_t *)PTOV(MEM_BTX_USR_ARG + 1) + 1;
984263bc
MD
262 bootinfo.bi_version = BOOTINFO_VERSION;
263 bootinfo.bi_size = sizeof(bootinfo);
264 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
5ee58eed 265 bootinfo.bi_extmem = memsize();
984263bc 266 bootinfo.bi_memsizes_valid++;
5ee58eed
MD
267
268 /* Process configuration file */
269
270 autoboot = 1;
271
272 if ((ino = lookup(PATH_CONFIG)))
273 fsread(ino, cmd, sizeof(cmd));
274
badbfe61 275 if (cmd[0]) {
984263bc 276 printf("%s: %s", PATH_CONFIG, cmd);
5ee58eed 277 if (parse())
984263bc 278 autoboot = 0;
5ee58eed 279 /* Do not process this command twice */
984263bc
MD
280 *cmd = 0;
281 }
5ee58eed 282
badbfe61 283 /*
38e10dff
MD
284 * Setup our (serial) console after processing the config file. If
285 * the initialization fails, don't try to use the serial port. This
286 * can happen if the serial port is unmaped (happens on new laptops a lot).
badbfe61 287 */
38e10dff 288 if ((opts & (RBF_MUTE|RBF_SERIAL|RBF_VIDEO)) == 0)
badbfe61 289 opts |= RBF_SERIAL|RBF_VIDEO;
38e10dff
MD
290 if (opts & RBF_SERIAL) {
291 if (sio_init())
292 opts = RBF_VIDEO;
293 }
badbfe61
MD
294
295
5ee58eed
MD
296 /*
297 * Try to exec stage 3 boot loader. If interrupted by a keypress,
298 * or in case of failure, try to load a kernel directly instead.
299 */
300
984263bc 301 if (autoboot && !*kname) {
5ee58eed
MD
302 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
303 if (!keyhit(3*SECOND)) {
304 load();
984263bc 305 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
5ee58eed 306 }
984263bc 307 }
5ee58eed
MD
308
309 /* Present the user with the boot2 prompt. */
310
984263bc 311 for (;;) {
38e10dff
MD
312 printf("\nDragonFly boot\n"
313 "%u:%s(%u,%c)%s: ",
984263bc
MD
314 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
315 'a' + dsk.part, kname);
5ee58eed
MD
316 if (!autoboot || keyhit(5*SECOND))
317 getstr();
984263bc
MD
318 else
319 putchar('\n');
320 autoboot = 0;
badbfe61 321 if (cmd[0] == 0 || parse())
5ee58eed 322 putchar('\a');
984263bc 323 else
5ee58eed 324 load();
984263bc
MD
325 }
326}
327
328/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
329void
330exit(int x)
331{
332}
333
334static void
5ee58eed 335load(void)
984263bc
MD
336{
337 union {
338 struct exec ex;
339 Elf32_Ehdr eh;
340 } hdr;
341 Elf32_Phdr ep[2];
342 Elf32_Shdr es[2];
343 caddr_t p;
344 ino_t ino;
345 uint32_t addr, x;
346 int fmt, i, j;
347
5ee58eed 348 if (!(ino = lookup(kname))) {
984263bc 349 if (!ls)
5ee58eed 350 printf("No %s\n", kname);
984263bc
MD
351 return;
352 }
353 if (xfsread(ino, &hdr, sizeof(hdr)))
354 return;
355 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
356 fmt = 0;
357 else if (IS_ELF(hdr.eh))
358 fmt = 1;
359 else {
4e06dda7 360 printf(INVALID_S, "format");
984263bc
MD
361 return;
362 }
363 if (fmt == 0) {
364 addr = hdr.ex.a_entry & 0xffffff;
365 p = PTOV(addr);
366 fs_off = PAGE_SIZE;
367 if (xfsread(ino, p, hdr.ex.a_text))
368 return;
369 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
370 if (xfsread(ino, p, hdr.ex.a_data))
371 return;
372 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
373 bootinfo.bi_symtab = VTOP(p);
374 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
375 p += sizeof(hdr.ex.a_syms);
376 if (hdr.ex.a_syms) {
377 if (xfsread(ino, p, hdr.ex.a_syms))
378 return;
379 p += hdr.ex.a_syms;
380 if (xfsread(ino, p, sizeof(int)))
381 return;
382 x = *(uint32_t *)p;
383 p += sizeof(int);
384 x -= sizeof(int);
385 if (xfsread(ino, p, x))
386 return;
387 p += x;
388 }
389 } else {
390 fs_off = hdr.eh.e_phoff;
391 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
392 if (xfsread(ino, ep + j, sizeof(ep[0])))
393 return;
394 if (ep[j].p_type == PT_LOAD)
395 j++;
396 }
397 for (i = 0; i < 2; i++) {
398 p = PTOV(ep[i].p_paddr & 0xffffff);
399 fs_off = ep[i].p_offset;
400 if (xfsread(ino, p, ep[i].p_filesz))
401 return;
402 }
403 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
404 bootinfo.bi_symtab = VTOP(p);
405 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
406 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
407 (hdr.eh.e_shstrndx + 1);
408 if (xfsread(ino, &es, sizeof(es)))
409 return;
410 for (i = 0; i < 2; i++) {
411 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
412 p += sizeof(es[i].sh_size);
413 fs_off = es[i].sh_offset;
414 if (xfsread(ino, p, es[i].sh_size))
415 return;
416 p += es[i].sh_size;
417 }
418 }
419 addr = hdr.eh.e_entry & 0xffffff;
420 }
421 bootinfo.bi_esymtab = VTOP(p);
5ee58eed 422 bootinfo.bi_kernelname = VTOP(kname);
984263bc 423 bootinfo.bi_bios_dev = dsk.drive;
5ee58eed 424 __exec((caddr_t)addr, opts & RBX_MASK,
984263bc
MD
425 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
426 0, 0, 0, VTOP(&bootinfo));
427}
428
429static int
5ee58eed 430parse()
984263bc 431{
5ee58eed 432 char *arg = cmd;
984263bc 433 char *p, *q;
5ee58eed
MD
434 unsigned int drv;
435 int c, i;
984263bc
MD
436
437 while ((c = *arg++)) {
438 if (c == ' ' || c == '\t' || c == '\n')
439 continue;
badbfe61
MD
440 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
441 ;
984263bc
MD
442 if (*p)
443 *p++ = 0;
444 if (c == '-') {
445 while ((c = *arg++)) {
badbfe61
MD
446 for (i = NOPT - 1; i >= 0; --i) {
447 if (optstr[i] == c) {
448 opts ^= 1 << flags[i];
449 goto ok;
450 }
451 }
452 return(-1);
453 ok: ; /* ugly but save space */
984263bc 454 }
badbfe61 455 if (opts & (1 << RBX_PROBEKBD)) {
984263bc 456 i = *(uint8_t *)PTOV(0x496) & 0x10;
2d7f6790
MD
457 if (!i) {
458 printf("NO KB\n");
badbfe61 459 opts |= RBF_VIDEO | RBF_SERIAL;
2d7f6790 460 }
984263bc
MD
461 opts &= ~(1 << RBX_PROBEKBD);
462 }
984263bc
MD
463 } else {
464 for (q = arg--; *q && *q != '('; q++);
465 if (*q) {
466 drv = -1;
467 if (arg[1] == ':') {
984263bc 468 drv = *arg - '0';
5ee58eed
MD
469 if (drv > 9)
470 return (-1);
984263bc
MD
471 arg += 2;
472 }
473 if (q - arg != 2)
474 return -1;
475 for (i = 0; arg[0] != dev_nm[i][0] ||
476 arg[1] != dev_nm[i][1]; i++)
477 if (i == NDEV - 1)
478 return -1;
479 dsk.type = i;
480 arg += 3;
984263bc 481 dsk.unit = *arg - '0';
5ee58eed
MD
482 if (arg[1] != ',' || dsk.unit > 9)
483 return -1;
984263bc
MD
484 arg += 2;
485 dsk.slice = WHOLE_DISK_SLICE;
486 if (arg[1] == ',') {
5ee58eed
MD
487 dsk.slice = *arg - '0' + 1;
488 if (dsk.slice > NDOSPART)
984263bc 489 return -1;
984263bc
MD
490 arg += 2;
491 }
5ee58eed 492 if (arg[1] != ')')
984263bc
MD
493 return -1;
494 dsk.part = *arg - 'a';
5ee58eed
MD
495 if (dsk.part > 7)
496 return (-1);
984263bc
MD
497 arg += 2;
498 if (drv == -1)
499 drv = dsk.unit;
5ee58eed
MD
500 dsk.drive = (dsk.type <= TYPE_MAXHARD
501 ? DRV_HARD : 0) + drv;
502 dsk_meta = 0;
984263bc
MD
503 }
504 if ((i = p - arg - !*(p - 1))) {
5ee58eed 505 if ((size_t)i >= sizeof(kname))
984263bc
MD
506 return -1;
507 memcpy(kname, arg, i + 1);
508 }
509 }
510 arg = p;
511 }
512 return 0;
513}
514
984263bc
MD
515static int
516dskread(void *buf, unsigned lba, unsigned nblk)
517{
984263bc
MD
518 struct dos_partition *dp;
519 struct disklabel *d;
5ee58eed 520 char *sec;
984263bc
MD
521 unsigned sl, i;
522
5ee58eed
MD
523 if (!dsk_meta) {
524 sec = dmadat->secbuf;
984263bc
MD
525 dsk.start = 0;
526 if (drvread(sec, DOSBBSECTOR, 1))
527 return -1;
528 dp = (void *)(sec + DOSPARTOFF);
529 sl = dsk.slice;
530 if (sl < BASE_SLICE) {
531 for (i = 0; i < NDOSPART; i++)
532 if (dp[i].dp_typ == DOSPTYP_386BSD &&
533 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
534 sl = BASE_SLICE + i;
535 if (dp[i].dp_flag & 0x80 ||
536 dsk.slice == COMPATIBILITY_SLICE)
537 break;
538 }
539 if (dsk.slice == WHOLE_DISK_SLICE)
540 dsk.slice = sl;
541 }
542 if (sl != WHOLE_DISK_SLICE) {
543 if (sl != COMPATIBILITY_SLICE)
544 dp += sl - BASE_SLICE;
545 if (dp->dp_typ != DOSPTYP_386BSD) {
4e06dda7 546 printf(INVALID_S, "slice");
984263bc
MD
547 return -1;
548 }
549 dsk.start = dp->dp_start;
550 }
551 if (drvread(sec, dsk.start + LABELSECTOR, 1))
552 return -1;
553 d = (void *)(sec + LABELOFFSET);
554 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
555 if (dsk.part != RAW_PART) {
4e06dda7 556 printf(INVALID_S, "label");
984263bc
MD
557 return -1;
558 }
559 } else {
560 if (!dsk.init) {
561 if (d->d_type == DTYPE_SCSI)
562 dsk.type = TYPE_DA;
563 dsk.init++;
564 }
565 if (dsk.part >= d->d_npartitions ||
566 !d->d_partitions[dsk.part].p_size) {
4e06dda7 567 printf(INVALID_S, "partition");
984263bc
MD
568 return -1;
569 }
5ee58eed
MD
570 dsk.start += d->d_partitions[dsk.part].p_offset;
571 dsk.start -= d->d_partitions[RAW_PART].p_offset;
984263bc
MD
572 }
573 }
574 return drvread(buf, dsk.start + lba, nblk);
575}
576
5ee58eed 577static void
984263bc
MD
578printf(const char *fmt,...)
579{
5ee58eed 580 va_list ap;
984263bc
MD
581 char buf[10];
582 char *s;
5ee58eed 583 unsigned u;
984263bc
MD
584 int c;
585
5ee58eed 586 va_start(ap, fmt);
984263bc
MD
587 while ((c = *fmt++)) {
588 if (c == '%') {
589 c = *fmt++;
590 switch (c) {
591 case 'c':
5ee58eed 592 putchar(va_arg(ap, int));
984263bc
MD
593 continue;
594 case 's':
5ee58eed 595 for (s = va_arg(ap, char *); *s; s++)
984263bc
MD
596 putchar(*s);
597 continue;
598 case 'u':
5ee58eed 599 u = va_arg(ap, unsigned);
984263bc
MD
600 s = buf;
601 do
5ee58eed
MD
602 *s++ = '0' + u % 10U;
603 while (u /= 10U);
984263bc
MD
604 while (--s >= buf)
605 putchar(*s);
606 continue;
607 }
608 }
609 putchar(c);
610 }
5ee58eed
MD
611 va_end(ap);
612 return;
984263bc
MD
613}
614
5ee58eed 615static void
984263bc
MD
616putchar(int c)
617{
618 if (c == '\n')
619 xputc('\r');
5ee58eed 620 xputc(c);
984263bc
MD
621}
622
623static int
624drvread(void *buf, unsigned lba, unsigned nblk)
625{
50a1695f 626 static unsigned c = 0x2d5c7c2f; /* twiddle */
984263bc 627
50a1695f
MD
628 c = (c << 8) | (c >> 24);
629 xputc(c);
630 xputc('\b');
984263bc
MD
631 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
632 v86.addr = XREADORG; /* call to xread in boot1 */
633 v86.es = VTOPSEG(buf);
634 v86.eax = lba;
635 v86.ebx = VTOPOFF(buf);
636 v86.ecx = lba >> 16;
637 v86.edx = nblk << 8 | dsk.drive;
638 v86int();
639 v86.ctl = V86_FLAGS;
640 if (V86_CY(v86.efl)) {
5ee58eed 641 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
984263bc
MD
642 return -1;
643 }
644 return 0;
645}
646
647static int
648keyhit(unsigned ticks)
649{
650 uint32_t t0, t1;
651
652 if (opts & 1 << RBX_NOINTR)
653 return 0;
654 t0 = 0;
655 for (;;) {
656 if (xgetc(1))
657 return 1;
658 t1 = *(uint32_t *)PTOV(0x46c);
659 if (!t0)
660 t0 = t1;
661 if (t1 < t0 || t1 >= t0 + ticks)
662 return 0;
663 }
664}
665
50a1695f 666static void
984263bc
MD
667xputc(int c)
668{
badbfe61 669 if (opts & RBF_VIDEO)
984263bc 670 putc(c);
badbfe61 671 if (opts & RBF_SERIAL)
984263bc 672 sio_putc(c);
984263bc
MD
673}
674
675static int
676xgetc(int fn)
677{
678 if (opts & 1 << RBX_NOINTR)
679 return 0;
680 for (;;) {
badbfe61 681 if ((opts & RBF_VIDEO) && getc(1))
984263bc 682 return fn ? 1 : getc(0);
badbfe61 683 if ((opts & RBF_SERIAL) && sio_ischar())
984263bc
MD
684 return fn ? 1 : sio_getc();
685 if (fn)
686 return 0;
687 }
688}
689
690static int
691getc(int fn)
692{
693 v86.addr = 0x16;
694 v86.eax = fn << 8;
695 v86int();
696 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
697}