mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	KVM: selftests: add Enlightened VMCS test
Modify test library and add eVMCS test. This includes nVMX save/restore testing. Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									c939989d74
								
							
						
					
					
						commit
						18178ff862
					
				
					 5 changed files with 1321 additions and 10 deletions
				
			
		| 
						 | 
					@ -13,6 +13,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test
 | 
				
			||||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
 | 
					TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
 | 
				
			||||||
TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test
 | 
					TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test
 | 
				
			||||||
TEST_GEN_PROGS_x86_64 += x86_64/state_test
 | 
					TEST_GEN_PROGS_x86_64 += x86_64/state_test
 | 
				
			||||||
 | 
					TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
 | 
				
			||||||
TEST_GEN_PROGS_x86_64 += dirty_log_test
 | 
					TEST_GEN_PROGS_x86_64 += dirty_log_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_GEN_PROGS_aarch64 += dirty_log_test
 | 
					TEST_GEN_PROGS_aarch64 += dirty_log_test
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1098
									
								
								tools/testing/selftests/kvm/include/evmcs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1098
									
								
								tools/testing/selftests/kvm/include/evmcs.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -339,6 +339,8 @@ struct vmx_msr_entry {
 | 
				
			||||||
	uint64_t value;
 | 
						uint64_t value;
 | 
				
			||||||
} __attribute__ ((aligned(16)));
 | 
					} __attribute__ ((aligned(16)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "evmcs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int vmxon(uint64_t phys)
 | 
					static inline int vmxon(uint64_t phys)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t ret;
 | 
						uint8_t ret;
 | 
				
			||||||
| 
						 | 
					@ -372,6 +374,9 @@ static inline int vmptrld(uint64_t vmcs_pa)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t ret;
 | 
						uint8_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]"
 | 
						__asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]"
 | 
				
			||||||
		: [ret]"=rm"(ret)
 | 
							: [ret]"=rm"(ret)
 | 
				
			||||||
		: [pa]"m"(vmcs_pa)
 | 
							: [pa]"m"(vmcs_pa)
 | 
				
			||||||
