Browse Source

Update kvm-unit-test from upstream

Fabian 6 years ago
parent
commit
1b6c1091ce
65 changed files with 3520 additions and 861 deletions
  1. 3 0
      tests/kvm-unit-tests/.gitignore
  2. 8 2
      tests/kvm-unit-tests/COPYRIGHT
  3. 7 0
      tests/kvm-unit-tests/MAINTAINERS
  4. 32 16
      tests/kvm-unit-tests/Makefile
  5. 57 25
      tests/kvm-unit-tests/configure
  6. 5 5
      tests/kvm-unit-tests/lib/alloc.c
  7. 14 9
      tests/kvm-unit-tests/lib/argv.c
  8. 2 2
      tests/kvm-unit-tests/lib/asm-generic/io.h
  9. 2 2
      tests/kvm-unit-tests/lib/asm-generic/page.h
  10. 15 1
      tests/kvm-unit-tests/lib/asm-generic/spinlock.h
  11. 4 0
      tests/kvm-unit-tests/lib/auxinfo.h
  12. 3 3
      tests/kvm-unit-tests/lib/bitops.h
  13. 25 2
      tests/kvm-unit-tests/lib/errata.h
  14. 32 5
      tests/kvm-unit-tests/lib/libcflat.h
  15. 1 1
      tests/kvm-unit-tests/lib/pci-edu.c
  16. 2 2
      tests/kvm-unit-tests/lib/pci-testdev.c
  17. 16 4
      tests/kvm-unit-tests/lib/pci.c
  18. 3 0
      tests/kvm-unit-tests/lib/pci.h
  19. 68 7
      tests/kvm-unit-tests/lib/printf.c
  20. 43 8
      tests/kvm-unit-tests/lib/report.c
  21. 6 0
      tests/kvm-unit-tests/lib/setjmp.h
  22. 7 0
      tests/kvm-unit-tests/lib/stack.c
  23. 6 0
      tests/kvm-unit-tests/lib/stack.h
  24. 48 0
      tests/kvm-unit-tests/lib/string.c
  25. 6 0
      tests/kvm-unit-tests/lib/string.h
  26. 1 0
      tests/kvm-unit-tests/lib/util.c
  27. 2 2
      tests/kvm-unit-tests/lib/virtio-mmio.c
  28. 2 2
      tests/kvm-unit-tests/lib/virtio-mmio.h
  29. 2 2
      tests/kvm-unit-tests/lib/virtio.c
  30. 2 2
      tests/kvm-unit-tests/lib/virtio.h
  31. 2 0
      tests/kvm-unit-tests/lib/x86/asm/page.h
  32. 1 6
      tests/kvm-unit-tests/lib/x86/asm/spinlock.h
  33. 12 20
      tests/kvm-unit-tests/lib/x86/desc.c
  34. 50 13
      tests/kvm-unit-tests/lib/x86/desc.h
  35. 1 1
      tests/kvm-unit-tests/lib/x86/fwcfg.c
  36. 8 8
      tests/kvm-unit-tests/lib/x86/intel-iommu.c
  37. 17 7
      tests/kvm-unit-tests/lib/x86/processor.h
  38. 21 16
      tests/kvm-unit-tests/lib/x86/smp.c
  39. 2 0
      tests/kvm-unit-tests/lib/x86/smp.h
  40. 160 23
      tests/kvm-unit-tests/lib/x86/vm.c
  41. 28 0
      tests/kvm-unit-tests/lib/x86/vm.h
  42. 1 1
      tests/kvm-unit-tests/x86/Makefile
  43. 22 20
      tests/kvm-unit-tests/x86/Makefile.common
  44. 1 1
      tests/kvm-unit-tests/x86/Makefile.i386
  45. 3 2
      tests/kvm-unit-tests/x86/Makefile.x86_64
  46. 3 3
      tests/kvm-unit-tests/x86/asyncpf.c
  47. 8 8
      tests/kvm-unit-tests/x86/cstart.S
  48. 6 6
      tests/kvm-unit-tests/x86/cstart64.S
  49. 1 1
      tests/kvm-unit-tests/x86/eventinj.c
  50. 55 10
      tests/kvm-unit-tests/x86/hyperv.c
  51. 33 7
      tests/kvm-unit-tests/x86/hyperv.h
  52. 7 22
      tests/kvm-unit-tests/x86/hyperv_clock.c
  53. 42 41
      tests/kvm-unit-tests/x86/hyperv_stimer.c
  54. 11 33
      tests/kvm-unit-tests/x86/hyperv_synic.c
  55. 11 22
      tests/kvm-unit-tests/x86/kvmclock_test.c
  56. 5 24
      tests/kvm-unit-tests/x86/msr.c
  57. 1 1
      tests/kvm-unit-tests/x86/pmu.c
  58. 0 51
      tests/kvm-unit-tests/x86/run
  59. 1 1
      tests/kvm-unit-tests/x86/tsc.c
  60. 0 226
      tests/kvm-unit-tests/x86/unittests.cfg
  61. 31 11
      tests/kvm-unit-tests/x86/vmexit.c
  62. 719 100
      tests/kvm-unit-tests/x86/vmx.c
  63. 201 16
      tests/kvm-unit-tests/x86/vmx.h
  64. 1631 57
      tests/kvm-unit-tests/x86/vmx_tests.c
  65. 1 1
      tests/kvm-unit-tests/x86/xsave.c

+ 3 - 0
tests/kvm-unit-tests/.gitignore

@@ -17,3 +17,6 @@ cscope.*
 /build-head
 /logs/
 /logs.old/
+/api/api-sample
+/api/dirty-log
+/api/dirty-log-perf

+ 8 - 2
tests/kvm-unit-tests/COPYRIGHT

@@ -1,4 +1,10 @@
 Copyright (C) 2006 Qumranet.
+Copyright (C) 2007-2017 by various contributors (see source files for details)
 
-The files in this directory and its subdirectories are licensed under the
-GNU LGPL, version 2.
+The kvm-unit-tests are free software; the whole package can be redistributed
+and/or modified under the terms of the GNU General Public License version 2
+as published by the Free Software Foundation.
+
+Many files in this directory and its subdirectories are also licensed under
+the less restrictive GNU LGPL, version 2, or other compatible licenses. See
+the individual files for details.

+ 7 - 0
tests/kvm-unit-tests/MAINTAINERS

@@ -76,6 +76,13 @@ F: powerpc/*
 F: lib/powerpc/*
 F: lib/ppc64/*
 
+S390X
+M: Thomas Huth <thuth@redhat.com>
+M: David Hildenbrand <david@redhat.com>
+L: kvm@vger.kernel.org
+F: s390x/*
+F: lib/s390x/*
+
 X86
 M: Paolo Bonzini <pbonzini@redhat.com>
 M: Radim Krčmář <rkrcmar@redhat.com>

+ 32 - 16
tests/kvm-unit-tests/Makefile

@@ -1,5 +1,5 @@
 
-SHELL := /bin/bash
+SHELL := /usr/bin/env bash
 
 ifeq ($(wildcard config.mak),)
 $(error run ./configure first. See ./configure -h)
@@ -7,8 +7,12 @@ endif
 
 include config.mak
 
+# Set search path for all sources
+VPATH = $(SRCDIR)
+
 libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
 ARCH_LIBDIRS := $(call libdirs-get,$(ARCH)) $(call libdirs-get,$(TEST_DIR))
+OBJDIRS := $(ARCH_LIBDIRS)
 
 DESTDIR := $(PREFIX)/share/kvm-unit-tests/
 
@@ -30,13 +34,15 @@ cflatobjs := \
 
 # libfdt paths
 LIBFDT_objdir = lib/libfdt
-LIBFDT_srcdir = lib/libfdt
+LIBFDT_srcdir = $(SRCDIR)/lib/libfdt
 LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
 LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
 LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
 
-#include architecure specific make rules
-include $(TEST_DIR)/Makefile
+OBJDIRS += $(LIBFDT_objdir)
+
+#include architecture specific make rules
+include $(SRCDIR)/$(TEST_DIR)/Makefile
 
 # cc-option
 # Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
@@ -44,8 +50,10 @@ include $(TEST_DIR)/Makefile
 cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
               > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
 
-CFLAGS += -g
-CFLAGS += $(autodepend-flags) -Wall -Werror
+COMMON_CFLAGS += -g $(autodepend-flags)
+COMMON_CFLAGS += -Wall -Wwrite-strings -Wclobbered -Wempty-body -Wuninitialized
+COMMON_CFLAGS += -Wignored-qualifiers -Wunused-but-set-parameter
+COMMON_CFLAGS += -Werror
 frame-pointer-flag=-f$(if $(KEEP_FRAME_POINTER),no-,)omit-frame-pointer
 fomit_frame_pointer := $(call cc-option, $(frame-pointer-flag), "")
 fnostack_protector := $(call cc-option, -fno-stack-protector, "")
@@ -53,34 +61,42 @@ fnostack_protector_all := $(call cc-option, -fno-stack-protector-all, "")
 wno_frame_address := $(call cc-option, -Wno-frame-address, "")
 fno_pic := $(call cc-option, -fno-pic, "")
 no_pie := $(call cc-option, -no-pie, "")
-CFLAGS += $(fomit_frame_pointer)
-CFLAGS += $(fno_stack_protector)
-CFLAGS += $(fno_stack_protector_all)
-CFLAGS += $(wno_frame_address)
-CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,)
-CFLAGS += $(fno_pic) $(no_pie)
+COMMON_CFLAGS += $(fomit_frame_pointer)
+COMMON_CFLAGS += $(fno_stack_protector)
+COMMON_CFLAGS += $(fno_stack_protector_all)
+COMMON_CFLAGS += $(wno_frame_address)
+COMMON_CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,)
+COMMON_CFLAGS += $(fno_pic) $(no_pie)
+
+CFLAGS += $(COMMON_CFLAGS)
+CFLAGS += -Wmissing-parameter-type -Wold-style-declaration -Woverride-init
 
-CXXFLAGS += $(CFLAGS)
+CXXFLAGS += $(COMMON_CFLAGS)
 
 autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
 
 LDFLAGS += $(CFLAGS)
-LDFLAGS += -pthread -lrt
 
 $(libcflat): $(cflatobjs)
 	$(AR) rcs $@ $^
 
 include $(LIBFDT_srcdir)/Makefile.libfdt
-$(LIBFDT_archive): CFLAGS += -ffreestanding -I lib -I lib/libfdt -Wno-sign-compare
+$(LIBFDT_archive): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/libfdt -Wno-sign-compare
 $(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
 	$(AR) rcs $@ $^
 
+
+# Build directory target
+.PHONY: directories
+directories:
+	@mkdir -p $(OBJDIRS)
+
 %.o: %.S
 	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
 
 -include */.*.d */*/.*.d
 
-all: $(shell git rev-parse --verify --short=8 HEAD >build-head 2>/dev/null)
+all: directories $(shell cd $(SRCDIR) && git rev-parse --verify --short=8 HEAD >$(PWD)/build-head 2>/dev/null)
 
 standalone: all
 	@scripts/mkstandalone.sh

+ 57 - 25
tests/kvm-unit-tests/configure

@@ -1,17 +1,20 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
+srcdir=$(cd "$(dirname "$0")"; pwd)
 prefix=/usr/local
 cc=gcc
+cxx=g++
 ld=ld
 objcopy=objcopy
 objdump=objdump
 ar=ar
 addr2line=addr2line
-arch=i386
+arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'`
 host=$arch
 cross_prefix=
 endian=""
 pretty_print_stacks=yes
+environ_default=yes
 u32_long=
 
 usage() {
@@ -23,11 +26,15 @@ usage() {
 	    --processor=PROCESSOR  processor to compile for ($arch)
 	    --cross-prefix=PREFIX  cross compiler prefix
 	    --cc=CC		   c compiler to use ($cc)
+	    --cxx=CXX		   c++ compiler to use ($cxx)
 	    --ld=LD		   ld linker to use ($ld)
 	    --prefix=PREFIX        where to install things ($prefix)
 	    --endian=ENDIAN        endianness to compile for (little or big, ppc64 only)
 	    --[enable|disable]-pretty-print-stacks
 	                           enable or disable pretty stack printing (enabled by default)
+	    --[enable|disable]-default-environ
+	                           enable or disable the generation of a default environ when
+	                           no environ is provided by the user (enabled by default)
 EOF
     exit 1
 }
@@ -58,6 +65,9 @@ while [[ "$1" = -* ]]; do
 	--cc)
 	    cc="$arg"
 	    ;;
+	--cxx)
+	    cxx="$arg"
+	    ;;
 	--ld)
 	    ld="$arg"
 	    ;;
@@ -67,6 +77,12 @@ while [[ "$1" = -* ]]; do
 	--disable-pretty-print-stacks)
 	    pretty_print_stacks=no
 	    ;;
+	--enable-default-environ)
+	    environ_default=yes
+	    ;;
+	--disable-default-environ)
+	    environ_default=no
+	    ;;
 	--help)
 	    usage
 	    ;;
@@ -102,12 +118,12 @@ elif [ "$arch" = "ppc64" ]; then
 else
     testdir=$arch
 fi
-if [ ! -d $testdir ]; then
+if [ ! -d "$srcdir/$testdir" ]; then
     echo "$testdir does not exist!"
     exit 1
 fi
-if [ -f $testdir/run ]; then
-    ln -fs $testdir/run $testdir-run
+if [ -f "$srcdir/$testdir/run" ]; then
+    ln -fs "$srcdir/$testdir/run" $testdir-run
 fi
 
 # check if uint32_t needs a long format modifier
@@ -117,42 +133,56 @@ EOF
 u32_long=$($cross_prefix$cc -E lib-test.c | grep -v '^#' | grep -q long && echo yes)
 rm -f lib-test.c
 
-# check for dependent 32 bit libraries
-if [ "$arch" != "arm" ]; then
-cat << EOF > lib_test.c
-#include <stdc++.h>
-#include <boost_thread-mt.h>
-#include <pthread.h>
-
-int main ()
-{}
-EOF
-$cc -m32 -o /dev/null lib_test.c &> /dev/null
-exit=$?
-if [ $exit -eq 0 ]; then
-    api=true
+# api/: check for dependent 32 bit libraries and gnu++11 support
+if [ "$testdir" = "x86" ]; then
+    echo 'int main () {}' > lib-test.c
+    $cc -m32 -o /dev/null -lstdc++ -lpthread -lrt lib-test.c &> /dev/null
+    exit=$?
+    $cxx -m32 -o /dev/null -std=gnu++11 lib-test.c &> /dev/null
+    if [ $? -eq 0 -a $exit -eq 0 ]; then
+        api=true
+    fi
+    rm -f lib-test.c
 fi
-rm -f lib_test.c
+
+# Are we in a separate build tree? If so, link the Makefile
+# and shared stuff so that 'make' and run_tests.sh work.
+if test ! -e Makefile; then
+    echo "linking Makefile..."
+    ln -s "$srcdir/Makefile" .
+
+    echo "linking tests..."
+    mkdir -p $testdir
+    ln -sf "$srcdir/$testdir/run" $testdir/
+    ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/
+    ln -sf "$srcdir/run_tests.sh"
+
+    echo "linking scripts..."
+    ln -sf "$srcdir/scripts"
 fi
 
 # link lib/asm for the architecture
 rm -f lib/asm
 asm=asm-generic
-if [ -d lib/$arch/asm ]; then
-	asm=$arch/asm
-elif [ -d lib/$testdir/asm ]; then
-	asm=$testdir/asm
+if [ -d "$srcdir/lib/$arch/asm" ]; then
+	asm="$srcdir/lib/$arch/asm"
+elif [ -d "$srcdir/lib/$testdir/asm" ]; then
+	asm="$srcdir/lib/$testdir/asm"
 fi
-ln -s $asm lib/asm
+mkdir -p lib
+ln -sf "$asm" lib/asm
+
 
 # create the config
 cat <<EOF > config.mak
+SRCDIR=$srcdir
 PREFIX=$prefix
 HOST=$host
 ARCH=$arch
 ARCH_NAME=$arch_name
 PROCESSOR=$processor
 CC=$cross_prefix$cc
+CXX=$cross_prefix$cxx
 LD=$cross_prefix$ld
 OBJCOPY=$cross_prefix$objcopy
 OBJDUMP=$cross_prefix$objdump
@@ -163,5 +193,7 @@ TEST_DIR=$testdir
 FIRMWARE=$firmware
 ENDIAN=$endian
 PRETTY_PRINT_STACKS=$pretty_print_stacks
+ENVIRON_DEFAULT=$environ_default
+ERRATATXT=errata.txt
 U32_LONG_FMT=$u32_long
 EOF

+ 5 - 5
tests/kvm-unit-tests/lib/alloc.c

@@ -25,7 +25,7 @@ void phys_alloc_show(void)
 	int i;
 
 	spin_lock(&lock);
-	printf("phys_alloc minimum alignment: 0x%" PRIx64 "\n",
+	printf("phys_alloc minimum alignment: %#" PRIx64 "\n",
 		(u64)align_min);
 	for (i = 0; i < nr_regions; ++i)
 		printf("%016" PRIx64 "-%016" PRIx64 " [%s]\n",
@@ -75,10 +75,10 @@ static phys_addr_t phys_alloc_aligned_safe(phys_addr_t size,
 	size += addr - base;
 
 	if ((top_safe - base) < size) {
-		printf("phys_alloc: requested=0x%" PRIx64
-		       " (align=0x%" PRIx64 "), "
-		       "need=0x%" PRIx64 ", but free=0x%" PRIx64 ". "
-		       "top=0x%" PRIx64 ", top_safe=0x%" PRIx64 "\n",
+		printf("phys_alloc: requested=%#" PRIx64
+		       " (align=%#" PRIx64 "), "
+		       "need=%#" PRIx64 ", but free=%#" PRIx64 ". "
+		       "top=%#" PRIx64 ", top_safe=%#" PRIx64 "\n",
 		       (u64)size_orig, (u64)align, (u64)size, top_safe - base,
 		       (u64)top, top_safe);
 		spin_unlock(&lock);

+ 14 - 9
tests/kvm-unit-tests/lib/argv.c

@@ -1,8 +1,16 @@
+/*
+ * Set up arguments for main() and prepare environment variables
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+
 #include "libcflat.h"
+#include "argv.h"
 #include "auxinfo.h"
 
 int __argc;
-char *__args;
+const char *__args;
 char *__argv[100];
 char *__environ[200];
 
@@ -15,7 +23,7 @@ static char *copy_ptr = args_copy;
 #define isalpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || (c) == '_')
 #define isalnum(c) (isalpha(c) || ((c) >= '0' && (c) <= '9'))
 
-static char *skip_blanks(char *p)
+static const char *skip_blanks(const char *p)
 {
 	while (isblank(*p))
 		++p;
@@ -24,7 +32,7 @@ static char *skip_blanks(char *p)
 
 void __setup_args(void)
 {
-	char *args = __args;
+	const char *args = __args;
 	char **argv = __argv + __argc;
 
 	while (*(args = skip_blanks(args)) != '\0') {
@@ -36,7 +44,7 @@ void __setup_args(void)
 	__argc = argv - __argv;
 }
 
-void setup_args(char *args)
+static void setup_args(const char *args)
 {
 	if (!args)
 		return;
@@ -45,16 +53,13 @@ void setup_args(char *args)
 	__setup_args();
 }
 
-void setup_args_progname(char *args)
+void setup_args_progname(const char *args)
 {
 	__argv[0] = copy_ptr;
 	strcpy(__argv[0], auxinfo.progname);
 	copy_ptr += strlen(auxinfo.progname) + 1;
 	++__argc;
-	if (args) {
-		__args = args;
-		__setup_args();
-	}
+	setup_args(args);
 }
 
 static char *env_eol(char *env)

+ 2 - 2
tests/kvm-unit-tests/lib/asm-generic/io.h

@@ -5,9 +5,9 @@
  *  adapted from the Linux kernel's include/asm-generic/io.h
  *  and arch/arm/include/asm/io.h
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 #include "libcflat.h"
 #include "asm/page.h"

+ 2 - 2
tests/kvm-unit-tests/lib/asm-generic/page.h

@@ -4,9 +4,9 @@
  * asm-generic/page.h
  *  adapted from the Linux kernel's include/asm-generic/page.h
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 
 #include <linux/const.h>

+ 15 - 1
tests/kvm-unit-tests/lib/asm-generic/spinlock.h

@@ -1,4 +1,18 @@
 #ifndef _ASM_GENERIC_SPINLOCK_H_
 #define _ASM_GENERIC_SPINLOCK_H_
-#error need architecture specific asm/spinlock.h
+
+struct spinlock {
+    unsigned int v;
+};
+
+static inline void spin_lock(struct spinlock *lock)
+{
+	while (__sync_lock_test_and_set(&lock->v, 1));
+}
+
+static inline void spin_unlock(struct spinlock *lock)
+{
+	__sync_lock_release(&lock->v);
+}
+
 #endif

+ 4 - 0
tests/kvm-unit-tests/lib/auxinfo.h

@@ -1,3 +1,7 @@
+/*
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
 #ifndef _AUXINFO_H_
 #define _AUXINFO_H_
 struct auxinfo {

+ 3 - 3
tests/kvm-unit-tests/lib/bitops.h

@@ -2,12 +2,12 @@
 #define _BITOPS_H_
 
 /*
- * Adapated from
+ * Adapted from
  *   include/linux/bitops.h
  *
- * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 
 #define BITS_PER_LONG_LONG	64

+ 25 - 2
tests/kvm-unit-tests/lib/errata.h

@@ -1,3 +1,9 @@
+/*
+ * errata functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
 #ifndef _ERRATA_H_
 #define _ERRATA_H_
 
@@ -7,16 +13,33 @@
 #define _ERRATA_RELAXED(erratum) errata_relaxed("ERRATA_" # erratum)
 #define ERRATA_RELAXED(erratum) _ERRATA_RELAXED(erratum)
 
+static inline bool errata_force(void)
+{
+	char *s = getenv("ERRATA_FORCE");
+
+	return s && (*s == '1' || *s == 'y' || *s == 'Y');
+}
+
 static inline bool errata(const char *erratum)
 {
-	char *s = getenv(erratum);
+	char *s;
+
+	if (errata_force())
+		return true;
+
+	s = getenv(erratum);
 
 	return s && (*s == '1' || *s == 'y' || *s == 'Y');
 }
 
 static inline bool errata_relaxed(const char *erratum)
 {
-	char *s = getenv(erratum);
+	char *s;
+
+	if (errata_force())
+		return true;
+
+	s = getenv(erratum);
 
 	return !(s && (*s == '0' || *s == 'n' || *s == 'N'));
 }

+ 32 - 5
tests/kvm-unit-tests/lib/libcflat.h

@@ -96,15 +96,25 @@ extern int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 extern int vprintf(const char *fmt, va_list va)
 					__attribute__((format(printf, 1, 0)));
 
+void report_prefix_pushf(const char *prefix_fmt, ...)
+					__attribute__((format(printf, 1, 2)));
 extern void report_prefix_push(const char *prefix);
 extern void report_prefix_pop(void);
-extern void report(const char *msg_fmt, bool pass, ...);
-extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...);
-extern void report_abort(const char *msg_fmt, ...);
-extern void report_skip(const char *msg_fmt, ...);
-extern void report_info(const char *msg_fmt, ...);
+extern void report(const char *msg_fmt, bool pass, ...)
+					__attribute__((format(printf, 1, 3)));
+extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...)
+					__attribute__((format(printf, 1, 4)));
+extern void report_abort(const char *msg_fmt, ...)
+					__attribute__((format(printf, 1, 2)));
+extern void report_skip(const char *msg_fmt, ...)
+					__attribute__((format(printf, 1, 2)));
+extern void report_info(const char *msg_fmt, ...)
+					__attribute__((format(printf, 1, 2)));
+extern void report_pass(void);
 extern int report_summary(void);
 
+bool simple_glob(const char *text, const char *pattern);
+
 extern void dump_stack(void);
 extern void dump_frame_stack(const void *instruction, const void *frame);
 
@@ -124,9 +134,26 @@ do {									\
 	}								\
 } while (0)
 
+#define assert_msg(cond, fmt, args...)					\
+do {									\
+	if (!(cond)) {							\
+		printf("%s:%d: assert failed: %s: " fmt "\n",		\
+		       __FILE__, __LINE__, #cond, ## args);		\
+		dump_stack();						\
+		abort();						\
+	}								\
+} while (0)
+
 static inline bool is_power_of_2(unsigned long n)
 {
 	return n && !(n & (n - 1));
 }
 
+/*
+ * One byte per bit, a ' between each group of 4 bits, and a null terminator.
+ */
+#define BINSTR_SZ (sizeof(unsigned long) * 8 + sizeof(unsigned long) * 2)
+void binstr(unsigned long x, char out[BINSTR_SZ]);
+void print_binstr(unsigned long x);
+
 #endif

+ 1 - 1
tests/kvm-unit-tests/lib/pci-edu.c

@@ -48,7 +48,7 @@ void edu_dma(struct pci_edu_dev *dev, iova_t iova,
 	assert(size <= EDU_DMA_SIZE_MAX);
 	assert(dev_offset < EDU_DMA_SIZE_MAX);
 
-	printf("edu device DMA start %s addr 0x%" PRIx64 " size 0x%lu off 0x%x\n",
+	printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n",
 	       from_device ? "FROM" : "TO",
 	       iova, (ulong)size, dev_offset);
 

+ 2 - 2
tests/kvm-unit-tests/lib/pci-testdev.c

@@ -131,8 +131,8 @@ static bool pci_testdev_one(struct pci_test_dev_hdr *test,
 	return (int)count == nr_writes;
 }
 
-void pci_testdev_print(struct pci_test_dev_hdr *test,
-		       struct pci_testdev_ops *ops)
+static void pci_testdev_print(struct pci_test_dev_hdr *test,
+			      struct pci_testdev_ops *ops)
 {
 	bool io = (ops == &pci_testdev_io_ops);
 	int i;

+ 16 - 4
tests/kvm-unit-tests/lib/pci.c

@@ -49,7 +49,7 @@ bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data)
 	assert(dev);
 
 	if (!dev->msi_offset) {
-		printf("MSI: dev 0x%x does not support MSI.\n", dev->bdf);
+		printf("MSI: dev %#x does not support MSI.\n", dev->bdf);
 		return false;
 	}
 
@@ -112,6 +112,8 @@ uint32_t pci_bar_mask(uint32_t bar)
 
 uint32_t pci_bar_get(struct pci_dev *dev, int bar_num)
 {
+	ASSERT_BAR_NUM(bar_num);
+
 	return pci_config_readl(dev->bdf, PCI_BASE_ADDRESS_0 +
 				bar_num * 4);
 }
@@ -134,6 +136,8 @@ static phys_addr_t __pci_bar_get_addr(struct pci_dev *dev, int bar_num)
 
 phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num)
 {
+	ASSERT_BAR_NUM(bar_num);
+
 	return dev->resource[bar_num];
 }
 
@@ -141,11 +145,19 @@ void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr)
 {
 	int off = PCI_BASE_ADDRESS_0 + bar_num * 4;
 
+	assert(addr != INVALID_PHYS_ADDR);
+	assert(dev->resource[bar_num] != INVALID_PHYS_ADDR);
+
+	ASSERT_BAR_NUM(bar_num);
+	if (pci_bar_is64(dev, bar_num))
+		ASSERT_BAR_NUM(bar_num + 1);
+	else
+		assert((addr >> 32) == 0);
+
 	pci_config_writel(dev->bdf, off, (uint32_t)addr);
 	dev->resource[bar_num] = addr;
 
 	if (pci_bar_is64(dev, bar_num)) {
-		assert(bar_num + 1 < PCI_BAR_NUM);
 		pci_config_writel(dev->bdf, off + 4, (uint32_t)(addr >> 32));
 		dev->resource[bar_num + 1] = dev->resource[bar_num];
 	}
@@ -283,10 +295,10 @@ static void pci_cap_print(struct pci_dev *dev, int cap_offset, int cap_id)
 		break;
 	}
 	default:
-		printf("\tcapability 0x%02x ", cap_id);
+		printf("\tcapability %#04x ", cap_id);
 		break;
 	}
-	printf("at offset 0x%02x\n", cap_offset);
+	printf("at offset %#04x\n", cap_offset);
 }
 
 void pci_dev_print(struct pci_dev *dev)

+ 3 - 0
tests/kvm-unit-tests/lib/pci.h

@@ -18,6 +18,9 @@ enum {
 #define PCI_BAR_NUM                     6
 #define PCI_DEVFN_MAX                   256
 
+#define ASSERT_BAR_NUM(bar_num)	\
+	do { assert(bar_num >= 0 && bar_num < PCI_BAR_NUM); } while (0)
+
 #define PCI_BDF_GET_DEVFN(x)            ((x) & 0xff)
 #define PCI_BDF_GET_BUS(x)              (((x) >> 8) & 0xff)
 

+ 68 - 7
tests/kvm-unit-tests/lib/printf.c

@@ -1,3 +1,10 @@
+/*
+ * libc printf and friends
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+
 #include "libcflat.h"
 
 #define BUFSZ 2000
@@ -11,6 +18,7 @@ typedef struct pstream {
 typedef struct strprops {
     char pad;
     int npad;
+    bool alternate;
 } strprops_t;
 
 static void addchar(pstream_t *p, char c)
@@ -22,7 +30,7 @@ static void addchar(pstream_t *p, char c)
     ++p->added;
 }
 
-void print_str(pstream_t *p, const char *s, strprops_t props)
+static void print_str(pstream_t *p, const char *s, strprops_t props)
 {
     const char *s_orig = s;
     int npad = props.npad;
@@ -50,7 +58,7 @@ void print_str(pstream_t *p, const char *s, strprops_t props)
 
 static char digits[16] = "0123456789abcdef";
 
-void print_int(pstream_t *ps, long long n, int base, strprops_t props)
+static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
 {
     char buf[sizeof(long) * 3 + 2], *p = buf;
     int s = 0, i;
@@ -84,10 +92,10 @@ void print_int(pstream_t *ps, long long n, int base, strprops_t props)
     print_str(ps, buf, props);
 }
 
-void print_unsigned(pstream_t *ps, unsigned long long n, int base,
-		    strprops_t props)
+static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
+			   strprops_t props)
 {
-    char buf[sizeof(long) * 3 + 1], *p = buf;
+    char buf[sizeof(long) * 3 + 3], *p = buf;
     int i;
 
     while (n) {
@@ -97,6 +105,18 @@ void print_unsigned(pstream_t *ps, unsigned long long n, int base,
 
     if (p == buf)
 	*p++ = '0';
+    else if (props.alternate && base == 16) {
+	if (props.pad == '0') {
+	    addchar(ps, '0');
+	    addchar(ps, 'x');
+
+	    if (props.npad > 0)
+		props.npad = MAX(props.npad - 2, 0);
+	} else {
+	    *p++ = 'x';
+	    *p++ = '0';
+	}
+    }
 
     for (i = 0; i < (p - buf) / 2; ++i) {
 	char tmp;
@@ -157,6 +177,9 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	case '\0':
 	    --fmt;
 	    break;
+	case '#':
+	    props.alternate = true;
+	    goto morefmt;
 	case '0':
 	    props.pad = '0';
 	    ++fmt;
@@ -169,6 +192,15 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	case 'l':
 	    ++nlong;
 	    goto morefmt;
+	case 't':
+	case 'z':
+	    /* Here we only care that sizeof(size_t) == sizeof(long).
+	     * On a 32-bit platform it doesn't matter that size_t is
+	     * typedef'ed to int or long; va_arg will work either way.
+	     * Same for ptrdiff_t (%td).
+	     */
+	    nlong = 1;
+	    goto morefmt;
 	case 'd':
 	    switch (nlong) {
 	    case 0:
@@ -209,7 +241,7 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	    }
 	    break;
 	case 'p':
-	    print_str(&s, "0x", props);
+	    props.alternate = true;
 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
 	    break;
 	case 's':
@@ -221,7 +253,6 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	}
     }
     *s.buffer = 0;
