]> Git Repo - linux.git/commitdiff
Merge tag 'kvm-x86-selftests-6.9' of https://github.com/kvm-x86/linux into HEAD
authorPaolo Bonzini <[email protected]>
Mon, 11 Mar 2024 14:20:35 +0000 (10:20 -0400)
committerPaolo Bonzini <[email protected]>
Mon, 11 Mar 2024 14:20:35 +0000 (10:20 -0400)
KVM selftests changes for 6.9:

 - Add macros to reduce the amount of boilerplate code needed to write "simple"
   selftests, and to utilize selftest TAP infrastructure, which is especially
   beneficial for KVM selftests with multiple testcases.

 - Add basic smoke tests for SEV and SEV-ES, along with a pile of library
   support for handling private/encrypted/protected memory.

 - Fix benign bugs where tests neglect to close() guest_memfd files.

1  2 
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util_base.h
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/lib/aarch64/processor.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/riscv/processor.c
tools/testing/selftests/kvm/lib/s390x/processor.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c
tools/testing/selftests/kvm/x86_64/sync_regs_test.c

index 426f85798aead0521b04d196fd602b96328f68a5,c75251d5c97c11a31676a5ad8b74935228261a83..b0f13fafa1552d93630289813bce88c8957af459
@@@ -37,6 -37,7 +37,7 @@@ LIBKVM_x86_64 += lib/x86_64/handlers.
  LIBKVM_x86_64 += lib/x86_64/hyperv.c
  LIBKVM_x86_64 += lib/x86_64/memstress.c
  LIBKVM_x86_64 += lib/x86_64/processor.c
+ LIBKVM_x86_64 += lib/x86_64/sev.c
  LIBKVM_x86_64 += lib/x86_64/svm.c
  LIBKVM_x86_64 += lib/x86_64/ucall.c
  LIBKVM_x86_64 += lib/x86_64/vmx.c
@@@ -53,7 -54,6 +54,7 @@@ LIBKVM_s390x += lib/s390x/diag318_test_
  LIBKVM_s390x += lib/s390x/processor.c
  LIBKVM_s390x += lib/s390x/ucall.c
  
 +LIBKVM_riscv += lib/riscv/handlers.S
  LIBKVM_riscv += lib/riscv/processor.c
  LIBKVM_riscv += lib/riscv/ucall.c
  
@@@ -118,6 -118,7 +119,7 @@@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_pmu
  TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test
  TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
  TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
+ TEST_GEN_PROGS_x86_64 += x86_64/sev_smoke_test
  TEST_GEN_PROGS_x86_64 += x86_64/amx_test
  TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test
  TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test
@@@ -144,6 -145,7 +146,6 @@@ TEST_GEN_PROGS_x86_64 += system_counter
  TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test
  
  TEST_GEN_PROGS_aarch64 += aarch64/aarch32_id_regs
 -TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
  TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
  TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
  TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test
@@@ -155,7 -157,6 +157,7 @@@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_
  TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
  TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
  TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
 +TEST_GEN_PROGS_aarch64 += arch_timer
  TEST_GEN_PROGS_aarch64 += demand_paging_test
  TEST_GEN_PROGS_aarch64 += dirty_log_test
  TEST_GEN_PROGS_aarch64 += dirty_log_perf_test
@@@ -185,7 -186,6 +187,7 @@@ TEST_GEN_PROGS_s390x += rseq_tes
  TEST_GEN_PROGS_s390x += set_memory_region_test
  TEST_GEN_PROGS_s390x += kvm_binary_stats_test
  
 +TEST_GEN_PROGS_riscv += arch_timer
  TEST_GEN_PROGS_riscv += demand_paging_test
  TEST_GEN_PROGS_riscv += dirty_log_test
  TEST_GEN_PROGS_riscv += get-reg-list
@@@ -196,7 -196,6 +198,7 @@@ TEST_GEN_PROGS_riscv += kvm_page_table_
  TEST_GEN_PROGS_riscv += set_memory_region_test
  TEST_GEN_PROGS_riscv += steal_time
  
 +SPLIT_TESTS += arch_timer
  SPLIT_TESTS += get-reg-list
  
  TEST_PROGS += $(TEST_PROGS_$(ARCH_DIR))
@@@ -220,7 -219,7 +222,7 @@@ els
  LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include
  endif
  CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
 -      -Wno-gnu-variable-sized-type-not-at-end -MD -MP \
 +      -Wno-gnu-variable-sized-type-not-at-end -MD -MP -DCONFIG_64BIT \
        -fno-builtin-memcmp -fno-builtin-memcpy -fno-builtin-memset \
        -fno-builtin-strnlen \
        -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \
@@@ -263,36 -262,32 +265,36 @@@ LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPU
  LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
  LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
  LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ)
 -SPLIT_TESTS_TARGETS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
 -SPLIT_TESTS_OBJS := $(patsubst %, $(ARCH_DIR)/%.o, $(SPLIT_TESTS))
 +SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
 +SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH_DIR)/%.o, $(SPLIT_TESTS))
  
  TEST_GEN_OBJ = $(patsubst %, %.o, $(TEST_GEN_PROGS))
  TEST_GEN_OBJ += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
  TEST_DEP_FILES = $(patsubst %.o, %.d, $(TEST_GEN_OBJ))
  TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBKVM_OBJS))
 -TEST_DEP_FILES += $(patsubst %.o, %.d, $(SPLIT_TESTS_OBJS))
 +TEST_DEP_FILES += $(patsubst %.o, %.d, $(SPLIT_TEST_GEN_OBJ))
  -include $(TEST_DEP_FILES)
  
 -$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o
 +x := $(shell mkdir -p $(sort $(OUTPUT)/$(ARCH_DIR) $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ))))
 +
 +$(filter-out $(SPLIT_TEST_GEN_PROGS), $(TEST_GEN_PROGS)) \
 +$(TEST_GEN_PROGS_EXTENDED): %: %.o
        $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBKVM_OBJS) $(LDLIBS) -o $@
  $(TEST_GEN_OBJ): $(OUTPUT)/%.o: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
  
 -$(SPLIT_TESTS_TARGETS): %: %.o $(SPLIT_TESTS_OBJS)
 +$(SPLIT_TEST_GEN_PROGS): $(OUTPUT)/%: $(OUTPUT)/%.o $(OUTPUT)/$(ARCH_DIR)/%.o
        $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@
 +$(SPLIT_TEST_GEN_OBJ): $(OUTPUT)/$(ARCH_DIR)/%.o: $(ARCH_DIR)/%.c
 +      $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
  
  EXTRA_CLEAN += $(GEN_HDRS) \
               $(LIBKVM_OBJS) \
 -             $(SPLIT_TESTS_OBJS) \
 +             $(SPLIT_TEST_GEN_OBJ) \
               $(TEST_DEP_FILES) \
               $(TEST_GEN_OBJ) \
               cscope.*
  
 -x := $(shell mkdir -p $(sort $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ))))
  $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c $(GEN_HDRS)
        $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
  
