[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





On 22/11/2021 14:19, Ayan Kumar Halder wrote:
Hi Julien/Stefano/Wei/Jan,

Hi,

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.

This statement implies that the issue happens on both AArch32 and AArch64 state. I am OK if we only handle the latter for now. But I would clarify it in the commit message.

Thus any post indexing ldr/str instruction at EL1 results in a data abort with ISV=0.

Instruction from EL0 may also trap in Xen. So I would prefer if you just say "instruction executed by a domain results ...".

As a result, Xen needs to decode the instruction.

Can you give some information on the domain used. Something like:

"this was discovered with XXX which let the compiler deciding which instruction to use."


Thus, DomU will be able to read/write to ioreg space with post indexing

I would say "domain" rather "domU" because all the domains are affected.

instructions for 32 bit.

How about the following commit message:

"
xen/arm64: io: Decode 32-bit ldr/str post-indexing instructions

At the moment, Xen is only handling data abort with valid syndrome (i.e.
ISV=0). Unfortunately, this doesn't cover all the instructions a domain
could use to access MMIO regions.

For instance, Xilinx baremetal OS will use:

        volatile u32 *LocalAddr = (volatile u32 *)Addr;
        *LocalAddr = Value;

This leave the compiler to decide which store instructions to use. This
may be a post-index store instruction where the HW will not provide a
valid syndrome.

In order to handle post-indexing store/load instructions,
Xen will need to fetch and decode the instruction.

This patch only cover post-index store/load instructions from AArch64 mode. For now, this is left unimplemented for trap from AArch32 mode.
"

+{
+    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)

That would be OK with me. Alternatively, you could use the union approach suggested by Bertrand.



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.

vreg_reg*_extract() are meant to work on a register. So I think they are not appropriate here as you don't deal with registers.

[...]

+
+    /* 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)) )

This should work, but I think you can simplify to use:

!psr_mode_is_32bit()

+         */
+        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() ?

Yes.

Cheers,

--
Julien Grall



 


Rackspace

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