freebsd-src/release/tools/vmimage.subr
Muhammad Moinur Rahman 65190700cb
release/tools: Add support for building armv7 vm
Currently there is no support for generating armv7 vm images in the
release artifacts. In fact in terms of release artifacts and
architecture there is no good reason to have a vm release artifact for
armv7 as those are mostly used in SOCs or embedded boards. However
considering that developers actually do need an easy way to test armv7
with a vm running this is really important. As part of pre-commit ci for
developers this can be really helpful for the end developers.

Approved by:	cperciva, imp, re
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D43952
2024-02-19 00:49:52 +01:00

332 lines
7.7 KiB
Bash

#!/bin/sh
#
#
#
# Common functions for virtual machine image build scripts.
#
scriptdir=$(dirname $(realpath $0))
. ${scriptdir}/../../tools/boot/install-boot.sh
export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
trap "cleanup" INT QUIT TRAP ABRT TERM
# Platform-specific large-scale setup
# Most platforms use GPT, so put that as default, then special cases
PARTSCHEME=gpt
ROOTLABEL="gpt"
case "${TARGET}:${TARGET_ARCH}" in
powerpc:powerpc*)
PARTSCHEME=mbr
ROOTLABEL="ufs"
NOSWAP=yes # Can't label swap partition with MBR, so no swap
;;
esac
err() {
printf "${@}\n"
cleanup
return 1
}
cleanup() {
if [ -c "${DESTDIR}/dev/null" ]; then
umount_loop ${DESTDIR}/dev 2>/dev/null
fi
return 0
}
vm_create_base() {
mkdir -p ${DESTDIR}
return 0
}
vm_copy_base() {
# Defunct
}
vm_install_base() {
# Installs the FreeBSD userland/kernel to the virtual machine disk.
cd ${WORLDDIR} && \
make DESTDIR=${DESTDIR} \
installworld installkernel distribution || \
err "\n\nCannot install the base system to ${DESTDIR}."
# Bootstrap etcupdate(8) database.
mkdir -p ${DESTDIR}/var/db/etcupdate
etcupdate extract -B \
-M "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \
-s ${WORLDDIR} -d ${DESTDIR}/var/db/etcupdate
echo '# Custom /etc/fstab for FreeBSD VM images' \
> ${DESTDIR}/etc/fstab
if [ "${VMFS}" != zfs ]; then
echo "/dev/${ROOTLABEL}/rootfs / ${VMFS} rw 1 1" \
>> ${DESTDIR}/etc/fstab
fi
if [ -z "${NOSWAP}" ]; then
echo '/dev/gpt/swapfs none swap sw 0 0' \
>> ${DESTDIR}/etc/fstab
fi
local hostname
hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')"
echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf
if [ "${VMFS}" = zfs ]; then
echo "zfs_enable=\"YES\"" >> ${DESTDIR}/etc/rc.conf
echo "zpool_reguid=\"zroot\"" >> ${DESTDIR}/etc/rc.conf
echo "zpool_upgrade=\"zroot\"" >> ${DESTDIR}/etc/rc.conf
fi
if ! [ -z "${QEMUSTATIC}" ]; then
export EMULATOR=/qemu
cp ${QEMUSTATIC} ${DESTDIR}/${EMULATOR}
fi
mkdir -p ${DESTDIR}/dev
mount -t devfs devfs ${DESTDIR}/dev
chroot ${DESTDIR} ${EMULATOR} /usr/bin/newaliases
chroot ${DESTDIR} ${EMULATOR} /bin/sh /etc/rc.d/ldconfig forcestart
umount_loop ${DESTDIR}/dev
cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf
if [ "${VMFS}" = zfs ]; then
echo "kern.geom.label.disk_ident.enable=0" >> ${DESTDIR}/boot/loader.conf
echo "zfs_load=YES" >> ${DESTDIR}/boot/loader.conf
fi
return 0
}
vm_extra_install_base() {
# Prototype. When overridden, runs extra post-installworld commands
# as needed, based on the target virtual machine image or cloud
# provider image target.
return 0
}
vm_extra_enable_services() {
if [ ! -z "${VM_RC_LIST}" ]; then
for _rcvar in ${VM_RC_LIST}; do
echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf
done
fi
if [ -z "${VMCONFIG}" -o -c "${VMCONFIG}" ]; then
echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> \
${DESTDIR}/etc/rc.conf
# Expand the filesystem to fill the disk.
echo 'growfs_enable="YES"' >> ${DESTDIR}/etc/rc.conf
touch ${DESTDIR}/firstboot
fi
return 0
}
vm_extra_install_packages() {
if [ -z "${VM_EXTRA_PACKAGES}" ]; then
return 0
fi
mkdir -p ${DESTDIR}/dev
mount -t devfs devfs ${DESTDIR}/dev
chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
/usr/sbin/pkg bootstrap -y
for p in ${VM_EXTRA_PACKAGES}; do
chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
/usr/sbin/pkg install -y ${p}
done
umount_loop ${DESTDIR}/dev
return 0
}
vm_extra_install_ports() {
# Prototype. When overridden, installs additional ports within the
# virtual machine environment.
return 0
}
vm_extra_pre_umount() {
# Prototype. When overridden, performs additional tasks within the
# virtual machine environment prior to unmounting the filesystem.
# Note: When overriding this function, removing resolv.conf in the
# disk image must be included.
if ! [ -z "${QEMUSTATIC}" ]; then
rm -f ${DESTDIR}/${EMULATOR}
fi
rm -f ${DESTDIR}/etc/resolv.conf
return 0
}
vm_extra_pkg_rmcache() {
if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then
chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
/usr/local/sbin/pkg clean -y -a
fi
return 0
}
buildfs() {
local md tmppool
case "${VMFS}" in
ufs)
makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
${VMBASE} ${DESTDIR}
;;
zfs)
makefs -t zfs ${MAKEFSARGS} \
-o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \
-o fs=zroot\;mountpoint=none \
-o fs=zroot/ROOT\;mountpoint=none \
-o fs=zroot/ROOT/default\;mountpoint=/ \
-o fs=zroot/home\;mountpoint=/home \
-o fs=zroot/tmp\;mountpoint=/tmp\;exec=on\;setuid=off \
-o fs=zroot/usr\;mountpoint=/usr\;canmount=off \
-o fs=zroot/usr/ports\;setuid=off \
-o fs=zroot/usr/src \
-o fs=zroot/usr/obj \
-o fs=zroot/var\;mountpoint=/var\;canmount=off \
-o fs=zroot/var/audit\;setuid=off\;exec=off \
-o fs=zroot/var/crash\;setuid=off\;exec=off \
-o fs=zroot/var/log\;setuid=off\;exec=off \
-o fs=zroot/var/mail\;atime=on \
-o fs=zroot/var/tmp\;setuid=off \
${VMBASE} ${DESTDIR}
;;
*)
echo "Unexpected VMFS value '${VMFS}'"
exit 1
;;
esac
}
umount_loop() {
DIR=$1
i=0
sync
while ! umount ${DIR}; do
i=$(( $i + 1 ))
if [ $i -ge 10 ]; then
# This should never happen. But, it has happened.
echo "Cannot umount(8) ${DIR}"
echo "Something has gone horribly wrong."
return 1
fi
sleep 1
done
return 0
}
vm_create_disk() {
local BOOTFILES BOOTPARTSOFFSET FSPARTTYPE X86GPTBOOTFILE
if [ -z "${NOSWAP}" ]; then
SWAPOPT="-p freebsd-swap/swapfs::${SWAPSIZE}"
fi
if [ -n "${VM_BOOTPARTSOFFSET}" ]; then
BOOTPARTSOFFSET=":${VM_BOOTPARTSOFFSET}"
fi
case "${VMFS}" in
ufs)
FSPARTTYPE=freebsd-ufs
X86GPTBOOTFILE=i386/gptboot/gptboot
;;
zfs)
FSPARTTYPE=freebsd-zfs
X86GPTBOOTFILE=i386/gptzfsboot/gptzfsboot
;;
*)
echo "Unexpected VMFS value '${VMFS}'"
return 1
;;
esac
echo "Creating image... Please wait."
echo
BOOTFILES="$(env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \
WITH_UNIFIED_OBJDIR=yes \
make -C ${WORLDDIR}/stand -V .OBJDIR)"
BOOTFILES="$(realpath ${BOOTFILES})"
MAKEFSARGS="-s ${VMSIZE}"
case "${TARGET}:${TARGET_ARCH}" in
amd64:amd64 | i386:i386)
ESP=yes
BOOTPARTS="-b ${BOOTFILES}/i386/pmbr/pmbr \
-p freebsd-boot/bootfs:=${BOOTFILES}/${X86GPTBOOTFILE}${BOOTPARTSOFFSET}"
ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}"
MAKEFSARGS="$MAKEFSARGS -B little"
;;
arm:armv7 | arm64:aarch64 | riscv:riscv64*)
ESP=yes
BOOTPARTS=
ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}"
MAKEFSARGS="$MAKEFSARGS -B little"
;;
powerpc:powerpc*)
ESP=no
BOOTPARTS="-p prepboot:=${BOOTFILES}/powerpc/boot1.chrp/boot1.elf -a 1"
ROOTFSPART="-p freebsd:=${VMBASE}"
if [ ${TARGET_ARCH} = powerpc64le ]; then
MAKEFSARGS="$MAKEFSARGS -B little"
else
MAKEFSARGS="$MAKEFSARGS -B big"
fi
;;
*)
echo "vmimage.subr: unsupported target '${TARGET}:${TARGET_ARCH}'" >&2
exit 1
;;
esac
if [ ${ESP} = "yes" ]; then
# Create an ESP
espfilename=$(mktemp /tmp/efiboot.XXXXXX)
make_esp_file ${espfilename} ${fat32min} ${BOOTFILES}/efi/loader_lua/loader_lua.efi
BOOTPARTS="${BOOTPARTS} -p efi/efiesp:=${espfilename}"
# Add this to fstab
mkdir -p ${DESTDIR}/boot/efi
echo "/dev/${ROOTLABEL}/efiesp /boot/efi msdosfs rw 2 2" \
>> ${DESTDIR}/etc/fstab
fi
echo "Building filesystem... Please wait."
buildfs
echo "Building final disk image... Please wait."
mkimg -s ${PARTSCHEME} -f ${VMFORMAT} \
${BOOTPARTS} \
${SWAPOPT} \
${ROOTFSPART} \
-o ${VMIMAGE}
echo "Disk image ${VMIMAGE} created."
if [ ${ESP} = "yes" ]; then
rm ${espfilename}
fi
return 0
}
vm_extra_create_disk() {
return 0
}