@@@ -306,7 -301,7 +308,7 @@@ $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.
        $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@
  
  x := $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS))))
 -$(SPLIT_TESTS_OBJS): $(GEN_HDRS)
 +$(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS)
  $(TEST_GEN_PROGS): $(LIBKVM_OBJS)
  $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS)
  $(TEST_GEN_OBJ): $(GEN_HDRS)
index 39c2499df34106645f794fe37aae80676ca49b7d,4a40b332115d34559eb48c8a25a2cd0e4bf7cbef..9ff131a6a1a56c1dcf7d1133144117ad0bbdff7c
  #include <linux/types.h>
  
  #include <asm/atomic.h>
+ #include <asm/kvm.h>
  
  #include <sys/ioctl.h>
  
+ #include "kvm_util_arch.h"
  #include "sparsebit.h"
  
  /*
@@@ -46,6 -48,7 +48,7 @@@ typedef uint64_t vm_vaddr_t; /* Virtua
  struct userspace_mem_region {
        struct kvm_userspace_memory_region2 region;
        struct sparsebit *unused_phy_pages;
+       struct sparsebit *protected_phy_pages;
        int fd;
        off_t offset;
        enum vm_mem_backing_src_type backing_src_type;
@@@ -90,6 -93,7 +93,7 @@@ enum kvm_mem_region_type 
  struct kvm_vm {
        int mode;
        unsigned long type;
+       uint8_t subtype;
        int kvm_fd;
        int fd;
        unsigned int pgtable_levels;
        vm_vaddr_t idt;
        vm_vaddr_t handlers;
        uint32_t dirty_ring_size;
+       uint64_t gpa_tag_mask;
+       struct kvm_vm_arch arch;
  
        /* Cache of information for binary stats interface */
        int stats_fd;
@@@ -191,10 -198,14 +198,14 @@@ enum vm_guest_mode 
  };
  
  struct vm_shape {
-       enum vm_guest_mode mode;
-       unsigned int type;
+       uint32_t type;
+       uint8_t  mode;
+       uint8_t  subtype;
+       uint16_t padding;
  };
  
+ kvm_static_assert(sizeof(struct vm_shape) == sizeof(uint64_t));
  #define VM_TYPE_DEFAULT                       0
  
  #define VM_SHAPE(__mode)                      \
@@@ -564,6 -575,13 +575,13 @@@ void vm_mem_add(struct kvm_vm *vm, enu
                uint64_t guest_paddr, uint32_t slot, uint64_t npages,
                uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset);
  
+ #ifndef vm_arch_has_protected_memory
+ static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm)
+ {
+       return false;
+ }
+ #endif
  void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
  void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
  void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot);
@@@ -573,6 -591,9 +591,9 @@@ vm_vaddr_t vm_vaddr_unused_gap(struct k
  vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min);
  vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
                            enum kvm_mem_region_type type);
+ vm_vaddr_t vm_vaddr_alloc_shared(struct kvm_vm *vm, size_t sz,
+                                vm_vaddr_t vaddr_min,
+                                enum kvm_mem_region_type type);
  vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages);
  vm_vaddr_t __vm_vaddr_alloc_page(struct kvm_vm *vm,
                                 enum kvm_mem_region_type type);
@@@ -585,6 -606,12 +606,12 @@@ void *addr_gva2hva(struct kvm_vm *vm, v
  vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva);
  void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa);
  
+ static inline vm_paddr_t vm_untag_gpa(struct kvm_vm *vm, vm_paddr_t gpa)
+ {
+       return gpa & ~vm->gpa_tag_mask;
+ }
  void vcpu_run(struct kvm_vcpu *vcpu);
  int _vcpu_run(struct kvm_vcpu *vcpu);
  
@@@ -827,10 -854,23 +854,23 @@@ const char *exit_reason_str(unsigned in
  
  vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
                             uint32_t memslot);
- vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
-                             vm_paddr_t paddr_min, uint32_t memslot);
+ vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+                               vm_paddr_t paddr_min, uint32_t memslot,
+                               bool protected);
  vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm);
  
+ static inline vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+                                           vm_paddr_t paddr_min, uint32_t memslot)
+ {
+       /*
+        * By default, allocate memory as protected for VMs that support
+        * protected memory, as the majority of memory for such VMs is
+        * protected, i.e. using shared memory is effectively opt-in.
+        */
+       return __vm_phy_pages_alloc(vm, num, paddr_min, memslot,
+                                   vm_arch_has_protected_memory(vm));
+ }
  /*
   * ____vm_create() does KVM_CREATE_VM and little else.  __vm_create() also
   * loads the test binary into guest memory and creates an IRQ chip (x86 only).
@@@ -969,15 -1009,18 +1009,18 @@@ static inline void vcpu_dump(FILE *stre
   * Input Args:
   *   vm - Virtual Machine
   *   vcpu_id - The id of the VCPU to add to the VM.
-  *   guest_code - The vCPU's entry point
   */
- struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
                                void *guest_code);
+ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id);
void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
  
  static inline struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
                                           void *guest_code)
  {
-       return vm_arch_vcpu_add(vm, vcpu_id, guest_code);
+       struct kvm_vcpu *vcpu = vm_arch_vcpu_add(vm, vcpu_id);
+       vcpu_arch_set_entry_point(vcpu, guest_code);
+       return vcpu;
  }
  
  /* Re-create a vCPU after restarting a VM, e.g. for state save/restore tests. */
@@@ -1081,6 -1124,6 +1124,8 @@@ void kvm_selftest_arch_init(void)
  
  void kvm_arch_vm_post_create(struct kvm_vm *vm);
  
+ bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr);
 +uint32_t guest_get_vcpuid(void);
 +
  #endif /* SELFTEST_KVM_UTIL_BASE_H */
index 5bca8c947c8253819dd07ed6266a03194a0c1857,20c9e3b33b07c65fd27f6ebac74f2c3a84a6b1f2..d2534a4a077b76e8775fc90c913e2fdc738ddc71
  extern bool host_cpu_is_intel;
  extern bool host_cpu_is_amd;
  
+ enum vm_guest_x86_subtype {
+       VM_SUBTYPE_NONE = 0,
+       VM_SUBTYPE_SEV,
+       VM_SUBTYPE_SEV_ES,
+ };
  #define NMI_VECTOR            0x02
  
  #define X86_EFLAGS_FIXED       (1u << 1)
@@@ -273,6 -279,7 +279,7 @@@ struct kvm_x86_cpu_property 
  #define X86_PROPERTY_MAX_EXT_LEAF             KVM_X86_CPU_PROPERTY(0x80000000, 0, EAX, 0, 31)
  #define X86_PROPERTY_MAX_PHY_ADDR             KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 0, 7)
  #define X86_PROPERTY_MAX_VIRT_ADDR            KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 8, 15)
+ #define X86_PROPERTY_SEV_C_BIT                        KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 0, 5)
  #define X86_PROPERTY_PHYS_ADDR_REDUCTION      KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 6, 11)
  
  #define X86_PROPERTY_MAX_CENTAUR_LEAF         KVM_X86_CPU_PROPERTY(0xC0000000, 0, EAX, 0, 31)
@@@ -1059,6 -1066,7 +1066,7 @@@ do {                                                                                    
  } while (0)
  
  void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits);
+ void kvm_init_vm_address_properties(struct kvm_vm *vm);
  bool vm_is_unrestricted_guest(struct kvm_vm *vm);
  
  struct ex_regs {
@@@ -1271,6 -1279,4 +1279,6 @@@ void virt_map_level(struct kvm_vm *vm, 
  #define PFERR_GUEST_PAGE_MASK BIT_ULL(PFERR_GUEST_PAGE_BIT)
  #define PFERR_IMPLICIT_ACCESS BIT_ULL(PFERR_IMPLICIT_ACCESS_BIT)
  
 +bool sys_clocksource_is_based_on_tsc(void);
 +
  #endif /* SELFTEST_KVM_PROCESSOR_H */
index 43b9a72833602e072ad7ba5e7e69c341fb8469a6,c83616e19bad49a8b29e43832017ff86e0b71dac..a9eb17295be42f36b564113d4a0b01a3e4782d12
@@@ -365,8 -365,13 +365,13 @@@ void vcpu_arch_dump(FILE *stream, struc
                indent, "", pstate, pc);
  }
  
- struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
-                                 struct kvm_vcpu_init *init, void *guest_code)
+ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+ {
+       vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
+ }
+ static struct kvm_vcpu *__aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
+                                          struct kvm_vcpu_init *init)
  {
        size_t stack_size;
        uint64_t stack_vaddr;
        aarch64_vcpu_setup(vcpu, init);
  
        vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size);
-       vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
+       return vcpu;
+ }
+ struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
+                                 struct kvm_vcpu_init *init, void *guest_code)
+ {
+       struct kvm_vcpu *vcpu = __aarch64_vcpu_add(vm, vcpu_id, init);
+       vcpu_arch_set_entry_point(vcpu, guest_code);
  
        return vcpu;
  }
  
- struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
-                                 void *guest_code)
+ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  {
-       return aarch64_vcpu_add(vm, vcpu_id, NULL, guest_code);
+       return __aarch64_vcpu_add(vm, vcpu_id, NULL);
  }
  
  void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
        int i;
  
        TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n"
 -                  "  num: %u\n", num);
 +                  "  num: %u", num);
  
        va_start(ap, num);
  
index 1b197426f29fcd1e6faf4abe3069044dfe64b9ca,adc51b0712caecff973936a147e23271df6064a0..13b92f995bdecbb9a1ccef6c17d292f43b097794
@@@ -27,8 -27,7 +27,8 @@@ int open_path_or_exit(const char *path
        int fd;
  
        fd = open(path, flags);
 -      __TEST_REQUIRE(fd >= 0, "%s not available (errno: %d)", path, errno);
 +      __TEST_REQUIRE(fd >= 0 || errno != ENOENT, "Cannot open %s: %s", path, strerror(errno));
 +      TEST_ASSERT(fd >= 0, "Failed to open '%s'", path);
  
        return fd;
  }
@@@ -226,6 -225,7 +226,7 @@@ struct kvm_vm *____vm_create(struct vm_
  
        vm->mode = shape.mode;
        vm->type = shape.type;
+       vm->subtype = shape.subtype;
  
        vm->pa_bits = vm_guest_mode_params[vm->mode].pa_bits;
        vm->va_bits = vm_guest_mode_params[vm->mode].va_bits;
        case VM_MODE_PXXV48_4K:
  #ifdef __x86_64__
                kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits);
+               kvm_init_vm_address_properties(vm);
                /*
                 * Ignore KVM support for 5-level paging (vm->va_bits == 57),
                 * it doesn't take effect unless a CR4.LA57 is set, which it
@@@ -321,7 -322,7 +323,7 @@@ static uint64_t vm_nr_pages_required(en
        uint64_t nr_pages;
  
        TEST_ASSERT(nr_runnable_vcpus,
 -                  "Use vm_create_barebones() for VMs that _never_ have vCPUs\n");
 +                  "Use vm_create_barebones() for VMs that _never_ have vCPUs");
  
        TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS),
                    "nr_vcpus = %d too large for host, max-vcpus = %d",
@@@ -492,7 -493,7 +494,7 @@@ void kvm_pin_this_task_to_pcpu(uint32_
        CPU_ZERO(&mask);
        CPU_SET(pcpu, &mask);
        r = sched_setaffinity(0, sizeof(mask), &mask);
 -      TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.\n", pcpu);
 +      TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.", pcpu);
  }
  
  static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask)
        uint32_t pcpu = atoi_non_negative("CPU number", cpu_str);
  
        TEST_ASSERT(CPU_ISSET(pcpu, allowed_mask),
 -                  "Not allowed to run on pCPU '%d', check cgroups?\n", pcpu);
 +                  "Not allowed to run on pCPU '%d', check cgroups?", pcpu);
        return pcpu;
  }
  
@@@ -530,7 -531,7 +532,7 @@@ void kvm_parse_vcpu_pinning(const char 
        int i, r;
  
        cpu_list = strdup(pcpus_string);
 -      TEST_ASSERT(cpu_list, "strdup() allocation failed.\n");
 +      TEST_ASSERT(cpu_list, "strdup() allocation failed.");
  
        r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
        TEST_ASSERT(!r, "sched_getaffinity() failed");
  
        /* 1. Get all pcpus for vcpus. */
        for (i = 0; i < nr_vcpus; i++) {
 -              TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'\n", i);
 +              TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'", i);
                vcpu_to_pcpu[i] = parse_pcpu(cpu, &allowed_mask);
                cpu = strtok(NULL, delim);
        }
@@@ -666,6 -667,7 +668,7 @@@ static void __vm_mem_region_delete(stru
        vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
  
        sparsebit_free(&region->unused_phy_pages);
+       sparsebit_free(&region->protected_phy_pages);
        ret = munmap(region->mmap_start, region->mmap_size);
        TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
        if (region->fd >= 0) {
@@@ -1047,6 -1049,8 +1050,8 @@@ void vm_mem_add(struct kvm_vm *vm, enu
        }
  
        region->unused_phy_pages = sparsebit_alloc();
+       if (vm_arch_has_protected_memory(vm))
+               region->protected_phy_pages = sparsebit_alloc();
        sparsebit_set_num(region->unused_phy_pages,
                guest_paddr >> vm->page_shift, npages);
        region->region.slot = slot;
        TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n"
                "  rc: %i errno: %i\n"
                "  slot: %u flags: 0x%x\n"
 -              "  guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d\n",
 +              "  guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d",
                ret, errno, slot, flags,
                guest_paddr, (uint64_t) region->region.memory_size,
                region->region.guest_memfd);
@@@ -1223,7 -1227,7 +1228,7 @@@ void vm_guest_mem_fallocate(struct kvm_
                len = min_t(uint64_t, end - gpa, region->region.memory_size - offset);
  
                ret = fallocate(region->region.guest_memfd, mode, fd_offset, len);
 -              TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx\n",
 +              TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx",
                            punch_hole ? "punch hole" : "allocate", gpa, len,
                            region->region.guest_memfd, mode, fd_offset);
        }
@@@ -1266,7 -1270,7 +1271,7 @@@ struct kvm_vcpu *__vm_vcpu_add(struct k
        struct kvm_vcpu *vcpu;
  
        /* Confirm a vcpu with the specified id doesn't already exist. */
 -      TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id);
 +      TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists", vcpu_id);
  
        /* Allocate and initialize new vcpu structure. */
        vcpu = calloc(1, sizeof(*vcpu));
@@@ -1377,15 -1381,17 +1382,17 @@@ va_found
        return pgidx_start * vm->page_size;
  }
  
- vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
-                           enum kvm_mem_region_type type)
+ static vm_vaddr_t ____vm_vaddr_alloc(struct kvm_vm *vm, size_t sz,
+                                    vm_vaddr_t vaddr_min,
+                                    enum kvm_mem_region_type type,
+                                    bool protected)
  {
        uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0);
  
        virt_pgd_alloc(vm);
-       vm_paddr_t paddr = vm_phy_pages_alloc(vm, pages,
-                                             KVM_UTIL_MIN_PFN * vm->page_size,
-                                             vm->memslots[type]);
+       vm_paddr_t paddr = __vm_phy_pages_alloc(vm, pages,
+                                               KVM_UTIL_MIN_PFN * vm->page_size,
+                                               vm->memslots[type], protected);
  
        /*
         * Find an unused range of virtual page addresses of at least
        return vaddr_start;
  }
  
+ vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
+                           enum kvm_mem_region_type type)
+ {
+       return ____vm_vaddr_alloc(vm, sz, vaddr_min, type,
+                                 vm_arch_has_protected_memory(vm));
+ }
+ vm_vaddr_t vm_vaddr_alloc_shared(struct kvm_vm *vm, size_t sz,
+                                vm_vaddr_t vaddr_min,
+                                enum kvm_mem_region_type type)
+ {
+       return ____vm_vaddr_alloc(vm, sz, vaddr_min, type, false);
+ }
  /*
   * VM Virtual Address Allocate
   *
@@@ -1527,6 -1547,8 +1548,8 @@@ void *addr_gpa2hva(struct kvm_vm *vm, v
  {
        struct userspace_mem_region *region;
  
+       gpa = vm_untag_gpa(vm, gpa);
        region = userspace_mem_region_find(vm, gpa, gpa);
        if (!region) {
                TEST_FAIL("No vm physical memory at 0x%lx", gpa);
@@@ -1873,6 -1895,10 +1896,10 @@@ void vm_dump(FILE *stream, struct kvm_v
                        region->host_mem);
                fprintf(stream, "%*sunused_phy_pages: ", indent + 2, "");
                sparsebit_dump(stream, region->unused_phy_pages, 0);
+               if (region->protected_phy_pages) {
+                       fprintf(stream, "%*sprotected_phy_pages: ", indent + 2, "");
+                       sparsebit_dump(stream, region->protected_phy_pages, 0);
+               }
        }
        fprintf(stream, "%*sMapped Virtual Pages:\n", indent, "");
        sparsebit_dump(stream, vm->vpages_mapped, indent + 2);
@@@ -1974,6 -2000,7 +2001,7 @@@ const char *exit_reason_str(unsigned in
   *   num - number of pages
   *   paddr_min - Physical address minimum
   *   memslot - Memory region to allocate page from
+  *   protected - True if the pages will be used as protected/private memory
   *
   * Output Args: None
   *
   * and their base address is returned. A TEST_ASSERT failure occurs if
   * not enough pages are available at or above paddr_min.
   */
- vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
-                             vm_paddr_t paddr_min, uint32_t memslot)
+ vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+                               vm_paddr_t paddr_min, uint32_t memslot,
+                               bool protected)
  {
        struct userspace_mem_region *region;
        sparsebit_idx_t pg, base;
                paddr_min, vm->page_size);
  
        region = memslot2region(vm, memslot);
-       base = pg = paddr_min >> vm->page_shift;
+       TEST_ASSERT(!protected || region->protected_phy_pages,
+                   "Region doesn't support protected memory");
  
+       base = pg = paddr_min >> vm->page_shift;
        do {
                for (; pg < base + num; ++pg) {
                        if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
                abort();
        }
  
-       for (pg = base; pg < base + num; ++pg)
+       for (pg = base; pg < base + num; ++pg) {
                sparsebit_clear(region->unused_phy_pages, pg);
+               if (protected)
+                       sparsebit_set(region->protected_phy_pages, pg);
+       }
  
        return base * vm->page_size;
  }
@@@ -2224,3 -2257,18 +2258,18 @@@ void __attribute((constructor)) kvm_sel
  
        kvm_selftest_arch_init();
  }
+ bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr)
+ {
+       sparsebit_idx_t pg = 0;
+       struct userspace_mem_region *region;
+       if (!vm_arch_has_protected_memory(vm))
+               return false;
+       region = userspace_mem_region_find(vm, paddr, paddr);
+       TEST_ASSERT(region, "No vm physical memory at 0x%lx", paddr);
+       pg = paddr >> vm->page_shift;
+       return sparsebit_is_set(region->protected_phy_pages, pg);
+ }
index ec66d331a127389447510070d4fdfb916ffa4155,c993947f07823f09fb151578b2dad2c43e0eff32..e8211f5d68637ea7d0b9916e7931a23c0573dbe0
  
  #define DEFAULT_RISCV_GUEST_STACK_VADDR_MIN   0xac0000
  
 +static vm_vaddr_t exception_handlers;
 +
 +bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
 +{
 +      unsigned long value = 0;
 +      int ret;
 +
 +      ret = __vcpu_get_reg(vcpu, ext, &value);
 +
 +      return !ret && !!value;
 +}
 +
  static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
  {
        return (v + vm->page_size) & ~(vm->page_size - 1);
@@@ -289,8 -277,12 +289,12 @@@ static void __aligned(16) guest_unexp_t
                  0, 0, 0, 0, 0, 0);
  }
  
- struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
-                                 void *guest_code)
+ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+ {
+       vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code);
+ }
+ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  {
        int r;
        size_t stack_size;
  
        /* Setup stack pointer and program counter of guest */
        vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.sp), stack_vaddr + stack_size);
-       vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code);
  
 +      /* Setup sscratch for guest_get_vcpuid() */
 +      vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(sscratch), vcpu_id);
 +
        /* Setup default exception vector of guest */
        vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)guest_unexp_trap);
  
@@@ -342,7 -330,7 +345,7 @@@ void vcpu_args_set(struct kvm_vcpu *vcp
        int i;
  
        TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n"
 -                  "  num: %u\n", num);
 +                  "  num: %u", num);
  
        va_start(ap, num);
  
        va_end(ap);
  }
  
 +void kvm_exit_unexpected_exception(int vector, int ec)
 +{
 +      ucall(UCALL_UNHANDLED, 2, vector, ec);
 +}
 +
  void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
  {
 +      struct ucall uc;
 +
 +      if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) {
 +              TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)",
 +                      uc.args[0], uc.args[1]);
 +      }
 +}
 +
 +struct handlers {
 +      exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS];
 +};
 +
 +void route_exception(struct ex_regs *regs)
 +{
 +      struct handlers *handlers = (struct handlers *)exception_handlers;
 +      int vector = 0, ec;
 +
 +      ec = regs->cause & ~CAUSE_IRQ_FLAG;
 +      if (ec >= NR_EXCEPTIONS)
 +              goto unexpected_exception;
 +
 +      /* Use the same handler for all the interrupts */
 +      if (regs->cause & CAUSE_IRQ_FLAG) {
 +              vector = 1;
 +              ec = 0;
 +      }
 +
 +      if (handlers && handlers->exception_handlers[vector][ec])
 +              return handlers->exception_handlers[vector][ec](regs);
 +
 +unexpected_exception:
 +      return kvm_exit_unexpected_exception(vector, ec);
 +}
 +
 +void vcpu_init_vector_tables(struct kvm_vcpu *vcpu)
 +{
 +      extern char exception_vectors;
 +
 +      vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)&exception_vectors);
 +}
 +
 +void vm_init_vector_tables(struct kvm_vm *vm)
 +{
 +      vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers),
 +                                 vm->page_size, MEM_REGION_DATA);
 +
 +      *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
 +}
 +
 +void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler)
 +{
 +      struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
 +
 +      assert(vector < NR_EXCEPTIONS);
 +      handlers->exception_handlers[0][vector] = handler;
 +}
 +
 +void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler)
 +{
 +      struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
 +
 +      handlers->exception_handlers[1][0] = handler;
 +}
 +
 +uint32_t guest_get_vcpuid(void)
 +{
 +      return csr_read(CSR_SSCRATCH);
  }
  
  struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
index f6d227892cbcfc88cc97abcc9a0d78b2aa38f459,cd5301cc9788adc3e636c131b039d0e7e79080aa..4ad4492eea1d96f88a544ab510300ed43e2934f1
@@@ -155,15 -155,18 +155,18 @@@ void virt_arch_dump(FILE *stream, struc
        virt_dump_region(stream, vm, indent, vm->pgd);
  }
  
- struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
-                                 void *guest_code)
+ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+ {
+       vcpu->run->psw_addr = (uintptr_t)guest_code;
+ }
+ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  {
        size_t stack_size =  DEFAULT_STACK_PGS * getpagesize();
        uint64_t stack_vaddr;
        struct kvm_regs regs;
        struct kvm_sregs sregs;
        struct kvm_vcpu *vcpu;
-       struct kvm_run *run;
  
        TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
                    vm->page_size);
        sregs.crs[1] = vm->pgd | 0xf;           /* Primary region table */
        vcpu_sregs_set(vcpu, &sregs);
  
-       run = vcpu->run;
-       run->psw_mask = 0x0400000180000000ULL;  /* DAT enabled + 64 bit mode */
-       run->psw_addr = (uintptr_t)guest_code;
+       vcpu->run->psw_mask = 0x0400000180000000ULL;  /* DAT enabled + 64 bit mode */
  
        return vcpu;
  }
@@@ -198,7 -199,7 +199,7 @@@ void vcpu_args_set(struct kvm_vcpu *vcp
        int i;
  
        TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args,\n"
 -                  "  num: %u\n",
 +                  "  num: %u",
                    num);
  
        va_start(ap, num);
index f639b3e062e3a328165bfb6ed32f606cf1f48e76,49288fe10cd34eeb84a252260d4acbc271b1d5ac..c3bb2eb38cffedf60580e7e69dd23f77cb7acf00
@@@ -9,6 -9,7 +9,7 @@@
  #include "test_util.h"
  #include "kvm_util.h"
  #include "processor.h"
+ #include "sev.h"
  
  #ifndef NUM_INTERRUPTS
  #define NUM_INTERRUPTS 256
