git: a3b72d89c702 - main - zfsboot: Remove zfsboot(8) program used to boot ZFS from MBR + BIOS

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 28 Jul 2025 14:58:15 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=a3b72d89c7028a2254381e4d2b126416dee3fbb5

commit a3b72d89c7028a2254381e4d2b126416dee3fbb5
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-07-28 14:57:16 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-07-28 14:58:02 +0000

    zfsboot: Remove zfsboot(8) program used to boot ZFS from MBR + BIOS
    
    This has not worked since the import of OpenZFS in FreeBSD 13.0.
    Trying to fix it at this point would probably entail rearchitecting
    how it works (e.g. using a dedicated freebsd-boot slice to hold
    zfsboot).  However, it's not really worth doing that at this point.
    
    PR:             271262
    Reported by:    Henryk Paluch <hpaluch@seznam.cz>
    Reviewed by:    imp, emaste
    Relnotes:       yes
    Differential Revision:  https://reviews.freebsd.org/D51545
---
 ObsoleteFiles.inc                            |   4 +
 sbin/zfsbootcfg/zfsbootcfg.8                 |   8 +-
 stand/i386/Makefile                          |   2 +-
 stand/i386/common/bootargs.h                 |   2 +-
 stand/i386/loader/main.c                     |   2 +-
 stand/i386/zfsboot/Makefile                  |  92 ---------
 stand/i386/zfsboot/Makefile.depend           |  17 --
 stand/i386/zfsboot/zfsboot.8                 | 130 -------------
 stand/i386/zfsboot/zfsldr.S                  | 281 ---------------------------
 targets/pseudo/userland/misc/Makefile.depend |   1 -
 tools/boot/install-boot.sh                   |  23 +--
 tools/boot/rootgen.sh                        |  63 +-----
 tools/build/mk/OptionalObsoleteFiles.inc     |   4 -
 13 files changed, 20 insertions(+), 609 deletions(-)

diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 2aa914ab089f..83fb2d3f3a2c 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,10 @@
 #   xargs -n1 | sort | uniq -d;
 # done
 
+# 20250728: zfsboot (MBR) removed
+OLD_FILES+=boot/zfsboot
+OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
+
 # 20250728: Machine versions of 'runq.h' do not exist anymore
 OLD_FILES+=usr/include/machine/runq.h
 
diff --git a/sbin/zfsbootcfg/zfsbootcfg.8 b/sbin/zfsbootcfg/zfsbootcfg.8
index 5e7f02b2578c..3831adfc81bd 100644
--- a/sbin/zfsbootcfg/zfsbootcfg.8
+++ b/sbin/zfsbootcfg/zfsbootcfg.8
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 22, 2020
+.Dd July 28, 2025
 .Dt ZFSBOOTCFG 8
 .Os
 .Sh NAME
@@ -44,14 +44,11 @@
 is used to set
 .Xr boot.config 5 Ns -style
 options to be used by
-.Xr zfsboot 8 ,
 .Xr gptzfsboot 8
 or
 .Xr loader 8
 the next time the machine is booted.
 Once
-.Xr zfsboot 8
-or
 .Xr gptzfsboot 8
 or
 .Xr loader 8
@@ -130,8 +127,7 @@ To clear the boot options:
 .Xr boot.config 5 ,
 .Xr bectl 8 ,
 .Xr gptzfsboot 8 ,
-.Xr loader 8 ,
-.Xr zfsboot 8
+.Xr loader 8
 .Sh HISTORY
 .Nm
 appeared in
diff --git a/stand/i386/Makefile b/stand/i386/Makefile
index 768496598575..299e070d8cd5 100644
--- a/stand/i386/Makefile
+++ b/stand/i386/Makefile
@@ -18,7 +18,7 @@ SUBDIR.yes+=	loader_simp
 # special boot programs, 'self-extracting boot2+loader'
 SUBDIR.${MK_LOADER_PXEBOOT}+=	pxeldr
 
-SUBDIR.${MK_LOADER_ZFS}+=	zfsboot gptzfsboot
+SUBDIR.${MK_LOADER_ZFS}+=	gptzfsboot
 
 .if defined(PXEBOOT_DEFAULT_INTERP)
 L=${PXEBOOT_DEFAULT_INTERP}
