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