[edk2-devel] [PATCH v6 7/9] OvmfPkg/CpuHotplugSmm: add CpuEject()

Laszlo Ersek lersek at redhat.com
Wed Feb 3 20:55:24 UTC 2021


On 02/03/21 07:13, Ankur Arora wrote:
> On 2021-02-02 6:00 a.m., Laszlo Ersek wrote:
>> On 02/01/21 21:12, Ankur Arora wrote:
>>> On 2021-02-01 11:08 a.m., Laszlo Ersek wrote:

>>>> (16) This function uses a data structure for communication between BSP
>>>> and APs -- mCpuHotEjectData->ApicIdMap is modified in UnplugCpus() on
>>>> the BSP, and checked above by the APs (too).
>>>>
>>>> What guarantees the visibility of mCpuHotEjectData->ApicIdMap?
>>>
>>> I was banking on SmiRendezvous() explicitly signalling that all
>>> processing on the BSP was done before any AP will look at
>>> mCpuHotEjectData in SmmCpuFeaturesRendezvousExit().
>>>
>>> 1716     //
>>> 1717     // Wait for BSP's signal to exit SMI
>>> 1718     //
>>> 1719     while (*mSmmMpSyncData->AllCpusInSync) {
>>> 1720       CpuPause ();
>>> 1721     }
>>> 1722   }
>>> 1723
>>> 1724 Exit:
>>> 1725   SmmCpuFeaturesRendezvousExit (CpuIndex);
>>
>> Right; it's a general pattern in edk2: volatile UINT8 (aka BOOLEAN)
>> objects are considered atomic. (See
>> SMM_DISPATCHER_MP_SYNC_DATA.AllCpusInSync -- it's a pointer to a
>> volatile BOOLEAN.)
>>
>> But our UINT64 values are neither volatile nor UINT8, and I got suddenly
>> doubtful about "AllCpusInSync" working as a multiprocessor barrier.
>>
>> (I could be unjustifiedly worried, as a bunch of other fields in
>> SMM_DISPATCHER_MP_SYNC_DATA are volatile, wider than UINT8, and *not*
>> accessed with InterlockedCompareExchageXx().)
> 
> Thanks for pointing me to this code. There's a curious comment in
> about making this structure uncache-able in the declaration here
> (though I couldn't figure out how that is done):
> 
> 418 typedef struct {
> 419   //
> 420   // Pointer to an array. The array should be located immediately
> after this structure
> 421   // so that UC cache-ability can be set together.
> 422   //

This is probably through SMRR manipulation.

The "UefiCpuPkg/Library/SmmCpuFeaturesLib" instance contains SMRR support.

The "OvmfPkg/Library/SmmCpuFeaturesLib" instance contains no SMRR
support. (Just search both source files for "SMRR".)


> 423   SMM_CPU_DATA_BLOCK            *CpuData;
> 424   volatile UINT32               *Counter;
> 425   volatile UINT32               BspIndex;
> 426   volatile BOOLEAN              *InsideSmm;
> 427   volatile BOOLEAN              *AllCpusInSync;
> 428   volatile SMM_CPU_SYNC_MODE    EffectiveSyncMode;
> 429   volatile BOOLEAN              SwitchBsp;
> 430   volatile BOOLEAN              *CandidateBsp;
> 431   EFI_AP_PROCEDURE              StartupProcedure;
> 432   VOID                          *StartupProcArgs;
> 433 } SMM_DISPATCHER_MP_SYNC_DATA;
> 
> Also, is there an expectation that these fields (at least some of
> them) switch over when a new leader is chosen?

Yes, see for example the "Elect BSP" section in SmiRendezvous().


> Otherwise I'm not sure why for instance, AllCpusInSync would be
> a pointer.

TBH I can't explain that; I'm not too familiar with those parts...


>>> CpuEject():
>>> 218   ApicId = mCpuHotEjectData->ApicIdMap[ProcessorNum];
>>>
>>> For the to-be-ejected-AP, this value can only move from
>>>     valid-APIC-ID (=> wait in CpuDeadLoop()) -> CPU_EJECT_INVALID.
>>>
>>> Given that, by the time the worker does the write on line 254, this
>>> AP is guaranteed to be dead already, I don't think there's any
>>> scenario where the to-be-ejected-AP can see anything other than
>>> a valid-APIC-ID.
>>
>> The scenario I had in mind was different: what guarantees that the
>> effect of
>>
>>     375        mCpuHotEjectData->ApicIdMap[ProcessorNum] =
>> (UINT64)RemoveApicId;
>>
>> which is performed by the BSP in UnplugCpus(), is visible by the AP on
>> line 218 (see your quote above)?
>>
>> What if the AP gets to line 218 before the BSP's write on line 375
>> *propagates* sufficiently?
> 
> I understand. That does make sense. And, as you said elsewhere, a real
> memory fence would come in useful here.
> 
> We could use AsmCpuid() as a poor man's mfence, but that seems overkill
> given that x86 at least guarantees store-order.

Right -- I don't recall any examples of AsmCpuid() being used like that
in edk2.

Thanks!
Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#71115): https://edk2.groups.io/g/devel/message/71115
Mute This Topic: https://groups.io/mt/80199926/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list