aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Xu <peterx@redhat.com>2018-08-22 03:19:57 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2018-08-22 10:48:37 -0400
commit4e18bccc2e5544f0be28fc1c4e6be47a469d6c60 (patch)
treed334c9b09f5e94cb97c85ac487d4da9bf75cf86f
parent07a262cc7c586e3f385a61b8870b0913bf31309a (diff)
kvm: selftest: unify the guest port macros
Most of the tests are using the same way to do guest to host sync but the code is mostly duplicated. Generalize the guest port macros into the common header file and use it in different tests. Meanwhile provide "struct guest_args" and a helper "guest_args_read()" to hide the register details when playing with these port operations on RDI and RSI. Signed-off-by: Peter Xu <peterx@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--tools/testing/selftests/kvm/cr4_cpuid_sync_test.c30
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util.h39
-rw-r--r--tools/testing/selftests/kvm/lib/kvm_util.c14
-rw-r--r--tools/testing/selftests/kvm/state_test.c30
-rw-r--r--tools/testing/selftests/kvm/sync_regs_test.c19
-rw-r--r--tools/testing/selftests/kvm/vmx_tsc_adjust_test.c41
6 files changed, 78 insertions, 95 deletions
diff --git a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c
index 8346b33c2073..d46b42274fd5 100644
--- a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c
+++ b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c
@@ -23,20 +23,6 @@
23#define X86_FEATURE_OSXSAVE (1<<27) 23#define X86_FEATURE_OSXSAVE (1<<27)
24#define VCPU_ID 1 24#define VCPU_ID 1
25 25
26enum {
27 GUEST_UPDATE_CR4 = 0x1000,
28 GUEST_FAILED,
29 GUEST_DONE,
30};
31
32static void exit_to_hv(uint16_t port)
33{
34 __asm__ __volatile__("in %[port], %%al"
35 :
36 : [port]"d"(port)
37 : "rax");
38}
39
40static inline bool cr4_cpuid_is_sync(void) 26static inline bool cr4_cpuid_is_sync(void)
41{ 27{
42 int func, subfunc; 28 int func, subfunc;
@@ -64,17 +50,15 @@ static void guest_code(void)
64 set_cr4(cr4); 50 set_cr4(cr4);
65 51
66 /* verify CR4.OSXSAVE == CPUID.OSXSAVE */ 52 /* verify CR4.OSXSAVE == CPUID.OSXSAVE */
67 if (!cr4_cpuid_is_sync()) 53 GUEST_ASSERT(cr4_cpuid_is_sync());
68 exit_to_hv(GUEST_FAILED);
69 54
70 /* notify hypervisor to change CR4 */ 55 /* notify hypervisor to change CR4 */
71 exit_to_hv(GUEST_UPDATE_CR4); 56 GUEST_SYNC(0);
72 57
73 /* check again */ 58 /* check again */
74 if (!cr4_cpuid_is_sync()) 59 GUEST_ASSERT(cr4_cpuid_is_sync());
75 exit_to_hv(GUEST_FAILED);
76 60
77 exit_to_hv(GUEST_DONE); 61 GUEST_DONE();
78} 62}
79 63
80int main(int argc, char *argv[]) 64int main(int argc, char *argv[])
@@ -104,16 +88,16 @@ int main(int argc, char *argv[])
104 88
105 if (run->exit_reason == KVM_EXIT_IO) { 89 if (run->exit_reason == KVM_EXIT_IO) {
106 switch (run->io.port) { 90 switch (run->io.port) {
107 case GUEST_UPDATE_CR4: 91 case GUEST_PORT_SYNC:
108 /* emulate hypervisor clearing CR4.OSXSAVE */ 92 /* emulate hypervisor clearing CR4.OSXSAVE */
109 vcpu_sregs_get(vm, VCPU_ID, &sregs); 93 vcpu_sregs_get(vm, VCPU_ID, &sregs);
110 sregs.cr4 &= ~X86_CR4_OSXSAVE; 94 sregs.cr4 &= ~X86_CR4_OSXSAVE;
111 vcpu_sregs_set(vm, VCPU_ID, &sregs); 95 vcpu_sregs_set(vm, VCPU_ID, &sregs);
112 break; 96 break;
113 case GUEST_FAILED: 97 case GUEST_PORT_ABORT:
114 TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); 98 TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
115 break; 99 break;
116 case GUEST_DONE: 100 case GUEST_PORT_DONE:
117 goto done; 101 goto done;
118 default: 102 default:
119 TEST_ASSERT(false, "Unknown port 0x%x.", 103 TEST_ASSERT(false, "Unknown port 0x%x.",
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index d32632f71ab8..d8ca48687e35 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -144,4 +144,43 @@ allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region);
144 144
145int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); 145int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd);
146 146
147#define GUEST_PORT_SYNC 0x1000
148#define GUEST_PORT_ABORT 0x1001
149#define GUEST_PORT_DONE 0x1002
150
151static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
152{
153 __asm__ __volatile__("in %[port], %%al"
154 :
155 : [port]"d"(port), "D"(arg0), "S"(arg1)
156 : "rax");
157}
158
159/*
160 * Allows to pass three arguments to the host: port is 16bit wide,
161 * arg0 & arg1 are 64bit wide
162 */
163#define GUEST_SYNC_ARGS(_port, _arg0, _arg1) \
164 __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
165
166#define GUEST_ASSERT(_condition) do { \
167 if (!(_condition)) \
168 GUEST_SYNC_ARGS(GUEST_PORT_ABORT, \
169 "Failed guest assert: " \
170 #_condition, __LINE__); \
171 } while (0)
172
173#define GUEST_SYNC(stage) GUEST_SYNC_ARGS(GUEST_PORT_SYNC, "hello", stage)
174
175#define GUEST_DONE() GUEST_SYNC_ARGS(GUEST_PORT_DONE, 0, 0)
176
177struct guest_args {
178 uint64_t arg0;
179 uint64_t arg1;
180 uint16_t port;
181} __attribute__ ((packed));
182
183void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id,
184 struct guest_args *args);
185
147#endif /* SELFTEST_KVM_UTIL_H */ 186#endif /* SELFTEST_KVM_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 643309d6de74..97d344303c92 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1536,3 +1536,17 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva)
1536{ 1536{
1537 return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); 1537 return addr_gpa2hva(vm, addr_gva2gpa(vm, gva));
1538} 1538}
1539
1540void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id,
1541 struct guest_args *args)
1542{
1543 struct kvm_run *run = vcpu_state(vm, vcpu_id);
1544 struct kvm_regs regs;
1545
1546 memset(&regs, 0, sizeof(regs));
1547 vcpu_regs_get(vm, vcpu_id, &regs);
1548
1549 args->port = run->io.port;
1550 args->arg0 = regs.rdi;
1551 args->arg1 = regs.rsi;
1552}
diff --git a/tools/testing/selftests/kvm/state_test.c b/tools/testing/selftests/kvm/state_test.c
index ecabf25b7077..438d7b828581 100644
--- a/tools/testing/selftests/kvm/state_test.c
+++ b/tools/testing/selftests/kvm/state_test.c
@@ -21,28 +21,6 @@
21#include "vmx.h" 21#include "vmx.h"
22 22
23#define VCPU_ID 5 23#define VCPU_ID 5
24#define PORT_SYNC 0x1000
25#define PORT_ABORT 0x1001
26#define PORT_DONE 0x1002
27
28static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
29{
30 __asm__ __volatile__("in %[port], %%al"
31 :
32 : [port]"d"(port), "D"(arg0), "S"(arg1)
33 : "rax");
34}
35
36#define exit_to_l0(_port, _arg0, _arg1) \
37 __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
38
39#define GUEST_ASSERT(_condition) do { \
40 if (!(_condition)) \
41 exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, __LINE__);\
42} while (0)
43
44#define GUEST_SYNC(stage) \
45 exit_to_l0(PORT_SYNC, "hello", stage);
46 24
47static bool have_nested_state; 25static bool have_nested_state;
48 26
@@ -137,7 +115,7 @@ void guest_code(struct vmx_pages *vmx_pages)
137 if (vmx_pages) 115 if (vmx_pages)
138 l1_guest_code(vmx_pages); 116 l1_guest_code(vmx_pages);
139 117
140 exit_to_l0(PORT_DONE, 0, 0); 118 GUEST_DONE();
141} 119}
142 120
143int main(int argc, char *argv[]) 121int main(int argc, char *argv[])
@@ -178,13 +156,13 @@ int main(int argc, char *argv[])
178 memset(&regs1, 0, sizeof(regs1)); 156 memset(&regs1, 0, sizeof(regs1));
179 vcpu_regs_get(vm, VCPU_ID, &regs1); 157 vcpu_regs_get(vm, VCPU_ID, &regs1);
180 switch (run->io.port) { 158 switch (run->io.port) {
181 case PORT_ABORT: 159 case GUEST_PORT_ABORT:
182 TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi, 160 TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi,
183 __FILE__, regs1.rsi); 161 __FILE__, regs1.rsi);
184 /* NOT REACHED */ 162 /* NOT REACHED */
185 case PORT_SYNC: 163 case GUEST_PORT_SYNC:
186 break; 164 break;
187 case PORT_DONE: 165 case GUEST_PORT_DONE:
188 goto done; 166 goto done;
189 default: 167 default:
190 TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); 168 TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port);
diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/sync_regs_test.c
index eae1ece3c31b..2dbf2e1af6c6 100644
--- a/tools/testing/selftests/kvm/sync_regs_test.c
+++ b/tools/testing/selftests/kvm/sync_regs_test.c
@@ -22,28 +22,11 @@
22#include "x86.h" 22#include "x86.h"
23 23
24#define VCPU_ID 5 24#define VCPU_ID 5
25#define PORT_HOST_SYNC 0x1000
26
27static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
28{
29 __asm__ __volatile__("in %[port], %%al"
30 :
31 : [port]"d"(port), "D"(arg0), "S"(arg1)
32 : "rax");
33}
34
35#define exit_to_l0(_port, _arg0, _arg1) \
36 __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
37
38#define GUEST_ASSERT(_condition) do { \
39 if (!(_condition)) \
40 exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\
41} while (0)
42 25
43void guest_code(void) 26void guest_code(void)
44{ 27{
45 for (;;) { 28 for (;;) {
46 exit_to_l0(PORT_HOST_SYNC, "hello", 0); 29 GUEST_SYNC(0);
47 asm volatile ("inc %r11"); 30 asm volatile ("inc %r11");
48 } 31 }
49} 32}
diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c
index fc414c284368..4ddae120a9ea 100644
--- a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c
+++ b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c
@@ -62,27 +62,12 @@ struct kvm_single_msr {
62/* The virtual machine object. */ 62/* The virtual machine object. */
63static struct kvm_vm *vm; 63static struct kvm_vm *vm;
64 64
65#define exit_to_l0(_port, _arg) do_exit_to_l0(_port, (unsigned long) (_arg))
66static void do_exit_to_l0(uint16_t port, unsigned long arg)
67{
68 __asm__ __volatile__("in %[port], %%al"
69 :
70 : [port]"d"(port), "D"(arg)
71 : "rax");
72}
73
74
75#define GUEST_ASSERT(_condition) do { \
76 if (!(_condition)) \
77 exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition); \
78} while (0)
79
80static void check_ia32_tsc_adjust(int64_t max) 65static void check_ia32_tsc_adjust(int64_t max)
81{ 66{
82 int64_t adjust; 67 int64_t adjust;
83 68
84 adjust = rdmsr(MSR_IA32_TSC_ADJUST); 69 adjust = rdmsr(MSR_IA32_TSC_ADJUST);
85 exit_to_l0(PORT_REPORT, adjust); 70 GUEST_SYNC(adjust);
86 GUEST_ASSERT(adjust <= max); 71 GUEST_ASSERT(adjust <= max);
87} 72}
88 73
@@ -132,7 +117,7 @@ static void l1_guest_code(struct vmx_pages *vmx_pages)
132 117
133 check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); 118 check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE);
134 119
135 exit_to_l0(PORT_DONE, 0); 120 GUEST_DONE();
136} 121}
137 122
138void report(int64_t val) 123void report(int64_t val)
@@ -161,26 +146,26 @@ int main(int argc, char *argv[])
161 146
162 for (;;) { 147 for (;;) {
163 volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); 148 volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
164 struct kvm_regs regs; 149 struct guest_args args;
165 150
166 vcpu_run(vm, VCPU_ID); 151 vcpu_run(vm, VCPU_ID);
167 vcpu_regs_get(vm, VCPU_ID, &regs); 152 guest_args_read(vm, VCPU_ID, &args);
168 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, 153 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
169 "Got exit_reason other than KVM_EXIT_IO: %u (%s), rip=%lx\n", 154 "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
170 run->exit_reason, 155 run->exit_reason,
171 exit_reason_str(run->exit_reason), regs.rip); 156 exit_reason_str(run->exit_reason));
172 157
173 switch (run->io.port) { 158 switch (args.port) {
174 case PORT_ABORT: 159 case GUEST_PORT_ABORT:
175 TEST_ASSERT(false, "%s", (const char *) regs.rdi); 160 TEST_ASSERT(false, "%s", (const char *) args.arg0);
176 /* NOT REACHED */ 161 /* NOT REACHED */
177 case PORT_REPORT: 162 case GUEST_PORT_SYNC:
178 report(regs.rdi); 163 report(args.arg1);
179 break; 164 break;
180 case PORT_DONE: 165 case GUEST_PORT_DONE:
181 goto done; 166 goto done;
182 default: 167 default:
183 TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); 168 TEST_ASSERT(false, "Unknown port 0x%x.", args.port);
184 } 169 }
185 } 170 }
186 171