@@@ -157,6 -158,8 +158,8 @@@ static uint64_t *virt_create_upper_pte(
  {
        uint64_t *pte = virt_get_pte(vm, parent_pte, vaddr, current_level);
  
+       paddr = vm_untag_gpa(vm, paddr);
        if (!(*pte & PTE_PRESENT_MASK)) {
                *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK;
                if (current_level == target_level)
                 * this level.
                 */
                TEST_ASSERT(current_level != target_level,
 -                          "Cannot create hugepage at level: %u, vaddr: 0x%lx\n",
 +                          "Cannot create hugepage at level: %u, vaddr: 0x%lx",
                            current_level, vaddr);
                TEST_ASSERT(!(*pte & PTE_LARGE_MASK),
 -                          "Cannot create page table at level: %u, vaddr: 0x%lx\n",
 +                          "Cannot create page table at level: %u, vaddr: 0x%lx",
                            current_level, vaddr);
        }
        return pte;
@@@ -200,6 -203,8 +203,8 @@@ void __virt_pg_map(struct kvm_vm *vm, u
                    "Physical address beyond maximum supported,\n"
                    "  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
                    paddr, vm->max_gfn, vm->page_size);
+       TEST_ASSERT(vm_untag_gpa(vm, paddr) == paddr,
+                   "Unexpected bits in paddr: %lx", paddr);
  
        /*
         * Allocate upper level page tables, if not already present.  Return
        /* Fill in page table entry. */
        pte = virt_get_pte(vm, pde, vaddr, PG_LEVEL_4K);
        TEST_ASSERT(!(*pte & PTE_PRESENT_MASK),
 -                  "PTE already present for 4k page at vaddr: 0x%lx\n", vaddr);
 +                  "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
        *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK);
+       /*
+        * Neither SEV nor TDX supports shared page tables, so only the final
+        * leaf PTE needs manually set the C/S-bit.
+        */
+       if (vm_is_gpa_protected(vm, paddr))
+               *pte |= vm->arch.c_bit;
+       else
+               *pte |= vm->arch.s_bit;
  }
  
  void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
@@@ -253,7 -267,7 +267,7 @@@ static bool vm_is_target_pte(uint64_t *
        if (*pte & PTE_LARGE_MASK) {
                TEST_ASSERT(*level == PG_LEVEL_NONE ||
                            *level == current_level,
 -                          "Unexpected hugepage at level %d\n", current_level);
 +                          "Unexpected hugepage at level %d", current_level);
                *level = current_level;
        }
  
@@@ -265,6 -279,9 +279,9 @@@ uint64_t *__vm_get_page_table_entry(str
  {
        uint64_t *pml4e, *pdpe, *pde;
  
+       TEST_ASSERT(!vm->arch.is_pt_protected,
+                   "Walking page tables of protected guests is impossible");
        TEST_ASSERT(*level >= PG_LEVEL_NONE && *level < PG_LEVEL_NUM,
                    "Invalid PG_LEVEL_* '%d'", *level);
  
@@@ -496,7 -513,7 +513,7 @@@ vm_paddr_t addr_arch_gva2gpa(struct kvm
         * No need for a hugepage mask on the PTE, x86-64 requires the "unused"
         * address bits to be zero.
         */
-       return PTE_GET_PA(*pte) | (gva & ~HUGEPAGE_MASK(level));
+       return vm_untag_gpa(vm, PTE_GET_PA(*pte)) | (gva & ~HUGEPAGE_MASK(level));
  }
  
  static void kvm_setup_gdt(struct kvm_vm *vm, struct kvm_dtable *dt)
@@@ -560,10 -577,23 +577,23 @@@ void kvm_arch_vm_post_create(struct kvm
        vm_create_irqchip(vm);
        sync_global_to_guest(vm, host_cpu_is_intel);
        sync_global_to_guest(vm, host_cpu_is_amd);
+       if (vm->subtype == VM_SUBTYPE_SEV)
+               sev_vm_init(vm);
+       else if (vm->subtype == VM_SUBTYPE_SEV_ES)
+               sev_es_vm_init(vm);
+ }
+ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+ {
+       struct kvm_regs regs;
+       vcpu_regs_get(vcpu, &regs);
+       regs.rip = (unsigned long) guest_code;
+       vcpu_regs_set(vcpu, &regs);
  }
  
- struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
-                                 void *guest_code)
+ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  {
        struct kvm_mp_state mp_state;
        struct kvm_regs regs;
        vcpu_regs_get(vcpu, &regs);
        regs.rflags = regs.rflags | 0x2;
        regs.rsp = stack_vaddr;
-       regs.rip = (unsigned long) guest_code;
        vcpu_regs_set(vcpu, &regs);
  
        /* Setup the MP state */
@@@ -825,7 -854,7 +854,7 @@@ void vcpu_args_set(struct kvm_vcpu *vcp
        struct kvm_regs regs;
  
        TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n"
 -                  "  num: %u\n",
 +                  "  num: %u",
                    num);
  
        va_start(ap, num);
@@@ -1041,6 -1070,14 +1070,14 @@@ void kvm_get_cpu_address_width(unsigne
        }
  }
  
+ void kvm_init_vm_address_properties(struct kvm_vm *vm)
+ {
+       if (vm->subtype == VM_SUBTYPE_SEV || vm->subtype == VM_SUBTYPE_SEV_ES) {
+               vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT));
+               vm->gpa_tag_mask = vm->arch.c_bit;
+       }
+ }
  static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr,
                          int dpl, unsigned short selector)
  {
@@@ -1299,14 -1336,3 +1336,14 @@@ void kvm_selftest_arch_init(void
        host_cpu_is_intel = this_cpu_is_intel();
        host_cpu_is_amd = this_cpu_is_amd();
  }
 +
 +bool sys_clocksource_is_based_on_tsc(void)
 +{
 +      char *clk_name = sys_get_cur_clocksource();
 +      bool ret = !strcmp(clk_name, "tsc\n") ||
 +                 !strcmp(clk_name, "hyperv_clocksource_tsc_page\n");
 +
 +      free(clk_name);
 +
 +      return ret;
 +}
index a49828adf2949464b668f530a977e9efd9d75888,ec3709e1c6847621e652452d4bcdd8c60df39600..0a6dfba3905b68c03cebaf1e821c7019c4a68cf1
  #include "test_util.h"
  #include "kvm_util.h"
  #include "processor.h"
- #include "svm_util.h"
+ #include "sev.h"
  #include "kselftest.h"
  
- #define SEV_POLICY_ES 0b100
  #define NR_MIGRATE_TEST_VCPUS 4
  #define NR_MIGRATE_TEST_VMS 3
  #define NR_LOCK_TESTING_THREADS 3
  
  bool have_sev_es;
  
- static int __sev_ioctl(int vm_fd, int cmd_id, void *data, __u32 *fw_error)
- {
-       struct kvm_sev_cmd cmd = {
-               .id = cmd_id,
-               .data = (uint64_t)data,
-               .sev_fd = open_sev_dev_path_or_exit(),
-       };
-       int ret;
-       ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
-       *fw_error = cmd.error;
-       return ret;
- }
- static void sev_ioctl(int vm_fd, int cmd_id, void *data)
- {
-       int ret;
-       __u32 fw_error;
-       ret = __sev_ioctl(vm_fd, cmd_id, data, &fw_error);
-       TEST_ASSERT(ret == 0 && fw_error == SEV_RET_SUCCESS,
-                   "%d failed: return code: %d, errno: %d, fw error: %d",
-                   cmd_id, ret, errno, fw_error);
- }
  static struct kvm_vm *sev_vm_create(bool es)
  {
        struct kvm_vm *vm;
-       struct kvm_sev_launch_start start = { 0 };
        int i;
  
        vm = vm_create_barebones();
-       sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL);
+       if (!es)
+               sev_vm_init(vm);
+       else
+               sev_es_vm_init(vm);
        for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
                __vm_vcpu_add(vm, i);
+       sev_vm_launch(vm, es ? SEV_POLICY_ES : 0);
        if (es)
-               start.policy |= SEV_POLICY_ES;
-       sev_ioctl(vm->fd, KVM_SEV_LAUNCH_START, &start);
-       if (es)
-               sev_ioctl(vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
+               vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
        return vm;
  }
  
@@@ -91,7 -67,7 +67,7 @@@ static void sev_migrate_from(struct kvm
        int ret;
  
        ret = __sev_migrate_from(dst, src);
 -      TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno);
 +      TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d", ret, errno);
  }
  
  static void test_sev_migrate_from(bool es)
        /* Migrate the guest back to the original VM. */
        ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]);
        TEST_ASSERT(ret == -1 && errno == EIO,
 -                  "VM that was migrated from should be dead. ret %d, errno: %d\n", ret,
 +                  "VM that was migrated from should be dead. ret %d, errno: %d", ret,
                    errno);
  
        kvm_vm_free(src_vm);
@@@ -172,7 -148,7 +148,7 @@@ static void test_sev_migrate_parameters
        vm_no_sev = aux_vm_create(true);
        ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev);
        TEST_ASSERT(ret == -1 && errno == EINVAL,
 -                  "Migrations require SEV enabled. ret %d, errno: %d\n", ret,
 +                  "Migrations require SEV enabled. ret %d, errno: %d", ret,
                    errno);
  
        if (!have_sev_es)
        sev_vm = sev_vm_create(/* es= */ false);
        sev_es_vm = sev_vm_create(/* es= */ true);
        sev_es_vm_no_vmsa = vm_create_barebones();
-       sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL);
+       sev_es_vm_init(sev_es_vm_no_vmsa);
        __vm_vcpu_add(sev_es_vm_no_vmsa, 1);
  
        ret = __sev_migrate_from(sev_vm, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n",
 +              "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d",
                ret, errno);
  
        ret = __sev_migrate_from(sev_es_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n",
 +              "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d",
                ret, errno);
  
        ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n",
 +              "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d",
                ret, errno);
  
        ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n",
 +              "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d",
                ret, errno);
  
        kvm_vm_free(sev_vm);
@@@ -227,16 -203,16 +203,16 @@@ static void sev_mirror_create(struct kv
        int ret;
  
        ret = __sev_mirror_create(dst, src);
 -      TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno);
 +      TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d", ret, errno);
  }
  
- static void verify_mirror_allowed_cmds(int vm_fd)
+ static void verify_mirror_allowed_cmds(struct kvm_vm *vm)
  {
        struct kvm_sev_guest_status status;
+       int cmd_id;
  
-       for (int cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) {
+       for (cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) {
                int ret;
-               __u32 fw_error;
  
                /*
                 * These commands are allowed for mirror VMs, all others are
                 * These commands should be disallowed before the data
                 * parameter is examined so NULL is OK here.
                 */
-               ret = __sev_ioctl(vm_fd, cmd_id, NULL, &fw_error);
+               ret = __vm_sev_ioctl(vm, cmd_id, NULL);
                TEST_ASSERT(
                        ret == -1 && errno == EINVAL,
 -                      "Should not be able call command: %d. ret: %d, errno: %d\n",
 +                      "Should not be able call command: %d. ret: %d, errno: %d",
                        cmd_id, ret, errno);
        }
  
-       sev_ioctl(vm_fd, KVM_SEV_GUEST_STATUS, &status);
+       vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status);
  }
  
  static void test_sev_mirror(bool es)
                __vm_vcpu_add(dst_vm, i);
  
        if (es)
-               sev_ioctl(dst_vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
+               vm_sev_ioctl(dst_vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
  
-       verify_mirror_allowed_cmds(dst_vm->fd);
+       verify_mirror_allowed_cmds(dst_vm);
  
        kvm_vm_free(src_vm);
        kvm_vm_free(dst_vm);
@@@ -301,18 -277,18 +277,18 @@@ static void test_sev_mirror_parameters(
        ret = __sev_mirror_create(sev_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "Should not be able copy context to self. ret: %d, errno: %d\n",
 +              "Should not be able copy context to self. ret: %d, errno: %d",
                ret, errno);
  
        ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu);
        TEST_ASSERT(ret == -1 && errno == EINVAL,
 -                  "Copy context requires SEV enabled. ret %d, errno: %d\n", ret,
 +                  "Copy context requires SEV enabled. ret %d, errno: %d", ret,
                    errno);
  
        ret = __sev_mirror_create(vm_with_vcpu, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d\n",
 +              "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d",
                ret, errno);
  
        if (!have_sev_es)
        ret = __sev_mirror_create(sev_vm, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d\n",
 +              "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d",
                ret, errno);
  
        ret = __sev_mirror_create(sev_es_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
 -              "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d\n",
 +              "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d",
                ret, errno);
  
        kvm_vm_free(sev_es_vm);
index a91b5b145fa35ac81dfaa225ff350e4186a229d0,67f78c0a58a51844e75df58383c53d31bc7d6591..adb5593daf483ec6b84d18dda8f5ebf8823a6827
@@@ -17,6 -17,7 +17,7 @@@
  #include <sys/ioctl.h>
  #include <pthread.h>
  
+ #include "kvm_test_harness.h"
  #include "test_util.h"
  #include "kvm_util.h"
  #include "processor.h"
@@@ -41,12 -42,14 +42,14 @@@ void guest_code(void
                     : "rax", "rbx");
  }
  
+ KVM_ONE_VCPU_TEST_SUITE(sync_regs_test);
  static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
  {
  #define REG_COMPARE(reg) \
        TEST_ASSERT(left->reg == right->reg, \
                    "Register " #reg \
 -                  " values did not match: 0x%llx, 0x%llx\n", \
 +                  " values did not match: 0x%llx, 0x%llx", \
                    left->reg, right->reg)
        REG_COMPARE(rax);
        REG_COMPARE(rbx);
@@@ -152,18 -155,15 +155,15 @@@ static noinline void *race_sregs_cr4(vo
        return NULL;
  }
  
- static void race_sync_regs(void *racer)
+ static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer)
  {
        const time_t TIMEOUT = 2; /* seconds, roughly */
        struct kvm_x86_state *state;
        struct kvm_translation tr;
-       struct kvm_vcpu *vcpu;
        struct kvm_run *run;
-       struct kvm_vm *vm;
        pthread_t thread;
        time_t t;
  
-       vm = vm_create_with_one_vcpu(&vcpu, guest_code);
        run = vcpu->run;
  
        run->kvm_valid_regs = KVM_SYNC_X86_SREGS;
        TEST_ASSERT_EQ(pthread_join(thread, NULL), 0);
  
        kvm_x86_state_cleanup(state);
-       kvm_vm_free(vm);
  }
  
int main(int argc, char *argv[])
KVM_ONE_VCPU_TEST(sync_regs_test, read_invalid, guest_code)
  {
-       struct kvm_vcpu *vcpu;
-       struct kvm_vm *vm;
-       struct kvm_run *run;
-       struct kvm_regs regs;
-       struct kvm_sregs sregs;
-       struct kvm_vcpu_events events;
-       int rv, cap;
-       cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
-       TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS);
-       TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD));
-       vm = vm_create_with_one_vcpu(&vcpu, guest_code);
-       run = vcpu->run;
+       struct kvm_run *run = vcpu->run;
+       int rv;
  
        /* Request reading invalid register set from VCPU. */
        run->kvm_valid_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
 -                  "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
 +                  "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
  
        run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
 -                  "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
 +                  "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, set_invalid, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
