summaryrefslogtreecommitdiffstats
path: root/sys/boot/i386/common
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2010-09-24 19:49:12 +0000
committerpjd <pjd@FreeBSD.org>2010-09-24 19:49:12 +0000
commit891c7fcf8c7cafacd74e5b0eb6462a111cc62f1b (patch)
treea29246e5237a4044bc235bbad59ee0d0c6a5fff1 /sys/boot/i386/common
parent39f36627d95bb74f59e469420305bfd0d61c8626 (diff)
downloadFreeBSD-src-891c7fcf8c7cafacd74e5b0eb6462a111cc62f1b.zip
FreeBSD-src-891c7fcf8c7cafacd74e5b0eb6462a111cc62f1b.tar.gz
- Split code shared by almost any boot loader into separate files and
clean up most layering violations: sys/boot/i386/common/rbx.h: RBX_* defines OPT_SET() OPT_CHECK() sys/boot/common/util.[ch]: memcpy() memset() memcmp() bcpy() bzero() bcmp() strcmp() strncmp() [new] strcpy() strcat() strchr() strlen() printf() sys/boot/i386/common/cons.[ch]: ioctrl putc() xputc() putchar() getc() xgetc() keyhit() [now takes number of seconds as an argument] getstr() sys/boot/i386/common/drv.[ch]: struct dsk drvread() drvwrite() [new] drvsize() [new] sys/boot/common/crc32.[ch] [new] sys/boot/common/gpt.[ch] [new] - Teach gptboot and gptzfsboot about new files. I haven't touched the rest, but there is still a lot of code duplication to be removed. - Implement full GPT support. Currently we just read primary header and partition table and don't care about checksums, etc. After this change we verify checksums of primary header and primary partition table and if there is a problem we fall back to backup header and backup partition table. - Clean up most messages to use prefix of boot program, so in case of an error we know where the error comes from, eg.: gptboot: unable to read primary GPT header - If we can't boot, print boot prompt only once and not every five seconds. - Honour newly added GPT attributes: bootme - this is bootable partition bootonce - try to boot from this partition only once bootfailed - we failed to boot from this partition - Change boot order of gptboot to the following: 1. Try to boot from all the partitions that have both 'bootme' and 'bootonce' attributes one by one. 2. Try to boot from all the partitions that have only 'bootme' attribute one by one. 3. If there are no partitions with 'bootme' attribute, boot from the first UFS partition. - The 'bootonce' functionality is implemented in the following way: 1. Walk through all the partitions and when 'bootonce' attribute is found without 'bootme' attribute, remove 'bootonce' attribute and set 'bootfailed' attribute. 'bootonce' attribute alone means that we tried to boot from this partition, but boot failed after leaving gptboot and machine was restarted. 2. Find partition with both 'bootme' and 'bootonce' attributes. 3. Remove 'bootme' attribute. 4. Try to execute /boot/loader or /boot/kernel/kernel from that partition. If succeeded we stop here. 5. If execution failed, remove 'bootonce' and set 'bootfailed'. 6. Go to 2. If whole boot succeeded there is new /etc/rc.d/gptboot script coming that will log all partitions that we failed to boot from (the ones with 'bootfailed' attribute) and will remove this attribute. It will also find partition with 'bootonce' attribute - this is the partition we booted from successfully. The script will log success and remove the attribute. All the GPT updates we do here goes to both primary and backup GPT if they are valid. We don't touch headers or partition tables when checksum doesn't match. Reviewed by: arch (Message-ID: <20100917234542.GE1902@garage.freebsd.pl>) Obtained from: Wheel Systems Sp. z o.o. http://www.wheelsystems.com MFC after: 2 weeks
Diffstat (limited to 'sys/boot/i386/common')
-rw-r--r--sys/boot/i386/common/cons.c152
-rw-r--r--sys/boot/i386/common/cons.h34
-rw-r--r--sys/boot/i386/common/drv.c131
-rw-r--r--sys/boot/i386/common/drv.h48
-rw-r--r--sys/boot/i386/common/rbx.h61
5 files changed, 426 insertions, 0 deletions
diff --git a/sys/boot/i386/common/cons.c b/sys/boot/i386/common/cons.c
new file mode 100644
index 0000000..56febf2
--- /dev/null
+++ b/sys/boot/i386/common/cons.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/psl.h>
+
+#include <btxv86.h>
+
+#include "lib.h"
+#include "rbx.h"
+#include "util.h"
+#include "cons.h"
+
+#define V86_ZR(x) ((x) & PSL_Z)
+
+#define SECOND 18 /* Circa that many ticks in a second. */
+
+uint8_t ioctrl = IO_KEYBOARD;
+
+void
+putc(int c)
+{
+
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+}
+
+void
+xputc(int c)
+{
+
+ if (ioctrl & IO_KEYBOARD)
+ putc(c);
+ if (ioctrl & IO_SERIAL)
+ sio_putc(c);
+}
+
+void
+putchar(int c)
+{
+
+ if (c == '\n')
+ xputc('\r');
+ xputc(c);
+}
+
+int
+getc(int fn)
+{
+
+ /*
+ * The extra comparison against zero is an attempt to work around
+ * what appears to be a bug in QEMU and Bochs. Both emulators
+ * sometimes report a key-press with scancode one and ascii zero
+ * when no such key is pressed in reality. As far as I can tell,
+ * this only happens shortly after a reboot.
+ */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x16;
+ v86.eax = fn << 8;
+ v86int();
+ return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff));
+}
+
+int
+xgetc(int fn)
+{
+
+ if (OPT_CHECK(RBX_NOINTR))
+ return (0);
+ for (;;) {
+ if (ioctrl & IO_KEYBOARD && getc(1))
+ return (fn ? 1 : getc(0));
+ if (ioctrl & IO_SERIAL && sio_ischar())
+ return (fn ? 1 : sio_getc());
+ if (fn)
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+int
+keyhit(unsigned int secs)
+{
+ uint32_t t0, t1;
+
+ if (OPT_CHECK(RBX_NOINTR))
+ return (0);
+ secs *= SECOND;
+ t0 = 0;
+ for (;;) {
+ if (xgetc(1))
+ return (1);
+ if (secs > 0) {
+ t1 = *(uint32_t *)PTOV(0x46c);
+ if (!t0)
+ t0 = t1;
+ if (t1 < t0 || t1 >= t0 + secs)
+ return (0);
+ }
+ }
+ /* NOTREACHED */
+}
+
+void
+getstr(char *cmdstr, size_t cmdstrsize)
+{
+ char *s;
+ int c;
+
+ s = cmdstr;
+ for (;;) {
+ switch (c = xgetc(0)) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > cmdstr) {
+ s--;
+ printf("\b \b");
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - cmdstr < cmdstrsize - 1)
+ *s++ = c;
+ putchar(c);
+ break;
+ }
+ }
+}
diff --git a/sys/boot/i386/common/cons.h b/sys/boot/i386/common/cons.h
new file mode 100644
index 0000000..fe00a13
--- /dev/null
+++ b/sys/boot/i386/common/cons.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CONS_H_
+#define _CONS_H_
+
+#define IO_KEYBOARD 1
+#define IO_SERIAL 2
+
+extern uint8_t ioctrl;
+
+void putc(int c);
+void xputc(int c);
+void putchar(int c);
+int getc(int fn);
+int xgetc(int fn);
+int keyhit(unsigned int secs);
+void getstr(char *cmdstr, size_t cmdstrsize);
+
+#endif /* !_CONS_H_ */
diff --git a/sys/boot/i386/common/drv.c b/sys/boot/i386/common/drv.c
new file mode 100644
index 0000000..d249bc1
--- /dev/null
+++ b/sys/boot/i386/common/drv.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/psl.h>
+
+#include <btxv86.h>
+
+#include "rbx.h"
+#include "util.h"
+#include "drv.h"
+#ifndef GPT
+#include "xreadorg.h"
+#endif
+
+#define V86_CY(x) ((x) & PSL_C)
+#define V86_ZR(x) ((x) & PSL_Z)
+
+#ifdef GPT
+uint64_t
+drvsize(struct dsk *dskp)
+{
+ unsigned char params[0x42];
+ uint64_t sectors;
+
+ *(uint32_t *)params = sizeof(params);
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4800;
+ v86.edx = dskp->drive;
+ v86.ds = VTOPSEG(params);
+ v86.esi = VTOPOFF(params);
+ v86int();
+ if (V86_CY(v86.efl)) {
+ printf("error %u\n", v86.eax >> 8 & 0xff);
+ return (0);
+ }
+ memcpy(&sectors, params + 0x10, sizeof(sectors));
+ return (sectors);
+}
+#endif /* GPT */
+
+#ifdef GPT
+static struct {
+ uint16_t len;
+ uint16_t count;
+ uint16_t off;
+ uint16_t seg;
+ uint64_t lba;
+} packet;
+#endif /* GPT */
+
+int
+drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
+{
+ static unsigned c = 0x2d5c7c2f;
+
+ if (!OPT_CHECK(RBX_QUIET))
+ printf("%c\b", c = c << 8 | c >> 24);
+#ifdef GPT
+ packet.len = 0x10;
+ packet.count = nblk;
+ packet.off = VTOPOFF(buf);
+ packet.seg = VTOPSEG(buf);
+ packet.lba = lba;
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4200;
+ v86.edx = dskp->drive;
+ v86.ds = VTOPSEG(&packet);
+ v86.esi = VTOPOFF(&packet);
+#else /* !GPT */
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = XREADORG; /* call to xread in boot1 */
+ v86.es = VTOPSEG(buf);
+ v86.eax = lba;
+ v86.ebx = VTOPOFF(buf);
+ v86.ecx = lba >> 32;
+ v86.edx = nblk << 8 | dskp->drive;
+#endif /* !GPT */
+ v86int();
+ if (V86_CY(v86.efl)) {
+ printf("%s: error %u lba %u\n",
+ BOOTPROG, v86.eax >> 8 & 0xff, lba);
+ return (-1);
+ }
+ return (0);
+}
+
+#ifdef GPT
+int
+drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
+{
+
+ packet.len = 0x10;
+ packet.count = nblk;
+ packet.off = VTOPOFF(buf);
+ packet.seg = VTOPSEG(buf);
+ packet.lba = lba;
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4300;
+ v86.edx = dskp->drive;
+ v86.ds = VTOPSEG(&packet);
+ v86.esi = VTOPOFF(&packet);
+ v86int();
+ if (V86_CY(v86.efl)) {
+ printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
+ return (-1);
+ }
+ return (0);
+}
+#endif /* GPT */
diff --git a/sys/boot/i386/common/drv.h b/sys/boot/i386/common/drv.h
new file mode 100644
index 0000000..1ecfbc3
--- /dev/null
+++ b/sys/boot/i386/common/drv.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DRV_H_
+#define _DRV_H_
+
+struct dsk {
+ unsigned int drive;
+ unsigned int type;
+ unsigned int unit;
+ unsigned int slice;
+ int part;
+ daddr_t start;
+ int init;
+};
+
+int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
+#ifdef GPT
+int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
+uint64_t drvsize(struct dsk *dskp);
+#endif /* GPT */
+
+#endif /* !_DRV_H_ */
diff --git a/sys/boot/i386/common/rbx.h b/sys/boot/i386/common/rbx.h
new file mode 100644
index 0000000..21371a5
--- /dev/null
+++ b/sys/boot/i386/common/rbx.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RBX_H_
+#define _RBX_H_
+
+#define RBX_ASKNAME 0x0 /* -a */
+#define RBX_SINGLE 0x1 /* -s */
+/* 0x2 is reserved for log2(RB_NOSYNC). */
+/* 0x3 is reserved for log2(RB_HALT). */
+/* 0x4 is reserved for log2(RB_INITNAME). */
+#define RBX_DFLTROOT 0x5 /* -r */
+#define RBX_KDB 0x6 /* -d */
+/* 0x7 is reserved for log2(RB_RDONLY). */
+/* 0x8 is reserved for log2(RB_DUMP). */
+/* 0x9 is reserved for log2(RB_MINIROOT). */
+#define RBX_CONFIG 0xa /* -c */
+#define RBX_VERBOSE 0xb /* -v */
+#define RBX_SERIAL 0xc /* -h */
+#define RBX_CDROM 0xd /* -C */
+/* 0xe is reserved for log2(RB_POWEROFF). */
+#define RBX_GDB 0xf /* -g */
+#define RBX_MUTE 0x10 /* -m */
+/* 0x11 is reserved for log2(RB_SELFTEST). */
+/* 0x12 is reserved for boot programs. */
+/* 0x13 is reserved for boot programs. */
+#define RBX_PAUSE 0x14 /* -p */
+#define RBX_QUIET 0x15 /* -q */
+#define RBX_NOINTR 0x1c /* -n */
+/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
+#define RBX_DUAL 0x1d /* -D */
+/* 0x1f is reserved for log2(RB_BOOTINFO). */
+
+/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */
+#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
+ OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \
+ OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \
+ OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \
+ OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \
+ OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL))
+
+#define OPT_SET(opt) (1 << (opt))
+#define OPT_CHECK(opt) ((opts) & OPT_SET(opt))
+
+extern uint32_t opts;
+
+#endif /* !_RBX_H_ */
OpenPOWER on IntegriCloud