diff options
author | kevans <kevans@FreeBSD.org> | 2018-02-12 01:08:44 +0000 |
---|---|---|
committer | kevans <kevans@FreeBSD.org> | 2018-02-12 01:08:44 +0000 |
commit | 7d97ee5b28b409c00bfaf12daf5ab497a6038b9d (patch) | |
tree | 245306b754606bcf49c0ff17b131b58609b6c7a6 /stand/i386/gptboot | |
parent | 43b278e1b66cf4de337a17034087ea785031bd6f (diff) | |
download | FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.zip FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.tar.gz |
MFC r325834,r325997,326502: Move sys/boot to stand/
This is effectively a direct commit to stable/11, due to differences between
stable/11 and head. Changes to DTS in sys/boot/fdt/dts were often
accompanied by kernel changes. Many of these were also risc-v updates that
likely had many more dependencies to MFC.
Because of this, sys/boot/fdt/dts remains as-is while everything else in
sys/boot relocates to stand/.
r325834: Move sys/boot to stand. Fix all references to new location
r325997: Remove empty directories.
r326502: Document the sys/boot -> stand move in hier.7 and the top-level README.
Diffstat (limited to 'stand/i386/gptboot')
-rw-r--r-- | stand/i386/gptboot/Makefile | 75 | ||||
-rw-r--r-- | stand/i386/gptboot/Makefile.depend | 19 | ||||
-rw-r--r-- | stand/i386/gptboot/gptboot.8 | 245 | ||||
-rw-r--r-- | stand/i386/gptboot/gptboot.c | 648 | ||||
-rw-r--r-- | stand/i386/gptboot/gptldr.S | 142 |
5 files changed, 1129 insertions, 0 deletions
diff --git a/stand/i386/gptboot/Makefile b/stand/i386/gptboot/Makefile new file mode 100644 index 0000000..9e62007 --- /dev/null +++ b/stand/i386/gptboot/Makefile @@ -0,0 +1,75 @@ +# $FreeBSD$ + +HAVE_GELI= yes + +.include <bsd.init.mk> + +.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC} + +FILES= gptboot +MAN= gptboot.8 + +NM?= nm + +BOOT_COMCONSOLE_PORT?= 0x3f8 +BOOT_COMCONSOLE_SPEED?= 9600 +B2SIOFMT?= 0x3 + +REL1= 0x700 +ORG1= 0x7c00 +ORG2= 0x0 + +# Decide level of UFS support. +GPTBOOT_UFS?= UFS1_AND_UFS2 +#GPTBOOT_UFS?= UFS2_ONLY +#GPTBOOT_UFS?= UFS1_ONLY + +CFLAGS+=-DBOOTPROG=\"gptboot\" \ + -O1 \ + -DGPT \ + -D${GPTBOOT_UFS} \ + -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ + -DSIOFMT=${B2SIOFMT} \ + -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ + -I${LDRSRC} \ + -I${BOOTSRC}/i386/common \ + -I${BTXLIB} \ + -I${BOOTSRC}/i386/boot2 \ + -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ + -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ + -Winline -Wno-pointer-sign + +CFLAGS.gcc+= --param max-inline-insns-single=100 + +LD_FLAGS+=${LD_FLAGS_BIN} + +CLEANFILES+= gptboot + +gptboot: gptldr.bin gptboot.bin ${BTXKERN} + btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \ + -o ${.TARGET} gptboot.bin + +CLEANFILES+= gptldr.bin gptldr.out gptldr.o + +gptldr.bin: gptldr.out + ${OBJCOPY} -S -O binary gptldr.out ${.TARGET} + +gptldr.out: gptldr.o + ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o + +CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \ + cons.o ${OPENCRYPTO_XTS} + +gptboot.bin: gptboot.out + ${OBJCOPY} -S -O binary gptboot.out ${.TARGET} + +gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o ${OPENCRYPTO_XTS} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBGELIBOOT} ${LIBSA32} + +gptboot.o: ${SASRC}/ufsread.c + +.include <bsd.prog.mk> + +# XXX: clang integrated-as doesn't grok .codeNN directives yet +CFLAGS.gptldr.S= ${CLANG_NO_IAS} diff --git a/stand/i386/gptboot/Makefile.depend b/stand/i386/gptboot/Makefile.depend new file mode 100644 index 0000000..295be1a --- /dev/null +++ b/stand/i386/gptboot/Makefile.depend @@ -0,0 +1,19 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libmd \ + lib/libstand \ + sys/boot/geli \ + sys/boot/i386/btx/btx \ + sys/boot/i386/btx/lib \ + sys/boot/libstand32 \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/i386/gptboot/gptboot.8 b/stand/i386/gptboot/gptboot.8 new file mode 100644 index 0000000..a7afd81 --- /dev/null +++ b/stand/i386/gptboot/gptboot.8 @@ -0,0 +1,245 @@ +.\" Copyright (c) 2013 Warren Block +.\" 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$ +.\" +.Dd February 5, 2014 +.Dt GPTBOOT 8 +.Os +.Sh NAME +.Nm gptboot +.Nd GPT bootcode for UFS on BIOS-based computers +.Sh DESCRIPTION +.Nm +is used on BIOS-based computers to boot from a UFS partition on a +GPT-partitioned disk. +.Nm +is installed in a +.Cm freebsd-boot +partition with +.Xr gpart 8 . +.Sh IMPLEMENTATION NOTES +The GPT standard allows a variable number of partitions, but +.Nm +only boots from tables with 128 partitions or less. +.Sh PARTITION ATTRIBUTES +.Nm +checks and manages several attributes of GPT UFS partitions. +.Bl -tag -width ".Cm bootfailed" +.It Cm bootme +Attempt to boot from this partition. +If more than one partition has the +.Cm bootme +attribute set, +.Nm +will attempt to boot each one until successful. +.It Cm bootonce +Attempt to boot from this partition only one time. +Setting this attribute with +.Xr gpart 8 +automatically also sets the +.Cm bootme +attribute. +Multiple partitions may have the +.Cm bootonce +and +.Cm bootme +attributes set. +.It Cm bootfailed +The +.Cm bootfailed +attribute marks partitions that had the +.Cm bootonce +attribute set, but failed to boot. +This attribute is managed by the system. +See +.Sx "BOOTING" +and +.Sx "POST-BOOT ACTIONS" +below for details. +.El +.Sh USAGE +For normal usage, the user does not have to set or manage any of the +partition attributes. +.Nm +will boot from the first UFS partition found. +.Pp +The +.Cm bootonce +attribute can be used for testing an upgraded operating system on +an already-working computer. +The existing system partition is left untouched, and the new version +of the operating system to be tested is installed on another partition. +The +.Cm bootonce +attribute is set on that new test partition. +The next boot is attempted from the test partition. +Success or failure will be shown in the system log files. +After a successful boot of the test partition, a user script can check +the logs and change the +.Cm bootme +attributes so the test partition becomes the new system partition. +Because the +.Cm bootonce +attribute is cleared after an attempted boot, a failed boot will not +leave the system attempting to boot from a partition that will never +succeed. +Instead, the system will boot from the older, known-working operating +system that has not been modified. +If the +.Cm bootme +attribute is set on any partitions, booting will be attempted from them +first. +If no partitions with +.Cm bootme +attributes are found, booting will be attempted from the first UFS +partition found. +.Sh BOOTING +.Nm +first reads the partition table. +All +.Cm freebsd-ufs +partitions with only the +.Cm bootonce +attribute set, indicating a failed boot, are set to +.Cm bootfailed . +.Nm +then scans through all of the +.Cm freebsd-ufs +partitions. +Boot behavior depends on the combination of +.Cm bootme +and +.Cm bootonce +attributes set on those partitions. +.Bl -tag -width ".Cm bootonce + .Cm bootme" +.It Cm bootonce + Cm bootme +Highest priority: booting is attempted from each of the +.Cm freebsd-ufs +partitions with both of these attributes. +On each partition, the +.Cm bootme +attribute is removed and the boot attempted. +.It Cm bootme +Middle priority: booting is attempted from each of the +.Cm freebsd-ufs +partitions with the +.Cm bootme +attribute. +.El +.Pp +If neither +.Cm bootonce +nor +.Cm bootme +attributes are found on any partitions, booting is attempted from the +first +.Cm freebsd-ufs +partition on the disk. +.Sh POST-BOOT ACTIONS +The startup script +.Pa /etc/rc.d/gptboot +checks the attributes of +.Cm freebsd-ufs +partitions on all GPT disks. +Partitions with the +.Cm bootfailed +attribute generate a +.Dq boot from X failed +system log message. +Partitions with only the +.Cm bootonce +attribute, indicating a partition that successfully booted, generate a +.Dq boot from X succeeded +system log message. +The +.Cm bootfailed +attributes are cleared from all the partitions. +The +.Cm bootonce +attribute is cleared from the partition that successfully booted. +There is normally only one of these. +.Sh FILES +.Bl -tag -width /boot/gptboot -compact +.It Pa /boot/gptboot +bootcode binary +.It Pa /boot.config +parameters for the boot blocks +.Pq optional +.El +.Sh EXAMPLES +.Nm +is installed in a +.Cm freebsd-boot +partition, usually the first partition on the disk. +A +.Dq protective MBR +.Po +see +.Xr gpart 8 +.Pc +is typically installed in combination with +.Nm . +.Pp +Install +.Nm +on the +.Pa ada0 +drive: +.Bd -literal -offset indent +gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 ada0 +.Ed +.Pp +.Nm +can also be installed without the PMBR: +.Bd -literal -offset indent +gpart bootcode -p /boot/gptboot -i 1 ada0 +.Ed +.Pp +Set the +.Cm bootme +attribute for partition 2: +.Bd -literal -offset indent +gpart set -a bootme -i 2 ada0 +.Ed +.Pp +Set the +.Cm bootonce +attribute for partition 2, automatically also setting the +.Cm bootme +attribute: +.Bd -literal -offset indent +gpart set -a bootonce -i 2 ada0 +.Ed +.Sh SEE ALSO +.Xr boot.config 5 , +.Xr rc.conf 5 , +.Xr boot 8 , +.Xr gpart 8 +.Sh HISTORY +.Nm +appeared in FreeBSD 7.1. +.Sh AUTHORS +This manual page written by +.An Warren Block Aq wblock@FreeBSD.org . diff --git a/stand/i386/gptboot/gptboot.c b/stand/i386/gptboot/gptboot.c new file mode 100644 index 0000000..dd06f0c --- /dev/null +++ b/stand/i386/gptboot/gptboot.c @@ -0,0 +1,648 @@ +/*- + * 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 <sys/gpt.h> +#include <sys/dirent.h> +#include <sys/reboot.h> + +#include <machine/bootinfo.h> +#include <machine/elf.h> +#include <machine/pc/bios.h> +#include <machine/psl.h> + +#include <stdarg.h> + +#include <a.out.h> + +#include <btxv86.h> + +#include "bootargs.h" +#include "lib.h" +#include "rbx.h" +#include "drv.h" +#include "util.h" +#include "cons.h" +#include "gpt.h" +#include "paths.h" + +#define ARGS 0x900 +#define NOPT 14 +#define NDEV 3 +#define MEM_BASE 0x12 +#define MEM_EXT 0x15 + +#define DRV_HARD 0x80 +#define DRV_MASK 0x7f + +#define TYPE_AD 0 +#define TYPE_DA 1 +#define TYPE_MAXHARD TYPE_DA +#define TYPE_FD 2 + +extern uint32_t _end; + +static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; +static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ +static const unsigned char flags[NOPT] = { + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_MUTE, + RBX_NOINTR, + RBX_PAUSE, + RBX_QUIET, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_VERBOSE +}; +uint32_t opts; + +static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; +static const unsigned char dev_maj[NDEV] = {30, 4, 2}; + +static struct dsk dsk; +static char kname[1024]; +static int comspeed = SIOSPD; +static struct bootinfo bootinfo; +#ifdef LOADER_GELI_SUPPORT +static struct geli_boot_args geliargs; +#endif + +static vm_offset_t high_heap_base; +static uint32_t bios_basemem, bios_extmem, high_heap_size; + +static struct bios_smap smap; + +/* + * The minimum amount of memory to reserve in bios_extmem for the heap. + */ +#define HEAP_MIN (3 * 1024 * 1024) + +static char *heap_next; +static char *heap_end; + +void exit(int); +static void load(void); +static int parse_cmds(char *, int *); +static int dskread(void *, daddr_t, unsigned); +void *malloc(size_t n); +void free(void *ptr); +#ifdef LOADER_GELI_SUPPORT +static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, + size_t bytes); +#endif + +void * +malloc(size_t n) +{ + char *p = heap_next; + if (p + n > heap_end) { + printf("malloc failure\n"); + for (;;) + ; + /* NOTREACHED */ + return (0); + } + heap_next += n; + return (p); +} + +void +free(void *ptr) +{ + + return; +} + +#include "ufsread.c" +#include "gpt.c" +#ifdef LOADER_GELI_SUPPORT +#include "geliboot.c" +static char gelipw[GELI_PW_MAXLEN]; +static struct keybuf *gelibuf; +#endif + +static inline int +xfsread(ufs_ino_t inode, void *buf, size_t nbyte) +{ + + if ((size_t)fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return (-1); + } + return (0); +} + +static void +bios_getmem(void) +{ + uint64_t size; + + /* Parse system memory map */ + v86.ebx = 0; + do { + v86.ctl = V86_FLAGS; + v86.addr = MEM_EXT; /* int 0x15 function 0xe820*/ + v86.eax = 0xe820; + v86.ecx = sizeof(struct bios_smap); + v86.edx = SMAP_SIG; + v86.es = VTOPSEG(&smap); + v86.edi = VTOPOFF(&smap); + v86int(); + if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) + break; + /* look for a low-memory segment that's large enough */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && + (smap.length >= (512 * 1024))) + bios_basemem = smap.length; + /* look for the first segment in 'extended' memory */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { + bios_extmem = smap.length; + } + + /* + * Look for the largest segment in 'extended' memory beyond + * 1MB but below 4GB. + */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && + (smap.base < 0x100000000ull)) { + size = smap.length; + + /* + * If this segment crosses the 4GB boundary, truncate it. + */ + if (smap.base + size > 0x100000000ull) + size = 0x100000000ull - smap.base; + + if (size > high_heap_size) { + high_heap_size = size; + high_heap_base = smap.base; + } + } + } while (v86.ebx != 0); + + /* Fall back to the old compatibility function for base memory */ + if (bios_basemem == 0) { + v86.ctl = 0; + v86.addr = 0x12; /* int 0x12 */ + v86int(); + + bios_basemem = (v86.eax & 0xffff) * 1024; + } + + /* Fall back through several compatibility functions for extended memory */ + if (bios_extmem == 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe801*/ + v86.eax = 0xe801; + v86int(); + if (!(v86.efl & 1)) { + bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; + } + } + if (bios_extmem == 0) { + v86.ctl = 0; + v86.addr = 0x15; /* int 0x15 function 0x88*/ + v86.eax = 0x8800; + v86int(); + bios_extmem = (v86.eax & 0xffff) * 1024; + } + + /* + * If we have extended memory and did not find a suitable heap + * region in the SMAP, use the last 3MB of 'extended' memory as a + * high heap candidate. + */ + if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { + high_heap_size = HEAP_MIN; + high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; + } +} + +static int +gptinit(void) +{ + + if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { + printf("%s: unable to load GPT\n", BOOTPROG); + return (-1); + } + if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { + printf("%s: no UFS partition was found\n", BOOTPROG); + return (-1); + } +#ifdef LOADER_GELI_SUPPORT + if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end - + gpttable[curent].ent_lba_start)) == 0) { + if (geli_havekey(&dsk) != 0 && geli_passphrase(&gelipw, + dsk.unit, 'p', curent + 1, &dsk) != 0) { + printf("%s: unable to decrypt GELI key\n", BOOTPROG); + return (-1); + } + } +#endif + + dsk_meta = 0; + return (0); +} + +int +main(void) +{ + char cmd[512], cmdtmp[512]; + ssize_t sz; + int autoboot, dskupdated; + ufs_ino_t ino; + + dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); + + bios_getmem(); + + if (high_heap_size > 0) { + heap_end = PTOV(high_heap_base + high_heap_size); + heap_next = PTOV(high_heap_base); + } else { + heap_next = (char *)dmadat + sizeof(*dmadat); + heap_end = (char *)PTOV(bios_basemem); + } + + v86.ctl = V86_FLAGS; + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + dsk.drive = *(uint8_t *)PTOV(ARGS); + dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; + dsk.unit = dsk.drive & DRV_MASK; + dsk.part = -1; + dsk.start = 0; + bootinfo.bi_version = BOOTINFO_VERSION; + bootinfo.bi_size = sizeof(bootinfo); + bootinfo.bi_basemem = bios_basemem / 1024; + bootinfo.bi_extmem = bios_extmem / 1024; + bootinfo.bi_memsizes_valid++; + bootinfo.bi_bios_dev = dsk.drive; + +#ifdef LOADER_GELI_SUPPORT + geli_init(); +#endif + /* Process configuration file */ + + if (gptinit() != 0) + return (-1); + + autoboot = 1; + *cmd = '\0'; + + for (;;) { + *kname = '\0'; + if ((ino = lookup(PATH_CONFIG)) || + (ino = lookup(PATH_DOTCONFIG))) { + sz = fsread(ino, cmd, sizeof(cmd) - 1); + cmd[(sz < 0) ? 0 : sz] = '\0'; + } + if (*cmd != '\0') { + memcpy(cmdtmp, cmd, sizeof(cmdtmp)); + if (parse_cmds(cmdtmp, &dskupdated)) + break; + if (dskupdated && gptinit() != 0) + break; + if (!OPT_CHECK(RBX_QUIET)) + printf("%s: %s", PATH_CONFIG, cmd); + *cmd = '\0'; + } + + if (autoboot && keyhit(3)) { + if (*kname == '\0') + memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); + break; + } + autoboot = 0; + + /* + * Try to exec stage 3 boot loader. If interrupted by a + * keypress, or in case of failure, try to load a kernel + * directly instead. + */ + if (*kname != '\0') + load(); + memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); + load(); + memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); + load(); + gptbootfailed(&dsk); + if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) + break; + dsk_meta = 0; + } + + /* Present the user with the boot2 prompt. */ + + for (;;) { + if (!OPT_CHECK(RBX_QUIET)) { + printf("\nFreeBSD/x86 boot\n" + "Default: %u:%s(%up%u)%s\n" + "boot: ", + dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, + dsk.part, kname); + } + if (ioctrl & IO_SERIAL) + sio_flush(); + *cmd = '\0'; + if (keyhit(0)) + getstr(cmd, sizeof(cmd)); + else if (!OPT_CHECK(RBX_QUIET)) + putchar('\n'); + if (parse_cmds(cmd, &dskupdated)) { + putchar('\a'); + continue; + } + if (dskupdated && gptinit() != 0) + continue; + load(); + } + /* NOTREACHED */ +} + +/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ +void +exit(int x) +{ +} + +static void +load(void) +{ + union { + struct exec ex; + Elf32_Ehdr eh; + } hdr; + static Elf32_Phdr ep[2]; + static Elf32_Shdr es[2]; + caddr_t p; + ufs_ino_t ino; + uint32_t addr, x; + int fmt, i, j; + + if (!(ino = lookup(kname))) { + if (!ls) { + printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, + kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, + dsk.part); + } + return; + } + if (xfsread(ino, &hdr, sizeof(hdr))) + return; + if (N_GETMAGIC(hdr.ex) == ZMAGIC) + fmt = 0; + else if (IS_ELF(hdr.eh)) + fmt = 1; + else { + printf("Invalid %s\n", "format"); + return; + } + if (fmt == 0) { + addr = hdr.ex.a_entry & 0xffffff; + p = PTOV(addr); + fs_off = PAGE_SIZE; + if (xfsread(ino, p, hdr.ex.a_text)) + return; + p += roundup2(hdr.ex.a_text, PAGE_SIZE); + if (xfsread(ino, p, hdr.ex.a_data)) + return; + p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + p += sizeof(hdr.ex.a_syms); + if (hdr.ex.a_syms) { + if (xfsread(ino, p, hdr.ex.a_syms)) + return; + p += hdr.ex.a_syms; + if (xfsread(ino, p, sizeof(int))) + return; + x = *(uint32_t *)p; + p += sizeof(int); + x -= sizeof(int); + if (xfsread(ino, p, x)) + return; + p += x; + } + } else { + fs_off = hdr.eh.e_phoff; + for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { + if (xfsread(ino, ep + j, sizeof(ep[0]))) + return; + if (ep[j].p_type == PT_LOAD) + j++; + } + for (i = 0; i < 2; i++) { + p = PTOV(ep[i].p_paddr & 0xffffff); + fs_off = ep[i].p_offset; + if (xfsread(ino, p, ep[i].p_filesz)) + return; + } + p += roundup2(ep[1].p_memsz, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { + fs_off = hdr.eh.e_shoff + sizeof(es[0]) * + (hdr.eh.e_shstrndx + 1); + if (xfsread(ino, &es, sizeof(es))) + return; + for (i = 0; i < 2; i++) { + memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + p += sizeof(es[i].sh_size); + fs_off = es[i].sh_offset; + if (xfsread(ino, p, es[i].sh_size)) + return; + p += es[i].sh_size; + } + } + addr = hdr.eh.e_entry & 0xffffff; + } + bootinfo.bi_esymtab = VTOP(p); + bootinfo.bi_kernelname = VTOP(kname); + bootinfo.bi_bios_dev = dsk.drive; +#ifdef LOADER_GELI_SUPPORT + geliargs.size = sizeof(geliargs); + explicit_bzero(gelipw, sizeof(gelipw)); + gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); + geli_fill_keybuf(gelibuf); + geliargs.notapw = '\0'; + geliargs.keybuf_sentinel = KEYBUF_SENTINEL; + geliargs.keybuf = gelibuf; +#endif + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), + KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo) +#ifdef LOADER_GELI_SUPPORT + , geliargs +#endif + ); +} + +static int +parse_cmds(char *cmdstr, int *dskupdated) +{ + char *arg = cmdstr; + char *ep, *p, *q; + const char *cp; + unsigned int drv; + int c, i, j; + + *dskupdated = 0; + while ((c = *arg++)) { + if (c == ' ' || c == '\t' || c == '\n') + continue; + for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); + ep = p; + if (*p) + *p++ = 0; + if (c == '-') { + while ((c = *arg++)) { + if (c == 'P') { + if (*(uint8_t *)PTOV(0x496) & 0x10) { + cp = "yes"; + } else { + opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); + cp = "no"; + } + printf("Keyboard: %s\n", cp); + continue; + } else if (c == 'S') { + j = 0; + while ((unsigned int)(i = *arg++ - '0') <= 9) + j = j * 10 + i; + if (j > 0 && i == -'0') { + comspeed = j; + break; + } + /* Fall through to error below ('S' not in optstr[]). */ + } + for (i = 0; c != optstr[i]; i++) + if (i == NOPT - 1) + return -1; + opts ^= OPT_SET(flags[i]); + } + ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : + OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; + if (ioctrl & IO_SERIAL) { + if (sio_init(115200 / comspeed) != 0) + ioctrl &= ~IO_SERIAL; + } + } else { + for (q = arg--; *q && *q != '('; q++); + if (*q) { + drv = -1; + if (arg[1] == ':') { + drv = *arg - '0'; + if (drv > 9) + return (-1); + arg += 2; + } + if (q - arg != 2) + return -1; + for (i = 0; arg[0] != dev_nm[i][0] || + arg[1] != dev_nm[i][1]; i++) + if (i == NDEV - 1) + return -1; + dsk.type = i; + arg += 3; + dsk.unit = *arg - '0'; + if (arg[1] != 'p' || dsk.unit > 9) + return -1; + arg += 2; + dsk.part = *arg - '0'; + if (dsk.part < 1 || dsk.part > 9) + return -1; + arg++; + if (arg[0] != ')') + return -1; + arg++; + if (drv == -1) + drv = dsk.unit; + dsk.drive = (dsk.type <= TYPE_MAXHARD + ? DRV_HARD : 0) + drv; + *dskupdated = 1; + } + if ((i = ep - arg)) { + if ((size_t)i >= sizeof(kname)) + return -1; + memcpy(kname, arg, i + 1); + } + } + arg = p; + } + return 0; +} + +static int +dskread(void *buf, daddr_t lba, unsigned nblk) +{ + int err; + + err = drvread(&dsk, buf, lba + dsk.start, nblk); + +#ifdef LOADER_GELI_SUPPORT + if (err == 0 && is_geli(&dsk) == 0) { + /* Decrypt */ + if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE)) + return (err); + } +#endif + + return (err); +} + +#ifdef LOADER_GELI_SUPPORT +/* + * Read function compartible with the ZFS callback, required to keep the GELI + * Implementation the same for both UFS and ZFS + */ +static int +vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes) +{ + char *p; + daddr_t lba; + unsigned int nb; + struct dsk *dskp = (struct dsk *) priv; + + if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) + return (-1); + + p = buf; + lba = off / DEV_BSIZE; + lba += dskp->start; + + while (bytes > 0) { + nb = bytes / DEV_BSIZE; + if (nb > VBLKSIZE / DEV_BSIZE) + nb = VBLKSIZE / DEV_BSIZE; + if (drvread(dskp, dmadat->blkbuf, lba, nb)) + return (-1); + memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE); + p += nb * DEV_BSIZE; + lba += nb; + bytes -= nb * DEV_BSIZE; + } + + return (0); +} +#endif /* LOADER_GELI_SUPPORT */ diff --git a/stand/i386/gptboot/gptldr.S b/stand/i386/gptboot/gptldr.S new file mode 100644 index 0000000..088122f --- /dev/null +++ b/stand/i386/gptboot/gptldr.S @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 2007 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin <jhb@FreeBSD.org> + * + * 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$ + * + * Partly from: src/sys/boot/i386/boot2/boot1.S 1.31 + */ + +/* Memory Locations */ + .set MEM_REL,0x700 # Relocation address + .set MEM_ARG,0x900 # Arguments + .set MEM_ORG,0x7c00 # Origin + .set MEM_BUF,0x8cec # Load area + .set MEM_BTX,0x9000 # BTX start + .set MEM_JMP,0x9010 # BTX entry point + .set MEM_USR,0xa000 # Client start + .set BDA_BOOT,0x472 # Boot howto flag + +/* Misc. Constants */ + .set SIZ_PAG,0x1000 # Page size + .set SIZ_SEC,0x200 # Sector size + .set COPY_BLKS,0x8 # Number of blocks + # to copy for boot2 + .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be + # a multiple of 16 bytes + + .globl start + .code16 + +/* + * Copy BTX and boot2 to the right locations and start it all up. + */ + +/* + * Setup the segment registers to flat addressing (segment 0) and setup the + * stack to end just below the start of our code. + */ +start: xor %cx,%cx # Zero + mov %cx,%es # Address + mov %cx,%ds # data + mov %cx,%ss # Set up + mov $start,%sp # stack + +/* + * BTX is right after us at 'end'. We read the length of BTX out of + * its header to find boot2. We need to copy boot2 to MEM_USR and BTX + * to MEM_BTX. Since those might overlap, we have to copy boot2 + * backwards first and then copy BTX. We aren't sure exactly how long + * boot2 is, but it's currently under 128kB so we'll copy 4 blocks of 32kB + * each; this can be adjusted via COPY_BLK and COPY_BLK_SZ above. + */ + mov $end,%bx # BTX + mov 0xa(%bx),%si # Get BTX length and set + add %bx,%si # %si to start of boot2 + dec %si # Set %ds:%si to point at the + mov %si,%ax # last byte we want to copy + shr $4,%ax # from boot2, with %si made as + add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # small as possible. + and $0xf,%si # + mov %ax,%ds # + mov $MEM_USR/16,%ax # Set %es:(-1) to point at + add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # the last byte we + mov %ax,%es # want to copy boot2 into. + mov $COPY_BLKS,%bx # Copy COPY_BLKS 32k blocks +copyloop: + add $COPY_BLK_SZ,%si # Adjust %ds:%si to point at + mov %ds,%ax # the end of the next 32k to + sub $COPY_BLK_SZ/16,%ax # copy from boot2 + mov %ax,%ds + mov $COPY_BLK_SZ-1,%di # Adjust %es:%di to point at + mov %es,%ax # the end of the next 32k into + sub $COPY_BLK_SZ/16,%ax # which we want boot2 copied + mov %ax,%es + mov $COPY_BLK_SZ,%cx # Copy 32k + std + rep movsb + dec %bx + jnz copyloop + mov %cx,%ds # Reset %ds and %es + mov %cx,%es + mov $end,%bx # BTX + mov 0xa(%bx),%cx # Get BTX length and set + mov %bx,%si # %si to end of BTX + mov $MEM_BTX,%di # %di -> end of BTX at + add %cx,%si # MEM_BTX + add %cx,%di + dec %si + dec %di + rep movsb # Move BTX + cld # String ops inc +/* + * Enable A20 so we can access memory above 1 meg. + * Use the zero-valued %cx as a timeout for embedded hardware which do not + * have a keyboard controller. + */ +seta20: cli # Disable interrupts +seta20.1: dec %cx # Timeout? + jz seta20.3 # Yes + inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.1 # Yes + movb $0xd1,%al # Command: Write + outb %al,$0x64 # output port +seta20.2: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.2 # Yes + movb $0xdf,%al # Enable + outb %al,$0x60 # A20 +seta20.3: sti # Enable interrupts + +/* + * Save drive number from BIOS so boot2 can see it and start BTX. + */ + movb %dl,MEM_ARG + jmp MEM_JMP # Start BTX +end: |