[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: Ayan Kumar Halder <ayan.kumar.halder@xxxxxxxxxx>
  • From: Bertrand Marquis <Bertrand.Marquis@xxxxxxx>
  • Date: Mon, 22 Nov 2021 15:19:35 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; 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=42344sngtbG94OAdW8CuncTwOHEpUf1J9q6GjCHxGHc=; b=KOBHZPa3eH9MqNNrJNUX4FRmbcZAzC5XT/9xSbaoYC07N8XWkn4ko29Scz/0bNcfR79DTQiKv/VnQiMdbwF+QKjtXIWcNupT5+d3stwySL840GPkPOwAVRAyfNcA2jLA+uBRbihcV4s/bs1w1nKcnvCewXZB4DlTw1fiUMB+8DEwXdWcGt2imN8J2WnruzJBlAvcF8VuhW5pPuukFvWueJJQmxxm7zx8YdzqaXHwemE4XooTPpbtvXhv5xVBn7nUjh8OoOnSGblyBsGATrrLd8a5tzyp0pURSsxeFpPDWsQrVtWZV/65BYQTC6aTJ/ysxKvFcocra2ShWKVDW7KqOg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ZzcvpdIf0KLJDir6Lqhu5ZJWiu8hiAyw2axZQO98lp4lv9JYEB9Zxz3RJnY87bSSnq+Seoqm4fhR9ZEOfxM8lWZDzaWkCUW1cVG81pODJffS/lqC9gOc6oEHTBbV4aglRS4Un1mtNAzLUtm6M3GdC4457m/DPG0aF+op3kvRqIIqJZTHbRCalFL+3efdlP4ba4Re+LU43a42N4UpCp6icyAmGrBTrV+eaBSNClmDaMq/u2cVzIy7FOWHyYwQEg56eHBUAM19tV8l6FsOo9qgt91AXtcWj7NLZGyuVxkFTx8A1ejEa4//YoYSfQqqwkBP5m8EgTKBswvVHjoKyGi/Cw==
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: Julien Grall <julien@xxxxxxx>, "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Wei Chen <Wei.Chen@xxxxxxx>, "stefano.stabellini@xxxxxxxxxx" <stefano.stabellini@xxxxxxxxxx>, "sstabellini@xxxxxxxxxx" <sstabellini@xxxxxxxxxx>, "jbeulich@xxxxxxxx" <jbeulich@xxxxxxxx>, "Volodymyr_Babchuk@xxxxxxxx" <Volodymyr_Babchuk@xxxxxxxx>, Rahul Singh <Rahul.Singh@xxxxxxx>
  • Delivery-date: Mon, 22 Nov 2021 15:20:12 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Original-authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Thread-index: AQHX3WXgMxQOWtsAQkCagYrL+eVmYKwLGnaAgASCuICAABC7AA==
  • Thread-topic: [RFC PATCH] Added the logic to decode 32 bit ldr/str post-indexing instructions

Hi Ayan

> On 22 Nov 2021, at 14:19, Ayan Kumar Halder <ayan.kumar.halder@xxxxxxxxxx> 
> wrote:
> 
> 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.

In fact you could also use a union and define in a structure what the bits are.

Union instr {
        uint32_t value
        struct {
            ….
            Unsigned int size:2;
        }
}

This could simplify some of your code.

Cheers
Bertrand


> 
> - 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®.