[PATCHv2] firmware: zynqmp: add handling of the NULL return payload pointer in xilinx_pm_request.

Michal Simek michal.simek at xilinx.com
Thu Oct 14 13:34:06 CEST 2021



On 10/14/21 13:17, Adrian Fiergolski wrote:
> On 14.10.2021 11:47, Michal Simek wrote:
>>
>>
>> On 10/14/21 10:54, Adrian Fiergolski wrote:
>>> On 14.10.2021 at 09:22, Michal Simek wrote:
>>>>
>>>> First of all subject is quite long. Please make it shorter and remove
>>>> dot at the end.
>>>>
>>>>
>>>> On 10/13/21 18:21, Adrian Fiergolski wrote:
>>>>> When a caller is not interested in the returned message, the
>>>>> ret_payload pointer is set to NULL in the u-boot-sources.
>>>>> In this case, under EL3, the memory from address 0x0 would be
>>>>> overwritten by xilinx_pm_request with the returned IPI message,
>>>>> damaging the original data under this address. The patch, in case
>>>>> ret_payload is NULL, assigns the pointer to the array
>>>>> holding the IPI message being sent.
>>>>
>>>> There is any limit around 80 chars on the line that's why please use
>>>> it.
>>>>
>>>>>
>>>>> Signed-off-by: Adrian Fiergolski <adrian.fiergolski at fastree3d.com>
>>>>> ---
>>>>>     drivers/firmware/firmware-zynqmp.c | 20 ++++++++++++++------
>>>>>     1 file changed, 14 insertions(+), 6 deletions(-)
>>>>>
>>>>> diff --git a/drivers/firmware/firmware-zynqmp.c
>>>>> b/drivers/firmware/firmware-zynqmp.c
>>>>> index d4dc856baf..7517a84f0e 100644
>>>>> --- a/drivers/firmware/firmware-zynqmp.c
>>>>> +++ b/drivers/firmware/firmware-zynqmp.c
>>>>> @@ -154,16 +154,24 @@ U_BOOT_DRIVER(zynqmp_power) = {
>>>>>     int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32
>>>>> arg1, u32 arg2,
>>>>>                          u32 arg3, u32 *ret_payload)
>>>>>     {
>>>>> +#if defined(CONFIG_ZYNQMP_IPI)
>>>>> +    /*
>>>>> +     * Use fixed payload and arg size as the EL2 call. The firmware
>>>>> +     * is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the
>>>>> +     * firmware API is limited by the SMC call size
>>>>> +     */
>>>>> +    u32 regs[] = {api_id, arg0, arg1, arg2, arg3};
>>>>> +
>>>>> +    /*
>>>>> +     * Use regs array in case ret_payload is NULL
>>>>> +     */
>>>>> +    if (ret_payload == NULL)
>>>>> +        ret_payload = regs;
>>>>> +#endif
>>>>>         debug("%s at EL%d, API ID: 0x%0x\n", __func__, current_el(),
>>>>> api_id);
>>>>>           if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
>>>>>     #if defined(CONFIG_ZYNQMP_IPI)
>>>>> -        /*
>>>>> -         * Use fixed payload and arg size as the EL2 call. The
>>>>> firmware
>>>>> -         * is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the
>>>>> -         * firmware API is limited by the SMC call size
>>>>> -         */
>>>>> -        u32 regs[] = {api_id, arg0, arg1, arg2, arg3};
>>>>>     
>>>>
>>>> Based on your description the only code affected by this is here and
>>>> there is no reason to move it out of there.
>>>> It should be enough just to define ret_payload here as:
>>>>
>>>>       /* Use regs array in case ret_payload is NULL */
>>>>       if (!ret_payload)
>>>>           ret_payload = regs;
>>>>
>>>>
>>>> Or is there any other reason why you have moved code from here?
>>>> In else part regs are defined as pt_regs that's why that regs won't be
>>>> used anyway. And reg_payload is checked already.
>>>
>>> I moved the code, because otherwise, the life scope of regs would be
>>> limited to the first branch of the 'if' statement. As a consequence,
>>> outside 'if', reg_payload would point to the already invalid location of
>>> the regs variable in the return statement. Do you agree?
>>
>> Ok. I see it was purely for handling
>> return (ret_payload) ? ret_payload[0] : 0;
>>
>> Just simply call return within CONFIG_ZYNQMP_IPI code and that should
>> be it.
>> It really doesn't look good that you have
>>
>> #if defined(CONFIG_ZYNQMP_IPI)
>> ...
>> #endif
>> ..
>> if
>> #if defined(CONFIG_ZYNQMP_IPI)
>> ...
>> #else
>> ...
>> #endif
>> else
>> ...
>>
>>
>>>
>>> I also realised, that in the return statement, if ret_payload was NULL,
>>> a success status (0) was returned. Is it intended? After all, even e.g.
>>> a setter call to pmu-firmware (not interested in the returned payload),
>>> could fail. The returned value would be misleading then.
>>
>> That's a little bit different story. If ipi_req fails it should be
>> error out. But if doesn't fail and user doesn't care about return
>> value you should return just 0/success.
>> Definitely adding handling for ipi_req() failure is good to do.
> 
> Am I wrong assuming that pmu-firmware in case of success will return 0
> for any ipi request in the first byte of ret_payload, otherwise non-zero
> value? If that's true, shouldn't xilinx_pm_request simply return,
> unconditionally, ret_payload[0] ?

It is also plm for versal case. And assumption is right ret_payload[0] 
is return value from firmware if command passes/fails.

It means if ret_payload is NULL user doesn't care about returning values 
via ret_payload[1-up] but for sure it cares that command passes.

That means you can return in EL2 case regs.regs[0] as return value.

Thanks,
Michal





More information about the U-Boot mailing list