-    ++s.added;
     return s.added;
 }
 
@@ -259,3 +290,33 @@ int printf(const char *fmt, ...)
     puts(buf);
     return r;
 }
+
+void binstr(unsigned long x, char out[BINSTR_SZ])
+{
+	int i;
+	char *c;
+	int n;
+
+	n = sizeof(unsigned long) * 8;
+	i = 0;
+	c = &out[0];
+	for (;;) {
+		*c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
+		i++;
+
+		if (i == n) {
+			*c = '\0';
+			break;
+		}
+		if (i % 4 == 0)
+			*c++ = '\'';
+	}
+	assert(c + 1 - &out[0] == BINSTR_SZ);
+}
+
+void print_binstr(unsigned long x)
+{
+	char out[BINSTR_SZ];
+	binstr(x, out);
+	printf("%s", out);
+}

+ 43 - 8
tests/kvm-unit-tests/lib/report.c

@@ -17,14 +17,49 @@ static unsigned int tests, failures, xfailures, skipped;
 static char prefixes[256];
 static struct spinlock lock;
 
-void report_prefix_push(const char *prefix)
+#define PREFIX_DELIMITER ": "
+
+void report_pass(void)
+{
+	spin_lock(&lock);
+	tests++;
+	spin_unlock(&lock);
+}
+
+void report_prefix_pushf(const char *prefix_fmt, ...)
 {
+	va_list va;
+	unsigned int len;
+	int start;
+
 	spin_lock(&lock);
-	strcat(prefixes, prefix);
-	strcat(prefixes, ": ");
+
+	len = strlen(prefixes);
+	assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
+	start = len;
+
+	va_start(va, prefix_fmt);
+	len += vsnprintf(&prefixes[len], sizeof(prefixes) - len, prefix_fmt,
+			 va);
+	va_end(va);
+	assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
+
+	assert_msg(!strstr(&prefixes[start], PREFIX_DELIMITER),
+		   "Prefix \"%s\" contains delimiter \"" PREFIX_DELIMITER "\"",
+		   &prefixes[start]);
+
+	len += snprintf(&prefixes[len], sizeof(prefixes) - len,
+			PREFIX_DELIMITER);
+	assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
+
 	spin_unlock(&lock);
 }
 
+void report_prefix_push(const char *prefix)
+{
+	report_prefix_pushf("%s", prefix);
+}
+
 void report_prefix_pop(void)
 {
 	char *p, *q;
@@ -34,9 +69,9 @@ void report_prefix_pop(void)
 	if (!*prefixes)
 		return;
 
-	for (p = prefixes, q = strstr(p, ": ") + 2;
+	for (p = prefixes, q = strstr(p, PREFIX_DELIMITER) + 2;
 			*q;
-			p = q, q = strstr(p, ": ") + 2)
+			p = q, q = strstr(p, PREFIX_DELIMITER) + 2)
 		;
 	*p = '\0';
 
@@ -46,9 +81,9 @@ void report_prefix_pop(void)
 static void va_report(const char *msg_fmt,
 		bool pass, bool xfail, bool skip, va_list va)
 {
-	char *prefix = skip ? "SKIP"
-	                    : xfail ? (pass ? "XPASS" : "XFAIL")
-	                            : (pass ? "PASS"  : "FAIL");
+	const char *prefix = skip ? "SKIP"
+				  : xfail ? (pass ? "XPASS" : "XFAIL")
+					  : (pass ? "PASS"  : "FAIL");
 
 	spin_lock(&lock);
 

+ 6 - 0
tests/kvm-unit-tests/lib/setjmp.h

@@ -1,3 +1,9 @@
+/*
+ * setjmp/longjmp prototypes
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
 #ifndef LIBCFLAT_SETJMP_H
 #define LIBCFLAT_SETJMP_H 1
 

+ 7 - 0
tests/kvm-unit-tests/lib/stack.c

@@ -1,3 +1,10 @@
+/*
+ * stack related functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+
 #include <libcflat.h>
 #include <stack.h>
 

+ 6 - 0
tests/kvm-unit-tests/lib/stack.h

@@ -1,3 +1,9 @@
+/*
+ * Header for stack related functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
 #ifndef _STACK_H_
 #define _STACK_H_
 

+ 48 - 0
tests/kvm-unit-tests/lib/string.c

@@ -1,3 +1,10 @@
+/*
+ * libc string functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+
 #include "libcflat.h"
 
 unsigned long strlen(const char *buf)
@@ -173,3 +180,44 @@ char *getenv(const char *name)
     }
     return NULL;
 }
+
+/* Very simple glob matching. Allows '*' at beginning and end of pattern. */
+bool simple_glob(const char *text, const char *pattern)
+{
+	bool star_start = false;
+	bool star_end = false;
+	size_t n = strlen(pattern);
+	char copy[n + 1];
+
+	if (pattern[0] == '*') {
+		pattern += 1;
+		n -= 1;
+		star_start = true;
+	}
+
+	strcpy(copy, pattern);
+
+	if (n > 0 && pattern[n - 1] == '*') {
+		n -= 1;
+		copy[n] = '\0';
+		star_end = true;
+	}
+
+	if (star_start && star_end)
+		return strstr(text, copy);
+
+	if (star_end)
+		return strstr(text, copy) == text;
+
+	if (star_start) {
+		size_t text_len = strlen(text);
+		const char *suffix;
+
+		if (n > text_len)
+			return false;
+		suffix = text + text_len - n;
+		return !strcmp(suffix, copy);
+	}
+
+	return !strcmp(text, copy);
+}

+ 6 - 0
tests/kvm-unit-tests/lib/string.h

@@ -1,3 +1,9 @@
+/*
+ * Header for libc string functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
 #ifndef __STRING_H
 #define __STRING_H
 

+ 1 - 0
tests/kvm-unit-tests/lib/util.c

@@ -4,6 +4,7 @@
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
 #include <libcflat.h>
+#include "util.h"
 
 int parse_keyval(char *s, long *val)
 {

+ 2 - 2
tests/kvm-unit-tests/lib/virtio-mmio.c

@@ -1,9 +1,9 @@
 /*
  * virtqueue support adapted from the Linux kernel.
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 #include "libcflat.h"
 #include "devicetree.h"

+ 2 - 2
tests/kvm-unit-tests/lib/virtio-mmio.h

@@ -3,9 +3,9 @@
 /*
  * A minimal implementation of virtio-mmio. Adapted from the Linux Kernel.
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 #include "libcflat.h"
 #include "asm/page.h"

+ 2 - 2
tests/kvm-unit-tests/lib/virtio.c

@@ -1,9 +1,9 @@
 /*
  * virtqueue support adapted from the Linux kernel.
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 #include "libcflat.h"
 #include "asm/io.h"

+ 2 - 2
tests/kvm-unit-tests/lib/virtio.h

@@ -4,9 +4,9 @@
  * A minimal implementation of virtio.
  * Structures adapted from the Linux Kernel.
  *
- * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
- * This work is licensed under the terms of the GNU LGPL, version 2.
+ * This work is licensed under the terms of the GNU GPL, version 2.
  */
 #include "libcflat.h"
 

+ 2 - 0
tests/kvm-unit-tests/lib/x86/asm/page.h

@@ -31,6 +31,8 @@
 #define PT64_NX_MASK		(1ull << 63)
 #define PT_ADDR_MASK		GENMASK_ULL(51, 12)
 
+#define PT_AD_MASK              (PT_ACCESSED_MASK | PT_DIRTY_MASK)
+
 #ifdef __x86_64__
 #define	PAGE_LEVEL	4
 #define	PGDIR_WIDTH	9

+ 1 - 6
tests/kvm-unit-tests/lib/x86/asm/spinlock.h

@@ -1,11 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-struct spinlock {
-    int v;
-};
-
-void spin_lock(struct spinlock *lock);
-void spin_unlock(struct spinlock *lock);
+#include <asm-generic/spinlock.h>
 
 #endif

+ 12 - 20
tests/kvm-unit-tests/lib/x86/desc.c

@@ -69,7 +69,7 @@ static void unhandled_exception(struct ex_regs *regs, bool cpu)
 	       cpu ? "cpu " : "", regs->vector,
 	       exception_mnemonic(regs->vector), regs->rip);
 	if (regs->vector == 14)
-		printf("PF at 0x%lx addr 0x%lx\n", regs->rip, read_cr2());
+		printf("PF at %#lx addr %#lx\n", regs->rip, read_cr2());
 
 	printf("error_code=%04lx      rflags=%08lx      cs=%08lx\n"
 	       "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n"
@@ -117,13 +117,16 @@ static void check_exception_table(struct ex_regs *regs)
     unhandled_exception(regs, false);
 }
 
-static void (*exception_handlers[32])(struct ex_regs *regs);
+static handler exception_handlers[32];
 
-
-void handle_exception(u8 v, void (*func)(struct ex_regs *regs))
+handler handle_exception(u8 v, handler fn)
 {
+	handler old;
+
+	old = exception_handlers[v];
 	if (v < 32)
-		exception_handlers[v] = func;
+		exception_handlers[v] = fn;
+	return old;
 }
 
 #ifndef __x86_64__
@@ -262,19 +265,6 @@ bool exception_rflags_rf(void)
 static char intr_alt_stack[4096];
 
 #ifndef __x86_64__
-/*
- * GDT, with 6 entries:
- * 0x00 - NULL descriptor
- * 0x08 - Code segment (ring 0)
- * 0x10 - Data segment (ring 0)
- * 0x18 - Not present code segment (ring 0)
- * 0x20 - Code segment (ring 3)
- * 0x28 - Data segment (ring 3)
- * 0x30 - Interrupt task
- * 0x38 to 0x78 - Free to use for test cases
- * 0x80 - Primary task (CPU 0)
- */
-
 void set_gdt_entry(int sel, u32 base,  u32 limit, u8 access, u8 gran)
 {
 	int num = sel >> 3;
@@ -385,19 +375,21 @@ static void exception_handler(struct ex_regs *regs)
 	/* longjmp must happen after iret, so do not do it now.  */
 	exception = true;
 	regs->rip = (unsigned long)&exception_handler_longjmp;
+	regs->cs = read_cs();
 }
 
 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
 			void *data)
 {
+	handler old;
 	jmp_buf jmpbuf;
 	int ret;
 
-	handle_exception(ex, exception_handler);
+	old = handle_exception(ex, exception_handler);
 	ret = set_exception_jmpbuf(jmpbuf);
 	if (ret == 0)
 		trigger_func(data);
-	handle_exception(ex, NULL);
+	handle_exception(ex, old);
 	return ret;
 }
 

+ 50 - 13
tests/kvm-unit-tests/lib/x86/desc.h

@@ -20,6 +20,8 @@ struct ex_regs {
     unsigned long rflags;
 };
 
+typedef void (*handler)(struct ex_regs *regs);
+
 typedef struct {
 	u16 prev;
 	u16 res1;
@@ -85,24 +87,59 @@ typedef struct  __attribute__((packed)) {
 #define UD_VECTOR   6
 #define GP_VECTOR   13
 
-#define KERNEL_CS 0x08
-#define KERNEL_DS 0x10
-#define NP_SEL 0x18
-#define USER_CS 0x23
-#define USER_DS 0x2b
+/*
+ * selector     32-bit                        64-bit
+ * 0x00         NULL descriptor               NULL descriptor
+ * 0x08         ring-0 code segment (32-bit)  ring-0 code segment (64-bit)
+ * 0x10         ring-0 data segment (32-bit)  ring-0 data segment (32/64-bit)
+ * 0x18         ring-0 code segment (P=0)     ring-0 code segment (64-bit, P=0)
+ * 0x20         intr_alt_stack TSS            ring-0 code segment (32-bit)
+ * 0x28         ring-0 code segment (16-bit)  same
+ * 0x30         ring-0 data segment (16-bit)  same
+ * 0x38 (0x3b)  ring-3 code segment (32-bit)  same
+ * 0x40 (0x43)  ring-3 data segment (32-bit)  ring-3 data segment (32/64-bit)
+ * 0x48 (0x4b)  **unused**                    ring-3 code segment (64-bit)
+ * 0x50--0x78   free to use for test cases    same
+ * 0x80         primary TSS (CPU 0)           same
+ *
+ * Note that the same segment can be used for 32-bit and 64-bit data segments
+ * (the L bit is only defined for code segments)
+ *
+ * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
+ * and SYSRET instructions.
+ */
+
+#define KERNEL_CS   0x08
+#define KERNEL_DS   0x10
+#define NP_SEL      0x18
+#ifdef __x86_64__
+#define KERNEL_CS32 0x20
+#else
+#define TSS_INTR    0x20
+#endif
+#define KERNEL_CS16 0x28
+#define KERNEL_DS16 0x30
+#define USER_CS32   0x3b
+#define USER_DS     0x43
+#ifdef __x86_64__
+#define USER_CS64   0x4b
+#endif
+
+/* Synonyms */
+#define KERNEL_DS32 KERNEL_DS
+#define USER_DS32   USER_DS
+
 #ifdef __x86_64__
 #define KERNEL_CS64 KERNEL_CS
+#define USER_CS     USER_CS64
 #define KERNEL_DS64 KERNEL_DS
-#define KERNEL_CS32 0x30
-#define KERNEL_DS32 0x38
-#define KERNEL_CS16 0x40
-#define KERNEL_DS16 0x48
+#define USER_DS64   USER_DS
 #else
 #define KERNEL_CS32 KERNEL_CS
-#define KERNEL_DS32 KERNEL_DS
+#define USER_CS     USER_CS32
 #endif
-#define TSS_INTR 0x50
-#define FIRST_SPARE_SEL 0x58
+
+#define FIRST_SPARE_SEL 0x50
 #define TSS_MAIN 0x80
 
 typedef struct {
@@ -153,7 +190,7 @@ void set_idt_dpl(int vec, u16 dpl);
 void set_gdt_entry(int sel, u32 base,  u32 limit, u8 access, u8 gran);
 void set_intr_alt_stack(int e, void *fn);
 void print_current_tss_info(void);
-void handle_exception(u8 v, void (*func)(struct ex_regs *regs));
+handler handle_exception(u8 v, handler fn);
 
 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
 			void *data);

+ 1 - 1
tests/kvm-unit-tests/lib/x86/fwcfg.c

@@ -3,7 +3,7 @@
 
 static struct spinlock lock;
 
-uint64_t fwcfg_get_u(uint16_t index, int bytes)
+static uint64_t fwcfg_get_u(uint16_t index, int bytes)
 {
     uint64_t r = 0;
     uint8_t b;

+ 8 - 8
tests/kvm-unit-tests/lib/x86/intel-iommu.c

@@ -115,9 +115,9 @@ static void vtd_dump_init_info(void)
 	/* Major version >= 1 */
 	assert(((version >> 3) & 0xf) >= 1);
 
-	printf("VT-d version:   0x%x\n", version);
-	printf("     cap:       0x%016lx\n", vtd_readq(DMAR_CAP_REG));
-	printf("     ecap:      0x%016lx\n", vtd_readq(DMAR_ECAP_REG));
+	printf("VT-d version:   %#x\n", version);
+	printf("     cap:       %#018lx\n", vtd_readq(DMAR_CAP_REG));
+	printf("     ecap:      %#018lx\n", vtd_readq(DMAR_ECAP_REG));
 }
 
 static void vtd_setup_root_table(void)
@@ -127,7 +127,7 @@ static void vtd_setup_root_table(void)
 	memset(root, 0, PAGE_SIZE);
 	vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root));
 	vtd_gcmd_or(VTD_GCMD_ROOT);
-	printf("DMAR table address: 0x%016lx\n", vtd_root_table());
+	printf("DMAR table address: %#018lx\n", vtd_root_table());
 }
 
 static void vtd_setup_ir_table(void)
@@ -138,7 +138,7 @@ static void vtd_setup_ir_table(void)
 	/* 0xf stands for table size (2^(0xf+1) == 65536) */
 	vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf);
 	vtd_gcmd_or(VTD_GCMD_IR_TABLE);
-	printf("IR table address: 0x%016lx\n", vtd_ir_table());
+	printf("IR table address: %#018lx\n", vtd_ir_table());
 }
 
 static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
@@ -219,14 +219,14 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
 		ce->present = 1;
 		/* No error reporting yet */
 		ce->disable_fault_report = 1;
-		printf("allocated vt-d context entry for devfn 0x%x\n",
+		printf("allocated vt-d context entry for devfn %#x\n",
 		       devfn);
 	} else
 		slptptr = phys_to_virt(ce->slptptr << VTD_PAGE_SHIFT);
 
 	while (size) {
 		/* TODO: currently we only map 4K pages (level = 1) */
-		printf("map 4K page IOVA 0x%lx to 0x%lx (sid=0x%04x)\n",
+		printf("map 4K page IOVA %#lx to %#lx (sid=%#06x)\n",
 		       iova, pa, sid);
 		vtd_install_pte(slptptr, iova, pa, 1);
 		size -= VTD_PAGE_SIZE;
@@ -324,7 +324,7 @@ bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id)
 	msi_addr.head = 0xfee;
 	msi_data.subhandle = 0;
 
-	printf("%s: msi_addr=0x%" PRIx64 ", msi_data=0x%x\n", __func__,
+	printf("%s: msi_addr=%#" PRIx64 ", msi_data=%#x\n", __func__,
 		*(uint64_t *)&msi_addr, *(uint32_t *)&msi_data);
 
 	return pci_setup_msi(dev, *(uint64_t *)&msi_addr,

+ 17 - 7
tests/kvm-unit-tests/lib/x86/processor.h

@@ -30,13 +30,18 @@
 #define X86_CR4_SMAP   0x00200000
 #define X86_CR4_PKE    0x00400000
 
-#define X86_EFLAGS_CF  0x00000001
-#define X86_EFLAGS_PF  0x00000004
-#define X86_EFLAGS_AF  0x00000010
-#define X86_EFLAGS_ZF  0x00000040
-#define X86_EFLAGS_SF  0x00000080
-#define X86_EFLAGS_OF  0x00000800
-#define X86_EFLAGS_AC  0x00040000
+#define X86_EFLAGS_CF    0x00000001
+#define X86_EFLAGS_FIXED 0x00000002
+#define X86_EFLAGS_PF    0x00000004
+#define X86_EFLAGS_AF    0x00000010
+#define X86_EFLAGS_ZF    0x00000040
+#define X86_EFLAGS_SF    0x00000080
+#define X86_EFLAGS_TF    0x00000100
+#define X86_EFLAGS_IF    0x00000200
+#define X86_EFLAGS_DF    0x00000400
+#define X86_EFLAGS_OF    0x00000800
+#define X86_EFLAGS_NT    0x00004000
+#define X86_EFLAGS_AC    0x00040000
 
 #define X86_IA32_EFER          0xc0000080
 #define X86_EFER_LMA           (1UL << 8)
@@ -430,4 +435,9 @@ static inline void write_pkru(u32 pkru)
         : : "a" (eax), "c" (ecx), "d" (edx));
 }
 
+static inline bool is_canonical(u64 addr)
+{
+	return (s64)(addr << 16) >> 16 == addr;
+}
+
 #endif

+ 21 - 16
tests/kvm-unit-tests/lib/x86/smp.c

@@ -1,5 +1,7 @@
 
 #include <libcflat.h>
+#include "processor.h"
+#include "atomic.h"
 #include "smp.h"
 #include "apic.h"
 #include "fwcfg.h"
@@ -15,6 +17,7 @@ static void *volatile ipi_data;
 static volatile int ipi_done;
 static volatile bool ipi_wait;
 static int _cpu_count;
+static atomic_t active_cpus;
 
 static __attribute__((used)) void ipi()
 {
@@ -27,6 +30,7 @@ static __attribute__((used)) void ipi()
 	apic_write(APIC_EOI, 0);
     }
     function(data);
+    atomic_dec(&active_cpus);
     if (wait) {
 	ipi_done = 1;
 	apic_write(APIC_EOI, 0);
@@ -43,22 +47,6 @@ asm (
 #endif
      );
 
-void spin_lock(struct spinlock *lock)
-{
-    int v = 1;
-
-    do {
-	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
-    } while (v);
-    asm volatile ("" : : : "memory");
-}
-
-void spin_unlock(struct spinlock *lock)
-{
-    asm volatile ("" : : : "memory");
-    lock->v = 0;
-}
-
 int cpu_count(void)
 {
     return _cpu_count;
@@ -84,6 +72,7 @@ static void __on_cpu(int cpu, void (*function)(void *data), void *data,
     if (cpu == smp_id())
 	function(data);
     else {
+	atomic_inc(&active_cpus);
 	ipi_done = 0;
 	ipi_function = function;
 	ipi_data = data;
@@ -107,6 +96,21 @@ void on_cpu_async(int cpu, void (*function)(void *data), void *data)
     __on_cpu(cpu, function, data, 0);
 }
 
+void on_cpus(void (*function)(void *data), void *data)
+{
+    int cpu;
+
+    for (cpu = cpu_count() - 1; cpu >= 0; --cpu)
+        on_cpu_async(cpu, function, data);
+
+    while (cpus_active() > 1)
+        pause();
+}
+
+int cpus_active(void)
+{
+    return atomic_read(&active_cpus);
+}
 
 void smp_init(void)
 {
@@ -122,4 +126,5 @@ void smp_init(void)
     for (i = 1; i < cpu_count(); ++i)
         on_cpu(i, setup_smp_id, 0);
 
+    atomic_inc(&active_cpus);
 }

+ 2 - 0
tests/kvm-unit-tests/lib/x86/smp.h

@@ -6,7 +6,9 @@ void smp_init(void);
 
 int cpu_count(void);
 int smp_id(void);
+int cpus_active(void);
 void on_cpu(int cpu, void (*function)(void *data), void *data);
 void on_cpu_async(int cpu, void (*function)(void *data), void *data);
+void on_cpus(void (*function)(void *data), void *data);
 
 #endif

+ 160 - 23
tests/kvm-unit-tests/lib/x86/vm.c

@@ -7,12 +7,29 @@ static void *vfree_top = 0;
 
 static void free_memory(void *mem, unsigned long size)
 {
-    while (size >= PAGE_SIZE) {
-	*(void **)mem = free;
+	void *end;
+
+	assert_msg((unsigned long) mem % PAGE_SIZE == 0,
+		   "mem not page aligned: %p", mem);
+
+	assert_msg(size % PAGE_SIZE == 0, "size not page aligned: %#lx", size);
+
+	assert_msg(size == 0 || mem + size > mem,
+		   "mem + size overflow: %p + %#lx", mem, size);
+
+	if (size == 0) {
+		free = NULL;
+		return;
+	}
+
 	free = mem;
-	mem += PAGE_SIZE;
-	size -= PAGE_SIZE;
-    }
+	end = mem + size;
+	while (mem + PAGE_SIZE != end) {
+		*(void **)mem = (mem + PAGE_SIZE);
+		mem += PAGE_SIZE;
+	}
+
+	*(void **)mem = NULL;
 }
 
 void *alloc_page()
@@ -28,6 +45,63 @@ void *alloc_page()
     return p;
 }
 
+/*
+ * Allocates (1 << order) physically contiguous and naturally aligned pages.
+ * Returns NULL if there's no memory left.
+ */
+void *alloc_pages(unsigned long order)
+{
+	/* Generic list traversal. */
+	void *prev;
+	void *curr = NULL;
+	void *next = free;
+
+	/* Looking for a run of length (1 << order). */
+	unsigned long run = 0;
+	const unsigned long n = 1ul << order;
+	const unsigned long align_mask = (n << PAGE_SHIFT) - 1;
+	void *run_start = NULL;
+	void *run_prev = NULL;
+	unsigned long run_next_pa = 0;
+	unsigned long pa;
+
+	assert(order < sizeof(unsigned long) * 8);
+
+	for (;;) {
+		prev = curr;
+		curr = next;
+		next = curr ? *((void **) curr) : NULL;
+
+		if (!curr)
+			return 0;
+
+		pa = virt_to_phys(curr);
+
+		if (run == 0) {
+			if (!(pa & align_mask)) {
+				run_start = curr;
+				run_prev = prev;
+				run_next_pa = pa + PAGE_SIZE;
+				run = 1;
+			}
+		} else if (pa == run_next_pa) {
+			run_next_pa += PAGE_SIZE;
+			run += 1;
+		} else {
+			run = 0;
+		}
+
+		if (run == n) {
+			if (run_prev)
+				*((void **) run_prev) = next;
+			else
+				free = next;
+			return run_start;
+		}
+	}
+}
+
+
 void free_page(void *page)
 {
     *(void **)page = free;
@@ -65,23 +139,62 @@ unsigned long *install_pte(unsigned long *cr3,
     return &pt[offset];
 }
 
+/*
+ * Finds last PTE in the mapping of @virt that's at or above @lowest_level. The
+ * returned PTE isn't necessarily present, but its parent is.
+ */
+struct pte_search find_pte_level(unsigned long *cr3, void *virt,
+				 int lowest_level)
+{
+	unsigned long *pt = cr3, pte;
+	unsigned offset;
+	unsigned long shift;
+	struct pte_search r;
+
+	assert(lowest_level >= 1 && lowest_level <= PAGE_LEVEL);
+
+	for (r.level = PAGE_LEVEL;; --r.level) {
+		shift = (r.level - 1) * PGDIR_WIDTH + 12;
+		offset = ((unsigned long)virt >> shift) & PGDIR_MASK;
+		r.pte = &pt[offset];
+		pte = *r.pte;
+
+		if (!(pte & PT_PRESENT_MASK))
+			return r;
+
+		if ((r.level == 2 || r.level == 3) && (pte & PT_PAGE_SIZE_MASK))
+			return r;
+
+		if (r.level == lowest_level)
+			return r;
+
+		pt = phys_to_virt(pte & 0xffffffffff000ull);
+	}
+}
+
+/*
+ * Returns the leaf PTE in the mapping of @virt (i.e., 4K PTE or a present huge
+ * PTE). Returns NULL if no leaf PTE exists.
+ */
 unsigned long *get_pte(unsigned long *cr3, void *virt)
 {
-    int level;
-    unsigned long *pt = cr3, pte;
-    unsigned offset;
+	struct pte_search search;
 
-    for (level = PAGE_LEVEL; level > 1; --level) {
-	offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
-	pte = pt[offset];
-	if (!(pte & PT_PRESENT_MASK))
-	    return NULL;
-	if (level == 2 && (pte & PT_PAGE_SIZE_MASK))
-	    return &pt[offset];
-	pt = phys_to_virt(pte & PT_ADDR_MASK);
-    }
-    offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
-    return &pt[offset];
+	search = find_pte_level(cr3, virt, 1);
+	return found_leaf_pte(search) ? search.pte : NULL;
+}
+
+/*
+ * Returns the PTE in the mapping of @virt at the given level @pte_level.
+ * Returns NULL if the PT at @pte_level isn't present (i.e., the mapping at
+ * @pte_level - 1 isn't present).
+ */
+unsigned long *get_pte_level(unsigned long *cr3, void *virt, int pte_level)
+{
+	struct pte_search search;
+
+	search = find_pte_level(cr3, virt, pte_level);
+	return search.level == pte_level ? search.pte : NULL;
 }
 
 unsigned long *install_large_page(unsigned long *cr3,
@@ -99,6 +212,33 @@ unsigned long *install_page(unsigned long *cr3,
     return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0);
 }
 
+void install_pages(unsigned long *cr3, unsigned long phys, unsigned long len,
+		   void *virt)
+{
+	unsigned long max = (u64)len + (u64)phys;
+	assert(phys % PAGE_SIZE == 0);
+	assert((unsigned long) virt % PAGE_SIZE == 0);
+	assert(len % PAGE_SIZE == 0);
+
+	while (phys + PAGE_SIZE <= max) {
+		install_page(cr3, phys, virt);
+		phys += PAGE_SIZE;
+		virt = (char *) virt + PAGE_SIZE;
+	}
+}
+
+bool any_present_pages(unsigned long *cr3, void *virt, unsigned long len)
+{
+	unsigned long max = (unsigned long) virt + len;
+	unsigned long curr;
+
+	for (curr = (unsigned long) virt; curr < max; curr += PAGE_SIZE) {
+		unsigned long *ptep = get_pte(cr3, (void *) curr);
+		if (ptep && (*ptep & PT_PRESENT_MASK))
+			return true;
+	}
+	return false;
+}
 
 static void setup_mmu_range(unsigned long *cr3, unsigned long start,
 			    unsigned long len)
@@ -110,10 +250,7 @@ static void setup_mmu_range(unsigned long *cr3, unsigned long start,
 		install_large_page(cr3, phys, (void *)(ulong)phys);
 		phys += LARGE_PAGE_SIZE;
 	}
-	while (phys + PAGE_SIZE <= max) {
-		install_page(cr3, phys, (void *)(ulong)phys);
-		phys += PAGE_SIZE;
-	}
+	install_pages(cr3, phys, max - phys, (void *)(ulong)phys);
 }
 
 static void setup_mmu(unsigned long len)

+ 28 - 0
tests/kvm-unit-tests/lib/x86/vm.h

@@ -14,7 +14,27 @@ void *alloc_vpage(void);
 void *alloc_vpages(ulong nr);
 uint64_t virt_to_phys_cr3(void *mem);
 
+struct pte_search {
+	int level;
+	unsigned long *pte;
+};
+
+static inline bool found_huge_pte(struct pte_search search)
+{
+	return (search.level == 2 || search.level == 3) &&
+	       (*search.pte & PT_PRESENT_MASK) &&
+	       (*search.pte & PT_PAGE_SIZE_MASK);
+}
+
+static inline bool found_leaf_pte(struct pte_search search)
+{
+	return search.level == 1 || found_huge_pte(search);
+}
+
+struct pte_search find_pte_level(unsigned long *cr3, void *virt,
+				 int lowest_level);
 unsigned long *get_pte(unsigned long *cr3, void *virt);
+unsigned long *get_pte_level(unsigned long *cr3, void *virt, int pte_level);
 unsigned long *install_pte(unsigned long *cr3,
                            int pte_level,
                            void *virt,
@@ -22,10 +42,18 @@ unsigned long *install_pte(unsigned long *cr3,
                            unsigned long *pt_page);
 
 void *alloc_page();
+void *alloc_pages(unsigned long order);
 void free_page(void *page);
 
 unsigned long *install_large_page(unsigned long *cr3,unsigned long phys,
                                   void *virt);
 unsigned long *install_page(unsigned long *cr3, unsigned long phys, void *virt);
+void install_pages(unsigned long *cr3, unsigned long phys, unsigned long len,
+		   void *virt);
+bool any_present_pages(unsigned long *cr3, void *virt, unsigned long len);
 
+static inline void *current_page_table(void)
+{
+	return phys_to_virt(read_cr3());
+}
 #endif

+ 1 - 1
tests/kvm-unit-tests/x86/Makefile

@@ -1 +1 @@
-include $(TEST_DIR)/Makefile.$(ARCH)
+include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH)

+ 22 - 20
tests/kvm-unit-tests/x86/Makefile.common

@@ -1,6 +1,6 @@
 #This is a make file with common rules for both x86 & x86-64
 
-all: test_cases
+all: directories test_cases
 
 cflatobjs += lib/pci.o
 cflatobjs += lib/pci-edu.o
@@ -16,11 +16,13 @@ cflatobjs += lib/x86/isr.o
 cflatobjs += lib/x86/acpi.o
 cflatobjs += lib/x86/stack.o
 
+OBJDIRS += lib/x86
+
 $(libcflat): LDFLAGS += -nostdlib
-$(libcflat): CFLAGS += -ffreestanding -I lib
+$(libcflat): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I lib
 
-CFLAGS += -m$(bits)
-CFLAGS += -O1
+COMMON_CFLAGS += -m$(bits)
+COMMON_CFLAGS += -O1
 
 # stack.o relies on frame pointers.
 KEEP_FRAME_POINTER := y
@@ -31,8 +33,8 @@ libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
 .PRECIOUS: %.elf %.o
 
 FLATLIBS = lib/libcflat.a $(libgcc)
-%.elf: %.o $(FLATLIBS) x86/flat.lds $(cstart.o)
-	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,x86/flat.lds \
+%.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o)
+	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,$(SRCDIR)/x86/flat.lds \
 		$(filter %.o, $^) $(FLATLIBS)
 
 %.flat: %.elf
@@ -47,19 +49,20 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
                $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
                $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \
+               $(TEST_DIR)/hyperv_connections.flat \
 
 ifdef API
-tests-common += api/api-sample
-tests-common += api/dirty-log
-tests-common += api/dirty-log-perf
+tests-api = api/api-sample api/dirty-log api/dirty-log-perf
+
+OBJDIRS += api
 endif
 
-test_cases: $(tests-common) $(tests)
+test_cases: $(tests-common) $(tests) $(tests-api)
 
-$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
+$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/x86 -I lib
 
 $(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o
-	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
+	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(SRCDIR)/$(TEST_DIR)/realmode.lds $^
 
 $(TEST_DIR)/realmode.o: bits = 32
 
@@ -69,20 +72,19 @@ $(TEST_DIR)/hyperv_synic.elf: $(TEST_DIR)/hyperv.o
 
 $(TEST_DIR)/hyperv_stimer.elf: $(TEST_DIR)/hyperv.o
 
+$(TEST_DIR)/hyperv_connections.elf: $(TEST_DIR)/hyperv.o
+
 arch_clean:
 	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
-	$(TEST_DIR)/.*.d lib/x86/.*.d
+	$(TEST_DIR)/.*.d lib/x86/.*.d \
+	$(tests-api) api/*.o api/*.a api/.*.d
 
-api/%.o: CFLAGS += -m32
+api/%.o: CXXFLAGS += -m32 -std=gnu++11
 
-api/%: LDLIBS += -lstdc++ -lboost_thread -lpthread -lrt
+api/%: LDLIBS += -lstdc++ -lpthread -lrt
 api/%: LDFLAGS += -m32
 
 api/libapi.a: api/kvmxx.o api/identity.o api/exception.o api/memmap.o
 	$(AR) rcs $@ $^
 
-api/api-sample: api/api-sample.o api/libapi.a
-
-api/dirty-log: api/dirty-log.o api/libapi.a
-
-api/dirty-log-perf: api/dirty-log-perf.o api/libapi.a
+$(tests-api) : % : %.o api/libapi.a

+ 1 - 1
tests/kvm-unit-tests/x86/Makefile.i386

@@ -30,4 +30,4 @@ tests += $(TEST_DIR)/tscdeadline_latency.flat
 #tests += $(TEST_DIR)/intel-iommu.flat
 
 
-include $(TEST_DIR)/Makefile.common
+include $(SRCDIR)/$(TEST_DIR)/Makefile.common

+ 3 - 2
tests/kvm-unit-tests/x86/Makefile.x86_64

@@ -1,7 +1,7 @@
 cstart.o = $(TEST_DIR)/cstart64.o
 bits = 64
 ldarch = elf64-x86-64
-CFLAGS += -mno-red-zone
+COMMON_CFLAGS += -mno-red-zone
 
 cflatobjs += lib/x86/setjmp64.o
 cflatobjs += lib/x86/intel-iommu.o
@@ -12,12 +12,13 @@ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
 	  $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \
 	  $(TEST_DIR)/ioapic.flat $(TEST_DIR)/memory.flat \
 	  $(TEST_DIR)/pku.flat $(TEST_DIR)/hyperv_clock.flat
+tests += $(TEST_DIR)/syscall.flat
 tests += $(TEST_DIR)/svm.flat
 tests += $(TEST_DIR)/vmx.flat
 tests += $(TEST_DIR)/tscdeadline_latency.flat
 tests += $(TEST_DIR)/intel-iommu.flat
 
-include $(TEST_DIR)/Makefile.common
+include $(SRCDIR)/$(TEST_DIR)/Makefile.common
 
 $(TEST_DIR)/hyperv_clock.elf: $(TEST_DIR)/hyperv_clock.o
 

+ 3 - 3
tests/kvm-unit-tests/x86/asyncpf.c

@@ -52,13 +52,13 @@ static void pf_isr(struct ex_regs *r)
 
 	switch (reason) {
 		case 0:
-			report("unexpected #PF at %p", false, read_cr2());
+			report("unexpected #PF at %#lx", false, read_cr2());
 			break;
 		case KVM_PV_REASON_PAGE_NOT_PRESENT:
 			phys = virt_to_phys_cr3(virt);
 			install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0);
 			write_cr3(read_cr3());
-			report("Got not present #PF token %x virt addr %p phys addr %p",
+			report("Got not present #PF token %lx virt addr %p phys addr %#" PRIx64,
 					true, read_cr2(), virt, phys);
 			while(phys) {
 				safe_halt(); /* enables irq */
@@ -66,7 +66,7 @@ static void pf_isr(struct ex_regs *r)
 			}
 			break;
 		case KVM_PV_REASON_PAGE_READY:
-			report("Got present #PF token %x", true, read_cr2());
+			report("Got present #PF token %lx", true, read_cr2());
 			if ((uint32_t)read_cr2() == ~0)
 				break;
 			install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0);

+ 8 - 8
tests/kvm-unit-tests/x86/cstart.S

@@ -34,14 +34,14 @@ gdt32:
 	.quad 0x00cf9b000000ffff // flat 32-bit code segment
 	.quad 0x00cf93000000ffff // flat 32-bit data segment
 	.quad 0x00cf1b000000ffff // flat 32-bit code segment, not present
-	.quad 0x00cffb000000ffff // 64-bit code segment (user)
-	.quad 0x00cff3000000ffff // 64-bit data segment (user)
-
-	.quad 0			 // 10 spare selectors
-	.quad 0
-	.quad 0
-	.quad 0
-	.quad 0
+	.quad 0                  // TSS for task gates
+	.quad 0x008f9b000000FFFF // 16-bit code segment
+	.quad 0x008f93000000FFFF // 16-bit data segment
+	.quad 0x00cffb000000ffff // 32-bit code segment (user)
+	.quad 0x00cff3000000ffff // 32-bit data segment (user)
+	.quad 0                  // unused
+
+	.quad 0			 // 6 spare selectors
 	.quad 0
 	.quad 0
 	.quad 0

+ 6 - 6
tests/kvm-unit-tests/x86/cstart64.S

@@ -53,14 +53,14 @@ gdt64_desc:
 gdt64:
 	.quad 0
 	.quad 0x00af9b000000ffff // 64-bit code segment
-	.quad 0x00cf93000000ffff // 64-bit data segment
+	.quad 0x00cf93000000ffff // 32/64-bit data segment
 	.quad 0x00af1b000000ffff // 64-bit code segment, not present
-	.quad 0x00affb000000ffff // 64-bit code segment (user)
-	.quad 0x00cff3000000ffff // 64-bit data segment (user)
 	.quad 0x00cf9b000000ffff // 32-bit code segment
-	.quad 0x00cf92000000ffff // 32-bit data segment
-	.quad 0x008F9A000000FFFF // 16-bit code segment
-	.quad 0x008F92000000FFFF // 16-bit data segment
+	.quad 0x008f9b000000FFFF // 16-bit code segment
+	.quad 0x008f93000000FFFF // 16-bit data segment
+	.quad 0x00cffb000000ffff // 32-bit code segment (user)
+	.quad 0x00cff3000000ffff // 32/64-bit data segment (user)
+	.quad 0x00affb000000ffff // 64-bit code segment (user)
 
 	.quad 0			 // 6 spare selectors
 	.quad 0

+ 1 - 1
tests/kvm-unit-tests/x86/eventinj.c

@@ -171,7 +171,7 @@ static void nmi_iret_isr(struct ex_regs *r)
 static void tirq0(isr_regs_t *r)
 {
 	printf("irq0 running\n");
-	if (test_count != 0)
+	if (test_count == 1)
 		test_count++;
 	eoi();
 }

+ 55 - 10
tests/kvm-unit-tests/x86/hyperv.c

@@ -1,25 +1,70 @@
 #include "hyperv.h"
 #include "asm/io.h"
+#include "smp.h"
 
-static void synic_ctl(u8 ctl, u8 vcpu_id, u8 sint)
+enum {
+    HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
+    HV_TEST_DEV_SINT_ROUTE_DESTROY,
+    HV_TEST_DEV_SINT_ROUTE_SET_SINT,
+    HV_TEST_DEV_MSG_CONN_CREATE,
+    HV_TEST_DEV_MSG_CONN_DESTROY,
+    HV_TEST_DEV_EVT_CONN_CREATE,
+    HV_TEST_DEV_EVT_CONN_DESTROY,
+};
+
+static void synic_ctl(u32 ctl, u32 vcpu_id, u32 sint, u32 conn_id)
 {
-    outl((ctl << 16)|((vcpu_id) << 8)|sint, 0x3000);
+    outl((conn_id << 24) | (ctl << 16) | (vcpu_id << 8) | sint, 0x3000);
 }
 
-void synic_sint_create(int vcpu, int sint, int vec, bool auto_eoi)
+static void sint_enable(u8 sint, u8 vec, bool auto_eoi)
 {
     wrmsr(HV_X64_MSR_SINT0 + sint,
-          (u64)vec | ((auto_eoi) ? HV_SYNIC_SINT_AUTO_EOI : 0));
-    synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, vcpu, sint);
+          (u64)vec | (auto_eoi ? HV_SYNIC_SINT_AUTO_EOI : 0));
+}
+
+static void sint_disable(u8 sint)
+{
+    wrmsr(HV_X64_MSR_SINT0 + sint, 0xff | HV_SYNIC_SINT_MASKED);
+}
+
+void synic_sint_create(u8 sint, u8 vec, bool auto_eoi)
+{
+    synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, smp_id(), sint, 0);
+    sint_enable(sint, vec, auto_eoi);
+}
+
+void synic_sint_set(u8 vcpu, u8 sint)
+{
+    synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint, 0);
+}
+
+void synic_sint_destroy(u8 sint)
+{
+    sint_disable(sint);
+    synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, smp_id(), sint, 0);
+}
+
+void msg_conn_create(u8 sint, u8 vec, u8 conn_id)
+{
+    synic_ctl(HV_TEST_DEV_MSG_CONN_CREATE, smp_id(), sint, conn_id);
+    sint_enable(sint, vec, true);
+}
+
+void msg_conn_destroy(u8 sint, u8 conn_id)
+{
+    sint_disable(sint);
+    synic_ctl(HV_TEST_DEV_MSG_CONN_DESTROY, 0, 0, conn_id);
 }
 
-void synic_sint_set(int vcpu, int sint)
+void evt_conn_create(u8 sint, u8 vec, u8 conn_id)
 {
-    synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint);
+    synic_ctl(HV_TEST_DEV_EVT_CONN_CREATE, smp_id(), sint, conn_id);
+    sint_enable(sint, vec, true);
 }
 
-void synic_sint_destroy(int vcpu, int sint)
+void evt_conn_destroy(u8 sint, u8 conn_id)
 {
-    wrmsr(HV_X64_MSR_SINT0 + sint, 0xFF|HV_SYNIC_SINT_MASKED);
-    synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, vcpu, sint);
+    sint_disable(sint);
+    synic_ctl(HV_TEST_DEV_EVT_CONN_DESTROY, 0, 0, conn_id);
 }

+ 33 - 7
tests/kvm-unit-tests/x86/hyperv.h

@@ -10,6 +10,9 @@
 #define HV_X64_MSR_SYNIC_AVAILABLE              (1 << 2)
 #define HV_X64_MSR_SYNTIMER_AVAILABLE           (1 << 3)
 
+#define HV_X64_MSR_GUEST_OS_ID                  0x40000000
+#define HV_X64_MSR_HYPERCALL                    0x40000001
+
 #define HV_X64_MSR_TIME_REF_COUNT               0x40000020
 #define HV_X64_MSR_REFERENCE_TSC                0x40000021
 
