Skip to content

Commit 8acc351

Browse files
dwmw2bonzini
authored andcommitted
KVM: x86/xen: Add runstate tests for 32-bit mode and crossing page boundary
Torture test the cases where the runstate crosses a page boundary, and and especially the case where it's configured in 32-bit mode and doesn't, but then switching to 64-bit mode makes it go onto the second page. To simplify this, make the KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST ioctl also update the guest runstate area. It already did so if the actual runstate changed, as a side-effect of kvm_xen_update_runstate(). So doing it in the plain adjustment case is making it more consistent, as well as giving us a nice way to trigger the update without actually running the vCPU again and changing the values. Signed-off-by: David Woodhouse <[email protected]> Reviewed-by: Paul Durrant <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent d8ba8ba commit 8acc351

File tree

2 files changed

+97
-20
lines changed

2 files changed

+97
-20
lines changed

arch/x86/kvm/xen.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,8 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
884884

885885
if (data->u.runstate.state <= RUNSTATE_offline)
886886
kvm_xen_update_runstate(vcpu, data->u.runstate.state);
887+
else if (vcpu->arch.xen.runstate_cache.active)
888+
kvm_xen_update_runstate_guest(vcpu, false);
887889
r = 0;
888890
break;
889891

tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,20 @@ struct pvclock_wall_clock {
8888
} __attribute__((__packed__));
8989

9090
struct vcpu_runstate_info {
91-
uint32_t state;
92-
uint64_t state_entry_time;
93-
uint64_t time[4];
91+
uint32_t state;
92+
uint64_t state_entry_time;
93+
uint64_t time[5]; /* Extra field for overrun check */
9494
};
9595

96+
struct compat_vcpu_runstate_info {
97+
uint32_t state;
98+
uint64_t state_entry_time;
99+
uint64_t time[5];
100+
} __attribute__((__packed__));;
101+
96102
struct arch_vcpu_info {
97-
unsigned long cr2;
98-
unsigned long pad; /* sizeof(vcpu_info_t) == 64 */
103+
unsigned long cr2;
104+
unsigned long pad; /* sizeof(vcpu_info_t) == 64 */
99105
};
100106

101107
struct vcpu_info {
@@ -1013,22 +1019,91 @@ int main(int argc, char *argv[])
10131019
runstate_names[i], rs->time[i]);
10141020
}
10151021
}
1016-
TEST_ASSERT(rs->state == rst.u.runstate.state, "Runstate mismatch");
1017-
TEST_ASSERT(rs->state_entry_time == rst.u.runstate.state_entry_time,
1018-
"State entry time mismatch");
1019-
TEST_ASSERT(rs->time[RUNSTATE_running] == rst.u.runstate.time_running,
1020-
"Running time mismatch");
1021-
TEST_ASSERT(rs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable,
1022-
"Runnable time mismatch");
1023-
TEST_ASSERT(rs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked,
1024-
"Blocked time mismatch");
1025-
TEST_ASSERT(rs->time[RUNSTATE_offline] == rst.u.runstate.time_offline,
1026-
"Offline time mismatch");
1027-
1028-
TEST_ASSERT(rs->state_entry_time == rs->time[0] +
1029-
rs->time[1] + rs->time[2] + rs->time[3],
1030-
"runstate times don't add up");
1022+
1023+
/*
1024+
* Exercise runstate info at all points across the page boundary, in
1025+
* 32-bit and 64-bit mode. In particular, test the case where it is
1026+
* configured in 32-bit mode and then switched to 64-bit mode while
1027+
* active, which takes it onto the second page.
1028+
*/
1029+
unsigned long runstate_addr;
1030+
struct compat_vcpu_runstate_info *crs;
1031+
for (runstate_addr = SHINFO_REGION_GPA + PAGE_SIZE + PAGE_SIZE - sizeof(*rs) - 4;
1032+
runstate_addr < SHINFO_REGION_GPA + PAGE_SIZE + PAGE_SIZE + 4; runstate_addr++) {
1033+
1034+
rs = addr_gpa2hva(vm, runstate_addr);
1035+
crs = (void *)rs;
1036+
1037+
memset(rs, 0xa5, sizeof(*rs));
1038+
1039+
/* Set to compatibility mode */
1040+
lm.u.long_mode = 0;
1041+
vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
1042+
1043+
/* Set runstate to new address (kernel will write it) */
1044+
struct kvm_xen_vcpu_attr st = {
1045+
.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
1046+
.u.gpa = runstate_addr,
1047+
};
1048+
vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &st);
1049+
1050+
if (verbose)
1051+
printf("Compatibility runstate at %08lx\n", runstate_addr);
1052+
1053+
TEST_ASSERT(crs->state == rst.u.runstate.state, "Runstate mismatch");
1054+
TEST_ASSERT(crs->state_entry_time == rst.u.runstate.state_entry_time,
1055+
"State entry time mismatch");
1056+
TEST_ASSERT(crs->time[RUNSTATE_running] == rst.u.runstate.time_running,
1057+
"Running time mismatch");
1058+
TEST_ASSERT(crs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable,
1059+
"Runnable time mismatch");
1060+
TEST_ASSERT(crs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked,
1061+
"Blocked time mismatch");
1062+
TEST_ASSERT(crs->time[RUNSTATE_offline] == rst.u.runstate.time_offline,
1063+
"Offline time mismatch");
1064+
TEST_ASSERT(crs->time[RUNSTATE_offline + 1] == 0xa5a5a5a5a5a5a5a5ULL,
1065+
"Structure overrun");
1066+
TEST_ASSERT(crs->state_entry_time == crs->time[0] +
1067+
crs->time[1] + crs->time[2] + crs->time[3],
1068+
"runstate times don't add up");
1069+
1070+
1071+
/* Now switch to 64-bit mode */
1072+
lm.u.long_mode = 1;
1073+
vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
1074+
1075+
memset(rs, 0xa5, sizeof(*rs));
1076+
1077+
/* Don't change the address, just trigger a write */
1078+
struct kvm_xen_vcpu_attr adj = {
1079+
.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST,
1080+
.u.runstate.state = (uint64_t)-1
1081+
};
1082+
vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &adj);
1083+
1084+
if (verbose)
1085+
printf("64-bit runstate at %08lx\n", runstate_addr);
1086+
1087+
TEST_ASSERT(rs->state == rst.u.runstate.state, "Runstate mismatch");
1088+
TEST_ASSERT(rs->state_entry_time == rst.u.runstate.state_entry_time,
1089+
"State entry time mismatch");
1090+
TEST_ASSERT(rs->time[RUNSTATE_running] == rst.u.runstate.time_running,
1091+
"Running time mismatch");
1092+
TEST_ASSERT(rs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable,
1093+
"Runnable time mismatch");
1094+
TEST_ASSERT(rs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked,
1095+
"Blocked time mismatch");
1096+
TEST_ASSERT(rs->time[RUNSTATE_offline] == rst.u.runstate.time_offline,
1097+
"Offline time mismatch");
1098+
TEST_ASSERT(rs->time[RUNSTATE_offline + 1] == 0xa5a5a5a5a5a5a5a5ULL,
1099+
"Structure overrun");
1100+
1101+
TEST_ASSERT(rs->state_entry_time == rs->time[0] +
1102+
rs->time[1] + rs->time[2] + rs->time[3],
1103+
"runstate times don't add up");
1104+
}
10311105
}
1106+
10321107
kvm_vm_free(vm);
10331108
return 0;
10341109
}

0 commit comments

Comments
 (0)