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