|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 1/4] x86/guest: Introduce {get,set}_reg() infrastructure
Various registers have per-guest-type or per-vendor locations or access
requirements. To support their use from common code, provide accessors which
allow for per-guest-type behaviour.
For now, just infrastructure handling default cases and expectations.
Subsequent patches will start handling registers using this infrastructure.
Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
CC: Wei Liu <wl@xxxxxxx>
CC: Jun Nakajima <jun.nakajima@xxxxxxxxx>
CC: Kevin Tian <kevin.tian@xxxxxxxxx>
It is deliberately {get,set}_reg() because in the fullness of time, it will
handle more than just MSRs. There's loads of space in the MSR index range
which we can reuse for non-MSRs.
v2:
* New
---
xen/arch/x86/hvm/hvm.c | 22 ++++++++++++++++++++++
xen/arch/x86/hvm/svm/svm.c | 30 ++++++++++++++++++++++++++++++
xen/arch/x86/hvm/vmx/vmx.c | 31 +++++++++++++++++++++++++++++++
xen/arch/x86/include/asm/hvm/hvm.h | 24 ++++++++++++++++++++++++
xen/arch/x86/include/asm/pv/domain.h | 13 +++++++++++++
xen/arch/x86/pv/emulate.c | 31 +++++++++++++++++++++++++++++++
6 files changed, 151 insertions(+)
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 3b87506ac4b3..b530e986e86c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3744,6 +3744,28 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t
msr_content,
return X86EMUL_EXCEPTION;
}
+uint64_t hvm_get_reg(struct vcpu *v, unsigned int reg)
+{
+ ASSERT(v == current || !vcpu_runnable(v));
+
+ switch ( reg )
+ {
+ default:
+ return alternative_call(hvm_funcs.get_reg, v, reg);
+ }
+}
+
+void hvm_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ ASSERT(v == current || !vcpu_runnable(v));
+
+ switch ( reg )
+ {
+ default:
+ return alternative_vcall(hvm_funcs.set_reg, v, reg, val);
+ }
+}
+
static bool is_sysdesc_access(const struct x86_emulate_state *state,
const struct x86_emulate_ctxt *ctxt)
{
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index fae39c4b4cbd..bb6b8e560a9f 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2469,6 +2469,33 @@ static bool svm_get_pending_event(struct vcpu *v, struct
x86_event *info)
return true;
}
+static uint64_t svm_get_reg(struct vcpu *v, unsigned int reg)
+{
+ struct domain *d = v->domain;
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x) Bad register\n",
+ __func__, v, reg);
+ domain_crash(d);
+ return 0;
+ }
+}
+
+static void svm_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ struct domain *d = v->domain;
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x, 0x%016"PRIx64") Bad register\n",
+ __func__, v, reg, val);
+ domain_crash(d);
+ }
+}
+
static struct hvm_function_table __initdata svm_function_table = {
.name = "SVM",
.cpu_up_prepare = svm_cpu_up_prepare,
@@ -2518,6 +2545,9 @@ static struct hvm_function_table __initdata
svm_function_table = {
.nhvm_intr_blocked = nsvm_intr_blocked,
.nhvm_hap_walk_L1_p2m = nsvm_hap_walk_L1_p2m,
+ .get_reg = svm_get_reg,
+ .set_reg = svm_set_reg,
+
.tsc_scaling = {
.max_ratio = ~TSC_RATIO_RSVD_BITS,
},
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index a7a0d662342a..4ff92ab4e94e 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -2404,6 +2404,33 @@ static int vmtrace_reset(struct vcpu *v)
return 0;
}
+static uint64_t vmx_get_reg(struct vcpu *v, unsigned int reg)
+{
+ struct domain *d = v->domain;
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x) Bad register\n",
+ __func__, v, reg);
+ domain_crash(d);
+ return 0;
+ }
+}
+
+static void vmx_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ struct domain *d = v->domain;
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x, 0x%016"PRIx64") Bad register\n",
+ __func__, v, reg, val);
+ domain_crash(d);
+ }
+}
+
static struct hvm_function_table __initdata vmx_function_table = {
.name = "VMX",
.cpu_up_prepare = vmx_cpu_up_prepare,
@@ -2464,6 +2491,10 @@ static struct hvm_function_table __initdata
vmx_function_table = {
.vmtrace_set_option = vmtrace_set_option,
.vmtrace_get_option = vmtrace_get_option,
.vmtrace_reset = vmtrace_reset,
+
+ .get_reg = vmx_get_reg,
+ .set_reg = vmx_set_reg,
+
.tsc_scaling = {
.max_ratio = VMX_TSC_MULTIPLIER_MAX,
},
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h
b/xen/arch/x86/include/asm/hvm/hvm.h
index b26302d9e769..c8b62b514b42 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -223,6 +223,9 @@ struct hvm_function_table {
int (*vmtrace_get_option)(struct vcpu *v, uint64_t key, uint64_t *value);
int (*vmtrace_reset)(struct vcpu *v);
+ uint64_t (*get_reg)(struct vcpu *v, unsigned int reg);
+ void (*set_reg)(struct vcpu *v, unsigned int reg, uint64_t val);
+
/*
* Parameters and callbacks for hardware-assisted TSC scaling,
* which are valid only when the hardware feature is available.
@@ -730,6 +733,18 @@ static inline int hvm_vmtrace_reset(struct vcpu *v)
}
/*
+ * Accessors for registers which have per-guest-type or per-vendor locations
+ * (e.g. VMCS, msr load/save lists, VMCB, VMLOAD lazy, etc).
+ *
+ * The caller is responsible for all auditing - these accessors do not fail,
+ * but do use domain_crash() for usage errors.
+ *
+ * Must cope with being called in non-current context.
+ */
+uint64_t hvm_get_reg(struct vcpu *v, unsigned int reg);
+void hvm_set_reg(struct vcpu *v, unsigned int reg, uint64_t val);
+
+/*
* This must be defined as a macro instead of an inline function,
* because it uses 'struct vcpu' and 'struct domain' which have
* not been defined yet.
@@ -852,6 +867,15 @@ static inline int hvm_vmtrace_get_option(
return -EOPNOTSUPP;
}
+static inline uint64_t pv_get_reg(struct vcpu *v, unsigned int reg)
+{
+ ASSERT_UNREACHABLE();
+}
+static inline void pv_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ ASSERT_UNREACHABLE();
+}
+
#define is_viridian_domain(d) ((void)(d), false)
#define is_viridian_vcpu(v) ((void)(v), false)
#define has_viridian_time_ref_count(d) ((void)(d), false)
diff --git a/xen/arch/x86/include/asm/pv/domain.h
b/xen/arch/x86/include/asm/pv/domain.h
index df9716ff26a8..5fbf4043e0d9 100644
--- a/xen/arch/x86/include/asm/pv/domain.h
+++ b/xen/arch/x86/include/asm/pv/domain.h
@@ -72,6 +72,10 @@ int pv_vcpu_initialise(struct vcpu *v);
void pv_domain_destroy(struct domain *d);
int pv_domain_initialise(struct domain *d);
+/* See hvm_{get,set}_reg() for description. */
+uint64_t pv_get_reg(struct vcpu *v, unsigned int reg);
+void pv_set_reg(struct vcpu *v, unsigned int reg, uint64_t val);
+
/*
* Bits which a PV guest can toggle in its view of cr4. Some are loaded into
* hardware, while some are fully emulated.
@@ -100,6 +104,15 @@ static inline int pv_vcpu_initialise(struct vcpu *v) {
return -EOPNOTSUPP; }
static inline void pv_domain_destroy(struct domain *d) {}
static inline int pv_domain_initialise(struct domain *d) { return -EOPNOTSUPP;
}
+static inline uint64_t pv_get_reg(struct vcpu *v, unsigned int reg)
+{
+ ASSERT_UNREACHABLE();
+}
+static inline void pv_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ ASSERT_UNREACHABLE();
+}
+
static inline unsigned long pv_make_cr4(const struct vcpu *v) { return ~0ul; }
#endif /* CONFIG_PV */
diff --git a/xen/arch/x86/pv/emulate.c b/xen/arch/x86/pv/emulate.c
index e8bb326efdfe..ae049b60f2fc 100644
--- a/xen/arch/x86/pv/emulate.c
+++ b/xen/arch/x86/pv/emulate.c
@@ -90,6 +90,37 @@ void pv_emul_instruction_done(struct cpu_user_regs *regs,
unsigned long rip)
}
}
+uint64_t pv_get_reg(struct vcpu *v, unsigned int reg)
+{
+ struct domain *d = v->domain;
+
+ ASSERT(v == current || !vcpu_runnable(v));
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x) Bad register\n",
+ __func__, v, reg);
+ domain_crash(d);
+ return 0;
+ }
+}
+
+void pv_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
+{
+ struct domain *d = v->domain;
+
+ ASSERT(v == current || !vcpu_runnable(v));
+
+ switch ( reg )
+ {
+ default:
+ printk(XENLOG_G_ERR "%s(%pv, 0x%08x, 0x%016"PRIx64") Bad register\n",
+ __func__, v, reg, val);
+ domain_crash(d);
+ }
+}
+
/*
* Local variables:
* mode: C
--
2.11.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |