Signed-off-by: Ayan Kumar Halder <ayank...@xilinx.com>
---
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)
+{
+ int32_t ret;
+
+ if ( !(start >= 0 && length > 0 && length <= 32 - start) )
+ return -EINVAL;
+
+ ret = (value >> start) & (~0U >> (32 - length));
+
+ 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;
+
+ /* For details on decoding, refer to Armv8 Architecture reference manual
+ * Section - "Load/store register (immediate post-indexed)", Pg 318
+ */
+ 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
+ * op4 = 1 - Load/store register (immediate post-indexed)
+ */
+ 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);
+
+ /* At the moment, we support STR(immediate) - 32 bit variant and
+ * LDR(immediate) - 32 bit variant only.
+ */
+ if (!((size==2) && (v==0) && ((opc==0) || (opc==1))))
+ 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);
+
+ 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) )
+ return decode_64bit_loadstore_postindexing(regs->pc, dabt);
+
/* TODO: Handle ARM instruction */
gprintk(XENLOG_ERR, "unhandled ARM instruction\n");
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.
+ */
+ rc = decode_instruction(regs, &info.dabt);
+ if ( rc )
+ return IO_ABORT;
+ }
/*
* Erratum 766422: Thumb store translation fault to Hypervisor may