[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH] Added the logic to decode 32 bit ldr/str post-indexing instructions


  • To: Julien Grall <julien@xxxxxxx>, Ayan Kumar Halder <ayan.kumar.halder@xxxxxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxxx>, <wei.chen@xxxxxxx>, <stefano.stabellini@xxxxxxxxxx>, <sstabellini@xxxxxxxxxx>, <jbeulich@xxxxxxxx>
  • From: Ayan Kumar Halder <ayan.kumar.halder@xxxxxxxxxx>
  • Date: Mon, 22 Nov 2021 14:19:41 +0000
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.80.198) smtp.rcpttodomain=xen.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=bYL2Dlt4TbBTnT/juakRIf0jyz3Yh+XInVEk9Yj7yog=; b=aILtdGwH7KZ6MG3pq3qvgxvXc/GnRcY0WTXAA0S2uM6/zTizNnkgL79QbMwSytXAsMIdD+fx2AfuhTEnJE4lJVAy65GW3b5e/dtVDnfDodKC4MFvj3ZevYWl7qeqXgCBwNLZdd+onTnSnHA5CQZqjksTdaH/IBpb3NxFCQC3lrfun901TMpkcOXp1uTN+CLGwEo5xoW32ZxKmZ8gxz6/WarZEmIAu7cNTNw301XUiivCFxwkcunN23xTKAXKIkTyTMnnnlS5+MXmOguNTgyLcpYqvxZJ5KRHHQhbkB1B2WnquoGRR8OEOv8SZ7toEoK8rMmQRgh8Ea18oA7LwrcruA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=K2qq7Q1t4oRLBHngVk6DnLXgF5bqtDAV8JiTrM/K4KkAxBotJSbvCE2f38DLutX9+EPkvtGYT+AWI1ED4yHpH4M3cjlQ9ikeXLNBLTOxL5/swESj77Go4fcJcUiWkKM6PcreZbN6oY8ndCv159vNGDkQKXmKqqot/y83GhnRdMVAlw0CDAPSisP6DKwf7Q6LXGIjK12dbbFQoS/7FkFtdtAnkA0tmbLO1Tljv0SScG6ZWsMop7BT1I2XKZw0dadwnmIKU9bGpHzdj6OFGK/qAMS74b90glg3LsL9oRLiC+jkEUOxOByyvtGqxOgV3edoXP9K5xnE7BEaaZTuYY/k5w==
  • Cc: <Volodymyr_Babchuk@xxxxxxxx>, <bertrand.marquis@xxxxxxx>, <rahul.singh@xxxxxxx>
  • Delivery-date: Mon, 22 Nov 2021 14:19:53 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Hi Julien/Stefano/Wei/Jan,

Many thanks for your review.

As some of the comments were inter-related, I have consolidated my response to all the comments below.

On 19/11/2021 17:26, Julien Grall wrote:
Hi Ayan,

On 19/11/2021 16:52, Ayan Kumar Halder wrote:
At present, post indexing instructions are not emulated by Xen.

Can you explain in the commit message why this is a problem?

Yes, I will update the message as below :-
Armv8 hardware does not provide the correct syndrome for decoding post indexing ldr/str instructions. Thus any post indexing ldr/str instruction at EL1 results in a data abort with ISV=0. As a result, Xen needs to decode the instruction.

Thus, DomU will be able to read/write to ioreg space with post indexing instructions for 32 bit.


When Xen gets the exception, EL2_ESR.ISV bit not set. Thus as a
result, data abort is triggered.

Added the logic to decode ldr/str post indexing instructions.
With this, Xen can decode instructions like these:-
ldr w2, [x1], #4
Thus, domU can read ioreg with post indexing instructions.
Hmmm.... Don't you also need to update the register x1 after the instruction was emulated?

Yes, this is a mistake. X1 needs to be incremented by 4 after W2 is written.


Signed-off-by: Ayan Kumar Halder <ayankuma@xxxxxxxxxx>
---
Note to reviewer:-
This patch is based on an issue discussed in
https://lists.xenproject.org/archives/html/xen-devel/2021-11/msg00969.html
"Xen/ARM - Query about a data abort seen while reading GICD registers"


  xen/arch/arm/decode.c | 77 +++++++++++++++++++++++++++++++++++++++++++
  xen/arch/arm/io.c     | 14 ++++++--
  2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/decode.c b/xen/arch/arm/decode.c
index 792c2e92a7..7b60bedbc5 100644
--- a/xen/arch/arm/decode.c
+++ b/xen/arch/arm/decode.c
@@ -84,6 +84,80 @@ bad_thumb2:
      return 1;
  }
+static inline int32_t extract32(uint32_t value, int start, int length)

Any reason to have start and length signed?

Again a mistake. There is no reason to use signed types here or in the other places. As Jan Beulich has pointed out, I should be using unsigned int as per the CODING_STYLE.

+{
+    int32_t ret;
+
+    if ( !(start >= 0 && length > 0 && length <= 32 - start) )
+        return -EINVAL;
+
+    ret = (value >> start) & (~0U >> (32 - length));

This would be easier to read if you use GENMASK().

I see that GENMASK returns a register mask. In my scenario, I wish to compare the offsets 10, 21, 24 and 27 to some fixed value.

So, instead of using GENMASK four times, I can try the following
instr & MASK_for_10_21_24_27 == VALID_for_10_21_24_27 (Wei Chen's suggestion)


Also for size, v and opc, I can defined another bitmask to compare with VALID_for_32bit_LDR | VALID_for_32bit_STR.

Wei Chen, You had suggested using vreg_regx_extract(). However, I see that it is used to extract the complete u64 register value. In this case, I wish to compare certain offsets within a 32 bit register to some expected values. So, vreg_regx_extract() might not be appropriate and we can use the method mentioned before.


+
+    return ret;
+}
+
+static int decode_64bit_loadstore_postindexing(register_t pc, struct hsr_dabt *dabt)
+{
+    uint32_t instr;
+    int size;
+    int v;
+    int opc;
+    int rt;
+    int imm9;

Should all those variables need to be signed?

A mistake. I will change them to unsigned int.

+
+    /* For details on decoding, refer to Armv8 Architecture reference manual
+     * Section - "Load/store register (immediate post-indexed)", Pg 318
The page number varies between revision of the Armv8 spec. So can you specify which version you used?

Ack. I will mention the version.

+    */

The coding style for comment in Xen is:

/*
  * Foo
  * Bar
  */
Ack

+    if ( raw_copy_from_guest(&instr, (void * __user)pc, sizeof (instr)) )
+        return -EFAULT;
+
+    /* First, let's check for the fixed values */
+
+    /*  As per the "Encoding table for the Loads and Stores group", Pg 299

Same question here about the version.
Ack, I will mention the version.


+     * op4 = 1 - Load/store register (immediate post-indexed)
+     */

Coding style.
Ack


+    if ( extract32(instr, 10, 2) != 1 )
+        goto bad_64bit_loadstore;
+
+    /* For the following, refer to "Load/store register (immediate post-indexed)"
+     * to get the fixed values at various bit positions.
+     */
+    if ( extract32(instr, 21, 1) != 0 )
+        goto bad_64bit_loadstore;
+
+    if ( extract32(instr, 24, 2) != 0 )
+        goto bad_64bit_loadstore;
+
+    if ( extract32(instr, 27, 3) != 7 )
+        goto bad_64bit_loadstore;
+
+    size = extract32(instr, 30, 2);
+    v = extract32(instr, 26, 1);
+    opc = extract32(instr, 22, 1);

Stefano:- Thanks for catching my mistake. opc is 2 bits (bits 22, 23). I will fix this.

+
+    /* At the moment, we support STR(immediate) - 32 bit variant and
+     * LDR(immediate) - 32 bit variant only.
+     */

Coding style.
Ack


+    if (!((size==2) && (v==0) && ((opc==0) || (opc==1))))


The coding style for this should be:

if ( !(( size == 2 ) && ( ... ) ... ) )
Ack


  +        goto bad_64bit_loadstore;
+
+    rt = extract32(instr, 0, 5);
+    imm9 = extract32(instr, 12, 9);
+
+    if ( imm9 < 0 )
+        update_dabt(dabt, rt, size, true);
+    else
+        update_dabt(dabt, rt, size, false);

This could be simplified with:

update_dabt(dabt, rt, size, imm9 < 0);
Ack


+
+    dabt->valid = 1;
+
+
+    return 0;
+bad_64bit_loadstore:
+    gprintk(XENLOG_ERR, "unhandled 64bit instruction 0x%x\n", instr);
+    return 1;
+}
+
  static int decode_thumb(register_t pc, struct hsr_dabt *dabt)
  {
      uint16_t instr;
@@ -155,6 +229,9 @@ int decode_instruction(const struct cpu_user_regs *regs, struct hsr_dabt *dabt)
      if ( is_32bit_domain(current->domain) && regs->cpsr & PSR_THUMB )
          return decode_thumb(regs->pc, dabt);
+    if ( is_64bit_domain(current->domain) )

You can still run 32-bit code in 64-bit domain. So I think you want to check the SPSR mode.

Do you mean the following check :-
if ( (is_64bit_domain(current->domain) && (!(regs->spsr & PSR_MODE_BIT)) )


+        return decode_64bit_loadstore_postindexing(regs->pc, dabt);
+
      /* TODO: Handle ARM instruction */
      gprintk(XENLOG_ERR, "unhandled ARM instruction\n");

I think this comment should now be updated to "unhandled 32-bit ...".

Ack

diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
index 729287e37c..49e80358c0 100644
--- a/xen/arch/arm/io.c
+++ b/xen/arch/arm/io.c
@@ -106,14 +106,13 @@ enum io_state try_handle_mmio(struct cpu_user_regs *regs,
          .gpa = gpa,
          .dabt = dabt
      };
+    int rc;
      ASSERT(hsr.ec == HSR_EC_DATA_ABORT_LOWER_EL);
      handler = find_mmio_handler(v->domain, info.gpa);
      if ( !handler )
      {
-        int rc;
-
          rc = try_fwd_ioserv(regs, v, &info);
          if ( rc == IO_HANDLED )
              return handle_ioserv(regs, v);
@@ -123,7 +122,16 @@ enum io_state try_handle_mmio(struct cpu_user_regs *regs,       /* All the instructions used on emulated MMIO region should be valid */
      if ( !dabt.valid )
-        return IO_ABORT;
+    {
+        /*
+         * Post indexing ldr/str instructions are not emulated by Xen. So, the +         * ISS is invalid. In such a scenario, we try to manually decode the
+         * instruction from the program counter.

I am afraid this is wrong. The problem here is the processor didn't provide a valid syndrom for post-indexing ldr/str instructions. So in order to support them, Xen must decode.

Ack

+         */
+        rc = decode_instruction(regs, &info.dabt);

I actually expect this to also be useful when forwarding the I/O to device-model. So I would move the decoding earlier in the code and the check of dabt.valid earlier.

You mean I will move decode_instruction() before find_mmio_handler() ?

Stefano > It doesn't look like we are setting dabt->write anywhere.

Ayan > Yes, this is a miss. Depending on the opc, this should be upadeted accordingly in decode_64bit_loadstore_postindexing().

Stefano > Also, is info.gpa in try_handle_mmio already updated in the pre-index
case? If not, do we need to apply the offset manually here?

Ayan > Sorry, I did not understand you. This patch is only related to the post indexing ldr/str issue. Why do we need to check for pre-indexing ?

Stefano > In the post-index case, we need to update the base address in the Rn
register?

Ayan > Yes this is a mistake, As Julien pointed out before, the register x1 ie Rn needs to the incremented.

Jan > In addition to Julien's comment regarding the function parameters - why
is the return type int32_t and not uint32_t? Plus as per ./CODING_STYLE
it really shouldn't be a fixed width type anyway, but e.g. unsigned int.

Ayan > Yes, this is a mistake. I will update int32_t to unsigned int in all the places. However for extract32(), I don't think we need this function. Rather Wei's suggestion (ie instr & MASK_for_10_21_24_27 == VALID_for_10_21_24_27 ) makes the code simpler and shorter.

- Ayan


+        if ( rc )
+            return IO_ABORT;
+    }
      /*
       * Erratum 766422: Thumb store translation fault to Hypervisor may


Cheers,




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.