blob: c1d0fe4adbb0ace05ca246973a38744f0f9a709f [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 64k, 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.
(arm64 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 [ -z "$page_size" ]; then
if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then
page_size="4096"
elif [ "$arch" = "arm64" ]; then
page_size="65536"
elif [ "$arch" = "arm" ]; 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
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