diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 754baf68d5..c236e7da1f 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1089,12 +1089,25 @@ static int linear_read(unsigned long addr, unsigned int bytes, void *p_data, uint32_t pfec, struct hvm_emulate_ctxt *hvmemul_ctxt) { pagefault_info_t pfinfo; - int rc = hvm_copy_from_guest_linear(p_data, addr, bytes, pfec, &pfinfo); + unsigned int offset = addr & ~PAGE_MASK; + int rc; + + if ( offset + bytes > PAGE_SIZE ) + { + unsigned int part1 = PAGE_SIZE - offset; + + /* Split the access at the page boundary. */ + rc = linear_read(addr, part1, p_data, pfec, hvmemul_ctxt); + if ( rc == X86EMUL_OKAY ) + rc = linear_read(addr + part1, bytes - part1, p_data + part1, + pfec, hvmemul_ctxt); + return rc; + } + + rc = hvm_copy_from_guest_linear(p_data, addr, bytes, pfec, &pfinfo); switch ( rc ) { - unsigned int offset, part1; - case HVMTRANS_okay: return X86EMUL_OKAY; @@ -1106,19 +1119,9 @@ static int linear_read(unsigned long addr, unsigned int bytes, void *p_data, if ( pfec & PFEC_insn_fetch ) return X86EMUL_UNHANDLEABLE; - offset = addr & ~PAGE_MASK; - if ( offset + bytes <= PAGE_SIZE ) - return hvmemul_linear_mmio_read(addr, bytes, p_data, pfec, - hvmemul_ctxt, - known_gla(addr, bytes, pfec)); - - /* Split the access at the page boundary. */ - part1 = PAGE_SIZE - offset; - rc = linear_read(addr, part1, p_data, pfec, hvmemul_ctxt); - if ( rc == X86EMUL_OKAY ) - rc = linear_read(addr + part1, bytes - part1, p_data + part1, - pfec, hvmemul_ctxt); - return rc; + return hvmemul_linear_mmio_read(addr, bytes, p_data, pfec, + hvmemul_ctxt, + known_gla(addr, bytes, pfec)); case HVMTRANS_gfn_paged_out: case HVMTRANS_gfn_shared: @@ -1132,12 +1135,25 @@ static int linear_write(unsigned long addr, unsigned int bytes, void *p_data, uint32_t pfec, struct hvm_emulate_ctxt *hvmemul_ctxt) { pagefault_info_t pfinfo; - int rc = hvm_copy_to_guest_linear(addr, p_data, bytes, pfec, &pfinfo); + unsigned int offset = addr & ~PAGE_MASK; + int rc; + + if ( offset + bytes > PAGE_SIZE ) + { + unsigned int part1 = PAGE_SIZE - offset; + + /* Split the access at the page boundary. */ + rc = linear_write(addr, part1, p_data, pfec, hvmemul_ctxt); + if ( rc == X86EMUL_OKAY ) + rc = linear_write(addr + part1, bytes - part1, p_data + part1, + pfec, hvmemul_ctxt); + return rc; + } + + rc = hvm_copy_to_guest_linear(addr, p_data, bytes, pfec, &pfinfo); switch ( rc ) { - unsigned int offset, part1; - case HVMTRANS_okay: return X86EMUL_OKAY; @@ -1146,19 +1162,9 @@ static int linear_write(unsigned long addr, unsigned int bytes, void *p_data, return X86EMUL_EXCEPTION; case HVMTRANS_bad_gfn_to_mfn: - offset = addr & ~PAGE_MASK; - if ( offset + bytes <= PAGE_SIZE ) - return hvmemul_linear_mmio_write(addr, bytes, p_data, pfec, - hvmemul_ctxt, - known_gla(addr, bytes, pfec)); - - /* Split the access at the page boundary. */ - part1 = PAGE_SIZE - offset; - rc = linear_write(addr, part1, p_data, pfec, hvmemul_ctxt); - if ( rc == X86EMUL_OKAY ) - rc = linear_write(addr + part1, bytes - part1, p_data + part1, - pfec, hvmemul_ctxt); - return rc; + return hvmemul_linear_mmio_write(addr, bytes, p_data, pfec, + hvmemul_ctxt, + known_gla(addr, bytes, pfec)); case HVMTRANS_gfn_paged_out: case HVMTRANS_gfn_shared: