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