diff --git a/stand/i386/common/bootargs.h b/stand/i386/common/bootargs.h
index dafcf6a55554..072f7ee505fd 100644
--- a/stand/i386/common/bootargs.h
+++ b/stand/i386/common/bootargs.h
@@ -88,7 +88,7 @@ struct bootargs
 
 /*
  * geli_boot_data is embedded in geli_boot_args (passed from gptboot to loader)
- * and in zfs_boot_args (passed from zfsboot and gptzfsboot to loader).
+ * and in zfs_boot_args (passed from gptzfsboot to loader).
  */
 struct geli_boot_data
 {
diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c
index fd95cf5243cf..a70b3a253b90 100644
--- a/stand/i386/loader/main.c
+++ b/stand/i386/loader/main.c
@@ -198,7 +198,7 @@ main(void)
 
 #ifdef LOADER_ZFS_SUPPORT
 	/*
-	 * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS,
+	 * gptzfsboot has always passed KARGS_FLAGS_ZFS,
 	 * so if that is set along with KARGS_FLAGS_EXTARG we know we
 	 * can interpret the extarg data as a struct zfs_boot_args.
 	 */
diff --git a/stand/i386/zfsboot/Makefile b/stand/i386/zfsboot/Makefile
deleted file mode 100644
index b619b84c368e..000000000000
--- a/stand/i386/zfsboot/Makefile
+++ /dev/null
@@ -1,92 +0,0 @@
-.include <bsd.init.mk>
-
-.PATH:		${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${BOOTSRC}/common
-
-FILES=		zfsboot
-MAN=		zfsboot.8
-
-BOOT_COMCONSOLE_PORT?= 0x3f8
-BOOT_COMCONSOLE_SPEED?= 115200
-B2SIOFMT?=	0x3
-
-REL1=	0x700
-ORG1=	0x7c00
-ORG2=	0x2000
-
-CFLAGS+=-DBOOTPROG=\"zfsboot\" \
-	-O1 \
-	-DBOOT2 \
-	-DLOADER_GPT_SUPPORT \
-	-DLOADER_MBR_SUPPORT \
-	-DLOADER_ZFS_SUPPORT \
-	-DLOADER_UFS_SUPPORT \
-	-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
-	-DSIOFMT=${B2SIOFMT} \
-	-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
-	-I${LDRSRC} \
-	-I${BOOTSRC}/i386/common \
-	-I${BOOTSRC}/i386/libi386 \
-	-I${ZFSSRC} \
-	-I${SYSDIR}/crypto/skein \
-	-I${SYSDIR}/cddl/boot/zfs \
-	-I${SYSDIR}/contrib/openzfs/include \
-	-I${SYSDIR}/contrib/openzfs/include/os/freebsd/spl \
-	-I${SYSDIR}/contrib/openzfs/include/os/freebsd/zfs \
-	-I${SYSDIR}/cddl/contrib/opensolaris/common/lz4 \
-	-I${BOOTSRC}/i386/boot2 \
-	-Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-	-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-	-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
-
-CFLAGS.part.c+= -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
-
-CFLAGS.gcc+=	--param max-inline-insns-single=100
-
-LD_FLAGS+=${LD_FLAGS_BIN}
-
-CLEANFILES+=	zfsboot
-
-zfsboot: zfsboot1 zfsboot2
-	cat zfsboot1 zfsboot2 > zfsboot
-
-CLEANFILES+=	zfsboot1 zfsldr.out zfsldr.o
-
-zfsboot1: zfsldr.out
-	${OBJCOPY} -S -O binary zfsldr.out ${.TARGET}
-
-zfsldr.out: zfsldr.o
-	${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} zfsldr.o
-
-OBJS=	zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o misc.o
-CLEANFILES+=	zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
-		${OBJS}
-
-# We currently allow 256k bytes for zfsboot - in practice it could be
-# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
-# 
-BOOT2SIZE=	262144
-
-# i386 standalone support library
-LIBI386=	${BOOTOBJ}/i386/libi386/libi386.a
-
-zfsboot2: zfsboot.ld
-	@set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \
-	    echo "$$x bytes available"; test $$x -ge 0
-	${DD} if=${.ALLSRC} of=${.TARGET} bs=${BOOT2SIZE} conv=sync
-
-zfsboot.ld: zfsboot.ldr zfsboot.bin ${BTXKERN}
-	btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l zfsboot.ldr \
-	    -o ${.TARGET} -P 1 zfsboot.bin
-
-zfsboot.ldr:
-	:> ${.TARGET}
-
-zfsboot.bin: zfsboot.out
-	${OBJCOPY} -S -O binary zfsboot.out ${.TARGET}
-
-zfsboot.out: ${BTXCRT} ${OBJS}
-	${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32}
-
-SRCS=	zfsboot.c
-
-.include <bsd.prog.mk>
diff --git a/stand/i386/zfsboot/Makefile.depend b/stand/i386/zfsboot/Makefile.depend
deleted file mode 100644
index 92ab022283fd..000000000000
--- a/stand/i386/zfsboot/Makefile.depend
+++ /dev/null
@@ -1,17 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
-	include \
-	include/xlocale \
-	lib/libmd \
-	stand/i386/btx/btx \
-	stand/i386/btx/lib \
-	stand/libsa32 \
-	stand/zfs32 \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/stand/i386/zfsboot/zfsboot.8 b/stand/i386/zfsboot/zfsboot.8
deleted file mode 100644
index a8411bc065d0..000000000000
--- a/stand/i386/zfsboot/zfsboot.8
+++ /dev/null
@@ -1,130 +0,0 @@
-.\" Copyright (c) 2014 Andriy Gapon <avg@FreeBSD.org>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\"    notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\"    notice, this list of conditions and the following disclaimer in the
-.\"    documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd March 27, 2018
-.Dt ZFSBOOT 8
-.Os
-.Sh NAME
-.Nm zfsboot
-.Nd bootcode for ZFS on BIOS-based computers
-.Sh DESCRIPTION
-.Nm
-is used on BIOS-based computers to boot from a filesystem in
-a ZFS pool.
-.Nm
-is installed in two parts on a disk or a partition used by a ZFS pool.
-The first part, a single-sector starter boot block, is installed
-at the beginning of the disk or partition.
-The second part, a main boot block, is installed at a special offset
-within the disk or partition.
-Both areas are reserved by the ZFS on-disk specification for boot use.
-If
-.Nm
-is installed in a partition, then that partition should be made
-bootable using appropriate configuration and boot blocks described in
-.Xr boot 8 .
-.Sh BOOTING
-The
-.Nm
-boot process is very similar to that of
-.Xr gptzfsboot 8 .
-One significant difference is that
-.Nm
-does not currently support the GPT partitioning scheme.
-Thus only whole disks and MBR partitions, traditionally referred to as
-slices, are probed for ZFS disk labels.
-See the BUGS section in
-.Xr gptzfsboot 8
-for some limitations of the MBR scheme support.
-.Sh USAGE
-.Nm
-supports all the same prompt and configuration file arguments as
-.Xr gptzfsboot 8 .
-.Sh FILES
-.Bl -tag -width /boot/zfsboot -compact
-.It Pa /boot/zfsboot
-boot code binary
-.It Pa /boot.config
-parameters for the boot block
-.Pq optional
-.It Pa /boot/config
-alternative parameters for the boot block
-.Pq optional
-.El
-.Sh EXAMPLES
-.Nm
-is typically installed using
-.Xr dd 1 .
-To install
-.Nm
-on the
-.Pa ada0
-drive:
-.Bd -literal -offset indent
-dd if=/boot/zfsboot of=/dev/ada0 count=1
-dd if=/boot/zfsboot of=/dev/ada0 iseek=1 oseek=1024
-.Ed
-.Pp
-If the drive is currently in use, the GEOM safety will prevent writes
-and must be disabled before running the above commands:
-.Bd -literal -offset indent
-sysctl kern.geom.debugflags=0x10
-.Ed
-.Pp
-.Nm
-can also be installed in an MBR slice:
-.Bd -literal -offset indent
-gpart create -s mbr ada0
-gpart add -t freebsd ada0
-gpart bootcode -b /boot/boot0 ada0
-gpart set -a active -i 1 ada0
-dd if=/dev/zero of=/dev/ada0s1 count=2
-dd if=/boot/zfsboot of=/dev/ada0s1 count=1
-dd if=/boot/zfsboot of=/dev/ada0s1 iseek=1 oseek=1024
-.Ed
-.Pp
-Note that commands to create and populate a pool are not shown
-in the example above.
-.Sh SEE ALSO
-.Xr dd 1 ,
-.Xr boot.config 5 ,
-.Xr boot 8 ,
-.Xr gptzfsboot 8 ,
-.Xr loader 8 ,
-.Xr zpool 8
-.Sh HISTORY
-.Nm
-appeared in FreeBSD 7.3.
-.Sh AUTHORS
-This manual page was written by
-.An Andriy Gapon Aq avg@FreeBSD.org .
-.Sh BUGS
-Installing
-.Nm
-with
-.Xr dd 1
-is a hack.
-ZFS needs a command to properly install
-.Nm
-onto a ZFS-controlled disk or partition.
diff --git a/stand/i386/zfsboot/zfsldr.S b/stand/i386/zfsboot/zfsldr.S
deleted file mode 100644
index cd8289f952fd..000000000000
--- a/stand/i386/zfsboot/zfsldr.S
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * 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.
- */
-
-/* Memory Locations */
-		.set MEM_ARG,0x900		# Arguments
-		.set MEM_ORG,0x7c00		# Origin
-		.set MEM_BUF,0x8000		# Load area
-		.set MEM_BTX,0x9000		# BTX start
-		.set MEM_JMP,0x9010		# BTX entry point
-		.set MEM_USR,0xa000		# Client start
-		.set BDA_BOOT,0x472		# Boot howto flag
-	
-/* Partition Constants */
-		.set PRT_OFF,0x1be		# Partition offset
-		.set PRT_NUM,0x4		# Partitions
-		.set PRT_BSD,0xa5		# Partition type
-
-/* Misc. Constants */
-		.set SIZ_PAG,0x1000		# Page size
-		.set SIZ_SEC,0x200		# Sector size
-		.set COPY_BLKS,0x8		# Number of blocks
-						# to copy for boot2 (<= 15)
-		.set COPY_BLK_SZ,0x8000		# Copy in 32k blocks; must be
-						# a multiple of 16 bytes
-		.set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS)
-		.globl start
-		.code16
-
-/*
- * Load the rest of zfsboot2 and BTX up, copy the parts to the right locations,
- * and start it all up.
- */
-
-/*
- * Setup the segment registers to flat addressing (segment 0) and setup the
- * stack to end just below the start of our code.
- */
-start:		cld				# String ops inc
-		xor %cx,%cx			# Zero
-		mov %cx,%es			# Address
-		mov %cx,%ds			#  data
-		mov %cx,%ss			# Set up
-		mov $start,%sp			#  stack
-/*
- * Load the MBR and look for the first FreeBSD slice.  We use the fake
- * partition entry below that points to the MBR when we call read.
- * The first pass looks for the first active FreeBSD slice.  The
- * second pass looks for the first non-active FreeBSD slice if the
- * first one fails.
- */
-		call check_edd		 	# Make sure EDD works
-		mov $part4,%si			# Dummy partition
-		xor %eax,%eax			# Read MBR
-		movl $MEM_BUF,%ebx		#  from first
-		call read			#  sector
-		mov $0x1,%cx	 		# Two passes
-main.1: 	mov $MEM_BUF+PRT_OFF,%si	# Partition table
-		movb $0x1,%dh			# Partition
-main.2: 	cmpb $PRT_BSD,0x4(%si)		# Our partition type?
-		jne main.3			# No
-		jcxz main.5			# If second pass
-		testb $0x80,(%si)		# Active?
-		jnz main.5			# Yes
-main.3: 	add $0x10,%si	 		# Next entry
-		incb %dh			# Partition
-		cmpb $0x1+PRT_NUM,%dh		# In table?
-		jb main.2			# Yes
-		dec %cx				# Do two
-		jcxz main.1			#  passes
-/*
- * If we get here, we didn't find any FreeBSD slices at all, so print an
- * error message and die.
- */
-		mov $msg_part,%si		# Message
-		jmp error			# Error
-
-/*
- * Ok, we have a slice and drive in %dx now, so use that to locate and
- * load boot2.  %si references the start of the slice we are looking
- * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors
- * starting at sector 1024 (i.e. after the two vdev labels).  We don't
- * have do anything fancy here to allow for an extra copy of boot1 and
- * a partition table (compare to this section of the UFS bootstrap) so we
- * just load it all at 0x9000. The first part of boot2 is BTX, which wants
- * to run at 0x9000. The boot2.bin binary starts right after the end of BTX,
- * so we have to figure out where the start of it is and then move the
- * binary to 0xc000.  Normally, BTX clients start at MEM_USR, or 0xa000,
- * but when we use btxld to create zfsboot2, we use an entry point of
- * 0x2000.  That entry point is relative to MEM_USR; thus boot2.bin
- * starts at 0xc000.
- *
- * The load area and the target area for the client overlap so we have
- * to use a decrementing string move. We also play segment register
- * games with the destination address for the move so that the client
- * can be larger than 16k (which would overflow the zero segment since
- * the client starts at 0xc000).
- */
-main.5: 	mov %dx,MEM_ARG			# Save args
-		mov $NSECT,%cx			# Sector count
-		movl $1024,%eax			# Offset to boot2
-		mov $MEM_BTX,%ebx		# Destination buffer
-main.6:		pushal				# Save params
-		call read			# Read disk
-		popal				# Restore
-		incl %eax			# Advance to
-		add $SIZ_SEC,%ebx		#  next sector
-		loop main.6			# If not last, read another
-
-		mov $MEM_BTX,%bx		# BTX
-		mov 0xa(%bx),%si		# Get BTX length and set
-		add %bx,%si			#  %si to start of boot2
-		dec %si				# Set %ds:%si to point at the
-		mov %si,%ax			# last byte we want to copy
-		shr $4,%ax			# from boot2, with %si made as
-		add $(COPY_BLKS*COPY_BLK_SZ/16),%ax	# small as possible.
-		and $0xf,%si			#
-		mov %ax,%ds			#
-		mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at
-		add $(COPY_BLKS*COPY_BLK_SZ/16),%ax	# the last byte we
-		mov %ax,%es			# want to copy boot2 into.
-		mov $COPY_BLKS,%bx		# Copy COPY_BLKS 32k blocks
-copyloop:
-		add $COPY_BLK_SZ,%si		# Adjust %ds:%si to point at
-		mov %ds,%ax			# the end of the next 32k to
-		sub $COPY_BLK_SZ/16,%ax		# copy from boot2
-		mov %ax,%ds
-		mov $COPY_BLK_SZ-1,%di		# Adjust %es:%di to point at
-		mov %es,%ax			# the end of the next 32k into
-		sub $COPY_BLK_SZ/16,%ax		# which we want boot2 copied
-		mov %ax,%es
-		mov $COPY_BLK_SZ,%cx		# Copy 32k
-		std
-		rep movsb
-		dec %bx
-		jnz copyloop
-		mov %cx,%ds			# Reset %ds and %es
-		mov %cx,%es
-		cld				# Back to increment
-
-/*
- * Enable A20 so we can access memory above 1 meg.
- * Use the zero-valued %cx as a timeout for embedded hardware which do not
- * have a keyboard controller.
- */
-seta20: 	cli				# Disable interrupts
-seta20.1:	dec %cx				# Timeout?
-		jz seta20.3			# Yes
-		inb $0x64,%al			# Get status
-		testb $0x2,%al			# Busy?
-		jnz seta20.1			# Yes
-		movb $0xd1,%al			# Command: Write
-		outb %al,$0x64			#  output port
-seta20.2:	inb $0x64,%al			# Get status
-		testb $0x2,%al			# Busy?
-		jnz seta20.2			# Yes
-		movb $0xdf,%al			# Enable
-		outb %al,$0x60			#  A20
-seta20.3:	sti				# Enable interrupts
-
-		jmp start+MEM_JMP-MEM_ORG	# Start BTX
-
-
-/*
- * Read a sector from the disk.  Sets up an EDD packet on the stack
- * and passes it to read.  We assume that the destination address is
- * always segment-aligned.
- *
- * %eax		- int     - LBA to read in relative to partition start
- * %ebx		- ptr	  - destination address
- * %dl		- byte    - drive to read from
- * %si		- ptr     - MBR partition entry
- */
-read:		xor %ecx,%ecx			# Get
-		addl 0x8(%si),%eax		#  LBA
-		adc $0,%ecx
-		pushl %ecx			# Starting absolute block
-		pushl %eax			#  block number
-		shr $4,%ebx			# Convert to segment
-		push %bx			# Address of
-		push $0				#  transfer buffer
-		push $0x1			# Read 1 sector
-		push $0x10			# Size of packet
-		mov %sp,%si			# Packet pointer
-		mov $0x42,%ah			# BIOS: Extended
-		int $0x13			#  read
-		jc read.1			# If error, fail
-		lea 0x10(%si),%sp		# Clear stack
-		ret				# If success, return
-read.1:		mov %ah,%al			# Format
-		mov $read_err,%di		#  error
-		call hex8			#  code
-		mov $msg_read,%si		# Set the error message and
-						#  fall through to the error
-						#  routine
-/*
- * Print out the error message pointed to by %ds:(%si) followed
- * by a prompt, wait for a keypress, and then reboot the machine.
- */
-error:		callw putstr			# Display message
-		mov $prompt,%si			# Display
-		callw putstr			#  prompt
-		xorb %ah,%ah			# BIOS: Get
-		int $0x16			#  keypress
-		movw $0x1234, BDA_BOOT		# Do a warm boot
-		ljmp $0xffff,$0x0		# reboot the machine
-/*
- * Display a null-terminated string using the BIOS output.
- */
-putstr.0:	mov $0x7,%bx	 		# Page:attribute
-		movb $0xe,%ah			# BIOS: Display
-		int $0x10			#  character
-putstr: 	lodsb				# Get char
-		testb %al,%al			# End of string?
-		jne putstr.0			# No
-		ret				# To caller
-/*
- * Check to see if the disk supports EDD.  zfsboot requires EDD and does not
- * support older C/H/S disk I/O.
- */
-check_edd:	cmpb $0x80,%dl			# Hard drive?
-		jb check_edd.1 			# No, fail to boot
-		mov $0x55aa,%bx			# Magic
-		push %dx			# Save
-		movb $0x41,%ah			# BIOS: Check
-		int $0x13			#  extensions present
-		pop %dx				# Restore
-		jc check_edd.1			# If error, fail
-		cmp $0xaa55,%bx			# Magic?
-		jne check_edd.1			# No, so fail
-		testb $0x1,%cl			# Packet interface?
-		jz check_edd.1			# No, so fail
-		ret				# EDD ok, keep booting
-check_edd.1:	mov $msg_chs,%si		# Warn that CHS is
-		jmp error			#  unsupported and fail
-/*
- * AL to hex, saving the result to [EDI].
- */
-hex8:		push %ax			# Save
-		shrb $0x4,%al			# Do upper
-		call hex8.1			#  4
-		pop %ax				# Restore
-hex8.1: 	andb $0xf,%al			# Get lower 4
-		cmpb $0xa,%al			# Convert
-		sbbb $0x69,%al			#  to hex
-		das				#  digit
-		orb $0x20,%al			# To lower case
-		stosb				# Save char
-		ret				# (Recursive)
-
-/* Messages */
-
-msg_chs:	.asciz "CHS not supported"
-msg_read:	.ascii "Read error: "
-read_err:	.asciz "XX"
-msg_part:	.asciz "Boot error"
-
-prompt: 	.asciz "\r\n"
-
-		.org PRT_OFF,0x90
-
-/* Partition table */
-
-		.fill 0x30,0x1,0x0
-part4:		.byte 0x80, 0x00, 0x01, 0x00
-		.byte 0xa5, 0xfe, 0xff, 0xff
-		.byte 0x00, 0x00, 0x00, 0x00
-		.byte 0x50, 0xc3, 0x00, 0x00	# 50000 sectors long, bleh
-
-		.word 0xaa55			# Magic number
diff --git a/targets/pseudo/userland/misc/Makefile.depend b/targets/pseudo/userland/misc/Makefile.depend
index d3c97fc56b40..546800004d11 100644
--- a/targets/pseudo/userland/misc/Makefile.depend
+++ b/targets/pseudo/userland/misc/Makefile.depend
@@ -54,7 +54,6 @@ DIRDEPS.x86sys= \
 .if ${MK_ZFS} != "no"
 DIRDEPS.x86sys+= \
 	stand/i386/gptzfsboot \
-	stand/i386/zfsboot \
 	stand/i386/zfsloader \
 
 DIRDEPS+= \
diff --git a/tools/boot/install-boot.sh b/tools/boot/install-boot.sh
index 217bf0ff1457..10e62dd32ba8 100755
--- a/tools/boot/install-boot.sh
+++ b/tools/boot/install-boot.sh
@@ -294,27 +294,9 @@ boot_nogeli_mbr_ufs_both() {
     boot_nogeli_mbr_ufs_uefi $1 $2 $3
 }
 
+# ZFS+MBR+BIOS is not a supported configuration
 boot_nogeli_mbr_zfs_legacy() {
-    dev=$1
-    dst=$2
-
-    # search to find the BSD slice
-    s=$(find_part $dev "freebsd")
-    if [ -z "$s" ] ; then
-	die "No BSD slice found"
-    fi
-    idx=$(find_part ${dev}s${s} "freebsd-zfs")
-    if [ -z "$idx" ] ; then
-	die "No freebsd-zfs slice found"
-    fi
-    # search to find the freebsd-zfs partition within the slice
-    # Or just assume it is 'a' because it has to be since it fails otherwise
-    doit gpart bootcode -b ${dst}/boot/mbr ${dev}
-    dd if=${dst}/boot/zfsboot of=/tmp/zfsboot1 count=1
-    doit gpart bootcode -b /tmp/zfsboot1 ${dev}s${s}	# Put boot1 into the start of part
-    sysctl kern.geom.debugflags=0x10		# Put boot2 into ZFS boot slot
-    doit dd if=${dst}/boot/zfsboot of=/dev/${dev}s${s}a skip=1 seek=1024
-    sysctl kern.geom.debugflags=0x0
+    exit 1
 }
 
 boot_nogeli_mbr_zfs_uefi() {
@@ -322,7 +304,6 @@ boot_nogeli_mbr_zfs_uefi() {
 }
 
 boot_nogeli_mbr_zfs_both() {
-    boot_nogeli_mbr_zfs_legacy $1 $2 $3
     boot_nogeli_mbr_zfs_uefi $1 $2 $3
 }
 
diff --git a/tools/boot/rootgen.sh b/tools/boot/rootgen.sh
index 32007a46802e..2cd65bdd180d 100755
--- a/tools/boot/rootgen.sh
+++ b/tools/boot/rootgen.sh
@@ -202,33 +202,6 @@ mk_nogeli_mbr_ufs_both() {
     rm -f ${src}/etc/fstab
 }
 
-mk_nogeli_mbr_zfs_legacy() {
-    src=$1
-    img=$2
-    mntpt=$3
-    geli=$4
-    scheme=$5
-    fs=$6
-    bios=$7
-    pool=nogeli-mbr-zfs-legacy
-
-    zfs_extra $src $dst
-    makefs -t zfs -s 200m \
-	-o poolname=${pool} -o bootfs=${pool} -o rootpath=/ \
-	${img}.s1a ${src} ${dst}
-    # The old boot1/boot2 boot split is also used by zfs. We need to extract zfsboot1
-    # from this image. Since there's no room in the mbr format for the rest of the loader,
-    # it will load the zfsboot loader from the reserved for bootloader area of the ZFS volume
-    # being booted, hence the need to dd it into the raw img later.
-    # Please note: zfsboot only works with partition 'a' which must be the root
-    # partition / zfs volume
-    dd if=${src}/boot/zfsboot of=${dst}/zfsboot1 count=1
-    mkimg -s bsd -b ${dst}zfsboot1 -p freebsd-zfs:=${img}.s1a -o ${img}.s1
-    dd if=${src}/boot/zfsboot of=${img}.s1a skip=1 seek=1024
-    mkimg -a 1 -s mbr -b ${src}/boot/mbr -p freebsd:=${img}.s1 -o ${img}
-    rm -rf ${dst}
-}
-
 mk_nogeli_mbr_zfs_uefi() {
     src=$1
     img=$2
@@ -249,33 +222,6 @@ mk_nogeli_mbr_zfs_uefi() {
     rm -rf ${dst}
 }
 
-mk_nogeli_mbr_zfs_both() {
-    src=$1
-    img=$2
-    mntpt=$3
-    geli=$4
-    scheme=$5
-    fs=$6
-    bios=$7
-    pool=nogeli-mbr-zfs-both
-
-    zfs_extra $src $dst
-    make_esp_file ${img}.s1 ${espsize} ${src}/boot/loader.efi
-    makefs -t zfs -s 200m \
-	-o poolname=${pool} -o bootfs=${pool} -o rootpath=/ \
-	${img}.s2a ${src} ${dst}
-    # The old boot1/boot2 boot split is also used by zfs. We need to extract zfsboot1
-    # from this image. Since there's no room in the mbr format for the rest of the loader,
-    # it will load the zfsboot loader from the reserved for bootloader area of the ZFS volume
-    # being booted, hence the need to dd it into the raw img later.
-    # Please note: zfsboot only works with partition 'a' which must be the root
-    # partition / zfs volume
-    dd if=${src}/boot/zfsboot of=${dst}/zfsboot1 count=1
-    mkimg -s bsd -b ${dst}zfsboot1 -p freebsd-zfs:=${img}.s2a -o ${img}.s2
-    dd if=${src}/boot/zfsboot of=${img}.s1a skip=1 seek=1024
-    mkimg -a 1 -s mbr -b ${src}/boot/mbr -p efi:=${img}.s1 -p freebsd:=${img}.s2 -o ${img}
-}
-
 mk_geli_gpt_ufs_legacy() {
     src=$1
     img=$2
@@ -728,6 +674,10 @@ for arch in amd64; do
 	for scheme in gpt mbr; do
 	    for fs in ufs zfs; do
 		for bios in legacy uefi both; do
+		    # ZFS+MBR+BIOS is not supported
+		    if [ "$scheme" = "mbr" -a "$fs" = "zfs" -a "$bios" != "uefi" ]; then
+			continue
+		    fi
 		    make_one_image ${arch} ${geli} ${scheme} ${fs} ${bios}
 		done
 	    done
@@ -750,6 +700,11 @@ for arch in i386; do
 		for bios in legacy; do
 		    # The legacy boot is shared with amd64 so those routines could
 		    # likely be used here.
+
+		    # ZFS+MBR+BIOS is not supported
+		    if [ "$scheme" = "mbr" -a "$fs" = "zfs" -a "$bios" != "uefi" ]; then
+			continue
+		    fi
 		    make_one_image ${arch} ${geli} ${scheme} ${fs} ${bios}
 		done
 	    done
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index da7f57eec2d5..580be4362a18 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -357,7 +357,6 @@ OLD_FILES+=boot/shortcuts.4th
 OLD_FILES+=boot/support.4th
 OLD_FILES+=boot/userboot.so
 OLD_FILES+=boot/version.4th
-OLD_FILES+=boot/zfsboot
 OLD_FILES+=boot/zfsloader
 OLD_FILES+=usr/lib/kgzldr.o
 OLD_FILES+=usr/share/man/man5/loader.conf.5.gz
@@ -374,7 +373,6 @@ OLD_FILES+=usr/share/man/man8/menu.4th.8.gz
 OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz
 OLD_FILES+=usr/share/man/man8/pxeboot.8.gz
 OLD_FILES+=usr/share/man/man8/version.4th.8.gz
-OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
 OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
 .endif
 
@@ -12277,7 +12275,6 @@ OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt
 
 .if ${MK_ZFS} == no
 OLD_FILES+=boot/gptzfsboot
-OLD_FILES+=boot/zfsboot
 OLD_FILES+=boot/zfsloader
 OLD_FILES+=etc/rc.d/zfs
 OLD_FILES+=etc/rc.d/zfsbe
@@ -12380,7 +12377,6 @@ OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz
 OLD_FILES+=usr/share/man/man8/zdb.8.gz
 OLD_FILES+=usr/share/man/man8/zfs-program.8.gz
 OLD_FILES+=usr/share/man/man8/zfs.8.gz
-OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
 OLD_FILES+=usr/share/man/man8/zfsbootcfg.8.gz
 OLD_FILES+=usr/share/man/man8/zfsd.8.gz
 OLD_FILES+=usr/share/man/man8/zfsloader.8.gz