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