@@ -88,14 +88,20 @@ struct pvclock_wall_clock {
88
88
} __attribute__((__packed__ ));
89
89
90
90
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 */
94
94
};
95
95
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
+
96
102
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 */
99
105
};
100
106
101
107
struct vcpu_info {
@@ -1013,22 +1019,91 @@ int main(int argc, char *argv[])
1013
1019
runstate_names [i ], rs -> time [i ]);
1014
1020
}
1015
1021
}
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
+ }
1031
1105
}
1106
+
1032
1107
kvm_vm_free (vm );
1033
1108
return 0 ;
1034
1109
}
0 commit comments