Commit | Line | Data |
---|---|---|
8d4e7e80 DW |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * svm_vmcall_test | |
4 | * | |
5 | * Copyright © 2021 Amazon.com, Inc. or its affiliates. | |
6 | * | |
7 | * Xen shared_info / pvclock testing | |
8 | */ | |
9 | ||
10 | #include "test_util.h" | |
11 | #include "kvm_util.h" | |
12 | #include "processor.h" | |
13 | ||
14 | #include <stdint.h> | |
15 | #include <time.h> | |
30b5c851 | 16 | #include <sched.h> |
14243b38 | 17 | #include <signal.h> |
a51abbbf | 18 | #include <pthread.h> |
14243b38 DW |
19 | |
20 | #include <sys/eventfd.h> | |
8d4e7e80 | 21 | |
30b5c851 | 22 | #define SHINFO_REGION_GVA 0xc0000000ULL |
8d4e7e80 DW |
23 | #define SHINFO_REGION_GPA 0xc0000000ULL |
24 | #define SHINFO_REGION_SLOT 10 | |
8d4e7e80 | 25 | |
5ec3289b | 26 | #define DUMMY_REGION_GPA (SHINFO_REGION_GPA + (3 * PAGE_SIZE)) |
14243b38 DW |
27 | #define DUMMY_REGION_SLOT 11 |
28 | ||
29 | #define SHINFO_ADDR (SHINFO_REGION_GPA) | |
7c4de881 | 30 | #define VCPU_INFO_ADDR (SHINFO_REGION_GPA + 0x40) |
5ec3289b DW |
31 | #define PVTIME_ADDR (SHINFO_REGION_GPA + PAGE_SIZE) |
32 | #define RUNSTATE_ADDR (SHINFO_REGION_GPA + PAGE_SIZE + PAGE_SIZE - 15) | |
30b5c851 | 33 | |
14243b38 | 34 | #define SHINFO_VADDR (SHINFO_REGION_GVA) |
7c4de881 | 35 | #define VCPU_INFO_VADDR (SHINFO_REGION_GVA + 0x40) |
5ec3289b | 36 | #define RUNSTATE_VADDR (SHINFO_REGION_GVA + PAGE_SIZE + PAGE_SIZE - 15) |
7c4de881 DW |
37 | |
38 | #define EVTCHN_VECTOR 0x10 | |
8d4e7e80 | 39 | |
25eaeebe DW |
40 | #define EVTCHN_TEST1 15 |
41 | #define EVTCHN_TEST2 66 | |
42 | #define EVTCHN_TIMER 13 | |
43 | ||
8d4e7e80 DW |
44 | #define XEN_HYPERCALL_MSR 0x40000000 |
45 | ||
30b5c851 DW |
46 | #define MIN_STEAL_TIME 50000 |
47 | ||
a51abbbf ML |
48 | #define SHINFO_RACE_TIMEOUT 2 /* seconds */ |
49 | ||
25eaeebe DW |
50 | #define __HYPERVISOR_set_timer_op 15 |
51 | #define __HYPERVISOR_sched_op 29 | |
52 | #define __HYPERVISOR_event_channel_op 32 | |
53 | ||
54 | #define SCHEDOP_poll 3 | |
55 | ||
56 | #define EVTCHNOP_send 4 | |
57 | ||
58 | #define EVTCHNSTAT_interdomain 2 | |
59 | ||
60 | struct evtchn_send { | |
61 | u32 port; | |
62 | }; | |
63 | ||
64 | struct sched_poll { | |
65 | u32 *ports; | |
66 | unsigned int nr_ports; | |
67 | u64 timeout; | |
68 | }; | |
69 | ||
8d4e7e80 | 70 | struct pvclock_vcpu_time_info { |
96c852c8 PB |
71 | u32 version; |
72 | u32 pad0; | |
73 | u64 tsc_timestamp; | |
74 | u64 system_time; | |
75 | u32 tsc_to_system_mul; | |
76 | s8 tsc_shift; | |
77 | u8 flags; | |
78 | u8 pad[2]; | |
8d4e7e80 DW |
79 | } __attribute__((__packed__)); /* 32 bytes */ |
80 | ||
81 | struct pvclock_wall_clock { | |
96c852c8 PB |
82 | u32 version; |
83 | u32 sec; | |
84 | u32 nsec; | |
8d4e7e80 DW |
85 | } __attribute__((__packed__)); |
86 | ||
30b5c851 | 87 | struct vcpu_runstate_info { |
8acc3518 DW |
88 | uint32_t state; |
89 | uint64_t state_entry_time; | |
90 | uint64_t time[5]; /* Extra field for overrun check */ | |
30b5c851 DW |
91 | }; |
92 | ||
8acc3518 DW |
93 | struct compat_vcpu_runstate_info { |
94 | uint32_t state; | |
95 | uint64_t state_entry_time; | |
96 | uint64_t time[5]; | |
97 | } __attribute__((__packed__));; | |
98 | ||
7c4de881 | 99 | struct arch_vcpu_info { |
8acc3518 DW |
100 | unsigned long cr2; |
101 | unsigned long pad; /* sizeof(vcpu_info_t) == 64 */ | |
7c4de881 DW |
102 | }; |
103 | ||
104 | struct vcpu_info { | |
96c852c8 PB |
105 | uint8_t evtchn_upcall_pending; |
106 | uint8_t evtchn_upcall_mask; | |
107 | unsigned long evtchn_pending_sel; | |
108 | struct arch_vcpu_info arch; | |
109 | struct pvclock_vcpu_time_info time; | |
7c4de881 DW |
110 | }; /* 64 bytes (x86) */ |
111 | ||
14243b38 DW |
112 | struct shared_info { |
113 | struct vcpu_info vcpu_info[32]; | |
114 | unsigned long evtchn_pending[64]; | |
115 | unsigned long evtchn_mask[64]; | |
116 | struct pvclock_wall_clock wc; | |
117 | uint32_t wc_sec_hi; | |
118 | /* arch_shared_info here */ | |
119 | }; | |
120 | ||
30b5c851 DW |
121 | #define RUNSTATE_running 0 |
122 | #define RUNSTATE_runnable 1 | |
123 | #define RUNSTATE_blocked 2 | |
124 | #define RUNSTATE_offline 3 | |
125 | ||
14243b38 DW |
126 | static const char *runstate_names[] = { |
127 | "running", | |
128 | "runnable", | |
129 | "blocked", | |
130 | "offline" | |
131 | }; | |
132 | ||
133 | struct { | |
134 | struct kvm_irq_routing info; | |
135 | struct kvm_irq_routing_entry entries[2]; | |
136 | } irq_routes; | |
137 | ||
5addaf53 | 138 | static volatile bool guest_saw_irq; |
25eaeebe | 139 | |
7c4de881 DW |
140 | static void evtchn_handler(struct ex_regs *regs) |
141 | { | |
142 | struct vcpu_info *vi = (void *)VCPU_INFO_VADDR; | |
143 | vi->evtchn_upcall_pending = 0; | |
14243b38 | 144 | vi->evtchn_pending_sel = 0; |
25eaeebe | 145 | guest_saw_irq = true; |
7c4de881 DW |
146 | |
147 | GUEST_SYNC(0x20); | |
148 | } | |
149 | ||
25eaeebe DW |
150 | static void guest_wait_for_irq(void) |
151 | { | |
152 | while (!guest_saw_irq) | |
153 | __asm__ __volatile__ ("rep nop" : : : "memory"); | |
154 | guest_saw_irq = false; | |
155 | } | |
156 | ||
8d4e7e80 DW |
157 | static void guest_code(void) |
158 | { | |
30b5c851 | 159 | struct vcpu_runstate_info *rs = (void *)RUNSTATE_VADDR; |
a51abbbf | 160 | int i; |
30b5c851 | 161 | |
7c4de881 DW |
162 | __asm__ __volatile__( |
163 | "sti\n" | |
164 | "nop\n" | |
165 | ); | |
166 | ||
167 | /* Trigger an interrupt injection */ | |
168 | GUEST_SYNC(0); | |
169 | ||
25eaeebe DW |
170 | guest_wait_for_irq(); |
171 | ||
30b5c851 DW |
172 | /* Test having the host set runstates manually */ |
173 | GUEST_SYNC(RUNSTATE_runnable); | |
174 | GUEST_ASSERT(rs->time[RUNSTATE_runnable] != 0); | |
175 | GUEST_ASSERT(rs->state == 0); | |
176 | ||
177 | GUEST_SYNC(RUNSTATE_blocked); | |
178 | GUEST_ASSERT(rs->time[RUNSTATE_blocked] != 0); | |
179 | GUEST_ASSERT(rs->state == 0); | |
180 | ||
181 | GUEST_SYNC(RUNSTATE_offline); | |
182 | GUEST_ASSERT(rs->time[RUNSTATE_offline] != 0); | |
183 | GUEST_ASSERT(rs->state == 0); | |
184 | ||
185 | /* Test runstate time adjust */ | |
186 | GUEST_SYNC(4); | |
187 | GUEST_ASSERT(rs->time[RUNSTATE_blocked] == 0x5a); | |
188 | GUEST_ASSERT(rs->time[RUNSTATE_offline] == 0x6b6b); | |
189 | ||
190 | /* Test runstate time set */ | |
191 | GUEST_SYNC(5); | |
192 | GUEST_ASSERT(rs->state_entry_time >= 0x8000); | |
193 | GUEST_ASSERT(rs->time[RUNSTATE_runnable] == 0); | |
194 | GUEST_ASSERT(rs->time[RUNSTATE_blocked] == 0x6b6b); | |
195 | GUEST_ASSERT(rs->time[RUNSTATE_offline] == 0x5a); | |
196 | ||
197 | /* sched_yield() should result in some 'runnable' time */ | |
198 | GUEST_SYNC(6); | |
199 | GUEST_ASSERT(rs->time[RUNSTATE_runnable] >= MIN_STEAL_TIME); | |
200 | ||
14243b38 DW |
201 | /* Attempt to deliver a *masked* interrupt */ |
202 | GUEST_SYNC(7); | |
203 | ||
204 | /* Wait until we see the bit set */ | |
205 | struct shared_info *si = (void *)SHINFO_VADDR; | |
206 | while (!si->evtchn_pending[0]) | |
207 | __asm__ __volatile__ ("rep nop" : : : "memory"); | |
208 | ||
209 | /* Now deliver an *unmasked* interrupt */ | |
210 | GUEST_SYNC(8); | |
211 | ||
25eaeebe | 212 | guest_wait_for_irq(); |
14243b38 DW |
213 | |
214 | /* Change memslots and deliver an interrupt */ | |
215 | GUEST_SYNC(9); | |
216 | ||
25eaeebe DW |
217 | guest_wait_for_irq(); |
218 | ||
219 | /* Deliver event channel with KVM_XEN_HVM_EVTCHN_SEND */ | |
220 | GUEST_SYNC(10); | |
221 | ||
222 | guest_wait_for_irq(); | |
223 | ||
224 | GUEST_SYNC(11); | |
225 | ||
226 | /* Our turn. Deliver event channel (to ourselves) with | |
227 | * EVTCHNOP_send hypercall. */ | |
25eaeebe | 228 | struct evtchn_send s = { .port = 127 }; |
c0c76d99 | 229 | xen_hypercall(__HYPERVISOR_event_channel_op, EVTCHNOP_send, &s); |
25eaeebe DW |
230 | |
231 | guest_wait_for_irq(); | |
232 | ||
233 | GUEST_SYNC(12); | |
234 | ||
235 | /* Deliver "outbound" event channel to an eventfd which | |
236 | * happens to be one of our own irqfds. */ | |
237 | s.port = 197; | |
c0c76d99 | 238 | xen_hypercall(__HYPERVISOR_event_channel_op, EVTCHNOP_send, &s); |
25eaeebe DW |
239 | |
240 | guest_wait_for_irq(); | |
241 | ||
242 | GUEST_SYNC(13); | |
243 | ||
244 | /* Set a timer 100ms in the future. */ | |
c0c76d99 SC |
245 | xen_hypercall(__HYPERVISOR_set_timer_op, |
246 | rs->state_entry_time + 100000000, NULL); | |
25eaeebe DW |
247 | |
248 | GUEST_SYNC(14); | |
249 | ||
250 | /* Now wait for the timer */ | |
251 | guest_wait_for_irq(); | |
252 | ||
253 | GUEST_SYNC(15); | |
254 | ||
255 | /* The host has 'restored' the timer. Just wait for it. */ | |
256 | guest_wait_for_irq(); | |
257 | ||
258 | GUEST_SYNC(16); | |
259 | ||
260 | /* Poll for an event channel port which is already set */ | |
261 | u32 ports[1] = { EVTCHN_TIMER }; | |
262 | struct sched_poll p = { | |
263 | .ports = ports, | |
264 | .nr_ports = 1, | |
265 | .timeout = 0, | |
266 | }; | |
267 | ||
c0c76d99 | 268 | xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p); |
25eaeebe DW |
269 | |
270 | GUEST_SYNC(17); | |
271 | ||
272 | /* Poll for an unset port and wait for the timeout. */ | |
273 | p.timeout = 100000000; | |
c0c76d99 | 274 | xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p); |
25eaeebe DW |
275 | |
276 | GUEST_SYNC(18); | |
277 | ||
278 | /* A timer will wake the masked port we're waiting on, while we poll */ | |
279 | p.timeout = 0; | |
c0c76d99 | 280 | xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p); |
25eaeebe DW |
281 | |
282 | GUEST_SYNC(19); | |
283 | ||
284 | /* A timer wake an *unmasked* port which should wake us with an | |
285 | * actual interrupt, while we're polling on a different port. */ | |
286 | ports[0]++; | |
287 | p.timeout = 0; | |
c0c76d99 | 288 | xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p); |
25eaeebe DW |
289 | |
290 | guest_wait_for_irq(); | |
291 | ||
292 | GUEST_SYNC(20); | |
a29833e3 DW |
293 | |
294 | /* Timer should have fired already */ | |
295 | guest_wait_for_irq(); | |
296 | ||
297 | GUEST_SYNC(21); | |
a51abbbf ML |
298 | /* Racing host ioctls */ |
299 | ||
300 | guest_wait_for_irq(); | |
301 | ||
302 | GUEST_SYNC(22); | |
303 | /* Racing vmcall against host ioctl */ | |
304 | ||
305 | ports[0] = 0; | |
306 | ||
307 | p = (struct sched_poll) { | |
308 | .ports = ports, | |
309 | .nr_ports = 1, | |
310 | .timeout = 0 | |
311 | }; | |
312 | ||
313 | wait_for_timer: | |
314 | /* | |
315 | * Poll for a timer wake event while the worker thread is mucking with | |
316 | * the shared info. KVM XEN drops timer IRQs if the shared info is | |
317 | * invalid when the timer expires. Arbitrarily poll 100 times before | |
318 | * giving up and asking the VMM to re-arm the timer. 100 polls should | |
319 | * consume enough time to beat on KVM without taking too long if the | |
320 | * timer IRQ is dropped due to an invalid event channel. | |
321 | */ | |
322 | for (i = 0; i < 100 && !guest_saw_irq; i++) | |
c0c76d99 | 323 | __xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p); |
a51abbbf ML |
324 | |
325 | /* | |
326 | * Re-send the timer IRQ if it was (likely) dropped due to the timer | |
327 | * expiring while the event channel was invalid. | |
328 | */ | |
329 | if (!guest_saw_irq) { | |
330 | GUEST_SYNC(23); | |
331 | goto wait_for_timer; | |
332 | } | |
333 | guest_saw_irq = false; | |
334 | ||
335 | GUEST_SYNC(24); | |
8d4e7e80 DW |
336 | } |
337 | ||
338 | static int cmp_timespec(struct timespec *a, struct timespec *b) | |
339 | { | |
340 | if (a->tv_sec > b->tv_sec) | |
341 | return 1; | |
342 | else if (a->tv_sec < b->tv_sec) | |
343 | return -1; | |
344 | else if (a->tv_nsec > b->tv_nsec) | |
345 | return 1; | |
346 | else if (a->tv_nsec < b->tv_nsec) | |
347 | return -1; | |
348 | else | |
349 | return 0; | |
350 | } | |
0037727b SC |
351 | |
352 | static struct vcpu_info *vinfo; | |
353 | static struct kvm_vcpu *vcpu; | |
8d4e7e80 | 354 | |
14243b38 DW |
355 | static void handle_alrm(int sig) |
356 | { | |
25eaeebe DW |
357 | if (vinfo) |
358 | printf("evtchn_upcall_pending 0x%x\n", vinfo->evtchn_upcall_pending); | |
768e9a61 | 359 | vcpu_dump(stdout, vcpu, 0); |
14243b38 DW |
360 | TEST_FAIL("IRQ delivery timed out"); |
361 | } | |
362 | ||
a51abbbf ML |
363 | static void *juggle_shinfo_state(void *arg) |
364 | { | |
365 | struct kvm_vm *vm = (struct kvm_vm *)arg; | |
366 | ||
6c77ae71 | 367 | struct kvm_xen_hvm_attr cache_activate = { |
a51abbbf ML |
368 | .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, |
369 | .u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE | |
370 | }; | |
371 | ||
6c77ae71 | 372 | struct kvm_xen_hvm_attr cache_deactivate = { |
a51abbbf | 373 | .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, |
6c77ae71 | 374 | .u.shared_info.gfn = KVM_XEN_INVALID_GFN |
a51abbbf ML |
375 | }; |
376 | ||
377 | for (;;) { | |
6c77ae71 ML |
378 | __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_activate); |
379 | __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_deactivate); | |
a51abbbf | 380 | pthread_testcancel(); |
96e78ebb | 381 | } |
a51abbbf ML |
382 | |
383 | return NULL; | |
384 | } | |
385 | ||
8d4e7e80 DW |
386 | int main(int argc, char *argv[]) |
387 | { | |
388 | struct timespec min_ts, max_ts, vm_ts; | |
50aa870b | 389 | struct kvm_xen_hvm_attr evt_reset; |
0037727b | 390 | struct kvm_vm *vm; |
a51abbbf | 391 | pthread_t thread; |
14243b38 | 392 | bool verbose; |
a51abbbf | 393 | int ret; |
14243b38 DW |
394 | |
395 | verbose = argc > 1 && (!strncmp(argv[1], "-v", 3) || | |
396 | !strncmp(argv[1], "--verbose", 10)); | |
8d4e7e80 | 397 | |
30b5c851 | 398 | int xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM); |
7ed397d1 | 399 | TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO); |
8d4e7e80 | 400 | |
30b5c851 | 401 | bool do_runstate_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE); |
d8ba8ba4 | 402 | bool do_runstate_flag = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG); |
14243b38 | 403 | bool do_eventfd_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL); |
25eaeebe | 404 | bool do_evtchn_tests = do_eventfd_tests && !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND); |
30b5c851 | 405 | |
8d4e7e80 DW |
406 | clock_gettime(CLOCK_REALTIME, &min_ts); |
407 | ||
0037727b | 408 | vm = vm_create_with_one_vcpu(&vcpu, guest_code); |
8d4e7e80 DW |
409 | |
410 | /* Map a region for the shared_info page */ | |
411 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, | |
5ec3289b DW |
412 | SHINFO_REGION_GPA, SHINFO_REGION_SLOT, 3, 0); |
413 | virt_map(vm, SHINFO_REGION_GVA, SHINFO_REGION_GPA, 3); | |
8d4e7e80 | 414 | |
14243b38 DW |
415 | struct shared_info *shinfo = addr_gpa2hva(vm, SHINFO_VADDR); |
416 | ||
417 | int zero_fd = open("/dev/zero", O_RDONLY); | |
418 | TEST_ASSERT(zero_fd != -1, "Failed to open /dev/zero"); | |
419 | ||
8d4e7e80 DW |
420 | struct kvm_xen_hvm_config hvmc = { |
421 | .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, | |
422 | .msr = XEN_HYPERCALL_MSR, | |
423 | }; | |
1a65105a BO |
424 | |
425 | /* Let the kernel know that we *will* use it for sending all | |
426 | * event channels, which lets it intercept SCHEDOP_poll */ | |
25eaeebe | 427 | if (do_evtchn_tests) |
1a65105a BO |
428 | hvmc.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND; |
429 | ||
8d4e7e80 DW |
430 | vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &hvmc); |
431 | ||
432 | struct kvm_xen_hvm_attr lm = { | |
433 | .type = KVM_XEN_ATTR_TYPE_LONG_MODE, | |
434 | .u.long_mode = 1, | |
435 | }; | |
436 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm); | |
437 | ||
d8ba8ba4 DW |
438 | if (do_runstate_flag) { |
439 | struct kvm_xen_hvm_attr ruf = { | |
440 | .type = KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG, | |
441 | .u.runstate_update_flag = 1, | |
442 | }; | |
443 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ruf); | |
444 | ||
445 | ruf.u.runstate_update_flag = 0; | |
446 | vm_ioctl(vm, KVM_XEN_HVM_GET_ATTR, &ruf); | |
447 | TEST_ASSERT(ruf.u.runstate_update_flag == 1, | |
448 | "Failed to read back RUNSTATE_UPDATE_FLAG attr"); | |
449 | } | |
450 | ||
8d4e7e80 DW |
451 | struct kvm_xen_hvm_attr ha = { |
452 | .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, | |
453 | .u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE, | |
454 | }; | |
455 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha); | |
456 | ||
14243b38 DW |
457 | /* |
458 | * Test what happens when the HVA of the shinfo page is remapped after | |
459 | * the kernel has a reference to it. But make sure we copy the clock | |
460 | * info over since that's only set at setup time, and we test it later. | |
461 | */ | |
462 | struct pvclock_wall_clock wc_copy = shinfo->wc; | |
463 | void *m = mmap(shinfo, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, zero_fd, 0); | |
464 | TEST_ASSERT(m == shinfo, "Failed to map /dev/zero over shared info"); | |
465 | shinfo->wc = wc_copy; | |
466 | ||
8d4e7e80 DW |
467 | struct kvm_xen_vcpu_attr vi = { |
468 | .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, | |
7c4de881 | 469 | .u.gpa = VCPU_INFO_ADDR, |
8d4e7e80 | 470 | }; |
768e9a61 | 471 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &vi); |
8d4e7e80 DW |
472 | |
473 | struct kvm_xen_vcpu_attr pvclock = { | |
474 | .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, | |
475 | .u.gpa = PVTIME_ADDR, | |
476 | }; | |
768e9a61 | 477 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &pvclock); |
8d4e7e80 | 478 | |
7c4de881 DW |
479 | struct kvm_xen_hvm_attr vec = { |
480 | .type = KVM_XEN_ATTR_TYPE_UPCALL_VECTOR, | |
481 | .u.vector = EVTCHN_VECTOR, | |
482 | }; | |
483 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &vec); | |
484 | ||
485 | vm_init_descriptor_tables(vm); | |
768e9a61 | 486 | vcpu_init_descriptor_tables(vcpu); |
7c4de881 DW |
487 | vm_install_exception_handler(vm, EVTCHN_VECTOR, evtchn_handler); |
488 | ||
30b5c851 DW |
489 | if (do_runstate_tests) { |
490 | struct kvm_xen_vcpu_attr st = { | |
491 | .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, | |
492 | .u.gpa = RUNSTATE_ADDR, | |
493 | }; | |
768e9a61 | 494 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &st); |
30b5c851 DW |
495 | } |
496 | ||
14243b38 DW |
497 | int irq_fd[2] = { -1, -1 }; |
498 | ||
499 | if (do_eventfd_tests) { | |
500 | irq_fd[0] = eventfd(0, 0); | |
501 | irq_fd[1] = eventfd(0, 0); | |
502 | ||
503 | /* Unexpected, but not a KVM failure */ | |
504 | if (irq_fd[0] == -1 || irq_fd[1] == -1) | |
25eaeebe | 505 | do_evtchn_tests = do_eventfd_tests = false; |
14243b38 DW |
506 | } |
507 | ||
508 | if (do_eventfd_tests) { | |
509 | irq_routes.info.nr = 2; | |
510 | ||
511 | irq_routes.entries[0].gsi = 32; | |
512 | irq_routes.entries[0].type = KVM_IRQ_ROUTING_XEN_EVTCHN; | |
25eaeebe | 513 | irq_routes.entries[0].u.xen_evtchn.port = EVTCHN_TEST1; |
0037727b | 514 | irq_routes.entries[0].u.xen_evtchn.vcpu = vcpu->id; |
14243b38 DW |
515 | irq_routes.entries[0].u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; |
516 | ||
517 | irq_routes.entries[1].gsi = 33; | |
518 | irq_routes.entries[1].type = KVM_IRQ_ROUTING_XEN_EVTCHN; | |
25eaeebe | 519 | irq_routes.entries[1].u.xen_evtchn.port = EVTCHN_TEST2; |
0037727b | 520 | irq_routes.entries[1].u.xen_evtchn.vcpu = vcpu->id; |
14243b38 DW |
521 | irq_routes.entries[1].u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; |
522 | ||
fcba483e | 523 | vm_ioctl(vm, KVM_SET_GSI_ROUTING, &irq_routes.info); |
14243b38 DW |
524 | |
525 | struct kvm_irqfd ifd = { }; | |
526 | ||
527 | ifd.fd = irq_fd[0]; | |
528 | ifd.gsi = 32; | |
529 | vm_ioctl(vm, KVM_IRQFD, &ifd); | |
530 | ||
531 | ifd.fd = irq_fd[1]; | |
532 | ifd.gsi = 33; | |
533 | vm_ioctl(vm, KVM_IRQFD, &ifd); | |
534 | ||
535 | struct sigaction sa = { }; | |
536 | sa.sa_handler = handle_alrm; | |
537 | sigaction(SIGALRM, &sa, NULL); | |
538 | } | |
539 | ||
25eaeebe DW |
540 | struct kvm_xen_vcpu_attr tmr = { |
541 | .type = KVM_XEN_VCPU_ATTR_TYPE_TIMER, | |
542 | .u.timer.port = EVTCHN_TIMER, | |
543 | .u.timer.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, | |
544 | .u.timer.expires_ns = 0 | |
545 | }; | |
546 | ||
547 | if (do_evtchn_tests) { | |
548 | struct kvm_xen_hvm_attr inj = { | |
549 | .type = KVM_XEN_ATTR_TYPE_EVTCHN, | |
550 | .u.evtchn.send_port = 127, | |
551 | .u.evtchn.type = EVTCHNSTAT_interdomain, | |
552 | .u.evtchn.flags = 0, | |
553 | .u.evtchn.deliver.port.port = EVTCHN_TEST1, | |
0037727b | 554 | .u.evtchn.deliver.port.vcpu = vcpu->id + 1, |
25eaeebe DW |
555 | .u.evtchn.deliver.port.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, |
556 | }; | |
557 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); | |
558 | ||
559 | /* Test migration to a different vCPU */ | |
560 | inj.u.evtchn.flags = KVM_XEN_EVTCHN_UPDATE; | |
0037727b | 561 | inj.u.evtchn.deliver.port.vcpu = vcpu->id; |
25eaeebe DW |
562 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); |
563 | ||
564 | inj.u.evtchn.send_port = 197; | |
565 | inj.u.evtchn.deliver.eventfd.port = 0; | |
566 | inj.u.evtchn.deliver.eventfd.fd = irq_fd[1]; | |
567 | inj.u.evtchn.flags = 0; | |
568 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); | |
569 | ||
768e9a61 | 570 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); |
25eaeebe DW |
571 | } |
572 | vinfo = addr_gpa2hva(vm, VCPU_INFO_VADDR); | |
7c4de881 DW |
573 | vinfo->evtchn_upcall_pending = 0; |
574 | ||
b9c36fde | 575 | struct vcpu_runstate_info *rs = addr_gpa2hva(vm, RUNSTATE_ADDR); |
30b5c851 DW |
576 | rs->state = 0x5a; |
577 | ||
7c4de881 DW |
578 | bool evtchn_irq_expected = false; |
579 | ||
8d4e7e80 | 580 | for (;;) { |
0037727b | 581 | volatile struct kvm_run *run = vcpu->run; |
8d4e7e80 DW |
582 | struct ucall uc; |
583 | ||
768e9a61 | 584 | vcpu_run(vcpu); |
8d4e7e80 DW |
585 | |
586 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | |
587 | "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", | |
588 | run->exit_reason, | |
589 | exit_reason_str(run->exit_reason)); | |
590 | ||
768e9a61 | 591 | switch (get_ucall(vcpu, &uc)) { |
8d4e7e80 | 592 | case UCALL_ABORT: |
594a1c27 | 593 | REPORT_GUEST_ASSERT(uc); |
8d4e7e80 | 594 | /* NOT REACHED */ |
30b5c851 DW |
595 | case UCALL_SYNC: { |
596 | struct kvm_xen_vcpu_attr rst; | |
597 | long rundelay; | |
598 | ||
7c4de881 DW |
599 | if (do_runstate_tests) |
600 | TEST_ASSERT(rs->state_entry_time == rs->time[0] + | |
601 | rs->time[1] + rs->time[2] + rs->time[3], | |
602 | "runstate times don't add up"); | |
30b5c851 DW |
603 | |
604 | switch (uc.args[1]) { | |
7c4de881 | 605 | case 0: |
14243b38 DW |
606 | if (verbose) |
607 | printf("Delivering evtchn upcall\n"); | |
7c4de881 DW |
608 | evtchn_irq_expected = true; |
609 | vinfo->evtchn_upcall_pending = 1; | |
610 | break; | |
611 | ||
612 | case RUNSTATE_runnable...RUNSTATE_offline: | |
613 | TEST_ASSERT(!evtchn_irq_expected, "Event channel IRQ not seen"); | |
614 | if (!do_runstate_tests) | |
615 | goto done; | |
14243b38 DW |
616 | if (verbose) |
617 | printf("Testing runstate %s\n", runstate_names[uc.args[1]]); | |
30b5c851 DW |
618 | rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT; |
619 | rst.u.runstate.state = uc.args[1]; | |
768e9a61 | 620 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); |
30b5c851 | 621 | break; |
14243b38 | 622 | |
30b5c851 | 623 | case 4: |
14243b38 DW |
624 | if (verbose) |
625 | printf("Testing RUNSTATE_ADJUST\n"); | |
30b5c851 DW |
626 | rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST; |
627 | memset(&rst.u, 0, sizeof(rst.u)); | |
628 | rst.u.runstate.state = (uint64_t)-1; | |
629 | rst.u.runstate.time_blocked = | |
630 | 0x5a - rs->time[RUNSTATE_blocked]; | |
631 | rst.u.runstate.time_offline = | |
632 | 0x6b6b - rs->time[RUNSTATE_offline]; | |
633 | rst.u.runstate.time_runnable = -rst.u.runstate.time_blocked - | |
634 | rst.u.runstate.time_offline; | |
768e9a61 | 635 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); |
30b5c851 DW |
636 | break; |
637 | ||
638 | case 5: | |
14243b38 DW |
639 | if (verbose) |
640 | printf("Testing RUNSTATE_DATA\n"); | |
30b5c851 DW |
641 | rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA; |
642 | memset(&rst.u, 0, sizeof(rst.u)); | |
643 | rst.u.runstate.state = RUNSTATE_running; | |
644 | rst.u.runstate.state_entry_time = 0x6b6b + 0x5a; | |
645 | rst.u.runstate.time_blocked = 0x6b6b; | |
646 | rst.u.runstate.time_offline = 0x5a; | |
768e9a61 | 647 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); |
30b5c851 | 648 | break; |
14243b38 | 649 | |
30b5c851 | 650 | case 6: |
14243b38 DW |
651 | if (verbose) |
652 | printf("Testing steal time\n"); | |
30b5c851 DW |
653 | /* Yield until scheduler delay exceeds target */ |
654 | rundelay = get_run_delay() + MIN_STEAL_TIME; | |
655 | do { | |
656 | sched_yield(); | |
657 | } while (get_run_delay() < rundelay); | |
658 | break; | |
14243b38 DW |
659 | |
660 | case 7: | |
661 | if (!do_eventfd_tests) | |
662 | goto done; | |
663 | if (verbose) | |
664 | printf("Testing masked event channel\n"); | |
25eaeebe | 665 | shinfo->evtchn_mask[0] = 1UL << EVTCHN_TEST1; |
14243b38 DW |
666 | eventfd_write(irq_fd[0], 1UL); |
667 | alarm(1); | |
668 | break; | |
669 | ||
670 | case 8: | |
671 | if (verbose) | |
672 | printf("Testing unmasked event channel\n"); | |
673 | /* Unmask that, but deliver the other one */ | |
674 | shinfo->evtchn_pending[0] = 0; | |
675 | shinfo->evtchn_mask[0] = 0; | |
676 | eventfd_write(irq_fd[1], 1UL); | |
677 | evtchn_irq_expected = true; | |
678 | alarm(1); | |
679 | break; | |
680 | ||
681 | case 9: | |
25eaeebe DW |
682 | TEST_ASSERT(!evtchn_irq_expected, |
683 | "Expected event channel IRQ but it didn't happen"); | |
684 | shinfo->evtchn_pending[1] = 0; | |
14243b38 DW |
685 | if (verbose) |
686 | printf("Testing event channel after memslot change\n"); | |
687 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, | |
688 | DUMMY_REGION_GPA, DUMMY_REGION_SLOT, 1, 0); | |
689 | eventfd_write(irq_fd[0], 1UL); | |
690 | evtchn_irq_expected = true; | |
691 | alarm(1); | |
692 | break; | |
693 | ||
25eaeebe DW |
694 | case 10: |
695 | TEST_ASSERT(!evtchn_irq_expected, | |
696 | "Expected event channel IRQ but it didn't happen"); | |
697 | if (!do_evtchn_tests) | |
698 | goto done; | |
699 | ||
700 | shinfo->evtchn_pending[0] = 0; | |
701 | if (verbose) | |
702 | printf("Testing injection with KVM_XEN_HVM_EVTCHN_SEND\n"); | |
703 | ||
704 | struct kvm_irq_routing_xen_evtchn e; | |
705 | e.port = EVTCHN_TEST2; | |
0037727b | 706 | e.vcpu = vcpu->id; |
25eaeebe DW |
707 | e.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; |
708 | ||
709 | vm_ioctl(vm, KVM_XEN_HVM_EVTCHN_SEND, &e); | |
710 | evtchn_irq_expected = true; | |
711 | alarm(1); | |
712 | break; | |
713 | ||
714 | case 11: | |
715 | TEST_ASSERT(!evtchn_irq_expected, | |
716 | "Expected event channel IRQ but it didn't happen"); | |
717 | shinfo->evtchn_pending[1] = 0; | |
718 | ||
719 | if (verbose) | |
720 | printf("Testing guest EVTCHNOP_send direct to evtchn\n"); | |
721 | evtchn_irq_expected = true; | |
722 | alarm(1); | |
723 | break; | |
724 | ||
725 | case 12: | |
726 | TEST_ASSERT(!evtchn_irq_expected, | |
727 | "Expected event channel IRQ but it didn't happen"); | |
728 | shinfo->evtchn_pending[0] = 0; | |
729 | ||
730 | if (verbose) | |
731 | printf("Testing guest EVTCHNOP_send to eventfd\n"); | |
732 | evtchn_irq_expected = true; | |
733 | alarm(1); | |
734 | break; | |
735 | ||
736 | case 13: | |
737 | TEST_ASSERT(!evtchn_irq_expected, | |
738 | "Expected event channel IRQ but it didn't happen"); | |
739 | shinfo->evtchn_pending[1] = 0; | |
740 | ||
741 | if (verbose) | |
742 | printf("Testing guest oneshot timer\n"); | |
743 | break; | |
744 | ||
745 | case 14: | |
746 | memset(&tmr, 0, sizeof(tmr)); | |
42c35fdc | 747 | tmr.type = KVM_XEN_VCPU_ATTR_TYPE_TIMER; |
768e9a61 | 748 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); |
25eaeebe DW |
749 | TEST_ASSERT(tmr.u.timer.port == EVTCHN_TIMER, |
750 | "Timer port not returned"); | |
751 | TEST_ASSERT(tmr.u.timer.priority == KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, | |
752 | "Timer priority not returned"); | |
753 | TEST_ASSERT(tmr.u.timer.expires_ns > rs->state_entry_time, | |
754 | "Timer expiry not returned"); | |
755 | evtchn_irq_expected = true; | |
756 | alarm(1); | |
757 | break; | |
758 | ||
759 | case 15: | |
760 | TEST_ASSERT(!evtchn_irq_expected, | |
761 | "Expected event channel IRQ but it didn't happen"); | |
762 | shinfo->evtchn_pending[0] = 0; | |
763 | ||
764 | if (verbose) | |
765 | printf("Testing restored oneshot timer\n"); | |
766 | ||
fcba483e | 767 | tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; |
768e9a61 | 768 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); |
25eaeebe DW |
769 | evtchn_irq_expected = true; |
770 | alarm(1); | |
771 | break; | |
772 | ||
773 | case 16: | |
774 | TEST_ASSERT(!evtchn_irq_expected, | |
775 | "Expected event channel IRQ but it didn't happen"); | |
776 | ||
777 | if (verbose) | |
778 | printf("Testing SCHEDOP_poll with already pending event\n"); | |
779 | shinfo->evtchn_pending[0] = shinfo->evtchn_mask[0] = 1UL << EVTCHN_TIMER; | |
780 | alarm(1); | |
781 | break; | |
782 | ||
783 | case 17: | |
784 | if (verbose) | |
785 | printf("Testing SCHEDOP_poll timeout\n"); | |
786 | shinfo->evtchn_pending[0] = 0; | |
787 | alarm(1); | |
788 | break; | |
789 | ||
790 | case 18: | |
791 | if (verbose) | |
792 | printf("Testing SCHEDOP_poll wake on masked event\n"); | |
793 | ||
fcba483e | 794 | tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; |
768e9a61 | 795 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); |
a29833e3 | 796 | alarm(1); |
25eaeebe DW |
797 | break; |
798 | ||
799 | case 19: | |
800 | shinfo->evtchn_pending[0] = shinfo->evtchn_mask[0] = 0; | |
801 | if (verbose) | |
802 | printf("Testing SCHEDOP_poll wake on unmasked event\n"); | |
803 | ||
25eaeebe | 804 | evtchn_irq_expected = true; |
a29833e3 | 805 | tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; |
768e9a61 | 806 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); |
a29833e3 DW |
807 | |
808 | /* Read it back and check the pending time is reported correctly */ | |
809 | tmr.u.timer.expires_ns = 0; | |
768e9a61 | 810 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); |
a29833e3 DW |
811 | TEST_ASSERT(tmr.u.timer.expires_ns == rs->state_entry_time + 100000000, |
812 | "Timer not reported pending"); | |
813 | alarm(1); | |
25eaeebe DW |
814 | break; |
815 | ||
816 | case 20: | |
817 | TEST_ASSERT(!evtchn_irq_expected, | |
818 | "Expected event channel IRQ but it didn't happen"); | |
a29833e3 | 819 | /* Read timer and check it is no longer pending */ |
768e9a61 | 820 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); |
a29833e3 DW |
821 | TEST_ASSERT(!tmr.u.timer.expires_ns, "Timer still reported pending"); |
822 | ||
823 | shinfo->evtchn_pending[0] = 0; | |
824 | if (verbose) | |
825 | printf("Testing timer in the past\n"); | |
826 | ||
827 | evtchn_irq_expected = true; | |
828 | tmr.u.timer.expires_ns = rs->state_entry_time - 100000000ULL; | |
768e9a61 | 829 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); |
a29833e3 DW |
830 | alarm(1); |
831 | break; | |
832 | ||
833 | case 21: | |
834 | TEST_ASSERT(!evtchn_irq_expected, | |
835 | "Expected event channel IRQ but it didn't happen"); | |
a51abbbf ML |
836 | alarm(0); |
837 | ||
838 | if (verbose) | |
839 | printf("Testing shinfo lock corruption (KVM_XEN_HVM_EVTCHN_SEND)\n"); | |
840 | ||
841 | ret = pthread_create(&thread, NULL, &juggle_shinfo_state, (void *)vm); | |
842 | TEST_ASSERT(ret == 0, "pthread_create() failed: %s", strerror(ret)); | |
843 | ||
844 | struct kvm_irq_routing_xen_evtchn uxe = { | |
845 | .port = 1, | |
846 | .vcpu = vcpu->id, | |
847 | .priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL | |
848 | }; | |
849 | ||
850 | evtchn_irq_expected = true; | |
851 | for (time_t t = time(NULL) + SHINFO_RACE_TIMEOUT; time(NULL) < t;) | |
852 | __vm_ioctl(vm, KVM_XEN_HVM_EVTCHN_SEND, &uxe); | |
853 | break; | |
854 | ||
855 | case 22: | |
856 | TEST_ASSERT(!evtchn_irq_expected, | |
857 | "Expected event channel IRQ but it didn't happen"); | |
858 | ||
859 | if (verbose) | |
860 | printf("Testing shinfo lock corruption (SCHEDOP_poll)\n"); | |
861 | ||
862 | shinfo->evtchn_pending[0] = 1; | |
863 | ||
864 | evtchn_irq_expected = true; | |
865 | tmr.u.timer.expires_ns = rs->state_entry_time + | |
866 | SHINFO_RACE_TIMEOUT * 1000000000ULL; | |
867 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); | |
868 | break; | |
869 | ||
870 | case 23: | |
871 | /* | |
872 | * Optional and possibly repeated sync point. | |
873 | * Injecting the timer IRQ may fail if the | |
874 | * shinfo is invalid when the timer expires. | |
875 | * If the timer has expired but the IRQ hasn't | |
876 | * been delivered, rearm the timer and retry. | |
877 | */ | |
878 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); | |
879 | ||
880 | /* Resume the guest if the timer is still pending. */ | |
881 | if (tmr.u.timer.expires_ns) | |
882 | break; | |
883 | ||
884 | /* All done if the IRQ was delivered. */ | |
885 | if (!evtchn_irq_expected) | |
886 | break; | |
887 | ||
888 | tmr.u.timer.expires_ns = rs->state_entry_time + | |
889 | SHINFO_RACE_TIMEOUT * 1000000000ULL; | |
890 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); | |
891 | break; | |
892 | case 24: | |
893 | TEST_ASSERT(!evtchn_irq_expected, | |
894 | "Expected event channel IRQ but it didn't happen"); | |
895 | ||
896 | ret = pthread_cancel(thread); | |
897 | TEST_ASSERT(ret == 0, "pthread_cancel() failed: %s", strerror(ret)); | |
898 | ||
899 | ret = pthread_join(thread, 0); | |
900 | TEST_ASSERT(ret == 0, "pthread_join() failed: %s", strerror(ret)); | |
25eaeebe DW |
901 | goto done; |
902 | ||
7c4de881 DW |
903 | case 0x20: |
904 | TEST_ASSERT(evtchn_irq_expected, "Unexpected event channel IRQ"); | |
905 | evtchn_irq_expected = false; | |
906 | break; | |
30b5c851 | 907 | } |
8d4e7e80 | 908 | break; |
30b5c851 | 909 | } |
8d4e7e80 DW |
910 | case UCALL_DONE: |
911 | goto done; | |
912 | default: | |
913 | TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd); | |
914 | } | |
915 | } | |
916 | ||
917 | done: | |
50aa870b PB |
918 | evt_reset.type = KVM_XEN_ATTR_TYPE_EVTCHN; |
919 | evt_reset.u.evtchn.flags = KVM_XEN_EVTCHN_RESET; | |
a79b53aa PB |
920 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &evt_reset); |
921 | ||
25eaeebe | 922 | alarm(0); |
8d4e7e80 DW |
923 | clock_gettime(CLOCK_REALTIME, &max_ts); |
924 | ||
925 | /* | |
926 | * Just a *really* basic check that things are being put in the | |
927 | * right place. The actual calculations are much the same for | |
928 | * Xen as they are for the KVM variants, so no need to check. | |
929 | */ | |
930 | struct pvclock_wall_clock *wc; | |
931 | struct pvclock_vcpu_time_info *ti, *ti2; | |
932 | ||
f1b83973 SC |
933 | wc = addr_gpa2hva(vm, SHINFO_REGION_GPA + 0xc00); |
934 | ti = addr_gpa2hva(vm, SHINFO_REGION_GPA + 0x40 + 0x20); | |
935 | ti2 = addr_gpa2hva(vm, PVTIME_ADDR); | |
8d4e7e80 | 936 | |
14243b38 DW |
937 | if (verbose) { |
938 | printf("Wall clock (v %d) %d.%09d\n", wc->version, wc->sec, wc->nsec); | |
939 | printf("Time info 1: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n", | |
940 | ti->version, ti->tsc_timestamp, ti->system_time, ti->tsc_to_system_mul, | |
941 | ti->tsc_shift, ti->flags); | |
942 | printf("Time info 2: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n", | |
943 | ti2->version, ti2->tsc_timestamp, ti2->system_time, ti2->tsc_to_system_mul, | |
944 | ti2->tsc_shift, ti2->flags); | |
945 | } | |
946 | ||
8d4e7e80 DW |
947 | vm_ts.tv_sec = wc->sec; |
948 | vm_ts.tv_nsec = wc->nsec; | |
96c852c8 | 949 | TEST_ASSERT(wc->version && !(wc->version & 1), |
8d4e7e80 DW |
950 | "Bad wallclock version %x", wc->version); |
951 | TEST_ASSERT(cmp_timespec(&min_ts, &vm_ts) <= 0, "VM time too old"); | |
952 | TEST_ASSERT(cmp_timespec(&max_ts, &vm_ts) >= 0, "VM time too new"); | |
953 | ||
954 | TEST_ASSERT(ti->version && !(ti->version & 1), | |
955 | "Bad time_info version %x", ti->version); | |
956 | TEST_ASSERT(ti2->version && !(ti2->version & 1), | |
957 | "Bad time_info version %x", ti->version); | |
958 | ||
30b5c851 DW |
959 | if (do_runstate_tests) { |
960 | /* | |
961 | * Fetch runstate and check sanity. Strictly speaking in the | |
962 | * general case we might not expect the numbers to be identical | |
963 | * but in this case we know we aren't running the vCPU any more. | |
964 | */ | |
965 | struct kvm_xen_vcpu_attr rst = { | |
966 | .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA, | |
967 | }; | |
768e9a61 | 968 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &rst); |
30b5c851 | 969 | |
14243b38 DW |
970 | if (verbose) { |
971 | printf("Runstate: %s(%d), entry %" PRIu64 " ns\n", | |
972 | rs->state <= RUNSTATE_offline ? runstate_names[rs->state] : "unknown", | |
973 | rs->state, rs->state_entry_time); | |
974 | for (int i = RUNSTATE_running; i <= RUNSTATE_offline; i++) { | |
975 | printf("State %s: %" PRIu64 " ns\n", | |
976 | runstate_names[i], rs->time[i]); | |
977 | } | |
978 | } | |
8acc3518 DW |
979 | |
980 | /* | |
981 | * Exercise runstate info at all points across the page boundary, in | |
982 | * 32-bit and 64-bit mode. In particular, test the case where it is | |
983 | * configured in 32-bit mode and then switched to 64-bit mode while | |
984 | * active, which takes it onto the second page. | |
985 | */ | |
986 | unsigned long runstate_addr; | |
987 | struct compat_vcpu_runstate_info *crs; | |
988 | for (runstate_addr = SHINFO_REGION_GPA + PAGE_SIZE + PAGE_SIZE - sizeof(*rs) - 4; | |
989 | runstate_addr < SHINFO_REGION_GPA + PAGE_SIZE + PAGE_SIZE + 4; runstate_addr++) { | |
990 | ||
991 | rs = addr_gpa2hva(vm, runstate_addr); | |
992 | crs = (void *)rs; | |
993 | ||
994 | memset(rs, 0xa5, sizeof(*rs)); | |
995 | ||
996 | /* Set to compatibility mode */ | |
997 | lm.u.long_mode = 0; | |
998 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm); | |
999 | ||
1000 | /* Set runstate to new address (kernel will write it) */ | |
1001 | struct kvm_xen_vcpu_attr st = { | |
1002 | .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, | |
1003 | .u.gpa = runstate_addr, | |
1004 | }; | |
1005 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &st); | |
1006 | ||
1007 | if (verbose) | |
1008 | printf("Compatibility runstate at %08lx\n", runstate_addr); | |
1009 | ||
1010 | TEST_ASSERT(crs->state == rst.u.runstate.state, "Runstate mismatch"); | |
1011 | TEST_ASSERT(crs->state_entry_time == rst.u.runstate.state_entry_time, | |
1012 | "State entry time mismatch"); | |
1013 | TEST_ASSERT(crs->time[RUNSTATE_running] == rst.u.runstate.time_running, | |
1014 | "Running time mismatch"); | |
1015 | TEST_ASSERT(crs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable, | |
1016 | "Runnable time mismatch"); | |
1017 | TEST_ASSERT(crs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked, | |
1018 | "Blocked time mismatch"); | |
1019 | TEST_ASSERT(crs->time[RUNSTATE_offline] == rst.u.runstate.time_offline, | |
1020 | "Offline time mismatch"); | |
1021 | TEST_ASSERT(crs->time[RUNSTATE_offline + 1] == 0xa5a5a5a5a5a5a5a5ULL, | |
1022 | "Structure overrun"); | |
1023 | TEST_ASSERT(crs->state_entry_time == crs->time[0] + | |
1024 | crs->time[1] + crs->time[2] + crs->time[3], | |
1025 | "runstate times don't add up"); | |
1026 | ||
1027 | ||
1028 | /* Now switch to 64-bit mode */ | |
1029 | lm.u.long_mode = 1; | |
1030 | vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm); | |
1031 | ||
1032 | memset(rs, 0xa5, sizeof(*rs)); | |
1033 | ||
1034 | /* Don't change the address, just trigger a write */ | |
1035 | struct kvm_xen_vcpu_attr adj = { | |
1036 | .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST, | |
1037 | .u.runstate.state = (uint64_t)-1 | |
1038 | }; | |
1039 | vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &adj); | |
1040 | ||
1041 | if (verbose) | |
1042 | printf("64-bit runstate at %08lx\n", runstate_addr); | |
1043 | ||
1044 | TEST_ASSERT(rs->state == rst.u.runstate.state, "Runstate mismatch"); | |
1045 | TEST_ASSERT(rs->state_entry_time == rst.u.runstate.state_entry_time, | |
1046 | "State entry time mismatch"); | |
1047 | TEST_ASSERT(rs->time[RUNSTATE_running] == rst.u.runstate.time_running, | |
1048 | "Running time mismatch"); | |
1049 | TEST_ASSERT(rs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable, | |
1050 | "Runnable time mismatch"); | |
1051 | TEST_ASSERT(rs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked, | |
1052 | "Blocked time mismatch"); | |
1053 | TEST_ASSERT(rs->time[RUNSTATE_offline] == rst.u.runstate.time_offline, | |
1054 | "Offline time mismatch"); | |
1055 | TEST_ASSERT(rs->time[RUNSTATE_offline + 1] == 0xa5a5a5a5a5a5a5a5ULL, | |
1056 | "Structure overrun"); | |
1057 | ||
1058 | TEST_ASSERT(rs->state_entry_time == rs->time[0] + | |
1059 | rs->time[1] + rs->time[2] + rs->time[3], | |
1060 | "runstate times don't add up"); | |
1061 | } | |
30b5c851 | 1062 | } |
8acc3518 | 1063 | |
8d4e7e80 DW |
1064 | kvm_vm_free(vm); |
1065 | return 0; | |
1066 | } |