@@ -155,10 +158,29 @@ struct hv_message_page {
         struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
 };
 
-enum {
-    HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
-    HV_TEST_DEV_SINT_ROUTE_DESTROY,
-    HV_TEST_DEV_SINT_ROUTE_SET_SINT
+#define HV_EVENT_FLAGS_COUNT	(256 * 8)
+
+struct hv_event_flags {
+	ulong flags[HV_EVENT_FLAGS_COUNT / (8 * sizeof(ulong))];
+};
+
+struct hv_event_flags_page {
+	struct hv_event_flags slot[HV_SYNIC_SINT_COUNT];
+};
+
+#define HV_X64_MSR_HYPERCALL_ENABLE             0x1
+
+#define HV_HYPERCALL_FAST               (1u << 16)
+
+#define HVCALL_POST_MESSAGE                     0x5c
+#define HVCALL_SIGNAL_EVENT                     0x5d
+
+struct hv_input_post_message {
+	u32 connectionid;
+	u32 reserved;
+	u32 message_type;
+	u32 payload_size;
+	u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
 };
 
 static inline bool synic_supported(void)
@@ -176,9 +198,13 @@ static inline bool hv_time_ref_counter_supported(void)
     return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
 }
 
-void synic_sint_create(int vcpu, int sint, int vec, bool auto_eoi);
-void synic_sint_set(int vcpu, int sint);
-void synic_sint_destroy(int vcpu, int sint);
+void synic_sint_create(u8 sint, u8 vec, bool auto_eoi);
+void synic_sint_set(u8 vcpu, u8 sint);
+void synic_sint_destroy(u8 sint);
+void msg_conn_create(u8 sint, u8 vec, u8 conn_id);
+void msg_conn_destroy(u8 sint, u8 conn_id);
+void evt_conn_create(u8 sint, u8 vec, u8 conn_id);
+void evt_conn_destroy(u8 sint, u8 conn_id);
 
 struct hv_reference_tsc_page {
         uint32_t tsc_sequence;

+ 7 - 22
tests/kvm-unit-tests/x86/hyperv_clock.c

@@ -19,7 +19,7 @@ static inline u64 scale_delta(u64 delta, u64 mul_frac)
 	u64 product, unused;
 
 	__asm__ (
-		"mul %3"
+		"mulq %3"
 		: "=d" (product), "=a" (unused) : "1" (delta), "rm" ((u64)mul_frac) );
 
 	return product;
@@ -55,7 +55,6 @@ uint64_t hv_clock_read(void)
 	return hvclock_tsc_to_ticks(&shadow, rdtsc());
 }
 
-atomic_t cpus_left;
 bool ok[MAX_CPU];
 uint64_t loops[MAX_CPU];
 
@@ -99,7 +98,6 @@ static void hv_clock_test(void *data)
 	if (!got_drift)
 		printf("delta on CPU %d was %d...%d\n", smp_id(), min_delta, max_delta);
 	barrier();
-	atomic_dec(&cpus_left);
 }
 
 static void check_test(int ncpus)
@@ -107,13 +105,7 @@ static void check_test(int ncpus)
 	int i;
 	bool pass;
 
-	atomic_set(&cpus_left, ncpus);
-	for (i = ncpus - 1; i >= 0; i--)
-		on_cpu_async(i, hv_clock_test, NULL);
-
-	/* Wait for the end of other vcpu */
-	while(atomic_read(&cpus_left))
-		;
+	on_cpus(hv_clock_test, NULL);
 
 	pass = true;
 	for (i = ncpus - 1; i >= 0; i--)
@@ -134,7 +126,6 @@ static void hv_perf_test(void *data)
 	} while(t < end);
 
 	loops[smp_id()] = local_loops;
-	atomic_dec(&cpus_left);
 }
 
 static void perf_test(int ncpus)
@@ -142,13 +133,7 @@ static void perf_test(int ncpus)
 	int i;
 	uint64_t total_loops;
 
-	atomic_set(&cpus_left, ncpus);
-	for (i = ncpus - 1; i >= 0; i--)
-		on_cpu_async(i, hv_perf_test, NULL);
-
-	/* Wait for the end of other vcpu */
-	while(atomic_read(&cpus_left))
-		;
+	on_cpus(hv_perf_test, NULL);
 
 	total_loops = 0;
 	for (i = ncpus - 1; i >= 0; i--)
@@ -167,6 +152,10 @@ int main(int ac, char **av)
 	setup_vm();
 	smp_init();
 
+	ncpus = cpu_count();
+	if (ncpus > MAX_CPU)
+		report_abort("number cpus exceeds %d", MAX_CPU);
+
 	hv_clock = alloc_page();
 	wrmsr(HV_X64_MSR_REFERENCE_TSC, (u64)(uintptr_t)hv_clock | 1);
 	report("MSR value after enabling",
@@ -195,10 +184,6 @@ int main(int ac, char **av)
 	       "TSC reference %" PRId64" (delta %" PRId64")\n",
 	       ref2, ref2 - ref1, tsc2, t2, t2 - t1);
 
-	ncpus = cpu_count();
-	if (ncpus > MAX_CPU)
-		ncpus = MAX_CPU;
-
 	check_test(ncpus);
 	perf_test(ncpus);
 

+ 42 - 41
tests/kvm-unit-tests/x86/hyperv_stimer.c

@@ -19,8 +19,6 @@
 #define SINT2_NUM 3
 #define ONE_MS_IN_100NS 10000
 
-static atomic_t g_cpus_comp_count;
-static int g_cpus_count;
 static struct spinlock g_synic_alloc_lock;
 
 struct stimer {
@@ -216,20 +214,13 @@ static void synic_disable(void)
     synic_free_page(svcpu->msg_page);
 }
 
-static void cpu_comp(void)
-{
-    atomic_inc(&g_cpus_comp_count);
-}
 
 static void stimer_test_prepare(void *ctx)
 {
-    int vcpu = smp_id();
-
     write_cr3((ulong)ctx);
     synic_enable();
-    synic_sint_create(vcpu, SINT1_NUM, SINT1_VEC, false);
-    synic_sint_create(vcpu, SINT2_NUM, SINT2_VEC, true);
-    cpu_comp();
+    synic_sint_create(SINT1_NUM, SINT1_VEC, false);
+    synic_sint_create(SINT2_NUM, SINT2_VEC, true);
 }
 
 static void stimer_test_periodic(int vcpu, struct stimer *timer1,
@@ -280,6 +271,35 @@ static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer)
     stimer_shutdown(timer);
 }
 
+static void stimer_test_one_shot_busy(int vcpu, struct stimer *timer)
+{
+    struct hv_message_page *msg_page = g_synic_vcpu[vcpu].msg_page;
+    struct hv_message *msg = &msg_page->sint_message[timer->sint];
+
+    msg->header.message_type = HVMSG_TIMER_EXPIRED;
+    wmb();
+
+    stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM);
+
+    do
+        rmb();
+    while (!msg->header.message_flags.msg_pending);
+
+    report("no timer fired while msg slot busy: vcpu %d",
+           !atomic_read(&timer->fire_count), vcpu);
+
+    msg->header.message_type = HVMSG_NONE;
+    wmb();
+    wrmsr(HV_X64_MSR_EOM, 0);
+
+    while (atomic_read(&timer->fire_count) < 1) {
+        pause();
+    }
+    report("timer resumed when msg slot released: vcpu %d", true, vcpu);
+
+    stimer_shutdown(timer);
+}
+
 static void stimer_test(void *ctx)
 {
     int vcpu = smp_id();
@@ -295,33 +315,17 @@ static void stimer_test(void *ctx)
     stimer_test_one_shot(vcpu, timer1);
     stimer_test_auto_enable_one_shot(vcpu, timer2);
     stimer_test_auto_enable_periodic(vcpu, timer1);
+    stimer_test_one_shot_busy(vcpu, timer1);
 
     irq_disable();
-    cpu_comp();
 }
 
 static void stimer_test_cleanup(void *ctx)
 {
-    int vcpu = smp_id();
-
     stimers_shutdown();
-    synic_sint_destroy(vcpu, SINT1_NUM);
-    synic_sint_destroy(vcpu, SINT2_NUM);
+    synic_sint_destroy(SINT1_NUM);
+    synic_sint_destroy(SINT2_NUM);
     synic_disable();
-    cpu_comp();
-}
-
-static void on_each_cpu_async_wait(void (*func)(void *ctx), void *ctx)
-{
-    int i;
-
-    atomic_set(&g_cpus_comp_count, 0);
-    for (i = 0; i < g_cpus_count; i++) {
-        on_cpu_async(i, func, ctx);
-    }
-    while (atomic_read(&g_cpus_comp_count) != g_cpus_count) {
-        pause();
-    }
 }
 
 static void stimer_test_all(void)
@@ -332,20 +336,17 @@ static void stimer_test_all(void)
     smp_init();
     enable_apic();
 
-    handle_irq(SINT1_VEC, stimer_isr);
-    handle_irq(SINT2_VEC, stimer_isr_auto_eoi);
-
     ncpus = cpu_count();
-    if (ncpus > MAX_CPUS) {
-        ncpus = MAX_CPUS;
-    }
-
+    if (ncpus > MAX_CPUS)
+        report_abort("number cpus exceeds %d", MAX_CPUS);
     printf("cpus = %d\n", ncpus);
-    g_cpus_count = ncpus;
 
-    on_each_cpu_async_wait(stimer_test_prepare, (void *)read_cr3());
-    on_each_cpu_async_wait(stimer_test, NULL);
-    on_each_cpu_async_wait(stimer_test_cleanup, NULL);
+    handle_irq(SINT1_VEC, stimer_isr);
+    handle_irq(SINT2_VEC, stimer_isr_auto_eoi);
+
+    on_cpus(stimer_test_prepare, (void *)read_cr3());
+    on_cpus(stimer_test, NULL);
+    on_cpus(stimer_test_cleanup, NULL);
 }
 
 int main(int ac, char **av)

+ 11 - 33
tests/kvm-unit-tests/x86/hyperv_synic.c

@@ -12,7 +12,6 @@
 #define MAX_CPUS 4
 
 static atomic_t isr_enter_count[MAX_CPUS];
-static atomic_t cpus_comp_count;
 
 static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
 {
@@ -69,7 +68,7 @@ static void synic_sints_prepare(int vcpu)
     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
         vec = sint_vecs[i].vec;
         auto_eoi = sint_vecs[i].auto_eoi;
-        synic_sint_create(vcpu, i, vec, auto_eoi);
+        synic_sint_create(i, vec, auto_eoi);
     }
 }
 
@@ -90,8 +89,8 @@ static void synic_test_prepare(void *ctx)
     }
     r = rdmsr(HV_X64_MSR_EOM);
     if (r != 0) {
-        report("Hyper-V SynIC test, EOM read 0x%llx", false, r);
-        goto ret;
+        report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r);
+        return;
     }
 
     wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) |
@@ -101,8 +100,6 @@ static void synic_test_prepare(void *ctx)
     wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
 
     synic_sints_prepare(smp_id());
-ret:
-    atomic_inc(&cpus_comp_count);
 }
 
 static void synic_sints_test(int dst_vcpu)
@@ -125,24 +122,20 @@ static void synic_test(void *ctx)
 
     irq_enable();
     synic_sints_test(dst_vcpu);
-    atomic_inc(&cpus_comp_count);
 }
 
 static void synic_test_cleanup(void *ctx)
 {
-    int vcpu = smp_id();
     int i;
 
     irq_enable();
     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
-        synic_sint_destroy(vcpu, i);
-        wrmsr(HV_X64_MSR_SINT0 + i, 0xFF|HV_SYNIC_SINT_MASKED);
+        synic_sint_destroy(i);
     }
 
     wrmsr(HV_X64_MSR_SCONTROL, 0);
     wrmsr(HV_X64_MSR_SIMP, 0);
     wrmsr(HV_X64_MSR_SIEFP, 0);
-    atomic_inc(&cpus_comp_count);
 }
 
 int main(int ac, char **av)
@@ -156,40 +149,25 @@ int main(int ac, char **av)
         smp_init();
         enable_apic();
 
-        synic_prepare_sint_vecs();
-
         ncpus = cpu_count();
-        if (ncpus > MAX_CPUS) {
-            ncpus = MAX_CPUS;
-        }
+        if (ncpus > MAX_CPUS)
+            report_abort("number cpus exceeds %d", MAX_CPUS);
         printf("ncpus = %d\n", ncpus);
 
-        atomic_set(&cpus_comp_count, 0);
-        for (i = 0; i < ncpus; i++) {
-            on_cpu_async(i, synic_test_prepare, (void *)read_cr3());
-        }
+        synic_prepare_sint_vecs();
+
         printf("prepare\n");
-        while (atomic_read(&cpus_comp_count) != ncpus) {
-            pause();
-        }
+        on_cpus(synic_test_prepare, (void *)read_cr3());
 
-        atomic_set(&cpus_comp_count, 0);
         for (i = 0; i < ncpus; i++) {
             printf("test %d -> %d\n", i, ncpus - 1 - i);
             on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
         }
-        while (atomic_read(&cpus_comp_count) != ncpus) {
+        while (cpus_active() > 1)
             pause();
-        }
 
-        atomic_set(&cpus_comp_count, 0);
-        for (i = 0; i < ncpus; i++) {
-            on_cpu_async(i, synic_test_cleanup, NULL);
-        }
         printf("cleanup\n");
-        while (atomic_read(&cpus_comp_count) != ncpus) {
-            pause();
-        }
+        on_cpus(synic_test_cleanup, NULL);
 
         ok = true;
         for (i = 0; i < ncpus; ++i) {

+ 11 - 22
tests/kvm-unit-tests/x86/kvmclock_test.c

@@ -17,7 +17,6 @@ struct test_info {
         u64 stalls;               /* stall count */
         long long worst;          /* worst warp */
         volatile cycle_t last;    /* last cycle seen by test */
-        atomic_t ncpus;           /* number of cpu in the test*/
         int check;                /* check cycle ? */
 };
 
@@ -78,29 +77,20 @@ static void kvm_clock_test(void *data)
                 if (!((unsigned long)i & 31))
                         asm volatile("rep; nop");
         }
-
-        atomic_dec(&hv_test_info->ncpus);
 }
 
