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, %[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 : : "cc", "memory"); \ 19 }) 20 21 #define guest_test_fastop_1(insn, type_t, __val) \ 22 ({ \ 23 type_t val = __val, ex_val = __val, input = __val; \ 24 uint64_t flags, ex_flags; \ 25 \ 26 guest_execute_fastop_1("", insn, ex_val, ex_flags); \ 27 guest_execute_fastop_1(KVM_FEP, insn, val, flags); \ 28 \ 29 __GUEST_ASSERT(val == ex_val, \ 30 "Wanted 0x%lx for '%s 0x%lx', got 0x%lx", \ 31 (uint64_t)ex_val, insn, (uint64_t)input, (uint64_t)val); \ 32 __GUEST_ASSERT(flags == ex_flags, \ 33 "Wanted flags 0x%lx for '%s 0x%lx', got 0x%lx", \ 34 ex_flags, insn, (uint64_t)input, flags); \ 35 }) 36 37 #define guest_execute_fastop_2(FEP, insn, __input, __output, __flags) \ 38 ({ \ 39 __asm__ __volatile__("bt $0, %[output]\n\t" \ 40 FEP insn " %[input], %[output]\n\t" \ 41 "pushfq\n\t" \ 42 "pop %[flags]\n\t" \ 43 : [output]"+r"(__output), [flags]"=r"(__flags) \ 44 : [input]"r"(__input) : "cc", "memory"); \ 45 }) 46 47 #define guest_test_fastop_2(insn, type_t, __val1, __val2) \ 48 ({ \ 49 type_t input = __val1, input2 = __val2, output = __val2, ex_output = __val2; \ 50 uint64_t flags, ex_flags; \ 51 \ 52 guest_execute_fastop_2("", insn, input, ex_output, ex_flags); \ 53 guest_execute_fastop_2(KVM_FEP, insn, input, output, flags); \ 54 \ 55 __GUEST_ASSERT(output == ex_output, \ 56 "Wanted 0x%lx for '%s 0x%lx 0x%lx', got 0x%lx", \ 57 (uint64_t)ex_output, insn, (uint64_t)input, \ 58 (uint64_t)input2, (uint64_t)output); \ 59 __GUEST_ASSERT(flags == ex_flags, \ 60 "Wanted flags 0x%lx for '%s 0x%lx, 0x%lx', got 0x%lx", \ 61 ex_flags, insn, (uint64_t)input, (uint64_t)input2, flags); \ 62 }) 63 64 #define guest_execute_fastop_cl(FEP, insn, __shift, __output, __flags) \ 65 ({ \ 66 __asm__ __volatile__("bt $0, %[output]\n\t" \ 67 FEP insn " %%cl, %[output]\n\t" \ 68 "pushfq\n\t" \ 69 "pop %[flags]\n\t" \ 70 : [output]"+r"(__output), [flags]"=r"(__flags) \ 71 : "c"(__shift) : "cc", "memory"); \ 72 }) 73 74 #define guest_test_fastop_cl(insn, type_t, __val1, __val2) \ 75 ({ \ 76 type_t output = __val2, ex_output = __val2, input = __val2; \ 77 uint8_t shift = __val1; \ 78 uint64_t flags, ex_flags; \ 79 \ 80 guest_execute_fastop_cl("", insn, shift, ex_output, ex_flags); \ 81 guest_execute_fastop_cl(KVM_FEP, insn, shift, output, flags); \ 82 \ 83 __GUEST_ASSERT(output == ex_output, \ 84 "Wanted 0x%lx for '%s 0x%x, 0x%lx', got 0x%lx", \ 85 (uint64_t)ex_output, insn, shift, (uint64_t)input, \ 86 (uint64_t)output); \ 87 __GUEST_ASSERT(flags == ex_flags, \ 88 "Wanted flags 0x%lx for '%s 0x%x, 0x%lx', got 0x%lx", \ 89 ex_flags, insn, shift, (uint64_t)input, flags); \ 90 }) 91 92 static const uint64_t vals[] = { 93 0, 94 1, 95 2, 96 4, 97 7, 98 0x5555555555555555, 99 0xaaaaaaaaaaaaaaaa, 100 0xfefefefefefefefe, 101 0xffffffffffffffff, 102 }; 103 104 #define guest_test_fastops(type_t, suffix) \ 105 do { \ 106 int i, j; \ 107 \ 108 for (i = 0; i < ARRAY_SIZE(vals); i++) { \ 109 guest_test_fastop_1("dec" suffix, type_t, vals[i]); \ 110 guest_test_fastop_1("inc" suffix, type_t, vals[i]); \ 111 guest_test_fastop_1("neg" suffix, type_t, vals[i]); \ 112 guest_test_fastop_1("not" suffix, type_t, vals[i]); \ 113 \ 114 for (j = 0; j < ARRAY_SIZE(vals); j++) { \ 115 guest_test_fastop_2("add" suffix, type_t, vals[i], vals[j]); \ 116 guest_test_fastop_2("adc" suffix, type_t, vals[i], vals[j]); \ 117 guest_test_fastop_2("and" suffix, type_t, vals[i], vals[j]); \ 118 guest_test_fastop_2("bsf" suffix, type_t, vals[i], vals[j]); \ 119 guest_test_fastop_2("bsr" suffix, type_t, vals[i], vals[j]); \ 120 guest_test_fastop_2("bt" suffix, type_t, vals[i], vals[j]); \ 121 guest_test_fastop_2("btc" suffix, type_t, vals[i], vals[j]); \ 122 guest_test_fastop_2("btr" suffix, type_t, vals[i], vals[j]); \ 123 guest_test_fastop_2("bts" suffix, type_t, vals[i], vals[j]); \ 124 guest_test_fastop_2("cmp" suffix, type_t, vals[i], vals[j]); \ 125 guest_test_fastop_2("imul" suffix, type_t, vals[i], vals[j]); \ 126 guest_test_fastop_2("or" suffix, type_t, vals[i], vals[j]); \ 127 guest_test_fastop_2("sbb" suffix, type_t, vals[i], vals[j]); \ 128 guest_test_fastop_2("sub" suffix, type_t, vals[i], vals[j]); \ 129 guest_test_fastop_2("test" suffix, type_t, vals[i], vals[j]); \ 130 guest_test_fastop_2("xor" suffix, type_t, vals[i], vals[j]); \ 131 \ 132 guest_test_fastop_cl("rol" suffix, type_t, vals[i], vals[j]); \ 133 guest_test_fastop_cl("ror" suffix, type_t, vals[i], vals[j]); \ 134 guest_test_fastop_cl("rcl" suffix, type_t, vals[i], vals[j]); \ 135 guest_test_fastop_cl("rcr" suffix, type_t, vals[i], vals[j]); \ 136 guest_test_fastop_cl("sar" suffix, type_t, vals[i], vals[j]); \ 137 guest_test_fastop_cl("shl" suffix, type_t, vals[i], vals[j]); \ 138 guest_test_fastop_cl("shr" suffix, type_t, vals[i], vals[j]); \ 139 } \ 140 } \ 141 } while (0) 142 143 static void guest_code(void) 144 { 145 guest_test_fastops(uint16_t, "w"); 146 guest_test_fastops(uint32_t, "l"); 147 guest_test_fastops(uint64_t, "q"); 148 149 GUEST_DONE(); 150 } 151 152 int main(int argc, char *argv[]) 153 { 154 struct kvm_vcpu *vcpu; 155 struct kvm_vm *vm; 156 157 TEST_REQUIRE(is_forced_emulation_enabled); 158 159 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 160 161 vcpu_run(vcpu); 162 TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); 163 164 kvm_vm_free(vm); 165 } 166