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>
64 #include <machine/psl.h>
79 #include "../bootasm.h"
81 #define SECOND 18 /* Circa that many ticks in a second. */
83 #define RBX_ASKNAME 0x0 /* -a */
84 #define RBX_SINGLE 0x1 /* -s */
85 #define RBX_DFLTROOT 0x5 /* -r */
86 #define RBX_KDB 0x6 /* -d */
87 #define RBX_CONFIG 0xa /* -c */
88 #define RBX_VERBOSE 0xb /* -v */
89 #define RBX_SERIAL 0xc /* -h */
90 #define RBX_CDROM 0xd /* -C */
91 #define RBX_GDB 0xf /* -g */
92 #define RBX_MUTE 0x10 /* -m */
93 #define RBX_PAUSE 0x12 /* -p */
94 #define RBX_NOINTR 0x1c /* -n */
95 #define RBX_VIDEO 0x1d /* -V */
96 #define RBX_PROBEKBD 0x1e /* -P */
97 /* 0x1f is reserved for the historical RB_BOOTINFO option */
99 #define RBF_MUTE (1 << RBX_MUTE)
100 #define RBF_SERIAL (1 << RBX_SERIAL)
101 #define RBF_VIDEO (1 << RBX_VIDEO)
103 /* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -V */
104 #define RBX_MASK 0x2005ffff
106 #define PATH_CONFIG "/boot.config"
107 #define PATH_BOOT3 "/boot/loader" /* /boot in root */
108 #define PATH_BOOT3_ALT "/loader" /* /boot partition */
109 #define PATH_KERNEL "/kernel"
112 #define MEM_BASE 0x12
114 #define V86_CY(x) ((x) & PSL_C)
115 #define V86_ZR(x) ((x) & PSL_Z)
117 #define DRV_HARD 0x80
118 #define DRV_MASK 0x7f
122 #define TYPE_MAXHARD TYPE_DA
127 #define INVALID_S "Bad %s\n"
129 extern uint32_t _end
;
131 static const char optstr
[NOPT
] = { "VhaCgmnPprsv" };
132 static const unsigned char flags
[NOPT
] = {
147 static const char *const dev_nm
[NDEV
] = {"ad", "da", "fd"};
148 static const unsigned char dev_maj
[NDEV
] = {30, 4, 2};
160 static char cmd
[512];
161 static char kname
[1024];
162 static uint32_t opts
= RBF_VIDEO
;
163 static struct bootinfo bootinfo
;
166 * boot2 encapsulated ABI elements provided to *fsread.c
168 * NOTE: boot2_dmadat is extended by per-filesystem APIs
172 struct boot2_dmadat
*boot2_dmadat
;
175 static void load(void);
176 static int parse(void);
177 static int dskprobe(void);
178 static int xfsread(boot2_ino_t
, void *, size_t);
179 static uint32_t memsize(void);
180 static int drvread(void *, unsigned, unsigned);
181 static int keyhit(unsigned);
182 static void xputc(int);
183 static int xgetc(int);
184 static int getc(int);
187 memcpy(void *d
, const void *s
, int len
)
206 strcmp(const char *s1
, const char *s2
)
208 for (; *s1
== *s2
&& *s1
; s1
++, s2
++)
210 return ((int)((unsigned char)*s1
- (unsigned char)*s2
));
213 #if defined(UFS) && defined(HAMMERFS)
215 const struct boot2_fsapi
*fsapi
;
219 #define fsapi (&boot2_ufs_api)
221 #elif defined(HAMMERFS)
223 #define fsapi (&boot2_hammer_api)
228 xfsread(boot2_ino_t inode
, void *buf
, size_t nbyte
)
230 if ((size_t)fsapi
->fsread(inode
, buf
, nbyte
) != nbyte
) {
231 printf(INVALID_S
, "format");
237 static inline uint32_t
254 switch (c
= xgetc(0)) {
269 if (s
- cmd
< sizeof(cmd
) - 1)
280 v86
.eax
= 0xe00 | (c
& 0xff);
292 (void *)(roundup2(__base
+ (int32_t)&_end
, 0x10000) - __base
);
294 v86
.efl
= PSL_RESERVED_DEFAULT
| PSL_I
;
295 dsk
.drive
= *(uint8_t *)PTOV(MEM_BTX_USR_ARG
);
296 dsk
.type
= dsk
.drive
& DRV_HARD
? TYPE_AD
: TYPE_FD
;
297 dsk
.unit
= dsk
.drive
& DRV_MASK
;
298 dsk
.slice
= *(uint8_t *)PTOV(MEM_BTX_USR_ARG
+ 1) + 1;
299 bootinfo
.bi_version
= BOOTINFO_VERSION
;
300 bootinfo
.bi_size
= sizeof(bootinfo
);
301 bootinfo
.bi_basemem
= 0; /* XXX will be filled by loader or kernel */
302 bootinfo
.bi_extmem
= memsize();
303 bootinfo
.bi_memsizes_valid
++;
308 * Probe the default disk and process the configuration file if
311 if (dskprobe() == 0) {
312 if ((ino
= fsapi
->fslookup(PATH_CONFIG
)))
313 fsapi
->fsread(ino
, cmd
, sizeof(cmd
));
317 * Parse config file if present. parse() will re-probe if necessary.
320 printf("%s: %s", PATH_CONFIG
, cmd
);
323 /* Do not process this command twice */
328 * Setup our (serial) console after processing the config file. If
329 * the initialization fails, don't try to use the serial port. This
330 * can happen if the serial port is unmaped (happens on new laptops a lot).
332 if ((opts
& (RBF_MUTE
|RBF_SERIAL
|RBF_VIDEO
)) == 0)
333 opts
|= RBF_SERIAL
|RBF_VIDEO
;
334 if (opts
& RBF_SERIAL
) {
341 * Try to exec stage 3 boot loader. If interrupted by a keypress,
342 * or in case of failure, try to load a kernel directly instead.
344 * We have to try boot /boot/loader and /loader to support booting
345 * from a /boot partition instead of a root partition.
347 if (autoboot
&& !*kname
) {
348 memcpy(kname
, PATH_BOOT3
, sizeof(PATH_BOOT3
));
349 if (!keyhit(3*SECOND
)) {
351 memcpy(kname
, PATH_BOOT3_ALT
, sizeof(PATH_BOOT3_ALT
));
353 memcpy(kname
, PATH_KERNEL
, sizeof(PATH_KERNEL
));
357 /* Present the user with the boot2 prompt. */
360 printf("\nDragonFly boot\n"
362 dsk
.drive
& DRV_MASK
, dev_nm
[dsk
.type
], dsk
.unit
,
363 'a' + dsk
.part
, kname
);
364 if (!autoboot
|| keyhit(5*SECOND
))
376 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
396 if (!(ino
= fsapi
->fslookup(kname
))) {
398 printf("No %s\n", kname
);
401 if (xfsread(ino
, &hdr
, sizeof(hdr
)))
403 if (N_GETMAGIC(hdr
.ex
) == ZMAGIC
)
405 else if (IS_ELF(hdr
.eh
))
408 printf(INVALID_S
, "format");
412 addr
= hdr
.ex
.a_entry
& 0xffffff;
415 if (xfsread(ino
, p
, hdr
.ex
.a_text
))
417 p
+= roundup2(hdr
.ex
.a_text
, PAGE_SIZE
);
418 if (xfsread(ino
, p
, hdr
.ex
.a_data
))
420 p
+= hdr
.ex
.a_data
+ roundup2(hdr
.ex
.a_bss
, PAGE_SIZE
);
421 bootinfo
.bi_symtab
= VTOP(p
);
422 memcpy(p
, &hdr
.ex
.a_syms
, sizeof(hdr
.ex
.a_syms
));
423 p
+= sizeof(hdr
.ex
.a_syms
);
425 if (xfsread(ino
, p
, hdr
.ex
.a_syms
))
428 if (xfsread(ino
, p
, sizeof(int)))
433 if (xfsread(ino
, p
, x
))
438 fs_off
= hdr
.eh
.e_phoff
;
439 for (j
= i
= 0; i
< hdr
.eh
.e_phnum
&& j
< 2; i
++) {
440 if (xfsread(ino
, ep
+ j
, sizeof(ep
[0])))
442 if (ep
[j
].p_type
== PT_LOAD
)
445 for (i
= 0; i
< 2; i
++) {
446 p
= PTOV(ep
[i
].p_paddr
& 0xffffff);
447 fs_off
= ep
[i
].p_offset
;
448 if (xfsread(ino
, p
, ep
[i
].p_filesz
))
451 p
+= roundup2(ep
[1].p_memsz
, PAGE_SIZE
);
452 bootinfo
.bi_symtab
= VTOP(p
);
453 if (hdr
.eh
.e_shnum
== hdr
.eh
.e_shstrndx
+ 3) {
454 fs_off
= hdr
.eh
.e_shoff
+ sizeof(es
[0]) *
455 (hdr
.eh
.e_shstrndx
+ 1);
456 if (xfsread(ino
, &es
, sizeof(es
)))
458 for (i
= 0; i
< 2; i
++) {
459 memcpy(p
, &es
[i
].sh_size
, sizeof(es
[i
].sh_size
));
460 p
+= sizeof(es
[i
].sh_size
);
461 fs_off
= es
[i
].sh_offset
;
462 if (xfsread(ino
, p
, es
[i
].sh_size
))
467 addr
= hdr
.eh
.e_entry
& 0xffffff;
469 bootinfo
.bi_esymtab
= VTOP(p
);
470 bootinfo
.bi_kernelname
= VTOP(kname
);
471 bootinfo
.bi_bios_dev
= dsk
.drive
;
472 __exec((caddr_t
)addr
, opts
& RBX_MASK
,
473 MAKEBOOTDEV(dev_maj
[dsk
.type
], 0, dsk
.slice
, dsk
.unit
, dsk
.part
),
474 0, 0, 0, VTOP(&bootinfo
));
485 while ((c
= *arg
++)) {
486 if (c
== ' ' || c
== '\t' || c
== '\n')
488 for (p
= arg
; *p
&& *p
!= '\n' && *p
!= ' ' && *p
!= '\t'; p
++)
493 while ((c
= *arg
++)) {
494 for (i
= NOPT
- 1; i
>= 0; --i
) {
495 if (optstr
[i
] == c
) {
496 opts
^= 1 << flags
[i
];
501 ok
: ; /* ugly but save space */
503 if (opts
& (1 << RBX_PROBEKBD
)) {
504 i
= *(uint8_t *)PTOV(0x496) & 0x10;
507 opts
|= RBF_VIDEO
| RBF_SERIAL
;
509 opts
&= ~(1 << RBX_PROBEKBD
);
512 for (q
= arg
--; *q
&& *q
!= '('; q
++);
523 for (i
= 0; arg
[0] != dev_nm
[i
][0] ||
524 arg
[1] != dev_nm
[i
][1]; i
++)
529 dsk
.unit
= *arg
- '0';
530 if (arg
[1] != ',' || dsk
.unit
> 9)
533 dsk
.slice
= WHOLE_DISK_SLICE
;
535 dsk
.slice
= *arg
- '0' + 1;
536 if (dsk
.slice
> NDOSPART
)
542 dsk
.part
= *arg
- 'a';
548 dsk
.drive
= (dsk
.type
<= TYPE_MAXHARD
549 ? DRV_HARD
: 0) + drv
;
551 if ((i
= p
- arg
- !*(p
- 1))) {
552 if ((size_t)i
>= sizeof(kname
))
554 memcpy(kname
, arg
, i
+ 1);
565 struct dos_partition
*dp
;
567 struct disklabel64
*d
;
569 struct disklabel32
*d
;
577 sec
= boot2_dmadat
->secbuf
;
579 if (drvread(sec
, DOSBBSECTOR
, 1))
581 dp
= (void *)(sec
+ DOSPARTOFF
);
583 if (sl
< BASE_SLICE
) {
584 for (i
= 0; i
< NDOSPART
; i
++)
585 if (dp
[i
].dp_typ
== DOSPTYP_386BSD
&&
586 (dp
[i
].dp_flag
& 0x80 || sl
< BASE_SLICE
)) {
588 if (dp
[i
].dp_flag
& 0x80 ||
589 dsk
.slice
== COMPATIBILITY_SLICE
)
592 if (dsk
.slice
== WHOLE_DISK_SLICE
)
595 if (sl
!= WHOLE_DISK_SLICE
) {
596 if (sl
!= COMPATIBILITY_SLICE
)
597 dp
+= sl
- BASE_SLICE
;
598 if (dp
->dp_typ
!= DOSPTYP_386BSD
) {
599 printf(INVALID_S
, "slice");
602 dsk
.start
= dp
->dp_start
;
606 * Probe label and partition table
609 if (drvread(sec
, dsk
.start
, (sizeof(struct disklabel64
) + 511) / 512))
612 if (d
->d_magic
!= DISKMAGIC64
) {
613 printf(INVALID_S
, "label");
616 if (dsk
.part
>= d
->d_npartitions
|| d
->d_partitions
[dsk
.part
].p_bsize
== 0) {
617 printf(INVALID_S
, "partition");
620 dsk
.start
+= d
->d_partitions
[dsk
.part
].p_boffset
/ 512;
623 if (drvread(sec
, dsk
.start
+ LABELSECTOR32
, 1))
625 d
= (void *)(sec
+ LABELOFFSET32
);
626 if (d
->d_magic
!= DISKMAGIC32
|| d
->d_magic2
!= DISKMAGIC32
) {
627 if (dsk
.part
!= RAW_PART
) {
628 printf(INVALID_S
, "label");
633 if (d
->d_type
== DTYPE_SCSI
)
637 if (dsk
.part
>= d
->d_npartitions
||
638 !d
->d_partitions
[dsk
.part
].p_size
) {
639 printf(INVALID_S
, "partition");
642 dsk
.start
+= d
->d_partitions
[dsk
.part
].p_offset
;
643 dsk
.start
-= d
->d_partitions
[RAW_PART
].p_offset
;
649 #if defined(UFS) && defined(HAMMERFS)
650 if (boot2_hammer_api
.fsinit() == 0) {
651 fsapi
= &boot2_hammer_api
;
652 } else if (boot2_ufs_api
.fsinit() == 0) {
653 fsapi
= &boot2_ufs_api
;
655 printf("fs probe failed\n");
656 fsapi
= &boot2_ufs_api
;
661 return fsapi
->fsinit();
667 * Read from the probed disk. We have established the slice and partition
671 dskread(void *buf
, unsigned lba
, unsigned nblk
)
673 return drvread(buf
, dsk
.start
+ lba
, nblk
);
677 * boot encapsulated ABI
680 printf(const char *fmt
,...)
689 while ((c
= *fmt
++)) {
694 putchar(va_arg(ap
, int));
697 for (s
= va_arg(ap
, char *); *s
; s
++)
701 u
= va_arg(ap
, unsigned);
704 *s
++ = '0' + u
% 10U;
717 * boot encapsulated ABI
728 * boot encapsulated ABI
731 drvread(void *buf
, unsigned lba
, unsigned nblk
)
733 static unsigned c
= 0x2d5c7c2f; /* twiddle */
735 c
= (c
<< 8) | (c
>> 24);
738 v86
.ctl
= V86_ADDR
| V86_CALLF
| V86_FLAGS
;
739 v86
.addr
= XREADORG
; /* call to xread in boot1 */
740 v86
.es
= VTOPSEG(buf
);
742 v86
.ebx
= VTOPOFF(buf
);
744 v86
.edx
= nblk
<< 8 | dsk
.drive
;
747 if (V86_CY(v86
.efl
)) {
748 printf("error %u lba %u\n", v86
.eax
>> 8 & 0xff, lba
);
755 keyhit(unsigned ticks
)
759 if (opts
& 1 << RBX_NOINTR
)
765 t1
= *(uint32_t *)PTOV(0x46c);
768 if (t1
< t0
|| t1
>= t0
+ ticks
)
776 if (opts
& RBF_VIDEO
)
778 if (opts
& RBF_SERIAL
)
785 if (opts
& 1 << RBX_NOINTR
)
788 if ((opts
& RBF_VIDEO
) && getc(1))
789 return fn
? 1 : getc(0);
790 if ((opts
& RBF_SERIAL
) && sio_ischar())
791 return fn
? 1 : sio_getc();
803 return fn
== 0 ? v86
.eax
& 0xff : !V86_ZR(v86
.efl
);