An experiment to make a Multiboot-compliant kFreeBSD i386 image.
Copyright 2019 Rivoreo
Added code are released under the FreeBSD license (2-clause).

diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/boot/common/load_elf.c freebsd-10.4/sys/boot/common/load_elf.c
--- /var/archive3/public/freebsd-releng-10.4-src/sys/boot/common/load_elf.c	2017-09-29 08:20:01.000000000 +0800
+++ freebsd-10.4/sys/boot/common/load_elf.c	2019-08-17 22:11:53.101679679 +0800
@@ -161,6 +161,9 @@
     Elf_Ehdr 			*ehdr;
     int				err;
 
+#ifndef LOADER_USE_MULTIBOOT
+    if(multiboot) panic("%s: multiboot requested but LOADER_USE_MULTIBOOT was not set in build time", __func__);
+#endif
     fp = NULL;
     bzero(&ef, sizeof(struct elf_file));
     ef.fd = -1;
@@ -210,12 +213,14 @@
 	ef.kernel = 1;
 
     } else if (ehdr->e_type == ET_DYN) {
+#ifdef LOADER_USE_MULTIBOOT
 	/* Looks like a kld module */
 	if (multiboot != 0) {
 		printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n");
 		err = EPERM;
 		goto oerr;
 	}
+#endif
 	if (kfp == NULL) {
 	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
 	    err = EPERM;
@@ -248,14 +253,20 @@
 	    err = EPERM;
 	    goto out;
     }
+#ifdef LOADER_USE_MULTIBOOT
     if (ef.kernel == 1 && multiboot == 0)
+#endif
 	setenv("kernelname", filename, 1);
     fp->f_name = strdup(filename);
+#ifdef LOADER_USE_MULTIBOOT
     if (multiboot == 0)
+#endif
     	fp->f_type = strdup(ef.kernel ?
     	    __elfN(kerneltype) : __elfN(moduletype));
+#ifdef LOADER_USE_MULTIBOOT
     else
     	fp->f_type = strdup("elf multiboot kernel");
+#endif
 
 #ifdef ELF_VERBOSE
     if (ef.kernel)
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/libi386/multiboot.c freebsd-10.4/sys/boot/i386/libi386/multiboot.c
--- /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/libi386/multiboot.c	2017-09-29 08:20:01.000000000 +0800
+++ freebsd-10.4/sys/boot/i386/libi386/multiboot.c	2019-08-17 23:55:04.225245938 +0800
@@ -34,6 +34,8 @@
  * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
  */
 
+#ifdef LOADER_USE_MULTIBOOT
+
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: releng/10.4/sys/boot/i386/libi386/multiboot.c 294417 2016-01-20 13:23:02Z royger $");
 
@@ -423,3 +425,5 @@
 
 	return (EFTYPE);
 }
+
+#endif
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/libi386/multiboot_tramp.S freebsd-10.4/sys/boot/i386/libi386/multiboot_tramp.S
--- /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/libi386/multiboot_tramp.S	2017-09-29 08:20:01.000000000 +0800
+++ freebsd-10.4/sys/boot/i386/libi386/multiboot_tramp.S	2019-08-17 22:11:53.110679188 +0800
@@ -26,6 +26,8 @@
  * $FreeBSD: releng/10.4/sys/boot/i386/libi386/multiboot_tramp.S 294417 2016-01-20 13:23:02Z royger $
  */
 
+#ifdef LOADER_USE_MULTIBOOT
+
 #define ASM_FILE
 #include "multiboot.h"
 
@@ -49,3 +51,5 @@
 	movl	4(%esp), %ecx
 
 	call    *%ecx
+
+#endif
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/loader/conf.c freebsd-10.4/sys/boot/i386/loader/conf.c
--- /var/archive3/public/freebsd-releng-10.4-src/sys/boot/i386/loader/conf.c	2017-09-29 08:20:01.000000000 +0800
+++ freebsd-10.4/sys/boot/i386/loader/conf.c	2019-08-17 22:11:53.110679188 +0800
@@ -107,12 +107,12 @@
 extern struct file_format	i386_elf_obj;
 extern struct file_format	amd64_elf;
 extern struct file_format	amd64_elf_obj;
+#ifdef LOADER_USE_MULTIBOOT
 extern struct file_format	multiboot;
 extern struct file_format	multiboot_obj;
+#endif
 
 struct file_format *file_formats[] = {
-	&multiboot,
-	&multiboot_obj,
 #ifdef LOADER_PREFER_AMD64
     &amd64_elf,
     &amd64_elf_obj,
@@ -123,6 +123,10 @@
     &amd64_elf,
     &amd64_elf_obj,
 #endif
+#ifdef LOADER_USE_MULTIBOOT
+	&multiboot,
+	&multiboot_obj,
+#endif
     NULL
 };
 
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/conf/kern.pre.mk freebsd-10.4/sys/conf/kern.pre.mk
--- /var/archive3/public/freebsd-releng-10.4-src/sys/conf/kern.pre.mk	2017-09-29 08:19:45.000000000 +0800
+++ freebsd-10.4/sys/conf/kern.pre.mk	2019-08-17 23:55:16.556245349 +0800
@@ -170,8 +170,8 @@
 SYSTEM_OBJS= locore.o ${MDOBJS} ${OBJS}
 SYSTEM_OBJS+= ${SYSTEM_CFILES:.c=.o}
 SYSTEM_OBJS+= hack.So
-SYSTEM_LD= @${LD} -Bdynamic -T ${LDSCRIPT} ${LDFLAGS} --no-warn-mismatch \
-	-warn-common -export-dynamic -dynamic-linker /red/herring \
+SYSTEM_LD= @${LD} --call_shared -T ${LDSCRIPT} ${LDFLAGS} --no-warn-mismatch \
+	--warn-common --export-dynamic --dynamic-linker "" \
 	-o ${.TARGET} -X ${SYSTEM_OBJS} vers.o
 SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \
 	${SIZE} ${.TARGET} ; chmod 755 ${.TARGET}
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/conf/ldscript.i386 freebsd-10.4/sys/conf/ldscript.i386
--- /var/archive3/public/freebsd-releng-10.4-src/sys/conf/ldscript.i386	2017-09-29 08:19:45.000000000 +0800
+++ freebsd-10.4/sys/conf/ldscript.i386	2019-08-17 23:55:16.556245349 +0800
@@ -7,7 +7,7 @@
 {
   /* Read-only sections, merged into text segment: */
   . = kernbase + kernload + SIZEOF_HEADERS;
-  .interp         : { *(.interp) }
+  .mbheader	: AT (ADDR(.mbheader) - kernbase) { *(.mbheader) *(.interp) }
   .hash           : { *(.hash) }
   .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/conf/options freebsd-10.4/sys/conf/options
--- /var/archive3/public/freebsd-releng-10.4-src/sys/conf/options	2017-09-29 08:19:45.000000000 +0800
+++ freebsd-10.4/sys/conf/options	2019-08-18 00:01:09.084222141 +0800
@@ -950,3 +950,6 @@
 
 # Hyper-V network driver
 HN_DEBUG	opt_hn.h
+
+# Multiboot support, for i386 only
+MULTIBOOT	opt_multiboot.h
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/i386/conf/Rivoreo freebsd-10.4/sys/i386/conf/Rivoreo
--- /var/archive3/public/freebsd-releng-10.4-src/sys/i386/conf/Rivoreo	1970-01-01 08:00:00.000000000 +0800
+++ freebsd-10.4/sys/i386/conf/Rivoreo	2019-08-17 23:57:04.770238467 +0800
@@ -0,0 +1,378 @@
+#
+# GENERIC -- Generic kernel configuration file for FreeBSD/i386
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+#    http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD: releng/10.4/sys/i386/conf/GENERIC 302041 2016-06-21 04:51:55Z sephe $
+
+ident		Rivoreo
+
+cpu		I486_CPU
+cpu		I586_CPU
+cpu		I686_CPU
+
+#makeoptions	CC=gcc
+makeoptions	COPTFLAGS="-Os --pipe"
+makeoptions	DEBUG=-g		# Build kernel with gdb(1) debug symbols
+makeoptions	WITH_CTF=1		# Run ctfconvert(1) for DTrace support
+makeoptions	WITHOUT_SOURCELESS_HOST=1
+
+options 	SCHED_ULE		# ULE scheduler
+options 	PREEMPTION		# Enable kernel thread preemption
+options 	INET			# InterNETworking
+options 	INET6			# IPv6 communications protocols
+options 	TCP_OFFLOAD		# TCP offload
+options 	SCTP			# Stream Control Transmission Protocol
+options 	FFS			# Berkeley Fast Filesystem
+options 	SOFTUPDATES		# Enable FFS soft updates support
+options		UFS_EXTATTR
+options 	UFS_ACL			# Support for access control lists
+options 	UFS_DIRHASH		# Improve performance on big directories
+options 	UFS_GJOURNAL		# Enable gjournal-based UFS journaling
+options 	QUOTA			# Enable disk quotas for UFS
+options 	MD_ROOT			# MD is a potential root device
+options 	NFSCL			# New Network Filesystem Client
+options 	NFSD			# New Network Filesystem Server
+options 	NFSLOCKD		# Network Lock Manager
+options 	NFS_ROOT		# NFS usable as /, requires NFSCL
+#options 	MSDOSFS			# MSDOS Filesystem
+#options 	CD9660			# ISO 9660 Filesystem
+#options 	PROCFS			# Process filesystem (requires PSEUDOFS)
+options 	PSEUDOFS		# Pseudo-filesystem framework
+options 	GEOM_PART_GPT		# GUID Partition Tables.
+options		GEOM_PART_MBR
+options		GEOM_PART_BSD
+options 	GEOM_RAID		# Soft RAID functionality.
+options 	GEOM_LABEL		# Provides labelization
+options 	COMPAT_FREEBSD4		# Compatible with FreeBSD4
+options 	COMPAT_FREEBSD5		# Compatible with FreeBSD5
+options 	COMPAT_FREEBSD6		# Compatible with FreeBSD6
+options 	COMPAT_FREEBSD7		# Compatible with FreeBSD7
+options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
+options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
+options 	SYSVSHM			# SYSV-style shared memory
+options 	SYSVMSG			# SYSV-style message queues
+options 	SYSVSEM			# SYSV-style semaphores
+options 	_KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options 	PRINTF_BUFR_SIZE=128	# Prevent printf output being interspersed.
+options 	KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+options 	HWPMC_HOOKS		# Necessary kernel hooks for hwpmc(4)
+options 	AUDIT			# Security event auditing
+options 	CAPABILITY_MODE		# Capsicum capability mode
+options 	CAPABILITIES		# Capsicum capabilities
+options 	PROCDESC		# Support for process descriptors
+options 	MAC			# TrustedBSD MAC Framework
+options 	KDTRACE_HOOKS		# Kernel DTrace hooks
+options 	DDB_CTF			# Kernel ELF linker loads CTF data
+options 	INCLUDE_CONFIG_FILE	# Include this file in kernel
+options 	RACCT			# Resource accounting framework
+options 	RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
+options 	RCTL			# Resource limits
+options		MULTIBOOT
+
+# Debugging support.  Always need this:
+options 	KDB			# Enable kernel debugger support.
+options 	KDB_TRACE		# Print a stack trace for a panic.
+
+# To make an SMP kernel, the next two lines are needed
+options 	SMP			# Symmetric MultiProcessor Kernel
+device		apic			# I/O APIC
+
+# CPU frequency control
+device		cpufreq
+
+device		mem
+
+# Bus support.
+device		acpi
+device		eisa
+device		pci
+device		isa
+device		io
+
+# Floppy drives
+device		fdc
+
+# ATA controllers
+device		ahci			# AHCI-compatible SATA controllers
+device		ata			# Legacy ATA/SATA controllers
+options 	ATA_STATIC_ID		# Static device numbering
+device		mvs			# Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA
+device		siis			# SiliconImage SiI3124/SiI3132/SiI3531 SATA
+
+# SCSI Controllers
+device		ahb			# EISA AHA1742 family
+device		ahc			# AHA2940 and onboard AIC7xxx devices
+options 	AHC_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~128k to driver.
+device		ahd			# AHA39320/29320 and onboard AIC79xx devices
+options 	AHD_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~215k to driver.
+device		esp			# AMD Am53C974 (Tekram DC-390(T))
+device		hptiop			# Highpoint RocketRaid 3xxx series
+device		isp			# Qlogic family
+#device		ispfw			# Firmware for QLogic HBAs- normally a module
+device		mpt			# LSI-Logic MPT-Fusion
+device		mps			# LSI-Logic MPT-Fusion 2
+device		mpr			# LSI-Logic MPT-Fusion 3
+#device		ncr			# NCR/Symbios Logic
+device		sym			# NCR/Symbios Logic (newer chipsets + those of `ncr')
+device		trm			# Tekram DC395U/UW/F DC315U adapters
+
+device		adv			# Advansys SCSI adapters
+device		adw			# Advansys wide SCSI adapters
+device		aha			# Adaptec 154x SCSI adapters
+device		aic			# Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
+device		bt			# Buslogic/Mylex MultiMaster SCSI adapters
+
+device		ncv			# NCR 53C500
+device		nsp			# Workbit Ninja SCSI-3
+device		stg			# TMC 18C30/18C50
+device		isci			# Intel C600 SAS controller
+
+# ATA/SCSI peripherals
+device		scbus			# SCSI bus (required for ATA/SCSI)
+device		ch			# SCSI media changers
+device		da			# Direct Access (disks)
+device		sa			# Sequential Access (tape etc)
+device		cd			# CD
+device		pass			# Passthrough device (direct ATA/SCSI access)
+device		ses			# Enclosure Services (SES and SAF-TE)
+#device		ctl			# CAM Target Layer
+
+# RAID controllers interfaced to the SCSI subsystem
+device		amr			# AMI MegaRAID
+device		arcmsr			# Areca SATA II RAID
+device		asr			# DPT SmartRAID V, VI and Adaptec SCSI RAID
+device		ciss			# Compaq Smart RAID 5*
+device		dpt			# DPT Smartcache III, IV - See NOTES for options
+device		iir			# Intel Integrated RAID
+device		ips			# IBM (Adaptec) ServeRAID
+device		mly			# Mylex AcceleRAID/eXtremeRAID
+device		twa			# 3ware 9000 series PATA/SATA RAID
+device		tws			# LSI 3ware 9750 SATA+SAS 6Gb/s RAID controller
+
+# RAID controllers
+device		aac			# Adaptec FSA RAID
+device		aacp			# SCSI passthrough for aac (requires CAM)
+device		aacraid			# Adaptec by PMC RAID
+device		ida			# Compaq Smart RAID
+device		mfi			# LSI MegaRAID SAS
+device		mlx			# Mylex DAC960 family
+device		mrsas			# LSI/Avago MegaRAID SAS/SATA, 6Gb/s and 12Gb/s
+#XXX PCI ID conflicts with ahd(4) and mvs(4)
+#device		pmspcv			# PMC-Sierra SAS/SATA Controller driver
+device		pst			# Promise Supertrak SX6000
+device		twe			# 3ware ATA RAID
+
+# NVM Express (NVMe) support
+device		nvme			# base NVMe driver
+device		nvd			# expose NVMe namespace as disks, depends on nvme
+
+# atkbdc0 controls both the keyboard and the PS/2 mouse
+device		atkbdc			# AT keyboard controller
+device		atkbd			# AT keyboard
+device		psm			# PS/2 mouse
+
+device		kbdmux			# keyboard multiplexer
+
+device		vga			# VGA video card driver
+options 	VESA			# Add support for VESA BIOS Extensions (VBE)
+
+device		splash			# Splash screen and screen saver support
+
+# syscons is the default console driver, resembling an SCO console
+device		sc
+options 	SC_PIXEL_MODE		# add support for the raster text mode
+
+# vt is the new video console driver
+device		vt
+device		vt_vga
+
+device		agp			# support several AGP chipsets
+
+# Power management support (see NOTES for more options)
+#device		apm
+# Add suspend/resume support for the i8254.
+device		pmtimer
+
+# PCCARD (PCMCIA) support
+# PCMCIA and cardbus bridge support
+device		cbb			# cardbus (yenta) bridge
+device		pccard			# PC Card (16-bit) bus
+device		cardbus			# CardBus (32-bit) bus
+
+# Serial (COM) ports
+device		uart			# Generic UART driver
+
+# Parallel port
+device		ppc
+device		ppbus			# Parallel port bus (required)
+device		lpt			# Printer
+device		ppi			# Parallel port interface device
+#device		vpo			# Requires scbus and da
+
+device		puc			# Multi I/O cards and multi-channel UARTs
+
+# PCI Ethernet NICs.
+device		bxe			# Broadcom NetXtreme II BCM5771X/BCM578XX 10GbE
+device		de			# DEC/Intel DC21x4x (``Tulip'')
+device		em			# Intel PRO/1000 Gigabit Ethernet Family
+device		igb			# Intel PRO/1000 PCIE Server Gigabit Family
+device		ixgb			# Intel PRO/10GbE Ethernet Card
+device		le			# AMD Am7900 LANCE and Am79C9xx PCnet
+device		ti			# Alteon Networks Tigon I/II gigabit Ethernet
+device		txp			# 3Com 3cR990 (``Typhoon'')
+device		vx			# 3Com 3c590, 3c595 (``Vortex'')
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device		miibus			# MII bus support
+device		ae			# Attansic/Atheros L2 FastEthernet
+device		age			# Attansic/Atheros L1 Gigabit Ethernet
+device		alc			# Atheros AR8131/AR8132 Ethernet
+device		ale			# Atheros AR8121/AR8113/AR8114 Ethernet
+device		bce			# Broadcom BCM5706/BCM5708 Gigabit Ethernet
+device		bfe			# Broadcom BCM440x 10/100 Ethernet
+device		bge			# Broadcom BCM570xx Gigabit Ethernet
+device		cas			# Sun Cassini/Cassini+ and NS DP83065 Saturn
+device		dc			# DEC/Intel 21143 and various workalikes
+device		et			# Agere ET1310 10/100/Gigabit Ethernet
+device		fxp			# Intel EtherExpress PRO/100B (82557, 82558)
+device		gem			# Sun GEM/Sun ERI/Apple GMAC
+device		hme			# Sun HME (Happy Meal Ethernet)
+device		jme			# JMicron JMC250 Gigabit/JMC260 Fast Ethernet
+device		lge			# Level 1 LXT1001 gigabit Ethernet
+device		msk			# Marvell/SysKonnect Yukon II Gigabit Ethernet
+device		nfe			# nVidia nForce MCP on-board Ethernet
+device		nge			# NatSemi DP83820 gigabit Ethernet
+device		pcn			# AMD Am79C97x PCI 10/100 (precedence over 'le')
+device		re			# RealTek 8139C+/8169/8169S/8110S
+device		rl			# RealTek 8129/8139
+device		sf			# Adaptec AIC-6915 (``Starfire'')
+device		sge			# Silicon Integrated Systems SiS190/191
+device		sis			# Silicon Integrated Systems SiS 900/SiS 7016
+device		sk			# SysKonnect SK-984x & SK-982x gigabit Ethernet
+device		ste			# Sundance ST201 (D-Link DFE-550TX)
+device		stge			# Sundance/Tamarack TC9021 gigabit Ethernet
+device		tl			# Texas Instruments ThunderLAN
+device		tx			# SMC EtherPower II (83c170 ``EPIC'')
+device		vge			# VIA VT612x gigabit Ethernet
+device		vr			# VIA Rhine, Rhine II
+device		vte			# DM&P Vortex86 RDC R6040 Fast Ethernet
+device		wb			# Winbond W89C840F
+device		xl			# 3Com 3c90x (``Boomerang'', ``Cyclone'')
+
+# ISA Ethernet NICs.  pccard NICs included.
+device		cs			# Crystal Semiconductor CS89x0 NIC
+# 'device ed' requires 'device miibus'
+device		ed			# NE[12]000, SMC Ultra, 3c503, DS8390 cards
+device		ex			# Intel EtherExpress Pro/10 and Pro/10+
+device		ep			# Etherlink III based cards
+device		fe			# Fujitsu MB8696x based cards
+device		ie			# EtherExpress 8/16, 3C507, StarLAN 10 etc.
+device		sn			# SMC's 9000 series of Ethernet chips
+device		xe			# Xircom pccard Ethernet
+
+# Wireless NIC cards
+device		wlan			# 802.11 support
+options 	IEEE80211_DEBUG		# enable debug msgs
+options 	IEEE80211_AMPDU_AGE	# age frames in AMPDU reorder q's
+options 	IEEE80211_SUPPORT_MESH	# enable 802.11s draft support
+device		wlan_wep		# 802.11 WEP support
+device		wlan_ccmp		# 802.11 CCMP support
+device		wlan_tkip		# 802.11 TKIP support
+device		wlan_amrr		# AMRR transmit rate control algorithm
+device		an			# Aironet 4500/4800 802.11 wireless NICs.
+device		ath			# Atheros NICs
+device		ath_pci			# Atheros pci/cardbus glue
+device		ath_hal			# pci/cardbus chip support
+options 	AH_SUPPORT_AR5416	# enable AR5416 tx/rx descriptors
+options 	AH_AR5416_INTERRUPT_MITIGATION # AR5416 interrupt mitigation
+options 	ATH_ENABLE_11N		# Enable 802.11n support for AR5416 and later
+device		ath_rate_sample		# SampleRate tx rate control for ath
+#device		bwi			# Broadcom BCM430x/BCM431x wireless NICs.
+#device		bwn			# Broadcom BCM43xx wireless NICs.
+device		ipw			# Intel 2100 wireless NICs.
+device		iwi			# Intel 2200BG/2225BG/2915ABG wireless NICs.
+device		iwn			# Intel 4965/1000/5000/6000 wireless NICs.
+device		malo			# Marvell Libertas wireless NICs.
+device		mwl			# Marvell 88W8363 802.11n wireless NICs.
+device		ral			# Ralink Technology RT2500 wireless NICs.
+device		wi			# WaveLAN/Intersil/Symbol 802.11 wireless NICs.
+#device		wl			# Older non 802.11 Wavelan wireless NIC.
+device		wpi			# Intel 3945ABG wireless NICs.
+
+# Pseudo devices.
+device		loop			# Network loopback
+device		random			# Entropy device
+device		padlock_rng		# VIA Padlock RNG
+device		rdrand_rng		# Intel Bull Mountain RNG
+device		ether			# Ethernet support
+device		vlan			# 802.1Q VLAN support
+device		md			# Memory "disks"
+device		firmware		# firmware assist module
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device		bpf			# Berkeley packet filter
+
+# USB support
+options 	USB_DEBUG		# enable debug msgs
+device		uhci			# UHCI PCI->USB interface
+device		ohci			# OHCI PCI->USB interface
+device		ehci			# EHCI PCI->USB interface (USB 2.0)
+device		xhci			# XHCI PCI->USB interface (USB 3.0)
+device		usb			# USB Bus (required)
+device		ukbd			# Keyboard
+device		umass			# Disks/Mass storage - Requires scbus and da
+
+# Sound support
+device		sound			# Generic sound driver (required)
+device		snd_cmi			# CMedia CMI8338/CMI8738
+device		snd_csa			# Crystal Semiconductor CS461x/428x
+device		snd_emu10kx		# Creative SoundBlaster Live! and Audigy
+device		snd_es137x		# Ensoniq AudioPCI ES137x
+device		snd_hda			# Intel High Definition Audio
+device		snd_ich			# Intel, NVidia and other ICH AC'97 Audio
+device		snd_via8233		# VIA VT8233x Audio
+
+# MMC/SD
+device		mmc			# MMC/SD bus
+device		mmcsd			# MMC/SD memory card
+device		sdhci			# Generic PCI SD Host Controller
+
+# VirtIO support
+device		virtio			# Generic VirtIO bus (required)
+device		virtio_pci		# VirtIO PCI device
+device		vtnet			# VirtIO Ethernet device
+device		virtio_blk		# VirtIO Block device
+device		virtio_scsi		# VirtIO SCSI device
+device		virtio_balloon		# VirtIO Memory Balloon device
+
+# HyperV drivers and enchancement support
+options 	HYPERV			# Hyper-V kernel infrastructure
+device		hyperv			# HyperV drivers 
+
+# Xen HVM Guest Optimizations
+# NOTE: XENHVM depends on xenpci.  They must be added or removed together.
+#options 	XENHVM			# Xen HVM kernel infrastructure
+#device		xenpci			# Xen HVM Hypervisor services driver
+
+# VMware support
+#device		vmx			# VMware VMXNET3 Ethernet
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/i386/i386/locore.s freebsd-10.4/sys/i386/i386/locore.s
--- /var/archive3/public/freebsd-releng-10.4-src/sys/i386/i386/locore.s	2017-09-29 08:20:02.000000000 +0800
+++ freebsd-10.4/sys/i386/i386/locore.s	2019-08-17 23:55:16.559247691 +0800
@@ -43,10 +43,11 @@
 #include "opt_compat.h"
 #include "opt_nfsroot.h"
 #include "opt_pmap.h"
+#include "opt_multiboot.h"
 
 #include <sys/syscall.h>
 #include <sys/reboot.h>
-
+#include <sys/multiboot.h>
 #include <machine/asmacros.h>
 #include <machine/cputypes.h>
 #include <machine/psl.h>
@@ -126,6 +127,22 @@
 	.space	0x240
 #endif
 
+#ifdef MULTIBOOT
+	.globl	multiboot_env
+multiboot_env:	.long	0
+	.globl	multiboot_mem_lower, multiboot_mem_upper, multiboot_cmdline, multiboot_mods
+multiboot_mem_lower:
+	.long	0
+multiboot_mem_upper:
+	.long	0
+multiboot_cmdline:
+	.space	MI_CMDLINE_MAX, 0
+	.byte	0
+multiboot_mods:
+	.long	0
+	.long	0
+#endif
+
 /**********************************************************************
  *
  * Some handy macros
@@ -175,6 +192,16 @@
 	shrl	$PAGE_SHIFT, %ebx	; \
 	fillkpt(R(KPTphys), prot)
 
+	.section	.mbheader
+	.align 4
+#ifdef MULTIBOOT
+#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
+multiboot_header:
+	.long	MULTIBOOT_HEADER_MAGIC
+	.long	MULTIBOOT_HEADER_FLAGS
+	.long	-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+#endif
+
 	.text
 /**********************************************************************
  *
@@ -196,6 +223,17 @@
 	movw	$0x1234,0x472
 #endif	/* PC98 */
 
+#ifdef MULTIBOOT
+	/* Are we booted up by a multiboot bootloader? */
+	cmpl	$MULTIBOOT_BOOTLOADER_MAGIC, %eax
+	jne	1f
+	movl	$0, R(bootinfo+BI_KERNEND)
+	movl	%ebx, R(multiboot_env)
+	jmp	2f
+
+1:
+#endif
+
 /* Set up a real frame in case the double return in newboot is executed. */
 	pushl	%ebp
 	movl	%esp, %ebp
@@ -232,6 +270,8 @@
 
 	call	recover_bootinfo
 
+2:
+
 /* Get onto a stack that we can trust. */
 /*
  * XXX this step is delayed in case recover_bootinfo needs to return via
@@ -239,6 +279,12 @@
  * returns via the old frame.
  */
 	movl	$R(tmpstk),%esp
+#ifdef MULTIBOOT
+	cmpl	$MULTIBOOT_BOOTLOADER_MAGIC, %eax	/* %eax remains same if we jumped here by label 2 */
+	jne	3f
+	call	recover_multiboot_env
+3:
+#endif
 
 #ifdef PC98
 	/* pc98_machine_type & M_EPSON_PC98 */
@@ -552,6 +598,69 @@
 
 	ret
 
+#ifdef MULTIBOOT
+/* https://www.gnu.org/software/grub/manual/multiboot/html_node/Boot-information-format.html */
+recover_multiboot_env:
+	movl	R(multiboot_env), %eax
+	testl	$MI_FLAG_MEMORY, (%eax)
+	jz	1f
+	/* Recover memory information */
+	movl	MI_MEM_LOWER(%eax), %ecx
+	movl	%ecx, R(multiboot_mem_lower)
+	movl	MI_MEM_UPPER(%eax), %ecx
+	movl	%ecx, R(multiboot_mem_upper)
+1:
+	testl	$MI_FLAG_CMDLINE, (%eax)
+	jz	6f
+	/* Recover cmdline. */
+	movl	MI_CMDLINE(%eax), %esi
+	movl	$R(multiboot_cmdline), %edi
+	movl	$MI_CMDLINE_MAX, %ecx
+	cld
+2:
+	cmpl	$0, (%esi)
+	jz	3f
+	movsb
+	testl	%ecx, %ecx
+	jnz	2b
+3:
+	/* Copy first arguament to kernelname if it starts with '/' */
+	movl	MI_CMDLINE(%eax), %esi
+	cmpb	$'/', (%esi)
+	jne	6f
+	movl	$MAXPATHLEN-1, %ecx
+	movl	$R(kernelname), %edi
+	cld
+4:
+	cmpb	$' ', (%esi)
+	je	5f
+	cmpb	$0, (%esi)
+	je	5f
+	movsb
+	testl	%ecx, %ecx
+	jnz	4b
+5:
+	movb	$0, (%edi)
+6:
+	testl	$MI_FLAG_MODS, (%eax)
+	jz	7f
+	movl	MI_MODS_ADDR(%eax), %ecx
+	movl	%ecx, R(multiboot_mods+4)
+	movl	MI_MODS_COUNT(%eax), %ecx
+	movl	%ecx, R(multiboot_mods)
+	/* Set bootinfo.bi_kernend from multiboot modules if any */
+	testl	%ecx, %ecx
+	jz	7f
+//	pushl	%eax
+	pushl	%ecx
+	pushl	R(multiboot_mods+4)
+	call	get_kernend_from_multiboot_mods
+	addl	$8, %esp
+//	popl	%eax
+7:
+	ret
+#endif
+
 
 /**********************************************************************
  *
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/i386/i386/machdep.c freebsd-10.4/sys/i386/i386/machdep.c
--- /var/archive3/public/freebsd-releng-10.4-src/sys/i386/i386/machdep.c	2017-09-29 08:20:02.000000000 +0800
+++ freebsd-10.4/sys/i386/i386/machdep.c	2019-08-17 23:55:16.561251974 +0800
@@ -57,6 +57,7 @@
 #include "opt_platform.h"
 #include "opt_xbox.h"
 #include "opt_kdtrace.h"
+#include "opt_multiboot.h"
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -121,6 +122,10 @@
 #include <net/netisr.h>
 
 #include <machine/bootinfo.h>
+#ifdef MULTIBOOT
+#include <machine/multiboot.h>
+#include <machine/elf.h>
+#endif
 #include <machine/clock.h>
 #include <machine/cpu.h>
 #include <machine/cputypes.h>
@@ -2206,6 +2211,10 @@
 }
 #endif /* !XEN */
 
+#ifdef MULTIBOOT
+int ignore_multiboot_memory_size = 0;
+#endif
+
 /*
  * Populate the (physmap) array with base/bound pairs describing the
  * available physical memory in the system, then test this memory and
@@ -2556,6 +2565,15 @@
 		goto have_smap;
 	}
 
+#ifdef MULTIBOOT
+	if(!ignore_multiboot_memory_size && multiboot_env && multiboot_mem_lower && multiboot_mem_upper) {
+		basemem = multiboot_mem_lower;
+		basemem_setup();
+		extmem = multiboot_mem_upper;
+		goto skip_bios_calls;
+	}
+#endif
+
 	/*
 	 * Some newer BIOSes have a broken INT 12H implementation
 	 * which causes a kernel panic immediately.  In this case, we
@@ -2644,6 +2662,9 @@
 #endif
 	}
 
+#ifdef MULTIBOOT
+skip_bios_calls:
+#endif
 	/*
 	 * Special hack for chipsets that still remap the 384k hole when
 	 * there's 16MB of memory - this really confuses people that
@@ -2894,6 +2915,276 @@
 }
 #endif /* PC98 */
 
+#ifdef MULTIBOOT
+extern int _end;
+
+static size_t fill_module_info_from_multiboot(caddr_t addr) {
+	size_t r = 0;
+	unsigned int i = 0;
+	// Note the first module in bootinfo.bi_modulep should be the kernel image itself.
+	size_t kernel_name_len = strlen(kernelname) + 1;
+	r += sizeof(uint32_t) * 2 + roundup(kernel_name_len, sizeof(uint32_t));
+	if(addr) {
+		((uint32_t *)addr)[0] = MODINFO_NAME;
+		((uint32_t *)addr)[1] = kernel_name_len;
+		memcpy(addr + sizeof(uint32_t) * 2, kernelname, kernel_name_len);
+		addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+	}
+	r += sizeof(uint32_t) * 2 + roundup(sizeof "elf kernel", sizeof(uint32_t));
+	if(addr) {
+		((uint32_t *)addr)[0] = MODINFO_TYPE;
+		((uint32_t *)addr)[1] = sizeof "elf kernel";
+		strcpy(addr + sizeof(uint32_t) * 2, "elf kernel");
+		addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+	}
+	if(*multiboot_cmdline) {
+		const char *space = strchr(multiboot_cmdline, ' ');
+		if(space) {
+			size_t len = strlen(space + 1) + 1;
+			r += sizeof(uint32_t) * 2 + roundup(len, sizeof(uint32_t));
+			if(addr) {
+				((uint32_t *)addr)[0] = MODINFO_ARGS;
+				((uint32_t *)addr)[1] = len;
+				memcpy(addr + sizeof(uint32_t) * 2, space + 1, len);
+				addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+			}
+		}
+	}
+	r += sizeof(uint32_t) * 2 + sizeof(caddr_t);
+	if(addr) {
+		((uint32_t *)addr)[0] = MODINFO_ADDR;
+		((uint32_t *)addr)[1] = sizeof(uint32_t);
+		*(caddr_t *)(addr + sizeof(uint32_t) * 2) = (caddr_t)KERNLOAD;
+		addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+	}
+	r += sizeof(uint32_t) * 2 + sizeof(size_t);
+	if(addr) {
+		((uint32_t *)addr)[0] = MODINFO_SIZE;
+		((uint32_t *)addr)[1] = sizeof(uint32_t);
+		*(size_t *)(addr + sizeof(uint32_t) * 2) = (size_t)((caddr_t)&_end - (caddr_t)(KERNLOAD + KERNBASE));
+		addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+	}
+	while(i < multiboot_mods.count) {
+		struct multiboot_module *mbmod = (struct multiboot_module *)((caddr_t)(multiboot_mods.address + i) + KERNBASE);
+		const char *name = (const char *)mbmod->cmdline;
+		const char *space = strchr(name, ' ');
+		size_t name_len = space ? (space - name) : strlen(name);
+		r += sizeof(uint32_t) * 2 + roundup(name_len + 1, sizeof(uint32_t));
+		if(addr) {
+			((uint32_t *)addr)[0] = MODINFO_NAME;
+			((uint32_t *)addr)[1] = name_len + 1;
+			memcpy(addr + sizeof(uint32_t) * 2, name, name_len);
+			addr[sizeof(uint32_t) * 2 + name_len] = 0;
+			addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+		}
+
+		// XXX: Assuming other module types are 'md_image' (initrd).
+		const char *module_type = "md_image";
+		size_t module_type_len = sizeof "md_image";
+		size_t multiboot_module_size = mbmod->mod_end - mbmod->mod_start;
+		Elf_Ehdr *elfhdr = NULL;
+		caddr_t *start_address;
+		size_t *module_size;
+		if(multiboot_module_size > sizeof(Elf_Ehdr)) {
+			elfhdr = (Elf_Ehdr *)mbmod->mod_start;
+			if(IS_ELF(*elfhdr) && elfhdr->e_ident[EI_CLASS] == ELFCLASS32 &&
+			  elfhdr->e_ident[EI_DATA] == ELFDATA2LSB &&
+			  elfhdr->e_ident[EI_VERSION] == EV_CURRENT &&
+			  elfhdr->e_version == EV_CURRENT && elfhdr->e_machine == EM_386) {
+				//switch(elfhdr->e_type)
+				// i386 kernel didn't use relocatable object
+				module_type = "elf module";
+				module_type_len = sizeof "elf module";
+			} else {
+				elfhdr = NULL;
+			}
+		}
+		r += sizeof(uint32_t) * 2 + roundup(module_type_len, sizeof(uint32_t));
+		if(addr) {
+			((uint32_t *)addr)[0] = MODINFO_TYPE;
+			((uint32_t *)addr)[1] = module_type_len;
+			memcpy(addr + sizeof(uint32_t) * 2, module_type, module_type_len);
+			addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+		}
+		if(space) {
+			size_t len = strlen(space + 1) + 1;
+			r += sizeof(uint32_t) * 2 + roundup(len, sizeof(uint32_t));
+			if(addr) {
+				((uint32_t *)addr)[0] = MODINFO_ARGS;
+				((uint32_t *)addr)[1] = len;
+				memcpy(addr + sizeof(uint32_t) * 2, space + 1, len);
+				addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+			}
+		}
+		r += sizeof(uint32_t) * 2 + sizeof(caddr_t);
+		if(addr) {
+			((uint32_t *)addr)[0] = MODINFO_ADDR;
+			((uint32_t *)addr)[1] = sizeof(caddr_t);
+			start_address = (caddr_t *)(addr + sizeof(uint32_t) * 2);
+			*start_address = (caddr_t)mbmod->mod_start;
+			addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+		}
+		r += sizeof(uint32_t) * 2 + sizeof(size_t);
+		if(addr) {
+			((uint32_t *)addr)[0] = MODINFO_SIZE;
+			((uint32_t *)addr)[1] = sizeof(size_t);
+			module_size = (size_t *)(addr + sizeof(uint32_t) * 2);
+			*module_size = multiboot_module_size;
+			addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+		}
+		if(elfhdr) {
+			r += sizeof(uint32_t) * 2 + roundup(sizeof(Elf_Ehdr), sizeof(uint32_t));
+			if(addr) {
+				((uint32_t *)addr)[0] = MODINFO_METADATA | MODINFOMD_ELFHDR;
+				((uint32_t *)addr)[1] = sizeof(Elf_Ehdr);
+				memcpy(addr + sizeof(uint32_t) * 2, elfhdr, sizeof(Elf_Ehdr));
+				addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+			}
+			Elf_Phdr *phdr = (Elf_Phdr *)(mbmod->mod_start + elfhdr->e_phoff);
+			if((uint32_t)phdr < mbmod->mod_end) {
+				uint32_t segment_offset = (uint32_t)-1;
+				uint32_t segment_end_offset = 0;
+				unsigned int j = 0;
+				while(j < elfhdr->e_phnum) {
+					if(phdr->p_filesz < phdr->p_memsz) {
+						// This gap was the BSS
+						if(mbmod->mod_start + phdr->p_offset + phdr->p_memsz > mbmod->mod_end) {
+							// No room to fill BSS, sorry...
+							break;
+						}
+						memset((caddr_t)(mbmod->mod_start + phdr->p_offset + phdr->p_filesz),
+							0, phdr->p_memsz - phdr->p_filesz);
+					}/* else if(phdr->p_filesz > phdr->p_memsz) {
+						// What?
+						break;
+					}*/
+					if(phdr->p_offset < phdr->p_vaddr) {
+						// Relocate segment
+						if(mbmod->mod_start + phdr->p_vaddr + phdr->p_memsz > mbmod->mod_end) {
+							// No room to relocate, sorry...
+							break;
+						}
+						memmove((caddr_t)(mbmod->mod_start + phdr->p_vaddr),
+							(caddr_t)(mbmod->mod_start + phdr->p_offset), phdr->p_memsz);
+					} else if(phdr->p_offset > phdr->p_vaddr) {
+						// Hm?
+						memmove((caddr_t)(mbmod->mod_start + phdr->p_vaddr),
+							(caddr_t)(mbmod->mod_start + phdr->p_offset), phdr->p_memsz);
+					}
+					switch(phdr->p_type) {
+						case PT_LOAD:
+							//if(!addr) break;
+							if(segment_offset > phdr->p_vaddr) {
+								segment_offset = phdr->p_vaddr;
+							}
+							if(segment_end_offset < phdr->p_vaddr + phdr->p_memsz) {
+								segment_end_offset = phdr->p_vaddr + phdr->p_memsz;
+							}
+							break;
+						case PT_DYNAMIC:
+							r += sizeof phdr->p_vaddr;
+							if(addr) {
+								((uint32_t *)addr)[0] = MODINFO_METADATA | MODINFOMD_DYNAMIC;
+								((uint32_t *)addr)[1] = sizeof phdr->p_vaddr;
+								*(Elf_Addr *)(addr + sizeof(uint32_t) * 2) = phdr->p_vaddr;
+								addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+							}
+							break;
+					}
+					phdr++;
+					j++;
+				}
+				if(addr && segment_offset != (uint32_t)-1 && segment_end_offset) {
+					*start_address += segment_offset;
+					*module_size = roundup(segment_end_offset - segment_offset, sizeof(uint32_t));
+				}
+				size_t shdr_size = elfhdr->e_shnum * elfhdr->e_shentsize;
+				if(shdr_size && shdr_size <= multiboot_module_size - elfhdr->e_shoff &&
+				  segment_offset != (uint32_t)-1 && segment_end_offset) {
+					unsigned int k;
+					Elf_Shdr *shdr = (Elf_Shdr *)(mbmod->mod_start + elfhdr->e_shoff);
+/*					// Skip MODINFOMD_SHDR, i386 kernel doesn't use it
+					r += sizeof(uint32_t) * 2 + roundup(shdr_size, sizeof(uint32_t));
+					if(addr) {
+						((uint32_t *)addr)[0] = MODINFO_METADATA | MODINFOMD_SHDR;
+						((uint32_t *)addr)[1] = shdr_size;
+						memcpy(addr + sizeof(uint32_t) * 2, shdr, shdr_size);
+						addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+					}
+*/
+					// XXX: Assuming MODINFOMD_SSYM and MODINFOMD_ESYM will be written
+					r += (sizeof(uint32_t) * 2 + sizeof(Elf_Addr)) * 2;
+					if(addr) {
+						Elf_Addr ssym = 0, esym = 0;
+						int symtabi = -1, symstri = -1;
+						phdr = (Elf_Phdr *)(mbmod->mod_start + elfhdr->e_phoff);
+						for(j = 0; j < elfhdr->e_shnum; j++) {
+							if(shdr[j].sh_type != SHT_SYMTAB) continue;
+							for(k = 0; k < elfhdr->e_phnum; k++) {
+								if(phdr[k].p_type != PT_LOAD) continue;
+								if(shdr[j].sh_offset >= phdr[k].p_offset &&
+								  (shdr[j].sh_offset + shdr[j].sh_size <=
+								   phdr[k].p_offset + phdr[k].p_filesz)) {
+									shdr[j].sh_offset = 0;
+									shdr[j].sh_size = 0;
+								}
+								if(!shdr[j].sh_offset || !shdr[j].sh_size) continue;
+								symtabi = j;
+								symstri = shdr[j].sh_link;
+							}
+						}
+						if(symtabi >= 0 && symstri >= 0) {
+							caddr_t rewrite = (caddr_t)(mbmod->mod_start + segment_end_offset);
+							ssym = (Elf_Addr)rewrite;
+							for(j = symtabi; j >= 0; j = symstri) {
+								if(mbmod->mod_start + shdr[j].sh_offset + shdr[j].sh_size > mbmod->mod_end) {
+									ssym = 0;
+									break;
+								}
+								*(Elf_Size *)rewrite = shdr[j].sh_size;
+								rewrite += sizeof(Elf_Size);
+								memmove(rewrite, (caddr_t)(mbmod->mod_start + shdr[j].sh_offset), shdr[j].sh_size);
+								rewrite += roundup(shdr[j].sh_size, sizeof(Elf_Size));
+								if(j == symstri) break;
+							}
+							if(ssym) {
+								esym = (Elf_Addr)rewrite;
+								*module_size = roundup(rewrite - *start_address, sizeof(uint32_t));
+							}
+						}
+						((uint32_t *)addr)[0] = MODINFO_METADATA | MODINFOMD_SSYM;
+						((uint32_t *)addr)[1] = sizeof ssym;
+						*(Elf_Addr *)(addr + sizeof(uint32_t) * 2) = ssym;
+						addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+						((uint32_t *)addr)[0] = MODINFO_METADATA | MODINFOMD_ESYM;
+						((uint32_t *)addr)[1] = sizeof esym;
+						*(Elf_Addr *)(addr + sizeof(uint32_t) * 2) = esym;
+						addr += roundup(sizeof(uint32_t) * 2 + ((uint32_t *)addr)[1], sizeof(uint32_t));
+					}
+				}
+			}
+		}
+		i++;
+	}
+	r += sizeof(uint32_t) * 2;
+	if(addr) memset(addr, 0, sizeof(uint32_t) * 2);
+	return r;
+}
+
+// Prepare bootinfo.bi_modulep from the current image and multiboot modules if any
+static int init_multiboot_modules(int addr) {
+	size_t module_len = fill_module_info_from_multiboot(NULL);
+	int page = addr;
+	do {
+		pmap_kenter(page + KERNBASE, page);
+		page += PAGE_SIZE;
+	} while(page < addr + module_len);
+	bootinfo.bi_modulep = addr;
+	fill_module_info_from_multiboot((caddr_t)(addr + KERNBASE));
+	return page - addr;
+}
+#endif	/* MULTIBOOT */
+
 #ifdef XEN
 #define MTOPSIZE (1<<(14 + PAGE_SHIFT))
 
@@ -3182,6 +3473,15 @@
 	pc98_init_dmac();
 #endif
 
+#ifdef MULTIBOOT
+	if(multiboot_env) {
+		pmap_kenter(first + KERNBASE, first);
+		parse_kernel_command_line(multiboot_cmdline,
+			(char *)(first + KERNBASE), PAGE_SIZE);
+		first += PAGE_SIZE;
+		first += init_multiboot_modules(first);
+	}
+#endif
 	metadata_missing = 0;
 	if (bootinfo.bi_modulep) {
 		preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE;
@@ -3190,10 +3490,18 @@
 		metadata_missing = 1;
 	}
 
-	if (bootinfo.bi_envp)
-		init_static_kenv((caddr_t)bootinfo.bi_envp + KERNBASE, 0);
-	else
-		init_static_kenv(NULL, 0);
+	/* Static environment is already initialized in
+	 * parse_kernel_command_line if the kernel is loaded by a muiltboot
+	 * boot loader. */
+#ifdef MULTIBOOT
+	if(!multiboot_env) {
+#endif
+		init_static_kenv(bootinfo.bi_envp ?
+			(caddr_t)bootinfo.bi_envp + KERNBASE : NULL,
+			0);
+#ifdef MULTIBOOT
+	}
+#endif
 
 #ifndef XEN
 	identify_hypervisor();
@@ -4188,3 +4496,17 @@
 }
 
 #endif /* KDB */
+
+#ifdef MULTIBOOT
+/* Called from locore.s, before paging */
+void get_kernend_from_multiboot_mods(const struct multiboot_module *mbmod, size_t count) {
+	struct bootinfo *bi = (struct bootinfo *)((char *)&bootinfo - KERNBASE);
+	while(count > 0) {
+		if(bi->bi_kernend < mbmod->mod_end) {
+			bi->bi_kernend = roundup(mbmod->mod_end, PAGE_SIZE);
+		}
+		mbmod++;
+		count--;
+	}
+}
+#endif
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/i386/include/md_var.h freebsd-10.4/sys/i386/include/md_var.h
--- /var/archive3/public/freebsd-releng-10.4-src/sys/i386/include/md_var.h	2017-09-29 08:20:02.000000000 +0800
+++ freebsd-10.4/sys/i386/include/md_var.h	2019-08-17 23:55:16.562247975 +0800
@@ -85,6 +85,9 @@
 extern	int	_ucodesel;
 extern	int	use_xsave;
 extern	uint64_t xsave_mask;
+#ifdef MULTIBOOT
+extern	int	ignore_multiboot_memory_size;
+#endif
 
 typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
 struct	pcb;
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/i386/include/multiboot.h freebsd-10.4/sys/i386/include/multiboot.h
--- /var/archive3/public/freebsd-releng-10.4-src/sys/i386/include/multiboot.h	1970-01-01 08:00:00.000000000 +0800
+++ freebsd-10.4/sys/i386/include/multiboot.h	2019-08-17 23:55:16.562247975 +0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 Rivoreo
+ *
+ * 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.
+ */
+
+#ifndef _MACHINE_MULTIBOOT_H_
+#define _MACHINE_MULTIBOOT_H_
+
+struct multiboot_module {
+	uint32_t mod_start;
+	uint32_t mod_end;
+	uint32_t cmdline;
+	uint32_t pad;
+};
+
+#ifdef _KERNEL
+extern uint32_t multiboot_mem_lower;
+extern uint32_t multiboot_mem_upper;
+extern void *multiboot_env;
+extern char multiboot_cmdline[];
+extern struct {
+	uint32_t count;
+	struct multiboot_module *address;
+} multiboot_mods;
+#endif
+
+#endif
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/kern/init_main.c freebsd-10.4/sys/kern/init_main.c
--- /var/archive3/public/freebsd-releng-10.4-src/sys/kern/init_main.c	2017-09-29 08:19:46.000000000 +0800
+++ freebsd-10.4/sys/kern/init_main.c	2019-08-17 23:55:16.563246286 +0800
@@ -46,6 +46,7 @@
 
 #include "opt_ddb.h"
 #include "opt_init_path.h"
