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 4k, 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 [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 247 page_size="4096" 248 fi 249else 250 if [ "$arch" != "arm64" ]; then 251 echo "--page-size is not supported for $arch" 252 usage 253 fi 254 255 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then 256 page_size=$(( ${page_size%?} * 1024 )) 257 fi 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 267fi 268 269[ -z "$processor" ] && processor="$arch" 270 271if [ "$processor" = "arm64" ]; then 272 processor="cortex-a57" 273elif [ "$processor" = "arm" ]; then 274 processor="cortex-a15" 275fi 276 277if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 278 testdir=x86 279elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 280 testdir=arm 281 if [ "$target" = "qemu" ]; then 282 arm_uart_early_addr=0x09000000 283 elif [ "$target" = "kvmtool" ]; then 284 arm_uart_early_addr=0x1000000 285 errata_force=1 286 else 287 echo "--target must be one of 'qemu' or 'kvmtool'!" 288 usage 289 fi 290 291 if [ "$earlycon" ]; then 292 IFS=, read -r name type_addr addr <<<"$earlycon" 293 if [ "$name" != "uart" ] && [ "$name" != "uart8250" ] && 294 [ "$name" != "pl011" ]; then 295 echo "unknown earlycon name: $name" 296 usage 297 fi 298 299 if [ "$name" = "pl011" ]; then 300 if [ -z "$addr" ]; then 301 addr=$type_addr 302 else 303 if [ "$type_addr" != "mmio32" ]; then 304 echo "unknown $name earlycon type: $type_addr" 305 usage 306 fi 307 fi 308 else 309 if [ "$type_addr" != "mmio" ]; then 310 echo "unknown $name earlycon type: $type_addr" 311 usage 312 fi 313 fi 314 315 if [ -z "$addr" ]; then 316 echo "missing $name earlycon address" 317 usage 318 fi 319 if [[ $addr =~ ^0(x|X)[0-9a-fA-F]+$ ]] || 320 [[ $addr =~ ^[0-9]+$ ]]; then 321 arm_uart_early_addr=$addr 322 else 323 echo "invalid $name earlycon address: $addr" 324 usage 325 fi 326 fi 327elif [ "$arch" = "ppc64" ]; then 328 testdir=powerpc 329 firmware="$testdir/boot_rom.bin" 330 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then 331 echo "You must provide endianness (big or little)!" 332 usage 333 fi 334elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 335 testdir=riscv 336 arch_libdir=riscv 337elif [ "$arch" = "s390x" ]; then 338 testdir=s390x 339else 340 echo "arch $arch is not supported!" 341 arch= 342 usage 343fi 344if [ ! -d "$srcdir/$testdir" ]; then 345 echo "$srcdir/$testdir does not exist!" 346 exit 1 347fi 348 349if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then 350 ln -fs "$srcdir/$testdir/efi/run" $testdir-run 351elif [ -f "$srcdir/$testdir/run" ]; then 352 ln -fs "$srcdir/$testdir/run" $testdir-run 353fi 354 355testsubdir=$testdir 356if [ "$efi" = "y" ]; then 357 testsubdir=$testdir/efi 358fi 359 360# check if uint32_t needs a long format modifier 361cat << EOF > lib-test.c 362__UINT32_TYPE__ 363EOF 364u32_long=$("$cross_prefix$cc" -E lib-test.c | grep -v '^#' | grep -q long && echo yes) 365rm -f lib-test.c 366 367# check if slash can be used for division 368if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 369 cat << EOF > lib-test.S 370foo: 371 movl (8 / 2), %eax 372EOF 373 wa_divide=$("$cross_prefix$cc" -c lib-test.S >/dev/null 2>&1 || echo yes) 374 rm -f lib-test.{o,S} 375fi 376 377# warn if enhanced getopt is unavailable 378getopt -T > /dev/null 379if [ $? -ne 4 ]; then 380 echo "Without enhanced getopt you won't be able to use run_tests.sh." 381 echo "Add it to your PATH?" 382fi 383 384# Are we in a separate build tree? If so, link the Makefile 385# and shared stuff so that 'make' and run_tests.sh work. 386if test ! -e Makefile; then 387 echo "linking Makefile..." 388 ln -s "$srcdir/Makefile" . 389 390 echo "linking tests..." 391 mkdir -p $testsubdir 392 ln -sf "$srcdir/$testdir/run" $testdir/ 393 if test "$testdir" != "$testsubdir"; then 394 ln -sf "$srcdir/$testsubdir/run" $testsubdir/ 395 fi 396 ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/ 397 ln -sf "$srcdir/run_tests.sh" 398 399 if [ -d "$srcdir/$testdir/snippets" ]; then 400 mkdir -p "$testdir/snippets/c" 401 fi 402 403 echo "linking scripts..." 404 ln -sf "$srcdir/scripts" 405fi 406 407# link lib/asm for the architecture 408rm -f lib/asm 409asm="asm-generic" 410if [ -d "$srcdir/lib/$arch/asm" ]; then 411 asm="$srcdir/lib/$arch/asm" 412elif [ -d "$srcdir/lib/$testdir/asm" ]; then 413 asm="$srcdir/lib/$testdir/asm" 414fi 415mkdir -p lib 416ln -sf "$asm" lib/asm 417 418 419# create the config 420cat <<EOF > config.mak 421# Shellcheck does not see these are used 422# shellcheck disable=SC2034 423# Shellcheck can give pointless quoting warnings for some commands 424# shellcheck disable=SC2209 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