diff --git a/InOsEmuPkg/CpuRuntimeDxe/CpuDriver.h b/InOsEmuPkg/CpuRuntimeDxe/CpuDriver.h index 43b683014a..3ef251101f 100644 --- a/InOsEmuPkg/CpuRuntimeDxe/CpuDriver.h +++ b/InOsEmuPkg/CpuRuntimeDxe/CpuDriver.h @@ -109,6 +109,10 @@ typedef struct { BOOLEAN SingleThread; UINTN StartedNumber; PROCESSOR_DATA_BLOCK *ProcessorData; + UINTN Timeout; + UINTN *FailedList; + UINTN FailedListIndex; + BOOLEAN TimeoutActive; } MP_SYSTEM_DATA; diff --git a/InOsEmuPkg/CpuRuntimeDxe/MpService.c b/InOsEmuPkg/CpuRuntimeDxe/MpService.c index f49c55afa0..87b546bc5f 100644 --- a/InOsEmuPkg/CpuRuntimeDxe/MpService.c +++ b/InOsEmuPkg/CpuRuntimeDxe/MpService.c @@ -402,20 +402,24 @@ CpuMpServicesStartupAllAps ( if (FailedCpuList != NULL) { - FailledList = AllocatePool ((gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN)); - SetMemN (FailledList, (gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN), END_OF_CPU_LIST); - FailedListIndex = 0; - *FailedCpuList = FailledList; + gMPSystem.FailedList = AllocatePool ((gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN)); + if (gMPSystem.FailedList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + SetMemN (gMPSystem.FailedList, (gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN), END_OF_CPU_LIST); + gMPSystem.FailedListIndex = 0; + *FailedCpuList = gMPSystem.FailedList; } Timeout = TimeoutInMicroseconds; ListIndex = 0; - ProcessorData = NULL; + ProcessorData = NULL; - gMPSystem.FinishCount = 0; - gMPSystem.StartCount = 0; - APInitialState = CPU_STATE_READY; + gMPSystem.FinishCount = 0; + gMPSystem.StartCount = 0; + gMPSystem.SingleThread = SingleThread; + APInitialState = CPU_STATE_READY; for (Number = 0; Number < gMPSystem.NumberOfProcessors; Number++) { ProcessorData = &gMPSystem.ProcessorData[Number]; @@ -425,6 +429,12 @@ CpuMpServicesStartupAllAps ( continue; } + if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) { + // Skip Disabled processors + gMPSystem.FailedList[gMPSystem.FailedListIndex++] = Number; + continue; + } + // // Get APs prepared, and put failing APs into FailedCpuList // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready @@ -441,18 +451,42 @@ CpuMpServicesStartupAllAps ( if (SingleThread) { APInitialState = CPU_STATE_BLOCKED; } - - } else if (FailedCpuList != NULL) { - FailledList[FailedListIndex++] = Number; - ListIndex++; + } else { + return EFI_NOT_READY; } } - if (FailedCpuList != NULL) { - if (FailedListIndex == 0) { - FreePool (*FailedCpuList); - *FailedCpuList = NULL; + if (WaitEvent != NULL) { + for (Number = 0; Number < gMPSystem.NumberOfProcessors; Number++) { + ProcessorData = &gMPSystem.ProcessorData[Number]; + if ((ProcessorData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT) == PROCESSOR_AS_BSP_BIT) { + // Skip BSP + continue; + } + + if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) { + // Skip Disabled processors + continue; + } + + SetApProcedure (ProcessorData, Procedure, ProcedureArgument); } + + // + // Save data into private data structure, and create timer to poll AP state before exiting + // + gMPSystem.Procedure = Procedure; + gMPSystem.ProcedureArgument = ProcedureArgument; + gMPSystem.WaitEvent = WaitEvent; + gMPSystem.Timeout = TimeoutInMicroseconds; + gMPSystem.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0); + Status = gBS->SetTimer ( + gMPSystem.CheckAllAPsEvent, + TimerPeriodic, + gPollInterval + ); + return Status; + } while (TRUE) { @@ -463,6 +497,11 @@ CpuMpServicesStartupAllAps ( continue; } + if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) { + // Skip Disabled processors + continue; + } + gThread->MutexLock (ProcessorData->StateLock); ProcessorState = ProcessorData->State; gThread->MutexUnlock (ProcessorData->StateLock); @@ -490,29 +529,27 @@ CpuMpServicesStartupAllAps ( } if (gMPSystem.FinishCount == gMPSystem.StartCount) { - return EFI_SUCCESS; + Status = EFI_SUCCESS; + goto Done; } if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) { - // - // Save data into private data structure, and create timer to poll AP state before exiting - // - gMPSystem.Procedure = Procedure; - gMPSystem.ProcedureArgument = ProcedureArgument; - gMPSystem.WaitEvent = WaitEvent; - - Status = gBS->SetTimer ( - gMPSystem.CheckAllAPsEvent, - TimerPeriodic, - gPollInterval - ); - return EFI_TIMEOUT; + Status = EFI_TIMEOUT; + goto Done; } gBS->Stall (gPollInterval); Timeout -= gPollInterval; } +Done: + if (FailedCpuList != NULL) { + if (gMPSystem.FailedListIndex == 0) { + FreePool (*FailedCpuList); + *FailedCpuList = NULL; + } + } + return EFI_SUCCESS; } @@ -649,6 +686,18 @@ CpuMpServicesStartupThisAP ( SetApProcedure (&gMPSystem.ProcessorData[ProcessorNumber], Procedure, ProcedureArgument); + if (WaitEvent != NULL) { + // Non Blocking + gMPSystem.WaitEvent = WaitEvent; + Status = gBS->SetTimer ( + gMPSystem.ProcessorData[ProcessorNumber].CheckThisAPEvent, + TimerPeriodic, + gPollInterval + ); + return EFI_SUCCESS; + } + + // Blocking while (TRUE) { gThread->MutexLock (&gMPSystem.ProcessorData[ProcessorNumber].StateLock); if (gMPSystem.ProcessorData[ProcessorNumber].State == CPU_STATE_FINISHED) { @@ -660,12 +709,6 @@ CpuMpServicesStartupThisAP ( gThread->MutexUnlock (&gMPSystem.ProcessorData[ProcessorNumber].StateLock); if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) { - gMPSystem.WaitEvent = WaitEvent; - Status = gBS->SetTimer ( - gMPSystem.ProcessorData[ProcessorNumber].CheckThisAPEvent, - TimerPeriodic, - gPollInterval - ); return EFI_TIMEOUT; } @@ -929,7 +972,13 @@ CpuCheckAllAPsStatus ( PROCESSOR_DATA_BLOCK *NextData; EFI_STATUS Status; PROCESSOR_STATE ProcessorState; + UINTN Cpu; + BOOLEAN Found; + if (gMPSystem.TimeoutActive) { + gMPSystem.Timeout -= gPollInterval; + } + ProcessorData = (PROCESSOR_DATA_BLOCK *) Context; for (ProcessorNumber = 0; ProcessorNumber < gMPSystem.NumberOfProcessors; ProcessorNumber++) { @@ -938,6 +987,11 @@ CpuCheckAllAPsStatus ( continue; } + if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) { + // Skip Disabled processors + continue; + } + // This is an Interrupt Service routine. // This can grab a lock that is held in a non-interrupt // context. Meaning deadlock. Which is a bad thing. @@ -977,16 +1031,71 @@ CpuCheckAllAPsStatus ( break; } } + + if (gMPSystem.TimeoutActive && gMPSystem.Timeout < 0) { + // + // Timeout + // + if (gMPSystem.FailedList != NULL) { + for (ProcessorNumber = 0; ProcessorNumber < gMPSystem.NumberOfProcessors; ProcessorNumber++) { + if ((ProcessorData[ProcessorNumber].Info.StatusFlag & PROCESSOR_AS_BSP_BIT) == PROCESSOR_AS_BSP_BIT) { + // Skip BSP + continue; + } - if (gMPSystem.FinishCount == gMPSystem.StartCount) { - gBS->SetTimer ( - gMPSystem.CheckAllAPsEvent, - TimerCancel, - 0 - ); - Status = gBS->SignalEvent (gMPSystem.WaitEvent); + if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) { + // Skip Disabled processors + continue; + } + + // Mark the + Status = gThread->MutexTryLock (gMPSystem.ProcessorData[ProcessorNumber].StateLock); + if (EFI_ERROR(Status)) { + return; + } + ProcessorState = gMPSystem.ProcessorData[ProcessorNumber].State; + gThread->MutexUnlock (gMPSystem.ProcessorData[ProcessorNumber].StateLock); + + if (ProcessorState != CPU_STATE_IDLE) { + // If we are retrying make sure we don't double count + for (Cpu = 0, Found = FALSE; Cpu < gMPSystem.NumberOfProcessors; Cpu++) { + if (gMPSystem.FailedList[Cpu] == END_OF_CPU_LIST) { + break; + } + if (gMPSystem.FailedList[ProcessorNumber] == Cpu) { + Found = TRUE; + break; + } + } + if (!Found) { + gMPSystem.FailedList[gMPSystem.FailedListIndex++] = Cpu; + } + } + } + } + // Force terminal exit + gMPSystem.FinishCount = gMPSystem.StartCount; } + if (gMPSystem.FinishCount != gMPSystem.StartCount) { + return; + } + + gBS->SetTimer ( + gMPSystem.CheckAllAPsEvent, + TimerCancel, + 0 + ); + + if (gMPSystem.FailedListIndex == 0) { + if (gMPSystem.FailedList != NULL) { + FreePool (gMPSystem.FailedList); + gMPSystem.FailedList = NULL; + } + } + + Status = gBS->SignalEvent (gMPSystem.WaitEvent); + return ; } @@ -1004,8 +1113,8 @@ CpuCheckThisAPStatus ( ProcessorData = (PROCESSOR_DATA_BLOCK *) Context; // - // rdar://6260979 - This is an Interrupt Service routine. - // this can grab a lock that is held in a non-interrupt + // This is an Interrupt Service routine. + // that can grab a lock that is held in a non-interrupt // context. Meaning deadlock. Which is a badddd thing. // So, try lock it. If we can get it, cool, do our thing. // otherwise, just dump out & try again on the next iteration. diff --git a/InOsEmuPkg/Unix/UnixX64.dsc b/InOsEmuPkg/Unix/UnixX64.dsc index 3c867ef3fe..dcae0176ff 100644 --- a/InOsEmuPkg/Unix/UnixX64.dsc +++ b/InOsEmuPkg/Unix/UnixX64.dsc @@ -218,7 +218,7 @@ #define BOOT_IN_RECOVERY_MODE 0x20 gInOsEmuPkgTokenSpaceGuid.PcdEmuBootMode|0 - gInOsEmuPkgTokenSpaceGuid.PcdEmuApCount|L"0" + gInOsEmuPkgTokenSpaceGuid.PcdEmuApCount|L"1" gInOsEmuPkgTokenSpaceGuid.PcdEmuPhysicalDisk|L"E:RW;245760;512" gInOsEmuPkgTokenSpaceGuid.PcdEmuVirtualDisk|L"FW;40960;512"