1 /***************************************************************************
2 * time.c
3 *
4 * An implementation of some time related Viridian enlightenments.
5 * See Microsoft's Hypervisor Top Level Functional Specification.
6 * for more information.
7 */
8
9 #include <xen/domain_page.h>
10 #include <xen/hypercall.h>
11 #include <xen/sched.h>
12 #include <xen/version.h>
13
14 #include <asm/apic.h>
15 #include <asm/event.h>
16 #include <asm/guest/hyperv.h>
17 #include <asm/guest/hyperv-tlfs.h>
18
19 #include "private.h"
20
update_reference_tsc(const struct domain * d,bool initialize)21 static void update_reference_tsc(const struct domain *d, bool initialize)
22 {
23 struct viridian_domain *vd = d->arch.hvm.viridian;
24 const struct viridian_time_ref_count *trc = &vd->time_ref_count;
25 const struct viridian_page *rt = &vd->reference_tsc;
26 HV_REFERENCE_TSC_PAGE *p = rt->ptr;
27 uint32_t seq;
28
29 if ( initialize )
30 clear_page(p);
31
32 /*
33 * This enlightenment must be disabled is the host TSC is not invariant.
34 * However it is also disabled if vtsc is true (which means rdtsc is
35 * being emulated). This generally happens when guest TSC freq and host
36 * TSC freq don't match. The TscScale value could be adjusted to cope
37 * with this, allowing vtsc to be turned off, but support for this is
38 * not yet present in the hypervisor. Thus is it is possible that
39 * migrating a Windows VM between hosts of differing TSC frequencies
40 * may result in large differences in guest performance. Any jump in
41 * TSC due to migration down-time can, however, be compensated for by
42 * setting the TscOffset value (see below).
43 */
44 if ( !host_tsc_is_safe() || d->arch.vtsc )
45 {
46 /*
47 * The value 0 is used to indicate this mechanism is no longer a
48 * reliable source of time and that the VM should fall back to a
49 * different source.
50 */
51 p->tsc_sequence = 0;
52
53 printk(XENLOG_G_INFO "d%d: VIRIDIAN REFERENCE_TSC: invalidated\n",
54 d->domain_id);
55 return;
56 }
57
58 /*
59 * The guest will calculate reference time according to the following
60 * formula:
61 *
62 * ReferenceTime = ((RDTSC() * TscScale) >> 64) + TscOffset
63 *
64 * Windows uses a 100ns tick, so we need a scale which is cpu
65 * ticks per 100ns shifted left by 64.
66 * The offset value is calculated on restore after migration and
67 * ensures that Windows will not see a large jump in ReferenceTime.
68 */
69 p->tsc_scale = ((10000UL << 32) / d->arch.tsc_khz) << 32;
70 p->tsc_offset = trc->off;
71 smp_wmb();
72
73 seq = p->tsc_sequence + 1;
74 p->tsc_sequence = seq ? seq : 1; /* Avoid 'invalid' value 0 */
75 }
76
trc_val(const struct domain * d,int64_t offset)77 static uint64_t trc_val(const struct domain *d, int64_t offset)
78 {
79 uint64_t tsc, scale;
80
81 tsc = hvm_get_guest_tsc(pt_global_vcpu_target(d));
82 scale = ((10000UL << 32) / d->arch.tsc_khz) << 32;
83
84 return hv_scale_tsc(tsc, scale, offset);
85 }
86
time_ref_count_freeze(const struct domain * d)87 static void time_ref_count_freeze(const struct domain *d)
88 {
89 struct viridian_time_ref_count *trc =
90 &d->arch.hvm.viridian->time_ref_count;
91
92 if ( test_and_clear_bit(_TRC_running, &trc->flags) )
93 trc->val = trc_val(d, trc->off);
94 }
95
time_ref_count_thaw(const struct domain * d)96 static void time_ref_count_thaw(const struct domain *d)
97 {
98 struct viridian_domain *vd = d->arch.hvm.viridian;
99 struct viridian_time_ref_count *trc = &vd->time_ref_count;
100
101 if ( d->is_shutting_down ||
102 test_and_set_bit(_TRC_running, &trc->flags) )
103 return;
104
105 trc->off = (int64_t)trc->val - trc_val(d, 0);
106
107 if ( vd->reference_tsc.msr.enabled )
108 update_reference_tsc(d, false);
109 }
110
time_ref_count(const struct domain * d)111 static uint64_t time_ref_count(const struct domain *d)
112 {
113 const struct viridian_time_ref_count *trc =
114 &d->arch.hvm.viridian->time_ref_count;
115
116 return trc_val(d, trc->off);
117 }
118
stop_stimer(struct viridian_stimer * vs)119 static void stop_stimer(struct viridian_stimer *vs)
120 {
121 if ( !vs->started )
122 return;
123
124 stop_timer(&vs->timer);
125 vs->started = false;
126 }
127
stimer_expire(void * data)128 static void cf_check stimer_expire(void *data)
129 {
130 struct viridian_stimer *vs = data;
131 struct vcpu *v = vs->v;
132 struct viridian_vcpu *vv = v->arch.hvm.viridian;
133 unsigned int stimerx = vs - &vv->stimer[0];
134
135 set_bit(stimerx, &vv->stimer_pending);
136 vcpu_kick(v);
137 }
138
start_stimer(struct viridian_stimer * vs)139 static void start_stimer(struct viridian_stimer *vs)
140 {
141 const struct vcpu *v = vs->v;
142 struct viridian_vcpu *vv = v->arch.hvm.viridian;
143 unsigned int stimerx = vs - &vv->stimer[0];
144 int64_t now = time_ref_count(v->domain);
145 int64_t expiration;
146 s_time_t timeout;
147
148 if ( !test_and_set_bit(stimerx, &vv->stimer_enabled) )
149 printk(XENLOG_G_INFO "%pv: VIRIDIAN STIMER%u: enabled\n", v,
150 stimerx);
151
152 if ( vs->config.periodic )
153 {
154 /*
155 * The specification says that if the timer is lazy then we
156 * skip over any missed expirations so we can treat this case
157 * as the same as if the timer is currently stopped, i.e. we
158 * just schedule expiration to be 'count' ticks from now.
159 */
160 if ( !vs->started || vs->config.lazy )
161 expiration = now + vs->count;
162 else
163 {
164 unsigned int missed = 0;
165
166 /*
167 * The timer is already started, so we're re-scheduling.
168 * Hence advance the timer expiration by one tick.
169 */
170 expiration = vs->expiration + vs->count;
171
172 /* Now check to see if any expirations have been missed */
173 if ( expiration - now <= 0 )
174 missed = ((now - expiration) / vs->count) + 1;
175
176 /*
177 * The specification says that if the timer is not lazy then
178 * a non-zero missed count should be used to reduce the period
179 * of the timer until it catches up, unless the count has
180 * reached a 'significant number', in which case the timer
181 * should be treated as lazy. Unfortunately the specification
182 * does not state what that number is so the choice of number
183 * here is a pure guess.
184 */
185 if ( missed > 3 )
186 expiration = now + vs->count;
187 else if ( missed )
188 expiration = now + (vs->count / missed);
189 }
190 }
191 else
192 {
193 expiration = vs->count;
194 if ( expiration - now <= 0 )
195 {
196 vs->expiration = expiration;
197 stimer_expire(vs);
198 return;
199 }
200 }
201 ASSERT(expiration - now > 0);
202
203 vs->expiration = expiration;
204 timeout = (expiration - now) * 100ULL;
205
206 vs->started = true;
207 clear_bit(stimerx, &vv->stimer_pending);
208 migrate_timer(&vs->timer, v->processor);
209 set_timer(&vs->timer, timeout + NOW());
210 }
211
poll_stimer(struct vcpu * v,unsigned int stimerx)212 static void poll_stimer(struct vcpu *v, unsigned int stimerx)
213 {
214 struct viridian_vcpu *vv = v->arch.hvm.viridian;
215 struct viridian_stimer *vs = &vv->stimer[stimerx];
216
217 /*
218 * Timer expiry may race with the timer being disabled. If the timer
219 * is disabled make sure the pending bit is cleared to avoid re-
220 * polling.
221 */
222 if ( !vs->config.enable )
223 {
224 clear_bit(stimerx, &vv->stimer_pending);
225 return;
226 }
227
228 if ( !test_bit(stimerx, &vv->stimer_pending) )
229 return;
230
231 if ( !viridian_synic_deliver_timer_msg(v, vs->config.sintx,
232 stimerx, vs->expiration,
233 time_ref_count(v->domain)) )
234 return;
235
236 clear_bit(stimerx, &vv->stimer_pending);
237
238 if ( vs->config.periodic )
239 start_stimer(vs);
240 else
241 vs->config.enable = 0;
242 }
243
viridian_time_poll_timers(struct vcpu * v)244 void viridian_time_poll_timers(struct vcpu *v)
245 {
246 struct viridian_vcpu *vv = v->arch.hvm.viridian;
247 unsigned int i;
248
249 if ( !vv->stimer_pending )
250 return;
251
252 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
253 poll_stimer(v, i);
254 }
255
time_vcpu_freeze(struct vcpu * v)256 static void time_vcpu_freeze(struct vcpu *v)
257 {
258 struct viridian_vcpu *vv = v->arch.hvm.viridian;
259 unsigned int i;
260
261 if ( !is_viridian_vcpu(v) ||
262 !(viridian_feature_mask(v->domain) & HVMPV_stimer) )
263 return;
264
265 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
266 {
267 struct viridian_stimer *vs = &vv->stimer[i];
268
269 if ( vs->started )
270 stop_timer(&vs->timer);
271 }
272 }
273
time_vcpu_thaw(struct vcpu * v)274 static void time_vcpu_thaw(struct vcpu *v)
275 {
276 struct viridian_vcpu *vv = v->arch.hvm.viridian;
277 unsigned int i;
278
279 if ( !is_viridian_vcpu(v) ||
280 !(viridian_feature_mask(v->domain) & HVMPV_stimer) )
281 return;
282
283 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
284 {
285 struct viridian_stimer *vs = &vv->stimer[i];
286
287 if ( vs->config.enable )
288 start_stimer(vs);
289 }
290 }
291
viridian_time_domain_freeze(const struct domain * d)292 void viridian_time_domain_freeze(const struct domain *d)
293 {
294 struct vcpu *v;
295
296 if ( d->is_dying || !is_viridian_domain(d) )
297 return;
298
299 for_each_vcpu ( d, v )
300 time_vcpu_freeze(v);
301
302 time_ref_count_freeze(d);
303 }
304
viridian_time_domain_thaw(const struct domain * d)305 void viridian_time_domain_thaw(const struct domain *d)
306 {
307 struct vcpu *v;
308
309 if ( d->is_dying || !is_viridian_domain(d) )
310 return;
311
312 time_ref_count_thaw(d);
313
314 for_each_vcpu ( d, v )
315 time_vcpu_thaw(v);
316 }
317
viridian_time_wrmsr(struct vcpu * v,uint32_t idx,uint64_t val)318 int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val)
319 {
320 struct viridian_vcpu *vv = v->arch.hvm.viridian;
321 struct domain *d = v->domain;
322 struct viridian_domain *vd = d->arch.hvm.viridian;
323
324 switch ( idx )
325 {
326 case HV_X64_MSR_REFERENCE_TSC:
327 if ( !(viridian_feature_mask(d) & HVMPV_reference_tsc) )
328 return X86EMUL_EXCEPTION;
329
330 viridian_unmap_guest_page(&vd->reference_tsc);
331 vd->reference_tsc.msr.raw = val;
332 viridian_dump_guest_page(v, "REFERENCE_TSC", &vd->reference_tsc);
333 if ( vd->reference_tsc.msr.enabled )
334 {
335 viridian_map_guest_page(d, &vd->reference_tsc);
336 update_reference_tsc(d, true);
337 }
338 break;
339
340 case HV_X64_MSR_TIME_REF_COUNT:
341 return X86EMUL_EXCEPTION;
342
343 case HV_X64_MSR_STIMER0_CONFIG:
344 case HV_X64_MSR_STIMER1_CONFIG:
345 case HV_X64_MSR_STIMER2_CONFIG:
346 case HV_X64_MSR_STIMER3_CONFIG:
347 {
348 unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
349 struct viridian_stimer *vs =
350 &array_access_nospec(vv->stimer, stimerx);
351
352 if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
353 return X86EMUL_EXCEPTION;
354
355 stop_stimer(vs);
356
357 vs->config.as_uint64 = val;
358
359 if ( !vs->config.sintx )
360 vs->config.enable = 0;
361
362 if ( vs->config.enable )
363 start_stimer(vs);
364
365 break;
366 }
367
368 case HV_X64_MSR_STIMER0_COUNT:
369 case HV_X64_MSR_STIMER1_COUNT:
370 case HV_X64_MSR_STIMER2_COUNT:
371 case HV_X64_MSR_STIMER3_COUNT:
372 {
373 unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
374 struct viridian_stimer *vs =
375 &array_access_nospec(vv->stimer, stimerx);
376
377 if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
378 return X86EMUL_EXCEPTION;
379
380 stop_stimer(vs);
381
382 vs->count = val;
383
384 if ( !vs->count )
385 vs->config.enable = 0;
386 else if ( vs->config.auto_enable )
387 vs->config.enable = 1;
388
389 if ( vs->config.enable )
390 start_stimer(vs);
391
392 break;
393 }
394
395 default:
396 gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x (%016"PRIx64")\n",
397 __func__, idx, val);
398 return X86EMUL_EXCEPTION;
399 }
400
401 return X86EMUL_OKAY;
402 }
403
viridian_time_rdmsr(const struct vcpu * v,uint32_t idx,uint64_t * val)404 int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val)
405 {
406 const struct viridian_vcpu *vv = v->arch.hvm.viridian;
407 const struct domain *d = v->domain;
408 struct viridian_domain *vd = d->arch.hvm.viridian;
409
410 switch ( idx )
411 {
412 case HV_X64_MSR_TSC_FREQUENCY:
413 if ( viridian_feature_mask(d) & HVMPV_no_freq )
414 return X86EMUL_EXCEPTION;
415
416 *val = (uint64_t)d->arch.tsc_khz * 1000ULL;
417 break;
418
419 case HV_X64_MSR_APIC_FREQUENCY:
420 if ( viridian_feature_mask(d) & HVMPV_no_freq )
421 return X86EMUL_EXCEPTION;
422
423 *val = 1000000000ULL / APIC_BUS_CYCLE_NS;
424 break;
425
426 case HV_X64_MSR_REFERENCE_TSC:
427 if ( !(viridian_feature_mask(d) & HVMPV_reference_tsc) )
428 return X86EMUL_EXCEPTION;
429
430 *val = vd->reference_tsc.msr.raw;
431 break;
432
433 case HV_X64_MSR_TIME_REF_COUNT:
434 {
435 struct viridian_time_ref_count *trc = &vd->time_ref_count;
436
437 if ( !(viridian_feature_mask(d) & HVMPV_time_ref_count) )
438 return X86EMUL_EXCEPTION;
439
440 if ( !test_and_set_bit(_TRC_accessed, &trc->flags) )
441 printk(XENLOG_G_INFO "d%d: VIRIDIAN MSR_TIME_REF_COUNT: accessed\n",
442 d->domain_id);
443
444 *val = time_ref_count(d);
445 break;
446 }
447
448 case HV_X64_MSR_STIMER0_CONFIG:
449 case HV_X64_MSR_STIMER1_CONFIG:
450 case HV_X64_MSR_STIMER2_CONFIG:
451 case HV_X64_MSR_STIMER3_CONFIG:
452 {
453 unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
454 const struct viridian_stimer *vs =
455 &array_access_nospec(vv->stimer, stimerx);
456 union hv_stimer_config config = vs->config;
457
458 if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
459 return X86EMUL_EXCEPTION;
460
461 /*
462 * If the timer is single-shot and it has expired, make sure
463 * the enabled flag is clear.
464 */
465 if ( !config.periodic && test_bit(stimerx, &vv->stimer_pending) )
466 config.enable = 0;
467
468 *val = config.as_uint64;
469 break;
470 }
471
472 case HV_X64_MSR_STIMER0_COUNT:
473 case HV_X64_MSR_STIMER1_COUNT:
474 case HV_X64_MSR_STIMER2_COUNT:
475 case HV_X64_MSR_STIMER3_COUNT:
476 {
477 unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
478 const struct viridian_stimer *vs =
479 &array_access_nospec(vv->stimer, stimerx);
480
481 if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
482 return X86EMUL_EXCEPTION;
483
484 *val = vs->count;
485 break;
486 }
487
488 default:
489 gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x\n", __func__, idx);
490 return X86EMUL_EXCEPTION;
491 }
492
493 return X86EMUL_OKAY;
494 }
495
viridian_time_vcpu_init(struct vcpu * v)496 int viridian_time_vcpu_init(struct vcpu *v)
497 {
498 struct viridian_vcpu *vv = v->arch.hvm.viridian;
499 unsigned int i;
500
501 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
502 {
503 struct viridian_stimer *vs = &vv->stimer[i];
504
505 vs->v = v;
506 init_timer(&vs->timer, stimer_expire, vs, v->processor);
507 }
508
509 return 0;
510 }
511
viridian_time_domain_init(const struct domain * d)512 int viridian_time_domain_init(const struct domain *d)
513 {
514 return 0;
515 }
516
viridian_time_vcpu_deinit(const struct vcpu * v)517 void viridian_time_vcpu_deinit(const struct vcpu *v)
518 {
519 struct viridian_vcpu *vv = v->arch.hvm.viridian;
520 unsigned int i;
521
522 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
523 {
524 struct viridian_stimer *vs = &vv->stimer[i];
525
526 if ( !vs->v )
527 continue;
528 kill_timer(&vs->timer);
529 vs->v = NULL;
530 }
531 }
532
viridian_time_domain_deinit(const struct domain * d)533 void viridian_time_domain_deinit(const struct domain *d)
534 {
535 viridian_unmap_guest_page(&d->arch.hvm.viridian->reference_tsc);
536 }
537
viridian_time_save_vcpu_ctxt(const struct vcpu * v,struct hvm_viridian_vcpu_context * ctxt)538 void viridian_time_save_vcpu_ctxt(
539 const struct vcpu *v, struct hvm_viridian_vcpu_context *ctxt)
540 {
541 const struct viridian_vcpu *vv = v->arch.hvm.viridian;
542 unsigned int i;
543
544 BUILD_BUG_ON(ARRAY_SIZE(vv->stimer) !=
545 ARRAY_SIZE(ctxt->stimer_config_msr));
546 BUILD_BUG_ON(ARRAY_SIZE(vv->stimer) !=
547 ARRAY_SIZE(ctxt->stimer_count_msr));
548
549 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
550 {
551 const struct viridian_stimer *vs = &vv->stimer[i];
552
553 ctxt->stimer_config_msr[i] = vs->config.as_uint64;
554 ctxt->stimer_count_msr[i] = vs->count;
555 }
556 }
557
viridian_time_load_vcpu_ctxt(struct vcpu * v,const struct hvm_viridian_vcpu_context * ctxt)558 void viridian_time_load_vcpu_ctxt(
559 struct vcpu *v, const struct hvm_viridian_vcpu_context *ctxt)
560 {
561 struct viridian_vcpu *vv = v->arch.hvm.viridian;
562 unsigned int i;
563
564 for ( i = 0; i < ARRAY_SIZE(vv->stimer); i++ )
565 {
566 struct viridian_stimer *vs = &vv->stimer[i];
567
568 vs->config.as_uint64 = ctxt->stimer_config_msr[i];
569 vs->count = ctxt->stimer_count_msr[i];
570 }
571 }
572
viridian_time_save_domain_ctxt(const struct domain * d,struct hvm_viridian_domain_context * ctxt)573 void viridian_time_save_domain_ctxt(
574 const struct domain *d, struct hvm_viridian_domain_context *ctxt)
575 {
576 const struct viridian_domain *vd = d->arch.hvm.viridian;
577
578 ctxt->time_ref_count = vd->time_ref_count.val;
579 ctxt->reference_tsc = vd->reference_tsc.msr.raw;
580 }
581
viridian_time_load_domain_ctxt(struct domain * d,const struct hvm_viridian_domain_context * ctxt)582 void viridian_time_load_domain_ctxt(
583 struct domain *d, const struct hvm_viridian_domain_context *ctxt)
584 {
585 struct viridian_domain *vd = d->arch.hvm.viridian;
586
587 vd->time_ref_count.val = ctxt->time_ref_count;
588 vd->reference_tsc.msr.raw = ctxt->reference_tsc;
589
590 if ( vd->reference_tsc.msr.enabled )
591 viridian_map_guest_page(d, &vd->reference_tsc);
592 }
593
594 /*
595 * Local variables:
596 * mode: C
597 * c-file-style: "BSD"
598 * c-basic-offset: 4
599 * tab-width: 4
600 * indent-tabs-mode: nil
601 * End:
602 */
603