TianoCore EDK2 master
Loading...
Searching...
No Matches
ArmPsciMpServicesDxe.c
Go to the documentation of this file.
1
34#include <PiDxe.h>
35
36#include <Library/ArmLib.h>
37#include <Library/ArmMmuLib.h>
39#include <Library/ArmSmcLib.h>
43#include <Library/DebugLib.h>
44#include <Library/HobLib.h>
47#include <Library/UefiLib.h>
49#include <Ppi/ArmMpCoreInfo.h>
51
52#include "MpServicesInternal.h"
53
54#define POLL_INTERVAL_US 50000
55
56STATIC CPU_MP_DATA mCpuMpData;
57STATIC BOOLEAN mNonBlockingModeAllowed;
58UINT64 *gApStacksBase;
59UINT64 *gProcessorIDs;
60CONST UINT64 gApStackSize = AP_STACK_SIZE;
61VOID *gTtbr0;
62UINTN gTcr;
63UINTN gMair;
64
66BOOLEAN
68 VOID
69 );
70
82EFIAPI
84 IN UINTN ProcessorIndex
85 )
86{
87 ARM_SMC_ARGS Args;
88 EFI_STATUS Status;
89
90 Status = EFI_SUCCESS;
91
92 mCpuMpData.CpuData[ProcessorIndex].State = CpuStateBusy;
93
94 /* Turn the AP on */
95 if (sizeof (Args.Arg0) == sizeof (UINT32)) {
96 Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH32;
97 } else {
98 Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64;
99 }
100
101 Args.Arg1 = gProcessorIDs[ProcessorIndex];
102 Args.Arg2 = (UINTN)ApEntryPoint;
103
104 ArmCallSmc (&Args);
105
106 if (Args.Arg0 == ARM_SMC_PSCI_RET_ALREADY_ON) {
107 Status = EFI_NOT_READY;
108 } else if (Args.Arg0 != ARM_SMC_PSCI_RET_SUCCESS) {
109 DEBUG ((DEBUG_ERROR, "PSCI_CPU_ON call failed: %d\n", Args.Arg0));
110 Status = EFI_DEVICE_ERROR;
111 }
112
113 return Status;
114}
115
122STATIC
123BOOLEAN
125 UINTN ProcessorIndex
126 )
127{
129
130 CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
131
132 return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0;
133}
134
141CPU_STATE
143 IN CPU_AP_DATA *CpuData
144 )
145{
146 return CpuData->State;
147}
148
157STATIC
158VOID
160 IN CPU_AP_DATA *CpuData,
161 IN EFI_AP_PROCEDURE Procedure,
162 IN VOID *ProcedureArgument
163 )
164{
165 ASSERT (CpuData != NULL);
166 ASSERT (Procedure != NULL);
167
168 CpuData->Parameter = ProcedureArgument;
169 CpuData->Procedure = Procedure;
170}
171
180STATIC
183 OUT UINTN *NextNumber
184 )
185{
186 UINTN Index;
187 CPU_STATE State;
188 CPU_AP_DATA *CpuData;
189
190 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
191 CpuData = &mCpuMpData.CpuData[Index];
192 if (IsProcessorBSP (Index)) {
193 // Skip BSP
194 continue;
195 }
196
197 State = CpuData->State;
198
199 if (State == CpuStateBlocked) {
200 *NextNumber = Index;
201 return EFI_SUCCESS;
202 }
203 }
204
205 return EFI_NOT_FOUND;
206}
207
215STATIC
216UINTN
218 IN UINTN Timeout
219 )
220{
221 UINTN StallTime;
222
223 if ((Timeout < POLL_INTERVAL_US) && (Timeout != 0)) {
224 StallTime = Timeout;
225 } else {
226 StallTime = POLL_INTERVAL_US;
227 }
228
229 gBS->Stall (StallTime);
230
231 return StallTime;
232}
233
270STATIC
272EFIAPI
275 OUT UINTN *NumberOfProcessors,
276 OUT UINTN *NumberOfEnabledProcessors
277 )
278{
279 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
280 return EFI_INVALID_PARAMETER;
281 }
282
283 if (!IsCurrentProcessorBSP ()) {
284 return EFI_DEVICE_ERROR;
285 }
286
287 *NumberOfProcessors = mCpuMpData.NumberOfProcessors;
288 *NumberOfEnabledProcessors = mCpuMpData.NumberOfEnabledProcessors;
289 return EFI_SUCCESS;
290}
291
318STATIC
320EFIAPI
323 IN UINTN ProcessorIndex,
324 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
325 )
326{
327 if (ProcessorInfoBuffer == NULL) {
328 return EFI_INVALID_PARAMETER;
329 }
330
331 if (!IsCurrentProcessorBSP ()) {
332 return EFI_DEVICE_ERROR;
333 }
334
335 ProcessorIndex &= ~CPU_V2_EXTENDED_TOPOLOGY;
336
337 if (ProcessorIndex >= mCpuMpData.NumberOfProcessors) {
338 return EFI_NOT_FOUND;
339 }
340
341 CopyMem (
342 ProcessorInfoBuffer,
343 &mCpuMpData.CpuData[ProcessorIndex].Info,
345 );
346 return EFI_SUCCESS;
347}
348
494STATIC
496EFIAPI
499 IN EFI_AP_PROCEDURE Procedure,
500 IN BOOLEAN SingleThread,
501 IN EFI_EVENT WaitEvent OPTIONAL,
502 IN UINTN TimeoutInMicroseconds,
503 IN VOID *ProcedureArgument OPTIONAL,
504 OUT UINTN **FailedCpuList OPTIONAL
505 )
506{
507 EFI_STATUS Status;
508
509 if (!IsCurrentProcessorBSP ()) {
510 return EFI_DEVICE_ERROR;
511 }
512
513 if ((mCpuMpData.NumberOfProcessors == 1) || (mCpuMpData.NumberOfEnabledProcessors == 1)) {
514 return EFI_NOT_STARTED;
515 }
516
517 if (Procedure == NULL) {
518 return EFI_INVALID_PARAMETER;
519 }
520
521 if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
522 return EFI_UNSUPPORTED;
523 }
524
525 if (FailedCpuList != NULL) {
526 mCpuMpData.FailedList = AllocateZeroPool (
527 (mCpuMpData.NumberOfProcessors + 1) *
528 sizeof (UINTN)
529 );
530 if (mCpuMpData.FailedList == NULL) {
531 return EFI_OUT_OF_RESOURCES;
532 }
533
534 SetMemN (
535 mCpuMpData.FailedList,
536 (mCpuMpData.NumberOfProcessors + 1) *
537 sizeof (UINTN),
539 );
540 mCpuMpData.FailedListIndex = 0;
541 *FailedCpuList = mCpuMpData.FailedList;
542 }
543
544 StartupAllAPsPrepareState (SingleThread);
545
546 // If any enabled APs are busy (ignoring the BSP), return EFI_NOT_READY
547 if (mCpuMpData.StartCount != (mCpuMpData.NumberOfEnabledProcessors - 1)) {
548 return EFI_NOT_READY;
549 }
550
551 if (WaitEvent != NULL) {
553 Procedure,
554 ProcedureArgument,
555 WaitEvent,
556 TimeoutInMicroseconds,
557 SingleThread,
558 FailedCpuList
559 );
560
561 if (EFI_ERROR (Status) && (FailedCpuList != NULL)) {
562 if (mCpuMpData.FailedListIndex == 0) {
563 FreePool (*FailedCpuList);
564 *FailedCpuList = NULL;
565 }
566 }
567 } else {
568 Status = StartupAllAPsNoWaitEvent (
569 Procedure,
570 ProcedureArgument,
571 TimeoutInMicroseconds,
572 SingleThread,
573 FailedCpuList
574 );
575
576 if (FailedCpuList != NULL) {
577 if (mCpuMpData.FailedListIndex == 0) {
578 FreePool (*FailedCpuList);
579 *FailedCpuList = NULL;
580 }
581 }
582 }
583
584 return Status;
585}
586
673STATIC
675EFIAPI
678 IN EFI_AP_PROCEDURE Procedure,
679 IN UINTN ProcessorNumber,
680 IN EFI_EVENT WaitEvent OPTIONAL,
681 IN UINTN TimeoutInMicroseconds,
682 IN VOID *ProcedureArgument OPTIONAL,
683 OUT BOOLEAN *Finished OPTIONAL
684 )
685{
686 EFI_STATUS Status;
687 UINTN Timeout;
688 CPU_AP_DATA *CpuData;
689
690 if (!IsCurrentProcessorBSP ()) {
691 return EFI_DEVICE_ERROR;
692 }
693
694 if (Procedure == NULL) {
695 return EFI_INVALID_PARAMETER;
696 }
697
698 if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
699 return EFI_NOT_FOUND;
700 }
701
702 CpuData = &mCpuMpData.CpuData[ProcessorNumber];
703
704 if (IsProcessorBSP (ProcessorNumber)) {
705 return EFI_INVALID_PARAMETER;
706 }
707
708 if (!IsProcessorEnabled (ProcessorNumber)) {
709 return EFI_INVALID_PARAMETER;
710 }
711
712 if ((GetApState (CpuData) != CpuStateIdle) &&
713 (GetApState (CpuData) != CpuStateFinished))
714 {
715 return EFI_NOT_READY;
716 }
717
718 if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
719 return EFI_UNSUPPORTED;
720 }
721
722 Timeout = TimeoutInMicroseconds;
723
724 CpuData->Timeout = TimeoutInMicroseconds;
725 CpuData->TimeTaken = 0;
726 CpuData->TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
727
729 CpuData,
730 Procedure,
731 ProcedureArgument
732 );
733
734 Status = DispatchCpu (ProcessorNumber);
735 if (EFI_ERROR (Status)) {
736 CpuData->State = CpuStateIdle;
737 return EFI_NOT_READY;
738 }
739
740 if (WaitEvent != NULL) {
741 // Non Blocking
742 if (Finished != NULL) {
743 CpuData->SingleApFinished = Finished;
744 *Finished = FALSE;
745 }
746
747 CpuData->WaitEvent = WaitEvent;
748 Status = gBS->SetTimer (
749 CpuData->CheckThisAPEvent,
751 POLL_INTERVAL_US
752 );
753
754 return EFI_SUCCESS;
755 }
756
757 // Blocking
758 while (TRUE) {
759 if (GetApState (CpuData) == CpuStateFinished) {
760 CpuData->State = CpuStateIdle;
761 break;
762 }
763
764 if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
765 return EFI_TIMEOUT;
766 }
767
768 Timeout -= CalculateAndStallInterval (Timeout);
769 }
770
771 return EFI_SUCCESS;
772}
773
809STATIC
811EFIAPI
814 IN UINTN ProcessorNumber,
815 IN BOOLEAN EnableOldBSP
816 )
817{
818 return EFI_UNSUPPORTED;
819}
820
862STATIC
864EFIAPI
867 IN UINTN ProcessorNumber,
868 IN BOOLEAN EnableAP,
869 IN UINT32 *HealthFlag OPTIONAL
870 )
871{
872 UINTN StatusFlag;
873 CPU_AP_DATA *CpuData;
874
875 StatusFlag = mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag;
876 CpuData = &mCpuMpData.CpuData[ProcessorNumber];
877
878 if (!IsCurrentProcessorBSP ()) {
879 return EFI_DEVICE_ERROR;
880 }
881
882 if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
883 return EFI_NOT_FOUND;
884 }
885
886 if (IsProcessorBSP (ProcessorNumber)) {
887 return EFI_INVALID_PARAMETER;
888 }
889
890 if (GetApState (CpuData) != CpuStateIdle) {
891 return EFI_UNSUPPORTED;
892 }
893
894 if (EnableAP) {
895 if (!IsProcessorEnabled (ProcessorNumber)) {
896 mCpuMpData.NumberOfEnabledProcessors++;
897 }
898
899 StatusFlag |= PROCESSOR_ENABLED_BIT;
900 } else {
901 if (IsProcessorEnabled (ProcessorNumber) && !IsProcessorBSP (ProcessorNumber)) {
902 mCpuMpData.NumberOfEnabledProcessors--;
903 }
904
905 StatusFlag &= ~PROCESSOR_ENABLED_BIT;
906 }
907
908 if ((HealthFlag != NULL) && !IsProcessorBSP (ProcessorNumber)) {
909 StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
910 StatusFlag |= (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT);
911 }
912
913 mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag = StatusFlag;
914 return EFI_SUCCESS;
915}
916
941STATIC
943EFIAPI
946 OUT UINTN *ProcessorNumber
947 )
948{
949 UINTN Index;
950 UINT64 ProcessorId;
951
952 if (ProcessorNumber == NULL) {
953 return EFI_INVALID_PARAMETER;
954 }
955
956 ProcessorId = GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ());
957 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
958 if (ProcessorId == gProcessorIDs[Index]) {
959 *ProcessorNumber = Index;
960 break;
961 }
962 }
963
964 return EFI_SUCCESS;
965}
966
967STATIC EFI_MP_SERVICES_PROTOCOL mMpServicesProtocol = {
972 SwitchBSP,
974 WhoAmI
975};
976
983STATIC
984VOID
986 UINTN ProcessorIndex,
987 CPU_STATE ApState
988 )
989{
990 UINTN Index;
991 BOOLEAN Found;
992
993 Found = FALSE;
994
995 if ((mCpuMpData.FailedList == NULL) ||
996 (ApState == CpuStateIdle) ||
997 (ApState == CpuStateFinished) ||
998 IsProcessorBSP (ProcessorIndex))
999 {
1000 return;
1001 }
1002
1003 // If we are retrying make sure we don't double count
1004 for (Index = 0; Index < mCpuMpData.FailedListIndex; Index++) {
1005 if (mCpuMpData.FailedList[Index] == ProcessorIndex) {
1006 Found = TRUE;
1007 break;
1008 }
1009 }
1010
1011 /* If the CPU isn't already in the FailedList, add it */
1012 if (!Found) {
1013 mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = ProcessorIndex;
1014 }
1015}
1016
1020STATIC
1021VOID
1023 VOID
1024 )
1025{
1026 CPU_AP_DATA *CpuData;
1027 UINTN Index;
1028
1029 if (mCpuMpData.FailedList == NULL) {
1030 return;
1031 }
1032
1033 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1034 CpuData = &mCpuMpData.CpuData[Index];
1035 if (IsProcessorBSP (Index)) {
1036 // Skip BSP
1037 continue;
1038 }
1039
1040 if (!IsProcessorEnabled (Index)) {
1041 // Skip Disabled processors
1042 continue;
1043 }
1044
1045 CpuData = &mCpuMpData.CpuData[Index];
1046 AddProcessorToFailedList (Index, GetApState (CpuData));
1047 }
1048}
1049
1054STATIC
1055VOID
1057 IN UINTN ProcessorIndex
1058 )
1059{
1060 EFI_STATUS Status;
1061 CPU_AP_DATA *CpuData;
1062 CPU_AP_DATA *NextCpuData;
1063 CPU_STATE State;
1064 UINTN NextNumber;
1065
1066 CpuData = &mCpuMpData.CpuData[ProcessorIndex];
1067
1068 if (IsProcessorBSP (ProcessorIndex)) {
1069 // Skip BSP
1070 return;
1071 }
1072
1073 if (!IsProcessorEnabled (ProcessorIndex)) {
1074 // Skip Disabled processors
1075 return;
1076 }
1077
1078 State = GetApState (CpuData);
1079
1080 switch (State) {
1081 case CpuStateFinished:
1082 if (mCpuMpData.SingleThread) {
1083 Status = GetNextBlockedNumber (&NextNumber);
1084 if (!EFI_ERROR (Status)) {
1085 NextCpuData = &mCpuMpData.CpuData[NextNumber];
1086
1087 NextCpuData->State = CpuStateReady;
1088
1090 NextCpuData,
1091 mCpuMpData.Procedure,
1092 mCpuMpData.ProcedureArgument
1093 );
1094
1095 Status = DispatchCpu (NextNumber);
1096 if (!EFI_ERROR (Status)) {
1097 mCpuMpData.StartCount++;
1098 } else {
1099 AddProcessorToFailedList (NextNumber, NextCpuData->State);
1100 }
1101 }
1102 }
1103
1104 CpuData->State = CpuStateIdle;
1105 mCpuMpData.FinishCount++;
1106 break;
1107
1108 default:
1109 break;
1110 }
1111}
1112
1120STATIC
1121VOID
1122EFIAPI
1124 IN EFI_EVENT Event,
1125 IN VOID *Context
1126 )
1127{
1128 EFI_STATUS Status;
1129 UINTN Index;
1130
1131 mCpuMpData.AllTimeTaken += POLL_INTERVAL_US;
1132
1133 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1134 UpdateApStatus (Index);
1135 }
1136
1137 if (mCpuMpData.AllTimeoutActive && (mCpuMpData.AllTimeTaken > mCpuMpData.AllTimeout)) {
1139
1140 // Force terminal exit
1141 mCpuMpData.FinishCount = mCpuMpData.StartCount;
1142 }
1143
1144 if (mCpuMpData.FinishCount != mCpuMpData.StartCount) {
1145 return;
1146 }
1147
1148 gBS->SetTimer (
1149 mCpuMpData.CheckAllAPsEvent,
1151 0
1152 );
1153
1154 if (mCpuMpData.FailedListIndex == 0) {
1155 if (mCpuMpData.FailedList != NULL) {
1156 // Since we don't have the original `FailedCpuList`
1157 // pointer here to set to NULL, don't free the
1158 // memory.
1159 }
1160 }
1161
1162 Status = gBS->SignalEvent (mCpuMpData.AllWaitEvent);
1163 ASSERT_EFI_ERROR (Status);
1164 mCpuMpData.AllWaitEvent = NULL;
1165}
1166
1173STATIC
1174VOID
1175EFIAPI
1177 IN EFI_EVENT Event,
1178 IN VOID *Context
1179 )
1180{
1181 EFI_STATUS Status;
1182 CPU_AP_DATA *CpuData;
1183 CPU_STATE State;
1184
1185 CpuData = Context;
1186
1187 CpuData->TimeTaken += POLL_INTERVAL_US;
1188
1189 State = GetApState (CpuData);
1190
1191 if (State == CpuStateFinished) {
1192 Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);
1193 ASSERT_EFI_ERROR (Status);
1194
1195 if (CpuData->SingleApFinished != NULL) {
1196 *(CpuData->SingleApFinished) = TRUE;
1197 }
1198
1199 if (CpuData->WaitEvent != NULL) {
1200 Status = gBS->SignalEvent (CpuData->WaitEvent);
1201 ASSERT_EFI_ERROR (Status);
1202 }
1203
1204 CpuData->State = CpuStateIdle;
1205 }
1206
1207 if (CpuData->TimeoutActive && (CpuData->TimeTaken > CpuData->Timeout)) {
1208 Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);
1209 if (CpuData->WaitEvent != NULL) {
1210 Status = gBS->SignalEvent (CpuData->WaitEvent);
1211 ASSERT_EFI_ERROR (Status);
1212 CpuData->WaitEvent = NULL;
1213 }
1214 }
1215}
1216
1229STATIC
1232 IN BOOLEAN BSP,
1233 IN UINTN Mpidr,
1234 IN UINTN ProcessorIndex
1235 )
1236{
1238
1239 CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
1240
1241 CpuInfo->ProcessorId = GET_MPIDR_AFFINITY_BITS (Mpidr);
1243
1244 if (BSP) {
1245 CpuInfo->StatusFlag |= PROCESSOR_AS_BSP_BIT;
1246 }
1247
1248 if ((Mpidr & MPIDR_MT_BIT) > 0) {
1249 CpuInfo->Location.Package = GET_MPIDR_AFF2 (Mpidr);
1250 CpuInfo->Location.Core = GET_MPIDR_AFF1 (Mpidr);
1251 CpuInfo->Location.Thread = GET_MPIDR_AFF0 (Mpidr);
1252
1253 CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF3 (Mpidr);
1254 CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF2 (Mpidr);
1255 CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF1 (Mpidr);
1256 CpuInfo->ExtendedInformation.Location2.Thread = GET_MPIDR_AFF0 (Mpidr);
1257 } else {
1258 CpuInfo->Location.Package = GET_MPIDR_AFF1 (Mpidr);
1259 CpuInfo->Location.Core = GET_MPIDR_AFF0 (Mpidr);
1260 CpuInfo->Location.Thread = 0;
1261
1262 CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF2 (Mpidr);
1263 CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF1 (Mpidr);
1264 CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF0 (Mpidr);
1266 }
1267
1268 mCpuMpData.CpuData[ProcessorIndex].State = BSP ? CpuStateBusy : CpuStateIdle;
1269
1270 mCpuMpData.CpuData[ProcessorIndex].Procedure = NULL;
1271 mCpuMpData.CpuData[ProcessorIndex].Parameter = NULL;
1272
1273 return EFI_SUCCESS;
1274}
1275
1282STATIC
1285 IN UINTN NumberOfProcessors,
1286 IN CONST ARM_CORE_INFO *CoreInfo
1287 )
1288{
1289 EFI_STATUS Status;
1290 UINTN Index;
1291 EFI_EVENT ReadyToBootEvent;
1292 BOOLEAN IsBsp;
1293
1294 //
1295 // Clear the data structure area first.
1296 //
1297 ZeroMem (&mCpuMpData, sizeof (CPU_MP_DATA));
1298 //
1299 // First BSP fills and inits all known values, including its own records.
1300 //
1301 mCpuMpData.NumberOfProcessors = NumberOfProcessors;
1302 mCpuMpData.NumberOfEnabledProcessors = NumberOfProcessors;
1303
1304 mCpuMpData.CpuData = AllocateZeroPool (
1305 mCpuMpData.NumberOfProcessors * sizeof (CPU_AP_DATA)
1306 );
1307
1308 if (mCpuMpData.CpuData == NULL) {
1309 return EFI_OUT_OF_RESOURCES;
1310 }
1311
1312 /* Allocate one extra for the sentinel entry at the end */
1313 gProcessorIDs = AllocateZeroPool ((mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64));
1314 ASSERT (gProcessorIDs != NULL);
1315
1316 Status = gBS->CreateEvent (
1317 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1318 TPL_CALLBACK,
1320 NULL,
1321 &mCpuMpData.CheckAllAPsEvent
1322 );
1323 ASSERT_EFI_ERROR (Status);
1324
1325 gApStacksBase = AllocatePages (
1327 mCpuMpData.NumberOfProcessors *
1328 gApStackSize
1329 )
1330 );
1331 ASSERT (gApStacksBase != NULL);
1332
1333 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1334 if (GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ()) == CoreInfo[Index].Mpidr) {
1335 IsBsp = TRUE;
1336 } else {
1337 IsBsp = FALSE;
1338 }
1339
1340 FillInProcessorInformation (IsBsp, CoreInfo[Index].Mpidr, Index);
1341
1342 gProcessorIDs[Index] = mCpuMpData.CpuData[Index].Info.ProcessorId;
1343
1344 Status = gBS->CreateEvent (
1345 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1346 TPL_CALLBACK,
1348 (VOID *)&mCpuMpData.CpuData[Index],
1349 &mCpuMpData.CpuData[Index].CheckThisAPEvent
1350 );
1351 ASSERT_EFI_ERROR (Status);
1352 }
1353
1354 gProcessorIDs[Index] = MAX_UINT64;
1355
1356 gTcr = ArmGetTCR ();
1357 gMair = ArmGetMAIR ();
1358 gTtbr0 = ArmGetTTBR0BaseAddress ();
1359
1360 //
1361 // The global pointer variables as well as the gProcessorIDs array contents
1362 // are accessed by the other cores so we must clean them to the PoC
1363 //
1364 WriteBackDataCacheRange (&gProcessorIDs, sizeof (UINT64 *));
1365 WriteBackDataCacheRange (&gApStacksBase, sizeof (UINT64 *));
1366
1368 gProcessorIDs,
1369 (mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64)
1370 );
1371
1372 mNonBlockingModeAllowed = TRUE;
1373
1375 TPL_CALLBACK,
1377 NULL,
1378 &ReadyToBootEvent
1379 );
1380 ASSERT_EFI_ERROR (Status);
1381
1382 return EFI_SUCCESS;
1383}
1384
1394STATIC
1395VOID
1396EFIAPI
1398 IN EFI_EVENT Event,
1399 IN VOID *Context
1400 )
1401{
1402 mNonBlockingModeAllowed = FALSE;
1403}
1404
1414EFIAPI
1416 IN EFI_HANDLE ImageHandle,
1417 IN EFI_SYSTEM_TABLE *SystemTable
1418 )
1419{
1420 EFI_STATUS Status;
1421 EFI_HANDLE Handle;
1422 UINTN MaxCpus;
1425 VOID *HobData;
1426 UINTN HobDataSize;
1427 CONST ARM_CORE_INFO *CoreInfo;
1428
1429 MaxCpus = 1;
1430
1431 Status = gBS->HandleProtocol (
1432 ImageHandle,
1433 &gEfiLoadedImageProtocolGuid,
1434 (VOID **)&Image
1435 );
1436 ASSERT_EFI_ERROR (Status);
1437
1438 //
1439 // Parts of the code in this driver may be executed by other cores running
1440 // with the MMU off so we need to ensure that everything is clean to the
1441 // point of coherency (PoC)
1442 //
1444
1445 Hob = GetFirstGuidHob (&gArmMpCoreInfoGuid);
1446 if (Hob != NULL) {
1447 HobData = GET_GUID_HOB_DATA (Hob);
1448 HobDataSize = GET_GUID_HOB_DATA_SIZE (Hob);
1449 CoreInfo = (ARM_CORE_INFO *)HobData;
1450 MaxCpus = HobDataSize / sizeof (ARM_CORE_INFO);
1451 }
1452
1453 if (MaxCpus == 1) {
1454 DEBUG ((DEBUG_WARN, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system"));
1455 // We are not MP so nothing to do
1456 return EFI_NOT_FOUND;
1457 }
1458
1459 Status = MpServicesInitialize (MaxCpus, CoreInfo);
1460 if (Status != EFI_SUCCESS) {
1461 ASSERT_EFI_ERROR (Status);
1462 return Status;
1463 }
1464
1465 //
1466 // Now install the MP services protocol.
1467 //
1468 Handle = NULL;
1469 Status = gBS->InstallMultipleProtocolInterfaces (
1470 &Handle,
1471 &gEfiMpServiceProtocolGuid,
1472 &mMpServicesProtocol,
1473 NULL
1474 );
1475 ASSERT_EFI_ERROR (Status);
1476
1477 return Status;
1478}
1479
1486STATIC
1487VOID
1488EFIAPI
1490 IN CONST EFI_EXCEPTION_TYPE InterruptType,
1491 IN CONST EFI_SYSTEM_CONTEXT SystemContext
1492 )
1493{
1494 ARM_SMC_ARGS Args;
1495 UINT64 Mpidr;
1496 UINTN Index;
1497 UINTN ProcessorIndex;
1498
1499 Mpidr = GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ());
1500
1501 Index = 0;
1502 ProcessorIndex = MAX_UINT64;
1503
1504 do {
1505 if (gProcessorIDs[Index] == Mpidr) {
1506 ProcessorIndex = Index;
1507 break;
1508 }
1509
1510 Index++;
1511 } while (gProcessorIDs[Index] != MAX_UINT64);
1512
1513 if (ProcessorIndex != MAX_UINT64) {
1514 mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished;
1515 ArmDataMemoryBarrier ();
1516 }
1517
1518 Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF;
1519 ArmCallSmc (&Args);
1520
1521 /* Should never be reached */
1522 ASSERT (FALSE);
1523 CpuDeadLoop ();
1524}
1525
1530VOID
1532 VOID
1533 )
1534{
1535 ARM_SMC_ARGS Args;
1536 EFI_AP_PROCEDURE UserApProcedure;
1537 VOID *UserApParameter;
1538 UINTN ProcessorIndex;
1539
1540 ProcessorIndex = 0;
1541
1542 WhoAmI (&mMpServicesProtocol, &ProcessorIndex);
1543
1544 /* Fetch the user-supplied procedure and parameter to execute */
1545 UserApProcedure = mCpuMpData.CpuData[ProcessorIndex].Procedure;
1546 UserApParameter = mCpuMpData.CpuData[ProcessorIndex].Parameter;
1547
1548 InitializeCpuExceptionHandlers (NULL);
1549 RegisterCpuInterruptHandler (EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS, ApExceptionHandler);
1550 RegisterCpuInterruptHandler (EXCEPT_AARCH64_IRQ, ApExceptionHandler);
1551 RegisterCpuInterruptHandler (EXCEPT_AARCH64_FIQ, ApExceptionHandler);
1552 RegisterCpuInterruptHandler (EXCEPT_AARCH64_SERROR, ApExceptionHandler);
1553
1554 UserApProcedure (UserApParameter);
1555
1556 mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished;
1557
1558 ArmDataMemoryBarrier ();
1559
1560 /* Since we're finished with this AP, turn it off */
1561 Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF;
1562 ArmCallSmc (&Args);
1563
1564 /* Should never be reached */
1565 ASSERT (FALSE);
1566 CpuDeadLoop ();
1567}
1568
1573STATIC
1574BOOLEAN
1576 VOID
1577 )
1578{
1579 EFI_STATUS Status;
1580 UINTN ProcessorIndex;
1581
1582 Status = WhoAmI (&mMpServicesProtocol, &ProcessorIndex);
1583 if (EFI_ERROR (Status)) {
1584 ASSERT_EFI_ERROR (Status);
1585 return FALSE;
1586 }
1587
1588 return IsProcessorBSP (ProcessorIndex);
1589}
1590
1597STATIC
1598BOOLEAN
1600 UINTN ProcessorIndex
1601 )
1602{
1604
1605 CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
1606
1607 return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0;
1608}
1609
1615STATIC
1616VOID
1618 IN BOOLEAN SingleThread
1619 )
1620{
1621 UINTN Index;
1622 CPU_STATE APInitialState;
1623 CPU_AP_DATA *CpuData;
1624
1625 mCpuMpData.FinishCount = 0;
1626 mCpuMpData.StartCount = 0;
1627 mCpuMpData.SingleThread = SingleThread;
1628
1629 APInitialState = CpuStateReady;
1630
1631 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1632 CpuData = &mCpuMpData.CpuData[Index];
1633
1634 //
1635 // Get APs prepared, and put failing APs into FailedCpuList.
1636 // If "SingleThread", only 1 AP will put into ready state, other AP will be
1637 // put into ready state 1 by 1, until the previous 1 finished its task.
1638 // If not "SingleThread", all APs are put into ready state from the
1639 // beginning
1640 //
1641
1642 if (IsProcessorBSP (Index)) {
1643 // Skip BSP
1644 continue;
1645 }
1646
1647 if (!IsProcessorEnabled (Index)) {
1648 // Skip Disabled processors
1649 if (mCpuMpData.FailedList != NULL) {
1650 mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
1651 }
1652
1653 continue;
1654 }
1655
1656 // If any APs finished after timing out, reset state to Idle
1657 if (GetApState (CpuData) == CpuStateFinished) {
1658 CpuData->State = CpuStateIdle;
1659 }
1660
1661 if (GetApState (CpuData) != CpuStateIdle) {
1662 // Skip busy processors
1663 if (mCpuMpData.FailedList != NULL) {
1664 mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
1665 }
1666 }
1667
1668 CpuData->State = APInitialState;
1669
1670 mCpuMpData.StartCount++;
1671 if (SingleThread) {
1672 APInitialState = CpuStateBlocked;
1673 }
1674 }
1675}
1676
1690STATIC
1693 IN EFI_AP_PROCEDURE Procedure,
1694 IN VOID *ProcedureArgument,
1695 IN EFI_EVENT WaitEvent,
1696 IN UINTN TimeoutInMicroseconds,
1697 IN BOOLEAN SingleThread,
1698 IN UINTN **FailedCpuList
1699 )
1700{
1701 EFI_STATUS Status;
1702 UINTN Index;
1703 CPU_AP_DATA *CpuData;
1704
1705 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1706 CpuData = &mCpuMpData.CpuData[Index];
1707 if (IsProcessorBSP (Index)) {
1708 // Skip BSP
1709 continue;
1710 }
1711
1712 if (!IsProcessorEnabled (Index)) {
1713 // Skip Disabled processors
1714 continue;
1715 }
1716
1717 if (GetApState (CpuData) == CpuStateReady) {
1718 SetApProcedure (CpuData, Procedure, ProcedureArgument);
1719 if ((mCpuMpData.StartCount == 0) || !SingleThread) {
1720 Status = DispatchCpu (Index);
1721 if (EFI_ERROR (Status)) {
1722 AddProcessorToFailedList (Index, CpuData->State);
1723 break;
1724 }
1725 }
1726 }
1727 }
1728
1729 if (EFI_ERROR (Status)) {
1730 return EFI_NOT_READY;
1731 }
1732
1733 //
1734 // Save data into private data structure, and create timer to poll AP state
1735 // before exiting
1736 //
1737 mCpuMpData.Procedure = Procedure;
1738 mCpuMpData.ProcedureArgument = ProcedureArgument;
1739 mCpuMpData.AllWaitEvent = WaitEvent;
1740 mCpuMpData.AllTimeout = TimeoutInMicroseconds;
1741 mCpuMpData.AllTimeTaken = 0;
1742 mCpuMpData.AllTimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
1743 Status = gBS->SetTimer (
1744 mCpuMpData.CheckAllAPsEvent,
1746 POLL_INTERVAL_US
1747 );
1748
1749 return Status;
1750}
1751
1763STATIC
1766 IN EFI_AP_PROCEDURE Procedure,
1767 IN VOID *ProcedureArgument,
1768 IN UINTN TimeoutInMicroseconds,
1769 IN BOOLEAN SingleThread,
1770 IN UINTN **FailedCpuList
1771 )
1772{
1773 EFI_STATUS Status;
1774 UINTN Index;
1775 UINTN NextIndex;
1776 UINTN Timeout;
1777 CPU_AP_DATA *CpuData;
1778 BOOLEAN DispatchError;
1779
1780 Timeout = TimeoutInMicroseconds;
1781 DispatchError = FALSE;
1782
1783 while (TRUE) {
1784 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1785 CpuData = &mCpuMpData.CpuData[Index];
1786 if (IsProcessorBSP (Index)) {
1787 // Skip BSP
1788 continue;
1789 }
1790
1791 if (!IsProcessorEnabled (Index)) {
1792 // Skip Disabled processors
1793 continue;
1794 }
1795
1796 switch (GetApState (CpuData)) {
1797 case CpuStateReady:
1798 SetApProcedure (CpuData, Procedure, ProcedureArgument);
1799 Status = DispatchCpu (Index);
1800 if (EFI_ERROR (Status)) {
1801 AddProcessorToFailedList (Index, CpuData->State);
1802 CpuData->State = CpuStateIdle;
1803 mCpuMpData.StartCount--;
1804 DispatchError = TRUE;
1805
1806 if (SingleThread) {
1807 // Dispatch the next available AP
1808 Status = GetNextBlockedNumber (&NextIndex);
1809 if (!EFI_ERROR (Status)) {
1810 mCpuMpData.CpuData[NextIndex].State = CpuStateReady;
1811 }
1812 }
1813 }
1814
1815 break;
1816
1817 case CpuStateFinished:
1818 mCpuMpData.FinishCount++;
1819 if (SingleThread) {
1820 Status = GetNextBlockedNumber (&NextIndex);
1821 if (!EFI_ERROR (Status)) {
1822 mCpuMpData.CpuData[NextIndex].State = CpuStateReady;
1823 }
1824 }
1825
1826 CpuData->State = CpuStateIdle;
1827 break;
1828
1829 default:
1830 break;
1831 }
1832 }
1833
1834 if (mCpuMpData.FinishCount == mCpuMpData.StartCount) {
1835 Status = EFI_SUCCESS;
1836 break;
1837 }
1838
1839 if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
1840 Status = EFI_TIMEOUT;
1841 break;
1842 }
1843
1844 Timeout -= CalculateAndStallInterval (Timeout);
1845 }
1846
1847 if (Status == EFI_TIMEOUT) {
1848 // Add any remaining CPUs to the FailedCpuList
1849 if (FailedCpuList != NULL) {
1850 for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
1851 AddProcessorToFailedList (Index, mCpuMpData.CpuData[Index].State);
1852 }
1853 }
1854 }
1855
1856 if (DispatchError) {
1857 Status = EFI_NOT_READY;
1858 }
1859
1860 return Status;
1861}
UINT64 UINTN
VOID *EFIAPI WriteBackDataCacheRange(IN VOID *Address, IN UINTN Length)
STATIC EFI_STATUS MpServicesInitialize(IN UINTN NumberOfProcessors, IN CONST ARM_CORE_INFO *CoreInfo)
STATIC EFI_STATUS EFIAPI StartupThisAP(IN EFI_MP_SERVICES_PROTOCOL *This, IN EFI_AP_PROCEDURE Procedure, IN UINTN ProcessorNumber, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT BOOLEAN *Finished OPTIONAL)
CPU_STATE GetApState(IN CPU_AP_DATA *CpuData)
STATIC EFI_STATUS FillInProcessorInformation(IN BOOLEAN BSP, IN UINTN Mpidr, IN UINTN ProcessorIndex)
STATIC EFI_STATUS EFIAPI SwitchBSP(IN EFI_MP_SERVICES_PROTOCOL *This, IN UINTN ProcessorNumber, IN BOOLEAN EnableOldBSP)
STATIC EFI_STATUS EFIAPI DispatchCpu(IN UINTN ProcessorIndex)
STATIC EFI_STATUS StartupAllAPsWithWaitEvent(IN EFI_AP_PROCEDURE Procedure, IN VOID *ProcedureArgument, IN EFI_EVENT WaitEvent, IN UINTN TimeoutInMicroseconds, IN BOOLEAN SingleThread, IN UINTN **FailedCpuList)
STATIC BOOLEAN IsProcessorBSP(UINTN ProcessorIndex)
EFI_STATUS EFIAPI ArmPsciMpServicesDxeInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
STATIC VOID StartupAllAPsPrepareState(IN BOOLEAN SingleThread)
VOID ApProcedure(VOID)
STATIC EFI_STATUS EFIAPI EnableDisableAP(IN EFI_MP_SERVICES_PROTOCOL *This, IN UINTN ProcessorNumber, IN BOOLEAN EnableAP, IN UINT32 *HealthFlag OPTIONAL)
STATIC EFI_STATUS EFIAPI GetProcessorInfo(IN EFI_MP_SERVICES_PROTOCOL *This, IN UINTN ProcessorIndex, OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer)
STATIC EFI_STATUS EFIAPI WhoAmI(IN EFI_MP_SERVICES_PROTOCOL *This, OUT UINTN *ProcessorNumber)
STATIC BOOLEAN IsProcessorEnabled(UINTN ProcessorIndex)
STATIC UINTN CalculateAndStallInterval(IN UINTN Timeout)
STATIC VOID EFIAPI CheckAllAPsStatus(IN EFI_EVENT Event, IN VOID *Context)
STATIC VOID EFIAPI ReadyToBootSignaled(IN EFI_EVENT Event, IN VOID *Context)
STATIC EFI_STATUS EFIAPI StartupAllAPs(IN EFI_MP_SERVICES_PROTOCOL *This, IN EFI_AP_PROCEDURE Procedure, IN BOOLEAN SingleThread, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT UINTN **FailedCpuList OPTIONAL)
STATIC VOID UpdateApStatus(IN UINTN ProcessorIndex)
STATIC EFI_STATUS StartupAllAPsNoWaitEvent(IN EFI_AP_PROCEDURE Procedure, IN VOID *ProcedureArgument, IN UINTN TimeoutInMicroseconds, IN BOOLEAN SingleThread, IN UINTN **FailedCpuList)
STATIC VOID SetApProcedure(IN CPU_AP_DATA *CpuData, IN EFI_AP_PROCEDURE Procedure, IN VOID *ProcedureArgument)
STATIC EFI_STATUS EFIAPI GetNumberOfProcessors(IN EFI_MP_SERVICES_PROTOCOL *This, OUT UINTN *NumberOfProcessors, OUT UINTN *NumberOfEnabledProcessors)
STATIC VOID AddProcessorToFailedList(UINTN ProcessorIndex, CPU_STATE ApState)
STATIC VOID EFIAPI CheckThisAPStatus(IN EFI_EVENT Event, IN VOID *Context)
STATIC BOOLEAN IsCurrentProcessorBSP(VOID)
STATIC VOID ProcessStartupAllAPsTimeout(VOID)
STATIC EFI_STATUS GetNextBlockedNumber(OUT UINTN *NextNumber)
STATIC VOID EFIAPI ApExceptionHandler(IN CONST EFI_EXCEPTION_TYPE InterruptType, IN CONST EFI_SYSTEM_CONTEXT SystemContext)
VOID ArmCallSmc(IN OUT ARM_SMC_ARGS *Args)
Definition: ArmSmcLibNull.c:14
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMemN(OUT VOID *Buffer, IN UINTN Length, IN UINTN Value)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
Definition: DebugSupport.h:517
#define END_OF_CPU_LIST
Definition: MpService.h:63
#define PROCESSOR_HEALTH_STATUS_BIT
Definition: MpService.h:84
#define PROCESSOR_AS_BSP_BIT
Definition: MpService.h:70
#define PROCESSOR_ENABLED_BIT
Definition: MpService.h:77
VOID ApEntryPoint(VOID)
VOID(EFIAPI * EFI_AP_PROCEDURE)(IN OUT VOID *Buffer)
Definition: PiMultiPhase.h:198
VOID *EFIAPI AllocatePages(IN UINTN Pages)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI EfiCreateEventReadyToBootEx(IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN VOID *NotifyContext OPTIONAL, OUT EFI_EVENT *ReadyToBootEvent)
Definition: UefiNotTiano.c:164
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerPeriodic
Definition: UefiSpec.h:535
UINT64 ImageSize
The size in bytes of the loaded image.
Definition: LoadedImage.h:68
VOID * ImageBase
The base address at which the image was loaded.
Definition: LoadedImage.h:67
EXTENDED_PROCESSOR_INFORMATION ExtendedInformation
Definition: MpService.h:182
EFI_CPU_PHYSICAL_LOCATION Location
Definition: MpService.h:178
EFI_CPU_PHYSICAL_LOCATION2 Location2
Definition: MpService.h:140