Merge pull request #329 from marineam/grub

Switch to GRUB for both BIOS and UEFI booting
This commit is contained in:
Michael Marineau 2014-09-07 10:00:46 -07:00
commit 77f164f1a0
6 changed files with 162 additions and 67 deletions

View File

@ -204,6 +204,7 @@ finish_image() {
local disk_layout="$2"
local root_fs_dir="$3"
local image_contents="$4"
local install_grub=0
local disk_img="${BUILD_DIR}/${image_name}"
@ -220,10 +221,10 @@ finish_image() {
# Only configure bootloaders if there is a boot partition
if mountpoint -q "${root_fs_dir}"/boot; then
install_grub=1
${BUILD_LIBRARY_DIR}/configure_bootloaders.sh \
--arch=${ARCH} \
--disk_layout="${disk_layout}" \
--disk_image="${disk_img}" \
--boot_dir="${root_fs_dir}"/usr/boot \
--esp_dir="${root_fs_dir}"/boot \
--boot_args="${FLAGS_boot_args}"
@ -249,4 +250,13 @@ finish_image() {
rm -rf "${BUILD_DIR}"/configroot
cleanup_mounts "${root_fs_dir}"
trap - EXIT
# This script must mount the ESP partition differently, so run it after unmount
if [[ "${install_grub}" -eq 1 ]]; then
local target
for target in i386-pc x86_64-efi; do
${BUILD_LIBRARY_DIR}/grub_install.sh \
--target="${target}" --disk_image="${disk_img}"
done
fi
}

View File

@ -24,7 +24,6 @@ DEFINE_string boot_args "" \
"Additional boot arguments to pass to the commandline (Default: '')"
DEFINE_string disk_layout "base" \
"The disk layout type to use for this image."
DEFINE_string disk_image "" "The disk image."
# Parse flags
FLAGS "$@" || exit 1
@ -52,6 +51,7 @@ SYSLINUX_DIR="${FLAGS_boot_dir}/syslinux"
# Build configuration files for pygrub/pvgrub
configure_pvgrub() {
info "Installing legacy PV-GRUB configuration"
sudo mkdir -p "${GRUB_DIR}"
# Add hvc0 for hypervisors
@ -68,18 +68,21 @@ title CoreOS B Root
root (hd0,0)
kernel /syslinux/vmlinuz.B ${grub_args} ${slot_b_args}
EOF
info "Emitted ${GRUB_DIR}/menu.lst.A"
sudo_clobber "${GRUB_DIR}/menu.lst.B" <<EOF
default 1
$(< "${GRUB_DIR}/menu.lst.A")
EOF
sudo_append "${GRUB_DIR}/menu.lst.B" <"${GRUB_DIR}/menu.lst.A"
info "Emitted ${GRUB_DIR}/menu.lst.B"
sudo cp ${GRUB_DIR}/menu.lst.A ${GRUB_DIR}/menu.lst
sudo cp "${GRUB_DIR}/menu.lst.A" "${GRUB_DIR}/menu.lst"
# menu.lst needs to go under boot/grub so pvgrub can find it reliably
sudo mkdir -p "${FLAGS_esp_dir}/boot/grub"
sudo cp "${GRUB_DIR}/menu.lst" "${FLAGS_esp_dir}/boot/grub"
}
# Build configuration files for syslinux
configure_syslinux() {
info "Installing legacy SYSLINUX configuration"
sudo mkdir -p "${SYSLINUX_DIR}"
# Add ttyS0 as a secondary console, useful for qemu -nographic
@ -91,7 +94,6 @@ configure_syslinux() {
fi
sudo_clobber "${SYSLINUX_DIR}/syslinux.cfg" <<EOF
SERIAL 0 115200
PROMPT 1
# display boot: prompt for a half second
TIMEOUT 5
@ -109,22 +111,10 @@ include /syslinux/root.A.cfg
# coreos.B
include /syslinux/root.B.cfg
EOF
info "Emitted ${SYSLINUX_DIR}/syslinux.cfg"
sudo_clobber "${SYSLINUX_DIR}/default.cfg" <<EOF
DEFAULT boot_kernel
EOF
info "Emitted ${SYSLINUX_DIR}/default.cfg"
sudo_clobber "${SYSLINUX_DIR}/default.cfg.A" <<EOF
DEFAULT coreos.A
EOF
info "Emitted ${SYSLINUX_DIR}/default.cfg.A"
sudo_clobber "${SYSLINUX_DIR}/default.cfg.B" <<EOF
DEFAULT coreos.B
EOF
info "Emitted ${SYSLINUX_DIR}/default.cfg.B"
sudo_clobber "${SYSLINUX_DIR}/default.cfg" <<<"DEFAULT boot_kernel"
sudo_clobber "${SYSLINUX_DIR}/default.cfg.A" <<<"DEFAULT coreos.A"
sudo_clobber "${SYSLINUX_DIR}/default.cfg.B" <<<"DEFAULT coreos.B"
# Different files are used so that the updater can only touch the file it
# needs to for a given change. This will minimize any potential accidental
@ -135,7 +125,6 @@ label boot_kernel
kernel vmlinuz-boot_kernel
append ${syslinux_args} ${gptprio_args}
EOF
info "Emitted ${SYSLINUX_DIR}/boot_kernel.cfg"
sudo_clobber "${SYSLINUX_DIR}/root.A.cfg" <<EOF
label coreos.A
@ -143,7 +132,6 @@ label coreos.A
kernel vmlinuz.A
append ${syslinux_args} ${slot_a_args}
EOF
info "Emitted ${SYSLINUX_DIR}/root.A.cfg"
sudo_clobber "${SYSLINUX_DIR}/root.B.cfg" <<EOF
label coreos.B
@ -151,25 +139,9 @@ label coreos.B
kernel vmlinuz.B
append ${syslinux_args} ${slot_b_args}
EOF
info "Emitted ${SYSLINUX_DIR}/root.B.cfg"
}
# Copy configurations to the ESP, this is what is actually used to boot
copy_to_esp() {
if ! mountpoint -q "${FLAGS_esp_dir}"; then
die "${FLAGS_esp_dir} is not a mount point."
fi
sudo mkdir -p "${FLAGS_esp_dir}"/{syslinux,boot/grub,EFI/boot}
sudo cp -r "${GRUB_DIR}/." "${FLAGS_esp_dir}/boot/grub"
sudo cp -r "${SYSLINUX_DIR}/." "${FLAGS_esp_dir}/syslinux"
# Install UEFI bootloader
sudo cp /usr/share/syslinux/efi64/ldlinux.e64 \
"${FLAGS_esp_dir}/EFI/boot/ldlinux.e64"
sudo cp /usr/share/syslinux/efi64/syslinux.efi \
"${FLAGS_esp_dir}/EFI/boot/bootx64.efi"
# Stage all kernels with the only one we built.
for kernel in syslinux/{vmlinuz-boot_kernel,vmlinuz.A,vmlinuz.B}
do
@ -177,28 +149,11 @@ copy_to_esp() {
done
}
# Install GRUB2 to the disk image
install_grub() {
# Install under boot/coreos/grub instead of boot/grub to prevent
# more recent versions of pygrub that attempt to read grub2 configs
# from finding it, pygrub and pvgrub must stick with using menu.lst
sudo mkdir -p "${FLAGS_esp_dir}/coreos/grub"
sudo grub-install \
--target=i386-pc \
--modules=part_gpt \
--boot-directory="${FLAGS_esp_dir}/coreos" \
"${FLAGS_disk_image}"
sudo cp "${BUILD_LIBRARY_DIR}/grub.cfg" \
"${FLAGS_esp_dir}/coreos/grub/grub.cfg"
}
[[ -d "${FLAGS_esp_dir}" ]] || die_notrace "--esp_dir is required"
[[ -f "${FLAGS_disk_image}" ]] || die_notrace "--disk_image is required"
if [[ "${FLAGS_arch}" = "x86" || "${FLAGS_arch}" = "amd64" ]]; then
configure_pvgrub
configure_syslinux
copy_to_esp
else
error "No bootloader configuration for ${FLAGS_arch}"
fi

View File

@ -13,7 +13,7 @@
"blocks":"262144",
"fs_type":"vfat",
"mount":"/boot",
"features": ["syslinux"]
"features": ["hybrid"]
},
"2":{
"label":"BIOS-BOOT",

View File

@ -1,4 +1,8 @@
# Use both default console and ttyS0
# Load any and all video drivers.
# Required under UEFI to boot Linux with a working console.
insmod all_video
# Use both default text console and ttyS0
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
terminal_input console serial
terminal_output console serial
@ -6,4 +10,4 @@ terminal_output console serial
# Re-use the existing syslinux configuration
echo "Loading SYSLINUX configuration..."
insmod syslinuxcfg
syslinux_configfile -s /syslinux/syslinux.cfg
syslinux_source -s /syslinux/syslinux.cfg

127
build_library/grub_install.sh Executable file
View File

@ -0,0 +1,127 @@
#!/bin/bash
# Copyright (c) 2014 The CoreOS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Replacement script for 'grub-install' which does not detect drives
# properly when partitions are mounted via individual loopback devices.
SCRIPT_ROOT=$(readlink -f $(dirname "$0")/..)
. "${SCRIPT_ROOT}/common.sh" || exit 1
# We're invoked only by build_image, which runs in the chroot
assert_inside_chroot
# Flags.
DEFINE_string target "" \
"The GRUB target to install such as i386-pc or x86_64-efi"
DEFINE_string esp_dir "" \
"Path to EFI System partition mount point."
DEFINE_string disk_image "" \
"The disk image containing the EFI System partition."
# Parse flags
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
switch_to_strict_mode
# Our GRUB lives under coreos/grub so new pygrub versions cannot find grub.cfg
GRUB_DIR="coreos/grub/${FLAGS_target}"
# Assumes the ESP is the first partition, GRUB cannot search for it by type.
GRUB_PREFIX="(,gpt1)/coreos/grub"
# Modules required to find and read everything else from ESP
CORE_MODULES=( fat part_gpt gzio )
# Name of the core image, depends on target
CORE_NAME=
case "${FLAGS_target}" in
i386-pc)
CORE_MODULES+=( biosdisk )
CORE_NAME="core.img"
;;
x86_64-efi)
CORE_NAME="core.efi"
;;
*)
die_notrace "Unknown GRUB target ${FLAGS_target}"
;;
esac
# In order for grub-setup-bios to properly detect the layout of the disk
# image it expects a normal partitioned block device. For most of the build
# disk_util maps individual loop devices to each partition in the image so
# the kernel can automatically detach the loop devices on unmount. When
# using a single loop device with partitions there is no such cleanup.
# That's the story of why this script has all this goo for loop and mount.
STAGE_DIR=
ESP_DIR=
LOOP_DEV=
cleanup() {
if [[ -d "${STAGE_DIR}" ]]; then
rm -rf "${STAGE_DIR}"
fi
if [[ -d "${ESP_DIR}" ]]; then
if mountpoint -q "${ESP_DIR}"; then
sudo umount "${ESP_DIR}"
fi
rm -rf "${ESP_DIR}"
fi
if [[ -b "${LOOP_DEV}" ]]; then
sudo losetup --detach "${LOOP_DEV}"
fi
}
trap cleanup EXIT
STAGE_DIR=$(mktemp --directory)
mkdir -p "${STAGE_DIR}/${GRUB_DIR}"
info "Compressing modules in ${GRUB_DIR}"
for file in "/usr/lib/grub/${FLAGS_target}"/*{.lst,.mod}; do
out="${STAGE_DIR}/${GRUB_DIR}/${file##*/}"
gzip --best --stdout "${file}" > "${out}"
done
info "Generating ${GRUB_DIR}/${CORE_NAME}"
grub-mkimage \
--compression=auto \
--format "${FLAGS_target}" \
--prefix "${GRUB_PREFIX}" \
--output "${STAGE_DIR}/${GRUB_DIR}/${CORE_NAME}" \
"${CORE_MODULES[@]}"
info "Installing GRUB ${FLAGS_target} to ${FLAGS_disk_image##*/}"
LOOP_DEV=$(sudo losetup --find --show --partscan "${FLAGS_disk_image}")
ESP_DIR=$(mktemp --directory)
sudo mount -t vfat "${LOOP_DEV}p1" "${ESP_DIR}"
sudo cp -r "${STAGE_DIR}/." "${ESP_DIR}/."
# This script will get called a few times, no need to re-copy grub.cfg
if [[ ! -f "${ESP_DIR}/coreos/grub/grub.cfg" ]]; then
info "Installing grub.cfg"
sudo cp "${BUILD_LIBRARY_DIR}/grub.cfg" "${ESP_DIR}/coreos/grub/grub.cfg"
fi
# Now target specific steps to make the system bootable
case "${FLAGS_target}" in
i386-pc)
info "Installing MBR and the BIOS Boot partition."
sudo cp "/usr/lib/grub/i386-pc/boot.img" "${ESP_DIR}/${GRUB_DIR}"
sudo grub-bios-setup --device-map=/dev/null \
--directory="${ESP_DIR}/${GRUB_DIR}" "${LOOP_DEV}"
;;
x86_64-efi)
info "Installing default x86_64 UEFI bootloader."
sudo mkdir -p "${ESP_DIR}/EFI/boot"
sudo cp "${STAGE_DIR}/${GRUB_DIR}/${CORE_NAME}" \
"${ESP_DIR}/EFI/boot/bootx64.efi"
;;
esac
cleanup
trap - EXIT
command_completed

