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