Hi Oleg, Stefano

On 03/10/2023 02:13, Stefano Stabellini wrote:
> Hi Oleg,
> 
> You are getting this output:
> 
>> (XEN) d0v0 Forwarding AES operation: 3254779951 136bb00000000000 -> 
>> fffffffffffff000
> 
> Which means that the guest physical address is 0x136bb00000000000 and
> the translated physical address is 0xfffffffffffff000. It generates an
> error so you are asking if 0xfffffffffffff000 is incorrect because the
> translation is incorrect.
> 
> This is possible. However, I think it is more likely that
> 0x136bb000_00000000 is incorrect. This an extremely high address. Could
> it be wrong?

I think the issue is due to a different way of forming the r1 register for this 
particular EEMI call:

Take a look at the PM AES function from Linux:
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/firmware/xilinx/zynqmp.c#L1975
and EEMI call invocation:
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/firmware/xilinx/zynqmp.c#L390

The register passed as r1 is formed a bit differently than "normally". FWICS:
 - the upper 32 bits of address are stored in the lower 32 bits of r1 register.
 - the lower 32 bits of address are stored in the upper 32 bits of r1 register.

That is why you are getting a very high address in r1 0x136bb000_00000000.

Please, try to do the following (not tested):

case 0xC200002F:
{
    register_t gaddr, new_gaddr;
    paddr_t maddr;

    gaddr = ((register_t)get_user_reg(regs, 1) << 32) | (get_user_reg(regs, 1) 
>> 32);
    maddr = mfn_to_maddr(gfn_to_mfn(current->domain, gaddr_to_gfn(gaddr)));

    /* Most probably not needed given dma_alloc_coherent use */ 
    maddr += gaddr &~ PAGE_MASK;

    /* Convert back to required format */
    new_gaddr = ((register_t)maddr << 32) | (maddr >> 32);

    arm_smccc_1_1_smc(get_user_reg(regs, 0),
            get_user_reg(regs, 1),
            new_gaddr,
            get_user_reg(regs, 3),
            get_user_reg(regs, 4),
            get_user_reg(regs, 5),
            get_user_reg(regs, 6),
            get_user_reg(regs, 7),
            &res);

    set_user_reg(regs, 0, res.a0);
    set_user_reg(regs, 1, res.a1);
    set_user_reg(regs, 2, res.a2);
    set_user_reg(regs, 3, res.a3);
    return true;
}

~Michal


Reply via email to