diff -ruN 6.2-release/src/sys/boot/common/boot.c 6.2/src/sys/boot/common/boot.c --- 6.2-release/src/sys/boot/common/boot.c Thu May 19 17:03:01 2005 +++ 6.2/src/sys/boot/common/boot.c Thu Mar 1 10:09:05 2007 @@ -152,7 +152,17 @@ cp = getenv("autoboot_delay"); if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) - autoboot(-1, NULL); /* try to boot automatically */ + /* try to boot automatically */ + if (autoboot(-1, NULL) != CMD_OK && getenv("nodefaultboot") != NULL) { + struct bootblk_command **cmdp; + SET_FOREACH(cmdp, Xcommand_set) { + if (!strcmp("reboot", (*cmdp)->c_name)) { + printf("No bootfile specified, rebooting ...\n"); + ((*cmdp)->c_fn)(1, NULL); + } + } + + } } int @@ -248,8 +258,10 @@ /* * Try $bootfile, then try our builtin default */ - if ((spec = getenv("bootfile")) == NULL) - spec = default_bootfiles; + if ((spec = getenv("bootfile")) == NULL) { + if (getenv("nodefaultboot") == NULL) + spec = default_bootfiles; + } while ((try > 0) && (spec != NULL)) { spec = strchr(spec, ';'); diff -ruN 6.2-release/src/sys/boot/common/interp_forth.c 6.2/src/sys/boot/common/interp_forth.c --- 6.2-release/src/sys/boot/common/interp_forth.c Mon Aug 25 17:30:41 2003 +++ 6.2/src/sys/boot/common/interp_forth.c Thu Mar 1 10:09:05 2007 @@ -258,10 +258,12 @@ ficlSetEnv(bf_sys, "loader_version", (bootprog_rev[0] - '0') * 10 + (bootprog_rev[2] - '0')); - /* try to load and run init file if present */ - if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { - (void)ficlExecFD(bf_vm, fd); - close(fd); + if (getenv("noforthinit") == NULL) { + /* try to load and run init file if present */ + if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { + (void)ficlExecFD(bf_vm, fd); + close(fd); + } } /* Do this last, so /boot/boot.4th can change it */ diff -ruN 6.2-release/src/sys/boot/common/loader.8 6.2/src/sys/boot/common/loader.8 --- 6.2-release/src/sys/boot/common/loader.8 Thu Dec 21 05:43:02 2006 +++ 6.2/src/sys/boot/common/loader.8 Tue Dec 12 15:54:55 2006 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/sys/boot/common/loader.8,v 1.82.2.5.2.1 2006/12/21 12:43:02 yar Exp $ +.\" $FreeBSD: src/sys/boot/common/loader.8,v 1.82.2.6 2006/12/01 08:06:42 yar Exp $ .\" .Dd November 29, 2006 .Dt LOADER 8 diff -ruN 6.2-release/src/sys/boot/common/module.c 6.2/src/sys/boot/common/module.c --- 6.2-release/src/sys/boot/common/module.c Mon Jan 23 07:33:53 2006 +++ 6.2/src/sys/boot/common/module.c Thu Mar 1 10:09:05 2007 @@ -633,6 +633,9 @@ if (*name == 0) return(strdup(name)); + if (getenv("nomodsearch") != NULL) + return(strdup(name)); + if (file_havepath(name)) { /* Qualified, so just see if it exists */ if (stat(name, &sb) == 0) diff -ruN 6.2-release/src/sys/boot/ficl/loader.c 6.2/src/sys/boot/ficl/loader.c --- 6.2-release/src/sys/boot/ficl/loader.c Tue Nov 30 04:35:30 2004 +++ 6.2/src/sys/boot/ficl/loader.c Thu Mar 1 17:12:53 2007 @@ -419,7 +419,22 @@ mode = stackPopINT(pVM->pStack); /* get mode */ count = stackPopINT(pVM->pStack); /* get count */ - ptr = stackPopPtr(pVM->pStack); /* get ptr */ + + /* + * XXX Gruesome Emulab hack to allow us to run older Forth scripts. + * If it appears that there is no mode argument on the stack, assume + * mode 0 (RO) and shift the other arguments accordingly. + */ + if (getenv("forth_bc")) { + if ((mode < 0 || mode > 3) && + (count < 0 || count > (64*1024))) { + ptr = (char *)count; + count = mode; + mode = 0; + } else + ptr = stackPopPtr(pVM->pStack); + } else + ptr = stackPopPtr(pVM->pStack); /* get ptr */ if ((count < 0) || (ptr == NULL)) { stackPushINT(pVM->pStack, -1); diff -ruN 6.2-release/src/sys/boot/i386/Makefile 6.2/src/sys/boot/i386/Makefile --- 6.2-release/src/sys/boot/i386/Makefile Mon Dec 8 12:02:06 2003 +++ 6.2/src/sys/boot/i386/Makefile Thu Mar 1 10:09:05 2007 @@ -5,4 +5,9 @@ # special boot programs, 'self-extracting boot2+loader' SUBDIR+= pxeldr +.include <${.CURDIR}/Makefile.inc> +.if defined(TESTBED) +SUBDIR+= emuboot +.endif + .include diff -ruN 6.2-release/src/sys/boot/i386/Makefile.inc 6.2/src/sys/boot/i386/Makefile.inc --- 6.2-release/src/sys/boot/i386/Makefile.inc Wed Oct 25 09:03:29 2006 +++ 6.2/src/sys/boot/i386/Makefile.inc Thu Mar 1 13:34:55 2007 @@ -9,6 +9,52 @@ -mno-mmx -mno-3dnow -mno-sse -mno-sse2 LDFLAGS+= -nostdlib +# +# Force everything to use the serial console +# +FORCE_SERIAL_CONSOLE= 1 +BTX_SERIAL= 1 +BOOT_PXELDR_ALWAYS_SERIAL= 1 + +# +# Default console speed to 115200. +# +BOOT_COMCONSOLE_SPEED= 115200 + +# +# To use serial port 2 rather than 1 (for DETER) +# +#BOOT_COMCONSOLE_PORT= 0x2f8 + +# +# And use TFTP instead of NFS. +# +LOADER_TFTP_SUPPORT := 1 +CFLAGS := ${CFLAGS:S/LOADER_NFS_SUPPORT/LOADER_TFTP_SUPPORT/} +CFLAGS += -DPXENFSROOTPATH=\"/tftpboot\" -DNO_NFS_SUPPORT + +# +# This just adds extra TFTP lookups for .split and .split.gz files +# +LOADER_NO_SPLIT_SUPPORT := 1 +CFLAGS := ${CFLAGS:S/-DLOADER_SPLIT_SUPPORT//} + +# +# And add a TESTBED define for random stuff. +# +TESTBED = 1 +CFLAGS+= -DTESTBED + +# +# Do not prompt for input in Emulab pxeboot (sometimes serial lines can +# produce random input that will cause pxeboot to go into interactive +# mode when you don't really want it. +# +#CFLAGS+= -DNONINTERACTIVE + +# XXX do we need this? +.MAKEFLAGS: LOADER_NO_NFS_SUPPORT=1 LOADER_NO_SPLIT_SUPPORT=1 + .if ${MACHINE_ARCH} == "amd64" CFLAGS+= -m32 -march=i386 LDFLAGS+= -m elf_i386_fbsd diff -ruN 6.2-release/src/sys/boot/i386/boot2/boot2.c 6.2/src/sys/boot/i386/boot2/boot2.c --- 6.2-release/src/sys/boot/i386/boot2/boot2.c Wed Feb 15 08:08:51 2006 +++ 6.2/src/sys/boot/i386/boot2/boot2.c Thu Mar 1 10:09:05 2007 @@ -14,7 +14,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.72.2.4 2006/02/15 15:08:51 ru Exp $"); +__FBSDID("$FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.72.2.5 2006/11/27 14:49:38 ru Exp $"); #include #include @@ -79,7 +79,7 @@ #define PATH_KERNEL "/boot/kernel/kernel" #define ARGS 0x900 -#define NOPT 12 +#define NOPT 14 #define NDEV 3 #define MEM_BASE 0x12 #define MEM_EXT 0x15 @@ -99,12 +99,14 @@ extern uint32_t _end; -static const char optstr[NOPT] = "DhaCgmnpqrsv"; /* Also 'P', 'S' */ +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, @@ -132,7 +134,11 @@ static uint32_t opts; static int comspeed = SIOSPD; static struct bootinfo bootinfo; +#ifdef FORCE_SERIAL_CONSOLE +static uint8_t ioctrl = (IO_SERIAL|IO_KEYBOARD); +#else static uint8_t ioctrl = IO_KEYBOARD; +#endif void exit(int); static void load(void); @@ -332,7 +338,7 @@ return; } if (fmt == 0) { - addr = hdr.ex.a_entry; + addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); fs_off = PAGE_SIZE; if (xfsread(ino, p, hdr.ex.a_text)) @@ -366,7 +372,7 @@ j++; } for (i = 0; i < 2; i++) { - p = PTOV(ep[i].p_paddr); + p = PTOV(ep[i].p_paddr & 0xffffff); fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; @@ -387,7 +393,7 @@ p += es[i].sh_size; } } - addr = hdr.eh.e_entry; + addr = hdr.eh.e_entry & 0xffffff; } bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); diff -ruN 6.2-release/src/sys/boot/i386/btx/btx/btx.S 6.2/src/sys/boot/i386/btx/btx/btx.S --- 6.2-release/src/sys/boot/i386/btx/btx/btx.S Thu Dec 7 15:30:22 2006 +++ 6.2/src/sys/boot/i386/btx/btx/btx.S Thu Mar 1 10:09:05 2007 @@ -12,7 +12,7 @@ * warranties of merchantability and fitness for a particular * purpose. * - * $FreeBSD: src/sys/boot/i386/btx/btx/btx.S,v 1.38.2.1.2.1 2006/12/07 22:30:22 jhb Exp $ + * $FreeBSD: src/sys/boot/i386/btx/btx/btx.S,v 1.38.2.2 2006/12/07 22:26:51 jhb Exp $ */ /* @@ -56,6 +56,9 @@ */ .set SYS_EXIT,0x0 # Exit .set SYS_EXEC,0x1 # Exec +#ifdef TESTBED + .set SYS_RESTART,0x2 # Restart from real mode +#endif /* * V86 constants. */ @@ -262,10 +265,17 @@ movl %eax,%cr0 # paging xorl %ecx,%ecx # Zero movl %ecx,%cr3 # Flush TLB +#ifndef TESTBED +/* + * XXX this instruction causes a CPU reset. That is fine if you + * XXX are doing an exit, but if you are doing our restart it is bad! + * + */ /* * Restore the GDT in case we caught a kernel trap. */ lgdt gdtdesc # Set GDT +#endif /* * To 16 bits. */ @@ -293,6 +303,13 @@ * Reboot or await reset. */ sti # Enable interrupts +#ifdef TESTBED + testb $0x2,btx_hdr+0x7 # Restart? + jz exit.25 # No + andb $~0x3,btx_hdr+0x7 # clear flags in case of trap + call *%bp # Jump to magic location +exit.25: +#endif testb $0x1,btx_hdr+0x7 # Reboot? exit.3: jz exit.3 # No movw $0x1234, BDA_BOOT # Do a warm boot @@ -841,7 +858,19 @@ /* * System Call. */ -intx30: cmpl $SYS_EXEC,%eax # Exec system call? +intx30: +#ifdef TESTBED + cmpl $SYS_RESTART,%eax # Restart system call? + jne intx30.05 # No + orb $0x2,%ss:btx_hdr+0x7 # Magic exit flag + movl $MEM_USR,%eax # Grab + addl 0xc(%esp,1),%eax # target address + leal 0x4(%eax),%esp # from user stack + popl %ebp # Stash it in ebp + jmp exit # Exit +intx30.05: +#endif + cmpl $SYS_EXEC,%eax # Exec system call? jne intx30.1 # No pushl %ss # Set up popl %es # all diff -ruN 6.2-release/src/sys/boot/i386/btx/lib/Makefile 6.2/src/sys/boot/i386/btx/lib/Makefile --- 6.2-release/src/sys/boot/i386/btx/lib/Makefile Tue Dec 21 01:47:14 2004 +++ 6.2/src/sys/boot/i386/btx/lib/Makefile Thu Mar 1 10:24:44 2007 @@ -3,7 +3,7 @@ PROG= crt0.o INTERNALPROG= NO_MAN= -SRCS= btxcsu.s btxsys.s btxv86.s +SRCS= btxcsu.s btxsys.S btxv86.s LDFLAGS=-Wl,-r .include diff -ruN 6.2-release/src/sys/boot/i386/btx/lib/btxsys.S 6.2/src/sys/boot/i386/btx/lib/btxsys.S --- 6.2-release/src/sys/boot/i386/btx/lib/btxsys.S Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/btx/lib/btxsys.S Thu Mar 1 10:09:05 2007 @@ -0,0 +1,46 @@ +# +# 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: src/sys/boot/i386/btx/lib/btxsys.s,v 1.2 1999/08/28 00:40:07 peter Exp $ + +# +# BTX system calls. +# + +# +# Globals. +# + .global __exit + .global __exec +# +# Constants. +# + .set INT_SYS,0x30 # Interrupt number +# +# System call: exit +# +__exit: xorl %eax,%eax # BTX system + int $INT_SYS # call 0x0 +# +# System call: exec +# +__exec: movl $0x1,%eax # BTX system + int $INT_SYS # call 0x1 + +#ifdef TESTBED + .global __restart +__restart: movl $0x2,%eax # BTX system + int $INT_SYS # call 0x2 +#endif diff -ruN 6.2-release/src/sys/boot/i386/emuboot/Makefile 6.2/src/sys/boot/i386/emuboot/Makefile --- 6.2-release/src/sys/boot/i386/emuboot/Makefile Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/Makefile Thu Mar 1 13:38:01 2007 @@ -0,0 +1,138 @@ +# $FreeBSD: src/sys/boot/i386/loader/Makefile,v 1.41.2.8 2002/07/17 12:34:16 ru Exp $ + +LOADER= pxeboot +BASE= emuboot +PROG= ${LOADER} +#NOMAN= +STRIP= +NEWVERSWHAT= "BTX-based Emulab PXE boot loader" i386 +BINDIR?= /boot +INSTALLFLAGS= -b + +# architecture-specific loader code +SRCS= main.c conf.c emumain.c bootinfo.c multiboot.c diskboot.c groklilo.c +CFLAGS+= -DLOADER_TFTP_SUPPORT +#CFLAGS+= -DLOADER_NFS_SUPPORT + +.include <${.CURDIR}/../Makefile.inc> +.if defined(FORCE_SERIAL_CONSOLE) +M4FLAGS+= -DFORCE_SERIAL_CONSOLE +CFLAGS+= -DFORCE_SERIAL_CONSOLE +.endif + +# Enable PnP and ISA-PnP code. +HAVE_PNP= yes +HAVE_ISABUS= yes + +.if !defined(NOFORTH) +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.endif + +.if defined(LOADER_BZIP2_SUPPORT) +CFLAGS+= -DLOADER_BZIP2_SUPPORT +.endif +.if !defined(LOADER_NO_GZIP_SUPPORT) +CFLAGS+= -DLOADER_GZIP_SUPPORT +.endif +.if !defined(LOADER_NO_SPLIT_SUPPORT) +CFLAGS+= -DLOADER_SPLIT_SUPPORT +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common ${.CURDIR}/../loader +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I. + +# XXX loader is too big! +SRCS := ${SRCS:S/load_aout.c//} +SRCS := ${SRCS:S/load_elf64.c//} +SRCS := ${SRCS:S/load_elf64_obj.c//} +SRCS := ${SRCS:S/reloc_elf64.c//} + +CLEANFILES= vers.c vers.o ${BASE}.list ${BASE}.bin ${BASE}.sym ${BASE}.help + +CFLAGS+= -Wall +LDFLAGS= -static -Ttext 0x0 + +# i386 standalone support library +LIBI386= ${.OBJDIR}/../libi386/libi386.a +CFLAGS+= -I${.CURDIR}/.. + +# the location of libstand +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +# BTX components +CFLAGS+= -I${.CURDIR}/../btx/lib + +# Debug me! +#CFLAGS+= -g +#LDFLAGS+= -g + +# Pick up ../Makefile.inc early. +#.include + +all: ${LOADER} + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +${BASE}: ${BASE}.bin ${BTXLDR} ${BTXKERN} ${BTXCRT} ${BASE}.help + btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ + -b ${BTXKERN} ${BASE}.bin + +${BASE}.bin: ${BASE}.sym + cp ${.ALLSRC} ${.TARGET} + strip -R .comment -R .note ${.TARGET} + +${BASE}.help: help.common help.i386 + cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +# emuboot PXE wrapping stuff +ORG= 0x7c00 +LDR= ../pxeldr/pxeldr + +${LOADER}: ${LDR} ${BASE} + cat ${LDR} ${BASE} > ${.TARGET}.tmp + dd if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync + rm ${.TARGET}.tmp + +${LDR}: ${LDR}.o +.if ${OBJFORMAT} == aout + ${LD} -nostdlib -N -s -T ${ORG} -o ${LDR}.out ${LDR}.o + dd if=${LDR}.out of=${.TARGET} ibs=32 skip=1 +.else + ${LD} -N -e start -Ttext ${ORG} -o ${LDR}.out ${LDR}.o + objcopy -S -O binary ${LDR}.out ${.TARGET} +.endif + +${LDR}.o: ${LDR}.S + (cd ${.CURDIR}; ${M4} ${M4FLAGS} ${LDR}.S) | \ + ${AS} ${AFLAGS} -o ${.TARGET} + +install: + mv ${DESTDIR}${BINDIR}/pxeboot ${DESTDIR}${BINDIR}/pxeboot.old + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 emuboot ${DESTDIR}${BINDIR}/pxeboot + +#.include <${.CURDIR}/../Makefile.inc> + +# Cannot use ${OBJS} above this line +.include + +${BASE}.sym: ${OBJS} ${LIBI386} ${LIBSTAND} ${LIBFICL} vers.o + ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \ + ${LIBFICL} ${LIBI386} ${LIBSTAND} + +# If it's not there, don't consider it a target +.if exists(${.CURDIR}/../../../i386/include) +beforedepend ${OBJS}: machine + +machine: + ln -sf ${.CURDIR}/../../../i386/include machine + +.endif + +CLEANFILES+= machine diff -ruN 6.2-release/src/sys/boot/i386/emuboot/bootinfo.c 6.2/src/sys/boot/i386/emuboot/bootinfo.c --- 6.2-release/src/sys/boot/i386/emuboot/bootinfo.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/bootinfo.c Tue May 22 11:21:28 2007 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2000-2007 University of Utah and the Flux Group. + * All rights reserved. + * + * boot/bootinfo.c from the OSKit. + */ +#include +#include +#include +#include +#include + +#include "net.h" +#include "netif.h" + +#include "emuboot.h" +#include "bootwhat.h" + +static struct { + u_char header[HEADER_SIZE]; + boot_info_t boot_info; +} rpkt; + +/* + * A bug in libstand. open/close causes memory cooruption. + */ +static int +bootinfo_init() +{ + static int fd = -1; + + if (fd >= 0) + return fd; + + fd = open(NETDEV, 0); + if (fd < 0) { +#ifdef DEBUG + int err = errno; + printf("bootinfo: could not open net device %s err=%d\n", + NETDEV, err); + errno = err; +#endif + return -1; + } + return fd; +} + +static ssize_t +recvbootinfo(struct iodesc *d, void *pkt, size_t len, time_t tleft) +{ + struct udphdr *uh; + struct ip *ip; + + errno = 0; + len = readudp(d, pkt, len, tleft); + if (len == -1) + return (-1); + + uh = (struct udphdr *)pkt - 1; + ip = (struct ip *)uh - 1; + if (ip->ip_src.s_addr != rootip.s_addr || uh->uh_sport != d->destport) { +#ifdef DEBUG + printf("bootinfo reply not from server (%s/%d != %s/%d)\n", + inet_ntoa(ip->ip_src), ntohs(uh->uh_sport), + inet_ntoa(rootip), d->destport); +#endif + return (-1); + } + + /* + * Coming from our server and the right port, + * any other errors are fatal. + */ + if (len != sizeof(rpkt.boot_info) || + ! (rpkt.boot_info.opcode == BIOPCODE_BOOTWHAT_REPLY || + rpkt.boot_info.opcode == BIOPCODE_BOOTWHAT_ORDER)) { +#ifdef DEBUG + printf("bootinfo bogus reply from %s/%d, len=%d, opcode=%d\n", + inet_ntoa(ip->ip_src), ntohs(uh->uh_sport), + len, rpkt.boot_info.opcode); +#endif + errno = EINVAL; + return (-1); + } + + if (rpkt.boot_info.status != BISTAT_SUCCESS) { + printf("No bootinfo for us on server %s\n", + inet_ntoa(rootip)); + errno = EINVAL; + return (-1); + } + + return (len); +} + +int +bootinfo_getinfo(boot_what_t **boot_whatp) +{ + struct { + u_char header[HEADER_SIZE]; + boot_info_t boot_info; + } pkt; + struct iodesc *iodesc; + int rv, fd; + + fd = bootinfo_init(); + if (fd < 0) { + return errno; + } + + iodesc = socktodesc(fd); + if (iodesc == 0) { + return (ENODEV); + } + + memset(&pkt.boot_info, 0, sizeof(pkt.boot_info)); + pkt.boot_info.version = BIVERSION_CURRENT; + pkt.boot_info.opcode = BIOPCODE_BOOTWHAT_REQUEST; + + iodesc->myport = htons(BOOTWHAT_SRCPORT); + iodesc->destip = rootip; + iodesc->destport = htons(BOOTWHAT_DSTPORT); + iodesc->xid = 1; +#ifdef DEBUG + printf("bootinfo: request from %s/%d to ", + inet_ntoa(iodesc->myip), iodesc->myport); + printf("%s/%d\n", inet_ntoa(iodesc->destip), iodesc->destport); +#endif + + /* + * We give the server a little longer to respond here since the + * consequence of failure is likely to be a (multi-minute) reboot + * of the machine. + */ + rv = sendrecv_timo(iodesc, + sendudp, &pkt.boot_info, sizeof(pkt.boot_info), + recvbootinfo, &rpkt.boot_info, sizeof(rpkt.boot_info), + MINTMO, MAXTMO*2); + + if (rv == -1) { + if (errno == ETIMEDOUT) + printf("No reply from bootinfo server %s\n", + inet_ntoa(rootip)); + return (errno); + } + + /* + * Got a seemingly valid boot info packet that says what to do. + */ + *boot_whatp = (boot_what_t *) &rpkt.boot_info.data; + return 0; +} + +/* + * Check to see if bootinfo sent us a command packet. + */ +int +bootinfo_pollinfo(boot_what_t **boot_whatp) +{ + struct iodesc *iodesc; + int rv, fd; + + fd = bootinfo_init(); + if (fd < 0) { + return errno; + } + + iodesc = socktodesc(fd); + if (iodesc == 0) { + return (ENODEV); + } + + memset(&rpkt.boot_info, 0, sizeof(rpkt.boot_info)); + iodesc->myport = htons(BOOTWHAT_SRCPORT); + iodesc->destip = rootip; + iodesc->destport = htons(BOOTWHAT_SENDPORT); + iodesc->xid = 1; + errno = 0; + + rv = recvbootinfo(iodesc, + &rpkt.boot_info, sizeof(rpkt.boot_info), MINTMO); + + if (rv == -1) { + if (! errno) + errno = ETIMEDOUT; + return (errno); + } + + printf("pollinfo: Got one\n"); + + /* + * Got a seemingly valid boot info packet that says what to do. + */ + *boot_whatp = (boot_what_t *) &rpkt.boot_info.data; + return 0; +} + +void +bootinfo_showinfo(void) +{ + boot_what_t *boot_whatp; + + if (bootinfo_getinfo(&boot_whatp) != 0) + return; + + printf("Default boot:\n"); + switch (boot_whatp->type) { + + case BIBOOTWHAT_TYPE_MB: + printf("boot multiboot kernel `%s:%s'", + inet_ntoa(boot_whatp->what.mb.tftp_ip), + boot_whatp->what.mb.filename); + break; + + case BIBOOTWHAT_TYPE_PART: + printf("boot from main disk, partition %d", + boot_whatp->what.partition); + break; + + case BIBOOTWHAT_TYPE_SYSID: + printf("boot from main disk partition with sysid %d", + boot_whatp->what.sysid); + break; + + case BIBOOTWHAT_TYPE_WAIT: + printf("boot wait; waiting for bootinfo instructions\n"); + return; + + case BIBOOTWHAT_TYPE_MFS: + printf("boot from MFS %s", boot_whatp->what.mfs); + break; + + default: + printf("!? invalid action %d\n", boot_whatp->type); + return; + } + if (boot_whatp->cmdline[0]) + printf(" with cmdline `%s'", boot_whatp->cmdline); + printf("\n"); +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot/bootwhat.h 6.2/src/sys/boot/i386/emuboot/bootwhat.h --- 6.2-release/src/sys/boot/i386/emuboot/bootwhat.h Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/bootwhat.h Thu May 27 14:00:18 2004 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2001, 2003, 2004 University of Utah and the Flux Group. + * All rights reserved. + * + * boot/bootwhat.h from the OSKit. + */ + +#ifndef _OSKIT_BOOT_BOOTWHAT_H_ +#define _OSKIT_BOOT_BOOTWHAT_H_ + +#define BOOTWHAT_DSTPORT 6969 +#define BOOTWHAT_SRCPORT 9696 +#define BOOTWHAT_SENDPORT 6970 + +/* + * This is the structure we pass back and forth between pxeboot on a node + * and a server running on some other machine, that tells what to do. + * + * The structure below was changed, adding the version slot by splitting + * the opcode from an int into a short. Old clients conveniently look like a + * version zero client. The same was done for the "type" field, splitting + * that into "flags" and "type" shorts. + */ +#define MAX_BOOT_DATA 512 +#define MAX_BOOT_PATH 256 +#define MAX_BOOT_CMDLINE ((MAX_BOOT_DATA - MAX_BOOT_PATH) - 32) + +typedef struct { + short version; + short opcode; + int status; + char data[MAX_BOOT_DATA]; +} boot_info_t; + +/* Opcode */ +#define BIOPCODE_BOOTWHAT_REQUEST 1 /* What to boot request */ +#define BIOPCODE_BOOTWHAT_REPLY 2 /* What to boot reply */ +#define BIOPCODE_BOOTWHAT_ACK 3 /* Ack to Reply */ +#define BIOPCODE_BOOTWHAT_ORDER 4 /* Unsolicited command */ +#define BIOPCODE_BOOTWHAT_INFO 5 /* Request for bootinfo */ + +/* Version */ +#define BIVERSION_CURRENT 1 /* Old version is zero */ + +/* Status */ +#define BISTAT_SUCCESS 0 +#define BISTAT_FAIL 1 + +/* BOOTWHAT Reply */ +typedef struct boot_what { + short flags; + short type; + union { + /* + * Type is BIBOOTWHAT_TYPE_PART + * + * Specifies the partition number. + */ + int partition; + + /* + * Type is BIBOOTWHAT_TYPE_SYSID + * + * Specifies the PC BIOS filesystem type. + */ + int sysid; + + /* + * Type is BIBOOTWHAT_TYPE_MB + * + * Specifies a multiboot kernel pathway suitable for TFTP. + */ + struct { + struct in_addr tftp_ip; + char filename[MAX_BOOT_PATH]; + } mb; + + /* + * Type is BIBOOTWHAT_TYPE_MFS + * + * Specifies network path to MFS (boss:/tftpboot/frisbee) + * With no host spec, defaults to bootinfo server IP. + */ + char mfs[MAX_BOOT_PATH]; + } what; + /* + * Kernel and command line to pass to boot loader or multiboot kernel. + */ + char cmdline[1]; +} boot_what_t; + +/* What type of thing to boot */ +#define BIBOOTWHAT_TYPE_PART 1 /* Boot a partition number */ +#define BIBOOTWHAT_TYPE_SYSID 2 /* Boot a system ID */ +#define BIBOOTWHAT_TYPE_MB 3 /* Boot a multiboot image */ +#define BIBOOTWHAT_TYPE_WAIT 4 /* Wait, no boot until later */ +#define BIBOOTWHAT_TYPE_REBOOT 5 /* Reboot */ +#define BIBOOTWHAT_TYPE_AUTO 6 /* Do a bootinfo query */ +#define BIBOOTWHAT_TYPE_MFS 7 /* Boot an MFS from server:/path */ + +/* Flags */ +#define BIBOOTWHAT FLAGS_CMDLINE 0x01 /* Kernel to boot */ + +#endif /* _OSKIT_BOOT_BOOTWHAT_H_ */ diff -ruN 6.2-release/src/sys/boot/i386/emuboot/diskboot.c 6.2/src/sys/boot/i386/emuboot/diskboot.c --- 6.2-release/src/sys/boot/i386/emuboot/diskboot.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/diskboot.c Tue Sep 21 23:50:19 2004 @@ -0,0 +1,553 @@ +#include + +#include +#include +#include + +#include "btxv86.h" +#include "libi386/libi386.h" +#include "emuboot.h" +#include "bootwhat.h" +#include "bootstrap.h" + +/* + * Support for disk booting + */ + +#define DISKDEV 0x80 /* first BIOS hard drive */ + +static void *magicaddr = (void *)0x7C00; + +struct bios_mbr { + char bootcode[446]; + char partinfo[64]; /* 4 x bios_partition_info */ + unsigned short magic; +}; + +/* magic */ +#define BIOS_MAGIC 0xaa55 + +struct bios_partition_info { + unsigned char bootid; + unsigned char beghead; + unsigned char begsect; + unsigned char begcyl; + unsigned char sysid; + unsigned char endhead; + unsigned char endsect; + unsigned char endcyl; + unsigned long offset; + unsigned long numsectors; +}; + +/* bootable (active) bootid */ +#define BIOS_BOOTABLE 0x80 + +static struct bios_mbr diskmbr; +static char partbr[512]; +static int find_bootdisk(void); +static int load_mbr(int dieonerror); +static int check_mbr(void); +static void show_mbr(void); +static int bootdisk = -1; +static char bootdevice[] = "disk0:"; +static int diskdev = DISKDEV; + +void +set_bootdisk(int ndiskdev) +{ + if (bootdisk == -1 && find_bootdisk()) { + printf("can't find boot harddisk\n"); + return; + } + + if (ndiskdev >= 0 && ndiskdev != diskdev) { + int odiskdev = diskdev; + diskdev = ndiskdev; + if (find_bootdisk()) { + diskdev = odiskdev; + printf("can't set bootdisk to 0x%x, left as 0x%x\n", + ndiskdev, diskdev); + return; + } + } + if (ndiskdev != diskdev) + printf("boot disk is %s (0x%x)\n", bootdevice, diskdev); +} + +/* + * Locate the boot code biosdisk that corresponds to BIOS disk DISKDEV + */ +static int +find_bootdisk(void) +{ + bootdisk = bd_bios2unit(diskdev); + if (bootdisk >= 0) { + bootdevice[4] = bootdisk + '0'; + return 0; + } + + return -1; +} + +void +disk_showinfo(void) +{ + set_bootdisk(-1); + if (load_mbr(0) == 0) { + printf("Partitions, %s\n", bootdevice); + show_mbr(); + } +} + +/* + * Load the Master Boot Record using the BIOS. + */ +static int +load_mbr(int dieonerror) +{ + if (load_sector(0, &diskmbr) == 0 && check_mbr() == 0) + return 0; + + if (dieonerror) + panic("Could not load/verify MBR"); + return -1; +} + +/* + * Check sanity of the MBR. + */ +static int +check_mbr(void) +{ + struct bios_mbr *mbr; + struct bios_partition_info *entry; + int i; + + mbr = &diskmbr; +#ifdef DEBUG + printf("MBR@%p: magic=%x, partinfo@%p\n", mbr, mbr->magic, + mbr->partinfo); +#endif + if (mbr->magic != BIOS_MAGIC) { +#ifdef DEBUG + printf("MBR has bad magic (%x != %x)\n", + mbr->magic, BIOS_MAGIC); +#endif + return -1; + } + + entry = (struct bios_partition_info *) mbr->partinfo; + for (i = 0; i < 4; i++, entry++) { +#ifdef DEBUG + printf("%c%d: sysid=%d, offset=%lu, nsect=%lu\n", + entry->bootid==BIOS_BOOTABLE ? '*' : ' ', i+1, + entry->sysid, entry->offset, entry->numsectors); +#endif + if (entry->numsectors == 0) + continue; + + /* XXX sanity check fields */ + } + + return 0; +} + +static struct ptypes { + int sysid; + char *str; +} sysids[] = { + { 165, "FreeBSD" }, + { 131, "Linux" }, + { 130, "Linux swap" }, + { 7, "NTFS" }, + { 166, "OpenBSD" }, + { 0, "Unused" }, + { -1, "Unknown" } +}; + +static char * +ptypestr(int sysid) +{ + struct ptypes *pt = sysids; + + for (pt = sysids; pt->sysid >= 0; pt++) + if (pt->sysid == sysid) + break; + return (pt->str); +} + +static void +show_mbr(void) +{ + struct bios_partition_info *entry; + int i; + + entry = (struct bios_partition_info *) diskmbr.partinfo; + for (i = 0; i < 4; i++, entry++) { + if (entry->numsectors == 0) + continue; + printf("%c%d: sysid=%d (%s), offset=%lu, nsect=%lu\n", + entry->bootid==BIOS_BOOTABLE ? '*' : ' ', i+1, + entry->sysid, ptypestr(entry->sysid), + entry->offset, entry->numsectors); + } +} + +/* + * Copy the given sector contents into the magic load address, + * switch to 16bit/real mode, and then jump to the address. + * + * Note that we copy the sector into the memory previously occupied + * by the pxeldr, this way we should not be clobbering anything. + */ +static void +boot_from(void *buf) +{ + void __restart(void *) __attribute__((__noreturn__)); + + /* + * Shutdown PXE + */ + dev_cleanup(); + + i386_copyin(buf, (vm_offset_t)magicaddr, 512); + + /* + * FreeBSD's mbr, boot0 and boot1 all expect %dl to be set to + * the boot device when they are invoked. + * I don't know if this is a BIOS handoff feature or if it is + * a bug and everyone assumes it is a bit of PC lore. + * + * Anyway, we set it here and it makes it through the BTX intact. + */ + __asm __volatile("movb %0,%%dl" : : "m" (diskdev)); + + __restart(magicaddr); +} + +/* + * Boot from the MBR. As long as there is a MBR, and its intact, + * something good should happen (say, Lilo will appear). + */ +static void +boot_mbr(void) +{ + boot_from(&diskmbr); +} + +/* + * Load and boot the first sector of the indicated partition. + */ +static void +boot_partition(int pnum, struct bios_partition_info *ptab) +{ + if (load_sector((int)ptab->offset, partbr) != 0 || + ((struct bios_mbr *)partbr)->magic != BIOS_MAGIC) + panic("Could not load/verify partition %d boot record", pnum); + + boot_from(partbr); +} + +/* + * Simply load and boot the MBR right off the disk. + */ +void +boot_mbr_default(void) +{ + printf("Loading MBR and booting active partition\n"); + + (void) load_mbr(1); + boot_mbr(); +} + +/* + * Boot from a partition with a particular sysid. + * Search the table for the first non-empty partition of the given type. + * If the type does not exist, return non-zero. + */ +int +boot_mbr_sysid(int sysid) +{ + struct bios_partition_info *entry; + int partition; + + printf("Loading MBR and booting system ID %d\n", sysid); + + (void) load_mbr(1); + + /* + * Look for a non-empty partition that matches the one we want. + */ + entry = (struct bios_partition_info *)diskmbr.partinfo; + for (partition = 0; partition < 4; partition++, entry++) { + if (entry->numsectors == 0) + continue; + if (entry->sysid == sysid) + break; + } + if (partition == 4) { + printf("%d: sysid not found in any partition\n", sysid); + return 1; + } + + if (set_active(partition+1) != 0) + printf("WARNING: could not set active partition in MBR\n"); + boot_partition(partition+1, entry); + return 0; +} + +/* + * Boot from a particular partition. + * If the partition does not exist, return non-zero. + */ +int +boot_mbr_partition(int partition) +{ + struct bios_partition_info *entry; + + /* XXX hack: part:0 means boot through MBR */ + if (partition == 0) + boot_mbr_default(); + + printf("Loading MBR and booting system partition %d\n", partition); + + if (partition < 1 || partition > 4) { + printf("%d: invalid partition number\n", partition); + return 1; + } + + /* partition is 1-based, table is 0-based */ + partition--; + + (void) load_mbr(1); + + entry = ((struct bios_partition_info *)diskmbr.partinfo) + partition; + if (entry->numsectors == 0) { + printf("%d: non-existent partition\n", partition+1); + return 1; + } + + if (set_active(partition+1) != 0) + printf("WARNING: could not set active partition in MBR\n"); + boot_partition(partition+1, entry); + return 0; +} + +/* + * Return the sysid for a partition. + */ +int +partition_sysid(int partition, int *sysid) +{ + struct bios_partition_info *entry; + + if (partition < 1 || partition > 4) { + printf("%d: invalid partition number\n", partition); + return 1; + } + + /* partition is 1-based, table is 0-based */ + partition--; + + (void) load_mbr(1); + + entry = ((struct bios_partition_info *)diskmbr.partinfo) + partition; + if (entry->numsectors == 0) { + printf("%d: non-existent partition\n", partition+1); + return 1; + } + *sysid = entry->sysid; + return 0; +} + +int +load_sector(int sectno, void *buf) +{ + int fd, rv = 0; + + set_bootdisk(diskdev); + fd = open(bootdevice, 0); + if (fd >= 0) { + if (lseek(fd, (off_t)sectno * 512, SEEK_SET) < 0 || + read(fd, buf, 512) < 512) { + rv = errno; +#ifdef DEBUG + printf("short/failed read of sector %d, err=%x\n", + sectno, rv); +#endif + } + close(fd); + } else { + rv = errno; +#ifdef DEBUG + printf("failed open of %s, err=%x\n", bootdevice, rv); +#endif + } + +#ifdef DEBUG + printf("Got sector %d: magic=0x%x\n", + sectno, ((unsigned short *)buf)[255]); +#endif + return rv; +} + +#include + +/* + * Set the active partition in the disk MBR + */ +int +set_active(int apart) +{ + struct bios_partition_info *entry; + int i; + + if (apart < 1 || apart > 4) { + printf("set_active: invalid partition number %d\n", apart); + return 1; + } + + if (load_mbr(0) != 0) { + printf("set_active: could not load MBR\n"); + return 1; + } + + /* + * Already active + */ + entry = &((struct bios_partition_info *)diskmbr.partinfo)[apart-1]; + if (entry->bootid & BIOS_BOOTABLE) + return 0; + + /* + * Verify the desired partition and mark it as active + */ + if (entry->numsectors == 0) { + printf("set_active: emptry partition %d\n", apart); + return 1; + } + entry->bootid |= BIOS_BOOTABLE; + + /* + * Clear any other active indicator. + */ + apart--; + entry = (struct bios_partition_info *)diskmbr.partinfo; + for (i = 0; i < 4; i++, entry++) + if (i != apart && (entry->bootid & BIOS_BOOTABLE)) + entry->bootid &= ~BIOS_BOOTABLE; + + /* + * Write MBR back out. + * + * XXX we do this totally behind the back of the boot loader + * subsystem (biosdisk) since it doesn't support disk writes. + * Thus, this is the last thing you should do before jumping + * to the next level boot code. + * + * This code lifted from the biosdisk read code. + */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x300 | 1; + v86.ecx = 1; + v86.edx = diskdev; + v86.es = VTOPSEG(&diskmbr); + v86.ebx = VTOPOFF(&diskmbr); + v86int(); + if (v86.efl & 0x1) { + printf("set_active: could not write back MBR, eax=0x%x\n", + v86.eax); + return 1; + } + return 0; +} + +/* + * XXX for LILO support + */ + +/* + * Read the boot block for the indicated partition. + * Returns a pointer to our buffer on success, 0 on failure. + */ +void * +load_partition_bblock(int pnum) +{ + struct bios_partition_info *entry; + + if (load_mbr(0) != 0) + return 0; + + pnum--; + entry = ((struct bios_partition_info *)diskmbr.partinfo) + pnum; + if (load_sector((int)entry->offset, partbr) != 0 || + ((struct bios_mbr *)partbr)->magic != BIOS_MAGIC) { + printf("Could not load/verify partition %d boot record", pnum); + return 0; + } + + return partbr; +} + +/* + * Update a disk sector. + * Return 0 on success, non-zero otherwise. + * + * XXX we do this totally behind the back of the boot loader + * subsystem (biosdisk) since it doesn't support disk writes. + */ +int +save_sector(int sectno, void *buf) +{ + u_int cyl, hd, sec, bpc, dblk; + + dblk = sectno; + + /* + * Get the disk geometry + */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x800; + v86.edx = diskdev; + v86int(); + + if (v86.efl & 0x1) { +#ifdef DEBUG + printf("save_sector: cannot get disk geometry\n"); +#endif + return 1; + } + + hd = ((v86.edx & 0xff00) >> 8) + 1; + sec = v86.ecx & 0x3f; + bpc = sec * hd; + + cyl = dblk / bpc; + if (cyl > 1023) { + printf("save_sector: cannot do cyl > 1024\n"); + return 1; + } + + dblk %= bpc; + hd = dblk / sec; + sec = dblk % sec; + sec++; + + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x300 | 1; + v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; + v86.edx = (hd << 8) | diskdev; + v86.es = VTOPSEG(buf); + v86.ebx = VTOPOFF(buf); + v86int(); + if (v86.efl & 0x1) { + printf("save_sector: could not write back sector %d\n", + sectno); + return 1; + } + return 0; +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot/emuboot.h 6.2/src/sys/boot/i386/emuboot/emuboot.h --- 6.2-release/src/sys/boot/i386/emuboot/emuboot.h Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/emuboot.h Wed Sep 22 10:33:59 2004 @@ -0,0 +1,26 @@ +#define ROOTDIR "/tftpboot" +#define NETDEV "pxe0:" +#define SYSID_LINUX 131 +#define SYSID_FREEBSD 165 + +struct boot_what; +struct in_addr; + +int bootinfo_getinfo(struct boot_what **boot_whatp); +int bootinfo_pollinfo(struct boot_what **boot_whatp); +void bootinfo_showinfo(void); +int parse_multiboot_spec(char *cline, struct in_addr *ip, char **path, + char **args); +int load_multiboot_image(struct in_addr *server, char *filename, char *cmdline); +int load_sector(int sectno, void *buf); +int save_sector(int sectno, void *buf); +int boot_mbr_sysid(int sysid); +int boot_mbr_partition(int partition); +void boot_interactive(void); +void boot_mbr_default(void); +void disk_showinfo(void); +int set_active(int apart); +int partition_sysid(int partition, int *sysid); + +int set_lilo_cmdline(int partition, char *cmdline); +void *load_partition_bblock(int partition); diff -ruN 6.2-release/src/sys/boot/i386/emuboot/emumain.c 6.2/src/sys/boot/i386/emuboot/emumain.c --- 6.2-release/src/sys/boot/i386/emuboot/emumain.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/emumain.c Mon May 7 18:10:56 2007 @@ -0,0 +1,648 @@ +/*- + * Copyright (c) 1998, 2002, 2004 Michael Smith + * 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 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: src/sys/boot/i386/loader/main.c,v 1.17.2.5 2000/12/28 13:12:51 ps Exp $ + */ + +//#define RUNWHOAMI + +/* + * MD bootstrap main() and assorted miscellaneous + * commands. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "net.h" +#include "bootstrap.h" +#include "libi386/libi386.h" +#include "btxv86.h" + +#include "emuboot.h" +#include "bootwhat.h" + +void exit(int code); +static int boot_wait(boot_what_t **boot_whatp); +static int loader_setenv(char *var, int setit); +static void loader_getenv(void); +static int boot_loader(char *); +static int boot_local_partition(boot_what_t *boot_whatp); +static void load_fromdisk(char *bootspec, char *path, char *args); + +void +emumain(void) +{ + int i; + int err; + boot_what_t *boot_whatp; + + { + char cip[16], sip[16], gip[16]; + + /* XXX force DHCP query */ + close(open(NETDEV, 0)); + + strcpy(cip, inet_ntoa(myip)); + strcpy(sip, inet_ntoa(rootip)); + strcpy(gip, inet_ntoa(gateip)); + + printf("DHCP Info: IP: %s, Server: %s, Gateway: %s\n", + cip, sip, gip); + } + +#ifndef NONINTERACTIVE + /* + * Give the user a few seconds to interrupt and go into + * interactive mode. If we return, go through the auto + * boot and hope it works. + */ + printf("Type a key for interactive mode (quick, quick!)\n"); + for (i = 0; i < 3000; i++) { + if (ischar() == 0) + delay(1000); + else { + getchar(); + boot_interactive(); + break; + } + } +#endif + + /* + * See what the server thinks we should do. + * If no response or an error, boot the default partition. + */ + while (1) { + err = bootinfo_getinfo(&boot_whatp); + if (err != 0) + break; + bcheck: + switch (boot_whatp->type) { + case BIBOOTWHAT_TYPE_MB: + err = load_multiboot_image(&boot_whatp->what.mb.tftp_ip, + boot_whatp->what.mb.filename, + boot_whatp->cmdline); + break; + + case BIBOOTWHAT_TYPE_PART: + err = boot_local_partition(boot_whatp); + break; + + case BIBOOTWHAT_TYPE_SYSID: + err = boot_mbr_sysid(boot_whatp->what.sysid); + break; + + case BIBOOTWHAT_TYPE_WAIT: + boot_whatp = (boot_what_t *) NULL; + err = boot_wait(&boot_whatp); + /* If we got a bootinfo packet, process it */ + if (boot_whatp) + goto bcheck; + break; + + case BIBOOTWHAT_TYPE_REBOOT: + printf("Rebooting ...\n"); + exit(0); + break; + + case BIBOOTWHAT_TYPE_AUTO: + continue; + break; + + case BIBOOTWHAT_TYPE_MFS: + /* + * XXX Emulab hack: we don't use boot.4th, so do not + * even try to look it up. There are other magic options + * in the code as well, but they are triggered from the + * loader.conf file. + */ + loader_setenv("noforthinit=1", 1); + + printf("Attempting boot of: %s\n", + boot_whatp->what.mfs); + err = boot_loader(boot_whatp->what.mfs); + /* should not return */ + break; + + default: + panic("bootinfo invalid action %d\n", boot_whatp->type); + break; + } + if (err != 0) + break; + } + + /* + * Well, the only way to get here is if the specified boot failed. + * Fall through to booting the default, and hope it works. + */ + printf("Server specified boot failed (err=%d), ", err); +#ifdef NODISKBOOT + printf("rebooting and trying again...\n"); +#else + printf("booting from default partition...\n"); + boot_mbr_default(); +#endif + exit(0); +} + +/* + * Allow for an interactive boot specification. Returning implies that + * we go through the automated boot. + */ +void +boot_interactive(void) +{ +#define PROMPT "Enter boot spec: " + char buf[128]; + char bwbuf[MAX_BOOT_DATA]; + boot_what_t *bw = (boot_what_t *)bwbuf; + + bw->cmdline[0] = 0; + while (1) { + /* + * Flush! + */ + while (ischar() != 0) + getchar(); + + printf("%s", PROMPT); + gets(buf); + +#define PART "part:" + if (strncmp(buf, PART, strlen(PART)) == 0) { + int part = strtol(&buf[strlen(PART)], 0, 10); + bw->type = BIBOOTWHAT_TYPE_PART; + bw->what.partition = part; + boot_local_partition(bw); + } +#define SYSID "sysid:" + else if (strncmp(buf, SYSID, strlen(SYSID)) == 0) { + int sysid = strtol(&buf[strlen(SYSID)], 0, 10); + boot_mbr_sysid(sysid); + } +#define AUTO "auto" + else if (strncmp(buf, AUTO, strlen(AUTO)) == 0) { + return; + } +#define REBOOT "reboot" + else if (strncmp(buf, REBOOT, strlen(REBOOT)) == 0) { + printf("Rebooting ...\n"); + exit(0); + } +#define INFO "info" + else if (strncmp(buf, INFO, strlen(INFO)) == 0) { + disk_showinfo(); + bootinfo_showinfo(); + loader_getenv(); + continue; + } +#define LOADER "loader" + else if (strncmp(buf, LOADER, strlen(LOADER)) == 0) { + char *bp; + + if ((bp = strchr(buf, ':'))) + bp++; + + /* XXX magic, see comment above */ + loader_setenv("noforthinit=1", 1); + + boot_loader(bp); + + /* if we get here, it is an error */ + printf("Rebooting ...\n"); + exit(0); + } +#define ACTIVE "active:" + else if (strncmp(buf, ACTIVE, strlen(ACTIVE)) == 0) { + int active = strtol(&buf[strlen(ACTIVE)], 0, 10); + if (set_active(active) == 0) + printf("active partition now %d\n", active); + continue; + } +#define SETENV "setenv:" + else if (strncmp(buf, SETENV, strlen(SETENV)) == 0) { + loader_setenv(&buf[strlen(SETENV)], 1); + continue; + } +#define UNSET "unsetenv:" + else if (strncmp(buf, UNSET, strlen(UNSET)) == 0) { + loader_setenv(&buf[strlen(UNSET)], 0); + continue; + } +#define CMDLINE "cmdline:" + else if (strncmp(buf, CMDLINE, strlen(CMDLINE)) == 0) { + strncpy(bw->cmdline, &buf[strlen(CMDLINE)], + MAX_BOOT_CMDLINE); + continue; + } + + else if (isalpha(buf[0]) || isdigit(buf[0]) || buf[0] == '/') { + struct in_addr ip; + char *path, *args; + + parse_multiboot_spec(buf, &ip, &path, &args); + load_multiboot_image(&ip, path, args); + } + + printf("Choices are: \n" + " part:, or\n" + " sysid:, or\n" + " , or\n" + " auto (query the bootinfo server again), or\n" + " info (show boot options), or\n" + " active:, or\n" + " loader (boot DHCP default MFS), or\n" + " loader: (ex: /tftpboot/freebsd), or\n" + " loader:: (boot from other server), or\n" + " loader: (boot from disk), or\n" + " loader::/kernel (boot from disk), or\n" + " setenv:=, or\n" + " unsetenv:, or\n" + " cmdline:, or\n" + " reboot\n"); + } +} + +/* + * Wait to boot. Allow for interactive breakout though, lest we get + * stuck and need to power cycle. + */ +static int +boot_wait(boot_what_t **boot_whatp) +{ + printf("Entering boot wait mode. "); +#ifndef NONINTERACTIVE + printf("Type ^C for interactive mode ..."); +#endif + printf("\n"); + + /* + * Loop forever, but allow for interactive breakout. + */ + while (1) { + delay(1000); +#ifndef NONINTERACTIVE + if (ischar()) { + int c = getchar(); + if ((c == '')) { + boot_interactive(); + return 0; + } + } +#endif + /* See if bootinfo sent us an unsolicited command */ + if (bootinfo_pollinfo(boot_whatp) == 0) { + return 0; + } + } + return 0; +} + +static void +loader_getenv(void) +{ + struct env_var *ev; + char *cp; + + printf("Variables:\n"); + for (ev = environ; ev != NULL; ev = ev->ev_next) { + printf(" %s", ev->ev_name); + cp = getenv(ev->ev_name); + if (cp != NULL) + printf("=%s", cp); + printf("\n"); + } +} + +/* + * Set or unset a loader env variable + */ +static int +loader_setenv(char *var, int setit) +{ + if (setit) { + char *value = strchr(var, '='); + if (value) { + *value++ = 0; + setenv(var, value, 1); + } else + printf("setenv: no value for %s\n", var); + } else { + unsetenv(var); + } + return -1; +} + +/* + * Convert emuboot command line arguments into loader environment vars + * where possible. Returns anything unparsable. + * + * We don't recognize much right now. A couple of old-school - args: + * -v => boot_verbose=1 + * -s => boot_single=1 + * and key=value style args, some special, some not: + * HZ=N => kern.hz=N + * X=Y => X=Y + * will someday likely also handle ACPI options and console options. + */ +char * +parse_args(char *args) +{ + char *nargs = NULL; + char *var, *val; + + while (args != NULL) { + char *curarg = strsep(&args, " \t"); + + if (*curarg == '\0') + continue; + if (strcmp(curarg, "-v") == 0) { + var = "boot_verbose"; + val = "1"; + } else if (strcmp(curarg, "-s") == 0) { + var = "boot_single"; + val = "1"; + } else if (strncmp(curarg, "HZ=", 3) == 0) { + var = "kern.hz"; + val = curarg + 3; + } else if ((val = strchr(curarg, '=')) != NULL) { + /* + * Got equal? Assume it is a loader variable + * and just set it. + */ + var = curarg; + *val++ = 0; + } else { + /* + * For now we just toss extra args since we cannot + * pass them through with autoboot anyway. + */ + printf("Unrecognized argument '%s' ignored\n", curarg); + continue; + } +#if 0 + printf("args: %s=%s\n", var, val); +#endif + setenv(var, val, 1); + } + + return nargs; +} + +/* + * Zap into the loader, first checking to see if a bootdir was specified. + * This will overwrite the default we got from DHCP. + */ +static int +boot_loader(char *bootspec) +{ + struct in_addr old_tftp, new_tftp; + + /* + * XXX Gruesome Emulab hack to allow us to run older Forth scripts. + * At some point after FBSD 4, the interpreter fopen command changed + * to expect a mode argument on the stack. So we need to enable a + * heuristic that tells the interpreter to be on the lookout for + * fopen calls that appear to have no mode argument. + * See ficl/loader.c for details. + */ + loader_setenv("forth_bc=1", 1); + + new_tftp.s_addr = htonl(INADDR_NONE); + if (bootspec) { + char *path, *args; + + if ((args = strchr(bootspec, ' '))) { + *args = 0; + args++; + } + if ((path = strchr(bootspec, ':'))) { + *path = 0; + path++; + } + + if (strncmp(bootspec, "disk", strlen("disk")) == 0) { + load_fromdisk(bootspec, path, args); + return -1; + } + else { + /* + * If both a bootspec and path, bootspec + * must be an IP address. + * + * XXX we temporarily blast the given IP address + * into the tftpip field used by the tftp code. + */ + if (path) { + new_tftp.s_addr = inet_addr(bootspec); + if (new_tftp.s_addr == htonl(INADDR_NONE)) { + printf("Invalid TFTP IP address '%s' ignored\n", bootspec); + } else { + old_tftp = tftpip; + tftpip = new_tftp; + } + } + /* + * Copy file name part to rootpath + */ + strcpy(rootpath, (path ? path : bootspec)); + } + } + + interact(); + if (new_tftp.s_addr != htonl(INADDR_NONE)) + tftpip = old_tftp; + return -1; +} + +/* + * Boot a partition from the disk, possibly with a command line. + * + * For FreeBSD, when a cmdline is present; do not boot the loader from the + * partition, but jump in directly so that we can easily specify the kernel + * to boot, plus arguments. + * + * For Linux, we write the magic LILO map sector which is used to augment + * or override the default kernel options. + */ +static int +boot_local_partition(boot_what_t *boot_whatp) +{ + int sysid; + char buf[MAX_BOOT_DATA]; + int diskunit; + + /* XXX allow booting through MBR */ + if (boot_whatp->what.partition == 0) + return boot_mbr_partition(0); + + if (partition_sysid(boot_whatp->what.partition, &sysid)) + return 1; + + if (!boot_whatp->cmdline[0] || + !(sysid == SYSID_FREEBSD || sysid == SYSID_LINUX)) + return boot_mbr_partition(boot_whatp->what.partition); + + if (sysid == SYSID_LINUX) { + int rc; + rc = set_lilo_cmdline(boot_whatp->what.partition, + boot_whatp->cmdline); + if (rc == 0) + rc = boot_mbr_partition(boot_whatp->what.partition); + return rc; + } + + /* + * Treat command line as the name of the kernel. Later add support + * for kernel args, whatever. + * + * XXX for now we assume the kernel should come from the primary + * hard drive, this needs to be fixed. + */ + diskunit = bd_bios2unit(0x80); + sprintf(buf, "disk%ds1a:%s", diskunit, boot_whatp->cmdline); + + printf("Booting direct to FreeBSD kernel: %s\n", buf); + return boot_loader(buf); +} + +#ifdef BOOT_FORTH +#include "ficl.h" +extern FICL_VM *bf_vm; +#endif + +/* + * Read the boot loader config files as the disk-based loader would do. + */ +static void +load_fromdisk(char *bootspec, char *path, char *args) +{ + char *kname = 0; + + /* + * Establish currdev so we read configs from disk + */ + setenv("currdev", bootspec, 1); + +#ifdef BOOT_FORTH + bf_init(); + + /* + * Initialize loader environment as disk-based loader would: + * loader.4th normally read in loader.rc + * initialize first half of 'start' called from loader.rc + */ + if (include("/boot/loader.4th") != CMD_OK) { + printf("Could not read /boot/loader.4th\n"); + return; + } + + /* + * XXX unset ACPI. The on-disk loader.conf file will explicitly + * set it if needed. + */ + unsetenv("acpi_load"); + + bf_vm->sourceID.i = 0; + if (bf_run("initialize") != VM_OUTOFTEXT) { + return; + } +#endif + + /* + * Undo PXE-set environment variables. + */ + unsetenv("vfs.root.mountfrom"); + unsetenv("boot.nfsroot.nfshandle"); + unsetenv("boot.nfsroot.path"); + unsetenv("boot.nfsroot.server"); + unsetenv("boot.netif.ip"); + unsetenv("boot.netif.gateway"); + unsetenv("boot.netif.hwaddr"); + unsetenv("boot.netif.netmask"); + +#if 0 + printf("Before: bootspec='%s', path='%s', args='%s'\n", + bootspec, path, args ? args : ""); +#endif + + /* + * For FBSD 5 and above, strip off leading "/boot/" as it will + * be assumed and will also screw up the setting of module_path + */ + if (strncmp(path, "/boot/", 6) == 0) + path += 6; + + /* + * Now override the environment with our info: + * kernel kernel directory from which to boot + * bootfile kernel file to boot + */ + if (path[0] != '/' && (kname = strrchr(path, '/')) != 0) { + *kname++ = 0; + setenv("bootfile", kname, 1); + setenv("kernel", path, 1); + } + else { + setenv("bootfile", path, 1); + /* + * Such a hack: if the path started with slash (i.e., did not + * start with "/boot/"), then it is probably a 4.x boot where + * we need to set 'kernel' to the file to boot. + */ + if (path[0] == '/') { + setenv("kernel", path, 1); + kname = path; + } + } + + /* + * and fill in custom arguments. + */ + args = parse_args(args); + +#if 0 + printf("After: bootfile='%s', kernel='%s', args='%s'\n", + path, kname ? kname : "", args ? args : ""); +#endif + + /* + * Now load kernel plus any modules and then boot + */ +#ifdef BOOT_FORTH + bf_run("boot-conf"); +#else + autoboot(0, NULL); +#endif +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot/groklilo.c 6.2/src/sys/boot/i386/emuboot/groklilo.c --- 6.2-release/src/sys/boot/i386/emuboot/groklilo.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/groklilo.c Wed Sep 22 11:13:04 2004 @@ -0,0 +1,362 @@ +/* + * Code to grok a LILO bootblock and change the default command line string + */ + +/* + * XXX hack to recognize compilation in the boot loader as opposed to + * as a standalone application. + */ +#ifdef BOOT_FORTH +#define INBOOTLOADER +#endif + +#include + +#ifdef INBOOTLOADER +#include +#include "emuboot.h" + +#ifdef DEBUG +#define debug 1 +#else +#define debug 0 +#endif +#else +#include +#include + +static int debug; +#endif + +void *load_partition_bblock(int partition); +int load_sector(int sectno, void *buf); +int save_sector(int sectno, void *buf); + +/* + * These need to be consistant with LILO + */ +#define MAX_BOOT2_SECT 10 +#define MAX_IMAGE_DESC 19 +#define MAX_MAP_SECT 101 + +/* + * Sector addresses. + * These are the absolute values that must be relocated when moving + * a bootable partition. + */ +typedef struct sectaddr { + uint8_t sector; + uint8_t track; + uint8_t device; /* + flags, see below */ + uint8_t head; + uint8_t nsect; +} sectaddr_t; + +/* flags encoded in device */ +#define HARD_DISK 0x80 /* not a floppy */ +#define LINEAR_ADDR 0x40 /* mark linear address */ +#define LBA32_ADDR 0x20 /* mark lba 32-bit address */ +#define LBA32_NOCOUNT 0x10 /* mark address with count absent */ +#define DEVFLAGS 0xF0 + +struct bb1 { + uint8_t jumpinst[6]; + char sig[4]; /* LILO */ + uint16_t stage; /* 1 -- stage1 loader */ + uint16_t version; + uint16_t timeout; + uint16_t delay; + uint8_t port, portparams; + uint32_t timestamp; + sectaddr_t idesc[2]; /* image descriptors */ + sectaddr_t cmdline; /* command line (max 1 sector?) */ + uint8_t prompt; + uint16_t msglen; + sectaddr_t msg; /* "initial greeting message" */ + sectaddr_t keytab; /* "keyboard translation table" */ + sectaddr_t boot2[MAX_BOOT2_SECT+1]; /* 2nd stage boot sectors */ +}; + +union bblock { + struct bb1 bb1; + char data[1*512]; +}; + +struct cmdlineblock { + u_int16_t magic; + char cmdline[510]; +}; +#define CMDLINE_MAGIC 0xF4F2 + +static uint32_t +getsector(sectaddr_t *sect) +{ + int flags = (sect->device & DEVFLAGS) & ~HARD_DISK; + uint32_t sector = 0; + + if (sect->sector == 0 && sect->track == 0 && sect->device == 0 && + sect->head == 0 && sect->nsect == 0) + return 0; + + if (flags == 0) { + printf("groklilo: no can do CHS addresses!\n"); + return ~0; + } + + if (flags & LINEAR_ADDR) { + sector |= sect->head << 16; + sector |= sect->track << 8; + sector |= sect->sector; + } else { + if (flags & LBA32_NOCOUNT) + sector |= sect->nsect << 24; + sector |= sect->head << 16; + sector |= sect->track << 8; + sector |= sect->sector; + } + + return sector; +} + +int +set_lilo_cmdline(int partition, char *cmdline) +{ + struct bb1 *bb; + struct cmdlineblock clblock; + uint32_t cbsect; + + printf("Setting LILO cmdline in partition %d to `%s'\n", + partition, cmdline); + + if (partition < 1 || partition > 4) { + if (debug) + printf("%d: invalid partition number\n", partition); + return 1; + } + + bb = load_partition_bblock(partition); + if (bb == NULL) + return 1; + + if (strncmp(bb->sig, "LILO", 4) != 0) { + if (debug) + printf("%d: no LILO bootblock in partition\n", + partition); + return 1; + } + + if (bb->stage != 1) { + if (debug) + printf("%d: can only handle LILO stage1 bootblock\n", + partition); + return 1; + } + + cbsect = getsector(&bb->cmdline); + if (cbsect == ~0) { + if (debug) + printf("%d: error parsing LILO cmdline sector\n", + partition); + return 1; + } + + if (load_sector(cbsect, &clblock)) { + if (debug) + printf("%d: could not read LILO cmdline sector %d\n", + partition, cbsect); + return 1; + } + + if (debug) { + printf("%d: old command line was: %s\n", + partition, clblock.magic == CMDLINE_MAGIC ? + clblock.cmdline : "INVALID"); + } + + if (cmdline[0] == 0) { + clblock.magic = 0x6d6b; /* XXX what lilo does */ + } else { + strncpy(clblock.cmdline, cmdline, sizeof(clblock.cmdline)); + clblock.magic = CMDLINE_MAGIC; + } + + if (save_sector(cbsect, &clblock)) { + if (debug) + printf("%d: could not write LILO cmdline sector %d\n", + partition, cbsect); + return 1; + } + + return 0; +} + +#ifndef INBOOTLOADER + +#include +#include +#include +#include + +static int devfd; +static int nogo; + +static char *usagestr = + "usage: %s partition devicefile\n" + " -d Turn on debugging.\n" + " -c 'str' Set the LILO command line\n" + " -n Do not actually perform the operation\n" + " partition The DOS partition number where LILO resides (1-4)\n" + " device The *whole* disk device special file (ie: /dev/ad0)\n"; + +static void +usage(char *progname) +{ + fprintf(stderr, usagestr, progname); + exit(1); +} + +main(int argc, char **argv) +{ + int ch, part, rv; + char *cmdline, *progname; + + progname = argv[0]; + while ((ch = getopt(argc, argv, "c:dn")) != -1) + switch(ch) { + case 'd': + debug++; + break; + case 'c': + cmdline = optarg; + break; + case 'n': + nogo++; + break; + case '?': + default: + usage(progname); + } + argc -= optind; + argv += optind; + + if (argc != 2) + usage(progname); + + part = atoi(argv[0]); + if (part < 1 || part > 4) + usage(progname); + + if ((devfd = open(argv[1], nogo ? O_RDONLY : O_RDWR)) < 0) { + perror("opening device"); + exit(1); + } + + rv = set_lilo_cmdline(part, cmdline); + if (rv) { + fprintf(stderr, "%s: command failed on part %d, " + "no change made\n", + argv[1], part); + } + + exit(rv); +} + +struct bios_mbr { + char bootcode[446]; + char partinfo[64]; + unsigned short magic; +}; + +/* magic */ +#define BIOS_MAGIC 0xaa55 + +struct bios_partition_info { + unsigned char bootid; + unsigned char beghead; + unsigned char begsect; + unsigned char begcyl; + unsigned char sysid; + unsigned char endhead; + unsigned char endsect; + unsigned char endcyl; + unsigned long offset; + unsigned long numsectors; +}; + +static struct bios_mbr diskmbr; +static char partbr[512]; + +static int +check_mbr(void) +{ + struct bios_mbr *mbr; + struct bios_partition_info *entry; + int i; + + mbr = &diskmbr; + if (mbr->magic != BIOS_MAGIC) + return -1; + + entry = (struct bios_partition_info *) mbr->partinfo; + for (i = 0; i < 4; i++, entry++) { + if (entry->numsectors == 0) + continue; + + /* XXX sanity check fields */ + } + + return 0; +} + +int +load_sector(int sectno, void *buf) +{ + if (lseek(devfd, (off_t)sectno * 512, SEEK_SET) < 0 || + read(devfd, buf, 512) < 512) + return errno; + return 0; +} + +int +save_sector(int sectno, void *buf) +{ + if (nogo) { + fprintf(stderr, "Would write back sector %d\n", sectno); + return 0; + } + if (lseek(devfd, (off_t)sectno * 512, SEEK_SET) < 0 || + write(devfd, buf, 512) < 512) + return errno; + return 0; +} + +static void +load_mbr(void) +{ + if (load_sector(0, &diskmbr) == 0 && check_mbr() == 0) + return; + + fprintf(stderr, "Could not load/verify MBR\n"); + exit(-1); +} + +void * +load_partition_bblock(int pnum) +{ + struct bios_partition_info *entry; + + load_mbr(); + + pnum--; + entry = ((struct bios_partition_info *)diskmbr.partinfo) + pnum; + if (load_sector((int)entry->offset, partbr) != 0 || + ((struct bios_mbr *)partbr)->magic != BIOS_MAGIC) { + printf("Could not load/verify partition %d boot record\n", + pnum); + return 0; + } + + return partbr; +} + +#endif diff -ruN 6.2-release/src/sys/boot/i386/emuboot/main.c 6.2/src/sys/boot/i386/emuboot/main.c --- 6.2-release/src/sys/boot/i386/emuboot/main.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/main.c Thu Mar 1 13:24:30 2007 @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 1998 Michael Smith + * 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 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: src/sys/boot/i386/loader/main.c,v 1.17.2.6 2001/12/21 22:20:37 jhb Exp $ + */ + +/* + * MD bootstrap main() and assorted miscellaneous + * commands. + */ + +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386/libi386.h" +#include "btxv86.h" + +#define KARGS_FLAGS_CD 0x1 +#define KARGS_FLAGS_PXE 0x2 + +/* Arguments passed in from the boot1/boot2 loader */ +static struct +{ + u_int32_t howto; + u_int32_t bootdev; + u_int32_t bootflags; + u_int32_t pxeinfo; + u_int32_t res2; + u_int32_t bootinfo; +} *kargs; + +static u_int32_t initial_howto; +static u_int32_t initial_bootdev; +static struct bootinfo *initial_bootinfo; + +struct arch_switch archsw; /* MI/MD interface boundary */ + +static void extract_currdev(void); +static int isa_inb(int port); +static void isa_outb(int port, int value); +void exit(int code); + +/* from vers.c */ +extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; + +/* XXX debugging */ +extern char end[]; + +/* from emumain.c */ +void emumain(void); + +static void *heap_top; +static void *heap_bottom; + +int +main(void) +{ + int i; + + /* Pick up arguments */ + kargs = (void *)__args; + initial_howto = kargs->howto; + initial_bootdev = kargs->bootdev; + initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; + + /* + * Initialise the heap as early as possible. Once this is done, malloc() is usable. + */ + bios_getmem(); + +#if 1 + heap_top = PTOV(memtop_copyin); + memtop_copyin -= 0x300000; + heap_bottom = PTOV(memtop_copyin); +#else + heap_top = (void *)bios_basemem; + heap_bottom = (void *)end; +#endif + setheap(heap_bottom, heap_top); + + /* + * XXX Chicken-and-egg problem; we want to have console output early, but some + * console attributes may depend on reading from eg. the boot device, which we + * can't do yet. + * + * We can use printf() etc. once this is done. + * If the previous boot stage has requested a serial console, prefer that. + */ + bi_setboothowto(initial_howto); + if (initial_howto & RB_MULTIPLE) { + if (initial_howto & RB_SERIAL) + setenv("console", "comconsole vidconsole", 1); + else + setenv("console", "vidconsole comconsole", 1); + } else if (initial_howto & RB_SERIAL) + setenv("console", "comconsole", 1); + else if (initial_howto & RB_MUTE) + setenv("console", "nullconsole", 1); + cons_probe(); + + /* + * Initialise the block cache + */ + bcache_init(32, 512); /* 16k cache XXX tune this */ + + /* + * Special handling for PXE and CD booting. + */ + if (kargs->bootinfo == 0) { + /* + * We only want the PXE disk to try to init itself in the below + * walk through devsw if we actually booted off of PXE. + */ + if (kargs->bootflags & KARGS_FLAGS_PXE) + pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); + else if (kargs->bootflags & KARGS_FLAGS_CD) + bc_add(initial_bootdev); + } + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); + if (initial_bootinfo != NULL) { + initial_bootinfo->bi_basemem = bios_basemem / 1024; + initial_bootinfo->bi_extmem = bios_extmem / 1024; + } + + /* detect ACPI for future reference */ + biosacpi_detect(); + + /* detect SMBIOS for future reference */ + smbios_detect(); + + printf("\n"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); + + extract_currdev(); /* set $currdev and $loaddev */ + setenv("LINES", "24", 1); /* optional */ + + bios_getsmap(); + + archsw.arch_autoload = i386_autoload; + archsw.arch_getdev = i386_getdev; + archsw.arch_copyin = i386_copyin; + archsw.arch_copyout = i386_copyout; + archsw.arch_readin = i386_readin; + archsw.arch_isainb = isa_inb; + archsw.arch_isaoutb = isa_outb; + + emumain(); /* doesn't return */ + + /* if we ever get here, it is an error */ + return (1); +} + +/* + * Set the 'current device' by (if possible) recovering the boot device as + * supplied by the initial bootstrap. + * + * XXX should be extended for netbooting. + */ +static void +extract_currdev(void) +{ + struct i386_devdesc new_currdev; + int major, biosdev = -1; + + /* Assume we are booting from a BIOS disk by default */ + new_currdev.d_dev = &biosdisk; + + /* new-style boot loaders such as pxeldr and cdldr */ + if (kargs->bootinfo == 0) { + if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { + /* we are booting from a CD with cdboot */ + new_currdev.d_dev = &bioscd; + new_currdev.d_kind.bioscd.unit = bc_bios2unit(initial_bootdev); + } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { + /* we are booting from pxeldr */ + new_currdev.d_dev = &pxedisk; + new_currdev.d_kind.netif.unit = 0; + } else { + /* we don't know what our boot device is */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } + } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { + /* The passed-in boot device is bad */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } else { + new_currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) + + B_CONTROLLER(initial_bootdev) - 1; + new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); + biosdev = initial_bootinfo->bi_bios_dev; + major = B_TYPE(initial_bootdev); + + /* + * If we are booted by an old bootstrap, we have to guess at the BIOS + * unit number. We will lose if there is more than one disk type + * and we are not booting from the lowest-numbered disk type + * (ie. SCSI when IDE also exists). + */ + if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ + biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ + } + new_currdev.d_type = new_currdev.d_dev->dv_type; + + /* + * If we are booting off of a BIOS disk and we didn't succeed in determining + * which one we booted off of, just use disk0: as a reasonable default. + */ + if ((new_currdev.d_type == biosdisk.dv_type) && + ((new_currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1)) { + printf("Can't work out which disk we are booting from.\n" + "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); + new_currdev.d_kind.biosdisk.unit = 0; + } + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), + i386_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, + env_nounset); +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc, char *argv[]) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + printf("Rebooting...\n"); + delay(1000000); + __exit(0); +} + +/* provide this for panic, as it's not in the startup code */ +void +exit(int code) +{ + __exit(code); +} + +COMMAND_SET(heap, "heap", "show heap usage", command_heap); + +static int +command_heap(int argc, char *argv[]) +{ + mallocstats(); + printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, + sbrk(0), heap_top); + return(CMD_OK); +} + +/* ISA bus access functions for PnP, derived from */ +static int +isa_inb(int port) +{ + u_char data; + + if (__builtin_constant_p(port) && + (((port) & 0xffff) < 0x100) && + ((port) < 0x10000)) { + __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); + } else { + __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); + } + return(data); +} + +static void +isa_outb(int port, int value) +{ + u_char al = value; + + if (__builtin_constant_p(port) && + (((port) & 0xffff) < 0x100) && + ((port) < 0x10000)) { + __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port))); + } else { + __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); + } +} + diff -ruN 6.2-release/src/sys/boot/i386/emuboot/multiboot.c 6.2/src/sys/boot/i386/emuboot/multiboot.c --- 6.2-release/src/sys/boot/i386/emuboot/multiboot.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/multiboot.c Thu Mar 1 13:15:48 2007 @@ -0,0 +1,290 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386/libi386.h" +#include "btxv86.h" +#include "net.h" + +#include "emuboot.h" +#include "multiboot.h" + +#define DEBUG + +static struct multiboot_info *boot_info; + +static int init_boot_info(char *filename, char *cmdline); +static void multiboot_info_dump(struct multiboot_info *bi); +static void boot_start(struct multiboot_info *bi, vm_offset_t entry); + +int +load_multiboot_image(struct in_addr *tftpserver, char *filename, char *cmdline) +{ + vm_offset_t entry = 0; + int err; + +#ifdef DEBUG + printf("Creating Multiboot goo ...\n"); +#endif + err = init_boot_info(filename, cmdline); + if (err) { +#ifdef DEBUG + printf("Could not build multiboot header, err=%d\n", err); +#endif + return err; + } + + /* + * XXX tweak some magic global variables while we do the TFTP load. + */ + { + struct preloaded_file *fp = 0; + struct file_metadata *md; + struct in_addr Orootip; + char Orootpath[FNAME_SIZE]; + + Orootip.s_addr = rootip.s_addr; + strncpy(Orootpath, rootpath, FNAME_SIZE); + + if (tftpserver && tftpserver->s_addr) + rootip.s_addr = tftpserver->s_addr; + rootpath[0] = '\0'; + +#ifdef DEBUG + printf("Loading ELF file `%s' from %s...\n", + filename, inet_ntoa(rootip)); +#endif + err = __elfN(loadfile)(filename, 0, &fp); + if (err == 0) { + md = file_findmetadata(fp, MODINFOMD_ELFHDR); + if (md != 0) + entry = ((Elf_Ehdr *)&(md->md_data))->e_entry + & 0xffffff; + else + err = EINVAL; + } + strncpy(rootpath, Orootpath, FNAME_SIZE); + rootip.s_addr = Orootip.s_addr; + + if (err) { +#ifdef DEBUG + printf("Load failed, err=%d\n", err); +#endif + if (fp) + file_discard(fp); + return (err); + } +#ifdef DEBUG + printf("Loaded, entry=0x%x\n", entry); +#endif + } + +#ifdef DEBUG + printf("Booting the kernel ...\n"); +#endif + __exec((void *)VTOP(boot_start), VTOP(boot_info), entry, 0); + + /* + * Never returns, but of course + */ + return 0; +} + +static void +boot_start(struct multiboot_info *bi, vm_offset_t entry) +{ + asm volatile("call *%%ecx" : : "b" (bi), "c" (entry)); +} + +/* + * Take a string and separate the IP, path, and arguments into strings. + */ +int +parse_multiboot_spec(char *cline, struct in_addr *ip, char **path, char **args) +{ + char *p; + + if (isdigit(*cline) && (p = strchr(cline, ':'))) { + *p++ = '\0'; + ip->s_addr = inet_addr(cline); + } else { + ip->s_addr = 0; + p = cline; + } + + *path = p; + + if ((p = strchr(p, ' '))) { + *p++ = '\0'; + *args = p; + } else + *args = ""; + + return 0; +} + +static int +init_boot_info(char *filename, char *cmdline) +{ + char *dest; + + /* Allocate memory for the boot_info structure and modules array. */ + boot_info = (struct multiboot_info*)calloc(sizeof(*boot_info), 1); + if (boot_info == 0) + return (ENOMEM); + + boot_info->mods_count = 0; + boot_info->mods_addr = 0; + + /* Fill in the upper and lower memory size fields in the boot_info. */ + boot_info->flags |= MULTIBOOT_MEMORY; + + /* + * Find lower and upper bounds of physical memory. + * We look in the NVRAM to find the size of base memory and + * use extended_mem_size() to find the size of extended memory. + */ + boot_info->mem_lower = bios_basemem / 1024; + boot_info->mem_upper = bios_extmem / 1024; + + /* + * Boot arguments + */ + dest = calloc(2048, 1); + if (dest == 0) { + free(boot_info); + return (ENOMEM); + } + boot_info->cmdline = VTOP(dest); + boot_info->flags |= MULTIBOOT_CMDLINE; + strcpy(dest, filename); + strcat(dest, " "); + +#ifdef FORCE_SERIAL_CONSOLE + /* Force serial line console */ + strcat(dest, " -h -f "); +#endif + if (!cmdline[0] || !strstr(cmdline, "--")) + strcat(dest, " -- "); + if (cmdline[0]) + strcat(dest, cmdline); + + printf("Kernel Command Line: %s\n", dest); + + /* + * - No command lines passed up from 16 bit mode. + * - No Boot module support. + * The loaded kernel needs to be wrapped in a multiboot adaptor + * if it wants boot modules. + */ + +#ifdef DEBUG + multiboot_info_dump(boot_info); +#endif + + return (0); +} + +static void +multiboot_info_dump(struct multiboot_info *bi) +{ + struct multiboot_module *m; + unsigned i; + + printf("MultiBoot Info (flags: 0x%x)\n", bi->flags); + + if (bi->flags & MULTIBOOT_MEMORY) + printf(" PC Memory: lower %dK, upper %dK\n", + bi->mem_lower, bi->mem_upper); + + if (bi->flags & MULTIBOOT_BOOT_DEVICE) + printf(" Boot device: {%d,%d,%d,%d}\n", + bi->boot_device[0], + bi->boot_device[1], + bi->boot_device[2], + bi->boot_device[3]); + + if (bi->flags & MULTIBOOT_CMDLINE) + printf(" Kernel command line: `%s'\n", + (char *)PTOV(bi->cmdline)); + + if (bi->flags & MULTIBOOT_MODS) { + printf(" Boot modules: %d\n", bi->mods_count); + m = (struct multiboot_module *)PTOV(bi->mods_addr); + for (i = 0; i < bi->mods_count; i++) { + printf(" Module %d: %08x-%08x (size %d)\n", + i, m[i].mod_start, m[i].mod_end, + m[i].mod_end - m[i].mod_start); + if (m[i].string) + printf(" String: `%s' at %08x\n", + (char*)PTOV(m[i].string), m[i].string); + } + } + + if (bi->flags & MULTIBOOT_AOUT_SYMS) + printf(" Symbol table (a.out): start 0x%08x," + " symtab 0x%08x, strtab 0x%08x\n", + bi->syms.a.addr, + bi->syms.a.tabsize, bi->syms.a.strsize); + + if (bi->flags & MULTIBOOT_ELF_SHDR) + /* XXX */ + printf(" Has MULTIBOOT_ELF_SHDR info\n"); + + if (bi->flags & MULTIBOOT_MEM_MAP) { + struct AddrRangeDesc *rdesc; + unsigned end; + + printf(" Memory Map:\n addr: 0x%08x," + " count: %d\n", + bi->mmap_addr, bi->mmap_count); + + /* XXX Count is currently the length in bytes of the + * entire structure: GRUB and the multiboot spec + * actually call it mmap_length. + */ + rdesc = (struct AddrRangeDesc *)bi->mmap_addr; + end = bi->mmap_addr + bi->mmap_count; + + while (end > (int)rdesc) { + /* + * I'd rather use .0 precision for the High + * entries (since they're guaranteed to be 0 + * on a PC), but this works too. */ + printf(" base: 0x"); + if (rdesc->BaseAddrHigh) + printf("%08lx", rdesc->BaseAddrHigh); + printf("%08lx length: 0x", rdesc->BaseAddrLow); + + if (rdesc->LengthHigh) + printf("%08lx", rdesc->LengthHigh); + printf("%08lx type: ", rdesc->LengthLow); + + switch (rdesc->Type) { + case 1: + printf("memory\n"); + break; + case 2: + printf("reserved\n"); + break; + default: + printf("undefined (%ld)\n", rdesc->Type); + } + + { + char *cp = (char *)rdesc; + cp += rdesc->size + 4; + rdesc = (struct AddrRangeDesc *)cp; + } + }; + } + + +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot/multiboot.h 6.2/src/sys/boot/i386/emuboot/multiboot.h --- 6.2-release/src/sys/boot/i386/emuboot/multiboot.h Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/multiboot.h Thu May 27 14:00:18 2004 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1994-1995, 1998, 2001 University of Utah and the Flux Group. + * All rights reserved. + * + * x86/multiboot.h from the OSKit. + */ +#ifndef _OSKIT_X86_MULTIBOOT_H_ +#define _OSKIT_X86_MULTIBOOT_H_ + +#ifndef ASSEMBLER + +/* XXX from oskit/x86/types.h */ +typedef unsigned int oskit_addr_t; +typedef unsigned int oskit_size_t; + +/* For a.out kernel boot images, the following header must appear + somewhere in the first 8192 bytes of the kernel image file. */ +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* Checksum: magic + flags + checksum == 0 */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + oskit_addr_t header_addr; + oskit_addr_t load_addr; + oskit_addr_t load_end_addr; + oskit_addr_t bss_end_addr; + oskit_addr_t entry; +}; + +#endif /* not defined ASSEMBLER */ + +/* The entire multiboot_header must be contained + within the first MULTIBOOT_SEARCH bytes of the kernel image. */ +#define MULTIBOOT_SEARCH 8192 + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1badb002 + +/* Features flags for 'flags'. + If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + and it doesn't understand it, it must fail. */ +#define MULTIBOOT_MUSTKNOW 0x0000ffff + +/* Align all boot modules on page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must be provided memory information in multiboot_info structure */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Use the load address fields above instead of the ones in the a.out header + to figure out what to load where, and what to do afterwards. + This should only be needed for a.out kernel images + (ELF and other formats can generally provide the needed information). */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* The boot loader passes this value in register EAX to signal the kernel + that the multiboot method is being used */ +#define MULTIBOOT_VALID 0x2badb002 + +/* The boot loader passes this data structure to the kernel in + register EBX on entry. */ +#ifndef ASSEMBLER +struct multiboot_info +{ + /* These flags indicate which parts of the multiboot_info are valid; + see below for the actual flag bit definitions. */ + unsigned flags; + + /* Lower/Upper memory installed in the machine. + Valid only if MULTIBOOT_MEMORY is set in flags word above. */ + oskit_size_t mem_lower; + oskit_size_t mem_upper; + + /* BIOS disk device the kernel was loaded from. + Valid only if MULTIBOOT_BOOT_DEVICE is set in flags word above. */ + unsigned char boot_device[4]; + + /* Command-line for the OS kernel: a null-terminated ASCII string. + Valid only if MULTIBOOT_CMDLINE is set in flags word above. */ + oskit_addr_t cmdline; + + /* List of boot modules loaded with the kernel. + Valid only if MULTIBOOT_MODS is set in flags word above. */ + unsigned mods_count; + oskit_addr_t mods_addr; + + /* Symbol information for a.out or ELF executables. */ + union + { + struct + { + /* a.out symbol information valid only if MULTIBOOT_AOUT_SYMS + is set in flags word above. */ + oskit_size_t tabsize; + oskit_size_t strsize; + oskit_addr_t addr; + unsigned reserved; + } a; + + struct + { + /* ELF section header information valid only if + MULTIBOOT_ELF_SHDR is set in flags word above. */ + unsigned num; + oskit_size_t size; + oskit_addr_t addr; + unsigned shndx; + } e; + } syms; + + /* Memory map buffer. + Valid only if MULTIBOOT_MEM_MAP is set in flags word above. */ + oskit_size_t mmap_count; + oskit_addr_t mmap_addr; +}; + +#define MULTIBOOT_MEMORY (1L<<0) +#define MULTIBOOT_BOOT_DEVICE (1L<<1) +#define MULTIBOOT_CMDLINE (1L<<2) +#define MULTIBOOT_MODS (1L<<3) +#define MULTIBOOT_AOUT_SYMS (1L<<4) +#define MULTIBOOT_ELF_SHDR (1L<<5) +#define MULTIBOOT_MEM_MAP (1L<<6) + +/* For use with printf's %b format. */ +#define MULTIBOOT_FLAGS_FORMAT \ + "\20\1MEMORY\2BOOT_DEVICE\3CMDLINE\4MODS\5AOUT_SYMS\6ELF_SHDR\7MEM_MAP" + +/* The mods_addr field above contains the physical address of the first + of 'mods_count' multiboot_module structures. */ +struct multiboot_module +{ + /* Physical start and end addresses of the module data itself. */ + oskit_addr_t mod_start; + oskit_addr_t mod_end; + + /* Arbitrary ASCII string associated with the module. */ + oskit_addr_t string; + + /* Boot loader must set to 0; OS must ignore. */ + unsigned reserved; +}; + + +/* The mmap_addr field above contains the physical address of the first + of the AddrRangeDesc structure. "size" represents the size of the + rest of the structure and optional padding. The offset to the beginning + of the next structure is therefore "size + 4". */ +struct AddrRangeDesc +{ + unsigned long size; + unsigned long BaseAddrLow; + unsigned long BaseAddrHigh; + unsigned long LengthLow; + unsigned long LengthHigh; + unsigned long Type; + + /* unspecified optional padding... */ +}; + +#endif /* ifndef ASSEMBLER */ + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + + +#endif /* _OSKIT_X86_MULTIBOOT_H_ */ diff -ruN 6.2-release/src/sys/boot/i386/emuboot/newvers.sh 6.2/src/sys/boot/i386/emuboot/newvers.sh --- 6.2-release/src/sys/boot/i386/emuboot/newvers.sh Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/newvers.sh Thu May 27 14:00:18 2004 @@ -0,0 +1,47 @@ +#!/bin/sh - +# +# $FreeBSD: src/sys/boot/common/newvers.sh,v 1.1.2.2 2001/03/05 13:08:45 ru Exp $ +# $NetBSD: newvers.sh,v 1.1 1997/07/26 01:50:38 thorpej Exp $ +# +# Copyright (c) 1984, 1986, 1990, 1993 +# The Regents of the University of California. 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. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +# +# @(#)newvers.sh 8.1 (Berkeley) 4/20/94 + +LC_ALL=C; export LC_ALL +u=${USER-root} h=`hostname` t=`date` +#r=`head -n 6 $1 | tail -n 1 | awk -F: ' { print $1 } '` +r=`awk -F: ' /^[0-9]\.[0-9]+:/ { print $1; exit }' $1` + +echo "char bootprog_name[] = \"Emulab.net/${3} ${2}\";" > vers.c +echo "char bootprog_rev[] = \"${r}\";" >> vers.c +echo "char bootprog_date[] = \"${t}\";" >> vers.c +echo "char bootprog_maker[] = \"${u}@${h}\";" >> vers.c diff -ruN 6.2-release/src/sys/boot/i386/emuboot/version 6.2/src/sys/boot/i386/emuboot/version --- 6.2-release/src/sys/boot/i386/emuboot/version Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot/version Mon May 7 18:10:48 2007 @@ -0,0 +1,14 @@ +$FreeBSD: src/sys/boot/i386/loader/version,v 1.5.2.1 2000/07/06 23:45:00 obrien Exp $ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +1.9: Fix direct booting of 4.x kernels +1.8: Add argument parsing for FreeBSD kernel command lines +1.7: Convert to FreeBSD 6.2 base +1.6: Read disk-based loader files when booting alternate kernel +1.5: Optimizations to avoid excess TFTP stat calls +1.4: Use DHCP info from PXE, do not bootp ourselves +1.3: Add support booting MFS directly. Boot specific kernel directly. +1.2: Add support for setting active partition +1.1: EMULAB boot version 1.1 diff -ruN 6.2-release/src/sys/boot/i386/emuboot-cd/Makefile 6.2/src/sys/boot/i386/emuboot-cd/Makefile --- 6.2-release/src/sys/boot/i386/emuboot-cd/Makefile Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot-cd/Makefile Fri Mar 9 15:51:14 2007 @@ -0,0 +1,107 @@ +# $FreeBSD: src/sys/boot/i386/loader/Makefile,v 1.81.2.1 2005/10/30 14:37:02 scottl Exp $ + +PROG= loader.sym +INTERNALPROG= +NEWVERSWHAT= "BTX-based Emulab boot loader" i386 + +# architecture-specific loader code +SRCS= main.c conf.c diskboot.c testbed.c vers.c + +.include <${.CURDIR}/../Makefile.inc> +.if defined(FORCE_SERIAL_CONSOLE) +M4FLAGS+= -DFORCE_SERIAL_CONSOLE +CFLAGS+= -DFORCE_SERIAL_CONSOLE +.endif + +# Enable PXE TFTP or NFS support, not both. +.if defined(LOADER_TFTP_SUPPORT) +CFLAGS+= -DLOADER_TFTP_SUPPORT +.else +CFLAGS+= -DLOADER_NFS_SUPPORT +.endif + +# Enable PnP and ISA-PnP code. +HAVE_PNP= yes +HAVE_ISABUS= yes + +.if !defined(NO_FORTH) +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.endif + +.if defined(LOADER_BZIP2_SUPPORT) +CFLAGS+= -DLOADER_BZIP2_SUPPORT +.endif +.if !defined(LOADER_NO_GZIP_SUPPORT) +CFLAGS+= -DLOADER_GZIP_SUPPORT +.endif +.if !defined(LOADER_NO_SPLIT_SUPPORT) +CFLAGS+= -DLOADER_SPLIT_SUPPORT +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common ${.CURDIR}/../loader +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I. + +CLEANFILES= vers.c loader loader.bin loader.help + +CFLAGS+= -Wall +LDFLAGS= -static -Ttext 0x0 + +# i386 standalone support library +LIBI386= ${.OBJDIR}/../libi386/libi386.a +CFLAGS+= -I${.CURDIR}/.. + +# BTX components +CFLAGS+= -I${.CURDIR}/../btx/lib + +# Debug me! +#CFLAGS+= -g +#LDFLAGS+= -g + +# Pick up ../Makefile.inc early. +.include + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +loader: loader.bin ${BTXLDR} ${BTXKERN} + btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ + -b ${BTXKERN} loader.bin + +loader.bin: loader.sym + cp ${.ALLSRC} ${.TARGET} + strip -R .comment -R .note ${.TARGET} + +loader.help: help.common help.i386 + cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.PATH: ${.CURDIR}/../../forth +FILES= loader loader.help loader.4th support.4th loader.conf +FILES+= screen.4th frames.4th beastie.4th +# XXX INSTALLFLAGS_loader= -b +FILESMODE_loader= ${BINMODE} -b +FILESDIR_loader.conf= /boot/defaults + +.if !exists(${DESTDIR}/boot/loader.rc) +FILES+= loader.rc +.endif + +# XXX crt0.o needs to be first for pxeboot(8) to work +OBJS= ${BTXCRT} + +DPADD= ${LIBFICL} ${LIBI386} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBI386} -lstand + +.include + +.if ${MACHINE_ARCH} == "amd64" +beforedepend ${OBJS}: machine +CLEANFILES+= machine +machine: + ln -sf ${.CURDIR}/../../../i386/include machine +.endif diff -ruN 6.2-release/src/sys/boot/i386/emuboot-cd/diskboot.c 6.2/src/sys/boot/i386/emuboot-cd/diskboot.c --- 6.2-release/src/sys/boot/i386/emuboot-cd/diskboot.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot-cd/diskboot.c Fri Mar 9 16:57:45 2007 @@ -0,0 +1,554 @@ +#include + +#include +#include +#include + +#include "btxv86.h" +#include "libi386/libi386.h" +#include "bootstrap.h" + +int load_sector(int sectno, void *buf); +int set_active(int apart); + +/* + * Support for disk booting + */ + +#define DISKDEV 0x80 /* first BIOS hard drive */ + +static void *magicaddr = (void *)0x7C00; + +struct bios_mbr { + char bootcode[446]; + char partinfo[64]; /* 4 x bios_partition_info */ + unsigned short magic; +}; + +/* magic */ +#define BIOS_MAGIC 0xaa55 + +struct bios_partition_info { + unsigned char bootid; + unsigned char beghead; + unsigned char begsect; + unsigned char begcyl; + unsigned char sysid; + unsigned char endhead; + unsigned char endsect; + unsigned char endcyl; + unsigned long offset; + unsigned long numsectors; +}; + +/* bootable (active) bootid */ +#define BIOS_BOOTABLE 0x80 + +static struct bios_mbr diskmbr; +static char partbr[512]; +static int find_bootdisk(void); +static int load_mbr(int dieonerror); +static int check_mbr(void); +static void show_mbr(void); +static int bootdisk = -1; +static char bootdevice[] = "disk0:"; +static int diskdev = DISKDEV; + +void +set_bootdisk(int ndiskdev) +{ + if (bootdisk == -1 && find_bootdisk()) { + printf("can't find boot harddisk\n"); + return; + } + + if (ndiskdev >= 0 && ndiskdev != diskdev) { + int odiskdev = diskdev; + diskdev = ndiskdev; + if (find_bootdisk()) { + diskdev = odiskdev; + printf("can't set bootdisk to 0x%x, left as 0x%x\n", + ndiskdev, diskdev); + return; + } + } + if (ndiskdev != diskdev) + printf("Boot disk is %s (0x%x)\n", bootdevice, diskdev); +} + +/* + * Locate the boot code biosdisk that corresponds to BIOS disk DISKDEV + */ +static int +find_bootdisk(void) +{ + bootdisk = bd_bios2unit(diskdev); + if (bootdisk >= 0) { + bootdevice[4] = bootdisk + '0'; + return 0; + } + + return -1; +} + +void +disk_showinfo(void) +{ + set_bootdisk(-1); + if (load_mbr(0) == 0) { + printf("Partitions, %s\n", bootdevice); + show_mbr(); + } +} + +/* + * Load the Master Boot Record using the BIOS. + */ +static int +load_mbr(int dieonerror) +{ + if (load_sector(0, &diskmbr) == 0 && check_mbr() == 0) + return 0; + + if (dieonerror) + panic("Could not load/verify MBR"); + return -1; +} + +/* + * Check sanity of the MBR. + */ +static int +check_mbr(void) +{ + struct bios_mbr *mbr; + struct bios_partition_info *entry; + int i; + + mbr = &diskmbr; +#ifdef DEBUG + printf("MBR@%p: magic=%x, partinfo@%p\n", mbr, mbr->magic, + mbr->partinfo); +#endif + if (mbr->magic != BIOS_MAGIC) { +#ifdef DEBUG + printf("MBR has bad magic (%x != %x)\n", + mbr->magic, BIOS_MAGIC); +#endif + return -1; + } + + entry = (struct bios_partition_info *) mbr->partinfo; + for (i = 0; i < 4; i++, entry++) { +#ifdef DEBUG + printf("%c%d: sysid=%d, offset=%lu, nsect=%lu\n", + entry->bootid==BIOS_BOOTABLE ? '*' : ' ', i+1, + entry->sysid, entry->offset, entry->numsectors); +#endif + if (entry->numsectors == 0) + continue; + + /* XXX sanity check fields */ + } + + return 0; +} + +static struct ptypes { + int sysid; + char *str; +} sysids[] = { + { 165, "FreeBSD" }, + { 131, "Linux" }, + { 130, "Linux swap" }, + { 7, "NTFS" }, + { 166, "OpenBSD" }, + { 0, "Unused" }, + { -1, "Unknown" } +}; + +static char * +ptypestr(int sysid) +{ + struct ptypes *pt = sysids; + + for (pt = sysids; pt->sysid >= 0; pt++) + if (pt->sysid == sysid) + break; + return (pt->str); +} + +static void +show_mbr(void) +{ + struct bios_partition_info *entry; + int i; + + entry = (struct bios_partition_info *) diskmbr.partinfo; + for (i = 0; i < 4; i++, entry++) { + if (entry->numsectors == 0) + continue; + printf("%c%d: sysid=%d (%s), offset=%lu, nsect=%lu\n", + entry->bootid==BIOS_BOOTABLE ? '*' : ' ', i+1, + entry->sysid, ptypestr(entry->sysid), + entry->offset, entry->numsectors); + } +} + +/* + * Copy the given sector contents into the magic load address, + * switch to 16bit/real mode, and then jump to the address. + * + * Note that we copy the sector into the memory previously occupied + * by the pxeldr, this way we should not be clobbering anything. + */ +static void +boot_from(void *buf) +{ + void __restart(void *) __attribute__((__noreturn__)); + + /* + * Shutdown PXE + */ + dev_cleanup(); + + i386_copyin(buf, (vm_offset_t)magicaddr, 512); + + /* + * FreeBSD's mbr, boot0 and boot1 all expect %dl to be set to + * the boot device when they are invoked. + * I don't know if this is a BIOS handoff feature or if it is + * a bug and everyone assumes it is a bit of PC lore. + * + * Anyway, we set it here and it makes it through the BTX intact. + */ + __asm __volatile("movb %0,%%dl" : : "m" (diskdev)); + + __restart(magicaddr); +} + +/* + * Boot from the MBR. As long as there is a MBR, and its intact, + * something good should happen (say, Lilo will appear). + */ +static void +boot_mbr(void) +{ + boot_from(&diskmbr); +} + +/* + * Load and boot the first sector of the indicated partition. + */ +static void +boot_partition(int pnum, struct bios_partition_info *ptab) +{ + if (load_sector((int)ptab->offset, partbr) != 0 || + ((struct bios_mbr *)partbr)->magic != BIOS_MAGIC) + panic("Could not load/verify partition %d boot record", pnum); + + boot_from(partbr); +} + +/* + * Simply load and boot the MBR right off the disk. + */ +void +boot_mbr_default(void) +{ + printf("Loading MBR and booting active partition\n"); + + (void) load_mbr(1); + boot_mbr(); +} + +/* + * Boot from a partition with a particular sysid. + * Search the table for the first non-empty partition of the given type. + * If the type does not exist, return non-zero. + */ +int +boot_mbr_sysid(int sysid) +{ + struct bios_partition_info *entry; + int partition; + + printf("Loading MBR and booting system ID %d\n", sysid); + + (void) load_mbr(1); + + /* + * Look for a non-empty partition that matches the one we want. + */ + entry = (struct bios_partition_info *)diskmbr.partinfo; + for (partition = 0; partition < 4; partition++, entry++) { + if (entry->numsectors == 0) + continue; + if (entry->sysid == sysid) + break; + } + if (partition == 4) { + printf("%d: sysid not found in any partition\n", sysid); + return 1; + } + + if (set_active(partition+1) != 0) + printf("WARNING: could not set active partition in MBR\n"); + boot_partition(partition+1, entry); + return 0; +} + +/* + * Boot from a particular partition. + * If the partition does not exist, return non-zero. + */ +int +boot_mbr_partition(int partition) +{ + struct bios_partition_info *entry; + + /* XXX hack: part:0 means boot through MBR */ + if (partition == 0) + boot_mbr_default(); + + printf("Loading MBR and booting system partition %d\n", partition); + + if (partition < 1 || partition > 4) { + printf("%d: invalid partition number\n", partition); + return 1; + } + + /* partition is 1-based, table is 0-based */ + partition--; + + (void) load_mbr(1); + + entry = ((struct bios_partition_info *)diskmbr.partinfo) + partition; + if (entry->numsectors == 0) { + printf("%d: non-existent partition\n", partition+1); + return 1; + } + + if (set_active(partition+1) != 0) + printf("WARNING: could not set active partition in MBR\n"); + boot_partition(partition+1, entry); + return 0; +} + +/* + * Return the sysid for a partition. + */ +int +partition_sysid(int partition, int *sysid) +{ + struct bios_partition_info *entry; + + if (partition < 1 || partition > 4) { + printf("%d: invalid partition number\n", partition); + return 1; + } + + /* partition is 1-based, table is 0-based */ + partition--; + + (void) load_mbr(1); + + entry = ((struct bios_partition_info *)diskmbr.partinfo) + partition; + if (entry->numsectors == 0) { + printf("%d: non-existent partition\n", partition+1); + return 1; + } + *sysid = entry->sysid; + return 0; +} + +int +load_sector(int sectno, void *buf) +{ + int fd, rv = 0; + + set_bootdisk(diskdev); + fd = open(bootdevice, 0); + if (fd >= 0) { + if (lseek(fd, (off_t)sectno * 512, SEEK_SET) < 0 || + read(fd, buf, 512) < 512) { + rv = errno; +#ifdef DEBUG + printf("short/failed read of sector %d, err=%x\n", + sectno, rv); +#endif + } + close(fd); + } else { + rv = errno; +#ifdef DEBUG + printf("failed open of %s, err=%x\n", bootdevice, rv); +#endif + } + +#ifdef DEBUG + printf("Got sector %d: magic=0x%x\n", + sectno, ((unsigned short *)buf)[255]); +#endif + return rv; +} + +#include + +/* + * Set the active partition in the disk MBR + */ +int +set_active(int apart) +{ + struct bios_partition_info *entry; + int i; + + if (apart < 1 || apart > 4) { + printf("set_active: invalid partition number %d\n", apart); + return 1; + } + + if (load_mbr(0) != 0) { + printf("set_active: could not load MBR\n"); + return 1; + } + + /* + * Already active + */ + entry = &((struct bios_partition_info *)diskmbr.partinfo)[apart-1]; + if (entry->bootid & BIOS_BOOTABLE) + return 0; + + /* + * Verify the desired partition and mark it as active + */ + if (entry->numsectors == 0) { + printf("set_active: emptry partition %d\n", apart); + return 1; + } + entry->bootid |= BIOS_BOOTABLE; + + /* + * Clear any other active indicator. + */ + apart--; + entry = (struct bios_partition_info *)diskmbr.partinfo; + for (i = 0; i < 4; i++, entry++) + if (i != apart && (entry->bootid & BIOS_BOOTABLE)) + entry->bootid &= ~BIOS_BOOTABLE; + + /* + * Write MBR back out. + * + * XXX we do this totally behind the back of the boot loader + * subsystem (biosdisk) since it doesn't support disk writes. + * Thus, this is the last thing you should do before jumping + * to the next level boot code. + * + * This code lifted from the biosdisk read code. + */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x300 | 1; + v86.ecx = 1; + v86.edx = diskdev; + v86.es = VTOPSEG(&diskmbr); + v86.ebx = VTOPOFF(&diskmbr); + v86int(); + if (v86.efl & 0x1) { + printf("set_active: could not write back MBR, eax=0x%x\n", + v86.eax); + return 1; + } + return 0; +} + +/* + * XXX for LILO support + */ + +/* + * Read the boot block for the indicated partition. + * Returns a pointer to our buffer on success, 0 on failure. + */ +void * +load_partition_bblock(int pnum) +{ + struct bios_partition_info *entry; + + if (load_mbr(0) != 0) + return 0; + + pnum--; + entry = ((struct bios_partition_info *)diskmbr.partinfo) + pnum; + if (load_sector((int)entry->offset, partbr) != 0 || + ((struct bios_mbr *)partbr)->magic != BIOS_MAGIC) { + printf("Could not load/verify partition %d boot record", pnum); + return 0; + } + + return partbr; +} + +/* + * Update a disk sector. + * Return 0 on success, non-zero otherwise. + * + * XXX we do this totally behind the back of the boot loader + * subsystem (biosdisk) since it doesn't support disk writes. + */ +int +save_sector(int sectno, void *buf) +{ + u_int cyl, hd, sec, bpc, dblk; + + dblk = sectno; + + /* + * Get the disk geometry + */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x800; + v86.edx = diskdev; + v86int(); + + if (v86.efl & 0x1) { +#ifdef DEBUG + printf("save_sector: cannot get disk geometry\n"); +#endif + return 1; + } + + hd = ((v86.edx & 0xff00) >> 8) + 1; + sec = v86.ecx & 0x3f; + bpc = sec * hd; + + cyl = dblk / bpc; + if (cyl > 1023) { + printf("save_sector: cannot do cyl > 1024\n"); + return 1; + } + + dblk %= bpc; + hd = dblk / sec; + sec = dblk % sec; + sec++; + + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x300 | 1; + v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; + v86.edx = (hd << 8) | diskdev; + v86.es = VTOPSEG(buf); + v86.ebx = VTOPOFF(buf); + v86int(); + if (v86.efl & 0x1) { + printf("save_sector: could not write back sector %d\n", + sectno); + return 1; + } + return 0; +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot-cd/testbed.c 6.2/src/sys/boot/i386/emuboot-cd/testbed.c --- 6.2-release/src/sys/boot/i386/emuboot-cd/testbed.c Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot-cd/testbed.c Fri Mar 9 17:10:00 2007 @@ -0,0 +1,259 @@ +/* + * EMULAB-COPYRIGHT + * Copyright (c) 2000-2002, 2004, 2007 University of Utah and the Flux Group. + * All rights reserved. + */ + +/* + * Copyright (c) 1998 Michael Smith + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include "../libi386/libi386.h" + +#include "bootstrap.h" +#include "testbed_boot.h" + +COMMAND_SET(testbed_boot, "testbed_boot", + "boot the testbed", command_tbboot); + +static char iobuf[SECSIZE]; +static int gettbboot(int unit, tbboot_t *tbhdr); +extern int unload_modules(void); + +extern int boot_mbr_partition(int partition); +extern int set_active(int apart); + +static int +command_tbboot(int argc, char *argv[]) +{ + char *defpart = "a"; + char diskdev[32], ffs[32]; + tbboot_t tbboot_hdr, *tbhdr = &tbboot_hdr; + int biosdev, unit, slice; + unsigned newcrc; + + if (argc < 2) { + for (unit = 0; ; unit++) { + biosdev = bd_unit2bios(unit); + if (biosdev == -1) { + sprintf(command_errbuf, + "no drive found for testbed boot"); + return(CMD_ERROR); + } + if (biosdev >= 0x80 && gettbboot(unit, tbhdr) == 0) + break; + } + sprintf(diskdev, "disk%d", unit); + } + else { + unit = -1; + if (strncmp(argv[1], "disk", 4) == 0 && + argv[1][4] >= '0' && argv[1][4] <= '9') + unit = argv[1][4] - '0'; + + biosdev = bd_unit2bios(unit); + if (biosdev == -1) { + sprintf(command_errbuf, + "no such drive '%s' for testbed boot", + argv[1]); + return(CMD_ERROR); + } + if (biosdev < 0x80 || gettbboot(unit, tbhdr) != 0) { + sprintf(command_errbuf, + "invalid drive '%s' for testbed boot", + argv[1]); + return(CMD_ERROR); + } + strncpy(diskdev, argv[1], sizeof(diskdev)); + } + slice = tbhdr->bootfromdisk; + if (slice == 255) { + slice = 0; + strncpy(ffs, diskdev, sizeof(ffs)); + } else { + sprintf(ffs, "%ss%d%s", diskdev, slice, defpart); + } + set_bootdisk(biosdev); + strcat(diskdev, ":"); + + /* + * Check boot direction. Its an error for them to be equal, + * so boot to the cdrom and leave things as they are. + */ + if (tbhdr->bootfromcdrom || + tbhdr->bootfromcdrom == tbhdr->bootfromdisk) { + if (tbhdr->bootfromcdrom == tbhdr->bootfromdisk) + printf("Oops, bootfromdisk==bootfromcdrom==%d. " + "Booting from CDROM ...\n", + tbhdr->bootfromdisk); + else + printf("Booting from CDROM ...\n"); + + autoboot(-1, NULL); + return 0; + } + + /* + * Only choice is bootfromdisk=$slice. Clear it and go. + */ + tbhdr->bootfromdisk = 0; + tbhdr->bootfromcdrom = 1; + newcrc = crc32(0L, Z_NULL, 0); + newcrc = crc32(newcrc, (const char *) tbhdr, sizeof(*tbhdr)); + tbhdr->checksum = newcrc; + + /* + * Write the sector out. + */ + printf("Writing out new boot header ...\n"); + { + bzero(iobuf, sizeof(iobuf)); + memcpy(iobuf, tbhdr, sizeof(*tbhdr)); + + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x301; /* Write 1 sector */ + v86.ecx = TBBOOT_SECTOR + 1; /* BIOS is 1-based */ + v86.edx = biosdev; + v86.es = VTOPSEG(iobuf); + v86.ebx = VTOPOFF(iobuf); + v86int(); + if (v86.efl & 0x1) { + sprintf(command_errbuf, "Header write failed!"); + return(CMD_ERROR); + } + } + + /* + * Set the active partition on the disk we want to boot, and then + * load the appropriate boot sector. Even if we aren't loading the + * MBR boot sector, we still modify the active partition as some + * boot loaders (BSD boot2) use the active bit from there. + * + * We could/should optimize this for when we are booting into + * a BSD filesystem; i.e., just load the kernel from here. + */ + printf("Setting the active partition of %s to %d...\n", + diskdev, slice); + set_active(slice); + + /* + * Switch over and go + */ +#if 0 + /* + * We do this on the RON CD cause we know we are going to boot a + * FreeBSD slice, but in the testbed it could be anything, so we + * must boot through the MBR. As an optimization, we could do this + * if we first looked inside the slice to see what its type is. + */ + unload_modules(); + unsetenv("vfs.root.mountfrom"); + setenv("currdev", ffs, 1); +#endif + printf("Booting from %s...\n", ffs); +#if 0 + /* debugging: give us time to read the message on VGA */ + delay(2000000); +#endif + boot_mbr_partition(slice); + return(0); +} + +static int +gettbboot(int unit, tbboot_t *tbhdr) +{ + char disk[16]; + unsigned oldcrc, newcrc; + int fd; + + sprintf(disk, "disk%d:", unit); + + /* + * Open the disk and look for the magic structure. + */ + fd = open(disk, O_RDONLY); + if (fd < 0) { + printf("gettbboot: open '%s' failed: %s", disk, strerror(errno)); + goto out; + } + if (lseek(fd, (off_t) TBBOOT_OFFSET, SEEK_SET) < 0) { + printf("gettbboot: lseek '%s' failed: %s",disk, strerror(errno)); + goto out; + } + if (read(fd, iobuf, sizeof(iobuf)) < 0) { + printf("gettbboot: read '%s' failed: %s", disk, strerror(errno)); + goto out; + } +#if 0 /* causes a panic from free */ + close(fd); +#endif + fd = -1; + + memcpy(tbhdr, iobuf, sizeof(*tbhdr)); + if (tbhdr->magic1 != TBBOOT_MAGIC1 || + tbhdr->magic2 != TBBOOT_MAGIC2) { +#if 0 /* do not complain about this, as it might be RO dongle (aka CD) */ + printf("gettbboot: bad magic number on '%s'", disk); +#endif + goto out; + } + + if (0) { + printf("%s\n", disk); + printf(" bootfromdisk: %d\n", tbhdr->bootfromdisk); + printf(" bootfromcdrom: %d\n", tbhdr->bootfromcdrom); + printf(" checksum: %lx\n", tbhdr->checksum); + } + + /* + * Check the checksum. + */ + oldcrc = tbhdr->checksum; + tbhdr->checksum = 0; + newcrc = crc32(0L, Z_NULL, 0); + newcrc = crc32(newcrc, (const char *) tbhdr, sizeof(*tbhdr)); + + if (newcrc != oldcrc) { + printf("gettbboot: bad checksum number on '%s'", disk); + goto out; + } + + /* + * Good header! + */ + return(0); + + out: + if (fd >= 0) + close(fd); + return(CMD_ERROR); +} diff -ruN 6.2-release/src/sys/boot/i386/emuboot-cd/testbed_boot.h 6.2/src/sys/boot/i386/emuboot-cd/testbed_boot.h --- 6.2-release/src/sys/boot/i386/emuboot-cd/testbed_boot.h Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot-cd/testbed_boot.h Thu May 27 14:00:18 2004 @@ -0,0 +1,111 @@ +/* + * EMULAB-COPYRIGHT + * Copyright (c) 2000-2002 University of Utah and the Flux Group. + * All rights reserved. + */ + +#include + +/* + * This structure is placed in the boot block. The loader reads the + * structure to determine whether it should boot from CDROM or switch + * to the disk. + * + * The basic idea is this: + * + * 1. The node always boots from the CD-ROM (first in boot chain). + * 2. The loader looks for this magic structure: + * 2a: If not present continues to load from the CD-ROM (step 4). + * 2b: If present check the contents of the structure. If directed to + * boot from the disk goto step 3. If not, continues to load from + * the CDROM (step 4). + * 3. Boot from the disk. Switch the boot device to the disk so that the + * kernel is loaded from the disk. Also reset the flag (written to disk) + * to indicate that next reboot should happen from the CDROM. Also set + * another flag, cleared by the kernel, that indicates the kernel booted + * okay. This avoids reboot loops in the case of a scrogged disk. + * 4. Boot from the CD-ROM. The user level code on the CD-ROM will take care + * of the rest, writing the proper flags to the structure on the disk. + * Normally, this means checking in with Emulab, and then setting the flag + * to cause it to boot from the disk. + * + * This entire structure has to be less than a sector. + */ +#define SECSIZE 512 +#define TBBOOT_MAXIFACELEN 12 +#define TBBOOT_MAXHOSTLEN 32 +#define TBBOOT_MAXDOMAINLEN 64 +#define TBBOOT_MAXKEYLEN 64 +#define TBBOOT_MAXDISKDEVLEN 32 + +typedef struct tbboot_header +{ + unsigned long magic1; + short version; + + /* + * Set bootfromdisk to 1 to force loader to boot from disk. + */ + char bootfromdisk; + + /* + * Set bootfromcdrom to 0 when booting from the disk. The kernel + * will set this to 1. If the cdrom boots with bootfromdisk 0 + * and bootfromcdrom 0, something went wrong and the kernel did not + * boot properly. Avoids a loop. + */ + char bootfromcdrom; + + /* + * Flag to indicate the image is valid. Clear this when writing + * a new image, and set it when done. + */ + char validimage; + + /* + * Flag to indicate the system config block is valid (has info). + */ + char validconfig; + + /* + * crc32 from the zlib library. + */ + unsigned long checksum; + + /* Paranoia */ + unsigned long magic2; + + /* + * The emulab key. + */ + char emulabkey[TBBOOT_MAXKEYLEN]; + + /* + * System configuration. + */ + struct { + char interface[TBBOOT_MAXIFACELEN]; + char hostname[TBBOOT_MAXHOSTLEN]; + char domain[TBBOOT_MAXDOMAINLEN]; + struct in_addr IP; + struct in_addr netmask; + struct in_addr nameserver; + struct in_addr gateway; + } sysconfig; +} tbboot_t; + +/* Magic value identifying the header. */ +#define TBBOOT_MAGIC1 0x9badbeef +#define TBBOOT_MAGIC2 0x69ceafd8 + +/* Current Version */ +#define TBBOOT_VERSION 100 + +/* + * Offset from start of the disk. Hardwired to sector 60 which should be + * clear on our images. + */ +#define TBBOOT_SECTOR 60 +#define TBBOOT_OFFSET (TBBOOT_SECTOR * SECSIZE) + + diff -ruN 6.2-release/src/sys/boot/i386/emuboot-cd/version 6.2/src/sys/boot/i386/emuboot-cd/version --- 6.2-release/src/sys/boot/i386/emuboot-cd/version Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot-cd/version Fri Mar 9 16:31:49 2007 @@ -0,0 +1,7 @@ +$FreeBSD: src/sys/boot/i386/loader/version,v 1.5.2.1 2000/07/06 23:45:00 obrien Exp $ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +1.1: FreeBSD 6.x version +0.9: Working version diff -ruN 6.2-release/src/sys/boot/i386/emuboot0/Makefile 6.2/src/sys/boot/i386/emuboot0/Makefile --- 6.2-release/src/sys/boot/i386/emuboot0/Makefile Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot0/Makefile Mon Mar 12 10:14:15 2007 @@ -0,0 +1,71 @@ +# $FreeBSD: src/sys/boot/i386/boot0/Makefile,v 1.32 2005/04/25 17:41:35 ru Exp $ + +PROG?= emuboot0 +STRIP= +BINMODE=${NOBINMODE} +NO_MAN= +SRCS= ${PROG}.S +MAINTAINER= testbed-ops@emulab.net + +# The default set of flags compiled into boot0. This enables update (writing +# the modified boot0 back to disk after running so that the selection made is +# saved), packet mode (detect and use the BIOS EDD extensions if we try to +# boot past the 1024 cylinder liimt), and booting from all valid slices. +BOOT_BOOT0_FLAGS?= 0x8f + +# The number of timer ticks to wait for a keypress before assuming the default +# selection. Since there are 18.2 ticks per second, the default value of +# 0xb6 (182d) corresponds to 10 seconds. +BOOT_BOOT0_TICKS?= 0xb6 + +# The base address that we the boot0 code to to run it. Don't change this +# unless you are glutton for punishment. +BOOT_BOOT0_ORG?= 0x600 + +# Comm settings for boot0sio. +# Bit(s) Description +# 7-5 data rate (110,150,300,600,1200,2400,4800,9600 bps) +# 4-3 parity (00 or 10 = none, 01 = odd, 11 = even) +# 2 stop bits (set = 2, clear = 1) +# 1-0 data bits (00 = 5, 01 = 6, 10 = 7, 11 = 8) +.if !defined(BOOT_BOOT0_COMCONSOLE_SPEED) +BOOT_COMCONSOLE_SPEED?= 9600 +.if ${BOOT_COMCONSOLE_SPEED} == 9600 +BOOT_BOOT0_COMCONSOLE_SPEED= "7 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 4800 +BOOT_BOOT0_COMCONSOLE_SPEED= "6 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 2400 +BOOT_BOOT0_COMCONSOLE_SPEED= "5 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 1200 +BOOT_BOOT0_COMCONSOLE_SPEED= "4 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 600 +BOOT_BOOT0_COMCONSOLE_SPEED= "3 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 300 +BOOT_BOOT0_COMCONSOLE_SPEED= "2 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 150 +BOOT_BOOT0_COMCONSOLE_SPEED= "1 << 5 + 3" +.elif ${BOOT_COMCONSOLE_SPEED} == 110 +BOOT_BOOT0_COMCONSOLE_SPEED= "0 << 5 + 3" +.else +BOOT_BOOT0_COMCONSOLE_SPEED= "7 << 5 + 3" +.endif +.endif + +CFLAGS+=-DFLAGS=${BOOT_BOOT0_FLAGS} \ + -DTICKS=${BOOT_BOOT0_TICKS} \ + -DCOMSPEED=${BOOT_BOOT0_COMCONSOLE_SPEED} + +LDFLAGS=-N -e start -Ttext ${BOOT_BOOT0_ORG} -Wl,-S,--oformat,binary + +install: + @echo "" + @echo "=============== NOTE ====================" + @echo "emuboot0 should be installed on nodes:" + @echo " sudo scp emuboot0 :/boot # node=\"pc0\", \"pc1\", etc." + @echo "and installed on their disks:" + @echo " slogin " + @echo " sudo boot0cfg -B -b emuboot0 # disk=\"ad0\", \"da0\", etc." + @echo "=========================================" + @echo "" + +.include diff -ruN 6.2-release/src/sys/boot/i386/emuboot0/emuboot0.S 6.2/src/sys/boot/i386/emuboot0/emuboot0.S --- 6.2-release/src/sys/boot/i386/emuboot0/emuboot0.S Wed Dec 31 17:00:00 1969 +++ 6.2/src/sys/boot/i386/emuboot0/emuboot0.S Mon Mar 12 10:29:07 2007 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2002 Bruce M. Simpson + * 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: src/sys/boot/i386/boot0/boot0.S,v 1.14.2.1 2006/05/31 21:32:24 jhb Exp $ + */ + +/* A modified version of the standard BSD boot0 program intended for use + * in Emulab. The only difference is that if there is no explicit input + * from the user we reboot. This is intended to be use in conjunction + * with the Emulab PXE boot loader (emuboot) where we should never reach + * the MBR boot code. Booting via the MBR implies that either the PXE BIOS + * didn't succeed (e.g., lost UDP packets during DHCP) or the bootinfo + * protocol broke down (e.g., lost UDP packets). In either case, we really + * want to keep trying. The easiest way to implement a retry at this level + * is to just reboot. + * + * We leave a provision for explicitly specifying a partition to boot from + * via console input so that a machine can be rebooted when detached from + * the Emulab environment. + */ + +/* A 512-byte boot manager. */ +#ifdef SIO +/* ... using a serial console on COM1. */ +#endif + + .set NHRDRV,0x475 # Number of hard drives + .set ORIGIN,0x600 # Execution address + .set FAKE,0x800 # Partition entry + .set LOAD,0x7c00 # Load address + + .set PRT_OFF,0x1be # Partition table + + .set TBL0SZ,0x3 # Table 0 size + .set TBL1SZ,0xa # Table 1 size + + .set MAGIC,0xaa55 # Magic: bootable + .set B0MAGIC,0xbb66 # Identification + + .set KEY_ENTER,0x1c # Enter key scan code + .set KEY_F1,0x3b # F1 key scan code + .set KEY_1,0x02 # #1 key scan code + + .set ASCII_BEL,0x07 # ASCII code for + .set ASCII_CR,0x0D # ASCII code for + +/* + * Addresses in the sector of embedded data values. + * Accessed with negative offsets from the end of the relocated sector (%ebp). + */ + .set _NXTDRV,-0x48 # Next drive + .set _OPT,-0x47 # Default option + .set _SETDRV,-0x46 # Drive to force + .set _FLAGS,-0x45 # Flags + .set _TICKS,-0x44 # Timeout ticks + .set _FAKE,0x0 # Fake partition entry + .set _MNUOPT,0xc # Menu options + + .globl start # Entry point + .code16 # This runs in real mode + +/* + * Initialise segments and registers to known values. + * segments start at 0. + * The stack is immediately below the address we were loaded to. + */ +start: cld # String ops inc + xorw %ax,%ax # Zero + movw %ax,%es # Address + movw %ax,%ds # data + movw %ax,%ss # Set up + movw $LOAD,%sp # stack + +/* + * Copy this code to the address it was linked for + */ + movw %sp,%si # Source + movw $start,%di # Destination + movw $0x100,%cx # Word count + rep # Relocate + movsw # code +/* + * Set address for variable space beyond code, and clear it. + * Notice that this is also used to point to the values embedded in the block, + * by using negative offsets. + */ + movw %di,%bp # Address variables + movb $0x8,%cl # Words to clear + rep # Zero + stosw # them +/* + * Relocate to the new copy of the code. + */ + incb -0xe(%di) # Sector number + jmp main-LOAD+ORIGIN # To relocated code + +main: +#if defined(SIO) && COMSPEED != 0 +/* + * Initialize the serial port. bioscom preserves the driver number in DX. + */ + movw COMSPEED,%ax # defined by Makefile + callw bioscom +#endif +/* + * Check what flags were loaded with us, specifically if a predefined drive + * number should be used. If what the bios gives us is bad, use the '0' in + * the block instead. + */ + testb $0x20,_FLAGS(%bp) # Set drive number? + jnz main.1 # Yes + testb %dl,%dl # Drive number valid? + js main.2 # Possibly (0x80 set) +/* + * Only update the boot-sector when there is a valid drive number or + * the drive number is set manually. + */ + orb $0x40,_FLAGS(%bp) # Disable updates +main.1: movb _SETDRV(%bp),%dl # Drive number to use +/* + * Whatever we decided to use, now store it into the fake + * partition entry that lives in the data space above us. + */ +main.2: movb %dl,_FAKE(%bp) # Save drive number + callw putn # To new line + pushw %dx # Save drive number +/* + * Start out with a pointer to the 4th byte of the first table entry + * so that after 4 iterations it's beyond the end of the sector + * and beyond a 256 byte boundary and has overflowed 8 bits (see next comment). + * Remember that the table starts 2 bytes earlier than you would expect + * as the bootable flag is after it in the block. + */ + movw $(partbl+0x4),%bx # Partition table (+4) + xorw %dx,%dx # Item number +/* + * Loop around on the partition table, printing values until we + * pass a 256 byte boundary. The end of loop test is at main.5. + */ +main.3: movb %ch,-0x4(%bx) # Zero active flag (ch == 0) + btw %dx,_FLAGS(%bp) # Entry enabled? + jnc main.5 # No +/* + * If any of the entries in the table are the same as the 'type' in the slice + * table entry, then this is an empty or non bootable partition. Skip it. + */ + movb (%bx),%al # Load type + movw $tables,%di # Lookup tables + movb $TBL0SZ,%cl # Number of entries + repne # Exclude + scasb # partition? + je main.5 # Yes +/* + * Now scan the table of known types + */ + movb $TBL1SZ+1,%cl # Number of entries + repne # Locate + scasb # type +/* + * Get the matching element in the next array. + */ + addw $TBL1SZ-1, %di # Adjust + movb (%di),%cl # Partition + addw %cx,%di # description + callw putx # Display it +main.5: incw %dx # Next item + addb $0x10,%bl # Next entry + jnc main.3 # Till done +/* + * Passed a 256 byte boundary; the table is finished. + * Add one to the drive number and check it is valid. + */ + popw %ax # Drive number + subb $0x80-0x1,%al # Does next + cmpb NHRDRV,%al # drive exist? (from BIOS?) + jb main.6 # Yes +/* + * If this is the only drive, don't display it as an option. + */ + decw %ax # Already drive 0? + jz main.7 # Yes +/* + * If it was illegal or we cycled through them, go back to drive 0. + */ + xorb %al,%al # Drive 0 +/* + * Whatever drive we selected, make it an ascii digit and save it back to the + * "next drive" location in the loaded block in case we want to save it later + * for next time. This also is part of the printed drive string so add 0x80 + * to indicate end of string. + */ +main.6: addb $'0'|0x80,%al # Save next + movb %al,_NXTDRV(%bp) # drive number + movw $drive,%di # Display + callw putx # item +/* + * Now that we've printed the drive (if we needed to), display a prompt. + */ +main.7: movw $prompt,%si # Display + callw putstr # prompt + jmp main.7_1 # Skip beep +/* + * Users's last try was bad, beep in displeasure. + */ +main.10: movb $ASCII_BEL,%al # Signal + callw putchr # beep! +/* + * Start of input loop. Take note of time + */ +main.7_1: xorb %ah,%ah # BIOS: Get + int $0x1a # system time + movw %dx,%di # Ticks when + addw _TICKS(%bp),%di # timeout +/* + * Busy loop, looking for keystrokes but keeping one eye on the time. + */ +main.8: +#ifndef SIO + movb $0x1,%ah # BIOS: Check + int $0x16 # for keypress + jnz main.11 # Have one +#else /* SIO */ + movb $0x03,%ah # BIOS: Read COM + call bioscom + testb $0x01,%ah # Check line status + jnz main.11 # (bit 1 indicates input) +#endif /* SIO */ + xorb %ah,%ah # BIOS: Get + int $0x1a # system time + cmpw %di,%dx # Timeout? + jb main.8 # No +/* + * If timed out or defaulting, come here. + */ +main.9: movw $0x1234,0x472 # Set warm boot and + ljmp $0xffff,$0x0 # reboot the machine +/* + * Get the keystroke. + */ +main.11: +#ifndef SIO + xorb %ah,%ah # BIOS: Get + int $0x16 # keypress + movb %ah,%al # Scan code +#else + movb $0x02,%ah # BIOS: Receive + call bioscom +#endif +/* + * If it's CR act as if timed out. + */ +#ifndef SIO + cmpb $KEY_ENTER,%al # Enter pressed? +#else + cmpb $ASCII_CR,%al # Enter pressed? +#endif + je main.9 # Yes +/* + * Otherwise check if legal. If not ask again. + */ +#ifndef SIO + subb $KEY_F1,%al # Less F1 scan code + cmpb $0x4,%al # F1..F5? + jna main.12 # Yes + subb $(KEY_1 - KEY_F1),%al # Less #1 scan code +#else + subb $'1',%al # Less '1' ascii character +#endif + cmpb $0x4,%al # #1..#5? + ja main.10 # No +/* + * We have a selection. If it's a bad selection go back to complain. + * The bits in MNUOPT were set when the options were printed. + * Anything not printed is not an option. + */ +main.12: cbtw # Option + btw %ax,_MNUOPT(%bp) # enabled? + jnc main.10 # No +/* + * Save the info in the original tables + * for rewriting to the disk. + */ + movb %al,_OPT(%bp) # Save option + movw $FAKE,%si # Partition for write + movb (%si),%dl # Drive number + movw %si,%bx # Partition for read + cmpb $0x4,%al # F5/#5 pressed? + pushf # Save + je main.13 # Yes + shlb $0x4,%al # Point to + addw $partbl,%ax # selected + xchgw %bx,%ax # partition + movb $0x80,(%bx) # Flag active +/* + * If not asked to do a write-back (flags 0x40) don't do one. + */ +main.13: pushw %bx # Save + testb $0x40,_FLAGS(%bp) # No updates? + jnz main.14 # Yes + movw $start,%bx # Data to write + movb $0x3,%ah # Write sector + callw intx13 # to disk +main.14: popw %si # Restore + popf # Restore +/* + * If going to next drive, replace drive with selected one. + * Remember to un-ascii it. Hey 0x80 is already set, cool! + */ + jne main.15 # If not F5/#5 + movb _NXTDRV(%bp),%dl # Next drive + subb $'0',%dl # number +/* + * Load selected bootsector to the LOAD location in RAM. + * If it fails to read or isn't marked bootable, treat it as a bad selection. + */ +main.15: movw $LOAD,%bx # Address for read + movb $0x2,%ah # Read sector + callw intx13 # from disk + jc main.10 # If error + cmpw $MAGIC,0x1fe(%bx) # Bootable? + jne main.10 # No + movw $crlf,%si # Leave some + callw puts # space + jmp *%bx # Invoke bootstrap + +/* + * Display routines + */ +putkey: +#ifndef SIO + movb $'F',%al # Display + callw putchr # 'F' +#endif + movb $'1',%al # Prepare + addb %dl,%al # digit + jmp putstr.1 # Display the rest + +/* + * Display the option and note that it is a valid option. + * That last point is a bit tricky.. + */ +putx: btsw %dx,_MNUOPT(%bp) # Enable menu option + movw $item,%si # Display + callw putkey # key + movw %di,%si # Display the rest + +puts: callw putstr # Display string + +putn: movw $crlf,%si # To next line + +putstr: lodsb # Get byte + testb $0x80,%al # End of string? + jnz putstr.2 # Yes +putstr.1: callw putchr # Display char + jmp putstr # Continue +putstr.2: andb $~0x80,%al # Clear MSB + +#ifndef SIO +putchr: + pushw %bx # Save + movw $0x7,%bx # Page:attribute + movb $0xe,%ah # BIOS: Display + int $0x10 # character + popw %bx # Restore + retw # To caller +#else /* SIO */ +putchr: + movb $0x01,%ah # BIOS: Send +bioscom: + pushw %dx # Save + xorw %dx,%dx # Use COM1 + int $0x14 # Character + popw %dx # Restore + retw # To caller +#endif /* SIO */ + +/* One-sector disk I/O routine */ + +intx13: movb 0x1(%si),%dh # Load head + movw 0x2(%si),%cx # Load cylinder:sector + movb $0x1,%al # Sector count + pushw %si # Save + movw %sp,%di # Save + testb $0x80,_FLAGS(%bp) # Use packet interface? + jz intx13.1 # No + pushl $0x0 # Set the + pushl 0x8(%si) # LBA address + pushw %es # Set the transfer + pushw %bx # buffer address + push $0x1 # Block count + push $0x10 # Packet size + movw %sp,%si # Packet pointer + decw %ax # Verify off + orb $0x40,%ah # Use disk packet +intx13.1: int $0x13 # BIOS: Disk I/O + movw %di,%sp # Restore + popw %si # Restore + retw # To caller + +/* Menu strings */ + +item: .ascii " "; .byte ' '|0x80 +prompt: .ascii "\nPXE bad:"; .byte ' '|0x80 +crlf: .ascii "\r"; .byte '\n'|0x80 + +/* Partition type tables */ + +tables: +/* + * These entries identify invalid or NON BOOT types and partitions. + */ + .byte 0x0, 0x5, 0xf +/* + * These values indicate bootable types we know the names of. + */ + .byte 0x1, 0x6, 0x7, 0xb, 0xc, 0xe, 0x83 + .byte 0xa5, 0xa6, 0xa9 +/* + * These are offsets that match the known names above and point to the strings + * that will be printed. os_misc will be used if the search of the above table + * runs over. + */ + .byte os_dos-. # DOS + .byte os_dos-. # DOS + .byte os_dos-. # Windows + .byte os_dos-. # Windows + .byte os_dos-. # Windows + .byte os_dos-. # Windows + .byte os_linux-. # Linux + .byte os_freebsd-. # FreeBSD + .byte os_bsd-. # OpenBSD + .byte os_bsd-. # NetBSD + .byte os_misc-. # Unknown +/* + * And here are the strings themselves. 0x80 or'd into a byte indicates + * the end of the string. (not so great for Russians but...) + */ +os_misc: .ascii "?"; .byte '?'|0x80 +os_dos: .ascii "DO"; .byte 'S'|0x80 +os_linux: .ascii "Linu"; .byte 'x'|0x80 +os_freebsd: .ascii "Free" +os_bsd: .ascii "BS"; .byte 'D'|0x80 + + .org PRT_OFF-0xe,0x90 + + .word B0MAGIC # Magic number + +/* + * These values are sometimes changed before writing back to the drive + * Be especially careful that nxtdrv: must come after drive:, as it + * is part of the same string. + */ +drive: .ascii "Drive " +nxtdrv: .byte 0x0 # Next drive number +opt: .byte 0x0 # Option +setdrv: .byte 0x80 # Drive to force +flags: .byte FLAGS # Flags +ticks: .word TICKS # Delay + +/* + * Here is the 64 byte partition table that fdisk would fiddle with. + */ +partbl: .fill 0x40,0x1,0x0 # Partition table + .word MAGIC # Magic number diff -ruN 6.2-release/src/sys/boot/i386/libi386/Makefile 6.2/src/sys/boot/i386/libi386/Makefile --- 6.2-release/src/sys/boot/i386/libi386/Makefile Sun Oct 1 06:07:07 2006 +++ 6.2/src/sys/boot/i386/libi386/Makefile Thu Mar 1 10:27:26 2007 @@ -6,9 +6,9 @@ SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \ comconsole.c devicename.c elf32_freebsd.c \ - elf64_freebsd.c \ i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ - smbios.c time.c vidconsole.c amd64_tramp.S + smbios.c time.c vidconsole.c +#SRCS+= elf64_freebsd.c amd64_tramp.S BOOT_COMCONSOLE_PORT?= 0x3f8 CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT} diff -ruN 6.2-release/src/sys/boot/i386/libi386/elf32_freebsd.c 6.2/src/sys/boot/i386/libi386/elf32_freebsd.c --- 6.2-release/src/sys/boot/i386/libi386/elf32_freebsd.c Sat Aug 28 18:48:41 2004 +++ 6.2/src/sys/boot/i386/libi386/elf32_freebsd.c Tue Dec 12 15:55:04 2006 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/boot/i386/libi386/elf32_freebsd.c,v 1.14 2004/08/29 00:48:41 iedowse Exp $"); +__FBSDID("$FreeBSD: src/sys/boot/i386/libi386/elf32_freebsd.c,v 1.14.2.1 2006/11/27 14:53:53 ru Exp $"); #include #include @@ -46,7 +46,7 @@ struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; /* - * There is an a.out kernel and one or more a.out modules loaded. + * There is an ELF kernel and one or more ELF modules loaded. * We wish to start executing the kernel image, so make such * preparations as are required, and do so. */ diff -ruN 6.2-release/src/sys/boot/i386/libi386/elf64_freebsd.c 6.2/src/sys/boot/i386/libi386/elf64_freebsd.c --- 6.2-release/src/sys/boot/i386/libi386/elf64_freebsd.c Sat Aug 28 18:48:41 2004 +++ 6.2/src/sys/boot/i386/libi386/elf64_freebsd.c Tue Dec 12 15:55:04 2006 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/boot/i386/libi386/elf64_freebsd.c,v 1.15 2004/08/29 00:48:41 iedowse Exp $"); +__FBSDID("$FreeBSD: src/sys/boot/i386/libi386/elf64_freebsd.c,v 1.15.2.1 2006/11/27 14:53:53 ru Exp $"); #define __ELF_WORD_SIZE 64 #include @@ -64,7 +64,7 @@ extern amd64_tramp(); /* - * There is an a.out kernel and one or more a.out modules loaded. + * There is an ELF kernel and one or more ELF modules loaded. * We wish to start executing the kernel image, so make such * preparations as are required, and do so. */ diff -ruN 6.2-release/src/sys/boot/i386/libi386/pxe.c 6.2/src/sys/boot/i386/libi386/pxe.c --- 6.2-release/src/sys/boot/i386/libi386/pxe.c Sun Apr 17 15:38:22 2005 +++ 6.2/src/sys/boot/i386/libi386/pxe.c Thu Mar 1 13:34:10 2007 @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -48,6 +49,12 @@ #include "pxe.h" /* + * Set to 1 to use cached PXE info rather than doing a bootp ourselves. + * Set to 0 to get the old behavior of doing a redundant bootp. + */ +#define USE_CACHED_BOOTP_INFO 1 + +/* * Allocate the PXE buffers statically instead of sticking grimy fingers into * BTX's private data area. The scratch buffer is used to send information to * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. @@ -61,6 +68,7 @@ static pxe_t *pxe_p = NULL; /* !PXE */ static BOOTPLAYER bootplayer; /* PXE Cached information. */ +int pxe_nobootp = USE_CACHED_BOOTP_INFO; static int pxe_debug = 0; static int pxe_sock = -1; static int pxe_opens = 0; @@ -77,7 +85,9 @@ static int pxe_close(struct open_file *f); static void pxe_print(int verbose); static void pxe_cleanup(void); +#ifndef NO_NFS_SUPPORT static void pxe_setnfshandle(char *rootpath); +#endif static void pxe_perror(int error); static int pxe_netif_match(struct netif *nif, void *machdep_hint); @@ -218,11 +228,11 @@ (uint8_t) (pxenv_p->Version >> 8), (uint8_t) (pxenv_p->Version & 0xFF)); if (pxe_call == bangpxe_call) - printf("@%04x:%04x\n", + printf("@%04x:%04x (!PXE)\n", pxe_p->EntryPointSP.segment, pxe_p->EntryPointSP.offset); else - printf("@%04x:%04x\n", + printf("@%04x:%04x (PXENV+)\n", pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; @@ -234,6 +244,8 @@ pxe_p = NULL; return (0); } + if (gci_p->BufferSize > sizeof(bootplayer)) + gci_p->BufferSize = sizeof(bootplayer); bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), &bootplayer, gci_p->BufferSize); return (1); @@ -274,14 +286,72 @@ } if (rootip.s_addr == 0) { /* + * Have seen the case where PXE doesn't fill in the + * client address. If so, we do need to bootp. + */ + if (pxe_nobootp && bootplayer.yip == 0) { + printf("pxe_open: no client addr in PXE info, " + "must bootp\n"); + pxe_nobootp = 0; + } + + /* * Do a bootp/dhcp request to find out where our * NFS/TFTP server is. Even if we dont get back * the proper information, fall back to the server * which brought us to life and a default rootpath. */ - bootp(pxe_sock, BOOTP_PXE); - if (rootip.s_addr == 0) - rootip.s_addr = bootplayer.sip; + if (!pxe_nobootp) + bootp(pxe_sock, BOOTP_PXE); + if (rootip.s_addr == 0) { + extern struct in_addr servip; + uint8_t vmagic[] = VM_RFC1048; + + /* + * Where available, use the information in the PXE + * bootplayer struct. + */ + printf("pxe_open:%susing PXE DHCP info\n", + pxe_nobootp ? " " : " incomplete bootp, "); + + if (bootplayer.yip != 0) + myip.s_addr = bootplayer.yip; + if (bootplayer.sip != 0) + rootip.s_addr = servip.s_addr = bootplayer.sip; + + /* + * Must look at the cached options for the rest + */ + if (bcmp(bootplayer.vendor.v.magic, vmagic, + sizeof(bootplayer.vendor.v.magic)) == 0) { + uint8_t *cp = bootplayer.vendor.d + 4; + + while (cp < &bootplayer.vendor.d[BOOTP_DHCPVEND]) { + uint8_t tag = *cp++; + uint32_t tsize = *cp++; + + if (tag == TAG_END) + break; + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &netmask, + sizeof(netmask)); + } else if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, + sizeof(gateip.s_addr)); + } else if (tag == TAG_ROOTPATH) { + i = tsize < sizeof(rootpath) ? + tsize : sizeof(rootpath)-1; + bcopy(cp, rootpath, i); + rootpath[i] = '\0'; + } + cp += tsize; + } + } + + if (!bootfile[0] && bootplayer.bootfile[0]) + strncpy(bootfile, bootplayer.bootfile, + sizeof(bootfile)); + } if (!rootpath[1]) strcpy(rootpath, PXENFSROOTPATH); @@ -295,6 +365,8 @@ bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1); bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1); } + printf("pxe_open: ipaddr: %s/", inet_ntoa(myip)); + printf("%s\n", intoa(netmask)); printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); printf("pxe_open: server path: %s\n", rootpath); printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); @@ -306,8 +378,10 @@ sprintf(temp, "%6D", bootplayer.CAddr, ":"); setenv("boot.netif.hwaddr", temp, 1); } +#ifndef NO_NFS_SUPPORT setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); +#endif setenv("dhcp.host-name", hostname, 1); } } @@ -335,8 +409,10 @@ if (pxe_opens > 0) return(0); +#ifndef NO_NFS_SUPPORT /* get an NFS filehandle for our root filesystem */ pxe_setnfshandle(rootpath); +#endif if (pxe_sock >= 0) { @@ -375,11 +451,16 @@ (t_PXENV_UNLOAD_STACK *)scratch_buffer; t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; + t_PXENV_STOP_UNDI *stop_undi_p = + (t_PXENV_STOP_UNDI *)scratch_buffer; #endif if (pxe_call == NULL) return; + /* PXENV_UDP_CLOSE */ + pxe_netif_end(0); + pxe_call(PXENV_UNDI_SHUTDOWN); #ifdef PXE_DEBUG @@ -395,6 +476,17 @@ printf("pxe_cleanup: UNLOAD_STACK failed %x\n", unload_stack_p->Status); #endif + + if (pxe_call != bangpxe_call) + return; + + pxe_call(PXENV_STOP_UNDI); + +#ifdef PXE_DEBUG + if (pxe_debug && stop_undi_p->Status != 0) + printf("pxe_cleanup: STOP_UNDI failed %x\n", + stop_undi_p->Status); +#endif } void @@ -403,6 +495,7 @@ return; } +#ifndef NO_NFS_SUPPORT /* * Reach inside the libstand NFS code and dig out an NFS handle * for the root filesystem. @@ -454,6 +547,7 @@ sprintf(cp, "X"); setenv("boot.nfsroot.nfshandle", buf, 1); } +#endif void pxenv_call(int func) @@ -605,9 +699,11 @@ readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) { t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; - struct udphdr *uh = NULL; + struct udphdr *uh; + struct ip *ip; uh = (struct udphdr *) pkt - 1; + ip = (struct ip *) uh - 1; bzero(udpread_p, sizeof(*udpread_p)); udpread_p->dest_ip = h->myip.s_addr; @@ -629,6 +725,7 @@ return -1; } bcopy(data_buffer, pkt, udpread_p->buffer_size); + ip->ip_src.s_addr = udpread_p->src_ip; uh->uh_sport = udpread_p->s_port; return udpread_p->buffer_size; } diff -ruN 6.2-release/src/sys/boot/i386/libi386/pxe.h 6.2/src/sys/boot/i386/libi386/pxe.h --- 6.2-release/src/sys/boot/i386/libi386/pxe.h Mon Sep 23 12:54:26 2002 +++ 6.2/src/sys/boot/i386/libi386/pxe.h Thu Mar 1 10:09:05 2007 @@ -61,7 +61,9 @@ #define MAC_ARGS(mac) \ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] +#ifndef PXENFSROOTPATH #define PXENFSROOTPATH "/pxeroot" +#endif typedef struct { uint16_t offset; @@ -72,7 +74,7 @@ uint16_t Seg_Addr; uint32_t Phy_Addr; uint16_t Seg_Size; -} SEGDESC_t; +} PACKED SEGDESC_t; typedef uint16_t SEGSEL_t; typedef uint16_t PXENV_STATUS_t; diff -ruN 6.2-release/src/sys/boot/i386/loader/Makefile 6.2/src/sys/boot/i386/loader/Makefile --- 6.2-release/src/sys/boot/i386/loader/Makefile Sun Oct 30 07:37:02 2005 +++ 6.2/src/sys/boot/i386/loader/Makefile Thu Mar 1 10:09:05 2007 @@ -31,6 +31,9 @@ .if !defined(LOADER_NO_GZIP_SUPPORT) CFLAGS+= -DLOADER_GZIP_SUPPORT .endif +.if !defined(LOADER_NO_SPLIT_SUPPORT) +CFLAGS+= -DLOADER_SPLIT_SUPPORT +.endif # Always add MI sources .PATH: ${.CURDIR}/../../common diff -ruN 6.2-release/src/sys/boot/i386/loader/conf.c 6.2/src/sys/boot/i386/loader/conf.c --- 6.2-release/src/sys/boot/i386/loader/conf.c Sat Aug 28 18:48:42 2004 +++ 6.2/src/sys/boot/i386/loader/conf.c Thu Mar 1 12:03:09 2007 @@ -61,7 +61,9 @@ &ext2fs_fsops, &dosfs_fsops, &cd9660_fsops, +#ifdef LOADER_SPLIT_SUPPORT &splitfs_fsops, +#endif #ifdef LOADER_GZIP_SUPPORT &gzipfs_fsops, #endif @@ -84,14 +86,18 @@ */ extern struct file_format i386_elf; extern struct file_format i386_elf_obj; +#if 0 extern struct file_format amd64_elf; extern struct file_format amd64_elf_obj; +#endif struct file_format *file_formats[] = { &i386_elf, &i386_elf_obj, +#ifndef TESTBED &amd64_elf, &amd64_elf_obj, +#endif NULL }; diff -ruN 6.2-release/src/sys/boot/i386/pxeldr/pxeboot.8 6.2/src/sys/boot/i386/pxeldr/pxeboot.8 --- 6.2-release/src/sys/boot/i386/pxeldr/pxeboot.8 Thu Dec 12 10:25:59 2002 +++ 6.2/src/sys/boot/i386/pxeldr/pxeboot.8 Tue Dec 12 15:55:05 2006 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/sys/boot/i386/pxeldr/pxeboot.8,v 1.7 2002/12/12 17:25:59 ru Exp $ +.\" $FreeBSD: src/sys/boot/i386/pxeldr/pxeboot.8,v 1.7.14.1 2006/11/22 16:39:21 pav Exp $ .\" .\" Note: The date here should be updated whenever a non-trivial .\" change is made to the manual page. @@ -103,7 +103,7 @@ .Pp For further information on Intel's PXE specifications and Wired for Management (WfM) systems, see -.Li http://developer.intel.com/ial/wfm/ . +.Li http://www.intel.com/design/archives/wfm/ . .Sh SEE ALSO .Xr loader 8 .Sh HISTORY