| 
						 | 
					@ -385,6 +390,9 @@ static inline int vmptrst(uint64_t *value)
 | 
				
			||||||
	uint64_t tmp;
 | 
						uint64_t tmp;
 | 
				
			||||||
	uint8_t ret;
 | 
						uint8_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return evmcs_vmptrst(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__("vmptrst %[value]; setna %[ret]"
 | 
						__asm__ __volatile__("vmptrst %[value]; setna %[ret]"
 | 
				
			||||||
		: [value]"=m"(tmp), [ret]"=rm"(ret)
 | 
							: [value]"=m"(tmp), [ret]"=rm"(ret)
 | 
				
			||||||
		: : "cc", "memory");
 | 
							: : "cc", "memory");
 | 
				
			||||||
| 
						 | 
					@ -411,6 +419,9 @@ static inline int vmlaunch(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return evmcs_vmlaunch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__("push %%rbp;"
 | 
						__asm__ __volatile__("push %%rbp;"
 | 
				
			||||||
			     "push %%rcx;"
 | 
								     "push %%rcx;"
 | 
				
			||||||
			     "push %%rdx;"
 | 
								     "push %%rdx;"
 | 
				
			||||||
| 
						 | 
					@ -443,6 +454,9 @@ static inline int vmresume(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return evmcs_vmresume();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__("push %%rbp;"
 | 
						__asm__ __volatile__("push %%rbp;"
 | 
				
			||||||
			     "push %%rcx;"
 | 
								     "push %%rcx;"
 | 
				
			||||||
			     "push %%rdx;"
 | 
								     "push %%rdx;"
 | 
				
			||||||
| 
						 | 
					@ -482,6 +496,9 @@ static inline int vmread(uint64_t encoding, uint64_t *value)
 | 
				
			||||||
	uint64_t tmp;
 | 
						uint64_t tmp;
 | 
				
			||||||
	uint8_t ret;
 | 
						uint8_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return evmcs_vmread(encoding, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]"
 | 
						__asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]"
 | 
				
			||||||
		: [value]"=rm"(tmp), [ret]"=rm"(ret)
 | 
							: [value]"=rm"(tmp), [ret]"=rm"(ret)
 | 
				
			||||||
		: [encoding]"r"(encoding)
 | 
							: [encoding]"r"(encoding)
 | 
				
			||||||
| 
						 | 
					@ -506,6 +523,9 @@ static inline int vmwrite(uint64_t encoding, uint64_t value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t ret;
 | 
						uint8_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_evmcs)
 | 
				
			||||||
 | 
							return evmcs_vmwrite(encoding, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]"
 | 
						__asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]"
 | 
				
			||||||
		: [ret]"=rm"(ret)
 | 
							: [ret]"=rm"(ret)
 | 
				
			||||||
		: [value]"rm"(value), [encoding]"r"(encoding)
 | 
							: [value]"rm"(value), [encoding]"r"(encoding)
 | 
				
			||||||
| 
						 | 
					@ -543,6 +563,14 @@ struct vmx_pages {
 | 
				
			||||||
	void *vmwrite_hva;
 | 
						void *vmwrite_hva;
 | 
				
			||||||
	uint64_t vmwrite_gpa;
 | 
						uint64_t vmwrite_gpa;
 | 
				
			||||||
	void *vmwrite;
 | 
						void *vmwrite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *vp_assist_hva;
 | 
				
			||||||
 | 
						uint64_t vp_assist_gpa;
 | 
				
			||||||
 | 
						void *vp_assist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *enlightened_vmcs_hva;
 | 
				
			||||||
 | 
						uint64_t enlightened_vmcs_gpa;
 | 
				
			||||||
 | 
						void *enlightened_vmcs;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva);
 | 
					struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,8 @@
 | 
				
			||||||
#include "processor.h"
 | 
					#include "processor.h"
 | 
				
			||||||
#include "vmx.h"
 | 
					#include "vmx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool enable_evmcs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Allocate memory regions for nested VMX tests.
 | 
					/* Allocate memory regions for nested VMX tests.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Input Args:
 | 
					 * Input Args:
 | 
				
			||||||
| 
						 | 
					@ -62,6 +64,20 @@ vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva)
 | 
				
			||||||
	vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite);
 | 
						vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite);
 | 
				
			||||||
	memset(vmx->vmwrite_hva, 0, getpagesize());
 | 
						memset(vmx->vmwrite_hva, 0, getpagesize());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Setup of a region of guest memory for the VP Assist page. */
 | 
				
			||||||
 | 
						vmx->vp_assist = (void *)vm_vaddr_alloc(vm, getpagesize(),
 | 
				
			||||||
 | 
											0x10000, 0, 0);
 | 
				
			||||||
 | 
						vmx->vp_assist_hva = addr_gva2hva(vm, (uintptr_t)vmx->vp_assist);
 | 
				
			||||||
 | 
						vmx->vp_assist_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vp_assist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Setup of a region of guest memory for the enlightened VMCS. */
 | 
				
			||||||
 | 
						vmx->enlightened_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(),
 | 
				
			||||||
 | 
											       0x10000, 0, 0);
 | 
				
			||||||
 | 
						vmx->enlightened_vmcs_hva =
 | 
				
			||||||
 | 
							addr_gva2hva(vm, (uintptr_t)vmx->enlightened_vmcs);
 | 
				
			||||||
 | 
						vmx->enlightened_vmcs_gpa =
 | 
				
			||||||
 | 
							addr_gva2gpa(vm, (uintptr_t)vmx->enlightened_vmcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*p_vmx_gva = vmx_gva;
 | 
						*p_vmx_gva = vmx_gva;
 | 
				
			||||||
	return vmx;
 | 
						return vmx;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -112,18 +128,26 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool load_vmcs(struct vmx_pages *vmx)
 | 
					bool load_vmcs(struct vmx_pages *vmx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Load a VMCS. */
 | 
						if (!enable_evmcs) {
 | 
				
			||||||
	*(uint32_t *)(vmx->vmcs) = vmcs_revision();
 | 
							/* Load a VMCS. */
 | 
				
			||||||
	if (vmclear(vmx->vmcs_gpa))
 | 
							*(uint32_t *)(vmx->vmcs) = vmcs_revision();
 | 
				
			||||||
		return false;
 | 
							if (vmclear(vmx->vmcs_gpa))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vmptrld(vmx->vmcs_gpa))
 | 
							if (vmptrld(vmx->vmcs_gpa))
 | 
				
			||||||
		return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Setup shadow VMCS, do not load it yet. */
 | 
							/* Setup shadow VMCS, do not load it yet. */
 | 
				
			||||||
	*(uint32_t *)(vmx->shadow_vmcs) = vmcs_revision() | 0x80000000ul;
 | 
							*(uint32_t *)(vmx->shadow_vmcs) =
 | 
				
			||||||
	if (vmclear(vmx->shadow_vmcs_gpa))
 | 
								vmcs_revision() | 0x80000000ul;
 | 
				
			||||||
		return false;
 | 
							if (vmclear(vmx->shadow_vmcs_gpa))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (evmcs_vmptrld(vmx->enlightened_vmcs_gpa,
 | 
				
			||||||
 | 
									  vmx->enlightened_vmcs))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							current_evmcs->revision_id = vmcs_revision();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										160
									
								
								tools/testing/selftests/kvm/x86_64/evmcs_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								tools/testing/selftests/kvm/x86_64/evmcs_test.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,160 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2018, Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Tests for Enlightened VMCS, including nested guest state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define _GNU_SOURCE /* for program_invocation_short_name */
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "test_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "kvm_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vmx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VCPU_ID		5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool have_nested_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void l2_guest_code(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GUEST_SYNC(6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GUEST_SYNC(7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Done, exit to L1 and never come back.  */
 | 
				
			||||||
 | 
						vmcall();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void l1_guest_code(struct vmx_pages *vmx_pages)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#define L2_GUEST_STACK_SIZE 64
 | 
				
			||||||
 | 
						unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enable_vp_assist(vmx_pages->vp_assist_gpa, vmx_pages->vp_assist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmx_pages->vmcs_gpa);
 | 
				
			||||||
 | 
						GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
 | 
				
			||||||
 | 
						GUEST_SYNC(3);
 | 
				
			||||||
 | 
						GUEST_ASSERT(load_vmcs(vmx_pages));
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GUEST_SYNC(4);
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prepare_vmcs(vmx_pages, l2_guest_code,
 | 
				
			||||||
 | 
							     &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GUEST_SYNC(5);
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
 | 
				
			||||||
 | 
						GUEST_ASSERT(!vmlaunch());
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
 | 
				
			||||||
 | 
						GUEST_SYNC(8);
 | 
				
			||||||
 | 
						GUEST_ASSERT(!vmresume());
 | 
				
			||||||
 | 
						GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
 | 
				
			||||||
 | 
						GUEST_SYNC(9);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void guest_code(struct vmx_pages *vmx_pages)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GUEST_SYNC(1);
 | 
				
			||||||
 | 
						GUEST_SYNC(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vmx_pages)
 | 
				
			||||||
 | 
							l1_guest_code(vmx_pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GUEST_DONE();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vmx_pages *vmx_pages = NULL;
 | 
				
			||||||
 | 
						vm_vaddr_t vmx_pages_gva = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct kvm_regs regs1, regs2;
 | 
				
			||||||
 | 
						struct kvm_vm *vm;
 | 
				
			||||||
 | 
						struct kvm_run *run;
 | 
				
			||||||
 | 
						struct kvm_x86_state *state;
 | 
				
			||||||
 | 
						struct ucall uc;
 | 
				
			||||||
 | 
						int stage;
 | 
				
			||||||
 | 
						uint16_t evmcs_ver;
 | 
				
			||||||
 | 
						struct kvm_enable_cap enable_evmcs_cap = {
 | 
				
			||||||
 | 
							.cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
 | 
				
			||||||
 | 
							 .args[0] = (unsigned long)&evmcs_ver
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create VM */
 | 
				
			||||||
 | 
						vm = vm_create_default(VCPU_ID, 0, guest_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!kvm_check_cap(KVM_CAP_NESTED_STATE) ||
 | 
				
			||||||
 | 
						    !kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) {
 | 
				
			||||||
 | 
							printf("capabilities not available, skipping test\n");
 | 
				
			||||||
 | 
							exit(KSFT_SKIP);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						run = vcpu_state(vm, VCPU_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vcpu_regs_get(vm, VCPU_ID, ®s1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vmx_pages = vcpu_alloc_vmx(vm, &vmx_pages_gva);
 | 
				
			||||||
 | 
						vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (stage = 1;; stage++) {
 | 
				
			||||||
 | 
							_vcpu_run(vm, VCPU_ID);
 | 
				
			||||||
 | 
							TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
 | 
				
			||||||
 | 
								    "Unexpected exit reason: %u (%s),\n",
 | 
				
			||||||
 | 
								    run->exit_reason,
 | 
				
			||||||
 | 
								    exit_reason_str(run->exit_reason));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(®s1, 0, sizeof(regs1));
 | 
				
			||||||
 | 
							vcpu_regs_get(vm, VCPU_ID, ®s1);
 | 
				
			||||||
 | 
							switch (get_ucall(vm, VCPU_ID, &uc)) {
 | 
				
			||||||
 | 
							case UCALL_ABORT:
 | 
				
			||||||
 | 
								TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0],
 | 
				
			||||||
 | 
									    __FILE__, uc.args[1]);
 | 
				
			||||||
 | 
								/* NOT REACHED */
 | 
				
			||||||
 | 
							case UCALL_SYNC:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case UCALL_DONE:
 | 
				
			||||||
 | 
								goto done;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* UCALL_SYNC is handled here.  */
 | 
				
			||||||
 | 
							TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
 | 
				
			||||||
 | 
								    uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx",
 | 
				
			||||||
 | 
								    stage, (ulong)uc.args[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							state = vcpu_save_state(vm, VCPU_ID);
 | 
				
			||||||
 | 
							kvm_vm_release(vm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Restore state in a new VM.  */
 | 
				
			||||||
 | 
							kvm_vm_restart(vm, O_RDWR);
 | 
				
			||||||
 | 
							vm_vcpu_add(vm, VCPU_ID, 0, 0);
 | 
				
			||||||
 | 
							vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
 | 
				
			||||||
 | 
							vcpu_load_state(vm, VCPU_ID, state);
 | 
				
			||||||
 | 
							run = vcpu_state(vm, VCPU_ID);
 | 
				
			||||||
 | 
							free(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(®s2, 0, sizeof(regs2));
 | 
				
			||||||
 | 
							vcpu_regs_get(vm, VCPU_ID, ®s2);
 | 
				
			||||||
 | 
							TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)),
 | 
				
			||||||
 | 
								    "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
 | 
				
			||||||
 | 
								    (ulong) regs2.rdi, (ulong) regs2.rsi);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						kvm_vm_free(vm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue