[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 01/25] x86/cpuid: Introduce guest_cpuid() and struct cpuid_leaf
Longterm, pv_cpuid() and hvm_cpuid() will be merged into a single guest_cpuid(), which is also capable of working outside of current context. To aid this transtion, introduce guest_cpuid() with the intended API, which simply defers back to pv_cpuid() or hvm_cpuid() as appropriate. Introduce struct cpuid_leaf which is used to represent the results of a CPUID query in a more efficient mannor than passing four pointers through the calltree. Update all codepaths which should use the new guest_cpuid() API. These are the codepaths which have variable inputs, and (other than some specific x86_emulate() cases) all pertain to servicing a CPUID instruction from a guest. The other codepaths using {pv,hvm}_cpuid() with fixed inputs will later be adjusted to read their data straight from the policy block. No intended functional change. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> CC: Paul Durrant <paul.durrant@xxxxxxxxxx> CC: Jun Nakajima <jun.nakajima@xxxxxxxxx> CC: Kevin Tian <kevin.tian@xxxxxxxxx> CC: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx> CC: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> --- v2: * Rename res to cpuid_leaf in x86_emulate(), and make common to functions. * Return lost const and newline in pv_emul_cpuid(). * Extra brackets around EMPTY_LEAF. * Consistently use uint32_t. * Tweak {hvm,pv}_cpuid() dispatch logic for a reduced delta later in the series. --- tools/tests/x86_emulator/x86_emulate.c | 15 ++++----- tools/tests/x86_emulator/x86_emulate.h | 60 ++++++++++++++++------------------ xen/arch/x86/cpuid.c | 36 ++++++++++++++++++++ xen/arch/x86/hvm/emulate.c | 10 ++---- xen/arch/x86/hvm/svm/svm.c | 23 ++++++------- xen/arch/x86/hvm/vmx/vmx.c | 35 ++++++-------------- xen/arch/x86/traps.c | 25 +++++++------- xen/arch/x86/x86_emulate/x86_emulate.c | 34 +++++++++---------- xen/arch/x86/x86_emulate/x86_emulate.h | 12 ++++--- xen/include/asm-x86/cpuid.h | 4 +++ xen/include/asm-x86/hvm/emulate.h | 8 ++--- xen/include/asm-x86/mm.h | 4 +-- 12 files changed, 137 insertions(+), 129 deletions(-) diff --git a/tools/tests/x86_emulator/x86_emulate.c b/tools/tests/x86_emulator/x86_emulate.c index d48f78a..2e8dfbf 100644 --- a/tools/tests/x86_emulator/x86_emulate.c +++ b/tools/tests/x86_emulator/x86_emulate.c @@ -41,22 +41,21 @@ bool emul_test_make_stack_executable(void) } int emul_test_cpuid( - unsigned int *eax, - unsigned int *ebx, - unsigned int *ecx, - unsigned int *edx, + uint32_t leaf, + uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt) { - unsigned int leaf = *eax; - - asm ("cpuid" : "+a" (*eax), "+c" (*ecx), "=d" (*edx), "=b" (*ebx)); + asm ("cpuid" + : "=a" (res->a), "=b" (res->b), "=c" (res->c), "=d" (res->d) + : "a" (leaf), "c" (subleaf)); /* * The emulator doesn't itself use MOVBE, so we can always run the * respective tests. */ if ( leaf == 1 ) - *ecx |= 1U << 22; + res->c |= 1U << 22; return X86EMUL_OKAY; } diff --git a/tools/tests/x86_emulator/x86_emulate.h b/tools/tests/x86_emulator/x86_emulate.h index c14c613..8bc2e43 100644 --- a/tools/tests/x86_emulator/x86_emulate.h +++ b/tools/tests/x86_emulator/x86_emulate.h @@ -58,61 +58,59 @@ static inline uint64_t xgetbv(uint32_t xcr) } #define cache_line_size() ({ \ - unsigned int eax = 1, ebx, ecx = 0, edx; \ - emul_test_cpuid(&eax, &ebx, &ecx, &edx, NULL); \ - edx & (1U << 19) ? (ebx >> 5) & 0x7f8 : 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + res.d & (1U << 19) ? (res.b >> 5) & 0x7f8 : 0; \ }) #define cpu_has_mmx ({ \ - unsigned int eax = 1, ecx = 0, edx; \ - emul_test_cpuid(&eax, &ecx, &ecx, &edx, NULL); \ - (edx & (1U << 23)) != 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + (res.d & (1U << 23)) != 0; \ }) #define cpu_has_sse ({ \ - unsigned int eax = 1, ecx = 0, edx; \ - emul_test_cpuid(&eax, &ecx, &ecx, &edx, NULL); \ - (edx & (1U << 25)) != 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + (res.d & (1U << 25)) != 0; \ }) #define cpu_has_sse2 ({ \ - unsigned int eax = 1, ecx = 0, edx; \ - emul_test_cpuid(&eax, &ecx, &ecx, &edx, NULL); \ - (edx & (1U << 26)) != 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + (res.d & (1U << 26)) != 0; \ }) #define cpu_has_xsave ({ \ - unsigned int eax = 1, ecx = 0; \ - emul_test_cpuid(&eax, &eax, &ecx, &eax, NULL); \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ /* Intentionally checking OSXSAVE here. */ \ - (ecx & (1U << 27)) != 0; \ + (res.c & (1U << 27)) != 0; \ }) #define cpu_has_avx ({ \ - unsigned int eax = 1, ecx = 0; \ - emul_test_cpuid(&eax, &eax, &ecx, &eax, NULL); \ - if ( !(ecx & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \ - ecx = 0; \ - (ecx & (1U << 28)) != 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + if ( !(res.c & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \ + res.c = 0; \ + (res.c & (1U << 28)) != 0; \ }) #define cpu_has_avx2 ({ \ - unsigned int eax = 1, ebx, ecx = 0; \ - emul_test_cpuid(&eax, &ebx, &ecx, &eax, NULL); \ - if ( !(ecx & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \ - ebx = 0; \ + struct cpuid_leaf res; \ + emul_test_cpuid(1, 0, &res, NULL); \ + if ( !(res.c & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \ + res.b = 0; \ else { \ - eax = 7, ecx = 0; \ - emul_test_cpuid(&eax, &ebx, &ecx, &eax, NULL); \ + emul_test_cpuid(7, 0, &res, NULL); \ } \ - (ebx & (1U << 5)) != 0; \ + (res.b & (1U << 5)) != 0; \ }) int emul_test_cpuid( - unsigned int *eax, - unsigned int *ebx, - unsigned int *ecx, - unsigned int *edx, + uint32_t leaf, + uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt); int emul_test_read_cr( diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 3e85a63..f3491ed 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -1,5 +1,6 @@ #include <xen/init.h> #include <xen/lib.h> +#include <xen/sched.h> #include <asm/cpuid.h> #include <asm/hvm/hvm.h> #include <asm/hvm/vmx/vmcs.h> @@ -17,6 +18,8 @@ uint32_t __read_mostly raw_featureset[FSCAPINTS]; uint32_t __read_mostly pv_featureset[FSCAPINTS]; uint32_t __read_mostly hvm_featureset[FSCAPINTS]; +#define EMPTY_LEAF ((struct cpuid_leaf){}) + static void __init sanitise_featureset(uint32_t *fs) { /* for_each_set_bit() uses unsigned longs. Extend with zeroes. */ @@ -215,6 +218,39 @@ const uint32_t * __init lookup_deep_deps(uint32_t feature) return NULL; } +void guest_cpuid(const struct vcpu *v, uint32_t leaf, + uint32_t subleaf, struct cpuid_leaf *res) +{ + const struct vcpu *curr = current; + const struct domain *d = v->domain; + + *res = EMPTY_LEAF; + + /* {hvm,pv}_cpuid() have this expectation. */ + ASSERT(v == curr); + + if ( is_hvm_domain(d) ) + { + res->c = subleaf; + + hvm_cpuid(leaf, &res->a, &res->b, &res->c, &res->d); + } + else + { + struct cpu_user_regs regs = *guest_cpu_user_regs(); + + regs._eax = leaf; + regs._ecx = subleaf; + + pv_cpuid(®s); + + res->a = regs._eax; + res->b = regs._ebx; + res->c = regs._ecx; + res->d = regs._edx; + } +} + static void __init __maybe_unused build_assertions(void) { BUILD_BUG_ON(ARRAY_SIZE(known_features) != FSCAPINTS); diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 41bd4f5..ecbac4b 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1552,12 +1552,8 @@ static int hvmemul_wbinvd( return X86EMUL_OKAY; } -int hvmemul_cpuid( - unsigned int *eax, - unsigned int *ebx, - unsigned int *ecx, - unsigned int *edx, - struct x86_emulate_ctxt *ctxt) +int hvmemul_cpuid(uint32_t leaf, uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt) { /* * x86_emulate uses this function to query CPU features for its own internal @@ -1568,7 +1564,7 @@ int hvmemul_cpuid( hvm_check_cpuid_faulting(current) ) return X86EMUL_EXCEPTION; - hvm_cpuid(*eax, eax, ebx, ecx, edx); + guest_cpuid(current, leaf, subleaf, res); return X86EMUL_OKAY; } diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 04a7b60..6fb1cbc 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1572,23 +1572,20 @@ static void svm_fpu_dirty_intercept(void) static void svm_vmexit_do_cpuid(struct cpu_user_regs *regs) { - unsigned int eax, ebx, ecx, edx, inst_len; + struct vcpu *curr = current; + unsigned int inst_len; + struct cpuid_leaf res; - if ( (inst_len = __get_instruction_length(current, INSTR_CPUID)) == 0 ) + if ( (inst_len = __get_instruction_length(curr, INSTR_CPUID)) == 0 ) return; - eax = regs->_eax; - ebx = regs->_ebx; - ecx = regs->_ecx; - edx = regs->_edx; - - hvm_cpuid(regs->_eax, &eax, &ebx, &ecx, &edx); - HVMTRACE_5D(CPUID, regs->_eax, eax, ebx, ecx, edx); + guest_cpuid(curr, regs->_eax, regs->_ecx, &res); + HVMTRACE_5D(CPUID, regs->_eax, res.a, res.b, res.c, res.d); - regs->rax = eax; - regs->rbx = ebx; - regs->rcx = ecx; - regs->rdx = edx; + regs->rax = res.a; + regs->rbx = res.b; + regs->rcx = res.c; + regs->rdx = res.d; __update_guest_eip(regs, inst_len); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index e75b190..01c225f 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2361,8 +2361,9 @@ static void vmx_fpu_dirty_intercept(void) static int vmx_do_cpuid(struct cpu_user_regs *regs) { - unsigned int eax, ebx, ecx, edx; - unsigned int leaf, subleaf; + struct vcpu *curr = current; + unsigned int leaf = regs->_eax, subleaf = regs->_ecx; + struct cpuid_leaf res; if ( hvm_check_cpuid_faulting(current) ) { @@ -2370,21 +2371,13 @@ static int vmx_do_cpuid(struct cpu_user_regs *regs) return 1; /* Don't advance the guest IP! */ } - eax = regs->_eax; - ebx = regs->_ebx; - ecx = regs->_ecx; - edx = regs->_edx; - - leaf = regs->_eax; - subleaf = regs->_ecx; + guest_cpuid(curr, leaf, subleaf, &res); + HVMTRACE_5D(CPUID, leaf, res.a, res.b, res.c, res.d); - hvm_cpuid(leaf, &eax, &ebx, &ecx, &edx); - HVMTRACE_5D(CPUID, leaf, eax, ebx, ecx, edx); - - regs->rax = eax; - regs->rbx = ebx; - regs->rcx = ecx; - regs->rdx = edx; + regs->rax = res.a; + regs->rbx = res.b; + regs->rcx = res.c; + regs->rdx = res.d; return hvm_monitor_cpuid(get_instruction_length(), leaf, subleaf); } @@ -3559,15 +3552,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) } case EXIT_REASON_CPUID: { - int rc; - - if ( is_pvh_vcpu(v) ) - { - pv_cpuid(regs); - rc = 0; - } - else - rc = vmx_do_cpuid(regs); + int rc = vmx_do_cpuid(regs); /* * rc < 0 error in monitor/vm_event, crash diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index e45ff71..3acc244 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1412,6 +1412,7 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) { char sig[5], instr[2]; unsigned long eip, rc; + struct cpuid_leaf res; eip = regs->rip; @@ -1444,7 +1445,12 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) eip += sizeof(instr); - pv_cpuid(regs); + guest_cpuid(current, regs->_eax, regs->_ecx, &res); + + regs->rax = res.a; + regs->rbx = res.b; + regs->rcx = res.c; + regs->rdx = res.d; instruction_done(regs, eip); @@ -3254,10 +3260,10 @@ static int priv_op_wbinvd(struct x86_emulate_ctxt *ctxt) return X86EMUL_OKAY; } -int pv_emul_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, - unsigned int *edx, struct x86_emulate_ctxt *ctxt) +int pv_emul_cpuid(uint32_t leaf, uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt) { - struct cpu_user_regs regs = *ctxt->regs; + const struct vcpu *curr = current; /* * x86_emulate uses this function to query CPU features for its own @@ -3266,7 +3272,6 @@ int pv_emul_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, */ if ( ctxt->opcode == X86EMUL_OPC(0x0f, 0xa2) ) { - const struct vcpu *curr = current; /* If cpuid faulting is enabled and CPL>0 leave the #GP untouched. */ if ( curr->arch.cpuid_faulting && @@ -3274,15 +3279,7 @@ int pv_emul_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, return X86EMUL_EXCEPTION; } - regs._eax = *eax; - regs._ecx = *ecx; - - pv_cpuid(®s); - - *eax = regs._eax; - *ebx = regs._ebx; - *ecx = regs._ecx; - *edx = regs._edx; + guest_cpuid(curr, leaf, subleaf, res); return X86EMUL_OKAY; } diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 98ba7c5..3dbc3ce 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1265,19 +1265,19 @@ static bool vcpu_has( struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { - unsigned int ebx = 0, ecx = 0, edx = 0; + struct cpuid_leaf res; int rc = X86EMUL_OKAY; fail_if(!ops->cpuid); - rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt); + rc = ops->cpuid(eax, 0, &res, ctxt); if ( rc == X86EMUL_OKAY ) { switch ( reg ) { - case EAX: reg = eax; break; - case EBX: reg = ebx; break; - case ECX: reg = ecx; break; - case EDX: reg = edx; break; + case EAX: reg = res.a; break; + case EBX: reg = res.b; break; + case ECX: reg = res.c; break; + case EDX: reg = res.d; break; default: BUG(); } if ( !(reg & (1U << bit)) ) @@ -2722,6 +2722,7 @@ x86_emulate( { enum x86_segment seg; struct segment_register cs, sreg; + struct cpuid_leaf cpuid_leaf; case 0x00 ... 0x05: add: /* add */ emulate_2op_SrcV("add", src, dst, _regs._eflags); @@ -4525,15 +4526,14 @@ x86_emulate( case 0xfc: /* clzero */ { - unsigned int eax = 1, ebx = 0, dummy = 0; unsigned long zero = 0; base = ad_bytes == 8 ? _regs.r(ax) : ad_bytes == 4 ? _regs._eax : _regs.ax; limit = 0; if ( vcpu_has_clflush() && - ops->cpuid(&eax, &ebx, &dummy, &dummy, ctxt) == X86EMUL_OKAY ) - limit = ((ebx >> 8) & 0xff) * 8; + ops->cpuid(1, 0, &cpuid_leaf, ctxt) == X86EMUL_OKAY ) + limit = ((cpuid_leaf.b >> 8) & 0xff) * 8; generate_exception_if(limit < sizeof(long) || (limit & (limit - 1)), EXC_UD); base &= ~(limit - 1); @@ -5265,22 +5265,18 @@ x86_emulate( dst.val = test_cc(b, _regs._eflags); break; - case X86EMUL_OPC(0x0f, 0xa2): /* cpuid */ { - unsigned int eax = _regs._eax, ebx = _regs._ebx; - unsigned int ecx = _regs._ecx, edx = _regs._edx; - + case X86EMUL_OPC(0x0f, 0xa2): /* cpuid */ fail_if(ops->cpuid == NULL); - rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt); + rc = ops->cpuid(_regs._eax, _regs._ecx, &cpuid_leaf, ctxt); generate_exception_if(rc == X86EMUL_EXCEPTION, EXC_GP, 0); /* CPUID Faulting? */ if ( rc != X86EMUL_OKAY ) goto done; - _regs.r(ax) = eax; - _regs.r(bx) = ebx; - _regs.r(cx) = ecx; - _regs.r(dx) = edx; + _regs.r(ax) = cpuid_leaf.a; + _regs.r(bx) = cpuid_leaf.b; + _regs.r(cx) = cpuid_leaf.c; + _regs.r(dx) = cpuid_leaf.d; break; - } case X86EMUL_OPC(0x0f, 0xa3): bt: /* bt */ emulate_2op_SrcV_nobyte("bt", src, dst, _regs._eflags); diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h index 43c0c5e..57ebfde 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -164,6 +164,11 @@ enum x86_emulate_fpu_type { X86EMUL_FPU_ymm /* AVX/XOP instruction set (%ymm0-%ymm7/15) */ }; +struct cpuid_leaf +{ + uint32_t a, b, c, d; +}; + struct x86_emulate_state; /* @@ -415,10 +420,9 @@ struct x86_emulate_ops * #GP[0]. Used to implement CPUID faulting. */ int (*cpuid)( - unsigned int *eax, - unsigned int *ebx, - unsigned int *ecx, - unsigned int *edx, + uint32_t leaf, + uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt); /* diff --git a/xen/include/asm-x86/cpuid.h b/xen/include/asm-x86/cpuid.h index 05f2c9a..4586c7d 100644 --- a/xen/include/asm-x86/cpuid.h +++ b/xen/include/asm-x86/cpuid.h @@ -17,6 +17,7 @@ #ifndef __ASSEMBLY__ #include <xen/types.h> +#include <asm/x86_emulate.h> #include <public/sysctl.h> extern const uint32_t known_features[FSCAPINTS]; @@ -64,6 +65,9 @@ extern struct cpuidmasks cpuidmask_defaults; /* Whether or not cpuid faulting is available for the current domain. */ DECLARE_PER_CPU(bool, cpuid_faulting_enabled); +void guest_cpuid(const struct vcpu *v, uint32_t leaf, + uint32_t subleaf, struct cpuid_leaf *res); + #endif /* __ASSEMBLY__ */ #endif /* !__X86_CPUID_H__ */ diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h index 68a95e4..83266bb 100644 --- a/xen/include/asm-x86/hvm/emulate.h +++ b/xen/include/asm-x86/hvm/emulate.h @@ -57,12 +57,8 @@ void hvm_emulate_init_per_insn( unsigned int insn_bytes); void hvm_emulate_writeback( struct hvm_emulate_ctxt *hvmemul_ctxt); -int hvmemul_cpuid( - unsigned int *eax, - unsigned int *ebx, - unsigned int *ecx, - unsigned int *edx, - struct x86_emulate_ctxt *ctxt); +int hvmemul_cpuid(uint32_t leaf, uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt); struct segment_register *hvmemul_get_seg_reg( enum x86_segment seg, struct hvm_emulate_ctxt *hvmemul_ctxt); diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index a15029c..93a073d 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -504,8 +504,8 @@ extern int mmcfg_intercept_write(enum x86_segment seg, void *p_data, unsigned int bytes, struct x86_emulate_ctxt *ctxt); -int pv_emul_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, - unsigned int *edx, struct x86_emulate_ctxt *ctxt); +int pv_emul_cpuid(uint32_t leaf, uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt); int ptwr_do_page_fault(struct vcpu *, unsigned long, struct cpu_user_regs *); -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |