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.
Thanks!
Laszlo
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel