2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * Copyright (c) 1998 Robert Nordier
35 * All rights reserved.
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
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
47 * $FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.64 2003/08/25 23:28:31 obrien Exp $
48 * $DragonFly: src/sys/boot/pc32/boot2/boot2.c,v 1.18 2008/09/13 11:45:45 corecode Exp $
51 #define AOUT_H_FORCE32
52 #include <sys/param.h>
54 #include <sys/disklabel64.h>
56 #include <sys/disklabel32.h>
58 #include <sys/diskslice.h>
59 #include <sys/diskmbr.h>
60 #include <sys/dtype.h>
61 #include <sys/dirent.h>
62 #include <machine/bootinfo.h>
63 #include <machine/elf.h>
78 #include "../bootasm.h"
80 #define SECOND 18 /* Circa that many ticks in a second. */
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 */
91 #define RBX_MUTE 0x10 /* -m */
92 #define RBX_PAUSE 0x12 /* -p */
93 #define RBX_NOINTR 0x1c /* -n */
94 #define RBX_VIDEO 0x1d /* -V */
95 #define RBX_PROBEKBD 0x1e /* -P */
96 /* 0x1f is reserved for the historical RB_BOOTINFO option */
98 #define RBF_MUTE (1 << RBX_MUTE)
99 #define RBF_SERIAL (1 << RBX_SERIAL)
100 #define RBF_VIDEO (1 << RBX_VIDEO)
102 /* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -V */
103 #define RBX_MASK 0x2005ffff
105 #define PATH_CONFIG "/boot.config"
106 #define PATH_BOOT3 "/boot/loader" /* /boot in root */
107 #define PATH_BOOT3_ALT "/loader" /* /boot partition */
108 #define PATH_KERNEL "/kernel"
111 #define MEM_BASE 0x12
113 #define V86_CY(x) ((x) & 1)
114 #define V86_ZR(x) ((x) & 0x40)
116 #define DRV_HARD 0x80
117 #define DRV_MASK 0x7f
121 #define TYPE_MAXHARD TYPE_DA
126 #define INVALID_S "Bad %s\n"
128 extern uint32_t _end
;
130 static const char optstr
[NOPT
] = { "VhaCgmnPprsv" };
131 static const unsigned char flags
[NOPT
] = {
146 static const char *const dev_nm
[NDEV
] = {"ad", "da", "fd"};
147 static const unsigned char dev_maj
[NDEV
] = {30, 4, 2};
159 static char cmd
[512];
160 static char kname
[1024];
161 static uint32_t opts
= RBF_VIDEO
;
162 static struct bootinfo bootinfo
;
165 * boot2 encapsulated ABI elements provided to *fsread.c
167 * NOTE: boot2_dmadat is extended by per-filesystem APIs
171 struct boot2_dmadat
*boot2_dmadat
;
174 static void load(void);
175 static int parse(void);
176 static int dskprobe(void);
177 static int xfsread(boot2_ino_t
, void *, size_t);
178 static uint32_t memsize(void);
179 static int drvread(void *, unsigned, unsigned);
180 static int keyhit(unsigned);
181 static void xputc(int);
182 static int xgetc(int);
183 static int getc(int);
186 memcpy(void *d
, const void *s
, int len
)
205 strcmp(const char *s1
, const char *s2
)
207 for (; *s1
== *s2
&& *s1
; s1
++, s2
++)
209 return ((int)((unsigned char)*s1
- (unsigned char)*s2
));
212 #if defined(UFS) && defined(HAMMERFS)
214 const struct boot2_fsapi
*fsapi
;
218 #define fsapi (&boot2_ufs_api)
220 #elif defined(HAMMERFS)
222 #define fsapi (&boot2_hammer_api)
227 xfsread(boot2_ino_t inode
, void *buf
, size_t nbyte
)
229 if ((size_t)fsapi
->fsread(inode
, buf
, nbyte
) != nbyte
) {
230 printf(INVALID_S
, "format");
236 static inline uint32_t
253 switch (c
= xgetc(0)) {
268 if (s
- cmd
< sizeof(cmd
) - 1)
279 v86
.eax
= 0xe00 | (c
& 0xff);
291 (void *)(roundup2(__base
+ (int32_t)&_end
, 0x10000) - __base
);
293 dsk
.drive
= *(uint8_t *)PTOV(MEM_BTX_USR_ARG
);
294 dsk
.type
= dsk
.drive
& DRV_HARD
? TYPE_AD
: TYPE_FD
;
295 dsk
.unit
= dsk
.drive
& DRV_MASK
;
296 dsk
.slice
= *(uint8_t *)PTOV(MEM_BTX_USR_ARG
+ 1) + 1;
297 bootinfo
.bi_version
= BOOTINFO_VERSION
;
298 bootinfo
.bi_size
= sizeof(bootinfo
);
299 bootinfo
.bi_basemem
= 0; /* XXX will be filled by loader or kernel */
300 bootinfo
.bi_extmem
= memsize();
301 bootinfo
.bi_memsizes_valid
++;
306 * Probe the default disk and process the configuration file if
309 if (dskprobe() == 0) {
310 if ((ino
= fsapi
->fslookup(PATH_CONFIG
)))
311 fsapi
->fsread(ino
, cmd
, sizeof(cmd
));
315 * Parse config file if present. parse() will re-probe if necessary.
318 printf("%s: %s", PATH_CONFIG
, cmd
);
321 /* Do not process this command twice */
326 * Setup our (serial) console after processing the config file. If
327 * the initialization fails, don't try to use the serial port. This
328 * can happen if the serial port is unmaped (happens on new laptops a lot).
330 if ((opts
& (RBF_MUTE
|RBF_SERIAL
|RBF_VIDEO
)) == 0)
331 opts
|= RBF_SERIAL
|RBF_VIDEO
;
332 if (opts
& RBF_SERIAL
) {
339 * Try to exec stage 3 boot loader. If interrupted by a keypress,
340 * or in case of failure, try to load a kernel directly instead.
342 * We have to try boot /boot/loader and /loader to support booting
343 * from a /boot partition instead of a root partition.
345 if (autoboot
&& !*kname
) {
346 memcpy(kname
, PATH_BOOT3
, sizeof(PATH_BOOT3
));
347 if (!keyhit(3*SECOND
)) {
349 memcpy(kname
, PATH_BOOT3_ALT
, sizeof(PATH_BOOT3_ALT
));
351 memcpy(kname
, PATH_KERNEL
, sizeof(PATH_KERNEL
));
355 /* Present the user with the boot2 prompt. */
358 printf("\nDragonFly boot\n"
360 dsk
.drive
& DRV_MASK
, dev_nm
[dsk
.type
], dsk
.unit
,
361 'a' + dsk
.part
, kname
);
362 if (!autoboot
|| keyhit(5*SECOND
))
374 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
394 if (!(ino
= fsapi
->fslookup(kname
))) {
396 printf("No %s\n", kname
);
399 if (xfsread(ino
, &hdr
, sizeof(hdr
)))
401 if (N_GETMAGIC(hdr
.ex
) == ZMAGIC
)
403 else if (IS_ELF(hdr
.eh
))
406 printf(INVALID_S
, "format");
410 addr
= hdr
.ex
.a_entry
& 0xffffff;
413 if (xfsread(ino
, p
, hdr
.ex
.a_text
))
415 p
+= roundup2(hdr
.ex
.a_text
, PAGE_SIZE
);
416 if (xfsread(ino
, p
, hdr
.ex
.a_data
))
418 p
+= hdr
.ex
.a_data
+ roundup2(hdr
.ex
.a_bss
, PAGE_SIZE
);
419 bootinfo
.bi_symtab
= VTOP(p
);
420 memcpy(p
, &hdr
.ex
.a_syms
, sizeof(hdr
.ex
.a_syms
));
421 p
+= sizeof(hdr
.ex
.a_syms
);
423 if (xfsread(ino
, p
, hdr
.ex
.a_syms
))
426 if (xfsread(ino
, p
, sizeof(int)))
431 if (xfsread(ino
, p
, x
))
436 fs_off
= hdr
.eh
.e_phoff
;
437 for (j
= i
= 0; i
< hdr
.eh
.e_phnum
&& j
< 2; i
++) {
438 if (xfsread(ino
, ep
+ j
, sizeof(ep
[0])))
440 if (ep
[j
].p_type
== PT_LOAD
)
443 for (i
= 0; i
< 2; i
++) {
444 p
= PTOV(ep
[i
].p_paddr
& 0xffffff);
445 fs_off
= ep
[i
].p_offset
;
446 if (xfsread(ino
, p
, ep
[i
].p_filesz
))
449 p
+= roundup2(ep
[1].p_memsz
, PAGE_SIZE
);
450 bootinfo
.bi_symtab
= VTOP(p
);
451 if (hdr
.eh
.e_shnum
== hdr
.eh
.e_shstrndx
+ 3) {
452 fs_off
= hdr
.eh
.e_shoff
+ sizeof(es
[0]) *
453 (hdr
.eh
.e_shstrndx
+ 1);
454 if (xfsread(ino
, &es
, sizeof(es
)))
456 for (i
= 0; i
< 2; i
++) {
457 memcpy(p
, &es
[i
].sh_size
, sizeof(es
[i
].sh_size
));
458 p
+= sizeof(es
[i
].sh_size
);
459 fs_off
= es
[i
].sh_offset
;
460 if (xfsread(ino
, p
, es
[i
].sh_size
))
465 addr
= hdr
.eh
.e_entry
& 0xffffff;
467 bootinfo
.bi_esymtab
= VTOP(p
);
468 bootinfo
.bi_kernelname
= VTOP(kname
);
469 bootinfo
.bi_bios_dev
= dsk
.drive
;
470 __exec((caddr_t
)addr
, opts
& RBX_MASK
,
471 MAKEBOOTDEV(dev_maj
[dsk
.type
], 0, dsk
.slice
, dsk
.unit
, dsk
.part
),
472 0, 0, 0, VTOP(&bootinfo
));
483 while ((c
= *arg
++)) {
484 if (c
== ' ' || c
== '\t' || c
== '\n')
486 for (p
= arg
; *p
&& *p
!= '\n' && *p
!= ' ' && *p
!= '\t'; p
++)
491 while ((c
= *arg
++)) {
492 for (i
= NOPT
- 1; i
>= 0; --i
) {
493 if (optstr
[i
] == c
) {
494 opts
^= 1 << flags
[i
];
499 ok
: ; /* ugly but save space */
501 if (opts
& (1 << RBX_PROBEKBD
)) {
502 i
= *(uint8_t *)PTOV(0x496) & 0x10;
505 opts
|= RBF_VIDEO
| RBF_SERIAL
;
507 opts
&= ~(1 << RBX_PROBEKBD
);
510 for (q
= arg
--; *q
&& *q
!= '('; q
++);
521 for (i
= 0; arg
[0] != dev_nm
[i
][0] ||
522 arg
[1] != dev_nm
[i
][1]; i
++)
527 dsk
.unit
= *arg
- '0';
528 if (arg
[1] != ',' || dsk
.unit
> 9)
531 dsk
.slice
= WHOLE_DISK_SLICE
;
533 dsk
.slice
= *arg
- '0' + 1;
534 if (dsk
.slice
> NDOSPART
)
540 dsk
.part
= *arg
- 'a';
546 dsk
.drive
= (dsk
.type
<= TYPE_MAXHARD
547 ? DRV_HARD
: 0) + drv
;
549 if ((i
= p
- arg
- !*(p
- 1))) {
550 if ((size_t)i
>= sizeof(kname
))
552 memcpy(kname
, arg
, i
+ 1);
563 struct dos_partition
*dp
;
565 struct disklabel64
*d
;
567 struct disklabel32
*d
;
575 sec
= boot2_dmadat
->secbuf
;
577 if (drvread(sec
, DOSBBSECTOR
, 1))
579 dp
= (void *)(sec
+ DOSPARTOFF
);
581 if (sl
< BASE_SLICE
) {
582 for (i
= 0; i
< NDOSPART
; i
++)
583 if (dp
[i
].dp_typ
== DOSPTYP_386BSD
&&
584 (dp
[i
].dp_flag
& 0x80 || sl
< BASE_SLICE
)) {
586 if (dp
[i
].dp_flag
& 0x80 ||
587 dsk
.slice
== COMPATIBILITY_SLICE
)
590 if (dsk
.slice
== WHOLE_DISK_SLICE
)
593 if (sl
!= WHOLE_DISK_SLICE
) {
594 if (sl
!= COMPATIBILITY_SLICE
)
595 dp
+= sl
- BASE_SLICE
;
596 if (dp
->dp_typ
!= DOSPTYP_386BSD
) {
597 printf(INVALID_S
, "slice");
600 dsk
.start
= dp
->dp_start
;
604 * Probe label and partition table
607 if (drvread(sec
, dsk
.start
, (sizeof(struct disklabel64
) + 511) / 512))
610 if (d
->d_magic
!= DISKMAGIC64
) {
611 printf(INVALID_S
, "label");
614 if (dsk
.part
>= d
->d_npartitions
|| d
->d_partitions
[dsk
.part
].p_bsize
== 0) {
615 printf(INVALID_S
, "partition");
618 dsk
.start
+= d
->d_partitions
[dsk
.part
].p_boffset
/ 512;
621 if (drvread(sec
, dsk
.start
+ LABELSECTOR32
, 1))
623 d
= (void *)(sec
+ LABELOFFSET32
);
624 if (d
->d_magic
!= DISKMAGIC32
|| d
->d_magic2
!= DISKMAGIC32
) {
625 if (dsk
.part
!= RAW_PART
) {
626 printf(INVALID_S
, "label");
631 if (d
->d_type
== DTYPE_SCSI
)
635 if (dsk
.part
>= d
->d_npartitions
||
636 !d
->d_partitions
[dsk
.part
].p_size
) {
637 printf(INVALID_S
, "partition");
640 dsk
.start
+= d
->d_partitions
[dsk
.part
].p_offset
;
641 dsk
.start
-= d
->d_partitions
[RAW_PART
].p_offset
;
647 #if defined(UFS) && defined(HAMMERFS)
648 if (boot2_hammer_api
.fsinit() == 0) {
649 fsapi
= &boot2_hammer_api
;
650 } else if (boot2_ufs_api
.fsinit() == 0) {
651 fsapi
= &boot2_ufs_api
;
653 printf("fs probe failed\n");
654 fsapi
= &boot2_ufs_api
;
659 return fsapi
->fsinit();
665 * Read from the probed disk. We have established the slice and partition
669 dskread(void *buf
, unsigned lba
, unsigned nblk
)
671 return drvread(buf
, dsk
.start
+ lba
, nblk
);
675 * boot encapsulated ABI
678 printf(const char *fmt
,...)
687 while ((c
= *fmt
++)) {
692 putchar(va_arg(ap
, int));
695 for (s
= va_arg(ap
, char *); *s
; s
++)
699 u
= va_arg(ap
, unsigned);
702 *s
++ = '0' + u
% 10U;
715 * boot encapsulated ABI
726 * boot encapsulated ABI
729 drvread(void *buf
, unsigned lba
, unsigned nblk
)
731 static unsigned c
= 0x2d5c7c2f; /* twiddle */
733 c
= (c
<< 8) | (c
>> 24);
736 v86
.ctl
= V86_ADDR
| V86_CALLF
| V86_FLAGS
;
737 v86
.addr
= XREADORG
; /* call to xread in boot1 */
738 v86
.es
= VTOPSEG(buf
);
740 v86
.ebx
= VTOPOFF(buf
);
742 v86
.edx
= nblk
<< 8 | dsk
.drive
;
745 if (V86_CY(v86
.efl
)) {
746 printf("error %u lba %u\n", v86
.eax
>> 8 & 0xff, lba
);
753 keyhit(unsigned ticks
)
757 if (opts
& 1 << RBX_NOINTR
)
763 t1
= *(uint32_t *)PTOV(0x46c);
766 if (t1
< t0
|| t1
>= t0
+ ticks
)
774 if (opts
& RBF_VIDEO
)
776 if (opts
& RBF_SERIAL
)
783 if (opts
& 1 << RBX_NOINTR
)
786 if ((opts
& RBF_VIDEO
) && getc(1))
787 return fn
? 1 : getc(0);
788 if ((opts
& RBF_SERIAL
) && sio_ischar())
789 return fn
? 1 : sio_getc();
801 return fn
== 0 ? v86
.eax
& 0xff : !V86_ZR(v86
.efl
);