diff --git a/xen/arch/x86/mm/shadow/hvm.c b/xen/arch/x86/mm/shadow/hvm.c index c16f3b3adf..114957a3e1 100644 --- a/xen/arch/x86/mm/shadow/hvm.c +++ b/xen/arch/x86/mm/shadow/hvm.c @@ -287,11 +287,29 @@ hvm_emulate_cmpxchg(enum x86_segment seg, return rc; } +static int cf_check +hvm_emulate_read_segment(enum x86_segment seg, + struct segment_register *reg, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + const struct segment_register *sreg = hvm_get_seg_reg(seg, sh_ctxt); + + if ( IS_ERR(sreg) ) + return -PTR_ERR(sreg); + + *reg = *sreg; + + return X86EMUL_OKAY; +} + static const struct x86_emulate_ops hvm_shadow_emulator_ops = { .read = hvm_emulate_read, .insn_fetch = hvm_emulate_insn_fetch, .write = hvm_emulate_write, .cmpxchg = hvm_emulate_cmpxchg, + .read_segment = hvm_emulate_read_segment, }; const struct x86_emulate_ops *shadow_init_emulation( diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 762fc34778..7e12b19805 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -447,14 +447,37 @@ static void put_fpu( if ( state->ea.type == OP_MEM ) { aux.dp = state->ea.mem.off; - if ( ops->read_segment && - ops->read_segment(state->ea.mem.seg, &sreg, - ctxt) == X86EMUL_OKAY ) + if ( state->ea.mem.seg == x86_seg_cs ) + aux.ds = aux.cs; + else if ( ops->read_segment && + ops->read_segment(state->ea.mem.seg, &sreg, + ctxt) == X86EMUL_OKAY ) aux.ds = sreg.sel; +#ifdef __XEN__ + /* + * While generally the expectation is that input structures are + * fully populated, the selector fields under ctxt->regs normally + * aren't set, with the exception of CS and SS for PV domains. + * Read the real selector registers for PV, and assert that HVM + * invocations always set a properly functioning ->read_segment() + * hook. + */ + else if ( is_pv_vcpu(current) ) + switch ( state->ea.mem.seg ) + { + case x86_seg_ds: aux.ds = read_sreg(ds); break; + case x86_seg_es: aux.ds = read_sreg(es); break; + case x86_seg_fs: aux.ds = read_sreg(fs); break; + case x86_seg_gs: aux.ds = read_sreg(gs); break; + case x86_seg_ss: aux.ds = ctxt->regs->ss; break; + default: ASSERT_UNREACHABLE(); break; + } + else + ASSERT_UNREACHABLE(); +#else else switch ( state->ea.mem.seg ) { - case x86_seg_cs: aux.ds = ctxt->regs->cs; break; case x86_seg_ds: aux.ds = ctxt->regs->ds; break; case x86_seg_es: aux.ds = ctxt->regs->es; break; case x86_seg_fs: aux.ds = ctxt->regs->fs; break; @@ -462,6 +485,7 @@ static void put_fpu( case x86_seg_ss: aux.ds = ctxt->regs->ss; break; default: ASSERT_UNREACHABLE(); break; } +#endif aux.dval = true; } ops->put_fpu(ctxt, X86EMUL_FPU_none, &aux);