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