On 2015-10-27 22:24:08, Fan, Jeff wrote: > Jordan, > > Sending Fixed Interrupt IPI to wakeup AP required set EFLAGS.IF bit > on AP from my experience. (Please correct me if I am wrong.) As a > result, system timer interrupt maybe handled by AP instead of BSP.
The APs would have to be set up to use a different "nop" interrupt handler table. So, the APs wouldn't run any interrupt handling code. I don't think this would interfere with the BSP getting the interrupts and handling them. Another idea to investigate is sending an NMI to wake the AP. > Most of cases, AP will be in hlt state and require INIT-SIPI-SIPI to > be wakeup and work on many real platform. I don’t think 1S is > reasonable data. (Do you remember where 1S comes from?) See Laszlo's patch "OvmfPkg: increase MP services startup timeout" > Using MP service in my original patch need to take care some MP > service local sync data. That's why I think Laszlo's patch is > simpler and better. I think Laszlo's patch is fine. I think he should prepare it, get it reviewed, and then add it to his SMM series, and then it'll be ready if nothing better comes along. > Another point: Dynamically to change the AP state (CpuSleep and > software loop) makes the code complex. I find some dead lock issue > between BSP/AP, I will send the fix later. Long term, I also suggest > to drop this logic. Anyway, I need others' input on it before > dropping it. Could you give an overview of what your idea would be? I don't agree that the current code is too complex. But, I'm sure there could be bugs. :) -Jordan > -----Original Message----- > From: Justen, Jordan L > Sent: Wednesday, October 28, 2015 6:55 AM > To: Laszlo Ersek; [email protected] > Cc: Chen Fan; Kinney, Michael D; Fan, Jeff > Subject: Re: [edk2] [PATCH] UefiCpuPkg/CpuDxe: fix ExitBootServices() > callback in the presence of SMIs > > On 2015-10-27 05:20:12, Laszlo Ersek wrote: > > On 10/27/15 07:48, Jordan Justen wrote: > > > What about adding this code to mStartupCodeTemplate and sending the > > > APs there using the MP services? > > > > That was the idea in Jeff's earlier series, but it comes with a number > > of complications. The main one is that the HLT loop is entered as a > > "normal" StartupAllAPs() callback function. That necessitates tearing > > down parts of the environment that the MP services implementation > > builds up carefully at initialization. Other parts of that laborously > > constructed environment are plain irrelevant. > > Hmm. I assumed that starting an AP task should be much lower latency than > running INIT-SIPI-SIPI. Yet, examining the current code, it looks like we > generally call CpuSleep on the AP, and we only currently support resuming > from this state with an INIT-SIPI-SIPI. > > I think the APs could be woken from CPU sleep by an interrupt IPI, which > should be a lot less traumatic than INIT-SIPI-SIPI. This probably would > require a stub interrupt table to be setup for the APs. > > With that in place, we could then send the APs to the cli-hlt loop much > faster than via INIT-SIPI-SIPI. > > (Especially given that apparently this can take up to 1 second?! :) > > Another reason it could be good to work with the code is that we probably > should put the code into a shutdown mode, so if future MP service requests > come in, the MP services code doesn't try to restart the APs. (Ie, it should > just return an immediate error.) > > > Instead, this solution takes manual mode switching, paging, and stacks > > out of the picture, which is a good thing. The INIT-SIPI-SIPI sequence > > places the AP in real mode immediately, which is perfect for the > > minimal stub that we'd like the APs to run. > > I didn't consider the potential problem with leaving paging enabled, but if > we get the processor back into IA32 mode, we can leave the APs running > anywhere in the low 32-bit address space. It would be nice to not to leave > any memory allocated below 1MB if we can avoid it. > > > > Regardless of that, I think the C-based-asm would better fit in > > > ApStartup.c. > > > > I can move the code of course, but to me it doesn't seem overly > > justified. The C-based ASM in this question is only used by the > > ExitBootServices() callback, so (as you can see it in the patch) I > > could keep the template STATIC. If I move it to ApStartup.c, I'll have > > to make it extern (or else do the copying outside of the callback). I > > feel that this isn't overly justified, but if you insist, I can do it. > > Ok. This is fine. I am not a fan of the C-base-asm, despite the fact that I > wrote it, and I still think it is better than separate assembly files. > (Having only NASM be used in EDK II might change my mind.) > > I guess I just don't want to see it proliferate too much. :) > > > > Why not just a cli-hlt loop? > > > > Because if the ExitBootServices() callback doesn't wait until all APs > > abort and abandon the MP services idle loop -- or worse, an assigned > > MP services job that is still running -- then the BSP could > > immediately return from ExitBootServices(), and proceed to third party code > > that: > > - overwrites the page that used to host the idle loop, or > > - raises an SMI (via a variable service call for example) and then the > > APs might return to the old idle loop upon seeing RSM. > > > > The synchronization is in place so that the callback returns knowing > > that all APs have abandoned the old idle loop (or whatever job they > > were running). > > We could verify all APs have set CpuStateBusy. By that time it seems > extremely likely that all APs will be running in the runtime safe code. > > -Jordan > > > > > > Maybe if the MP services were used then the separate counter goes > > > away. > > > > I don't want it to go away. :) Plus, as far as I can see in > > StartupAllAPs() [UefiCpuPkg/CpuDxe/CpuMp.c], it doesn't wait for the > > *initiation* of the user procedure in any case. It can wait for the > > completion, but that's not good to us now -- our procedure is an > > infinite loop; it will not complete. All we care about is feedback > > that the old code has been abandoned completely. > > > > > How about 0 rather than 0x1234? > > > > I wanted something that would reflect the little endian encoding in a > > pure hexdump. I don't feel strongly about this though. > > > > > Can you provide a nasm source block in a comment like in ApStartup.c? > > > > Sure. > > > > Please follow up one by one on the points where I disagreed, so I can > > send v2. The two parts that I do feel strongly about are (a) not using > > MP services itself for this, (b) the counter / synchronization. > > > > Thanks > > Laszl > > > > > > > > -Jordan > > > > > > On 2015-10-26 14:33:09, Laszlo Ersek wrote: > > >> Our current callback puts the APs in wait-for-SIPI state, by > > >> sending them an INIT IPI. This works fine as long as the APs are > > >> not woken between > > >> ExitBootServices() and the time the runtime OS boots the APs. > > >> > > >> However, if a platform includes PiSmmCpuDxeSmm, and bases the > > >> runtime UEFI services (like the variable services) on SMM and SMIs, > > >> then two problem scenarios can be experienced: > > >> > > >> (a) On virtual platforms, the APs can be (spuriously?) woken by SMIs, > > >> between ExitBootServices() and the runtime OS's AP boot; for example > > >> by variable service calls. In this case the APs have no code to > > >> continue executing after the RSM instruction, which causes them to > > >> re-set. > > >> > > >> (b) On physical platforms, the APs might not wake from the wait-for-SIPI > > >> state at all, causing performance (or functional) problems with > > >> PiSmmCpuDxeSmm, dependent on the BSP/AP sync mode configured therein. > > >> > > >> Implement the following logic instead: > > >> > > >> - If there is no AP, there's no need for an ExitBootServices() callback. > > >> > > >> - Otherwise, reboot all APs with a minimal real-mode stub. Each AP shall > > >> bump a shared counter atomically at first, then spiral into an infinite > > >> HLT loop. This occurs regardless of what each AP has been doing at that > > >> moment. > > >> > > >> - APs can wake from HLT due to an SMI easily. > > >> > > >> - The BSP in the ExitBootServices() callback will wait until all APs have > > >> moved on to the stub. > > >> > > >> - Since we exit boot services time now with the original MP services > > >> startup code abandoned by all APs, we can even allocate that startup > > >> code in Boot Services Code type memory; only the new stub has to be > > >> AcpiNVS. > > >> > > >> Cc: Chen Fan <[email protected]> > > >> Cc: Jeff Fan <[email protected]> > > >> Cc: Jordan Justen <[email protected]> > > >> Cc: Michael Kinney <[email protected]> > > >> Contributed-under: TianoCore Contribution Agreement 1.0 > > >> Signed-off-by: Laszlo Ersek <[email protected]> > > >> --- > > >> > > >> Notes: > > >> So this would be option (2) from > > >> <http://thread.gmane.org/gmane.comp.bios.edk2.devel/3357/focus=3403>. > > >> With this patch in place, the AP reboots I had seen on TCG are gone. > > >> > > >> UefiCpuPkg/CpuDxe/ApStartup.c | 2 +- > > >> UefiCpuPkg/CpuDxe/CpuMp.c | 84 > > >> +++++++++++++++++++++++++++++++++++-------- > > >> 2 files changed, 71 insertions(+), 15 deletions(-) > > >> > > >> diff --git a/UefiCpuPkg/CpuDxe/ApStartup.c > > >> b/UefiCpuPkg/CpuDxe/ApStartup.c index 78fb26f..b8d736f 100644 > > >> --- a/UefiCpuPkg/CpuDxe/ApStartup.c > > >> +++ b/UefiCpuPkg/CpuDxe/ApStartup.c > > >> @@ -382,7 +382,7 @@ PrepareAPStartupCode ( > > >> StartAddress = BASE_1MB; > > >> Status = gBS->AllocatePages ( > > >> AllocateMaxAddress, > > >> - EfiACPIMemoryNVS, > > >> + EfiBootServicesCode, > > >> EFI_SIZE_TO_PAGES (sizeof (*StartupCode)), > > >> &StartAddress > > >> ); > > >> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c > > >> index 04c2f1f..98976a1 100644 > > >> --- a/UefiCpuPkg/CpuDxe/CpuMp.c > > >> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c > > >> @@ -30,6 +30,33 @@ VOID *mApStackStart = 0; volatile BOOLEAN > > >> mAPsAlreadyInitFinished = FALSE; volatile BOOLEAN > > >> mStopCheckAllAPsStatus = TRUE; > > >> > > >> +#pragma pack (1) > > >> +typedef struct { > > >> + UINT8 MovAx; > > >> + UINT16 AxValue; > > >> + UINT8 MovDsAx[2]; > > >> + UINT8 LockedWordCounterIncrement[6]; > > >> + > > >> + UINT8 Cli; > > >> + UINT8 Hlt; > > >> + UINT8 JmpToCli[2]; > > >> + > > >> + UINT16 WordCounter; > > >> +} CPU_AP_HLT_LOOP; > > >> +#pragma pack () > > >> + > > >> +STATIC CONST CPU_AP_HLT_LOOP mCpuApHltLoopTemplate = { > > >> + 0xB8, 0x1234, // mov ax,0x1234 > > >> + { 0x8E, 0xD8 }, // mov ds,ax > > >> + { 0xF0, 0x3E, 0xFF, 0x06, 0x0F, 0x00 }, // lock inc word > > >> +[ds:0xf] > > >> + > > >> + 0xFA, // cli @ offset 0xb > > >> + 0xF4, // hlt > > >> + { 0xEB, 0xFC }, // jmp short 0xb > > >> + > > >> + 0x0000 // WordCounter @ offset 0xf > > >> +}; > > >> + > > >> EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = { > > >> GetNumberOfProcessors, > > >> GetProcessorInfo, > > >> @@ -1659,11 +1686,31 @@ ExitBootServicesCallback ( > > >> IN VOID *Context > > >> ) > > >> { > > >> + CPU_AP_HLT_LOOP *CpuApHltLoop; > > >> + UINT16 ApCount; > > >> + > > >> + CpuApHltLoop = Context; > > >> + CopyMem (CpuApHltLoop, &mCpuApHltLoopTemplate, sizeof > > >> + mCpuApHltLoopTemplate); > > >> + > > >> // > > >> - // Avoid APs access invalid buff datas which allocated by > > >> BootServices, > > >> - // so we send INIT IPI to APs to let them wait for SIPI state. > > >> + // Point DS via AX to the page where the routine has been allocated. > > >> // > > >> - SendInitIpiAllExcludingSelf (); > > >> + CpuApHltLoop->AxValue = (UINT16)((UINTN)Context >> 4); DEBUG > > >> + ((EFI_D_VERBOSE, "%a: %a: HLT loop routine at %04x:%04x\n", > > >> + gEfiCallerBaseName, __FUNCTION__, CpuApHltLoop->AxValue, 0)); > > >> + > > >> + // > > >> + // Force all APs to execute the HLT loop. Wait until they all enter > > >> the code. > > >> + // > > >> + SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)Context); > > >> + > > >> + ApCount = (UINT16)(mMpSystemData.NumberOfProcessors - 1); while > > >> + (InterlockedCompareExchange16 ( > > >> + &CpuApHltLoop->WordCounter, > > >> + ApCount, > > >> + ApCount) != ApCount) { > > >> + CpuPause(); > > >> + } > > >> } > > >> > > >> /** > > >> @@ -1691,9 +1738,10 @@ InitializeMpSupport ( > > >> VOID > > >> ) > > >> { > > >> - EFI_STATUS Status; > > >> - MTRR_SETTINGS MtrrSettings; > > >> - UINTN Timeout; > > >> + EFI_STATUS Status; > > >> + MTRR_SETTINGS MtrrSettings; > > >> + UINTN Timeout; > > >> + EFI_PHYSICAL_ADDRESS CpuApHltLoopAddress; > > >> > > >> gMaxLogicalProcessorNumber = (UINTN) PcdGet32 > > >> (PcdCpuMaxLogicalProcessorNumber); > > >> if (gMaxLogicalProcessorNumber < 1) { @@ -1795,12 +1843,20 @@ > > >> InitializeMpSupport ( > > >> } > > >> } > > >> > > >> - Status = gBS->CreateEvent ( > > >> - EVT_SIGNAL_EXIT_BOOT_SERVICES, > > >> - TPL_CALLBACK, > > >> - ExitBootServicesCallback, > > >> - NULL, > > >> - &mExitBootServicesEvent > > >> - ); > > >> - ASSERT_EFI_ERROR (Status); > > >> + if (mMpSystemData.NumberOfProcessors > 1) { > > >> + CpuApHltLoopAddress = BASE_1MB - 1; > > >> + Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, > > >> + EFI_SIZE_TO_PAGES (sizeof (CPU_AP_HLT_LOOP)), > > >> + &CpuApHltLoopAddress); > > >> + ASSERT_EFI_ERROR (Status); > > >> + > > >> + Status = gBS->CreateEvent ( > > >> + EVT_SIGNAL_EXIT_BOOT_SERVICES, > > >> + TPL_CALLBACK, > > >> + ExitBootServicesCallback, > > >> + (VOID *)(UINTN)CpuApHltLoopAddress, > > >> + &mExitBootServicesEvent > > >> + ); > > >> + ASSERT_EFI_ERROR (Status); > > >> + } > > >> } > > >> -- > > >> 1.8.3.1 > > >> > > > > _______________________________________________ > > edk2-devel mailing list > > [email protected] > > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

