mount_udf.8: Correct typo in arguments.
[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 $
984263bc 48 */
7580e818 49
79b4bbd6 50#define AOUT_H_FORCE32
984263bc 51#include <sys/param.h>
6080181b
SS
52#ifdef DISKLABEL64
53#include <sys/disklabel64.h>
54#else
2b961883 55#include <sys/disklabel32.h>
6080181b 56#endif
5ee58eed
MD
57#include <sys/diskslice.h>
58#include <sys/diskmbr.h>
ba0cc1ab 59#include <sys/dtype.h>
984263bc
MD
60#include <sys/dirent.h>
61#include <machine/bootinfo.h>
62#include <machine/elf.h>
32bf391f 63#include <machine/psl.h>
984263bc 64
984263bc
MD
65#include <stdarg.h>
66
67#include <a.out.h>
68
69#include <btxv86.h>
70
6080181b
SS
71#ifdef DISKLABEL64
72#include "boot2_64.h"
73#else
74#include "boot2_32.h"
75#endif
d64b2e33 76#include "boot2.h"
984263bc 77#include "lib.h"
409cbc03 78#include "../bootasm.h"
984263bc 79
5ee58eed
MD
80#define SECOND 18 /* Circa that many ticks in a second. */
81
984263bc
MD
82#define RBX_ASKNAME 0x0 /* -a */
83#define RBX_SINGLE 0x1 /* -s */
84#define RBX_DFLTROOT 0x5 /* -r */
85#define RBX_KDB 0x6 /* -d */
86#define RBX_CONFIG 0xa /* -c */
87#define RBX_VERBOSE 0xb /* -v */
88#define RBX_SERIAL 0xc /* -h */
89#define RBX_CDROM 0xd /* -C */
90#define RBX_GDB 0xf /* -g */
5ee58eed
MD
91#define RBX_MUTE 0x10 /* -m */
92#define RBX_PAUSE 0x12 /* -p */
93#define RBX_NOINTR 0x1c /* -n */
badbfe61 94#define RBX_VIDEO 0x1d /* -V */
984263bc 95#define RBX_PROBEKBD 0x1e /* -P */
5ee58eed 96/* 0x1f is reserved for the historical RB_BOOTINFO option */
984263bc 97
38e10dff 98#define RBF_MUTE (1 << RBX_MUTE)
badbfe61
MD
99#define RBF_SERIAL (1 << RBX_SERIAL)
100#define RBF_VIDEO (1 << RBX_VIDEO)
c9a7ee71
JM
101#define RBF_NOINTR (1 << RBX_NOINTR)
102#define RBF_PROBEKBD (1 << RBX_PROBEKBD)
badbfe61 103
50a1695f 104/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -V */
5ee58eed 105#define RBX_MASK 0x2005ffff
984263bc
MD
106
107#define PATH_CONFIG "/boot.config"
3735e368
MD
108#define PATH_BOOT3 "/loader" /* /boot is dedicated */
109#define PATH_BOOT3_ALT "/boot/loader" /* /boot in root */
984263bc
MD
110#define PATH_KERNEL "/kernel"
111
c9a7ee71 112#define NOPT 12
5ee58eed 113#define NDEV 3
984263bc
MD
114#define MEM_BASE 0x12
115#define MEM_EXT 0x15
32bf391f
MD
116#define V86_CY(x) ((x) & PSL_C)
117#define V86_ZR(x) ((x) & PSL_Z)
984263bc
MD
118
119#define DRV_HARD 0x80
120#define DRV_MASK 0x7f
121
122#define TYPE_AD 0
5ee58eed
MD
123#define TYPE_DA 1
124#define TYPE_MAXHARD TYPE_DA
125#define TYPE_FD 2
984263bc 126
4e06dda7
MD
127#define INVALID_S "Bad %s\n"
128
984263bc
MD
129extern uint32_t _end;
130
badbfe61 131static const char optstr[NOPT] = { "VhaCgmnPprsv" };
984263bc 132static const unsigned char flags[NOPT] = {
badbfe61 133 RBX_VIDEO,
984263bc
MD
134 RBX_SERIAL,
135 RBX_ASKNAME,
136 RBX_CDROM,
984263bc 137 RBX_GDB,
5ee58eed 138 RBX_MUTE,
984263bc
MD
139 RBX_NOINTR,
140 RBX_PROBEKBD,
5ee58eed 141 RBX_PAUSE,
984263bc
MD
142 RBX_DFLTROOT,
143 RBX_SINGLE,
144 RBX_VERBOSE
145};
146
5ee58eed
MD
147static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
148static const unsigned char dev_maj[NDEV] = {30, 4, 2};
984263bc
MD
149
150static struct dsk {
151 unsigned drive;
152 unsigned type;
153 unsigned unit;
c9a7ee71
JM
154 uint8_t slice;
155 uint8_t part;
984263bc
MD
156 unsigned start;
157 int init;
984263bc 158} dsk;
d64b2e33 159
984263bc 160static char cmd[512];
c9a7ee71 161static const char *kname;
d64b2e33 162static uint32_t opts = RBF_VIDEO;
984263bc 163static struct bootinfo bootinfo;
984263bc 164
d64b2e33
MD
165/*
166 * boot2 encapsulated ABI elements provided to *fsread.c
167 *
168 * NOTE: boot2_dmadat is extended by per-filesystem APIs
169 */
170uint32_t fs_off;
cdfd0a3e 171int no_io_error;
d64b2e33
MD
172int ls;
173struct boot2_dmadat *boot2_dmadat;
7580e818 174
984263bc 175void exit(int);
5ee58eed
MD
176static void load(void);
177static int parse(void);
d64b2e33
MD
178static int dskprobe(void);
179static int xfsread(boot2_ino_t, void *, size_t);
984263bc
MD
180static int drvread(void *, unsigned, unsigned);
181static int keyhit(unsigned);
c9a7ee71 182static int xputc(int);
984263bc
MD
183static int xgetc(int);
184static int getc(int);
185
d64b2e33 186void
5ee58eed 187memcpy(void *d, const void *s, int len)
984263bc 188{
5ee58eed
MD
189 char *dd = d;
190 const char *ss = s;
984263bc 191
5ee58eed
MD
192 while (--len >= 0)
193 dd[len] = ss[len];
984263bc
MD
194}
195
d64b2e33 196int
984263bc
MD
197strcmp(const char *s1, const char *s2)
198{
d64b2e33
MD
199 for (; *s1 == *s2 && *s1; s1++, s2++)
200 ;
201 return ((int)((unsigned char)*s1 - (unsigned char)*s2));
984263bc
MD
202}
203
cdfd0a3e 204#if defined(UFS) && defined(HAMMER2FS)
d64b2e33
MD
205
206const struct boot2_fsapi *fsapi;
207
208#elif defined(UFS)
209
210#define fsapi (&boot2_ufs_api)
211
cdfd0a3e 212#elif defined(HAMMER2FS)
d64b2e33 213
cdfd0a3e 214#define fsapi (&boot2_hammer2_api)
d64b2e33 215
7580e818 216#endif
5ee58eed
MD
217
218static int
d64b2e33 219xfsread(boot2_ino_t inode, void *buf, size_t nbyte)
984263bc 220{
d64b2e33 221 if ((size_t)fsapi->fsread(inode, buf, nbyte) != nbyte) {
4e06dda7 222 printf(INVALID_S, "format");
5ee58eed
MD
223 return -1;
224 }
984263bc
MD
225 return 0;
226}
227
984263bc 228static inline void
5ee58eed 229getstr(void)
984263bc
MD
230{
231 char *s;
232 int c;
233
5ee58eed
MD
234 s = cmd;
235 for (;;) {
236 switch (c = xgetc(0)) {
984263bc
MD
237 case 0:
238 break;
984263bc 239 case '\177':
5ee58eed
MD
240 case '\b':
241 if (s > cmd) {
984263bc 242 s--;
5ee58eed
MD
243 printf("\b \b");
244 }
984263bc
MD
245 break;
246 case '\n':
5ee58eed 247 case '\r':
984263bc 248 *s = 0;
5ee58eed 249 return;
984263bc 250 default:
5ee58eed 251 if (s - cmd < sizeof(cmd) - 1)
984263bc 252 *s++ = c;
984263bc 253 putchar(c);
5ee58eed
MD
254 }
255 }
984263bc
MD
256}
257
258static inline void
259putc(int c)
260{
261 v86.addr = 0x10;
262 v86.eax = 0xe00 | (c & 0xff);
263 v86.ebx = 0x7;
264 v86int();
265}
266
267int
268main(void)
269{
c9a7ee71 270 uint8_t autoboot;
d64b2e33 271 boot2_ino_t ino;
984263bc 272
c9a7ee71 273 kname = NULL;
d64b2e33
MD
274 boot2_dmadat =
275 (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
984263bc 276 v86.ctl = V86_FLAGS;
32bf391f 277 v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
cacaceec 278 dsk.drive = *(uint8_t *)PTOV(MEM_BTX_USR_ARG);
984263bc
MD
279 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
280 dsk.unit = dsk.drive & DRV_MASK;
cacaceec 281 dsk.slice = *(uint8_t *)PTOV(MEM_BTX_USR_ARG + 1) + 1;
984263bc
MD
282 bootinfo.bi_version = BOOTINFO_VERSION;
283 bootinfo.bi_size = sizeof(bootinfo);
5ee58eed 284
5ee58eed
MD
285 autoboot = 1;
286
d64b2e33
MD
287 /*
288 * Probe the default disk and process the configuration file if
289 * successful.
290 */
291 if (dskprobe() == 0) {
292 if ((ino = fsapi->fslookup(PATH_CONFIG)))
293 fsapi->fsread(ino, cmd, sizeof(cmd));
294 }
5ee58eed 295
d64b2e33
MD
296 /*
297 * Parse config file if present. parse() will re-probe if necessary.
298 */
badbfe61 299 if (cmd[0]) {
984263bc 300 printf("%s: %s", PATH_CONFIG, cmd);
5ee58eed 301 if (parse())
984263bc 302 autoboot = 0;
5ee58eed 303 /* Do not process this command twice */
984263bc
MD
304 *cmd = 0;
305 }
5ee58eed 306
badbfe61 307 /*
38e10dff
MD
308 * Setup our (serial) console after processing the config file. If
309 * the initialization fails, don't try to use the serial port. This
310 * can happen if the serial port is unmaped (happens on new laptops a lot).
badbfe61 311 */
38e10dff 312 if ((opts & (RBF_MUTE|RBF_SERIAL|RBF_VIDEO)) == 0)
badbfe61 313 opts |= RBF_SERIAL|RBF_VIDEO;
38e10dff
MD
314 if (opts & RBF_SERIAL) {
315 if (sio_init())
316 opts = RBF_VIDEO;
317 }
badbfe61
MD
318
319
5ee58eed
MD
320 /*
321 * Try to exec stage 3 boot loader. If interrupted by a keypress,
322 * or in case of failure, try to load a kernel directly instead.
79dc5fc6
MD
323 *
324 * We have to try boot /boot/loader and /loader to support booting
325 * from a /boot partition instead of a root partition.
5ee58eed 326 */
c9a7ee71
JM
327 if (autoboot && !kname) {
328 kname = PATH_BOOT3;
5ee58eed 329 if (!keyhit(3*SECOND)) {
79dc5fc6 330 load();
c9a7ee71 331 kname = PATH_BOOT3_ALT;
5ee58eed 332 load();
c9a7ee71 333 kname = PATH_KERNEL;
5ee58eed 334 }
984263bc 335 }
5ee58eed
MD
336
337 /* Present the user with the boot2 prompt. */
338
984263bc 339 for (;;) {
38e10dff
MD
340 printf("\nDragonFly boot\n"
341 "%u:%s(%u,%c)%s: ",
984263bc
MD
342 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
343 'a' + dsk.part, kname);
5ee58eed
MD
344 if (!autoboot || keyhit(5*SECOND))
345 getstr();
984263bc
MD
346 else
347 putchar('\n');
348 autoboot = 0;
d561b492 349 if (parse())
5ee58eed 350 putchar('\a');
984263bc 351 else
5ee58eed 352 load();
984263bc
MD
353 }
354}
355
356/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
357void
358exit(int x)
359{
360}
361
362static void
5ee58eed 363load(void)
984263bc
MD
364{
365 union {
366 struct exec ex;
367 Elf32_Ehdr eh;
368 } hdr;
c9a7ee71
JM
369 static Elf32_Phdr ep[2];
370 static Elf32_Shdr es[2];
984263bc 371 caddr_t p;
d64b2e33 372 boot2_ino_t ino;
c9a7ee71
JM
373 uint32_t addr;
374 int i, j;
984263bc 375
d64b2e33 376 if (!(ino = fsapi->fslookup(kname))) {
984263bc 377 if (!ls)
5ee58eed 378 printf("No %s\n", kname);
984263bc
MD
379 return;
380 }
381 if (xfsread(ino, &hdr, sizeof(hdr)))
382 return;
c9a7ee71
JM
383
384 if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
984263bc
MD
385 addr = hdr.ex.a_entry & 0xffffff;
386 p = PTOV(addr);
387 fs_off = PAGE_SIZE;
388 if (xfsread(ino, p, hdr.ex.a_text))
389 return;
390 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
391 if (xfsread(ino, p, hdr.ex.a_data))
392 return;
c9a7ee71 393 } else if (IS_ELF(hdr.eh)) {
984263bc
MD
394 fs_off = hdr.eh.e_phoff;
395 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
396 if (xfsread(ino, ep + j, sizeof(ep[0])))
397 return;
398 if (ep[j].p_type == PT_LOAD)
399 j++;
400 }
401 for (i = 0; i < 2; i++) {
402 p = PTOV(ep[i].p_paddr & 0xffffff);
403 fs_off = ep[i].p_offset;
404 if (xfsread(ino, p, ep[i].p_filesz))
405 return;
406 }
407 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
408 bootinfo.bi_symtab = VTOP(p);
409 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
410 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
411 (hdr.eh.e_shstrndx + 1);
412 if (xfsread(ino, &es, sizeof(es)))
413 return;
414 for (i = 0; i < 2; i++) {
c9a7ee71 415 *(Elf32_Word *)p = es[i].sh_size;
984263bc
MD
416 p += sizeof(es[i].sh_size);
417 fs_off = es[i].sh_offset;
418 if (xfsread(ino, p, es[i].sh_size))
419 return;
420 p += es[i].sh_size;
421 }
422 }
423 addr = hdr.eh.e_entry & 0xffffff;
c9a7ee71
JM
424 bootinfo.bi_esymtab = VTOP(p);
425 } else {
426 printf(INVALID_S, "format");
427 return;
984263bc 428 }
c9a7ee71 429
5ee58eed 430 bootinfo.bi_kernelname = VTOP(kname);
984263bc 431 bootinfo.bi_bios_dev = dsk.drive;
5ee58eed 432 __exec((caddr_t)addr, opts & RBX_MASK,
a05cac60 433 MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),
984263bc
MD
434 0, 0, 0, VTOP(&bootinfo));
435}
436
437static int
d64b2e33 438parse(void)
984263bc 439{
5ee58eed 440 char *arg = cmd;
984263bc 441 char *p, *q;
5ee58eed
MD
442 unsigned int drv;
443 int c, i;
984263bc
MD
444
445 while ((c = *arg++)) {
446 if (c == ' ' || c == '\t' || c == '\n')
447 continue;
badbfe61
MD
448 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
449 ;
984263bc
MD
450 if (*p)
451 *p++ = 0;
452 if (c == '-') {
453 while ((c = *arg++)) {
badbfe61
MD
454 for (i = NOPT - 1; i >= 0; --i) {
455 if (optstr[i] == c) {
456 opts ^= 1 << flags[i];
457 goto ok;
458 }
459 }
460 return(-1);
461 ok: ; /* ugly but save space */
984263bc 462 }
c9a7ee71 463 if (opts & RBF_PROBEKBD) {
984263bc 464 i = *(uint8_t *)PTOV(0x496) & 0x10;
2d7f6790
MD
465 if (!i) {
466 printf("NO KB\n");
badbfe61 467 opts |= RBF_VIDEO | RBF_SERIAL;
2d7f6790 468 }
c9a7ee71 469 opts &= ~RBF_PROBEKBD;
984263bc 470 }
984263bc
MD
471 } else {
472 for (q = arg--; *q && *q != '('; q++);
473 if (*q) {
474 drv = -1;
475 if (arg[1] == ':') {
984263bc 476 drv = *arg - '0';
5ee58eed
MD
477 if (drv > 9)
478 return (-1);
984263bc
MD
479 arg += 2;
480 }
481 if (q - arg != 2)
482 return -1;
483 for (i = 0; arg[0] != dev_nm[i][0] ||
484 arg[1] != dev_nm[i][1]; i++)
485 if (i == NDEV - 1)
486 return -1;
487 dsk.type = i;
488 arg += 3;
984263bc 489 dsk.unit = *arg - '0';
5ee58eed
MD
490 if (arg[1] != ',' || dsk.unit > 9)
491 return -1;
984263bc
MD
492 arg += 2;
493 dsk.slice = WHOLE_DISK_SLICE;
494 if (arg[1] == ',') {
5ee58eed 495 dsk.slice = *arg - '0' + 1;
c9a7ee71 496 if (dsk.slice > NDOSPART + 1)
984263bc 497 return -1;
984263bc
MD
498 arg += 2;
499 }
5ee58eed 500 if (arg[1] != ')')
984263bc
MD
501 return -1;
502 dsk.part = *arg - 'a';
5ee58eed
MD
503 if (dsk.part > 7)
504 return (-1);
984263bc
MD
505 arg += 2;
506 if (drv == -1)
507 drv = dsk.unit;
5ee58eed
MD
508 dsk.drive = (dsk.type <= TYPE_MAXHARD
509 ? DRV_HARD : 0) + drv;
984263bc 510 }
c9a7ee71 511 kname = arg;
984263bc
MD
512 }
513 arg = p;
514 }
d64b2e33 515 return dskprobe();
984263bc
MD
516}
517
984263bc 518static int
d64b2e33 519dskprobe(void)
984263bc 520{
984263bc 521 struct dos_partition *dp;
6080181b
SS
522#ifdef DISKLABEL64
523 struct disklabel64 *d;
524#else
2b961883 525 struct disklabel32 *d;
6080181b 526#endif
5ee58eed 527 char *sec;
c9a7ee71
JM
528 unsigned i;
529 uint8_t sl;
984263bc 530
d64b2e33
MD
531 /*
532 * Probe slice table
533 */
534 sec = boot2_dmadat->secbuf;
535 dsk.start = 0;
536 if (drvread(sec, DOSBBSECTOR, 1))
537 return -1;
538 dp = (void *)(sec + DOSPARTOFF);
539 sl = dsk.slice;
540 if (sl < BASE_SLICE) {
541 for (i = 0; i < NDOSPART; i++)
542 if (dp[i].dp_typ == DOSPTYP_386BSD &&
543 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
544 sl = BASE_SLICE + i;
545 if (dp[i].dp_flag & 0x80 ||
546 dsk.slice == COMPATIBILITY_SLICE)
547 break;
984263bc 548 }
d64b2e33
MD
549 if (dsk.slice == WHOLE_DISK_SLICE)
550 dsk.slice = sl;
551 }
552 if (sl != WHOLE_DISK_SLICE) {
553 if (sl != COMPATIBILITY_SLICE)
554 dp += sl - BASE_SLICE;
555 if (dp->dp_typ != DOSPTYP_386BSD) {
556 printf(INVALID_S, "slice");
557 return -1;
984263bc 558 }
d64b2e33
MD
559 dsk.start = dp->dp_start;
560 }
561
562 /*
563 * Probe label and partition table
564 */
6080181b 565#ifdef DISKLABEL64
d64b2e33
MD
566 if (drvread(sec, dsk.start, (sizeof(struct disklabel64) + 511) / 512))
567 return -1;
568 d = (void *)sec;
569 if (d->d_magic != DISKMAGIC64) {
570 printf(INVALID_S, "label");
571 return -1;
572 } else {
573 if (dsk.part >= d->d_npartitions || d->d_partitions[dsk.part].p_bsize == 0) {
574 printf(INVALID_S, "partition");
6080181b 575 return -1;
6080181b 576 }
d64b2e33
MD
577 dsk.start += d->d_partitions[dsk.part].p_boffset / 512;
578 }
6080181b 579#else
d64b2e33
MD
580 if (drvread(sec, dsk.start + LABELSECTOR32, 1))
581 return -1;
582 d = (void *)(sec + LABELOFFSET32);
583 if (d->d_magic != DISKMAGIC32 || d->d_magic2 != DISKMAGIC32) {
584 if (dsk.part != RAW_PART) {
585 printf(INVALID_S, "label");
586 return -1;
587 }
588 } else {
589 if (!dsk.init) {
590 if (d->d_type == DTYPE_SCSI)
591 dsk.type = TYPE_DA;
592 dsk.init++;
984263bc 593 }
d64b2e33
MD
594 if (dsk.part >= d->d_npartitions ||
595 !d->d_partitions[dsk.part].p_size) {
596 printf(INVALID_S, "partition");
597 return -1;
598 }
599 dsk.start += d->d_partitions[dsk.part].p_offset;
600 dsk.start -= d->d_partitions[RAW_PART].p_offset;
601 }
6080181b 602#endif
d64b2e33
MD
603 /*
604 * Probe filesystem
605 */
cdfd0a3e 606#if defined(UFS) && defined(HAMMER2FS)
33e7016e 607 if (boot2_ufs_api.fsinit() == 0) {
d64b2e33 608 fsapi = &boot2_ufs_api;
cdfd0a3e
MD
609 } else if (boot2_hammer2_api.fsinit() == 0) {
610 fsapi = &boot2_hammer2_api;
d64b2e33
MD
611 } else {
612 printf("fs probe failed\n");
613 fsapi = &boot2_ufs_api;
614 return -1;
984263bc 615 }
d64b2e33
MD
616 return 0;
617#else
618 return fsapi->fsinit();
619#endif
620}
621
622
623/*
624 * Read from the probed disk. We have established the slice and partition
625 * base sector.
626 */
627int
628dskread(void *buf, unsigned lba, unsigned nblk)
629{
984263bc
MD
630 return drvread(buf, dsk.start + lba, nblk);
631}
632
d64b2e33
MD
633/*
634 * boot encapsulated ABI
635 */
636void
984263bc
MD
637printf(const char *fmt,...)
638{
5ee58eed 639 va_list ap;
c9a7ee71 640 static char buf[10];
984263bc 641 char *s;
5ee58eed 642 unsigned u;
cdfd0a3e
MD
643#ifdef HAMMER2FS
644 uint64_t q;
645#endif
984263bc
MD
646 int c;
647
5ee58eed 648 va_start(ap, fmt);
984263bc
MD
649 while ((c = *fmt++)) {
650 if (c == '%') {
651 c = *fmt++;
652 switch (c) {
653 case 'c':
5ee58eed 654 putchar(va_arg(ap, int));
984263bc
MD
655 continue;
656 case 's':
5ee58eed 657 for (s = va_arg(ap, char *); *s; s++)
984263bc
MD
658 putchar(*s);
659 continue;
cdfd0a3e
MD
660#ifdef HAMMER2FS
661 case 'q':
662 ++fmt; /* skip the 'x' */
663 q = va_arg(ap, uint64_t);
664 s = buf;
665 do {
666 if ((q & 15) < 10)
667 *s++ = '0' + (q & 15);
668 else
669 *s++ = 'a' + (q & 15) - 10;
670 } while (q >>= 4);
671 while (--s >= buf)
672 putchar(*s);
673 continue;
674 case 'x':
675 u = va_arg(ap, unsigned);
676 s = buf;
677 do {
678 if ((u & 15) < 10)
679 *s++ = '0' + (u & 15);
680 else
681 *s++ = 'a' + (u & 15) - 10;
682 } while (u >>= 4);
683 while (--s >= buf)
684 putchar(*s);
685 continue;
686#endif
984263bc 687 case 'u':
5ee58eed 688 u = va_arg(ap, unsigned);
984263bc
MD
689 s = buf;
690 do
5ee58eed
MD
691 *s++ = '0' + u % 10U;
692 while (u /= 10U);
984263bc
MD
693 while (--s >= buf)
694 putchar(*s);
695 continue;
696 }
697 }
698 putchar(c);
699 }
5ee58eed 700 va_end(ap);
c9a7ee71 701 return;
984263bc
MD
702}
703
d64b2e33
MD
704/*
705 * boot encapsulated ABI
706 */
707void
984263bc
MD
708putchar(int c)
709{
710 if (c == '\n')
711 xputc('\r');
5ee58eed 712 xputc(c);
984263bc
MD
713}
714
d64b2e33
MD
715/*
716 * boot encapsulated ABI
717 */
c9a7ee71 718static int
984263bc
MD
719drvread(void *buf, unsigned lba, unsigned nblk)
720{
50a1695f 721 static unsigned c = 0x2d5c7c2f; /* twiddle */
984263bc 722
50a1695f
MD
723 c = (c << 8) | (c >> 24);
724 xputc(c);
725 xputc('\b');
984263bc
MD
726 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
727 v86.addr = XREADORG; /* call to xread in boot1 */
728 v86.es = VTOPSEG(buf);
729 v86.eax = lba;
730 v86.ebx = VTOPOFF(buf);
731 v86.ecx = lba >> 16;
732 v86.edx = nblk << 8 | dsk.drive;
733 v86int();
734 v86.ctl = V86_FLAGS;
cdfd0a3e 735 if (V86_CY(v86.efl) && !no_io_error) {
5ee58eed 736 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
984263bc
MD
737 return -1;
738 }
739 return 0;
740}
741
742static int
743keyhit(unsigned ticks)
744{
745 uint32_t t0, t1;
746
c9a7ee71 747 if (opts & RBF_NOINTR)
984263bc
MD
748 return 0;
749 t0 = 0;
750 for (;;) {
751 if (xgetc(1))
752 return 1;
753 t1 = *(uint32_t *)PTOV(0x46c);
754 if (!t0)
755 t0 = t1;
c9a7ee71 756 if ((uint32_t)(t1 - t0) >= ticks)
984263bc
MD
757 return 0;
758 }
759}
760
c9a7ee71 761static int
984263bc
MD
762xputc(int c)
763{
badbfe61 764 if (opts & RBF_VIDEO)
984263bc 765 putc(c);
badbfe61 766 if (opts & RBF_SERIAL)
984263bc 767 sio_putc(c);
c9a7ee71
JM
768 return c;
769}
770
771static int
772getc(int fn)
773{
774 v86.addr = 0x16;
775 v86.eax = fn << 8;
776 v86int();
777 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
984263bc
MD
778}
779
780static int
781xgetc(int fn)
782{
c9a7ee71 783 if (opts & RBF_NOINTR)
984263bc
MD
784 return 0;
785 for (;;) {
badbfe61 786 if ((opts & RBF_VIDEO) && getc(1))
984263bc 787 return fn ? 1 : getc(0);
badbfe61 788 if ((opts & RBF_SERIAL) && sio_ischar())
984263bc
MD
789 return fn ? 1 : sio_getc();
790 if (fn)
791 return 0;
792 }
793}