+#include "opt_multiboot.h"
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -76,7 +77,10 @@
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/cpuset.h>
-
+#ifdef MULTIBOOT
+#include <sys/multiboot.h>
+#endif
+#include <machine/md_var.h>
 #include <machine/cpu.h>
 
 #include <security/audit/audit.h>
@@ -120,6 +124,158 @@
 #endif
 
 /*
+ * List of paths to try when searching for "init".
+ */
+static char init_path[MAXPATHLEN] =
+#ifdef	INIT_PATH
+    __XSTRING(INIT_PATH);
+#else
+    "/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init";
+#endif
+SYSCTL_STRING(_kern, OID_AUTO, init_path, CTLFLAG_RD, init_path, 0,
+	"Path used to search the init process");
+
+#ifdef MULTIBOOT
+// Prase kernel command line to fill boothowto and static kernel environment
+// Usage: kernel [-acCdDghmprsv] [-i <init-path>] [-e <env>] [<env>] [...]
+void parse_kernel_command_line(const char *command_line, char *buffer, size_t buffer_size) {
+	int argc = 0;
+	char *argv[64];
+	char *p = buffer;
+	unsigned int i = 0, j = 0;
+	int qm = 0;
+	while(j < buffer_size - 1) {
+		char c = command_line[i];
+		switch(c) {
+			case '\\':
+				c = buffer[j++] = command_line[++i];
+				break;
+			case '\'':
+			case '"':
+				if(qm == c) qm = 0;
+				else if(!qm) qm = c;
+				else buffer[j++] = c;
+				break;
+			case ' ':
+			case '	':
+			case '\n':
+				if(qm) {
+					buffer[j++] = c;
+				} else {
+					buffer[j++] = 0;
+					if(argc >= sizeof argv / sizeof *argv - 2) {
+						// Stop parsing!
+						c = 0;
+						break;
+					}
+					argv[argc++] = p;
+					p = buffer + i + 1;
+				}
+				break;
+			default:
+				buffer[j++] = c;
+				break;
+		}
+		if(!c) {
+			argv[argc++] = p;
+			break;
+		}
+		i++;
+	}
+	argv[argc] = NULL;
+
+	if(*argv[0] == '-' || strchr(argv[0], '=')) {
+		i = strchr(argv[0], '/') ? 1 : 0;
+	} else {
+		strcpy(kernelname, argv[0]);
+		i = 1;
+	}
+	p = buffer;
+	while(i < argc) {
+		if(argv[i][0] == '-') {
+			const char *o = argv[i];
+			while(*++o) switch(*o) {
+				case 'a':
+					boothowto |= RB_ASKNAME;
+					break;
+				case 'c':
+#ifdef RB_CONFIG
+					boothowto |= RB_CONFIG;
+#endif
+					break;
+				case 'C':
+					boothowto |= RB_CDROM;
+					break;
+				case 'd':
+					boothowto |= RB_KDB;
+					break;
+				case 'D':
+					boothowto |= RB_MULTIPLE;
+					break;
+				case 'e':
+					if(!argv[++i]) goto next_outer_loop;
+				try_putenv:
+					{
+						const char *e = strchr(argv[i], '=');
+						if(e && (!(boothowto & RB_INITNAME) || e - argv[i] != 9 || strncmp(argv[i], "init_path", 9))) {
+							size_t len = strlen(argv[i]) + 1;
+							memmove(p, argv[i], len);
+							p += len;
+						}
+					}
+					goto next_outer_loop;
+				case 'g':
+					boothowto |= RB_GDB;
+					break;
+				case 'h':
+					boothowto |= RB_SERIAL;
+					break;
+				case 'i':
+					if(!argv[++i]) goto next_outer_loop;
+					strlcpy(init_path, argv[i], sizeof init_path);
+					boothowto |= RB_INITNAME;
+					goto next_outer_loop;
+				case 'm':
+					boothowto |= RB_MUTE;
+					break;
+#if defined __i386__ && defined MULTIBOOT
+				case 'M':
+					ignore_multiboot_memory_size = 1;
+					break;
+#endif
+				case 'p':
+					boothowto |= RB_PAUSE;
+					break;
+				case 'r':
+					boothowto |= RB_DFLTROOT;
+					break;
+				case 's':
+					boothowto |= RB_SINGLE;
+					break;
+#if 0
+				case 'S':
+					goto next_outer_loop;
+#endif
+				case 'v':
+					boothowto |= RB_VERBOSE;
+					break;
+			}
+		} else {
+			goto try_putenv;
+		}
+next_outer_loop:
+		i++;
+	}
+	*p = 0;
+//#ifdef __i386__
+//	bootinfo.bi_envp = (uint32_t)(buffer - KERNBASE);
+//#else
+	init_static_kenv(buffer, 0);
+//#endif
+}
+#endif	/* MULTIBOOT */
+
+/*
  * This ensures that there is at least one entry so that the sysinit_set
  * symbol is not undefined.  A sybsystem ID of SI_SUB_DUMMY is never
  * executed.
@@ -668,18 +824,6 @@
  */
 
 /*
- * List of paths to try when searching for "init".
- */
-static char init_path[MAXPATHLEN] =
-#ifdef	INIT_PATH
-    __XSTRING(INIT_PATH);
-#else
-    "/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init";
-#endif
-SYSCTL_STRING(_kern, OID_AUTO, init_path, CTLFLAG_RD, init_path, 0,
-	"Path used to search the init process");
-
-/*
  * Shutdown timeout of init(8).
  * Unused within kernel, but used to control init(8), hence do not remove.
  */
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/sys/multiboot.h freebsd-10.4/sys/sys/multiboot.h
--- /var/archive3/public/freebsd-releng-10.4-src/sys/sys/multiboot.h	1970-01-01 08:00:00.000000000 +0800
+++ freebsd-10.4/sys/sys/multiboot.h	2019-08-17 23:55:16.564254855 +0800
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 Rivoreo
+ *
+ * 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.
+ */
+
+#ifndef _SYS_MULTIBOOT_H_
+#define _SYS_MULTIBOOT_H_
+
+#define MULTIBOOT_HEADER_MAGIC 0x1badb002
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
+#define MULTIBOOT_PAGE_ALIGN (1)
+#define MULTIBOOT_MEMORY_INFO (1 << 1)
+#define MULTIBOOT_VIDEO_MODE (1 << 2)
+#define MI_FLAG_MEMORY (1)
+#define MI_FLAG_BOOTDEV (1 << 1)
+#define MI_FLAG_CMDLINE (1 << 2)
+#define MI_FLAG_MODS (1 << 3)
+#define MI_FLAG_AOUT_SYMS (1 << 4)
+#define MI_FLAG_ELF_SHDR (1 << 5)
+#define MI_FLAG_MMAP (1 << 6)
+#define MI_FLAG_DRIVES (1 << 7)
+#define MI_FLAG_CONFIG_TABLE (1 << 8)
+#define MI_FLAG_BOOT_LOADER_NAME (1 << 9)
+#define MI_FLAG_APM_TABLE (1 << 10)
+#define MI_FLAG_VBE (1 << 11)
+#define MI_FLAG_FRAMEBUFFER (1 << 12)
+#define MI_MEM_LOWER 0x4
+#define MI_MEM_UPPER 0x8
+#define MI_CMDLINE 0x10
+#define MI_MODS_COUNT 0x14
+#define MI_MODS_ADDR 0x18
+#define MI_MMAP_LENGTH 0x2c
+#define MI_MMAP_ADDR 0x2e
+#define MI_BOOT_LOADER_NAME 0x40
+#define MI_CMDLINE_MAX 0x1000
+
+#endif
diff -ru --exclude-from freebsd-src-diff-exclude-names --new-file /var/archive3/public/freebsd-releng-10.4-src/sys/sys/systm.h freebsd-10.4/sys/sys/systm.h
--- /var/archive3/public/freebsd-releng-10.4-src/sys/sys/systm.h	2017-09-29 08:19:46.000000000 +0800
+++ freebsd-10.4/sys/sys/systm.h	2019-08-17 23:55:16.564254855 +0800
@@ -235,6 +235,8 @@
 #define	HD_OMIT_HEX	(1 << 17)
 #define	HD_OMIT_CHARS	(1 << 18)
 
+void	parse_kernel_command_line(const char *, char *, size_t) __nonnull(1) __nonnull(2);
+
 #define ovbcopy(f, t, l) bcopy((f), (t), (l))
 void	bcopy(const void *from, void *to, size_t len) __nonnull(1) __nonnull(2);
 void	bzero(void *buf, size_t len) __nonnull(1);
