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