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