[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Ping: [PATCH] x86emul: de-duplicate scatters to the same linear address
On 10.11.2020 14:26, Jan Beulich wrote: > The SDM specifically allows for earlier writes to fully overlapping > ranges to be dropped. If a guest did so, hvmemul_phys_mmio_access() > would crash it if varying data was written to the same address. Detect > overlaps early, as doing so in hvmemul_{linear,phys}_mmio_access() would > be quite a bit more difficult. > > Note that due to cache slot use being linear address based, there's no > similar issue with multiple writes to the same physical address (mapped > through different linear addresses). > > Since this requires an adjustment to the EVEX Disp8 scaling test, > correct a comment there at the same time. > > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > --- > TBD: The SDM isn't entirely unambiguous about the faulting behavior in > this case: If a fault would need delivering on the earlier slot > despite the write getting squashed, we'd have to call ops->write() > with size set to zero for the earlier write(s). However, > hvm/emulate.c's handling of zero-byte accesses extends only to the > virtual-to-linear address conversions (and raising of involved > faults), so in order to also observe #PF changes to that logic > would then also be needed. Can we live with a possible misbehavior > here? > > --- a/tools/tests/x86_emulator/evex-disp8.c > +++ b/tools/tests/x86_emulator/evex-disp8.c > @@ -647,8 +647,8 @@ static const uint16_t imm0f[16] = { > static struct x86_emulate_ops emulops; > > /* > - * Access tracking (by granular) is used on the first 64 bytes of address > - * space. Instructions get encode with a raw Disp8 value of 1, which then > + * Access tracking (byte granular) is used on the first bytes of address > + * space. Instructions get encoded with a raw Disp8 value of 1, which then > * gets scaled accordingly. Hence accesses below the address <scaling factor> > * as well as at or above 2 * <scaling factor> are indications of bugs. To > * aid diagnosis / debugging, track all accesses below 3 * <scaling factor>. > @@ -804,6 +804,31 @@ static void test_one(const struct test * > > asm volatile ( "kxnorw %k1, %k1, %k1" ); > asm volatile ( "vxorps %xmm4, %xmm4, %xmm4" ); > + if ( sg && (test->opc | 3) == 0xa3 ) > + { > + /* > + * Non-prefetch scatters need handling specially, due to the > + * overlapped write elimination done by the emulator. The order of > + * indexes chosen is somewhat arbitrary, within the constraints > + * imposed by the various different uses. > + */ > + static const struct { > + int32_t _[16]; > + } off32 = {{ 1, 0, 2, 3, 7, 6, 5, 4, 8, 10, 12, 14, 9, 11, 13, 15 }}; > + > + if ( test->opc & 1 ) > + { > + asm volatile ( "vpmovsxdq %0, %%zmm4" :: "m" (off32) ); > + vsz >>= !evex.w; > + } > + else > + asm volatile ( "vmovdqu32 %0, %%zmm4" :: "m" (off32) ); > + > + /* Scale by element size. */ > + instr[6] |= (evex.w | 2) << 6; > + > + sg = false; > + } > > ctxt->regs->eip = (unsigned long)&instr[0]; > ctxt->regs->edx = 0; > --- a/xen/arch/x86/x86_emulate/x86_emulate.c > +++ b/xen/arch/x86/x86_emulate/x86_emulate.c > @@ -10032,25 +10032,47 @@ x86_emulate( > > for ( i = 0; op_mask; ++i ) > { > - long idx = b & 1 ? index.qw[i] : index.dw[i]; > + long idx = (b & 1 ? index.qw[i] > + : index.dw[i]) * (1 << state->sib_scale); > + unsigned long offs = truncate_ea(ea.mem.off + idx); > + unsigned int j; > > if ( !(op_mask & (1 << i)) ) > continue; > > - rc = ops->write(ea.mem.seg, > - truncate_ea(ea.mem.off + > - idx * (1 << state->sib_scale)), > - (void *)mmvalp + i * op_bytes, op_bytes, ctxt); > - if ( rc != X86EMUL_OKAY ) > + /* > + * hvmemul_linear_mmio_access() will find a cache slot based on > + * linear address. hvmemul_phys_mmio_access() will crash the > + * domain if observing varying data getting written to the same > + * address within a cache slot. Utilize that squashing earlier > + * writes to fully overlapping addresses is permitted by the > spec. > + */ > + for ( j = i + 1; j < n; ++j ) > { > - /* See comment in gather emulation. */ > - if ( rc != X86EMUL_EXCEPTION && done ) > - rc = X86EMUL_RETRY; > - break; > + long idx2 = (b & 1 ? index.qw[j] > + : index.dw[j]) * (1 << state->sib_scale); > + > + if ( (op_mask & (1 << j)) && > + truncate_ea(ea.mem.off + idx2) == offs ) > + break; > + } > + > + if ( j >= n ) > + { > + rc = ops->write(ea.mem.seg, offs, > + (void *)mmvalp + i * op_bytes, op_bytes, > ctxt); > + if ( rc != X86EMUL_OKAY ) > + { > + /* See comment in gather emulation. */ > + if ( rc != X86EMUL_EXCEPTION && done ) > + rc = X86EMUL_RETRY; > + break; > + } > + > + done = true; > } > > op_mask &= ~(1 << i); > - done = true; > > #ifdef __XEN__ > if ( op_mask && local_events_need_delivery() ) >
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |