On 10/20/15 18:24, Laszlo Ersek wrote:
> On 10/20/15 16:37, Laszlo Ersek wrote:
>
>> The variable access fails *iff* the access is made by a VCPU that is
>> *not* VCPU#0.
>>
>> I added a bunch of debug messages to the following functions:
>>
>> - InitCommunicateBuffer(), SendCommunicateBuffer()
>> [MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c]
>>
>> - BSPHandler(), APHandler()
>> [UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c]
>>
>> Now, when the "efibootmgr" utility is run on CPU#0, everything works:
>>
>>> [root@ovmf-fedlet ~]# taskset -c 0 efibootmgr
>>> BootCurrent: 0004
>>> Timeout: 0 seconds
>>> BootOrder: 0004,0003
>>> Boot0003* EFI Internal Shell
>>> Boot0004* fedlet grub
>>
>> and the OVMF debug log contains a sequence of the following snippets --
>> the snippet is repeated once per variable:
>>
>>> InitCommunicateBuffer: Function=1
>>> InitCommunicateBuffer: Status=Success
>>> BSPHandler: 318: CpuIndex=0
>>> BSPHandler: 544: CpuIndex=0
>>> SendCommunicateBuffer: ReturnStatus=Buffer Too Small
>>>
>>> InitCommunicateBuffer: Function=1
>>> InitCommunicateBuffer: Status=Success
>>> BSPHandler: 318: CpuIndex=0
>>> BSPHandler: 544: CpuIndex=0
>>> SendCommunicateBuffer: ReturnStatus=Success
>>
>> Here Function=1 is
>>
>> SMM_VARIABLE_FUNCTION_GET_VARIABLE
>> [MdeModulePkg/Include/Guid/SmmVariableCommon.h]
>>
>> It is one of the message types that the "unprivileged" runtime variable
>> driver composes for the "privileged" SMM variable driver. In the above
>> log, you can see
>> (1) the message buffer being initialized for this message type -- in the
>> unprivileged driver --,
>> (2) then the BSPHandler() function starting and completing (in SMM),
>> (3) finally the unprivileged driver looking at the status code coming
>> back, in the message buffer, from the privileged driver.
>>
>> The first triplet ends with "Buffer Too Small", because efibootmgr --
>> apparently -- only queries the buffer size it needs to allocate for
>> fetching the variable's contents. The second triplet succeeds.
>>
>> Side note: when testing variable access from a UEFI application or the
>> UEFI shell directly, the code *always* runs on VCPU#0! That's why such
>> testing always succeeds.
>>
>> Now, here's what happens when the same is attempted from VCPU#1:
>>
>>> [root@ovmf-fedlet ~]# taskset -c 1 efibootmgr
>>> efibootmgr: efibootmgr: Invalid argument
>>
>> and the matching OVMF debug log is:
>>
>>> InitCommunicateBuffer: Function=1
>>> InitCommunicateBuffer: Status=Success
>>> SendCommunicateBuffer: ReturnStatus=Buffer Too Small
>>>
>>> InitCommunicateBuffer: Function=1
>>> InitCommunicateBuffer: Status=Success
>>> SendCommunicateBBSPHandler: 318: CpuIndex=0
>>> BSPHandler: 544: CpuIndex=0
>>> uffer: ReturnStatus=Buffer Too Small
>>
>> Observations:
>> - the first triplet seems to complete similarly, however we don't see
>> either BSPHandler or APHandler logs for it
>>
>> - the second triplet fails too (which is why efibootmgr reports EINVAL
>> -- the second call uses the right variable buffer size, so it should
>> succeed)
>>
>> - there are no APHandler() log entries at all, despite the efibootmgr
>> process being bound to VCPU#1. Also note that BSPHandler logs
>> CpuIndex=0.
>>
>> This *cannot* be right. CpuIndex should be 1 in SmiRendezvous(),
>> APHandler() should be entered, and APHandler() should bring in the
>> BSP. The BSP should finally dispatch the SMI to the SMM core and the
>> variable driver.
>
> I think I have found the bug -- it's in QEMU.
>
> Namely, in ich9_apm_ctrl_changed(), the SMI is *always* injected on the
> first CPU:
>
> /* SMI_EN = PMBASE + 30. SMI control and enable register */
> if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
> cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
> }
>
> There's another similar function in this file, ich9_generate_smi(),
> which similarly insists on the first CPU only, but that should be
> alright. That function comes from:
>
> commit 920557971b60e53c2f3f22e5d6c620ab1ed411fd
> Author: Paulo Alcantara <[email protected]>
> Date: Sun Jun 28 14:58:56 2015 -0300
>
> ich9: add TCO interface emulation
>
> and is only called from "hw/acpi/tco.c".
>
> A watchdog device may plausibly be permitted to inject the SMI on the
> first CPU only, but for a synchronously triggered SMI, the SMI should be
> injected on the exact CPU that triggers it.
>
> The bug in ich9_apm_ctrl_changed() dates back to:
>
> commit 4d00636e97b7f55810ff7faccff594159175e24e
> Author: Jason Baron <[email protected]>
> Date: Wed Nov 14 15:54:05 2012 -0500
>
> ich9: Add the lpc chip
>
> Paolo, do you have an idea how the executing CPU's identity could be
> preserved from the exec-stuff until the device emulation code? I think
> it is trivial to know for someone who knows, but I don't know (yet). :)
> With that info surviving, ich9_apm_ctrl_changed() should be modified to
> inject the SMI on the subject CPU.
Can I simply rely on the global variable "current_cpu"?
>
> Thanks!
> Laszlo
>
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel