svn commit: r320011 - in head/sys/boot: efi/loader forth i386/libi386 i386/loader

Toomas Soome tsoome at FreeBSD.org
Fri Jun 16 20:08:46 UTC 2017


Author: tsoome
Date: Fri Jun 16 20:08:44 2017
New Revision: 320011
URL: https://svnweb.freebsd.org/changeset/base/320011

Log:
  Add chain loader support for loader
  
  Implement simple chain loader in loader; this update does add chain command,
  taking device or file as argument to load and start new boot loader.
  
  In case of BIOS, the chain will read the boot block to address 0000:7c00 and
  jumps on it. In case of UEFI, the chain command is to be used with efi
  application, typically stored in EFI System Partition.
  
  The update also does add simple menu entry, if the variable chain_disk is set.
  The value of the variable chain_disk is used as argument for chain loading.
  
  Relnotes:	yes
  Differential Revision:	https://reviews.freebsd.org/D5992

Added:
  head/sys/boot/i386/libi386/relocater_tramp.S   (contents, props changed)
  head/sys/boot/i386/loader/chain.c   (contents, props changed)
Modified:
  head/sys/boot/efi/loader/main.c
  head/sys/boot/forth/menu.rc
  head/sys/boot/i386/libi386/Makefile
  head/sys/boot/i386/libi386/libi386.h
  head/sys/boot/i386/loader/Makefile
  head/sys/boot/i386/loader/help.i386

Modified: head/sys/boot/efi/loader/main.c
==============================================================================
--- head/sys/boot/efi/loader/main.c	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/efi/loader/main.c	Fri Jun 16 20:08:44 2017	(r320011)
@@ -795,6 +795,100 @@ command_fdt(int argc, char *argv[])
 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
 #endif
 
+/*
+ * Chain load another efi loader.
+ */
+static int
+command_chain(int argc, char *argv[])
+{
+	EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+	EFI_HANDLE loaderhandle;
+	EFI_LOADED_IMAGE *loaded_image;
+	EFI_STATUS status;
+	struct stat st;
+	struct devdesc *dev;
+	char *name, *path;
+	void *buf;
+	int fd;
+
+	if (argc < 2) {
+		command_errmsg = "wrong number of arguments";
+		return (CMD_ERROR);
+	}
+
+	name = argv[1];
+
+	if ((fd = open(name, O_RDONLY)) < 0) {
+		command_errmsg = "no such file";
+		return (CMD_ERROR);
+	}
+
+	if (fstat(fd, &st) < -1) {
+		command_errmsg = "stat failed";
+		close(fd);
+		return (CMD_ERROR);
+	}
+
+	status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
+	if (status != EFI_SUCCESS) {
+		command_errmsg = "failed to allocate buffer";
+		close(fd);
+		return (CMD_ERROR);
+	}
+	if (read(fd, buf, st.st_size) != st.st_size) {
+		command_errmsg = "error while reading the file";
+		(void)BS->FreePool(buf);
+		close(fd);
+		return (CMD_ERROR);
+	}
+	close(fd);
+	status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
+	(void)BS->FreePool(buf);
+	if (status != EFI_SUCCESS) {
+		command_errmsg = "LoadImage failed";
+		return (CMD_ERROR);
+	}
+	status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
+	    (void **)&loaded_image);
+
+	if (argc > 2) {
+		int i, len = 0;
+		CHAR16 *argp;
+
+		for (i = 2; i < argc; i++)
+			len += strlen(argv[i]) + 1;
+
+		len *= sizeof (*argp);
+		loaded_image->LoadOptions = argp = malloc (len);
+		loaded_image->LoadOptionsSize = len;
+		for (i = 2; i < argc; i++) {
+			char *ptr = argv[i];
+			while (*ptr)
+				*(argp++) = *(ptr++);
+			*(argp++) = ' ';
+		}
+		*(--argv) = 0;
+	}
+
+	if (efi_getdev((void **)&dev, name, (const char **)&path) == 0)
+		loaded_image->DeviceHandle =
+		    efi_find_handle(dev->d_dev, dev->d_unit);
+
+	dev_cleanup();
+	status = BS->StartImage(loaderhandle, NULL, NULL);
+	if (status != EFI_SUCCESS) {
+		command_errmsg = "StartImage failed";
+		free(loaded_image->LoadOptions);
+		loaded_image->LoadOptions = NULL;
+		status = BS->UnloadImage(loaded_image);
+		return (CMD_ERROR);
+	}
+
+	return (CMD_ERROR);	/* not reached */
+}
+
+COMMAND_SET(chain, "chain", "chain load file", command_chain);
+
 #ifdef EFI_ZFS_BOOT
 static void
 efi_zfs_probe(void)

Modified: head/sys/boot/forth/menu.rc
==============================================================================
--- head/sys/boot/forth/menu.rc	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/forth/menu.rc	Fri Jun 16 20:08:44 2017	(r320011)
@@ -73,7 +73,22 @@ s" currdev" getenv dup 0> [if] drop 4 s" zfs:" compare
     set mainmenu_command[7]="3 goto_menu"
     set mainmenu_keycode[7]=101
     set mainansi_caption[7]="Select Boot ^[1mE^[37mnvironment..."
+
+    s" chain_disk" getenv? [if]
+	set mainmenu_caption[8]="Chain[L]oad ${chain_disk}"
+	set mainmenu_command[8]="chain ${chain_disk}"
+	set mainmenu_keycode[8]=108
+	set mainansi_caption[8]="Chain^[1mL^[moad ${chain_disk}"
+    [then]
+[else]
+    s" chain_disk" getenv? [if]
+	set mainmenu_caption[7]="Chain[L]oad ${chain_disk}"
+	set mainmenu_command[7]="chain ${chain_disk}"
+	set mainmenu_keycode[7]=108
+	set mainansi_caption[7]="Chain^[1mL^[moad ${chain_disk}"
+    [then]
 [then] [else] drop [then]
+
 
 \ 
 \ BOOT OPTIONS MENU

Modified: head/sys/boot/i386/libi386/Makefile
==============================================================================
--- head/sys/boot/i386/libi386/Makefile	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/i386/libi386/Makefile	Fri Jun 16 20:08:44 2017	(r320011)
@@ -6,7 +6,7 @@ INTERNALLIB=
 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 multiboot.c multiboot_tramp.S \
+	elf64_freebsd.c multiboot.c multiboot_tramp.S relocater_tramp.S \
 	i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \
 	smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c
 .PATH:	${.CURDIR}/../../zfs

Modified: head/sys/boot/i386/libi386/libi386.h
==============================================================================
--- head/sys/boot/i386/libi386/libi386.h	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/i386/libi386/libi386.h	Fri Jun 16 20:08:44 2017	(r320011)
@@ -60,6 +60,35 @@ struct i386_devdesc
     } d_kind;
 };
 
+/*
+ * relocater trampoline support.
+ */
+struct relocate_data {
+	uint32_t	src;
+	uint32_t	dest;
+	uint32_t	size;
+};
+
+extern void relocater(void);
+
+extern uint32_t relocater_data;
+extern uint32_t relocater_size;
+
+extern uint16_t relocator_ip;
+extern uint16_t relocator_cs;
+extern uint16_t relocator_ds;
+extern uint16_t relocator_es;
+extern uint16_t relocator_fs;
+extern uint16_t relocator_gs;
+extern uint16_t relocator_ss;
+extern uint16_t relocator_sp;
+extern uint32_t relocator_esi;
+extern uint32_t relocator_eax;
+extern uint32_t relocator_ebx;
+extern uint32_t relocator_edx;
+extern uint32_t relocator_ebp;
+extern uint16_t relocator_a20_enabled;
+
 int	i386_getdev(void **vdev, const char *devspec, const char **path);
 char	*i386_fmtdev(void *vdev);
 int	i386_setcurrdev(struct env_var *ev, int flags, const void *value);

Added: head/sys/boot/i386/libi386/relocater_tramp.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/i386/libi386/relocater_tramp.S	Fri Jun 16 20:08:44 2017	(r320011)
@@ -0,0 +1,358 @@
+/*-
+ * Copyright 2015 Toomas Soome <tsoome at me.com>
+ * 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$
+ */
+
+
+/*
+ * relocate is needed to support loading code which has to be located
+ * below 1MB, as both BTX and loader are using low memory area.
+ *
+ * relocate and start loaded code. Since loaded code may need to be
+ * placed to already occupied memory area, this code is moved to safe
+ * memory area and then btx __exec will be called with physical pointer
+ * to this area. __exec will set pointer to %eax and use call *%eax,
+ * so on entry, we have new "base" address in %eax.
+ *
+ * Relocate will first set up and load new safe GDT to shut down BTX,
+ * then loaded code will be relocated to final memory location,
+ * then machine will be switched from 32bit protected mode to 16bit
+ * protected mode following by switch to real mode with A20 enabled or
+ * disabled. Finally the loaded code will be started and it will take
+ * over the whole system.
+ *
+ * For now, the known "safe" memory area for relocate is 0x600,
+ * the actual "free" memory is supposed to start from 0x500, leaving
+ * first 0x100 bytes in reserve. As relocate code+data is very small,
+ * it will leave enough space to set up boot blocks to 0:7c00 or load
+ * linux kernel below 1MB space.
+ */
+/*
+ * segment selectors
+ */
+		.set SEL_SCODE,0x8
+		.set SEL_SDATA,0x10
+		.set SEL_RCODE,0x18
+		.set SEL_RDATA,0x20
+
+		.p2align	4
+		.globl relocater
+relocater:
+		cli
+		/*
+		 * set up GDT from new location
+		 */
+		movl	%eax, %esi		/* our base address */
+		add	$(relocater.1-relocater), %eax
+		jmp	*%eax
+relocater.1:
+		/* set up jump */
+		lea	(relocater.2-relocater)(%esi), %eax
+		movl	%eax, (jump_vector-relocater) (%esi)
+
+		/* set up gdt */
+		lea	(gdt-relocater) (%esi), %eax
+		movl	%eax, (gdtaddr-relocater) (%esi)
+
+		/* load gdt */
+		lgdt	(gdtdesc - relocater) (%esi)
+		lidt	(idt-relocater) (%esi)
+
+		/* update cs */
+		ljmp *(jump_vector-relocater) (%esi)
+
+		.code32
+relocater.2:
+		xorl	%eax, %eax
+		movb	$SEL_SDATA, %al
+		movw	%ax, %ss
+		movw	%ax, %ds
+		movw	%ax, %es
+		movw	%ax, %fs
+		movw	%ax, %gs
+		movl	%cr0, %eax		/* disable paging */
+		andl	$~0x80000000,%eax
+		movl	%eax, %cr0
+		xorl	%ecx, %ecx		/* flush TLB */
+		movl	%ecx, %cr3
+		cld
+/*
+ * relocate data loop. load source, dest and size from
+ * relocater_data[i], 0 value will stop the loop.
+ * registers used for move: %esi, %edi, %ecx.
+ * %ebx to keep base
+ * %edx for relocater_data offset
+ */
+		movl	%esi, %ebx		/* base address */
+		xorl	%edx, %edx
+loop.1:
+		movl	(relocater_data-relocater)(%ebx, %edx, 4), %eax
+		testl	%eax, %eax
+		jz	loop.2
+		movl	(relocater_data-relocater)(%ebx, %edx, 4), %esi
+		inc	%edx
+		movl	(relocater_data-relocater)(%ebx, %edx, 4), %edi
+		inc	%edx
+		movl	(relocater_data-relocater)(%ebx, %edx, 4), %ecx
+		inc	%edx
+		rep
+		movsb
+		jmp	loop.1
+loop.2:
+		movl	%ebx, %esi		/* restore esi */
+		/*
+		 * data is relocated, switch to 16bit mode
+		 */
+		lea	(relocater.3-relocater)(%esi), %eax
+		movl	%eax, (jump_vector-relocater) (%esi)
+		movl	$SEL_RCODE, %eax
+		movl	%eax, (jump_vector-relocater+4) (%esi)
+
+		ljmp *(jump_vector-relocater) (%esi)
+relocater.3:
+		.code16
+
+		movw	$SEL_RDATA, %ax
+		movw	%ax, %ds
+		movw	%ax, %es
+		movw	%ax, %fs
+		movw	%ax, %gs
+		movw	%ax, %ss
+		lidt	(idt-relocater) (%esi)
+		lea	(relocater.4-relocater)(%esi), %eax
+		movl	%eax, (jump_vector-relocater) (%esi)
+		xorl	%eax, %eax
+		movl	%eax, (jump_vector-relocater+4) (%esi)
+		/* clear PE */
+		movl	%cr0, %eax
+		dec	%al
+		movl	%eax, %cr0
+		ljmp *(jump_vector-relocater) (%esi)
+relocater.4:
+		xorw	%ax, %ax
+		movw	%ax, %ds
+		movw	%ax, %es
+		movw	%ax, %fs
+		movw	%ax, %gs
+		movw	%ax, %ss
+		/*
+		 * set real mode irq offsets
+		 */
+		movw	$0x7008,%bx
+		in $0x21,%al			# Save master
+		push %ax			#  IMR
+		in $0xa1,%al			# Save slave
+		push %ax			#  IMR
+		movb $0x11,%al			# ICW1 to
+		outb %al,$0x20			#  master,
+		outb %al,$0xa0			#  slave
+		movb %bl,%al			# ICW2 to
+		outb %al,$0x21			#  master
+		movb %bh,%al			# ICW2 to
+		outb %al,$0xa1			#  slave
+		movb $0x4,%al			# ICW3 to
+		outb %al,$0x21			#  master
+		movb $0x2,%al			# ICW3 to
+		outb %al,$0xa1			#  slave
+		movb $0x1,%al			# ICW4 to
+		outb %al,$0x21			#  master,
+		outb %al,$0xa1			#  slave
+		pop %ax				# Restore slave
+		outb %al,$0xa1			#  IMR
+		pop %ax				# Restore master
+		outb %al,$0x21			#  IMR
+						# done
+		/*
+		 * Should A20 be left enabled?
+		 */
+		/* movw imm16, %ax */
+		.byte	0xb8
+		.globl	relocator_a20_enabled
+relocator_a20_enabled:
+		.word	0
+		test	%ax, %ax
+		jnz	a20_done
+
+		movw	$0xa00, %ax
+		movw	%ax, %sp
+		movw	%ax, %bp
+
+		/* Disable A20 */
+		movw	$0x2400, %ax
+		int	$0x15
+#		jnc	a20_done
+
+		call	a20_check_state
+		testb	%al, %al
+		jz	a20_done
+
+		inb	$0x92
+		andb	$(~0x03), %al
+		outb	$0x92
+		jmp	a20_done
+
+a20_check_state:
+		movw	$100, %cx
+1:
+		xorw	%ax, %ax
+		movw	%ax, %ds
+		decw	%ax
+		movw	%ax, %es
+		xorw	%ax, %ax
+		movw	$0x8000, %ax
+		movw	%ax, %si
+		addw	$0x10, %ax
+		movw	%ax, %di
+		movb	%ds:(%si), %dl
+		movb	%es:(%di), %al
+		movb	%al, %dh
+		decb	%dh
+		movb	%dh, %ds:(%si)
+		outb	%al, $0x80
+		outb	%al, $0x80
+		movb	%es:(%di), %dh
+		subb	%dh, %al
+		xorb	$1, %al
+		movb	%dl, %ds:(%si)
+		testb	%al, %al
+		jz	a20_done
+		loop	1b
+		ret
+a20_done:
+		/*
+		 * set up registers
+		 */
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_ds
+relocator_ds:	.word	0
+		movw	%ax, %ds
+
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_es
+relocator_es:	.word	0
+		movw	%ax, %es
+
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_fs
+relocator_fs:	.word	0
+		movw	%ax, %fs
+
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_gs
+relocator_gs:	.word	0
+		movw	%ax, %gs
+
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_ss
+relocator_ss:	.word	0
+		movw	%ax, %ss
+
+		/* movw imm16, %ax. */
+		.byte	0xb8
+		.globl	relocator_sp
+relocator_sp:	.word	0
+		movzwl	%ax, %esp
+
+		/* movw imm32, %eax. */
+		.byte	0x66, 0xb8
+		.globl	relocator_esi
+relocator_esi:	.long	0
+		movl	%eax, %esi
+
+		/* movw imm32, %edx. */
+		.byte	0x66, 0xba
+		.globl	relocator_edx
+relocator_edx:	.long	0
+
+		/* movw imm32, %ebx. */
+		.byte	0x66, 0xbb
+		.globl	relocator_ebx
+relocator_ebx:	.long	0
+
+		/* movw imm32, %eax. */
+		.byte	0x66, 0xb8
+		.globl	relocator_eax
+relocator_eax:	.long	0
+
+		/* movw imm32, %ebp. */
+		.byte	0x66, 0xbd
+		.globl	relocator_ebp
+relocator_ebp:	.long	0
+
+		sti
+		.byte 0xea			 /* ljmp */
+		.globl relocator_ip
+relocator_ip:
+		.word 0
+		.globl relocator_cs
+relocator_cs:
+		.word 0
+
+/* GDT to reset BTX */
+		.code32
+		.p2align	4
+jump_vector:	.long	0
+		.long	SEL_SCODE
+
+gdt:		.word 0x0, 0x0			/* null entry */
+		.byte 0x0, 0x0, 0x0, 0x0
+		.word 0xffff, 0x0		/* SEL_SCODE */
+		.byte 0x0, 0x9a, 0xcf, 0x0
+		.word 0xffff, 0x0		/* SEL_SDATA */
+		.byte 0x0, 0x92, 0xcf, 0x0
+		.word 0xffff, 0x0		/* SEL_RCODE */
+		.byte 0x0, 0x9a, 0x0f, 0x0
+		.word 0xffff, 0x0		/* SEL_RDATA */
+		.byte 0x0, 0x92, 0x0f, 0x0
+gdt.1:
+
+gdtdesc:	.word gdt.1 - gdt - 1		/* limit */
+gdtaddr:	.long 0				/* base */
+
+idt:		.word 0x3ff
+		.long 0
+
+		.globl relocater_data
+relocater_data:
+		.long 0			/* src */
+		.long 0			/* dest */
+		.long 0			/* size */
+		.long 0			/* src */
+		.long 0			/* dest */
+		.long 0			/* size */
+		.long 0			/* src */
+		.long 0			/* dest */
+		.long 0			/* size */
+		.long 0
+
+		.globl relocater_size
+relocater_size:
+		.long relocater_size-relocater

Modified: head/sys/boot/i386/loader/Makefile
==============================================================================
--- head/sys/boot/i386/loader/Makefile	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/i386/loader/Makefile	Fri Jun 16 20:08:44 2017	(r320011)
@@ -14,7 +14,7 @@ LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	yes
 
 # architecture-specific loader code
-SRCS=		main.c conf.c vers.c
+SRCS=		main.c conf.c vers.c chain.c
 
 # Put LOADER_FIREWIRE_SUPPORT=yes in /etc/make.conf for FireWire/dcons support
 .if defined(LOADER_FIREWIRE_SUPPORT)

Added: head/sys/boot/i386/loader/chain.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/i386/loader/chain.c	Fri Jun 16 20:08:44 2017	(r320011)
@@ -0,0 +1,135 @@
+/*-
+ * Copyright 2015 Toomas Soome <tsoome at me.com>
+ * 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.
+ */
+
+/*
+ * Chain loader to load BIOS boot block either from MBR or PBR.
+ *
+ * Note the boot block location 0000:7c000 conflicts with loader, so we need to
+ * read in to temporary space and relocate on exec, when btx is stopped.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/diskmbr.h>
+
+#include "bootstrap.h"
+#include "libi386/libi386.h"
+#include "btxv86.h"
+
+/*
+ * The MBR/VBR is located in first sector of disk/partition.
+ * Read 512B to temporary location and set up relocation. Then
+ * exec relocator.
+ */
+#define	SECTOR_SIZE	(512)
+
+COMMAND_SET(chain, "chain", "chain load boot block from device", command_chain);
+
+static int
+command_chain(int argc, char *argv[])
+{
+	int fd, len, size = SECTOR_SIZE;
+	struct stat st;
+	vm_offset_t mem = 0x100000;
+	uint32_t *uintptr = &relocater_data;
+	struct i386_devdesc *rootdev;
+
+	if (argc == 1) {
+		command_errmsg = "no device or file name specified";
+		return (CMD_ERROR);
+	}
+	if (argc != 2) {
+		command_errmsg = "invalid trailing arguments";
+		return (CMD_ERROR);
+	}
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd == -1) {
+		command_errmsg = "open failed";
+		return (CMD_ERROR);
+	}
+
+	len = strlen(argv[1]);
+	if (argv[1][len-1] != ':') {
+		if (fstat(fd, &st) == -1) {
+			command_errmsg = "stat failed";
+			close(fd);
+			return (CMD_ERROR);
+		}
+		size = st.st_size;
+	} else if (strncmp(argv[1], "disk", 4) != 0) {
+		command_errmsg = "can only use disk device";
+		close(fd);
+		return (CMD_ERROR);
+	}
+
+	i386_getdev((void **)(&rootdev), argv[1], NULL);
+	if (rootdev == NULL) {
+		command_errmsg = "can't determine root device";
+		return (CMD_ERROR);
+	}
+
+	if (archsw.arch_readin(fd, mem, SECTOR_SIZE) != SECTOR_SIZE) {
+		command_errmsg = "failed to read disk";
+		close(fd);
+		return (CMD_ERROR);
+	}
+	close(fd);
+
+	if (*((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) {
+		command_errmsg = "wrong magic";
+		return (CMD_ERROR);
+	}
+
+	uintptr[0] = mem;
+	uintptr[1] = 0x7C00;
+	uintptr[2] = SECTOR_SIZE;
+
+	relocator_edx = bd_unit2bios(rootdev->d_unit);
+	relocator_esi = relocater_size;
+	relocator_ds = 0;
+	relocator_es = 0;
+	relocator_fs = 0;
+	relocator_gs = 0;
+	relocator_ss = 0;
+	relocator_cs = 0;
+	relocator_sp = 0x7C00;
+	relocator_ip = 0x7C00;
+	relocator_a20_enabled = 0;
+
+	i386_copyin(relocater, 0x600, relocater_size);
+
+	dev_cleanup();
+
+	__exec((void *)0x600);
+
+	panic("exec returned");
+	return (CMD_ERROR);		/* not reached */
+}

Modified: head/sys/boot/i386/loader/help.i386
==============================================================================
--- head/sys/boot/i386/loader/help.i386	Fri Jun 16 20:03:09 2017	(r320010)
+++ head/sys/boot/i386/loader/help.i386	Fri Jun 16 20:08:44 2017	(r320011)
@@ -43,3 +43,12 @@
 	Displays the BIOS SMAP (system memory map) table.
 
 ################################################################################
+# Tchain DChain load disk block
+
+	chain disk:
+
+	chain will read stage1 (MBR or VBR) boot block from specified device
+	to address 0000:7C00 and attempts to run it. Use lsdev to get available
+	device names. Disk name must end with colon.
+
+################################################################################


More information about the svn-src-all mailing list