-static int cycle_test(int ncpus, int check, struct test_info *ti)
+static int cycle_test(int check, struct test_info *ti)
 {
-        int i;
         unsigned long long begin, end;
 
         begin = rdtsc();
 
-        atomic_set(&ti->ncpus, ncpus);
         ti->check = check;
-        for (i = ncpus - 1; i >= 0; i--)
-                on_cpu_async(i, kvm_clock_test, (void *)ti);
-
-        /* Wait for the end of other vcpu */
-        while(atomic_read(&ti->ncpus))
-                ;
+        on_cpus(kvm_clock_test, ti);
 
         end = rdtsc();
 
-        printf("Total vcpus: %d\n", ncpus);
+        printf("Total vcpus: %d\n", cpu_count());
         printf("Test  loops: %ld\n", loops);
         if (check == 1) {
                 printf("Total warps:  %" PRId64 "\n", ti->warps);
@@ -129,9 +119,9 @@ int main(int ac, char **av)
 
         ncpus = cpu_count();
         if (ncpus > MAX_CPU)
-                ncpus = MAX_CPU;
-        for (i = 0; i < ncpus; ++i)
-                on_cpu(i, kvm_clock_init, (void *)0);
+                report_abort("number cpus exceeds %d", MAX_CPU);
+
+        on_cpus(kvm_clock_init, NULL);
 
         if (ac > 2) {
                 printf("Wallclock test, threshold %ld\n", threshold);
@@ -143,26 +133,25 @@ int main(int ac, char **av)
         printf("Check the stability of raw cycle ...\n");
         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
                           | PVCLOCK_RAW_CYCLE_BIT);
-        if (cycle_test(ncpus, 1, &ti[0]))
+        if (cycle_test(1, &ti[0]))
                 printf("Raw cycle is not stable\n");
         else
                 printf("Raw cycle is stable\n");
 
         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
         printf("Monotonic cycle test:\n");
-        nerr += cycle_test(ncpus, 1, &ti[1]);
+        nerr += cycle_test(1, &ti[1]);
 
         printf("Measure the performance of raw cycle ...\n");
         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
                           | PVCLOCK_RAW_CYCLE_BIT);
-        cycle_test(ncpus, 0, &ti[2]);
+        cycle_test(0, &ti[2]);
 
         printf("Measure the performance of adjusted cycle ...\n");
         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
-        cycle_test(ncpus, 0, &ti[3]);
+        cycle_test(0, &ti[3]);
 
-        for (i = 0; i < ncpus; ++i)
-                on_cpu(i, kvm_clock_clear, (void *)0);
+        on_cpus(kvm_clock_clear, NULL);
 
         return nerr > 0 ? 1 : 0;
 }

+ 5 - 24
tests/kvm-unit-tests/x86/msr.c

@@ -6,7 +6,7 @@
 
 struct msr_info {
     int index;
-    char *name;
+    const char *name;
     struct tc {
         int valid;
         unsigned long long value;
@@ -78,37 +78,20 @@ static void test_msr_rw(int msr_index, unsigned long long input, unsigned long l
 {
     unsigned long long r = 0;
     int index;
-    char *sptr;
+    const char *sptr;
     if ((index = find_msr_info(msr_index)) != -1) {
         sptr = msr_info[index].name;
     } else {
-        printf("couldn't find name for msr # 0x%x, skipping\n", msr_index);
+        printf("couldn't find name for msr # %#x, skipping\n", msr_index);
         return;
     }
     wrmsr(msr_index, input);
     r = rdmsr(msr_index);
     if (expected != r) {
-        printf("testing %s: output = 0x%x:0x%x expected = 0x%x:0x%x\n", sptr,
+        printf("testing %s: output = %#x:%#x expected = %#x:%#x\n", sptr,
                (u32)(r >> 32), (u32)r, (u32)(expected >> 32), (u32)expected);
     }
-    report(sptr, expected == r);
-}
-
-static void test_syscall_lazy_load(void)
-{
-#ifdef __x86_64__
-    extern void syscall_target();
-    u16 cs = read_cs(), ss = read_ss();
-    ulong tmp;
-
-    wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE);
-    wrmsr(MSR_LSTAR, (ulong)syscall_target);
-    wrmsr(MSR_STAR, (uint64_t)cs << 32);
-    asm volatile("pushf; syscall; syscall_target: popf" : "=c"(tmp) : : "r11");
-    write_ss(ss);
-    // will crash horribly if broken
-    report("MSR_*STAR eager loading", true);
-#endif
+    report("%s", expected == r, sptr);
 }
 
 int main(int ac, char **av)
@@ -124,8 +107,6 @@ int main(int ac, char **av)
         }
     }
 
-    test_syscall_lazy_load();
-
     return report_summary();
 }
 

+ 1 - 1
tests/kvm-unit-tests/x86/pmu.c