View File

@ -20,7 +20,7 @@ Options:
-c FILE Config drive as an iso or fat filesystem image.
-a FILE SSH public keys for login access. [~/.ssh/id_{dsa,rsa}.pub]
-p PORT The port on localhost to map to the VM's sshd. [2222]
-s Safe settings: single simple cpu, ide disks.
-s Safe settings: single simple cpu and no KVM.
-h this ;-)
This script is a wrapper around qemu for starting CoreOS virtual machines.
@ -131,11 +131,11 @@ fi
# Start assembling our default command line arguments
if [ "${SAFE_ARGS}" -eq 1 ]; then
disk_type="ide"
# Disable KVM, for testing things like UEFI which don't like it
set -- -machine accel=tcg "$@"
else
disk_type="virtio"
# Emulate the host CPU closely in both features and cores.
set -- -cpu host -smp "${VM_NCPUS}" "$@"
set -- -machine accel=kvm -cpu host -smp "${VM_NCPUS}" "$@"
fi
# ${CONFIG_DRIVE} or ${CONFIG_IMAGE} will be mounted in CoreOS as /media/configdrive
@ -146,11 +146,11 @@ if [ -n "${CONFIG_DRIVE}" ]; then
fi
if [ -n "${CONFIG_IMAGE}" ]; then
set -- -drive if=${disk_type},file="${CONFIG_IMAGE}" "$@"
set -- -drive if=virtio,file="${CONFIG_IMAGE}" "$@"
fi
if [ -n "${VM_IMAGE}" ]; then
set -- -drive if=${disk_type},file="${SCRIPT_DIR}/${VM_IMAGE}" "$@"
set -- -drive if=virtio,file="${SCRIPT_DIR}/${VM_IMAGE}" "$@"
fi
if [ -n "${VM_KERNEL}" ]; then
@ -173,7 +173,6 @@ fi
qemu-system-x86_64 \
-name "$VM_NAME" \
-m ${VM_MEMORY} \
-machine accel=kvm:tcg \
-net nic,vlan=0,model=virtio \
-net user,vlan=0,hostfwd=tcp::"${SSH_PORT}"-:22,hostname="${VM_NAME}" \
"$@"