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 8# Return the default CPU type to compile for 9function get_default_processor() 10{ 11 local arch="$1" 12 13 case "$arch" in 14 "arm") 15 echo "cortex-a15" 16 ;; 17 "arm64") 18 echo "cortex-a57" 19 ;; 20 *) 21 echo "$arch" 22 ;; 23 esac 24} 25 26# Return the default CPU type to run on 27function get_default_qemu_cpu() 28{ 29 local arch="$1" 30 31 case "$arch" in 32 "arm") 33 echo "cortex-a15" 34 ;; 35 "arm64") 36 echo "cortex-a57" 37 ;; 38 "riscv32" | "riscv64") 39 echo "max" 40 ;; 41 esac 42} 43 44srcdir=$(cd "$(dirname "$0")"; pwd) 45prefix=/usr/local 46cc=gcc 47cflags= 48ld=ld 49objcopy=objcopy 50objdump=objdump 51readelf=readelf 52ar=ar 53addr2line=addr2line 54arch=$(uname -m | sed -e 's/i.86/i386/;s/arm64/aarch64/;s/arm.*/arm/;s/ppc64.*/ppc64/') 55host=$arch 56cross_prefix= 57endian="" 58pretty_print_stacks=yes 59environ_default=yes 60u32_long= 61wa_divide= 62target= 63errata_force=0 64erratatxt="$srcdir/errata.txt" 65host_key_document= 66gen_se_header= 67enable_dump=no 68page_size= 69earlycon= 70console= 71efi= 72efi_direct= 73target_cpu= 74 75# Enable -Werror by default for git repositories only (i.e. developer builds) 76if [ -e "$srcdir"/.git ]; then 77 werror=-Werror 78else 79 werror= 80fi 81 82usage() { 83 [ "$arch" = "aarch64" ] && arch="arm64" 84 [ -z "$processor" ] && processor=$(get_default_processor $arch) 85 cat <<-EOF 86 Usage: $0 [options] 87 88 Options include: 89 --arch=ARCH architecture to compile for ($arch). ARCH can be one of: 90 arm, arm64, i386, ppc64, riscv32, riscv64, s390x, x86_64 91 --processor=PROCESSOR processor to compile for ($processor) 92 --target-cpu=CPU the CPU model to run on. If left unset, the run script 93 selects the best value based on the host system and the 94 test configuration. 95 --target=TARGET target platform that the tests will be running on (qemu or 96 kvmtool, default is qemu) (arm/arm64 only) 97 --cross-prefix=PREFIX cross compiler prefix 98 --cc=CC c compiler to use ($cc) 99 --cflags=FLAGS extra options to be passed to the c compiler 100 --ld=LD ld linker to use ($ld) 101 --prefix=PREFIX where to install things ($prefix) 102 --endian=ENDIAN endianness to compile for (little or big, ppc64 only) 103 --[enable|disable]-pretty-print-stacks 104 enable or disable pretty stack printing (enabled by default) 105 --[enable|disable]-default-environ 106 enable or disable the generation of a default environ when 107 no environ is provided by the user (enabled by default) 108 --erratatxt=FILE specify a file to use instead of errata.txt. Use 109 '--erratatxt=' to ensure no file is used. 110 --host-key-document=HOST_KEY_DOCUMENT 111 Specify the machine-specific host-key document for creating 112 a PVM image with 'genprotimg' (s390x only) 113 --gen-se-header=GEN_SE_HEADER 114 Provide an executable to generate a PV header 115 requires --host-key-document. (s390x-snippets only) 116 --[enable|disable]-dump 117 Allow PV guests to be dumped. Requires at least z16. 118 (s390x only) 119 --page-size=PAGE_SIZE 120 Specify the page size (translation granule). PAGE_SIZE can be 121 4k [default], 16k, 64k for arm64. 122 4k [default], 64k for ppc64. 123 --earlycon=EARLYCON 124 Specify the UART name, type and address used for the earlycon (optional). 125 The specified address will overwrite the UART address set by 126 the --target option. EARLYCON can be one of (case sensitive): 127 uart[8250],mmio,ADDR 128 Specify an 8250 compatible UART at address ADDR. Supported 129 register stride is 8 bit only. 130 pl011,ADDR 131 pl011,mmio32,ADDR 132 Specify a PL011 compatible UART at address ADDR. Supported 133 register stride is 32 bit only. 134 (arm/arm64 and riscv32/riscv64 only) 135 --console=CONSOLE 136 Specify the device used for output (optional). 137 sbi Use SBI DBCN (riscv only) 138 --[enable|disable]-efi Boot and run from UEFI (disabled by default, x86_64 and arm64 only) 139 --[enable|disable]-werror 140 Select whether to compile with the -Werror compiler flag 141 --[enable|disable]-efi-direct 142 Select whether to run EFI tests directly with QEMU's -kernel 143 option. When not enabled, tests will be placed in an EFI file 144 system and run from the UEFI shell. Ignored when efi isn't enabled 145 and defaults to enabled when efi is enabled for riscv64. 146 (arm64 and riscv64 only) 147EOF 148 exit 1 149} 150 151optno=1 152argc=$# 153while [[ $optno -le $argc ]]; do 154 opt="$1"; shift 155 optno=$(( $optno + 1 )) 156 arg= 157 if [[ "$opt" = *=* ]]; then 158 arg="${opt#*=}" 159 opt="${opt%%=*}" 160 fi 161 case "$opt" in 162 --prefix) 163 prefix="$arg" 164 ;; 165 --arch) 166 arch="$arg" 167 ;; 168 --processor) 169 processor="$arg" 170 ;; 171 --target-cpu) 172 target_cpu="$arg" 173 ;; 174 --target) 175 target="$arg" 176 ;; 177 --cross-prefix) 178 cross_prefix="$arg" 179 ;; 180 --endian) 181 endian="$arg" 182 ;; 183 --cc) 184 cc="$arg" 185 cc_selected=yes 186 ;; 187 --cflags) 188 cflags="$arg" 189 ;; 190 --ld) 191 ld="$arg" 192 ;; 193 --enable-pretty-print-stacks) 194 pretty_print_stacks=yes 195 ;; 196 --disable-pretty-print-stacks) 197 pretty_print_stacks=no 198 ;; 199 --enable-default-environ) 200 environ_default=yes 201 ;; 202 --disable-default-environ) 203 environ_default=no 204 ;; 205 --erratatxt) 206 erratatxt= 207 [ "$arg" ] && erratatxt=$(eval realpath "$arg") 208 ;; 209 --host-key-document) 210 host_key_document="$arg" 211 ;; 212 --gen-se-header) 213 gen_se_header="$arg" 214 ;; 215 --enable-dump) 216 enable_dump=yes 217 ;; 218 --disable-dump) 219 enable_dump=no 220 ;; 221 --page-size) 222 page_size="$arg" 223 ;; 224 --earlycon) 225 earlycon="$arg" 226 ;; 227 --console) 228 console="$arg" 229 ;; 230 --enable-efi) 231 efi=y 232 ;; 233 --disable-efi) 234 efi=n 235 ;; 236 --enable-efi-direct) 237 efi_direct=y 238 ;; 239 --disable-efi-direct) 240 efi_direct=n 241 ;; 242 --enable-werror) 243 werror=-Werror 244 ;; 245 --disable-werror) 246 werror= 247 ;; 248 --help) 249 usage 250 ;; 251 *) 252 echo "Unknown option '$opt'" 253 echo 254 usage 255 ;; 256 esac 257done 258 259if [ -z "$cc_selected" ] && [ "$cross_prefix" ]; then 260 cc="$cross_prefix$cc" 261fi 262 263if [ -z "$efi" ] || [ "$efi" = "n" ]; then 264 [ "$efi_direct" = "y" ] && efi_direct= 265fi 266 267if [ -n "$host_key_document" ] && [ ! -f "$host_key_document" ]; then 268 echo "Host key document doesn't exist at the specified location." 269 exit 1 270fi 271 272if [ "$erratatxt" ] && [ ! -f "$erratatxt" ]; then 273 echo "erratatxt: $erratatxt does not exist or is not a regular file" 274 exit 1 275fi 276 277arch_name=$arch 278[ "$arch" = "aarch64" ] && arch="arm64" 279[ "$arch_name" = "arm64" ] && arch_name="aarch64" 280arch_libdir=$arch 281 282if [ "$arch" = "riscv" ]; then 283 echo "riscv32 or riscv64 must be specified" 284 exit 1 285fi 286 287if [ -z "$target" ]; then 288 target="qemu" 289else 290 if [ "$arch" != "arm64" ] && [ "$arch" != "arm" ]; then 291 echo "--target is not supported for $arch" 292 usage 293 fi 294fi 295 296if [ "$efi" ] && [ "$arch" != "x86_64" ] && 297 [ "$arch" != "arm64" ] && [ "$arch" != "riscv64" ]; then 298 echo "--[enable|disable]-efi is not supported for $arch" 299 usage 300fi 301 302if [ "$efi" ] && [ "$arch" = "riscv64" ] && [ -z "$efi_direct" ]; then 303 efi_direct=y 304fi 305 306if [ -z "$page_size" ]; then 307 if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 308 page_size="4096" 309 elif [ "$arch" = "ppc64" ]; then 310 page_size="65536" 311 fi 312else 313 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then 314 page_size=$(( ${page_size%?} * 1024 )) 315 fi 316 317 if [ "$arch" = "arm64" ]; then 318 if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] && 319 [ "$page_size" != "65536" ]; then 320 echo "arm64 doesn't support page size of $page_size" 321 usage 322 fi 323 if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then 324 echo "efi must use 4K pages" 325 exit 1 326 fi 327 elif [ "$arch" = "ppc64" ]; then 328 if [ "$page_size" != "4096" ] && [ "$page_size" != "65536" ]; then 329 echo "ppc64 doesn't support page size of $page_size" 330 usage 331 fi 332 else 333 echo "--page-size is not supported for $arch" 334 usage 335 fi 336fi 337 338if [ "$earlycon" ]; then 339 IFS=, read -r name type_addr addr <<<"$earlycon" 340 if [ "$name" != "uart" ] && [ "$name" != "uart8250" ] && [ "$name" != "pl011" ]; then 341 echo "unknown earlycon name: $name" 342 usage 343 fi 344 345 if [ "$name" = "pl011" ]; then 346 if [ -z "$addr" ]; then 347 addr=$type_addr 348 else 349 if [ "$type_addr" != "mmio32" ]; then 350 echo "unknown $name earlycon type: $type_addr" 351 usage 352 fi 353 fi 354 else 355 if [ "$type_addr" != "mmio" ]; then 356 echo "unknown $name earlycon type: $type_addr" 357 usage 358 fi 359 fi 360 361 if [ -z "$addr" ]; then 362 echo "missing $name earlycon address" 363 usage 364 fi 365 if [[ $addr =~ ^0(x|X)[0-9a-fA-F]+$ ]] || [[ $addr =~ ^[0-9]+$ ]]; then 366 uart_early_addr=$addr 367 else 368 echo "invalid $name earlycon address: $addr" 369 usage 370 fi 371fi 372 373# $arch will have changed when cross-compiling. 374[ -z "$processor" ] && processor=$(get_default_processor $arch) 375 376if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 377 testdir=x86 378elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 379 testdir=arm 380 if [ "$target" = "qemu" ]; then 381 : "${uart_early_addr:=0x9000000}" 382 elif [ "$target" = "kvmtool" ]; then 383 : "${uart_early_addr:=0x1000000}" 384 errata_force=1 385 else 386 echo "--target must be one of 'qemu' or 'kvmtool'!" 387 usage 388 fi 389elif [ "$arch" = "ppc64" ]; then 390 testdir=powerpc 391 firmware="$testdir/boot_rom.bin" 392 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then 393 echo "You must provide endianness (big or little)!" 394 usage 395 fi 396elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 397 testdir=riscv 398 arch_libdir=riscv 399 : "${uart_early_addr:=0x10000000}" 400elif [ "$arch" = "s390x" ]; then 401 testdir=s390x 402else 403 echo "arch $arch is not supported!" 404 arch= 405 usage 406fi 407if [ ! -d "$srcdir/$testdir" ]; then 408 echo "$srcdir/$testdir does not exist!" 409 exit 1 410fi 411 412if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then 413 ln -fs "$srcdir/$testdir/efi/run" $testdir-run 414elif [ -f "$srcdir/$testdir/run" ]; then 415 ln -fs "$srcdir/$testdir/run" $testdir-run 416fi 417 418testsubdir=$testdir 419if [ "$efi" = "y" ]; then 420 testsubdir=$testdir/efi 421fi 422 423# check if uint32_t needs a long format modifier 424cat << EOF > lib-test.c 425__UINT32_TYPE__ 426EOF 427u32_long=$("$cc" $cflags -E lib-test.c | grep -v '^#' | grep -q long && echo yes) 428rm -f lib-test.c 429 430# check if slash can be used for division 431if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then 432 cat << EOF > lib-test.S 433foo: 434 movl (8 / 2), %eax 435EOF 436 wa_divide=$("$cc" $cflags -c lib-test.S >/dev/null 2>&1 || echo yes) 437 rm -f lib-test.{o,S} 438fi 439 440# warn if enhanced getopt is unavailable 441getopt -T > /dev/null 442if [ $? -ne 4 ]; then 443 echo "Without enhanced getopt you won't be able to use run_tests.sh." 444 echo "Add it to your PATH?" 445fi 446 447# Are we in a separate build tree? If so, link the Makefile 448# and shared stuff so that 'make' and run_tests.sh work. 449if test ! -e Makefile; then 450 echo "linking Makefile..." 451 ln -s "$srcdir/Makefile" . 452 453 echo "linking tests..." 454 mkdir -p $testsubdir 455 ln -sf "$srcdir/$testdir/run" $testdir/ 456 if test "$testdir" != "$testsubdir"; then 457 ln -sf "$srcdir/$testsubdir/run" $testsubdir/ 458 fi 459 ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/ 460 ln -sf "$srcdir/run_tests.sh" 461 462 if [ -d "$srcdir/$testdir/snippets" ]; then 463 mkdir -p "$testdir/snippets/c" 464 fi 465 466 echo "linking scripts..." 467 ln -sf "$srcdir/scripts" 468fi 469 470# link lib/asm for the architecture 471rm -f lib/asm 472asm="asm-generic" 473if [ -d "$srcdir/lib/$arch/asm" ]; then 474 asm="$srcdir/lib/$arch/asm" 475 mkdir -p "lib/$arch" 476elif [ -d "$srcdir/lib/$arch_libdir/asm" ]; then 477 asm="$srcdir/lib/$arch_libdir/asm" 478 mkdir -p "lib/$arch_libdir" 479elif [ -d "$srcdir/lib/$testdir/asm" ]; then 480 asm="$srcdir/lib/$testdir/asm" 481 mkdir -p "lib/$testdir" 482fi 483ln -sf "$asm" lib/asm 484mkdir -p lib/generated lib/libfdt 485 486# create the config 487cat <<EOF > config.mak 488# Shellcheck does not see these are used 489# shellcheck disable=SC2034 490# Shellcheck can give pointless quoting warnings for some commands 491# shellcheck disable=SC2209 492SRCDIR=$srcdir 493PREFIX=$prefix 494HOST=$host 495ARCH=$arch 496ARCH_NAME=$arch_name 497ARCH_LIBDIR=$arch_libdir 498PROCESSOR=$processor 499TARGET_CPU=$target_cpu 500DEFAULT_QEMU_CPU=$(get_default_qemu_cpu $arch) 501CC=$cc 502CFLAGS=$cflags 503LD=$cross_prefix$ld 504OBJCOPY=$cross_prefix$objcopy 505OBJDUMP=$cross_prefix$objdump 506READELF=$cross_prefix$readelf 507AR=$cross_prefix$ar 508ADDR2LINE=$cross_prefix$addr2line 509TEST_DIR=$testdir 510TEST_SUBDIR=$testsubdir 511FIRMWARE=$firmware 512ENDIAN=$endian 513PRETTY_PRINT_STACKS=$pretty_print_stacks 514ENVIRON_DEFAULT=$environ_default 515ERRATATXT=$erratatxt 516U32_LONG_FMT=$u32_long 517WA_DIVIDE=$wa_divide 518GENPROTIMG=${GENPROTIMG-genprotimg} 519HOST_KEY_DOCUMENT=$host_key_document 520CONFIG_DUMP=$enable_dump 521CONFIG_EFI=$efi 522EFI_DIRECT=$efi_direct 523CONFIG_WERROR=$werror 524GEN_SE_HEADER=$gen_se_header 525EOF 526if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 527 echo "TARGET=$target" >> config.mak 528fi 529 530cat <<EOF > lib/config.h 531#ifndef _CONFIG_H_ 532#define _CONFIG_H_ 533/* 534 * Generated file. DO NOT MODIFY. 535 * 536 */ 537 538EOF 539if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then 540cat <<EOF >> lib/config.h 541 542#define CONFIG_UART_EARLY_BASE ${uart_early_addr} 543#define CONFIG_ERRATA_FORCE ${errata_force} 544 545EOF 546fi 547 548if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then 549cat <<EOF >> lib/config.h 550 551#define CONFIG_PAGE_SIZE _AC(${page_size}, UL) 552 553EOF 554elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then 555 echo "#define CONFIG_UART_EARLY_BASE ${uart_early_addr}" >> lib/config.h 556 [ "$console" = "sbi" ] && echo "#define CONFIG_SBI_CONSOLE" >> lib/config.h 557 echo >> lib/config.h 558fi 559echo "#endif" >> lib/config.h 560