Files
kata-containers/scripts/configure-hypervisor.sh
Marco Vedovati 2162b9a472 QEMU: only enable AVX2 for x86_64
AVX2 are x86 specific extensions that should only be enabled for x86_64
targets.

Fixes: #558

Signed-off-by: Marco Vedovati <mvedovati@suse.com>
2019-05-31 17:48:15 +02:00

522 lines
13 KiB
Bash
Executable File

#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#---------------------------------------------------------------------
# Description: This script is the *ONLY* place where "qemu*" build options
# should be defined.
#
# Note to maintainers:
#
# XXX: Every option group *MUST* be documented explaining why it has
# been specified.
#---------------------------------------------------------------------
script_name=${0##*/}
arch=$(uname -m)
# Array of configure options.
#
# Each element is comprised of two parts in the form:
#
# tags:option
#
# Where,
#
# - 'tags' is a comma-separated list of values which denote why
# the option is being specified.
#
# - 'option' is the hypervisor configuration option.
typeset -a qemu_options
typeset -A recognised_tags
# Prefix were kata will be installed
prefix=${PREFIX:-/usr}
recognised_tags=(
[arch]="architecture-specific"
[functionality]="required functionality"
[minimal]="specified to avoid building unnecessary elements"
[misc]="miscellaneous"
[security]="specified for security reasons"
[size]="minimise binary size"
[speed]="maximise startup speed"
)
# Display message to stderr and exit indicating script failed.
die() {
local msg="$*"
echo >&2 "$script_name: ERROR: $msg"
exit 1
}
# Display usage to stdout.
usage() {
cat <<EOT
Overview:
Display configure options required to build the specified
hypervisor.
Usage:
$script_name [options] <hypervisor-name>
Options:
-d : Dump all options along with the tags explaining why each option
is specified.
-h : Display this help.
-m : Display options one per line (includes continuation characters).
-s : Generate options to build static
Example:
$ $script_name qemu-lite
EOT
}
show_tags_header() {
local keys
local key
local value
cat <<EOT
# Recognised option tags:
#
EOT
# sort the tags
keys=${!recognised_tags[@]}
keys=$(echo "$keys" | tr ' ' '\n' | sort -u)
for key in $keys; do
value="${recognised_tags[$key]}"
printf "# %s\t%s.\n" "$key" "$value"
done
printf "#\n\n"
}
check_tag() {
local tag="$1"
local entry="$2"
[ -z "$tag" ] && die "no tag for entry '$entry'"
[ -z "$entry" ] && die "no entry for tag '$tag'"
value="${recognised_tags[$tag]}"
# each tag MUST have a description
[ -n "$value" ] && return
die "invalid tag '$tag' found for entry '$entry'"
}
check_tags() {
local tags="$1"
local entry="$2"
[ -z "$tags" ] && die "entry '$entry' doesn't have any tags"
[ -z "$entry" ] && die "no entry for tags '$tags'"
tags=$(echo "$tags" | tr ',' '\n')
for tag in $tags; do
check_tag "$tag" "$entry"
done
}
# Display an array to stdout.
#
# If 2 arguments are specified, split array across multiple lines,
# one per element with a backslash at the end of all lines except
# the last.
#
# Arguments:
#
# $1: *Name* of array variable (no leading '$'!!)
# $2: (optional) "multi" - show values across multiple lines,
# "dump" - show full hash values. Any other value results in the
# options being displayed on a single line.
show_array() {
local action="$1"
local _array=("$@")
_array=("${_array[@]:1}")
local -i size="${#_array[*]}"
local -i i=1
local entry
local tags
local elem
local suffix
local one_line="no"
[ "$action" = "dump" ] && show_tags_header
for entry in "${_array[@]}"; do
[ -z "$entry" ] && die "found empty entry"
tags=$(echo "$entry" | cut -s -d: -f1)
elem=$(echo "$entry" | cut -s -d: -f2-)
[ -z "$elem" ] && die "no option for entry '$entry'"
check_tags "$tags" "$entry"
if [ "$action" = "dump" ]; then
printf "%s\t\t%s\n" "$tags" "$elem"
elif [ "$action" = "multi" ]; then
if [ $i -eq $size ]; then
suffix=""
else
suffix=' \'
fi
printf '%s%s\n' "$elem" "$suffix"
else
one_line="yes"
echo -n "$elem "
fi
i+=1
done
[ "$one_line" = yes ] && echo
}
generate_qemu_options() {
#---------------------------------------------------------------------
# Disabled options
# bluetooth support not required
qemu_options+=(size:--disable-bluez)
# braille support not required
qemu_options+=(size:--disable-brlapi)
# Don't build documentation
qemu_options+=(minimal:--disable-docs)
# Disable GUI (graphics)
qemu_options+=(size:--disable-curses)
qemu_options+=(size:--disable-gtk)
qemu_options+=(size:--disable-opengl)
qemu_options+=(size:--disable-sdl)
qemu_options+=(size:--disable-spice)
qemu_options+=(size:--disable-vte)
# Disable graphical network access
qemu_options+=(size:--disable-vnc)
qemu_options+=(size:--disable-vnc-jpeg)
qemu_options+=(size:--disable-vnc-png)
qemu_options+=(size:--disable-vnc-sasl)
# Disable PAM authentication: it's a feature used together with VNC access
# that's not used. See QEMU commit 8953caf for more details
[ "${qemu_version_major}" -ge 4 ] && qemu_options+=(size:--disable-auth-pam)
# Disable unused filesystem support
[ "$arch" == x86_64 ] && qemu_options+=(size:--disable-fdt)
qemu_options+=(size:--disable-glusterfs)
qemu_options+=(size:--disable-libiscsi)
qemu_options+=(size:--disable-libnfs)
qemu_options+=(size:--disable-libssh2)
# Disable unused compression support
qemu_options+=(size:--disable-bzip2)
qemu_options+=(size:--disable-lzo)
qemu_options+=(size:--disable-snappy)
# Disable unused security options
qemu_options+=(security:--disable-seccomp)
qemu_options+=(security:--disable-tpm)
# Disable userspace network access ("-net user")
qemu_options+=(size:--disable-slirp)
# Disable USB
qemu_options+=(size:--disable-libusb)
qemu_options+=(size:--disable-usb-redir)
# Disable TCG support
case "$arch" in
aarch64) ;;
x86_64) qemu_options+=(size:--disable-tcg) ;;
ppc64le) ;;
s390x) qemu_options+=(size:--disable-tcg) ;;
esac
# SECURITY: Don't build a static binary (lowers security)
# needed if qemu version is less than 2.7
if [ "${qemu_version_major}" -eq 2 ] && [ "${qemu_version_minor}" -lt 7 ]; then
qemu_options+=(security:--disable-static)
fi
if [ "${static}" == "true" ]; then
qemu_options+=(misc:--static)
fi
# Disable debug and "-uuid ..." is always passed to the qemu binary so not required.
case "$arch" in
aarch64)
qemu_options+=(size:--disable-uuid)
;;
x86_64)
qemu_options+=(size:--disable-uuid)
qemu_options+=(size:--disable-debug-tcg)
qemu_options+=(size:--disable-tcg-interpreter)
;;
ppc64le)
qemu_options+=(size:--disable-debug-tcg)
qemu_options+=(size:--disable-tcg-interpreter)
;;
s390x)
qemu_options+=(size:--disable-uuid)
qemu_options+=(size:--disable-debug-tcg)
qemu_options+=(size:--disable-tcg-interpreter)
;;
esac
qemu_options+=(size:--disable-qom-cast-debug)
qemu_options+=(size:--disable-tcmalloc)
# Disallow network downloads
qemu_options+=(security:--disable-curl)
# Disable Remote Direct Memory Access (Live Migration)
# https://wiki.qemu.org/index.php/Features/RDMALiveMigration
qemu_options+=(size:--disable-rdma)
# Don't build the qemu-io, qemu-nbd and qemu-image tools
qemu_options+=(size:--disable-tools)
# Disable XEN driver
case "$arch" in
aarch64) ;;
x86_64) qemu_options+=(size:--disable-xen) ;;
ppc64le) qemu_options+=(size:--disable-xen) ;;
s390x) qemu_options+=(size:--disable-xen) ;;
esac
# FIXME: why is this disabled?
# (for reference, it's explicitly enabled in Ubuntu 17.10 and
# implicitly enabled in Fedora 27).
qemu_options+=(size:--disable-linux-aio)
if [[ "${qemu_version_major}" -ge 4 || ( "${qemu_version_major}" -eq 3 && "${qemu_version_minor}" -ge 1 ) ]]; then
# Disable libpmem, vNVDIMM backend (aka rootfs image) shouldn't be modifed
# by the guest
qemu_options+=(security:--disable-libpmem)
# Disable graphics
qemu_options+=(size:--disable-virglrenderer)
# Disable block replication
qemu_options+=(size:--disable-replication)
# Disable USB smart card reader
qemu_options+=(size:--disable-smartcard)
# Disable guest agent
qemu_options+=(size:--disable-guest-agent)
qemu_options+=(size:--disable-guest-agent-msi)
# unused image formats
qemu_options+=(size:--disable-vvfat)
qemu_options+=(size:--disable-vdi)
qemu_options+=(size:--disable-qed)
qemu_options+=(size:--disable-qcow1)
qemu_options+=(size:--disable-bochs)
qemu_options+=(size:--disable-cloop)
qemu_options+=(size:--disable-dmg)
qemu_options+=(size:--disable-parallels)
qemu_options+=(size:--disable-vxhs)
fi
#---------------------------------------------------------------------
# Enabled options
# Enable kernel Virtual Machine support.
# This is the default, but be explicit to avoid any future surprises
qemu_options+=(speed:--enable-kvm)
# Required for fast network access
qemu_options+=(speed:--enable-vhost-net)
# Always strip binaries
# needed if qemu version is less than 2.7
if [ "${qemu_version_major}" -eq 2 ] && [ "${qemu_version_minor}" -lt 7 ]; then
qemu_options+=(size:--enable-strip)
fi
# Support Ceph RADOS Block Device (RBD)
[ -z "${static}" ] && qemu_options+=(functionality:--enable-rbd)
# In "passthrough" security mode
# (-fsdev "...,security_model=passthrough,..."), qemu uses a helper
# application called virtfs-proxy-helper(1) to make certain 9p
# operations safer.
qemu_options+=(functionality:--enable-virtfs)
qemu_options+=(functionality:--enable-attr)
qemu_options+=(functionality:--enable-cap-ng)
if [[ "${qemu_version_major}" -ge 4 || ( "${qemu_version_major}" -eq 3 && "${qemu_version_minor}" -ge 1 ) ]]; then
# AVX2 is enabled by default by x86_64, make sure it's enabled only
# for that architecture
if [ "$arch" == x86_64 ]; then
qemu_options+=(speed:--enable-avx2)
else
qemu_options+=(speed:--disable-avx2)
fi
# Enable libc malloc_trim() for memory optimization.
qemu_options+=(speed:--enable-malloc-trim)
fi
#---------------------------------------------------------------------
# Other options
# 64-bit only
if [ "${arch}" = "ppc64le" ]; then
qemu_options+=(arch:"--target-list=ppc64-softmmu")
else
qemu_options+=(arch:"--target-list=${arch}-softmmu")
fi
_qemu_cflags=""
# compile with high level of optimisation
_qemu_cflags+=" -O3"
# Improve code quality by assuming identical semantics for interposed
# synmbols.
# Only enable if gcc is 5.3 or newer
if [ "${gcc_version_major}" -ge 5 ] && [ "${gcc_version_minor}" -ge 3 ]; then
_qemu_cflags+=" -fno-semantic-interposition"
fi
# Performance optimisation
_qemu_cflags+=" -falign-functions=32"
# SECURITY: make the compiler check for common security issues
# (such as argument and buffer overflows checks).
_qemu_cflags+=" -D_FORTIFY_SOURCE=2"
# SECURITY: Create binary as a Position Independant Executable,
# and take advantage of ASLR, making ROP attacks much harder to perform.
# (https://wiki.debian.org/Hardening)
case "$arch" in
aarch64) _qemu_cflags+=" -fPIC" ;;
x86_64) _qemu_cflags+=" -fPIE" ;;
ppc64le) _qemu_cflags+=" -fPIE" ;;
s390x) _qemu_cflags+=" -fPIE" ;;
esac
# Set compile options
qemu_options+=(functionality,security,speed,size:"--extra-cflags=\"${_qemu_cflags}\"")
unset _qemu_cflags
_qemu_ldflags=""
# SECURITY: Link binary as a Position Independant Executable,
# and take advantage of ASLR, making ROP attacks much harder to perform.
# (https://wiki.debian.org/Hardening)
case "$arch" in
aarch64) ;;
x86_64) [ -z "${static}" ] && _qemu_ldflags+=" -pie" ;;
ppc64le) [ -z "${static}" ] && _qemu_ldflags+=" -pie" ;;
s390x) [ -z "${static}" ] && _qemu_ldflags+=" -pie" ;;
esac
# SECURITY: Disallow executing code on the stack.
_qemu_ldflags+=" -z noexecstack"
# SECURITY: Make the linker set some program sections to read-only
# before the program is run to stop certain attacks.
_qemu_ldflags+=" -z relro"
# SECURITY: Make the linker resolve all symbols immediately on program
# load.
_qemu_ldflags+=" -z now"
qemu_options+=(security:"--extra-ldflags=\"${_qemu_ldflags}\"")
unset _qemu_ldflags
# Where to install qemu helper binaries
qemu_options+=(misc:--prefix=${prefix})
# Where to install qemu libraries
qemu_options+=(arch:--libdir=${prefix}/lib/${hypervisor})
# Where to install qemu helper binaries
qemu_options+=(misc:--libexecdir=${prefix}/libexec/${hypervisor})
# Where to install data files
qemu_options+=(misc:--datadir=${prefix}/share/${hypervisor})
}
# Entry point
main() {
action=""
while getopts "dhms" opt; do
case "$opt" in
d)
action="dump"
;;
h)
usage
exit 0
;;
m)
action="multi"
;;
s)
static="true"
;;
esac
done
shift $((OPTIND - 1))
[ -z "$1" ] && die "need hypervisor name"
hypervisor="$1"
local qemu_version_file="VERSION"
[ -f ${qemu_version_file} ] || die "QEMU version file '$qemu_version_file' not found"
local qemu_version_major=$(cut -d. -f1 "${qemu_version_file}")
local qemu_version_minor=$(cut -d. -f2 "${qemu_version_file}")
[ -n "${qemu_version_major}" ] ||
die "cannot determine qemu major version from file $qemu_version_file"
[ -n "${qemu_version_minor}" ] ||
die "cannot determine qemu minor version from file $qemu_version_file"
local gcc_version_major=$(gcc -dumpversion | cut -f1 -d.)
local gcc_version_minor=$(gcc -dumpversion | cut -f2 -d.)
[ -n "${gcc_version_major}" ] ||
die "cannot determine gcc major version, please ensure it is installed"
[ -n "${gcc_version_minor}" ] ||
die "cannot determine gcc minor version, please ensure it is installed"
# Generate qemu options
generate_qemu_options
show_array "$action" "${qemu_options[@]}"
exit 0
}
main $@