+       int rv;
  
        /* Request setting invalid register set into VCPU. */
        run->kvm_dirty_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
 -                  "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
 +                  "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
  
        run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
 -                  "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
 +                  "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, req_and_verify_all_valid, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
+       struct kvm_vcpu_events events;
+       struct kvm_sregs sregs;
+       struct kvm_regs regs;
  
        /* Request and verify all valid register sets. */
        /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
        run->kvm_valid_regs = TEST_SYNC_FIELDS;
-       rv = _vcpu_run(vcpu);
+       vcpu_run(vcpu);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
  
        vcpu_regs_get(vcpu, &regs);
  
        vcpu_events_get(vcpu, &events);
        compare_vcpu_events(&events, &run->s.regs.events);
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, set_and_verify_various, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
+       struct kvm_vcpu_events events;
+       struct kvm_sregs sregs;
+       struct kvm_regs regs;
+       /* Run once to get register set */
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       vcpu_run(vcpu);
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
  
        /* Set and verify various register values. */
        run->s.regs.regs.rbx = 0xBAD1DEA;
  
        run->kvm_valid_regs = TEST_SYNC_FIELDS;
        run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
-       rv = _vcpu_run(vcpu);
+       vcpu_run(vcpu);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
        TEST_ASSERT(run->s.regs.regs.rbx == 0xBAD1DEA + 1,
                    "rbx sync regs value incorrect 0x%llx.",
  
        vcpu_events_get(vcpu, &events);
        compare_vcpu_events(&events, &run->s.regs.events);
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_dirty_regs_bits, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
  
        /* Clear kvm_dirty_regs bits, verify new s.regs values are
         * overwritten with existing guest values.
        run->kvm_valid_regs = TEST_SYNC_FIELDS;
        run->kvm_dirty_regs = 0;
        run->s.regs.regs.rbx = 0xDEADBEEF;
-       rv = _vcpu_run(vcpu);
+       vcpu_run(vcpu);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
        TEST_ASSERT(run->s.regs.regs.rbx != 0xDEADBEEF,
                    "rbx sync regs value incorrect 0x%llx.",
                    run->s.regs.regs.rbx);
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_valid_and_dirty_regs, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
+       struct kvm_regs regs;
+       /* Run once to get register set */
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       vcpu_run(vcpu);
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
  
        /* Clear kvm_valid_regs bits and kvm_dirty_bits.
         * Verify s.regs values are not overwritten with existing guest values
        run->kvm_valid_regs = 0;
        run->kvm_dirty_regs = 0;
        run->s.regs.regs.rbx = 0xAAAA;
+       vcpu_regs_get(vcpu, &regs);
        regs.rbx = 0xBAC0;
        vcpu_regs_set(vcpu, &regs);
-       rv = _vcpu_run(vcpu);
+       vcpu_run(vcpu);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
        TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA,
                    "rbx sync regs value incorrect 0x%llx.",
        TEST_ASSERT(regs.rbx == 0xBAC0 + 1,
                    "rbx guest value incorrect 0x%llx.",
                    regs.rbx);
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, clear_kvm_valid_regs_bits, guest_code)
+ {
+       struct kvm_run *run = vcpu->run;
+       struct kvm_regs regs;
+       /* Run once to get register set */
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       vcpu_run(vcpu);
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
  
        /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten
         * with existing guest values but that guest values are overwritten
        run->kvm_valid_regs = 0;
        run->kvm_dirty_regs = TEST_SYNC_FIELDS;
        run->s.regs.regs.rbx = 0xBBBB;
-       rv = _vcpu_run(vcpu);
+       vcpu_run(vcpu);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
        TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB,
                    "rbx sync regs value incorrect 0x%llx.",
        TEST_ASSERT(regs.rbx == 0xBBBB + 1,
                    "rbx guest value incorrect 0x%llx.",
                    regs.rbx);
+ }
  
-       kvm_vm_free(vm);
+ KVM_ONE_VCPU_TEST(sync_regs_test, race_cr4, guest_code)
+ {
+       race_sync_regs(vcpu, race_sregs_cr4);
+ }
+ KVM_ONE_VCPU_TEST(sync_regs_test, race_exc, guest_code)
+ {
+       race_sync_regs(vcpu, race_events_exc);
+ }
  
-       race_sync_regs(race_sregs_cr4);
-       race_sync_regs(race_events_exc);
-       race_sync_regs(race_events_inj_pen);
+ KVM_ONE_VCPU_TEST(sync_regs_test, race_inj_pen, guest_code)
+ {
+       race_sync_regs(vcpu, race_events_inj_pen);
+ }
+ int main(int argc, char *argv[])
+ {
+       int cap;
+       cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
+       TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS);
+       TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD));
  
-       return 0;
+       return test_harness_run(argc, argv);
  }
This page took 0.140972 seconds and 4 git commands to generate.