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

Reply via email to