@@ -73,7 +73,7 @@ union cpuid10_edx {
 } edx;
 
 struct pmu_event {
-	char *name;
+	const char *name;
 	uint32_t unit_sel;
 	int min;
 	int max;

+ 0 - 51
tests/kvm-unit-tests/x86/run

@@ -1,51 +0,0 @@
-#!/bin/bash
-
-[ -z "$STANDALONE" ] && source scripts/arch-run.bash
-
-qemubinarysearch="${QEMU:-qemu-kvm qemu-system-x86_64}"
-
-for qemucmd in ${qemubinarysearch}
-do
-	unset QEMUFOUND
-	unset qemu
-	if ! [ -z "${QEMUFOUND=$(${qemucmd} --help 2>/dev/null | grep "QEMU")}" ] &&
-			${qemucmd} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
-	then
-		qemu="${qemucmd}"
-		break
-	fi
-done
-
-if      [ -z "${QEMUFOUND}" ]
-then
-	echo "A QEMU binary was not found, You can set a custom location by using the QEMU=<path> environment variable "
-	exit 2
-elif    [ -z "${qemu}" ]
-then
-	echo "No Qemu test device support found"
-	exit 2
-fi
-
-if
-	${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null;
-then
-	pci_testdev="-device pci-testdev"
-else
-	pci_testdev=""
-fi
-
-if
-	${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null;
-then
-	pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4"
-else
-	pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out"
-fi
-
-command="${qemu} -nodefaults -enable-kvm $pc_testdev -vnc none -serial stdio $pci_testdev $hyperv_testdev"
-[ -f "$ENV" ] && command+=" -initrd $ENV"
-command+=" -kernel"
-command="$(timeout_cmd) $command"
-echo ${command} "$@"
-
-run_qemu ${command} "$@"

+ 1 - 1
tests/kvm-unit-tests/x86/tsc.c

@@ -23,7 +23,7 @@ void test_rdtscp(u64 aux)
 
        wrmsr(MSR_TSC_AUX, aux);
        rdtscp(&ecx);
-       report("Test RDTSCP %d", ecx == aux, aux);
+       report("Test RDTSCP %" PRIu64, ecx == aux, aux);
 }
 
 int main()

+ 0 - 226
tests/kvm-unit-tests/x86/unittests.cfg

@@ -1,226 +0,0 @@
-##############################################################################
-# unittest configuration
-#
-# [unittest_name]
-# file = <name>.flat		# Name of the flat file to be used.
-# smp  = <num>			# Number of processors the VM will use
-#				# during this test. Use $MAX_SMP to use
-#				# the maximum the host supports. Defaults
-#				# to one.
-# extra_params = -append <params...>	# Additional parameters used.
-# arch = i386|x86_64			# Select one if the test case is
-#					# specific to only one.
-# groups = <group_name1> <group_name2> ...	# Used to identify test cases
-#						# with run_tests -g ...
-#						# Specify group_name=nodefault
-#						# to have test not run by
-#						# default
-# accel = kvm|tcg		# Optionally specify if test must run with
-#				# kvm or tcg. If not specified, then kvm will
-#				# be used when available.
-# timeout = <duration>		# Optionally specify a timeout.
-# check = <path>=<value> # check a file for a particular value before running
-#                        # a test. The check line can contain multiple files
-#                        # to check separated by a space but each check
-#                        # parameter needs to be of the form <path>=<value>
-##############################################################################
-
-[apic-split]
-file = apic.flat
-smp = 2
-extra_params = -cpu qemu64,+x2apic,+tsc-deadline -machine kernel_irqchip=split
-arch = x86_64
-
-[ioapic-split]
-file = ioapic.flat
-extra_params = -cpu qemu64 -machine kernel_irqchip=split
-arch = x86_64
-
-[apic]
-file = apic.flat
-smp = 2
-extra_params = -cpu qemu64,+x2apic,+tsc-deadline
-arch = x86_64
-timeout = 30
-
-[ioapic]
-file = ioapic.flat
-extra_params = -cpu qemu64
-arch = x86_64
-
-[smptest]
-file = smptest.flat
-smp = 2
-
-[smptest3]
-file = smptest.flat
-smp = 3
-
-[vmexit_cpuid]
-file = vmexit.flat
-extra_params = -append 'cpuid'
-groups = vmexit
-
-[vmexit_vmcall]
-file = vmexit.flat
-extra_params = -append 'vmcall'
-groups = vmexit
-
-[vmexit_mov_from_cr8]
-file = vmexit.flat
-extra_params = -append 'mov_from_cr8'
-groups = vmexit
-
-[vmexit_mov_to_cr8]
-file = vmexit.flat
-extra_params = -append 'mov_to_cr8'
-groups = vmexit
-
-[vmexit_inl_pmtimer]
-file = vmexit.flat
-extra_params = -append 'inl_from_pmtimer'
-groups = vmexit
-
-[vmexit_ipi]
-file = vmexit.flat
-smp = 2
-extra_params = -append 'ipi'
-groups = vmexit
-
-[vmexit_ipi_halt]
-file = vmexit.flat
-smp = 2
-extra_params = -append 'ipi_halt'
-groups = vmexit
-
-[vmexit_ple_round_robin]
-file = vmexit.flat
-extra_params = -append 'ple_round_robin'
-groups = vmexit
-
-[access]
-file = access.flat
-arch = x86_64
-
-[smap]
-file = smap.flat
-extra_params = -cpu host
-
-[pku]
-file = pku.flat
-arch = x86_64
-extra_params = -cpu host
-
-#[asyncpf]
-#file = asyncpf.flat
-
-[emulator]
-file = emulator.flat
-arch = x86_64
-
-[eventinj]
-file = eventinj.flat
-
-[hypercall]
-file = hypercall.flat
-
-[idt_test]
-file = idt_test.flat
-arch = x86_64
-
-#[init]
-#file = init.flat
-
-[msr]
-file = msr.flat
-
-[pmu]
-file = pmu.flat
-extra_params = -cpu host
-check = /proc/sys/kernel/nmi_watchdog=0
-
-[port80]
-file = port80.flat
-
-[realmode]
-file = realmode.flat
-
-[s3]
-file = s3.flat
-
-[sieve]
-file = sieve.flat
-
-[tsc]
-file = tsc.flat
-extra_params = -cpu kvm64,+rdtscp
-
-[tsc_adjust]
-file = tsc_adjust.flat
-extra_params = -cpu host
-
-[xsave]
-file = xsave.flat
-arch = x86_64
-extra_params = -cpu host
-
-[rmap_chain]
-file = rmap_chain.flat
-arch = x86_64
-
-[svm]
-file = svm.flat
-smp = 2
-extra_params = -cpu qemu64,+svm
-arch = x86_64
-
-[taskswitch]
-file = taskswitch.flat
-arch = i386
-groups = tasks
-
-[taskswitch2]
-file = taskswitch2.flat
-arch = i386
-groups = tasks
-
-[kvmclock_test]
-file = kvmclock_test.flat
-smp = 2
-extra_params = --append "10000000 `date +%s`"
-
-[pcid]
-file = pcid.flat
-extra_params = -cpu qemu64,+pcid
-arch = x86_64
-
-[vmx]
-file = vmx.flat
-extra_params = -cpu host,+vmx
-arch = x86_64
-
-[debug]
-file = debug.flat
-arch = x86_64
-
-[hyperv_synic]
-file = hyperv_synic.flat
-smp = 2
-extra_params = -cpu kvm64,hv_synic -device hyperv-testdev
-
-[hyperv_stimer]
-file = hyperv_stimer.flat
-smp = 2
-extra_params = -cpu kvm64,hv_time,hv_synic,hv_stimer -device hyperv-testdev
-
-[hyperv_clock]
-file = hyperv_clock.flat
-smp = 2
-extra_params = -cpu kvm64,hv_time
-
-[intel_iommu]
-file = intel-iommu.flat
-arch = x86_64
-timeout = 30
-smp = 4
-extra_params = -M q35,kernel-irqchip=split -device intel-iommu,intremap=on,eim=off -device edu

+ 31 - 11
tests/kvm-unit-tests/x86/vmexit.c

@@ -387,6 +387,32 @@ static bool pci_io_next(struct test *test)
 	return ret;
 }
 
+static int has_tscdeadline(void)
+{
+    uint32_t lvtt;
+
+    if (cpuid(1).c & (1 << 24)) {
+        lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR;
+        apic_write(APIC_LVTT, lvtt);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static void tscdeadline_immed(void)
+{
+	wrmsr(MSR_IA32_TSCDEADLINE, rdtsc());
+	asm volatile("nop");
+}
+
+static void tscdeadline(void)
+{
+	x = 0;
+	wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000);
+	while (x == 0) barrier();
+}
+
 static struct test tests[] = {
 	{ cpuid_test, "cpuid", .parallel = 1,  },
 	{ vmcall, "vmcall", .parallel = 1, },
@@ -399,6 +425,8 @@ static struct test tests[] = {
 	{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
 	{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
 	{ mov_dr, "mov_dr", .parallel = 1 },
+	{ tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, },
+	{ tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, },
 	{ self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
 	{ self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
 	{ self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
@@ -419,7 +447,6 @@ static struct test tests[] = {
 };
 
 unsigned iterations;
-static atomic_t nr_cpus_done;
 
 static void run_test(void *_func)
 {
@@ -428,8 +455,6 @@ static void run_test(void *_func)
 
     for (i = 0; i < iterations; ++i)
         func();
-
-    atomic_inc(&nr_cpus_done);
 }
 
 static bool do_test(struct test *test)
@@ -463,11 +488,7 @@ static bool do_test(struct test *test)
 			for (i = 0; i < iterations; ++i)
 				func();
 		} else {
-			atomic_set(&nr_cpus_done, 0);
-			for (i = cpu_count(); i > 0; i--)
-				on_cpu_async(i-1, run_test, func);
-			while (atomic_read(&nr_cpus_done) < cpu_count())
-				;
+			on_cpus(run_test, func);
 		}
 		t2 = rdtsc();
 	} while ((t2 - t1) < GOAL);
@@ -509,8 +530,7 @@ int main(int ac, char **av)
 	nr_cpus = cpu_count();
 
 	irq_enable();
-	for (i = cpu_count(); i > 0; i--)
-		on_cpu(i-1, enable_nx, 0);
+	on_cpus(enable_nx, NULL);
 
 	fadt = find_acpi_table_addr(FACP_SIGNATURE);
 	pm_tmr_blk = fadt->pm_tmr_blk;
@@ -524,7 +544,7 @@ int main(int ac, char **av)
 		membar = pcidev.resource[PCI_TESTDEV_BAR_MEM];
 		pci_test.memaddr = ioremap(membar, PAGE_SIZE);
 		pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO];
-		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
+		printf("pci-testdev at %#x membar %lx iobar %x\n",
 		       pcidev.bdf, membar, pci_test.iobar);
 	}
 

File diff suppressed because it is too large
+ 719 - 100
tests/kvm-unit-tests/x86/vmx.c


+ 201 - 16
tests/kvm-unit-tests/x86/vmx.h

@@ -5,6 +5,7 @@
 #include "processor.h"
 #include "bitops.h"
 #include "asm/page.h"
+#include "asm/io.h"
 
 struct vmcs {
 	u32 revision_id; /* vmcs revision identifier */
@@ -13,6 +14,11 @@ struct vmcs {
 	char data[0];
 };
 
+struct invvpid_operand {
+	u64 vpid;
+	u64 gla;
+};
+
 struct regs {
 	u64 rax;
 	u64 rcx;
@@ -54,6 +60,8 @@ struct vmx_test {
 	int (*entry_failure_handler)(struct vmentry_failure *failure);
 	struct vmcs *vmcs;
 	int exits;
+	/* Alternative test interface. */
+	void (*v2)(void);
 };
 
 union vmx_basic {
@@ -108,6 +116,7 @@ enum Encoding {
 	GUEST_SEL_LDTR		= 0x080cul,
 	GUEST_SEL_TR		= 0x080eul,
 	GUEST_INT_STATUS	= 0x0810ul,
+	GUEST_PML_INDEX         = 0x0812ul,
 
 	/* 16-Bit Host State Fields */
 	HOST_SEL_ES		= 0x0c00ul,
@@ -132,6 +141,9 @@ enum Encoding {
 	APIC_ACCS_ADDR		= 0x2014ul,
 	EPTP			= 0x201aul,
 	EPTP_HI			= 0x201bul,
+	PMLADDR                 = 0x200eul,
+	PMLADDR_HI              = 0x200ful,
+
 
 	/* 64-Bit Readonly Data Field */
 	INFO_PHYS_ADDR		= 0x2400ul,
@@ -317,7 +329,15 @@ enum Reason {
 	VMX_PREEMPT		= 52,
 	VMX_INVVPID		= 53,
 	VMX_WBINVD		= 54,
-	VMX_XSETBV		= 55
+	VMX_XSETBV		= 55,
+	VMX_APIC_WRITE		= 56,
+	VMX_RDRAND		= 57,
+	VMX_INVPCID		= 58,
+	VMX_VMFUNC		= 59,
+	VMX_RDSEED		= 61,
+	VMX_PML_FULL		= 62,
+	VMX_XSAVES		= 63,
+	VMX_XRSTORS		= 64,
 };
 
 enum Ctrl_exi {
@@ -375,6 +395,7 @@ enum Ctrl1 {
 	CPU_URG			= 1ul << 7,
 	CPU_WBINVD		= 1ul << 6,
 	CPU_RDRAND		= 1ul << 11,
+	CPU_PML                 = 1ul << 17,
 };
 
 enum Intr_type {
@@ -396,6 +417,37 @@ enum Intr_type {
 
 #define INTR_INFO_INTR_TYPE_SHIFT       8
 
+/*
+ * VM-instruction error numbers
+ */
+enum vm_instruction_error_number {
+	VMXERR_VMCALL_IN_VMX_ROOT_OPERATION = 1,
+	VMXERR_VMCLEAR_INVALID_ADDRESS = 2,
+	VMXERR_VMCLEAR_VMXON_POINTER = 3,
+	VMXERR_VMLAUNCH_NONCLEAR_VMCS = 4,
+	VMXERR_VMRESUME_NONLAUNCHED_VMCS = 5,
+	VMXERR_VMRESUME_AFTER_VMXOFF = 6,
+	VMXERR_ENTRY_INVALID_CONTROL_FIELD = 7,
+	VMXERR_ENTRY_INVALID_HOST_STATE_FIELD = 8,
+	VMXERR_VMPTRLD_INVALID_ADDRESS = 9,
+	VMXERR_VMPTRLD_VMXON_POINTER = 10,
+	VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID = 11,
+	VMXERR_UNSUPPORTED_VMCS_COMPONENT = 12,
+	VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT = 13,
+	VMXERR_VMXON_IN_VMX_ROOT_OPERATION = 15,
+	VMXERR_ENTRY_INVALID_EXECUTIVE_VMCS_POINTER = 16,
+	VMXERR_ENTRY_NONLAUNCHED_EXECUTIVE_VMCS = 17,
+	VMXERR_ENTRY_EXECUTIVE_VMCS_POINTER_NOT_VMXON_POINTER = 18,
+	VMXERR_VMCALL_NONCLEAR_VMCS = 19,
+	VMXERR_VMCALL_INVALID_VM_EXIT_CONTROL_FIELDS = 20,
+	VMXERR_VMCALL_INCORRECT_MSEG_REVISION_ID = 22,
+	VMXERR_VMXOFF_UNDER_DUAL_MONITOR_TREATMENT_OF_SMIS_AND_SMM = 23,
+	VMXERR_VMCALL_INVALID_SMM_MONITOR_FEATURES = 24,
+	VMXERR_ENTRY_INVALID_VM_EXECUTION_CONTROL_FIELDS_IN_EXECUTIVE_VMCS = 25,
+	VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS = 26,
+	VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
+};
+
 #define SAVE_GPR				\
 	"xchg %rax, regs\n\t"			\
 	"xchg %rbx, regs+0x8\n\t"		\
@@ -451,10 +503,14 @@ enum Intr_type {
 #define VMX_TEST_VMEXIT		1
 #define VMX_TEST_EXIT		2
 #define VMX_TEST_RESUME		3
+#define VMX_TEST_VMABORT	4
+#define VMX_TEST_VMSKIP		5
 
 #define HYPERCALL_BIT		(1ul << 12)
 #define HYPERCALL_MASK		0xFFF
 #define HYPERCALL_VMEXIT	0x1
+#define HYPERCALL_VMABORT	0x2
+#define HYPERCALL_VMSKIP	0x3
 
 #define EPTP_PG_WALK_LEN_SHIFT	3ul
 #define EPTP_AD_FLAG		(1ul << 6)
@@ -487,8 +543,10 @@ enum Intr_type {
 #define EPT_CAP_INVEPT_ALL	(1ull << 26)
 #define EPT_CAP_AD_FLAG		(1ull << 21)
 #define VPID_CAP_INVVPID	(1ull << 32)
-#define VPID_CAP_INVVPID_SINGLE	(1ull << 41)
-#define VPID_CAP_INVVPID_ALL	(1ull << 42)
+#define VPID_CAP_INVVPID_ADDR   (1ull << 40)
+#define VPID_CAP_INVVPID_CXTGLB (1ull << 41)
+#define VPID_CAP_INVVPID_ALL    (1ull << 42)
+#define VPID_CAP_INVVPID_CXTLOC	(1ull << 43)
 
 #define PAGE_SIZE_2M		(512 * PAGE_SIZE)
 #define PAGE_SIZE_1G		(512 * PAGE_SIZE_2M)
@@ -506,19 +564,23 @@ enum Intr_type {
 #define EPT_VLT_PERM_RD		(1 << 3)
 #define EPT_VLT_PERM_WR		(1 << 4)
 #define EPT_VLT_PERM_EX		(1 << 5)
+#define EPT_VLT_PERMS		(EPT_VLT_PERM_RD | EPT_VLT_PERM_WR | \
+				 EPT_VLT_PERM_EX)
 #define EPT_VLT_LADDR_VLD	(1 << 7)
 #define EPT_VLT_PADDR		(1 << 8)
 
 #define MAGIC_VAL_1		0x12345678ul
 #define MAGIC_VAL_2		0x87654321ul
 #define MAGIC_VAL_3		0xfffffffful
+#define MAGIC_VAL_4		0xdeadbeeful
 
 #define INVEPT_SINGLE		1
 #define INVEPT_GLOBAL		2
 
-#define INVVPID_SINGLE_ADDRESS	0
-#define INVVPID_SINGLE		1
+#define INVVPID_ADDR            0
+#define INVVPID_CONTEXT_GLOBAL	1
 #define INVVPID_ALL		2
+#define INVVPID_CONTEXT_LOCAL	3
 
 #define ACTV_ACTIVE		0
 #define ACTV_HLT		1
@@ -532,10 +594,41 @@ extern union vmx_ctrl_msr ctrl_exit_rev;
 extern union vmx_ctrl_msr ctrl_enter_rev;
 extern union vmx_ept_vpid  ept_vpid;
 
+extern u64 *vmxon_region;
+
 void vmx_set_test_stage(u32 s);
 u32 vmx_get_test_stage(void);
 void vmx_inc_test_stage(void);
 
+static int vmx_on(void)
+{
+	bool ret;
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+	asm volatile ("push %1; popf; vmxon %2; setbe %0\n\t"
+		      : "=q" (ret) : "q" (rflags), "m" (vmxon_region) : "cc");
+	return ret;
+}
+
+static int vmx_off(void)
+{
+	bool ret;
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+
+	asm volatile("push %1; popf; vmxoff; setbe %0\n\t"
+		     : "=q"(ret) : "q" (rflags) : "cc");
+	return ret;
+}
+
+static inline int make_vmcs_current(struct vmcs *vmcs)
+{
+	bool ret;
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+
+	asm volatile ("push %1; popf; vmptrld %2; setbe %0"
+		      : "=q" (ret) : "q" (rflags), "m" (vmcs) : "cc");
+	return ret;
+}
+
 static inline int vmcs_clear(struct vmcs *vmcs)
 {
 	bool ret;
@@ -553,6 +646,25 @@ static inline u64 vmcs_read(enum Encoding enc)
 	return val;
 }
 
+static inline int vmcs_read_checking(enum Encoding enc, u64 *value)
+{
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+	u64 encoding = enc;
+	u64 val;
+
+	asm volatile ("shl $8, %%rax;"
+		      "sahf;"
+		      "vmread %[encoding], %[val];"
+		      "lahf;"
+		      "shr $8, %%rax"
+		      : /* output */ [val]"=rm"(val), "+a"(rflags)
+		      : /* input */ [encoding]"r"(encoding)
+		      : /* clobber */ "cc");
+
+	*value = val;
+	return rflags & (X86_EFLAGS_CF | X86_EFLAGS_ZF);
+}
+
 static inline int vmcs_write(enum Encoding enc, u64 val)
 {
 	bool ret;
@@ -564,10 +676,12 @@ static inline int vmcs_write(enum Encoding enc, u64 val)
 static inline int vmcs_save(struct vmcs **vmcs)
 {
 	bool ret;
+	unsigned long pa;
 	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
 
-	asm volatile ("push %1; popf; vmptrst %2; setbe %0"
-		      : "=q" (ret) : "q" (rflags), "m" (*vmcs) : "cc");
+	asm volatile ("push %2; popf; vmptrst %1; setbe %0"
+		      : "=q" (ret), "=m" (pa) : "r" (rflags) : "cc");
+	*vmcs = (pa == -1ull) ? NULL : phys_to_virt(pa);
 	return ret;
 }
 
@@ -584,21 +698,18 @@ static inline bool invept(unsigned long type, u64 eptp)
 	return ret;
 }
 
-static inline bool invvpid(unsigned long type, u16 vpid, u64 gva)
+static inline bool invvpid(unsigned long type, u64 vpid, u64 gla)
 {
 	bool ret;
 	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
 
-	struct {
-		u64 vpid : 16;
-		u64 rsvd : 48;
-		u64 gva;
-	} operand = {vpid, 0, gva};
+	struct invvpid_operand operand = {vpid, gla};
 	asm volatile("push %1; popf; invvpid %2, %3; setbe %0"
 		     : "=q" (ret) : "r" (rflags), "m"(operand),"r"(type) : "cc");
 	return ret;
 }
 
+const char *exit_reason_description(u64 reason);
 void print_vmexit_info();
 void print_vmentry_failure_info(struct vmentry_failure *failure);
 void ept_sync(int type, u64 eptp);
@@ -614,9 +725,83 @@ void install_ept(unsigned long *pml4, unsigned long phys,
 		unsigned long guest_addr, u64 perm);
 void setup_ept_range(unsigned long *pml4, unsigned long start,
 		     unsigned long len, int map_1g, int map_2m, u64 perm);
-unsigned long get_ept_pte(unsigned long *pml4,
-		unsigned long guest_addr, int level);
-int set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
+bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level,
+		unsigned long *pte);
+void set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
 		int level, u64 pte_val);
+void check_ept_ad(unsigned long *pml4, u64 guest_cr3,
+		  unsigned long guest_addr, int expected_gpa_ad,
+		  int expected_pt_ad);
+void clear_ept_ad(unsigned long *pml4, u64 guest_cr3,
+		  unsigned long guest_addr);
+
+bool ept_2m_supported(void);
+bool ept_1g_supported(void);
+bool ept_huge_pages_supported(int level);
+bool ept_execute_only_supported(void);
+bool ept_ad_bits_supported(void);
+
+void enter_guest(void);
+
+typedef void (*test_guest_func)(void);
+typedef void (*test_teardown_func)(void *data);
+void test_set_guest(test_guest_func func);
+void test_add_teardown(test_teardown_func func, void *data);
+void test_skip(const char *msg);
+
+void __abort_test(void);
+
+#define TEST_ASSERT(cond) \
+do { \
+	if (!(cond)) { \
+		report("%s:%d: Assertion failed: %s", 0, \
+		       __FILE__, __LINE__, #cond); \
+		dump_stack(); \
+		__abort_test(); \
+	} \
+	report_pass(); \
+} while (0)
+
+#define TEST_ASSERT_MSG(cond, fmt, args...) \
+do { \
+	if (!(cond)) { \
+		report("%s:%d: Assertion failed: %s\n" fmt, 0, \
+		       __FILE__, __LINE__, #cond, ##args); \
+		dump_stack(); \
+		__abort_test(); \
+	} \
+	report_pass(); \
+} while (0)
+
+#define __TEST_EQ(a, b, a_str, b_str, assertion, fmt, args...) \
+do { \
+	typeof(a) _a = a; \
+	typeof(b) _b = b; \
+	if (_a != _b) { \
+		char _bin_a[BINSTR_SZ]; \
+		char _bin_b[BINSTR_SZ]; \
+		binstr(_a, _bin_a); \
+		binstr(_b, _bin_b); \
+		report("%s:%d: %s failed: (%s) == (%s)\n" \
+		       "\tLHS: %#018lx - %s - %lu\n" \
+		       "\tRHS: %#018lx - %s - %lu%s" fmt, 0, \
+		       __FILE__, __LINE__, \
+		       assertion ? "Assertion" : "Expectation", a_str, b_str, \
+		       (unsigned long) _a, _bin_a, (unsigned long) _a, \
+		       (unsigned long) _b, _bin_b, (unsigned long) _b, \
+		       fmt[0] == '\0' ? "" : "\n", ## args); \
+		dump_stack(); \
+		if (assertion) \
+			__abort_test(); \
+	} \
+	report_pass(); \
+} while (0)
+
+#define TEST_ASSERT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 1, "")
+#define TEST_ASSERT_EQ_MSG(a, b, fmt, args...) \
+	__TEST_EQ(a, b, #a, #b, 1, fmt, ## args)
+#define TEST_EXPECT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 0, "")
+#define TEST_EXPECT_EQ_MSG(a, b, fmt, args...) \
+	__TEST_EQ(a, b, #a, #b, 0, fmt, ## args)
 
 #endif

File diff suppressed because it is too large
+ 1631 - 57
tests/kvm-unit-tests/x86/vmx_tests.c


+ 1 - 1
tests/kvm-unit-tests/x86/xsave.c

@@ -75,7 +75,7 @@ void test_xsave(void)
     printf("Legal instruction testing:\n");
 
     supported_xcr0 = get_supported_xcr0();
-    printf("Supported XCR0 bits: 0x%lx\n", supported_xcr0);
+    printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
 
     test_bits = XSTATE_FP | XSTATE_SSE;
     report("Check minimal XSAVE required bits",

Some files were not shown because too many files changed in this diff