|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 8/9] viridian: add implementation of synthetic timers
This patch introduces an implementation of the STIMER0-15_CONFIG/COUNT MSRs
and hence a the first SynIC message source.
The new (and documented) 'stimer' viridian enlightenment group may be
specified to enable this feature.
NOTE: It is necessary for correct operation that timer expiration and
message delivery time-stamping use the same time source as the guest.
The specification is ambiguous but testing with a Windows 10 1803
guest has shown that using the partition reference counter as a
source whilst the guest is using RDTSC and the reference tsc page
does not work correctly. Therefore the time_now() function is used.
This implements the algorithm for acquiring partition reference time
that is documented in the specifiction. This requires use of 128-bit
arithmetic and hence __int128_t values are used in the calculation,
although the result is a signed 64-bit value.
Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Tim Deegan <tim@xxxxxxx>
Cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx>
v3:
- Re-worked missed ticks calculation
---
docs/man/xl.cfg.5.pod.in | 12 +-
tools/libxl/libxl.h | 6 +
tools/libxl/libxl_dom.c | 4 +
tools/libxl/libxl_types.idl | 1 +
xen/arch/x86/hvm/viridian/private.h | 6 +
xen/arch/x86/hvm/viridian/synic.c | 48 +++-
xen/arch/x86/hvm/viridian/time.c | 343 +++++++++++++++++++++++++
xen/arch/x86/hvm/viridian/viridian.c | 19 ++
xen/include/asm-x86/hvm/viridian.h | 30 +++
xen/include/public/arch-x86/hvm/save.h | 2 +
xen/include/public/hvm/params.h | 7 +-
11 files changed, 474 insertions(+), 4 deletions(-)
diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index ad81af1ed8..355c654693 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -2167,11 +2167,19 @@ This group incorporates the crash control MSRs. These
enlightenments
allow Windows to write crash information such that it can be logged
by Xen.
+=item B<stimer>
+
+This set incorporates the SynIC and synthetic timer MSRs. Windows will
+use synthetic timers in preference to emulated HPET for a source of
+ticks and hence enabling this group will ensure that ticks will be
+consistent with use of an enlightened time source (B<time_ref_count> or
+B<reference_tsc>).
+
=item B<defaults>
This is a special value that enables the default set of groups, which
-is currently the B<base>, B<freq>, B<time_ref_count>, B<apic_assist>
-and B<crash_ctl> groups.
+is currently the B<base>, B<freq>, B<time_ref_count>, B<apic_assist>,
+B<crash_ctl> and B<stimer> groups.
=item B<all>
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index a923a380d3..c8f219b0d3 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -324,6 +324,12 @@
*/
#define LIBXL_HAVE_VIRIDIAN_SYNIC 1
+/*
+ * LIBXL_HAVE_VIRIDIAN_STIMER indicates that the 'stimer' value
+ * is present in the viridian enlightenment enumeration.
+ */
+#define LIBXL_HAVE_VIRIDIAN_STIMER 1
+
/*
* LIBXL_HAVE_BUILDINFO_HVM_ACPI_LAPTOP_SLATE indicates that
* libxl_domain_build_info has the u.hvm.acpi_laptop_slate field.
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index fb758d2ac3..2ee0f82ee7 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -269,6 +269,7 @@ static int hvm_set_viridian_features(libxl__gc *gc,
uint32_t domid,
libxl_bitmap_set(&enlightenments,
LIBXL_VIRIDIAN_ENLIGHTENMENT_TIME_REF_COUNT);
libxl_bitmap_set(&enlightenments,
LIBXL_VIRIDIAN_ENLIGHTENMENT_APIC_ASSIST);
libxl_bitmap_set(&enlightenments,
LIBXL_VIRIDIAN_ENLIGHTENMENT_CRASH_CTL);
+ libxl_bitmap_set(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_STIMER);
}
libxl_for_each_set_bit(v, info->u.hvm.viridian_enable) {
@@ -320,6 +321,9 @@ static int hvm_set_viridian_features(libxl__gc *gc,
uint32_t domid,
if (libxl_bitmap_test(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_SYNIC))
mask |= HVMPV_synic;
+ if (libxl_bitmap_test(&enlightenments,
LIBXL_VIRIDIAN_ENLIGHTENMENT_STIMER))
+ mask |= HVMPV_time_ref_count | HVMPV_synic | HVMPV_stimer;
+
if (mask != 0 &&
xc_hvm_param_set(CTX->xch,
domid,
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 9860bcaf5f..1cce249de4 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -236,6 +236,7 @@ libxl_viridian_enlightenment =
Enumeration("viridian_enlightenment", [
(5, "apic_assist"),
(6, "crash_ctl"),
(7, "synic"),
+ (8, "stimer"),
])
libxl_hdtype = Enumeration("hdtype", [
diff --git a/xen/arch/x86/hvm/viridian/private.h
b/xen/arch/x86/hvm/viridian/private.h
index 0bf34eefe0..6f81f62b60 100644
--- a/xen/arch/x86/hvm/viridian/private.h
+++ b/xen/arch/x86/hvm/viridian/private.h
@@ -74,6 +74,10 @@
int viridian_synic_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val);
int viridian_synic_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val);
+bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx,
+ unsigned int index,
+ int64_t expiration, int64_t delivery);
+
int viridian_synic_vcpu_init(struct vcpu *v);
int viridian_synic_domain_init(struct domain *d);
@@ -93,6 +97,8 @@ void viridian_synic_load_domain_ctxt(
int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val);
int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val);
+void viridian_time_poll_timers(struct vcpu *v);
+
int viridian_time_vcpu_init(struct vcpu *v);
int viridian_time_domain_init(struct domain *d);
diff --git a/xen/arch/x86/hvm/viridian/synic.c
b/xen/arch/x86/hvm/viridian/synic.c
index a754fa6336..edb5aa38ba 100644
--- a/xen/arch/x86/hvm/viridian/synic.c
+++ b/xen/arch/x86/hvm/viridian/synic.c
@@ -329,7 +329,53 @@ void viridian_synic_domain_deinit(struct domain *d)
void viridian_synic_poll_messages(struct vcpu *v)
{
- /* There are currently no message sources */
+ viridian_time_poll_timers(v);
+}
+
+bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx,
+ unsigned int index,
+ int64_t expiration, int64_t delivery)
+{
+ const union viridian_sint_msr *vs = &v->arch.hvm.viridian->sint[sintx];
+ HV_MESSAGE *msg = v->arch.hvm.viridian->simp.ptr;
+ struct {
+ uint32_t TimerIndex;
+ uint32_t Reserved;
+ uint64_t ExpirationTime;
+ uint64_t DeliveryTime;
+ } payload = {
+ .TimerIndex = index,
+ .ExpirationTime = expiration,
+ .DeliveryTime = delivery,
+ };
+
+ if ( test_bit(sintx, &v->arch.hvm.viridian->msg_pending) )
+ return false;
+
+ BUILD_BUG_ON(sizeof(*msg) != HV_MESSAGE_SIZE);
+ msg += sintx;
+
+ /*
+ * To avoid using an atomic test-and-set this function must be called
+ * in context of the vcpu receiving the message.
+ */
+ ASSERT(v == current);
+ if ( msg->Header.MessageType != HvMessageTypeNone )
+ {
+ msg->Header.MessageFlags.MessagePending = 1;
+ set_bit(sintx, &v->arch.hvm.viridian->msg_pending);
+ return false;
+ }
+
+ msg->Header.MessageType = HvMessageTimerExpired;
+ msg->Header.MessageFlags.MessagePending = 0;
+ msg->Header.PayloadSize = sizeof(payload);
+ memcpy(msg->Payload, &payload, sizeof(payload));
+
+ if ( !vs->fields.mask )
+ vlapic_set_irq(vcpu_vlapic(v), vs->fields.vector, 0);
+
+ return true;
}
bool viridian_synic_is_auto_eoi_sint(struct vcpu *v, uint8_t vector)
diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c
index cb7162c2d4..b2fe152038 100644
--- a/xen/arch/x86/hvm/viridian/time.c
+++ b/xen/arch/x86/hvm/viridian/time.c
@@ -12,6 +12,7 @@
#include <xen/version.h>
#include <asm/apic.h>
+#include <asm/event.h>
#include <asm/hvm/support.h>
#include "private.h"
@@ -118,14 +119,237 @@ static int64_t time_ref_count(struct domain *d)
return raw_trc_val(d) + trc->off;
}
+static int64_t time_now(struct domain *d)
+{
+ const struct viridian_page *rt = &d->arch.hvm.viridian->reference_tsc;
+ HV_REFERENCE_TSC_PAGE *p = rt->ptr;
+ uint32_t start, end;
+ __int128_t tsc;
+ __int128_t scale;
+ int64_t offset;
+
+ /*
+ * If the reference TSC page is not enabled, or has been invalidated
+ * fall back to the partition reference counter.
+ */
+ if ( !p || !p->TscSequence )
+ return time_ref_count(d);
+
+ /*
+ * The following sampling algorithm for tsc, scale and offset is
+ * documented in the specifiction.
+ */
+ start = p->TscSequence;
+
+ do {
+ tsc = rdtsc();
+ scale = p->TscScale;
+ offset = p->TscOffset;
+
+ smp_mb();
+ end = p->TscSequence;
+ } while (end != start);
+
+ /*
+ * The specification says: "The partition reference time is computed
+ * by the following formula:
+ *
+ * ReferenceTime = ((VirtualTsc * TscScale) >> 64) + TscOffset
+ *
+ * The multiplication is a 64 bit multiplication, which results in a
+ * 128 bit number which is then shifted 64 times to the right to obtain
+ * the high 64 bits."
+ */
+ return ((tsc * scale) >> 64) + offset;
+}
+
+static void stop_stimer(struct viridian_stimer *vs)
+{
+ struct vcpu *v = vs->v;
+ unsigned int stimerx = vs - &v->arch.hvm.viridian->stimer[0];
+
+ if ( !vs->started )
+ return;
+
+ stop_timer(&vs->timer);
+ clear_bit(stimerx, &v->arch.hvm.viridian->stimer_pending);
+ vs->started = false;
+}
+
+static void stimer_expire(void *data)
+{
+ struct viridian_stimer *vs = data;
+ struct vcpu *v = vs->v;
+ unsigned int stimerx = vs - &v->arch.hvm.viridian->stimer[0];
+
+ if ( !vs->config.fields.enabled )
+ return;
+
+ set_bit(stimerx, &v->arch.hvm.viridian->stimer_pending);
+ vcpu_kick(v);
+}
+
+static void start_stimer(struct viridian_stimer *vs)
+{
+ struct vcpu *v = vs->v;
+ unsigned int stimerx = vs - &v->arch.hvm.viridian->stimer[0];
+ int64_t now = time_now(v->domain);
+ s_time_t timeout;
+
+ if ( !test_and_set_bit(stimerx, &v->arch.hvm.viridian->stimer_enabled) )
+ printk(XENLOG_G_INFO "%pv: VIRIDIAN STIMER%u: enabled\n", v,
+ stimerx);
+
+ if ( vs->config.fields.periodic )
+ {
+ unsigned int missed = 0;
+ int64_t next;
+
+ /*
+ * The specification says that if the timer is lazy then we
+ * skip over any missed expirations so we can treat this case
+ * as the same as if the timer is currently stopped, i.e. we
+ * just schedule expiration to be 'count' ticks from now.
+ */
+ if ( !vs->started || vs->config.fields.lazy )
+ {
+ next = now + vs->count;
+ }
+ else
+ {
+ /*
+ * The timer is already started, so we're re-scheduling.
+ * Hence advance the timer expiration by one tick.
+ */
+ next = vs->expiration + vs->count;
+
+ /* Now check to see if any expirations have been missed */
+ if ( now - next > 0 )
+ missed = (now - next) / vs->count;
+
+ /*
+ * The specification says that if the timer is not lazy then
+ * a non-zero missed count should be used to reduce the period
+ * of the timer until it catches up, unless the count has
+ * reached a 'significant number', in which case the timer
+ * should be treated as lazy. Unfortunately the specification
+ * does not state what that number is so the choice of number
+ * here is a pure guess.
+ */
+ if ( missed > 3 )
+ {
+ missed = 0;
+ next = now + vs->count;
+ }
+ }
+
+ vs->expiration = next;
+ timeout = ((next - now) * 100ull) / (missed + 1);
+ }
+ else
+ {
+ vs->expiration = vs->count;
+ if ( vs->count - now <= 0 )
+ {
+ set_bit(stimerx, &v->arch.hvm.viridian->stimer_pending);
+ return;
+ }
+
+ timeout = (vs->expiration - now) * 100ull;
+ }
+
+ vs->started = true;
+ migrate_timer(&vs->timer, smp_processor_id());
+ set_timer(&vs->timer, timeout + NOW());
+}
+
+static void poll_stimer(struct vcpu *v, unsigned int stimerx)
+{
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[stimerx];
+
+ if ( !test_bit(stimerx, &v->arch.hvm.viridian->stimer_pending) )
+ return;
+
+ if ( !viridian_synic_deliver_timer_msg(v, vs->config.fields.sintx,
+ stimerx, vs->expiration,
+ time_now(v->domain)) )
+ return;
+
+ clear_bit(stimerx, &v->arch.hvm.viridian->stimer_pending);
+
+ if ( vs->config.fields.periodic )
+ start_stimer(vs);
+ else
+ vs->config.fields.enabled = 0;
+}
+
+void viridian_time_poll_timers(struct vcpu *v)
+{
+ unsigned int i;
+
+ if ( !v->arch.hvm.viridian->stimer_pending )
+ return;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ poll_stimer(v, i);
+}
+
+void viridian_time_vcpu_freeze(struct vcpu *v)
+{
+ unsigned int i;
+
+ if ( !is_viridian_vcpu(v) )
+ return;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ if ( vs->started )
+ stop_timer(&vs->timer);
+ }
+}
+
+void viridian_time_vcpu_thaw(struct vcpu *v)
+{
+ unsigned int i;
+
+ if ( !is_viridian_vcpu(v) )
+ return;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ if ( vs->config.fields.enabled )
+ start_stimer(vs);
+ }
+}
+
void viridian_time_domain_freeze(struct domain *d)
{
+ struct vcpu *v;
+
+ if ( !is_viridian_domain(d) )
+ return;
+
+ for_each_vcpu ( d, v )
+ viridian_time_vcpu_freeze(v);
+
time_ref_count_freeze(d);
}
void viridian_time_domain_thaw(struct domain *d)
{
+ struct vcpu *v;
+
+ if ( !is_viridian_domain(d) )
+ return;
+
time_ref_count_thaw(d);
+
+ for_each_vcpu ( d, v )
+ viridian_time_vcpu_thaw(v);
}
int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val)
@@ -149,6 +373,57 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx,
uint64_t val)
}
break;
+ case HV_X64_MSR_TIME_REF_COUNT:
+ return X86EMUL_EXCEPTION;
+
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER3_CONFIG:
+ {
+ unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[stimerx];
+
+ if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
+ return X86EMUL_EXCEPTION;
+
+ stop_stimer(vs);
+
+ vs->config.raw = val;
+
+ if ( !vs->config.fields.sintx )
+ vs->config.fields.enabled = 0;
+
+ if ( vs->config.fields.enabled )
+ start_stimer(vs);
+
+ break;
+ }
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_COUNT:
+ {
+ unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_COUNT) / 2;
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[stimerx];
+
+ if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
+ return X86EMUL_EXCEPTION;
+
+ stop_stimer(vs);
+
+ vs->count = val;
+
+ if ( !vs->count )
+ vs->config.fields.enabled = 0;
+ else if ( vs->config.fields.auto_enable )
+ vs->config.fields.enabled = 1;
+
+ if ( vs->config.fields.enabled )
+ start_stimer(vs);
+
+ break;
+ }
default:
gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x (%016"PRIx64")\n",
__func__, idx, val);
@@ -201,6 +476,32 @@ int viridian_time_rdmsr(const struct vcpu *v, uint32_t
idx, uint64_t *val)
break;
}
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER3_CONFIG:
+ {
+ unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
+
+ if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
+ return X86EMUL_EXCEPTION;
+
+ *val = v->arch.hvm.viridian->stimer[stimerx].config.raw;
+ break;
+ }
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_COUNT:
+ {
+ unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_COUNT) / 2;
+
+ if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
+ return X86EMUL_EXCEPTION;
+
+ *val = v->arch.hvm.viridian->stimer[stimerx].count;
+ break;
+ }
default:
gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x\n", __func__, idx);
return X86EMUL_EXCEPTION;
@@ -211,6 +512,16 @@ int viridian_time_rdmsr(const struct vcpu *v, uint32_t
idx, uint64_t *val)
int viridian_time_vcpu_init(struct vcpu *v)
{
+ unsigned int i;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ vs->v = v;
+ init_timer(&vs->timer, stimer_expire, vs, v->processor);
+ }
+
return 0;
}
@@ -221,6 +532,15 @@ int viridian_time_domain_init(struct domain *d)
void viridian_time_vcpu_deinit(struct vcpu *v)
{
+ unsigned int i;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ kill_timer(&vs->timer);
+ vs->v = NULL;
+ }
}
void viridian_time_domain_deinit(struct domain *d)
@@ -231,11 +551,34 @@ void viridian_time_domain_deinit(struct domain *d)
void viridian_time_save_vcpu_ctxt(
const struct vcpu *v, struct hvm_viridian_vcpu_context *ctxt)
{
+ unsigned int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(v->arch.hvm.viridian->stimer) !=
+ ARRAY_SIZE(ctxt->stimer_config_msr));
+ BUILD_BUG_ON(ARRAY_SIZE(v->arch.hvm.viridian->stimer) !=
+ ARRAY_SIZE(ctxt->stimer_count_msr));
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ ctxt->stimer_config_msr[i] = vs->config.raw;
+ ctxt->stimer_count_msr[i] = vs->count;
+ }
}
void viridian_time_load_vcpu_ctxt(
struct vcpu *v, const struct hvm_viridian_vcpu_context *ctxt)
{
+ unsigned int i;
+
+ for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ )
+ {
+ struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i];
+
+ vs->config.raw = ctxt->stimer_config_msr[i];
+ vs->count = ctxt->stimer_count_msr[i];
+ }
}
void viridian_time_save_domain_ctxt(
diff --git a/xen/arch/x86/hvm/viridian/viridian.c
b/xen/arch/x86/hvm/viridian/viridian.c
index 8d8cf3a37d..bca544aced 100644
--- a/xen/arch/x86/hvm/viridian/viridian.c
+++ b/xen/arch/x86/hvm/viridian/viridian.c
@@ -180,6 +180,8 @@ void cpuid_viridian_leaves(const struct vcpu *v, uint32_t
leaf,
mask.AccessPartitionReferenceTsc = 1;
if ( viridian_feature_mask(d) & HVMPV_synic )
mask.AccessSynicRegs = 1;
+ if ( viridian_feature_mask(d) & HVMPV_stimer )
+ mask.AccessSyntheticTimerRegs = 1;
u.mask = mask;
@@ -322,6 +324,15 @@ int guest_wrmsr_viridian(struct vcpu *v, uint32_t idx,
uint64_t val)
case HV_X64_MSR_TSC_FREQUENCY:
case HV_X64_MSR_APIC_FREQUENCY:
case HV_X64_MSR_REFERENCE_TSC:
+ case HV_X64_MSR_TIME_REF_COUNT:
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_CONFIG:
+ case HV_X64_MSR_STIMER3_COUNT:
return viridian_time_wrmsr(v, idx, val);
case HV_X64_MSR_CRASH_P0:
@@ -404,6 +415,14 @@ int guest_rdmsr_viridian(const struct vcpu *v, uint32_t
idx, uint64_t *val)
case HV_X64_MSR_APIC_FREQUENCY:
case HV_X64_MSR_REFERENCE_TSC:
case HV_X64_MSR_TIME_REF_COUNT:
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_CONFIG:
+ case HV_X64_MSR_STIMER3_COUNT:
return viridian_time_rdmsr(v, idx, val);
case HV_X64_MSR_CRASH_P0:
diff --git a/xen/include/asm-x86/hvm/viridian.h
b/xen/include/asm-x86/hvm/viridian.h
index 9a493cf048..32da65a064 100644
--- a/xen/include/asm-x86/hvm/viridian.h
+++ b/xen/include/asm-x86/hvm/viridian.h
@@ -40,6 +40,33 @@ union viridian_sint_msr
} fields;
};
+union viridian_stimer_config_msr
+{
+ uint64_t raw;
+ struct
+ {
+ uint64_t enabled:1;
+ uint64_t periodic:1;
+ uint64_t lazy:1;
+ uint64_t auto_enable:1;
+ uint64_t vector:8;
+ uint64_t direct_mode:1;
+ uint64_t reserved_zero1:3;
+ uint64_t sintx:4;
+ uint64_t reserved_zero2:44;
+ } fields;
+};
+
+struct viridian_stimer {
+ struct vcpu *v;
+ struct timer timer;
+ union viridian_stimer_config_msr config;
+ uint64_t count;
+ int64_t expiration;
+ s_time_t timeout;
+ bool started;
+};
+
struct viridian_vcpu
{
struct viridian_page vp_assist;
@@ -50,6 +77,9 @@ struct viridian_vcpu
union viridian_sint_msr sint[16];
uint8_t vector_to_sintx[256];
unsigned long msg_pending;
+ struct viridian_stimer stimer[4];
+ unsigned long stimer_enabled;
+ unsigned long stimer_pending;
uint64_t crash_param[5];
};
diff --git a/xen/include/public/arch-x86/hvm/save.h
b/xen/include/public/arch-x86/hvm/save.h
index ec3e4df12c..8344aa471f 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -604,6 +604,8 @@ struct hvm_viridian_vcpu_context {
uint8_t _pad[7];
uint64_t simp_msr;
uint64_t sint_msr[16];
+ uint64_t stimer_config_msr[4];
+ uint64_t stimer_count_msr[4];
};
DECLARE_HVM_SAVE_TYPE(VIRIDIAN_VCPU, 17, struct hvm_viridian_vcpu_context);
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index e7e3c7c892..e06b0942d0 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -150,6 +150,10 @@
#define _HVMPV_synic 7
#define HVMPV_synic (1 << _HVMPV_synic)
+/* Enable STIMER MSRs */
+#define _HVMPV_stimer 8
+#define HVMPV_stimer (1 << _HVMPV_stimer)
+
#define HVMPV_feature_mask \
(HVMPV_base_freq | \
HVMPV_no_freq | \
@@ -158,7 +162,8 @@
HVMPV_hcall_remote_tlb_flush | \
HVMPV_apic_assist | \
HVMPV_crash_ctl | \
- HVMPV_synic)
+ HVMPV_synic | \
+ HVMPV_stimer)
#endif
--
2.20.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |