summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Library/MpInitLib/MpLib.c
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2019-10-07 14:05:28 +0200
committerLaszlo Ersek <lersek@redhat.com>2019-10-11 23:20:09 +0200
commit778832bcad33512ae09bbf7235a1ddcfa7403083 (patch)
tree266ab52fe028d3cca60e96139ed33bedfa9cfdd5 /UefiCpuPkg/Library/MpInitLib/MpLib.c
parent30459ddde672b3130d7775fe16d91e63c6f95943 (diff)
downloadedk2-778832bcad33512ae09bbf7235a1ddcfa7403083.tar.gz
edk2-778832bcad33512ae09bbf7235a1ddcfa7403083.tar.bz2
edk2-778832bcad33512ae09bbf7235a1ddcfa7403083.zip
UefiCpuPkg/MpInitLib: honor the platform's boot CPU count in AP detection
- If a platform boots such that the boot CPU count is smaller than PcdCpuMaxLogicalProcessorNumber, then the platform cannot use the "fast AP detection" logic added in commit 6e1987f19af7. (Which has been documented as a subset of use case (2) in the previous patch.) Said logic depends on the boot CPU count being equal to PcdCpuMaxLogicalProcessorNumber. If the equality does not hold, the platform either has to wait too long, or risk missing APs due to an early timeout. - The platform may not be able to use the variant added in commit 0594ec417c89 either. (Which has been documented as use case (1) in the previous patch.) See commit 861218740d6d. When OVMF runs on QEMU/KVM, APs may check in with the BSP in arbitrary order, plus the individual AP may take arbitrarily long to check-in. If "NumApsExecuting" falls to zero mid-enumeration, APs will be missed. Allow platforms to specify the exact boot CPU count, independently of PcdCpuMaxLogicalProcessorNumber. In this mode, the BSP waits for all APs to check-in regardless of timeout. If at least one AP fails to check-in, then the AP enumeration hangs forever. That is the desired behavior when the exact boot CPU count is known in advance. (A hung boot is better than an AP checking-in after timeout, and executing code from released storage.) Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1515 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
Diffstat (limited to 'UefiCpuPkg/Library/MpInitLib/MpLib.c')
-rw-r--r--UefiCpuPkg/Library/MpInitLib/MpLib.c99
1 files changed, 60 insertions, 39 deletions
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 594a035d8b..622b70ca3c 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1044,46 +1044,67 @@ WakeUpAP (
SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
}
if (CpuMpData->InitFlag == ApInitConfig) {
- //
- // The AP enumeration algorithm below is suitable for two use cases.
- //
- // (1) The check-in time for an individual AP is bounded, and APs run
- // through their initialization routines strongly concurrently. In
- // particular, the number of concurrently running APs
- // ("NumApsExecuting") is never expected to fall to zero
- // *temporarily* -- it is expected to fall to zero only when all
- // APs have checked-in.
- //
- // In this case, the platform is supposed to set
- // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
- // enough for one AP to start initialization). The timeout will be
- // reached soon, and remaining APs are collected by watching
- // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
- // mid-process, while some APs have not completed initialization,
- // the behavior is undefined.
- //
- // (2) The check-in time for an individual AP is unbounded, and/or APs
- // may complete their initializations widely spread out. In
- // particular, some APs may finish initialization before some APs
- // even start.
- //
- // In this case, the platform is supposed to set
- // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
- // enumeration will always take that long (except when the boot CPU
- // count happens to be maximal, that is,
- // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
- // check-in before the timeout, and NumApsExecuting is assumed zero
- // at timeout. APs that miss the time-out may cause undefined
- // behavior.
- //
- TimedWaitForApFinish (
- CpuMpData,
- PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
- PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
- );
+ if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
+ //
+ // The AP enumeration algorithm below is suitable only when the
+ // platform can tell us the *exact* boot CPU count in advance.
+ //
+ // The wait below finishes only when the detected AP count reaches
+ // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
+ // takes. If at least one AP fails to check in (meaning a platform
+ // hardware bug), the detection hangs forever, by design. If the actual
+ // boot CPU count in the system is higher than
+ // PcdCpuBootLogicalProcessorNumber (meaning a platform
+ // misconfiguration), then some APs may complete initialization after
+ // the wait finishes, and cause undefined behavior.
+ //
+ TimedWaitForApFinish (
+ CpuMpData,
+ PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,
+ MAX_UINT32 // approx. 71 minutes
+ );
+ } else {
+ //
+ // The AP enumeration algorithm below is suitable for two use cases.
+ //
+ // (1) The check-in time for an individual AP is bounded, and APs run
+ // through their initialization routines strongly concurrently. In
+ // particular, the number of concurrently running APs
+ // ("NumApsExecuting") is never expected to fall to zero
+ // *temporarily* -- it is expected to fall to zero only when all
+ // APs have checked-in.
+ //
+ // In this case, the platform is supposed to set
+ // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
+ // enough for one AP to start initialization). The timeout will be
+ // reached soon, and remaining APs are collected by watching
+ // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
+ // mid-process, while some APs have not completed initialization,
+ // the behavior is undefined.
+ //
+ // (2) The check-in time for an individual AP is unbounded, and/or APs
+ // may complete their initializations widely spread out. In
+ // particular, some APs may finish initialization before some APs
+ // even start.
+ //
+ // In this case, the platform is supposed to set
+ // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
+ // enumeration will always take that long (except when the boot CPU
+ // count happens to be maximal, that is,
+ // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
+ // check-in before the timeout, and NumApsExecuting is assumed zero
+ // at timeout. APs that miss the time-out may cause undefined
+ // behavior.
+ //
+ TimedWaitForApFinish (
+ CpuMpData,
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
+ PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
+ );
- while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
- CpuPause();
+ while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
+ CpuPause();
+ }
}
} else {
//