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