diff mbox

[v7,3/5] x86/ioreq server: Handle read-modify-write cases for p2m_ioreq_server pages.

Message ID 1488987232-12349-4-git-send-email-yu.c.zhang@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Yu Zhang March 8, 2017, 3:33 p.m. UTC
In ept_handle_violation(), write violations are also treated as
read violations. And when a VM is accessing a write-protected
address with read-modify-write instructions, the read emulation
process is triggered first.

For p2m_ioreq_server pages, current ioreq server only forwards
the write operations to the device model. Therefore when such page
is being accessed by a read-modify-write instruction, the read
operations should be emulated here in hypervisor. This patch provides
such a handler to copy the data to the buffer.

Note: MMIOs with p2m_mmio_dm type do not need such special treatment
because both reads and writes will go to the device mode.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
---
Cc: Paul Durrant <paul.durrant@citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>

changes in v2: 
  - According to comments from Jan: rename mem_ops to ioreq_server_ops.
  - According to comments from Jan: use hvm_copy_from_guest_phys() in
    ioreq_server_read(), instead of do it by myself.
---
 xen/arch/x86/hvm/emulate.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

Comments

Jan Beulich March 10, 2017, 3:33 p.m. UTC | #1
>>> On 08.03.17 at 16:33, <yu.c.zhang@linux.intel.com> wrote:
> @@ -197,6 +217,10 @@ static int hvmemul_do_io(
>           *   - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
>           *   like a normal PIO or MMIO that doesn't have an ioreq
>           *   server (i.e., by ignoring it).
> +         *
> +         *   - If the accesss is a read, this could be part of a
> +         *   read-modify-write instruction, emulate the read so that we
> +         *   have it.

"it" being what here? Grammatically the insn, but we don't care
about "having" the insn.

> @@ -226,6 +250,17 @@ static int hvmemul_do_io(
>                  }
>  
>                  /*
> +                 * This is part of a read-modify-write instruction.

"is" or "may be"?

Jan
Yu Zhang March 11, 2017, 8:42 a.m. UTC | #2
On 3/10/2017 11:33 PM, Jan Beulich wrote:
>>>> On 08.03.17 at 16:33, <yu.c.zhang@linux.intel.com> wrote:
>> @@ -197,6 +217,10 @@ static int hvmemul_do_io(
>>            *   - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
>>            *   like a normal PIO or MMIO that doesn't have an ioreq
>>            *   server (i.e., by ignoring it).
>> +         *
>> +         *   - If the accesss is a read, this could be part of a
>> +         *   read-modify-write instruction, emulate the read so that we
>> +         *   have it.
> "it" being what here? Grammatically the insn, but we don't care
> about "having" the insn.

Here "have it" means " to have the value on this address copied in".
Sorry for the inaccurate comment. How about just "emulate the read first"?

>> @@ -226,6 +250,17 @@ static int hvmemul_do_io(
>>                   }
>>   
>>                   /*
>> +                 * This is part of a read-modify-write instruction.
> "is" or "may be"?

I believe should be "is".
It's the only scenario I can imagine when an read operation(only when 
this operation is
also a write one) traps. Otherwise there shall be no VM exit.

Thanks
Yu
> Jan
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
Jan Beulich March 13, 2017, 11:22 a.m. UTC | #3
>>> On 11.03.17 at 09:42, <yu.c.zhang@linux.intel.com> wrote:
> On 3/10/2017 11:33 PM, Jan Beulich wrote:
>>>>> On 08.03.17 at 16:33, <yu.c.zhang@linux.intel.com> wrote:
>>> @@ -197,6 +217,10 @@ static int hvmemul_do_io(
>>>            *   - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
>>>            *   like a normal PIO or MMIO that doesn't have an ioreq
>>>            *   server (i.e., by ignoring it).
>>> +         *
>>> +         *   - If the accesss is a read, this could be part of a
>>> +         *   read-modify-write instruction, emulate the read so that we
>>> +         *   have it.
>> "it" being what here? Grammatically the insn, but we don't care
>> about "having" the insn.
> 
> Here "have it" means " to have the value on this address copied in".
> Sorry for the inaccurate comment. How about just "emulate the read first"?

Sounds okay.

>>> @@ -226,6 +250,17 @@ static int hvmemul_do_io(
>>>                   }
>>>   
>>>                   /*
>>> +                 * This is part of a read-modify-write instruction.
>> "is" or "may be"?
> 
> I believe should be "is".
> It's the only scenario I can imagine when an read operation(only when 
> this operation is
> also a write one) traps. Otherwise there shall be no VM exit.

Even with a racing update to the type?

Jan
Yu Zhang March 14, 2017, 7:28 a.m. UTC | #4
On 3/13/2017 7:22 PM, Jan Beulich wrote:
>>>> On 11.03.17 at 09:42, <yu.c.zhang@linux.intel.com> wrote:
>> On 3/10/2017 11:33 PM, Jan Beulich wrote:
>>>>>> On 08.03.17 at 16:33, <yu.c.zhang@linux.intel.com> wrote:
>>>> @@ -197,6 +217,10 @@ static int hvmemul_do_io(
>>>>             *   - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
>>>>             *   like a normal PIO or MMIO that doesn't have an ioreq
>>>>             *   server (i.e., by ignoring it).
>>>> +         *
>>>> +         *   - If the accesss is a read, this could be part of a
>>>> +         *   read-modify-write instruction, emulate the read so that we
>>>> +         *   have it.
>>> "it" being what here? Grammatically the insn, but we don't care
>>> about "having" the insn.
>> Here "have it" means " to have the value on this address copied in".
>> Sorry for the inaccurate comment. How about just "emulate the read first"?
> Sounds okay.
>
>>>> @@ -226,6 +250,17 @@ static int hvmemul_do_io(
>>>>                    }
>>>>    
>>>>                    /*
>>>> +                 * This is part of a read-modify-write instruction.
>>> "is" or "may be"?
>> I believe should be "is".
>> It's the only scenario I can imagine when an read operation(only when
>> this operation is
>> also a write one) traps. Otherwise there shall be no VM exit.
> Even with a racing update to the type?

Yes.
With patch 1/5, there shall be no racing update to the p2m type during 
this process.
Besides, I believe even without patch 1/5, and we allow the racing p2m 
change, it will
only happen on a p2m_ioreq_server page changed to p2m_ram_rw(in such 
case it is shall
only be a write or a read-modify-write op that cause such vm exit). The 
race will not
happen for a p2m_ram_rw page changed to p2m_ioreq_server, because there 
shall be no
vm exit at all.

Thanks
Yu

> Jan
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index fb56f7b..9744dcb 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -94,6 +94,26 @@  static const struct hvm_io_handler null_handler = {
     .ops = &null_ops
 };
 
+static int ioreq_server_read(const struct hvm_io_handler *io_handler,
+                    uint64_t addr,
+                    uint32_t size,
+                    uint64_t *data)
+{
+    if ( hvm_copy_from_guest_phys(data, addr, size) != HVMCOPY_okay )
+        return X86EMUL_UNHANDLEABLE;
+
+    return X86EMUL_OKAY;
+}
+
+static const struct hvm_io_ops ioreq_server_ops = {
+    .read = ioreq_server_read,
+    .write = null_write
+};
+
+static const struct hvm_io_handler ioreq_server_handler = {
+    .ops = &ioreq_server_ops
+};
+
 static int hvmemul_do_io(
     bool_t is_mmio, paddr_t addr, unsigned long *reps, unsigned int size,
     uint8_t dir, bool_t df, bool_t data_is_addr, uintptr_t data)
@@ -197,6 +217,10 @@  static int hvmemul_do_io(
          *   - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
          *   like a normal PIO or MMIO that doesn't have an ioreq
          *   server (i.e., by ignoring it).
+         *
+         *   - If the accesss is a read, this could be part of a
+         *   read-modify-write instruction, emulate the read so that we
+         *   have it.
          */
         struct hvm_ioreq_server *s = NULL;
         p2m_type_t p2mt = p2m_invalid;
@@ -226,6 +250,17 @@  static int hvmemul_do_io(
                 }
 
                 /*
+                 * This is part of a read-modify-write instruction.
+                 * Emulate the read part so we have the value cached.
+                 */
+                if ( dir == IOREQ_READ )
+                {
+                    rc = hvm_process_io_intercept(&ioreq_server_handler, &p);
+                    vio->io_req.state = STATE_IOREQ_NONE;
+                    break;
+                }
+
+                /*
                  * If the IOREQ_MEM_ACCESS_WRITE flag is not set,
                  * we should set s to NULL, and just ignore such
                  * access.