0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define _GNU_SOURCE
0013 #include <fcntl.h>
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <sys/ioctl.h>
0018
0019 #include "test_util.h"
0020 #include "kvm_util.h"
0021 #include "processor.h"
0022
0023 #define UCALL_PIO_PORT ((uint16_t)0x1000)
0024
0025 struct ucall uc_none = {
0026 .cmd = UCALL_NONE,
0027 };
0028
0029
0030
0031
0032
0033
0034 void guest_code(void)
0035 {
0036 asm volatile("1: in %[port], %%al\n"
0037 "add $0x1, %%rbx\n"
0038 "jmp 1b"
0039 : : [port] "d" (UCALL_PIO_PORT), "D" (&uc_none)
0040 : "rax", "rbx");
0041 }
0042
0043 static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
0044 {
0045 #define REG_COMPARE(reg) \
0046 TEST_ASSERT(left->reg == right->reg, \
0047 "Register " #reg \
0048 " values did not match: 0x%llx, 0x%llx\n", \
0049 left->reg, right->reg)
0050 REG_COMPARE(rax);
0051 REG_COMPARE(rbx);
0052 REG_COMPARE(rcx);
0053 REG_COMPARE(rdx);
0054 REG_COMPARE(rsi);
0055 REG_COMPARE(rdi);
0056 REG_COMPARE(rsp);
0057 REG_COMPARE(rbp);
0058 REG_COMPARE(r8);
0059 REG_COMPARE(r9);
0060 REG_COMPARE(r10);
0061 REG_COMPARE(r11);
0062 REG_COMPARE(r12);
0063 REG_COMPARE(r13);
0064 REG_COMPARE(r14);
0065 REG_COMPARE(r15);
0066 REG_COMPARE(rip);
0067 REG_COMPARE(rflags);
0068 #undef REG_COMPARE
0069 }
0070
0071 static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right)
0072 {
0073 }
0074
0075 static void compare_vcpu_events(struct kvm_vcpu_events *left,
0076 struct kvm_vcpu_events *right)
0077 {
0078 }
0079
0080 #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS)
0081 #define INVALID_SYNC_FIELD 0x80000000
0082
0083 int main(int argc, char *argv[])
0084 {
0085 struct kvm_vcpu *vcpu;
0086 struct kvm_vm *vm;
0087 struct kvm_run *run;
0088 struct kvm_regs regs;
0089 struct kvm_sregs sregs;
0090 struct kvm_vcpu_events events;
0091 int rv, cap;
0092
0093
0094 setbuf(stdout, NULL);
0095
0096 cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
0097 TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS);
0098 TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD));
0099
0100 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0101
0102 run = vcpu->run;
0103
0104
0105 run->kvm_valid_regs = INVALID_SYNC_FIELD;
0106 rv = _vcpu_run(vcpu);
0107 TEST_ASSERT(rv < 0 && errno == EINVAL,
0108 "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
0109 rv);
0110 run->kvm_valid_regs = 0;
0111
0112 run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
0113 rv = _vcpu_run(vcpu);
0114 TEST_ASSERT(rv < 0 && errno == EINVAL,
0115 "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
0116 rv);
0117 run->kvm_valid_regs = 0;
0118
0119
0120 run->kvm_dirty_regs = INVALID_SYNC_FIELD;
0121 rv = _vcpu_run(vcpu);
0122 TEST_ASSERT(rv < 0 && errno == EINVAL,
0123 "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
0124 rv);
0125 run->kvm_dirty_regs = 0;
0126
0127 run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
0128 rv = _vcpu_run(vcpu);
0129 TEST_ASSERT(rv < 0 && errno == EINVAL,
0130 "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
0131 rv);
0132 run->kvm_dirty_regs = 0;
0133
0134
0135
0136 run->kvm_valid_regs = TEST_SYNC_FIELDS;
0137 rv = _vcpu_run(vcpu);
0138 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0139 "Unexpected exit reason: %u (%s),\n",
0140 run->exit_reason,
0141 exit_reason_str(run->exit_reason));
0142
0143 vcpu_regs_get(vcpu, ®s);
0144 compare_regs(®s, &run->s.regs.regs);
0145
0146 vcpu_sregs_get(vcpu, &sregs);
0147 compare_sregs(&sregs, &run->s.regs.sregs);
0148
0149 vcpu_events_get(vcpu, &events);
0150 compare_vcpu_events(&events, &run->s.regs.events);
0151
0152
0153 run->s.regs.regs.rbx = 0xBAD1DEA;
0154 run->s.regs.sregs.apic_base = 1 << 11;
0155
0156
0157 run->kvm_valid_regs = TEST_SYNC_FIELDS;
0158 run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
0159 rv = _vcpu_run(vcpu);
0160 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0161 "Unexpected exit reason: %u (%s),\n",
0162 run->exit_reason,
0163 exit_reason_str(run->exit_reason));
0164 TEST_ASSERT(run->s.regs.regs.rbx == 0xBAD1DEA + 1,
0165 "rbx sync regs value incorrect 0x%llx.",
0166 run->s.regs.regs.rbx);
0167 TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11,
0168 "apic_base sync regs value incorrect 0x%llx.",
0169 run->s.regs.sregs.apic_base);
0170
0171 vcpu_regs_get(vcpu, ®s);
0172 compare_regs(®s, &run->s.regs.regs);
0173
0174 vcpu_sregs_get(vcpu, &sregs);
0175 compare_sregs(&sregs, &run->s.regs.sregs);
0176
0177 vcpu_events_get(vcpu, &events);
0178 compare_vcpu_events(&events, &run->s.regs.events);
0179
0180
0181
0182
0183 run->kvm_valid_regs = TEST_SYNC_FIELDS;
0184 run->kvm_dirty_regs = 0;
0185 run->s.regs.regs.rbx = 0xDEADBEEF;
0186 rv = _vcpu_run(vcpu);
0187 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0188 "Unexpected exit reason: %u (%s),\n",
0189 run->exit_reason,
0190 exit_reason_str(run->exit_reason));
0191 TEST_ASSERT(run->s.regs.regs.rbx != 0xDEADBEEF,
0192 "rbx sync regs value incorrect 0x%llx.",
0193 run->s.regs.regs.rbx);
0194
0195
0196
0197
0198
0199 run->kvm_valid_regs = 0;
0200 run->kvm_dirty_regs = 0;
0201 run->s.regs.regs.rbx = 0xAAAA;
0202 regs.rbx = 0xBAC0;
0203 vcpu_regs_set(vcpu, ®s);
0204 rv = _vcpu_run(vcpu);
0205 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0206 "Unexpected exit reason: %u (%s),\n",
0207 run->exit_reason,
0208 exit_reason_str(run->exit_reason));
0209 TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA,
0210 "rbx sync regs value incorrect 0x%llx.",
0211 run->s.regs.regs.rbx);
0212 vcpu_regs_get(vcpu, ®s);
0213 TEST_ASSERT(regs.rbx == 0xBAC0 + 1,
0214 "rbx guest value incorrect 0x%llx.",
0215 regs.rbx);
0216
0217
0218
0219
0220
0221 run->kvm_valid_regs = 0;
0222 run->kvm_dirty_regs = TEST_SYNC_FIELDS;
0223 run->s.regs.regs.rbx = 0xBBBB;
0224 rv = _vcpu_run(vcpu);
0225 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0226 "Unexpected exit reason: %u (%s),\n",
0227 run->exit_reason,
0228 exit_reason_str(run->exit_reason));
0229 TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB,
0230 "rbx sync regs value incorrect 0x%llx.",
0231 run->s.regs.regs.rbx);
0232 vcpu_regs_get(vcpu, ®s);
0233 TEST_ASSERT(regs.rbx == 0xBBBB + 1,
0234 "rbx guest value incorrect 0x%llx.",
0235 regs.rbx);
0236
0237 kvm_vm_free(vm);
0238
0239 return 0;
0240 }