Last active
October 6, 2020 17:52
-
-
Save pdxjohnny/a0dc3a58b4651dc3761bee65a198a80d to your computer and use it in GitHub Desktop.
Use bzImage of built kernel with fedora container
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# DESCRIPTION | |
# | |
# Run a virtual machine using the bzImage of a compiled Linux kernel | |
# with the base fedora container image as the file system. | |
# | |
# ENVIRONMENT VARIABLES | |
# | |
# This section details environment variables this script uses and shows | |
# an example for each of how you'd override the default using `export`. | |
# | |
# BZ_IMAGE (default: "${HOME}/linux/arch/x86/boot/bzImage") | |
# Build a kernel or give the path to a built bzImage via the BZ_IMAGE | |
# environment variable. | |
# | |
# $ export BZ_IMAGE="${HOME}/linux/arch/x86/boot/bzImage" | |
# | |
# QEMU (default: "qemu-system-x86_64") | |
# Path to the qemu binary that should be used. Do not set this to use the | |
# on installed within your PATH. | |
# | |
# $ export QEMU="${HOME}/qemu/build/x86_64-softmmu/qemu-system-x86_64" | |
# | |
# VM_DISK (default: "~/vm/image.qcow2") | |
# Path to the virtual disk image we'll be creating to store the guest file | |
# system. | |
# | |
# $ export VM_DISK="${HOME}/my-guest-image.qcow2" | |
# | |
# VM_DEV (default: "/dev/nbd0") | |
# Path to the virtual disk image we'll be creating to store the guest file | |
# system. | |
# | |
# $ export VM_DISK="${HOME}/my-guest-image.qcow2" | |
# | |
# CHROOT (default: "~/vm/chroot") | |
# Path to the directory we'll use to access the guest file system from the | |
# host when the guest is not running. | |
# | |
# $ export CHROOT="${HOME}/my-guest-fs" | |
# | |
# CMDLINE (default: "console=ttyS0 root=/dev/sda3 rw resume=/dev/sda2 init=/usr/bin/init.sh") | |
# The kernel command line for the kernel we're going to run. | |
# | |
# $ export CMDLINE="nokaslr console=ttyS0 root=/dev/sda3 rw resume=/dev/sda2 init=/usr/bin/init.sh" | |
# | |
# DOWNLOAD | |
# | |
# $ curl -o run-vm.sh -fSL https://gist.github.com/pdxjohnny/a0dc3a58b4651dc3761bee65a198a80d/raw/da2f456c9ecbb56bf84ee30c8c83a2762e86fb43/run-vm.sh | |
# $ echo "eb5c49fb0aff6b3293ad6f4bd8c7a9c32df97f40d3c8c4fe404b72c1e9c283b44e714be493ce88b5f22e5bb717b8f71d run-vm.sh" | sha384sum -c - | |
# | |
# USAGE | |
# | |
# You can make the script executable or run it with bash. The script | |
# requries that the user running it be able to run the sudo command. | |
# | |
# $ chmod 755 run-vm.sh | |
# $ ./run-vm.sh | |
# | |
# $ bash run-vm.sh | |
# Echo every command in this cript to standard error before running it. | |
set -x | |
# Exit non-zero from this script if we encounter any errors | |
set -e | |
# Virtual machine disk image where virtual machine filesystem is stored | |
VM_DISK=${VM_DISK:-"${HOME}/vm/image.qcow2"} | |
# Block device we use as an intermediary to mount the guest filesystem from host | |
VM_DEV=${VM_DEV:-"/dev/nbd0"} | |
# The directory where we mount the guest filesystem on the host for access and | |
# modification when not in use by the guest | |
CHROOT=${CHROOT:-"${HOME}/vm/chroot"} | |
# Linux kernel bzImage file to boot from | |
BZ_IMAGE=${BZ_IMAGE:-"${HOME}/linux/arch/x86/boot/bzImage"} | |
# Linux kernel command line | |
CMDLINE=${CMDLINE:-"console=ttyS0 root=/dev/sda3 rw resume=/dev/sda2 init=/usr/bin/init.sh"} | |
# Location of qemu binary to use | |
QEMU=${QEMU:-"qemu-system-x86_64"} | |
# Load the network block device kernel module | |
sudo modprobe nbd max_part=8 | |
# Unmount the virtual disk image if it is currently mounted | |
sudo umount -R "${CHROOT}" || echo "Image was not mounted at ${CHROOT}" | |
# Disconnect the network block device | |
sudo qemu-nbd --disconnect "${VM_DEV}" || echo "Image was not connected as nbd" | |
mount_image() { | |
sudo qemu-nbd --connect="${VM_DEV}" "${VM_DISK}" | |
sudo mount "${VM_DEV}p3" "${CHROOT}" | |
sudo mount "${VM_DEV}p1" "${CHROOT}/boot" | |
} | |
unmount_image() { | |
sudo sync | |
sudo umount -R "${CHROOT}" | |
sudo qemu-nbd --disconnect "${VM_DEV}" | |
} | |
# Check if the block device we are going to use to mount the virtual disk image | |
# already exists | |
if [ -b "${VM_DEV}" ]; then | |
echo "VM_DEV already exists: ${VM_DEV}" >&2 | |
# exit 1 | |
fi | |
# Create the virtual disk image and populate it if it does not exist | |
if [ ! -f "${VM_DISK}" ]; then | |
mkdir -p "${CHROOT}" | |
mkdir -p "$(dirname ${VM_DISK})" | |
# Create the virtual disk image | |
qemu-img create -f qcow2 "${VM_DISK}" 20G | |
# Use the QEMU guest utils network block device utility to mount the virtual | |
# disk image as the $VM_DEV device | |
sudo qemu-nbd --connect="${VM_DEV}" "${VM_DISK}" | |
# Partition the block device | |
sudo parted "${VM_DEV}" << 'EOF' | |
mklabel gpt | |
mkpart primary fat32 1MiB 261MiB | |
set 1 esp on | |
mkpart primary linux-swap 261MiB 10491MiB | |
mkpart primary ext4 10491MiB 100% | |
EOF | |
# EFI partition | |
sudo mkfs.fat -F32 "${VM_DEV}p1" | |
# swap space | |
sudo mkswap "${VM_DEV}p2" | |
# Linux root partition | |
sudo mkfs.ext4 "${VM_DEV}p3" | |
sudo mount "${VM_DEV}p3" "${CHROOT}" | |
# Boot partiion | |
sudo mkdir "${CHROOT}/boot" | |
sudo mount "${VM_DEV}p1" "${CHROOT}/boot" | |
# Directory for docker image extraction utilities | |
utildir="$(mktemp -d)" | |
export PATH="${utildir}:${PATH}" | |
# https://github.com/genuinetools/reg | |
reg="${utildir}/reg" | |
export REG_SHA256="ade837fc5224acd8c34732bf54a94f579b47851cc6a7fd5899a98386b782e228" | |
curl -fSL "https://github.com/genuinetools/reg/releases/download/v0.16.1/reg-linux-amd64" \ | |
-o "${reg}" | |
echo "${REG_SHA256} ${reg}" | sha256sum -c - | |
chmod a+x "${reg}" | |
# Image to download | |
IMAGE="fedora" | |
# Registry to download from | |
REGISTRY="registry.fedoraproject.org" | |
# SHA digest of image's top layer | |
DIGEST=$(reg manifest "${REGISTRY}/${IMAGE}" \ | |
| grep digest \ | |
| head -n 2 \ | |
| tail -n 1 \ | |
| sed -e 's/.*sha/sha/' -e 's/"//g') | |
# Download container and extract it to chroot | |
reg layer "${REGISTRY}/${IMAGE}@${DIGEST}" | sudo tar xz -C "${CHROOT}" | |
# Put our init script in the guest file system | |
# Find the path to bash to use as the interpreter | |
BASH_PATH=$(cd ${CHROOT} && find . -name bash | grep bin/ | head -n 1) | |
echo "#!${BASH_PATH:1}" | sudo tee "${CHROOT}/usr/bin/init.sh" | |
# Write out the rest of the script | |
sudo tee -a "${CHROOT}/usr/bin/init.sh" <<'EOF' | |
set -xe | |
if [[ -f /etc/environment ]]; then | |
source /etc/environment | |
fi | |
export PATH="/usr/sbin:/usr/bin:${PATH}" | |
if [[ ! -d /sys/firmware ]]; then | |
mkdir -p /sys | |
mount -t sysfs sysfs /sys -n | |
if [ -d /sys/firmware/efi/efivars ]; then | |
mount -t efivarfs efivarfs /sys/firmware/efi/efivars | |
fi | |
mkdir -p /proc | |
mount -t proc proc /proc -n | |
mkdir -p /run | |
mount -t tmpfs tmpfs /run -n | |
ulimit -u unlimited | |
/usr/sbin/swapon /dev/sda2 | |
# Need vfat loaded to mount boot partition | |
# mount /dev/sda1 /boot | |
fi | |
cat /proc/cmdline | |
EOF | |
# Execute bash as the last thing in the init script | |
echo "exec bash" | sudo tee -a "${CHROOT}/usr/bin/init.sh" | |
# Make the script executable | |
sudo chmod 755 "${CHROOT}/usr/bin/init.sh" | |
# Consider doing something like this to add the vfat module to the guest image | |
# https://gist.github.com/pdxjohnny/aed9d495e606a816f4dfa51db6c2ebd4#install-kernel-to-chroot | |
# export INSTALL_MOD_PATH="${CHROOT}" | |
# export INSTALL_PATH=${INSTALL_MOD_PATH}/boot | |
# cd /path/to/kernel/build/dir | |
# make -j $(($(nproc)*4)) | |
# make install | |
# make modules_install -j $(($(nproc)*4)) | |
# Remove util dir | |
rm -rf "${utildir}" | |
# Unmount the virtual disk image so the virtual machine can use it | |
unmount_image | |
fi | |
# Mount the guest file system on the host when we exit the guest | |
trap mount_image EXIT | |
# Run the guest | |
"${QEMU}" \ | |
-smp cpus=2 \ | |
-m 8192M \ | |
-kernel "${BZ_IMAGE}" \ | |
-append "${CMDLINE}" \ | |
-enable-kvm \ | |
-nographic \ | |
-cpu host \ | |
-drive file="${VM_DISK}",index=0,media=disk,format=qcow2 $@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment