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 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 286[ -z "$processor" ] && processor="$arch" 287 288if [ "$processor" = "arm64" ]; then 289 processor="cortex-a57" 290elif [ "$processor" = "arm" ]; then 291 processor="cortex-a15" 292fi 293 294if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 295 testdir=x86 296elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 297 testdir=arm 298 if [ "$target" = "qemu" ]; then 299 arm_uart_early_addr=0x09000000 300 elif [ "$target" = "kvmtool" ]; then 301 arm_uart_early_addr=0x1000000 302 errata_force=1 303 else 304 echo "--target must be one of 'qemu' or 'kvmtool'!" 305 usage 306 fi 307 308 if [ "$earlycon" ]; then 309 IFS=, read -r name type_addr addr <<<"$earlycon" 310 if [ "$name" != "uart" ] && [ "$name" != "uart8250" ] && 311 [ "$name" != "pl011" ]; then 312 echo "unknown earlycon name: $name" 313 usage 314 fi 315 316 if [ "$name" = "pl011" ]; then 317 if [ -z "$addr" ]; then 318 addr=$type_addr 319 else 320 if [ "$type_addr" != "mmio32" ]; then 321 echo "unknown $name earlycon type: $type_addr" 322 usage 323 fi 324 fi 325 else 326 if [ "$type_addr" != "mmio" ]; then 327 echo "unknown $name earlycon type: $type_addr" 328 usage 329 fi 330 fi 331 332 if [ -z "$addr" ]; then 333 echo "missing $name earlycon address" 334 usage 335 fi 336 if [[ $addr =~ ^0(x|X)[0-9a-fA-F]+$ ]] || 337 [[ $addr =~ ^[0-9]+$ ]]; then 338 arm_uart_early_addr=$addr 339 else 340 echo "invalid $name earlycon address: $addr" 341 usage 342 fi 343 fi 344elif [ "$arch" = "ppc64" ]; then 345 testdir=powerpc 346 firmware="$testdir/boot_rom.bin" 347 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then 348 echo "You must provide endianness (big or little)!" 349 usage 350 fi 351elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 352 testdir=riscv 353 arch_libdir=riscv 354elif [ "$arch" = "s390x" ]; then 355 testdir=s390x 356else 357 echo "arch $arch is not supported!" 358 arch= 359 usage 360fi 361if [ ! -d "$srcdir/$testdir" ]; then 362 echo "$srcdir/$testdir does not exist!" 363 exit 1 364fi 365 366if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then 367 ln -fs "$srcdir/$testdir/efi/run" $testdir-run 368elif [ -f "$srcdir/$testdir/run" ]; then 369 ln -fs "$srcdir/$testdir/run" $testdir-run 370fi 371 372testsubdir=$testdir 373if [ "$efi" = "y" ]; then 374 testsubdir=$testdir/efi 375fi 376 377# check if uint32_t needs a long format modifier 378cat << EOF > lib-test.c 379__UINT32_TYPE__ 380EOF 381u32_long=$("$cc" $cflags -E lib-test.c | grep -v '^#' | grep -q long && echo yes) 382rm -f lib-test.c 383 384# check if slash can be used for division 385if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 386 cat << EOF > lib-test.S 387foo: 388 movl (8 / 2), %eax 389EOF 390 wa_divide=$("$cc" $cflags -c lib-test.S >/dev/null 2>&1 || echo yes) 391 rm -f lib-test.{o,S} 392fi 393 394# warn if enhanced getopt is unavailable 395getopt -T > /dev/null 396if [ $? -ne 4 ]; then 397 echo "Without enhanced getopt you won't be able to use run_tests.sh." 398 echo "Add it to your PATH?" 399fi 400 401# Are we in a separate build tree? If so, link the Makefile 402# and shared stuff so that 'make' and run_tests.sh work. 403if test ! -e Makefile; then 404 echo "linking Makefile..." 405 ln -s "$srcdir/Makefile" . 406 407 echo "linking tests..." 408 mkdir -p $testsubdir 409 ln -sf "$srcdir/$testdir/run" $testdir/ 410 if test "$testdir" != "$testsubdir"; then 411 ln -sf "$srcdir/$testsubdir/run" $testsubdir/ 412 fi 413 ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/ 414 ln -sf "$srcdir/run_tests.sh" 415 416 if [ -d "$srcdir/$testdir/snippets" ]; then 417 mkdir -p "$testdir/snippets/c" 418 fi 419 420 echo "linking scripts..." 421 ln -sf "$srcdir/scripts" 422fi 423 424# link lib/asm for the architecture 425rm -f lib/asm 426asm="asm-generic" 427if [ -d "$srcdir/lib/$arch/asm" ]; then 428 asm="$srcdir/lib/$arch/asm" 429 mkdir -p "lib/$arch" 430elif [ -d "$srcdir/lib/$arch_libdir/asm" ]; then 431 asm="$srcdir/lib/$arch_libdir/asm" 432 mkdir -p "lib/$arch_libdir" 433elif [ -d "$srcdir/lib/$testdir/asm" ]; then 434 asm="$srcdir/lib/$testdir/asm" 435 mkdir -p "lib/$testdir" 436fi 437ln -sf "$asm" lib/asm 438mkdir -p lib/generated lib/libfdt 439 440# create the config 441cat <<EOF > config.mak 442# Shellcheck does not see these are used 443# shellcheck disable=SC2034 444# Shellcheck can give pointless quoting warnings for some commands 445# shellcheck disable=SC2209 446SRCDIR=$srcdir 447PREFIX=$prefix 448HOST=$host 449ARCH=$arch 450ARCH_NAME=$arch_name 451ARCH_LIBDIR=$arch_libdir 452PROCESSOR=$processor 453CC=$cc 454CFLAGS=$cflags 455LD=$cross_prefix$ld 456OBJCOPY=$cross_prefix$objcopy 457OBJDUMP=$cross_prefix$objdump 458READELF=$cross_prefix$readelf 459AR=$cross_prefix$ar 460ADDR2LINE=$cross_prefix$addr2line 461TEST_DIR=$testdir 462TEST_SUBDIR=$testsubdir 463FIRMWARE=$firmware 464ENDIAN=$endian 465PRETTY_PRINT_STACKS=$pretty_print_stacks 466ENVIRON_DEFAULT=$environ_default 467ERRATATXT=$erratatxt 468U32_LONG_FMT=$u32_long 469WA_DIVIDE=$wa_divide 470GENPROTIMG=${GENPROTIMG-genprotimg} 471HOST_KEY_DOCUMENT=$host_key_document 472CONFIG_DUMP=$enable_dump 473CONFIG_EFI=$efi 474EFI_DIRECT=$efi_direct 475CONFIG_WERROR=$werror 476GEN_SE_HEADER=$gen_se_header 477EOF 478if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 479 echo "TARGET=$target" >> config.mak 480fi 481 482cat <<EOF > lib/config.h 483#ifndef _CONFIG_H_ 484#define _CONFIG_H_ 485/* 486 * Generated file. DO NOT MODIFY. 487 * 488 */ 489 490EOF 491if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 492cat <<EOF >> lib/config.h 493 494#define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr} 495#define CONFIG_ERRATA_FORCE ${errata_force} 496 497EOF 498fi 499 500if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then 501cat <<EOF >> lib/config.h 502 503#define CONFIG_PAGE_SIZE _AC(${page_size}, UL) 504 505EOF 506elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 507cat <<EOF >> lib/config.h 508 509#define CONFIG_UART_EARLY_BASE 0x10000000 510 511EOF 512fi 513echo "#endif" >> lib/config.h 514