blob: 0e0a288255c81080621ed8b13abd49e1d443a8df [file] [log] [blame]
#!/usr/bin/env bash
if [ -z "${BASH_VERSINFO[0]}" ] || [ "${BASH_VERSINFO[0]}" -lt 4 ] ; then
echo "Error: Bash version 4 or newer is required for the kvm-unit-tests"
exit 1
fi
srcdir=$(cd "$(dirname "$0")"; pwd)
prefix=/usr/local
cc=gcc
cflags=
ld=ld
objcopy=objcopy
objdump=objdump
readelf=readelf
ar=ar
addr2line=addr2line
arch=$(uname -m | sed -e 's/i.86/i386/;s/arm64/aarch64/;s/arm.*/arm/;s/ppc64.*/ppc64/')
host=$arch
cross_prefix=
endian=""
pretty_print_stacks=yes
environ_default=yes
u32_long=
wa_divide=
target=
errata_force=0
erratatxt="$srcdir/errata.txt"
host_key_document=
gen_se_header=
enable_dump=no
page_size=
earlycon=
efi=
efi_direct=
# Enable -Werror by default for git repositories only (i.e. developer builds)
if [ -e "$srcdir"/.git ]; then
werror=-Werror
else
werror=
fi
usage() {
cat <<-EOF
Usage: $0 [options]
Options include:
--arch=ARCH architecture to compile for ($arch). ARCH can be one of:
arm, arm64, i386, ppc64, riscv32, riscv64, s390x, x86_64
--processor=PROCESSOR processor to compile for ($arch)
--target=TARGET target platform that the tests will be running on (qemu or
kvmtool, default is qemu) (arm/arm64 only)
--cross-prefix=PREFIX cross compiler prefix
--cc=CC c compiler to use ($cc)
--cflags=FLAGS extra options to be passed to the c compiler
--ld=LD ld linker to use ($ld)
--prefix=PREFIX where to install things ($prefix)
--endian=ENDIAN endianness to compile for (little or big, ppc64 only)
--[enable|disable]-pretty-print-stacks
enable or disable pretty stack printing (enabled by default)
--[enable|disable]-default-environ
enable or disable the generation of a default environ when
no environ is provided by the user (enabled by default)
--erratatxt=FILE specify a file to use instead of errata.txt. Use
'--erratatxt=' to ensure no file is used.
--host-key-document=HOST_KEY_DOCUMENT
Specify the machine-specific host-key document for creating
a PVM image with 'genprotimg' (s390x only)
--gen-se-header=GEN_SE_HEADER
Provide an executable to generate a PV header
requires --host-key-document. (s390x-snippets only)
--[enable|disable]-dump
Allow PV guests to be dumped. Requires at least z16.
(s390x only)
--page-size=PAGE_SIZE
Specify the page size (translation granule) (4k, 16k or
64k, default is 4k, arm64 only)
--earlycon=EARLYCON
Specify the UART name, type and address (optional, arm and
arm64 only). The specified address will overwrite the UART
address set by the --target option. EARLYCON can be one of
(case sensitive):
uart[8250],mmio,ADDR
Specify an 8250 compatible UART at address ADDR. Supported
register stride is 8 bit only.
pl011,ADDR
pl011,mmio32,ADDR
Specify a PL011 compatible UART at address ADDR. Supported
register stride is 32 bit only.
--[enable|disable]-efi Boot and run from UEFI (disabled by default, x86_64 and arm64 only)
--[enable|disable]-werror
Select whether to compile with the -Werror compiler flag
--[enable|disable]-efi-direct
Select whether to run EFI tests directly with QEMU's -kernel
option. When not enabled, tests will be placed in an EFI file
system and run from the UEFI shell. Ignored when efi isn't enabled
and defaults to enabled when efi is enabled for riscv64.
(arm64 and riscv64 only)
EOF
exit 1
}
while [[ "$1" = -* ]]; do
opt="$1"; shift
arg=
if [[ "$opt" = *=* ]]; then
arg="${opt#*=}"
opt="${opt%%=*}"
fi
case "$opt" in
--prefix)
prefix="$arg"
;;
--arch)
arch="$arg"
;;
--processor)
processor="$arg"
;;
--target)
target="$arg"
;;
--cross-prefix)
cross_prefix="$arg"
;;
--endian)
endian="$arg"
;;
--cc)
cc="$arg"
;;
--cflags)
cflags="$arg"
;;
--ld)
ld="$arg"
;;
--enable-pretty-print-stacks)
pretty_print_stacks=yes
;;
--disable-pretty-print-stacks)
pretty_print_stacks=no
;;
--enable-default-environ)
environ_default=yes
;;
--disable-default-environ)
environ_default=no
;;
--erratatxt)
erratatxt=
[ "$arg" ] && erratatxt=$(eval realpath "$arg")
;;
--host-key-document)
host_key_document="$arg"
;;
--gen-se-header)
gen_se_header="$arg"
;;
--enable-dump)
enable_dump=yes
;;
--disable-dump)
enable_dump=no
;;
--page-size)
page_size="$arg"
;;
--earlycon)
earlycon="$arg"
;;
--enable-efi)
efi=y
;;
--disable-efi)
efi=n
;;
--enable-efi-direct)
efi_direct=y
;;
--disable-efi-direct)
efi_direct=n
;;
--enable-werror)
werror=-Werror
;;
--disable-werror)
werror=
;;
--help)
usage
;;
*)
echo "Unknown option '$opt'"
echo
usage
;;
esac
done
if [ -z "$efi" ] || [ "$efi" = "n" ]; then
[ "$efi_direct" = "y" ] && efi_direct=
fi
if [ -n "$host_key_document" ] && [ ! -f "$host_key_document" ]; then
echo "Host key document doesn't exist at the specified location."
exit 1
fi
if [ "$erratatxt" ] && [ ! -f "$erratatxt" ]; then
echo "erratatxt: $erratatxt does not exist or is not a regular file"
exit 1
fi
arch_name=$arch
[ "$arch" = "aarch64" ] && arch="arm64"
[ "$arch_name" = "arm64" ] && arch_name="aarch64"
arch_libdir=$arch
if [ "$arch" = "riscv" ]; then
echo "riscv32 or riscv64 must be specified"
exit 1
fi
if [ -z "$target" ]; then
target="qemu"
else
if [ "$arch" != "arm64" ] && [ "$arch" != "arm" ]; then
echo "--target is not supported for $arch"
usage
fi
fi
if [ "$efi" ] && [ "$arch" != "x86_64" ] &&
[ "$arch" != "arm64" ] && [ "$arch" != "riscv64" ]; then
echo "--[enable|disable]-efi is not supported for $arch"
usage
fi
if [ "$efi" ] && [ "$arch" = "riscv64" ] && [ -z "$efi_direct" ]; then
efi_direct=y
fi
if [ -z "$page_size" ]; then
if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
page_size="4096"
fi
else
if [ "$arch" != "arm64" ]; then
echo "--page-size is not supported for $arch"
usage
fi
if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then
page_size=$(( ${page_size%?} * 1024 ))
fi
if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
[ "$page_size" != "65536" ]; then
echo "arm64 doesn't support page size of $page_size"
usage
fi
if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
echo "efi must use 4K pages"
exit 1
fi
fi
[ -z "$processor" ] && processor="$arch"
if [ "$processor" = "arm64" ]; then
processor="cortex-a57"
elif [ "$processor" = "arm" ]; then
processor="cortex-a15"
fi
if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
testdir=x86
elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
testdir=arm
if [ "$target" = "qemu" ]; then
arm_uart_early_addr=0x09000000
elif [ "$target" = "kvmtool" ]; then
arm_uart_early_addr=0x1000000
errata_force=1
else
echo "--target must be one of 'qemu' or 'kvmtool'!"
usage
fi
if [ "$earlycon" ]; then
IFS=, read -r name type_addr addr <<<"$earlycon"
if [ "$name" != "uart" ] && [ "$name" != "uart8250" ] &&
[ "$name" != "pl011" ]; then
echo "unknown earlycon name: $name"
usage
fi
if [ "$name" = "pl011" ]; then
if [ -z "$addr" ]; then
addr=$type_addr
else
if [ "$type_addr" != "mmio32" ]; then
echo "unknown $name earlycon type: $type_addr"
usage
fi
fi
else
if [ "$type_addr" != "mmio" ]; then
echo "unknown $name earlycon type: $type_addr"
usage
fi
fi
if [ -z "$addr" ]; then
echo "missing $name earlycon address"
usage
fi
if [[ $addr =~ ^0(x|X)[0-9a-fA-F]+$ ]] ||
[[ $addr =~ ^[0-9]+$ ]]; then
arm_uart_early_addr=$addr
else
echo "invalid $name earlycon address: $addr"
usage
fi
fi
elif [ "$arch" = "ppc64" ]; then
testdir=powerpc
firmware="$testdir/boot_rom.bin"
if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
echo "You must provide endianness (big or little)!"
usage
fi
elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then
testdir=riscv
arch_libdir=riscv
elif [ "$arch" = "s390x" ]; then
testdir=s390x
else
echo "arch $arch is not supported!"
arch=
usage
fi
if [ ! -d "$srcdir/$testdir" ]; then
echo "$srcdir/$testdir does not exist!"
exit 1
fi
if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then
ln -fs "$srcdir/$testdir/efi/run" $testdir-run
elif [ -f "$srcdir/$testdir/run" ]; then
ln -fs "$srcdir/$testdir/run" $testdir-run
fi
testsubdir=$testdir
if [ "$efi" = "y" ]; then
testsubdir=$testdir/efi
fi
# check if uint32_t needs a long format modifier
cat << EOF > lib-test.c
__UINT32_TYPE__
EOF
u32_long=$("$cross_prefix$cc" -E lib-test.c | grep -v '^#' | grep -q long && echo yes)
rm -f lib-test.c
# check if slash can be used for division
if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
cat << EOF > lib-test.S
foo:
movl (8 / 2), %eax
EOF
wa_divide=$("$cross_prefix$cc" -c lib-test.S >/dev/null 2>&1 || echo yes)
rm -f lib-test.{o,S}
fi
# warn if enhanced getopt is unavailable
getopt -T > /dev/null
if [ $? -ne 4 ]; then
echo "Without enhanced getopt you won't be able to use run_tests.sh."
echo "Add it to your PATH?"
fi
# Are we in a separate build tree? If so, link the Makefile
# and shared stuff so that 'make' and run_tests.sh work.
if test ! -e Makefile; then
echo "linking Makefile..."
ln -s "$srcdir/Makefile" .
echo "linking tests..."
mkdir -p $testsubdir
ln -sf "$srcdir/$testdir/run" $testdir/
if test "$testdir" != "$testsubdir"; then
ln -sf "$srcdir/$testsubdir/run" $testsubdir/
fi
ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/
ln -sf "$srcdir/run_tests.sh"
if [ -d "$srcdir/$testdir/snippets" ]; then
mkdir -p "$testdir/snippets/c"
fi
echo "linking scripts..."
ln -sf "$srcdir/scripts"
fi
# link lib/asm for the architecture
rm -f lib/asm
asm="asm-generic"
if [ -d "$srcdir/lib/$arch/asm" ]; then
asm="$srcdir/lib/$arch/asm"
elif [ -d "$srcdir/lib/$testdir/asm" ]; then
asm="$srcdir/lib/$testdir/asm"
fi
mkdir -p lib
ln -sf "$asm" lib/asm
# create the config
cat <<EOF > config.mak
# Shellcheck does not see these are used
# shellcheck disable=SC2034
# Shellcheck can give pointless quoting warnings for some commands
# shellcheck disable=SC2209
SRCDIR=$srcdir
PREFIX=$prefix
HOST=$host
ARCH=$arch
ARCH_NAME=$arch_name
ARCH_LIBDIR=$arch_libdir
PROCESSOR=$processor
CC=$cross_prefix$cc
CFLAGS=$cflags
LD=$cross_prefix$ld
OBJCOPY=$cross_prefix$objcopy
OBJDUMP=$cross_prefix$objdump
READELF=$cross_prefix$readelf
AR=$cross_prefix$ar
ADDR2LINE=$cross_prefix$addr2line
TEST_DIR=$testdir
TEST_SUBDIR=$testsubdir
FIRMWARE=$firmware
ENDIAN=$endian
PRETTY_PRINT_STACKS=$pretty_print_stacks
ENVIRON_DEFAULT=$environ_default
ERRATATXT=$erratatxt
U32_LONG_FMT=$u32_long
WA_DIVIDE=$wa_divide
GENPROTIMG=${GENPROTIMG-genprotimg}
HOST_KEY_DOCUMENT=$host_key_document
CONFIG_DUMP=$enable_dump
CONFIG_EFI=$efi
EFI_DIRECT=$efi_direct
CONFIG_WERROR=$werror
GEN_SE_HEADER=$gen_se_header
EOF
if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
echo "TARGET=$target" >> config.mak
fi
cat <<EOF > lib/config.h
#ifndef _CONFIG_H_
#define _CONFIG_H_
/*
* Generated file. DO NOT MODIFY.
*
*/
EOF
if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
cat <<EOF >> lib/config.h
#define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr}
#define CONFIG_ERRATA_FORCE ${errata_force}
#define CONFIG_PAGE_SIZE _AC(${page_size}, UL)
EOF
elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then
cat <<EOF >> lib/config.h
#define CONFIG_UART_EARLY_BASE 0x10000000
EOF
fi
echo "#endif" >> lib/config.h