xref: /linux/tools/testing/selftests/kvm/x86/fastops_test.c (revision 9bf5da1ca4275c0403de763547f21f29795f8366)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include "test_util.h"
3 #include "kvm_util.h"
4 #include "processor.h"
5 
6 /*
7  * Execute a fastop() instruction, with or without forced emulation.  BT bit 0
8  * to set RFLAGS.CF based on whether or not the input is even or odd, so that
9  * instructions like ADC and SBB are deterministic.
10  */
11 #define guest_execute_fastop_1(FEP, insn, __val, __flags)				\
12 ({											\
13 	__asm__ __volatile__("bt $0, %[ro_val]\n\t"					\
14 			     FEP insn " %[val]\n\t"					\
15 			     "pushfq\n\t"						\
16 			     "pop %[flags]\n\t"						\
17 			     : [val]"+r"(__val), [flags]"=r"(__flags)			\
18 			     : [ro_val]"rm"((uint32_t)__val)				\
19 			     : "cc", "memory");						\
20 })
21 
22 #define guest_test_fastop_1(insn, type_t, __val)					\
23 ({											\
24 	type_t val = __val, ex_val = __val, input = __val;				\
25 	uint64_t flags, ex_flags;							\
26 											\
27 	guest_execute_fastop_1("", insn, ex_val, ex_flags);				\
28 	guest_execute_fastop_1(KVM_FEP, insn, val, flags);				\
29 											\
30 	__GUEST_ASSERT(val == ex_val,							\
31 		       "Wanted 0x%lx for '%s 0x%lx', got 0x%lx",			\
32 		       (uint64_t)ex_val, insn, (uint64_t)input, (uint64_t)val);		\
33 	__GUEST_ASSERT(flags == ex_flags,						\
34 			"Wanted flags 0x%lx for '%s 0x%lx', got 0x%lx",			\
35 			ex_flags, insn, (uint64_t)input, flags);			\
36 })
37 
38 #define guest_execute_fastop_2(FEP, insn, __input, __output, __flags)			\
39 ({											\
40 	__asm__ __volatile__("bt $0, %[ro_val]\n\t"					\
41 			     FEP insn " %[input], %[output]\n\t"			\
42 			     "pushfq\n\t"						\
43 			     "pop %[flags]\n\t"						\
44 			     : [output]"+r"(__output), [flags]"=r"(__flags)		\
45 			     : [input]"r"(__input), [ro_val]"rm"((uint32_t)__output)	\
46 			     : "cc", "memory");						\
47 })
48 
49 #define guest_test_fastop_2(insn, type_t, __val1, __val2)				\
50 ({											\
51 	type_t input = __val1, input2 = __val2, output = __val2, ex_output = __val2;	\
52 	uint64_t flags, ex_flags;							\
53 											\
54 	guest_execute_fastop_2("", insn, input, ex_output, ex_flags);			\
55 	guest_execute_fastop_2(KVM_FEP, insn, input, output, flags);			\
56 											\
57 	__GUEST_ASSERT(output == ex_output,						\
58 		       "Wanted 0x%lx for '%s 0x%lx 0x%lx', got 0x%lx",			\
59 		       (uint64_t)ex_output, insn, (uint64_t)input,			\
60 		       (uint64_t)input2, (uint64_t)output);				\
61 	__GUEST_ASSERT(flags == ex_flags,						\
62 			"Wanted flags 0x%lx for '%s 0x%lx, 0x%lx', got 0x%lx",		\
63 			ex_flags, insn, (uint64_t)input, (uint64_t)input2, flags);	\
64 })
65 
66 #define guest_execute_fastop_cl(FEP, insn, __shift, __output, __flags)			\
67 ({											\
68 	__asm__ __volatile__("bt $0, %[ro_val]\n\t"					\
69 			     FEP insn " %%cl, %[output]\n\t"				\
70 			     "pushfq\n\t"						\
71 			     "pop %[flags]\n\t"						\
72 			     : [output]"+r"(__output), [flags]"=r"(__flags)		\
73 			     : "c"(__shift), [ro_val]"rm"((uint32_t)__output)		\
74 			     : "cc", "memory");						\
75 })
76 
77 #define guest_test_fastop_cl(insn, type_t, __val1, __val2)				\
78 ({											\
79 	type_t output = __val2, ex_output = __val2, input = __val2;			\
80 	uint8_t shift = __val1;								\
81 	uint64_t flags, ex_flags;							\
82 											\
83 	guest_execute_fastop_cl("", insn, shift, ex_output, ex_flags);			\
84 	guest_execute_fastop_cl(KVM_FEP, insn, shift, output, flags);			\
85 											\
86 	__GUEST_ASSERT(output == ex_output,						\
87 		       "Wanted 0x%lx for '%s 0x%x, 0x%lx', got 0x%lx",			\
88 		       (uint64_t)ex_output, insn, shift, (uint64_t)input,		\
89 		       (uint64_t)output);						\
90 	__GUEST_ASSERT(flags == ex_flags,						\
91 			"Wanted flags 0x%lx for '%s 0x%x, 0x%lx', got 0x%lx",		\
92 			ex_flags, insn, shift, (uint64_t)input, flags);			\
93 })
94 
95 static const uint64_t vals[] = {
96 	0,
97 	1,
98 	2,
99 	4,
100 	7,
101 	0x5555555555555555,
102 	0xaaaaaaaaaaaaaaaa,
103 	0xfefefefefefefefe,
104 	0xffffffffffffffff,
105 };
106 
107 #define guest_test_fastops(type_t, suffix)						\
108 do {											\
109 	int i, j;									\
110 											\
111 	for (i = 0; i < ARRAY_SIZE(vals); i++) {					\
112 		guest_test_fastop_1("dec" suffix, type_t, vals[i]);			\
113 		guest_test_fastop_1("inc" suffix, type_t, vals[i]);			\
114 		guest_test_fastop_1("neg" suffix, type_t, vals[i]);			\
115 		guest_test_fastop_1("not" suffix, type_t, vals[i]);			\
116 											\
117 		for (j = 0; j < ARRAY_SIZE(vals); j++) {				\
118 			guest_test_fastop_2("add" suffix, type_t, vals[i], vals[j]);	\
119 			guest_test_fastop_2("adc" suffix, type_t, vals[i], vals[j]);	\
120 			guest_test_fastop_2("and" suffix, type_t, vals[i], vals[j]);	\
121 if (sizeof(type_t) != 1) {							\
122 			guest_test_fastop_2("bsf" suffix, type_t, vals[i], vals[j]);	\
123 			guest_test_fastop_2("bsr" suffix, type_t, vals[i], vals[j]);	\
124 			guest_test_fastop_2("bt" suffix, type_t, vals[i], vals[j]);	\
125 			guest_test_fastop_2("btc" suffix, type_t, vals[i], vals[j]);	\
126 			guest_test_fastop_2("btr" suffix, type_t, vals[i], vals[j]);	\
127 			guest_test_fastop_2("bts" suffix, type_t, vals[i], vals[j]);	\
128 			guest_test_fastop_2("imul" suffix, type_t, vals[i], vals[j]);	\
129 }											\
130 			guest_test_fastop_2("cmp" suffix, type_t, vals[i], vals[j]);	\
131 			guest_test_fastop_2("or" suffix, type_t, vals[i], vals[j]);	\
132 			guest_test_fastop_2("sbb" suffix, type_t, vals[i], vals[j]);	\
133 			guest_test_fastop_2("sub" suffix, type_t, vals[i], vals[j]);	\
134 			guest_test_fastop_2("test" suffix, type_t, vals[i], vals[j]);	\
135 			guest_test_fastop_2("xor" suffix, type_t, vals[i], vals[j]);	\
136 											\
137 			guest_test_fastop_cl("rol" suffix, type_t, vals[i], vals[j]);	\
138 			guest_test_fastop_cl("ror" suffix, type_t, vals[i], vals[j]);	\
139 			guest_test_fastop_cl("rcl" suffix, type_t, vals[i], vals[j]);	\
140 			guest_test_fastop_cl("rcr" suffix, type_t, vals[i], vals[j]);	\
141 			guest_test_fastop_cl("sar" suffix, type_t, vals[i], vals[j]);	\
142 			guest_test_fastop_cl("shl" suffix, type_t, vals[i], vals[j]);	\
143 			guest_test_fastop_cl("shr" suffix, type_t, vals[i], vals[j]);	\
144 		}									\
145 	}										\
146 } while (0)
147 
148 static void guest_code(void)
149 {
150 	guest_test_fastops(uint8_t, "b");
151 	guest_test_fastops(uint16_t, "w");
152 	guest_test_fastops(uint32_t, "l");
153 	guest_test_fastops(uint64_t, "q");
154 
155 	GUEST_DONE();
156 }
157 
158 int main(int argc, char *argv[])
159 {
160 	struct kvm_vcpu *vcpu;
161 	struct kvm_vm *vm;
162 
163 	TEST_REQUIRE(is_forced_emulation_enabled);
164 
165 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
166 
167 	vcpu_run(vcpu);
168 	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
169 
170 	kvm_vm_free(vm);
171 }
172