#define X86_FEATURE_OSXSAVE (1<<27)
#define VCPU_ID 1
-enum {
- GUEST_UPDATE_CR4 = 0x1000,
- GUEST_FAILED,
- GUEST_DONE,
-};
-
-static void exit_to_hv(uint16_t port)
-{
- __asm__ __volatile__("in %[port], %%al"
- :
- : [port]"d"(port)
- : "rax");
-}
-
static inline bool cr4_cpuid_is_sync(void)
{
int func, subfunc;
set_cr4(cr4);
/* verify CR4.OSXSAVE == CPUID.OSXSAVE */
- if (!cr4_cpuid_is_sync())
- exit_to_hv(GUEST_FAILED);
+ GUEST_ASSERT(cr4_cpuid_is_sync());
/* notify hypervisor to change CR4 */
- exit_to_hv(GUEST_UPDATE_CR4);
+ GUEST_SYNC(0);
/* check again */
- if (!cr4_cpuid_is_sync())
- exit_to_hv(GUEST_FAILED);
+ GUEST_ASSERT(cr4_cpuid_is_sync());
- exit_to_hv(GUEST_DONE);
+ GUEST_DONE();
}
int main(int argc, char *argv[])
if (run->exit_reason == KVM_EXIT_IO) {
switch (run->io.port) {
- case GUEST_UPDATE_CR4:
+ case GUEST_PORT_SYNC:
/* emulate hypervisor clearing CR4.OSXSAVE */
vcpu_sregs_get(vm, VCPU_ID, &sregs);
sregs.cr4 &= ~X86_CR4_OSXSAVE;
vcpu_sregs_set(vm, VCPU_ID, &sregs);
break;
- case GUEST_FAILED:
+ case GUEST_PORT_ABORT:
TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
break;
- case GUEST_DONE:
+ case GUEST_PORT_DONE:
goto done;
default:
TEST_ASSERT(false, "Unknown port 0x%x.",
int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd);
+#define GUEST_PORT_SYNC 0x1000
+#define GUEST_PORT_ABORT 0x1001
+#define GUEST_PORT_DONE 0x1002
+
+static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
+{
+ __asm__ __volatile__("in %[port], %%al"
+ :
+ : [port]"d"(port), "D"(arg0), "S"(arg1)
+ : "rax");
+}
+
+/*
+ * Allows to pass three arguments to the host: port is 16bit wide,
+ * arg0 & arg1 are 64bit wide
+ */
+#define GUEST_SYNC_ARGS(_port, _arg0, _arg1) \
+ __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
+
+#define GUEST_ASSERT(_condition) do { \
+ if (!(_condition)) \
+ GUEST_SYNC_ARGS(GUEST_PORT_ABORT, \
+ "Failed guest assert: " \
+ #_condition, __LINE__); \
+ } while (0)
+
+#define GUEST_SYNC(stage) GUEST_SYNC_ARGS(GUEST_PORT_SYNC, "hello", stage)
+
+#define GUEST_DONE() GUEST_SYNC_ARGS(GUEST_PORT_DONE, 0, 0)
+
+struct guest_args {
+ uint64_t arg0;
+ uint64_t arg1;
+ uint16_t port;
+} __attribute__ ((packed));
+
+void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id,
+ struct guest_args *args);
+
#endif /* SELFTEST_KVM_UTIL_H */
{
return addr_gpa2hva(vm, addr_gva2gpa(vm, gva));
}
+
+void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id,
+ struct guest_args *args)
+{
+ struct kvm_run *run = vcpu_state(vm, vcpu_id);
+ struct kvm_regs regs;
+
+ memset(®s, 0, sizeof(regs));
+ vcpu_regs_get(vm, vcpu_id, ®s);
+
+ args->port = run->io.port;
+ args->arg0 = regs.rdi;
+ args->arg1 = regs.rsi;
+}
#include "vmx.h"
#define VCPU_ID 5
-#define PORT_SYNC 0x1000
-#define PORT_ABORT 0x1001
-#define PORT_DONE 0x1002
-
-static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
-{
- __asm__ __volatile__("in %[port], %%al"
- :
- : [port]"d"(port), "D"(arg0), "S"(arg1)
- : "rax");
-}
-
-#define exit_to_l0(_port, _arg0, _arg1) \
- __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
-
-#define GUEST_ASSERT(_condition) do { \
- if (!(_condition)) \
- exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, __LINE__);\
-} while (0)
-
-#define GUEST_SYNC(stage) \
- exit_to_l0(PORT_SYNC, "hello", stage);
static bool have_nested_state;
if (vmx_pages)
l1_guest_code(vmx_pages);
- exit_to_l0(PORT_DONE, 0, 0);
+ GUEST_DONE();
}
int main(int argc, char *argv[])
memset(®s1, 0, sizeof(regs1));
vcpu_regs_get(vm, VCPU_ID, ®s1);
switch (run->io.port) {
- case PORT_ABORT:
+ case GUEST_PORT_ABORT:
TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi,
__FILE__, regs1.rsi);
/* NOT REACHED */
- case PORT_SYNC:
+ case GUEST_PORT_SYNC:
break;
- case PORT_DONE:
+ case GUEST_PORT_DONE:
goto done;
default:
TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port);
#include "x86.h"
#define VCPU_ID 5
-#define PORT_HOST_SYNC 0x1000
-
-static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
-{
- __asm__ __volatile__("in %[port], %%al"
- :
- : [port]"d"(port), "D"(arg0), "S"(arg1)
- : "rax");
-}
-
-#define exit_to_l0(_port, _arg0, _arg1) \
- __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
-
-#define GUEST_ASSERT(_condition) do { \
- if (!(_condition)) \
- exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\
-} while (0)
void guest_code(void)
{
for (;;) {
- exit_to_l0(PORT_HOST_SYNC, "hello", 0);
+ GUEST_SYNC(0);
asm volatile ("inc %r11");
}
}
/* The virtual machine object. */
static struct kvm_vm *vm;
-#define exit_to_l0(_port, _arg) do_exit_to_l0(_port, (unsigned long) (_arg))
-static void do_exit_to_l0(uint16_t port, unsigned long arg)
-{
- __asm__ __volatile__("in %[port], %%al"
- :
- : [port]"d"(port), "D"(arg)
- : "rax");
-}
-
-
-#define GUEST_ASSERT(_condition) do { \
- if (!(_condition)) \
- exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition); \
-} while (0)
-
static void check_ia32_tsc_adjust(int64_t max)
{
int64_t adjust;
adjust = rdmsr(MSR_IA32_TSC_ADJUST);
- exit_to_l0(PORT_REPORT, adjust);
+ GUEST_SYNC(adjust);
GUEST_ASSERT(adjust <= max);
}
check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE);
- exit_to_l0(PORT_DONE, 0);
+ GUEST_DONE();
}
void report(int64_t val)
for (;;) {
volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
- struct kvm_regs regs;
+ struct guest_args args;
vcpu_run(vm, VCPU_ID);
- vcpu_regs_get(vm, VCPU_ID, ®s);
+ guest_args_read(vm, VCPU_ID, &args);
TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
- "Got exit_reason other than KVM_EXIT_IO: %u (%s), rip=%lx\n",
+ "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
run->exit_reason,
- exit_reason_str(run->exit_reason), regs.rip);
+ exit_reason_str(run->exit_reason));
- switch (run->io.port) {
- case PORT_ABORT:
- TEST_ASSERT(false, "%s", (const char *) regs.rdi);
+ switch (args.port) {
+ case GUEST_PORT_ABORT:
+ TEST_ASSERT(false, "%s", (const char *) args.arg0);
/* NOT REACHED */
- case PORT_REPORT:
- report(regs.rdi);
+ case GUEST_PORT_SYNC:
+ report(args.arg1);
break;
- case PORT_DONE:
+ case GUEST_PORT_DONE:
goto done;
default:
- TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port);
+ TEST_ASSERT(false, "Unknown port 0x%x.", args.port);
}
}