1#!/usr/bin/env bash 2 3if [ -z "${BASH_VERSINFO[0]}" ] || [ "${BASH_VERSINFO[0]}" -lt 4 ] ; then 4 echo "Error: Bash version 4 or newer is required for the kvm-unit-tests" 5 exit 1 6fi 7 8srcdir=$(cd "$(dirname "$0")"; pwd) 9prefix=/usr/local 10cc=gcc 11cflags= 12ld=ld 13objcopy=objcopy 14objdump=objdump 15readelf=readelf 16ar=ar 17addr2line=addr2line 18arch=$(uname -m | sed -e 's/i.86/i386/;s/arm64/aarch64/;s/arm.*/arm/;s/ppc64.*/ppc64/') 19host=$arch 20cross_prefix= 21endian="" 22pretty_print_stacks=yes 23environ_default=yes 24u32_long= 25wa_divide= 26target= 27errata_force=0 28erratatxt="$srcdir/errata.txt" 29host_key_document= 30gen_se_header= 31enable_dump=no 32page_size= 33earlycon= 34efi= 35efi_direct= 36 37# Enable -Werror by default for git repositories only (i.e. developer builds) 38if [ -e "$srcdir"/.git ]; then 39 werror=-Werror 40else 41 werror= 42fi 43 44usage() { 45 cat <<-EOF 46 Usage: $0 [options] 47 48 Options include: 49 --arch=ARCH architecture to compile for ($arch). ARCH can be one of: 50 arm, arm64, i386, ppc64, riscv32, riscv64, s390x, x86_64 51 --processor=PROCESSOR processor to compile for ($arch) 52 --target=TARGET target platform that the tests will be running on (qemu or 53 kvmtool, default is qemu) (arm/arm64 only) 54 --cross-prefix=PREFIX cross compiler prefix 55 --cc=CC c compiler to use ($cc) 56 --cflags=FLAGS extra options to be passed to the c compiler 57 --ld=LD ld linker to use ($ld) 58 --prefix=PREFIX where to install things ($prefix) 59 --endian=ENDIAN endianness to compile for (little or big, ppc64 only) 60 --[enable|disable]-pretty-print-stacks 61 enable or disable pretty stack printing (enabled by default) 62 --[enable|disable]-default-environ 63 enable or disable the generation of a default environ when 64 no environ is provided by the user (enabled by default) 65 --erratatxt=FILE specify a file to use instead of errata.txt. Use 66 '--erratatxt=' to ensure no file is used. 67 --host-key-document=HOST_KEY_DOCUMENT 68 Specify the machine-specific host-key document for creating 69 a PVM image with 'genprotimg' (s390x only) 70 --gen-se-header=GEN_SE_HEADER 71 Provide an executable to generate a PV header 72 requires --host-key-document. (s390x-snippets only) 73 --[enable|disable]-dump 74 Allow PV guests to be dumped. Requires at least z16. 75 (s390x only) 76 --page-size=PAGE_SIZE 77 Specify the page size (translation granule) (4k, 16k or 78 64k, default is 64k, arm64 only) 79 --earlycon=EARLYCON 80 Specify the UART name, type and address (optional, arm and 81 arm64 only). The specified address will overwrite the UART 82 address set by the --target option. EARLYCON can be one of 83 (case sensitive): 84 uart[8250],mmio,ADDR 85 Specify an 8250 compatible UART at address ADDR. Supported 86 register stride is 8 bit only. 87 pl011,ADDR 88 pl011,mmio32,ADDR 89 Specify a PL011 compatible UART at address ADDR. Supported 90 register stride is 32 bit only. 91 --[enable|disable]-efi Boot and run from UEFI (disabled by default, x86_64 and arm64 only) 92 --[enable|disable]-werror 93 Select whether to compile with the -Werror compiler flag 94 --[enable|disable]-efi-direct 95 Select whether to run EFI tests directly with QEMU's -kernel 96 option. When not enabled, tests will be placed in an EFI file 97 system and run from the UEFI shell. Ignored when efi isn't enabled 98 and defaults to enabled when efi is enabled for riscv64. 99 (arm64 and riscv64 only) 100EOF 101 exit 1 102} 103 104while [[ "$1" = -* ]]; do 105 opt="$1"; shift 106 arg= 107 if [[ "$opt" = *=* ]]; then 108 arg="${opt#*=}" 109 opt="${opt%%=*}" 110 fi 111 case "$opt" in 112 --prefix) 113 prefix="$arg" 114 ;; 115 --arch) 116 arch="$arg" 117 ;; 118 --processor) 119 processor="$arg" 120 ;; 121 --target) 122 target="$arg" 123 ;; 124 --cross-prefix) 125 cross_prefix="$arg" 126 ;; 127 --endian) 128 endian="$arg" 129 ;; 130 --cc) 131 cc="$arg" 132 ;; 133 --cflags) 134 cflags="$arg" 135 ;; 136 --ld) 137 ld="$arg" 138 ;; 139 --enable-pretty-print-stacks) 140 pretty_print_stacks=yes 141 ;; 142 --disable-pretty-print-stacks) 143 pretty_print_stacks=no 144 ;; 145 --enable-default-environ) 146 environ_default=yes 147 ;; 148 --disable-default-environ) 149 environ_default=no 150 ;; 151 --erratatxt) 152 erratatxt= 153 [ "$arg" ] && erratatxt=$(eval realpath "$arg") 154 ;; 155 --host-key-document) 156 host_key_document="$arg" 157 ;; 158 --gen-se-header) 159 gen_se_header="$arg" 160 ;; 161 --enable-dump) 162 enable_dump=yes 163 ;; 164 --disable-dump) 165 enable_dump=no 166 ;; 167 --page-size) 168 page_size="$arg" 169 ;; 170 --earlycon) 171 earlycon="$arg" 172 ;; 173 --enable-efi) 174 efi=y 175 ;; 176 --disable-efi) 177 efi=n 178 ;; 179 --enable-efi-direct) 180 efi_direct=y 181 ;; 182 --disable-efi-direct) 183 efi_direct=n 184 ;; 185 --enable-werror) 186 werror=-Werror 187 ;; 188 --disable-werror) 189 werror= 190 ;; 191 --help) 192 usage 193 ;; 194 *) 195 echo "Unknown option '$opt'" 196 echo 197 usage 198 ;; 199 esac 200done 201 202if [ -z "$efi" ] || [ "$efi" = "n" ]; then 203 [ "$efi_direct" = "y" ] && efi_direct= 204fi 205 206if [ -n "$host_key_document" ] && [ ! -f "$host_key_document" ]; then 207 echo "Host key document doesn't exist at the specified location." 208 exit 1 209fi 210 211if [ "$erratatxt" ] && [ ! -f "$erratatxt" ]; then 212 echo "erratatxt: $erratatxt does not exist or is not a regular file" 213 exit 1 214fi 215 216arch_name=$arch 217[ "$arch" = "aarch64" ] && arch="arm64" 218[ "$arch_name" = "arm64" ] && arch_name="aarch64" 219arch_libdir=$arch 220 221if [ "$arch" = "riscv" ]; then 222 echo "riscv32 or riscv64 must be specified" 223 exit 1 224fi 225 226if [ -z "$target" ]; then 227 target="qemu" 228else 229 if [ "$arch" != "arm64" ] && [ "$arch" != "arm" ]; then 230 echo "--target is not supported for $arch" 231 usage 232 fi 233fi 234 235if [ "$efi" ] && [ "$arch" != "x86_64" ] && 236 [ "$arch" != "arm64" ] && [ "$arch" != "riscv64" ]; then 237 echo "--[enable|disable]-efi is not supported for $arch" 238 usage 239fi 240 241if [ "$efi" ] && [ "$arch" = "riscv64" ] && [ -z "$efi_direct" ]; then 242 efi_direct=y 243fi 244 245if [ -z "$page_size" ]; then 246 if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then 247 page_size="4096" 248 elif [ "$arch" = "arm64" ]; then 249 page_size="65536" 250 elif [ "$arch" = "arm" ]; then 251 page_size="4096" 252 fi 253else 254 if [ "$arch" != "arm64" ]; then 255 echo "--page-size is not supported for $arch" 256 usage 257 fi 258 259 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then 260 page_size=$(( ${page_size%?} * 1024 )) 261 fi 262 if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] && 263 [ "$page_size" != "65536" ]; then 264 echo "arm64 doesn't support page size of $page_size" 265 usage 266 fi 267 if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then 268 echo "efi must use 4K pages" 269 exit 1 270 fi 271fi 272 273[ -z "$processor" ] && processor="$arch" 274 275if [ "$processor" = "arm64" ]; then 276 processor="cortex-a57" 277elif [ "$processor" = "arm" ]; then 278 processor="cortex-a15" 279fi 280 281if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 282 testdir=x86 283elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 284 testdir=arm 285 if [ "$target" = "qemu" ]; then 286 arm_uart_early_addr=0x09000000 287 elif [ "$target" = "kvmtool" ]; then 288 arm_uart_early_addr=0x1000000 289 errata_force=1 290 else 291 echo "--target must be one of 'qemu' or 'kvmtool'!" 292 usage 293 fi 294 295 if [ "$earlycon" ]; then 296 IFS=, read -r name type_addr addr <<<"$earlycon" 297 if [ "$name" != "uart" ] && [ "$name" != "uart8250" ] && 298 [ "$name" != "pl011" ]; then 299 echo "unknown earlycon name: $name" 300 usage 301 fi 302 303 if [ "$name" = "pl011" ]; then 304 if [ -z "$addr" ]; then 305 addr=$type_addr 306 else 307 if [ "$type_addr" != "mmio32" ]; then 308 echo "unknown $name earlycon type: $type_addr" 309 usage 310 fi 311 fi 312 else 313 if [ "$type_addr" != "mmio" ]; then 314 echo "unknown $name earlycon type: $type_addr" 315 usage 316 fi 317 fi 318 319 if [ -z "$addr" ]; then 320 echo "missing $name earlycon address" 321 usage 322 fi 323 if [[ $addr =~ ^0(x|X)[0-9a-fA-F]+$ ]] || 324 [[ $addr =~ ^[0-9]+$ ]]; then 325 arm_uart_early_addr=$addr 326 else 327 echo "invalid $name earlycon address: $addr" 328 usage 329 fi 330 fi 331elif [ "$arch" = "ppc64" ]; then 332 testdir=powerpc 333 firmware="$testdir/boot_rom.bin" 334 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then 335 echo "You must provide endianness (big or little)!" 336 usage 337 fi 338elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 339 testdir=riscv 340 arch_libdir=riscv 341elif [ "$arch" = "s390x" ]; then 342 testdir=s390x 343else 344 echo "arch $arch is not supported!" 345 arch= 346 usage 347fi 348if [ ! -d "$srcdir/$testdir" ]; then 349 echo "$srcdir/$testdir does not exist!" 350 exit 1 351fi 352 353if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then 354 ln -fs "$srcdir/$testdir/efi/run" $testdir-run 355elif [ -f "$srcdir/$testdir/run" ]; then 356 ln -fs "$srcdir/$testdir/run" $testdir-run 357fi 358 359testsubdir=$testdir 360if [ "$efi" = "y" ]; then 361 testsubdir=$testdir/efi 362fi 363 364# check if uint32_t needs a long format modifier 365cat << EOF > lib-test.c 366__UINT32_TYPE__ 367EOF 368u32_long=$("$cross_prefix$cc" -E lib-test.c | grep -v '^#' | grep -q long && echo yes) 369rm -f lib-test.c 370 371# check if slash can be used for division 372if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 373 cat << EOF > lib-test.S 374foo: 375 movl (8 / 2), %eax 376EOF 377 wa_divide=$("$cross_prefix$cc" -c lib-test.S >/dev/null 2>&1 || echo yes) 378 rm -f lib-test.{o,S} 379fi 380 381# warn if enhanced getopt is unavailable 382getopt -T > /dev/null 383if [ $? -ne 4 ]; then 384 echo "Without enhanced getopt you won't be able to use run_tests.sh." 385 echo "Add it to your PATH?" 386fi 387 388# Are we in a separate build tree? If so, link the Makefile 389# and shared stuff so that 'make' and run_tests.sh work. 390if test ! -e Makefile; then 391 echo "linking Makefile..." 392 ln -s "$srcdir/Makefile" . 393 394 echo "linking tests..." 395 mkdir -p $testsubdir 396 ln -sf "$srcdir/$testdir/run" $testdir/ 397 if test "$testdir" != "$testsubdir"; then 398 ln -sf "$srcdir/$testsubdir/run" $testsubdir/ 399 fi 400 ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/ 401 ln -sf "$srcdir/run_tests.sh" 402 403 if [ -d "$srcdir/$testdir/snippets" ]; then 404 mkdir -p "$testdir/snippets/c" 405 fi 406 407 echo "linking scripts..." 408 ln -sf "$srcdir/scripts" 409fi 410 411# link lib/asm for the architecture 412rm -f lib/asm 413asm="asm-generic" 414if [ -d "$srcdir/lib/$arch/asm" ]; then 415 asm="$srcdir/lib/$arch/asm" 416elif [ -d "$srcdir/lib/$testdir/asm" ]; then 417 asm="$srcdir/lib/$testdir/asm" 418fi 419mkdir -p lib 420ln -sf "$asm" lib/asm 421 422 423# create the config 424cat <<EOF > config.mak 425SRCDIR=$srcdir 426PREFIX=$prefix 427HOST=$host 428ARCH=$arch 429ARCH_NAME=$arch_name 430ARCH_LIBDIR=$arch_libdir 431PROCESSOR=$processor 432CC=$cross_prefix$cc 433CFLAGS=$cflags 434LD=$cross_prefix$ld 435OBJCOPY=$cross_prefix$objcopy 436OBJDUMP=$cross_prefix$objdump 437READELF=$cross_prefix$readelf 438AR=$cross_prefix$ar 439ADDR2LINE=$cross_prefix$addr2line 440TEST_DIR=$testdir 441TEST_SUBDIR=$testsubdir 442FIRMWARE=$firmware 443ENDIAN=$endian 444PRETTY_PRINT_STACKS=$pretty_print_stacks 445ENVIRON_DEFAULT=$environ_default 446ERRATATXT=$erratatxt 447U32_LONG_FMT=$u32_long 448WA_DIVIDE=$wa_divide 449GENPROTIMG=${GENPROTIMG-genprotimg} 450HOST_KEY_DOCUMENT=$host_key_document 451CONFIG_DUMP=$enable_dump 452CONFIG_EFI=$efi 453EFI_DIRECT=$efi_direct 454CONFIG_WERROR=$werror 455GEN_SE_HEADER=$gen_se_header 456EOF 457if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 458 echo "TARGET=$target" >> config.mak 459fi 460 461cat <<EOF > lib/config.h 462#ifndef _CONFIG_H_ 463#define _CONFIG_H_ 464/* 465 * Generated file. DO NOT MODIFY. 466 * 467 */ 468 469EOF 470if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 471cat <<EOF >> lib/config.h 472 473#define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr} 474#define CONFIG_ERRATA_FORCE ${errata_force} 475#define CONFIG_PAGE_SIZE _AC(${page_size}, UL) 476 477EOF 478elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 479cat <<EOF >> lib/config.h 480 481#define CONFIG_UART_EARLY_BASE 0x10000000 482 483EOF 484fi 485echo "#endif" >> lib/config.h 486