[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 |