1 | /** @file
|
---|
2 | Construct MP Services Protocol.
|
---|
3 |
|
---|
4 | The MP Services Protocol provides a generalized way of performing following tasks:
|
---|
5 | - Retrieving information of multi-processor environment and MP-related status of
|
---|
6 | specific processors.
|
---|
7 | - Dispatching user-provided function to APs.
|
---|
8 | - Maintain MP-related processor status.
|
---|
9 |
|
---|
10 | The MP Services Protocol must be produced on any system with more than one logical
|
---|
11 | processor.
|
---|
12 |
|
---|
13 | The Protocol is available only during boot time.
|
---|
14 |
|
---|
15 | MP Services Protocol is hardware-independent. Most of the logic of this protocol
|
---|
16 | is architecturally neutral. It abstracts the multi-processor environment and
|
---|
17 | status of processors, and provides interfaces to retrieve information, maintain,
|
---|
18 | and dispatch.
|
---|
19 |
|
---|
20 | MP Services Protocol may be consumed by ACPI module. The ACPI module may use this
|
---|
21 | protocol to retrieve data that are needed for an MP platform and report them to OS.
|
---|
22 | MP Services Protocol may also be used to program and configure processors, such
|
---|
23 | as MTRR synchronization for memory space attributes setting in DXE Services.
|
---|
24 | MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot
|
---|
25 | by taking advantage of the processing capabilities of the APs, for example, using
|
---|
26 | APs to help test system memory in parallel with other device initialization.
|
---|
27 | Diagnostics applications may also use this protocol for multi-processor.
|
---|
28 |
|
---|
29 | Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
|
---|
30 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
31 |
|
---|
32 | **/
|
---|
33 |
|
---|
34 | #include <PiDxe.h>
|
---|
35 |
|
---|
36 | #include <Library/ArmLib.h>
|
---|
37 | #include <Library/ArmMmuLib.h>
|
---|
38 | #include <Library/ArmPlatformLib.h>
|
---|
39 | #include <Library/ArmSmcLib.h>
|
---|
40 | #include <Library/BaseMemoryLib.h>
|
---|
41 | #include <Library/CacheMaintenanceLib.h>
|
---|
42 | #include <Library/CpuExceptionHandlerLib.h>
|
---|
43 | #include <Library/DebugLib.h>
|
---|
44 | #include <Library/HobLib.h>
|
---|
45 | #include <Library/MemoryAllocationLib.h>
|
---|
46 | #include <Library/UefiBootServicesTableLib.h>
|
---|
47 | #include <Library/UefiLib.h>
|
---|
48 | #include <IndustryStandard/ArmStdSmc.h>
|
---|
49 | #include <Ppi/ArmMpCoreInfo.h>
|
---|
50 | #include <Protocol/LoadedImage.h>
|
---|
51 |
|
---|
52 | #include "MpServicesInternal.h"
|
---|
53 |
|
---|
54 | #define POLL_INTERVAL_US 50000
|
---|
55 |
|
---|
56 | STATIC CPU_MP_DATA mCpuMpData;
|
---|
57 | STATIC BOOLEAN mNonBlockingModeAllowed;
|
---|
58 | UINT64 *gApStacksBase;
|
---|
59 | UINT64 *gProcessorIDs;
|
---|
60 | CONST UINT64 gApStackSize = AP_STACK_SIZE;
|
---|
61 | VOID *gTtbr0;
|
---|
62 | UINTN gTcr;
|
---|
63 | UINTN gMair;
|
---|
64 |
|
---|
65 | STATIC
|
---|
66 | BOOLEAN
|
---|
67 | IsCurrentProcessorBSP (
|
---|
68 | VOID
|
---|
69 | );
|
---|
70 |
|
---|
71 | /** Turns on the specified core using PSCI and executes the user-supplied
|
---|
72 | function that's been configured via a previous call to SetApProcedure.
|
---|
73 |
|
---|
74 | @param ProcessorIndex The index of the core to turn on.
|
---|
75 |
|
---|
76 | @retval EFI_SUCCESS Success.
|
---|
77 | @retval EFI_DEVICE_ERROR The processor could not be turned on.
|
---|
78 |
|
---|
79 | **/
|
---|
80 | STATIC
|
---|
81 | EFI_STATUS
|
---|
82 | EFIAPI
|
---|
83 | DispatchCpu (
|
---|
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 |
|
---|
116 | /** Returns whether the specified processor is the BSP.
|
---|
117 |
|
---|
118 | @param[in] ProcessorIndex The index the processor to check.
|
---|
119 |
|
---|
120 | @return TRUE if the processor is the BSP, FALSE otherwise.
|
---|
121 | **/
|
---|
122 | STATIC
|
---|
123 | BOOLEAN
|
---|
124 | IsProcessorBSP (
|
---|
125 | UINTN ProcessorIndex
|
---|
126 | )
|
---|
127 | {
|
---|
128 | EFI_PROCESSOR_INFORMATION *CpuInfo;
|
---|
129 |
|
---|
130 | CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
|
---|
131 |
|
---|
132 | return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0;
|
---|
133 | }
|
---|
134 |
|
---|
135 | /** Get the Application Processors state.
|
---|
136 |
|
---|
137 | @param[in] CpuData The pointer to CPU_AP_DATA of specified AP.
|
---|
138 |
|
---|
139 | @return The AP status.
|
---|
140 | **/
|
---|
141 | CPU_STATE
|
---|
142 | GetApState (
|
---|
143 | IN CPU_AP_DATA *CpuData
|
---|
144 | )
|
---|
145 | {
|
---|
146 | return CpuData->State;
|
---|
147 | }
|
---|
148 |
|
---|
149 | /** Configures the processor context with the user-supplied procedure and
|
---|
150 | argument.
|
---|
151 |
|
---|
152 | @param CpuData The processor context.
|
---|
153 | @param Procedure The user-supplied procedure.
|
---|
154 | @param ProcedureArgument The user-supplied procedure argument.
|
---|
155 |
|
---|
156 | **/
|
---|
157 | STATIC
|
---|
158 | VOID
|
---|
159 | SetApProcedure (
|
---|
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 |
|
---|
172 | /** Returns the index of the next processor that is blocked.
|
---|
173 |
|
---|
174 | @param[out] NextNumber The index of the next blocked processor.
|
---|
175 |
|
---|
176 | @retval EFI_SUCCESS Successfully found the next blocked processor.
|
---|
177 | @retval EFI_NOT_FOUND There are no blocked processors.
|
---|
178 |
|
---|
179 | **/
|
---|
180 | STATIC
|
---|
181 | EFI_STATUS
|
---|
182 | GetNextBlockedNumber (
|
---|
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 |
|
---|
208 | /** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout.
|
---|
209 |
|
---|
210 | @param[in] Timeout The time limit in microseconds remaining for
|
---|
211 | APs to return from Procedure.
|
---|
212 |
|
---|
213 | @retval StallTime Time of execution stall.
|
---|
214 | **/
|
---|
215 | STATIC
|
---|
216 | UINTN
|
---|
217 | CalculateAndStallInterval (
|
---|
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 |
|
---|
234 | /**
|
---|
235 | This service retrieves the number of logical processor in the platform
|
---|
236 | and the number of those logical processors that are enabled on this boot.
|
---|
237 | This service may only be called from the BSP.
|
---|
238 |
|
---|
239 | This function is used to retrieve the following information:
|
---|
240 | - The number of logical processors that are present in the system.
|
---|
241 | - The number of enabled logical processors in the system at the instant
|
---|
242 | this call is made.
|
---|
243 |
|
---|
244 | Because MP Service Protocol provides services to enable and disable processors
|
---|
245 | dynamically, the number of enabled logical processors may vary during the
|
---|
246 | course of a boot session.
|
---|
247 |
|
---|
248 | If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
|
---|
249 | If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
|
---|
250 | EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
|
---|
251 | is returned in NumberOfProcessors, the number of currently enabled processor
|
---|
252 | is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
|
---|
253 |
|
---|
254 | @param[in] This A pointer to the
|
---|
255 | EFI_MP_SERVICES_PROTOCOL instance.
|
---|
256 | @param[out] NumberOfProcessors Pointer to the total number of logical
|
---|
257 | processors in the system, including
|
---|
258 | the BSP and disabled APs.
|
---|
259 | @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
|
---|
260 | logical processors that exist in the
|
---|
261 | system, including the BSP.
|
---|
262 |
|
---|
263 | @retval EFI_SUCCESS The number of logical processors and enabled
|
---|
264 | logical processors was retrieved.
|
---|
265 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
266 | @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
|
---|
267 | @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
|
---|
268 |
|
---|
269 | **/
|
---|
270 | STATIC
|
---|
271 | EFI_STATUS
|
---|
272 | EFIAPI
|
---|
273 | GetNumberOfProcessors (
|
---|
274 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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 |
|
---|
292 | /**
|
---|
293 | Gets detailed MP-related information on the requested processor at the
|
---|
294 | instant this call is made. This service may only be called from the BSP.
|
---|
295 |
|
---|
296 | This service retrieves detailed MP-related information about any processor
|
---|
297 | on the platform. Note the following:
|
---|
298 | - The processor information may change during the course of a boot session.
|
---|
299 | - The information presented here is entirely MP related.
|
---|
300 |
|
---|
301 | Information regarding the number of caches and their sizes, frequency of
|
---|
302 | operation, slot numbers is all considered platform-related information and is
|
---|
303 | not provided by this service.
|
---|
304 |
|
---|
305 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
---|
306 | instance.
|
---|
307 | @param[in] ProcessorIndex The index of the processor.
|
---|
308 | @param[out] ProcessorInfoBuffer A pointer to the buffer where information
|
---|
309 | for the requested processor is deposited.
|
---|
310 |
|
---|
311 | @retval EFI_SUCCESS Processor information was returned.
|
---|
312 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
313 | @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
|
---|
314 | @retval EFI_NOT_FOUND The processor with the handle specified by
|
---|
315 | ProcessorNumber does not exist in the platform.
|
---|
316 |
|
---|
317 | **/
|
---|
318 | STATIC
|
---|
319 | EFI_STATUS
|
---|
320 | EFIAPI
|
---|
321 | GetProcessorInfo (
|
---|
322 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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,
|
---|
344 | sizeof (EFI_PROCESSOR_INFORMATION)
|
---|
345 | );
|
---|
346 | return EFI_SUCCESS;
|
---|
347 | }
|
---|
348 |
|
---|
349 | /**
|
---|
350 | This service executes a caller provided function on all enabled APs. APs can
|
---|
351 | run either simultaneously or one at a time in sequence. This service supports
|
---|
352 | both blocking and non-blocking requests. The non-blocking requests use EFI
|
---|
353 | events so the BSP can detect when the APs have finished. This service may only
|
---|
354 | be called from the BSP.
|
---|
355 |
|
---|
356 | This function is used to dispatch all the enabled APs to the function
|
---|
357 | specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is
|
---|
358 | returned immediately and Procedure is not started on any AP.
|
---|
359 |
|
---|
360 | If SingleThread is TRUE, all the enabled APs execute the function specified by
|
---|
361 | Procedure one by one, in ascending order of processor handle number.
|
---|
362 | Otherwise, all the enabled APs execute the function specified by Procedure
|
---|
363 | simultaneously.
|
---|
364 |
|
---|
365 | If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
|
---|
366 | APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in
|
---|
367 | non-blocking mode, and the BSP returns from this service without waiting for
|
---|
368 | APs. If a non-blocking mode is requested after the UEFI Event
|
---|
369 | EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be
|
---|
370 | returned.
|
---|
371 |
|
---|
372 | If the timeout specified by TimeoutInMicroseconds expires before all APs
|
---|
373 | return from Procedure, then Procedure on the failed APs is terminated.
|
---|
374 | All enabled APs are always available for further calls to
|
---|
375 | EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
|
---|
376 | EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
|
---|
377 | content points to the list of processor handle numbers in which Procedure was
|
---|
378 | terminated.
|
---|
379 |
|
---|
380 | Note: It is the responsibility of the consumer of the
|
---|
381 | EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the
|
---|
382 | code that is executed on the BSP and the dispatched APs is well controlled.
|
---|
383 | The MP Services Protocol does not guarantee that the Procedure function is
|
---|
384 | MP-safe. Hence, the tasks that can be run in parallel are limited to certain
|
---|
385 | independent tasks and well-controlled exclusive code. EFI services and
|
---|
386 | protocols may not be called by APs unless otherwise specified.
|
---|
387 |
|
---|
388 | In blocking execution mode, BSP waits until all APs finish or
|
---|
389 | TimeoutInMicroseconds expires.
|
---|
390 |
|
---|
391 | In non-blocking execution mode, BSP is freed to return to the caller and then
|
---|
392 | proceed to the next task without having to wait for APs. The following
|
---|
393 | sequence needs to occur in a non-blocking execution mode:
|
---|
394 |
|
---|
395 | -# The caller that intends to use this MP Services Protocol in non-blocking
|
---|
396 | mode creates WaitEvent by calling the EFI CreateEvent() service. The
|
---|
397 | caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter
|
---|
398 | WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking
|
---|
399 | mode. It requests the function specified by Procedure to be started on
|
---|
400 | all the enabled APs, and releases the BSP to continue with other tasks.
|
---|
401 | -# The caller can use the CheckEvent() and WaitForEvent() services to check
|
---|
402 | the state of the WaitEvent created in step 1.
|
---|
403 | -# When the APs complete their task or TimeoutInMicroSecondss expires, the
|
---|
404 | MP Service signals WaitEvent by calling the EFI SignalEvent() function.
|
---|
405 | If FailedCpuList is not NULL, its content is available when WaitEvent is
|
---|
406 | signaled. If all APs returned from Procedure prior to the timeout, then
|
---|
407 | FailedCpuList is set to NULL. If not all APs return from Procedure before
|
---|
408 | the timeout, then FailedCpuList is filled in with the list of the failed
|
---|
409 | APs. The buffer is allocated by MP Service Protocol using AllocatePool().
|
---|
410 | It is the caller's responsibility to free the buffer with FreePool()
|
---|
411 | service.
|
---|
412 | -# This invocation of SignalEvent() function informs the caller that invoked
|
---|
413 | EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs
|
---|
414 | completed the specified task or a timeout occurred. The contents of
|
---|
415 | FailedCpuList can be examined to determine which APs did not complete the
|
---|
416 | specified task prior to the timeout.
|
---|
417 |
|
---|
418 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
---|
419 | instance.
|
---|
420 | @param[in] Procedure A pointer to the function to be run on
|
---|
421 | enabled APs of the system. See type
|
---|
422 | EFI_AP_PROCEDURE.
|
---|
423 | @param[in] SingleThread If TRUE, then all the enabled APs execute
|
---|
424 | the function specified by Procedure one by
|
---|
425 | one, in ascending order of processor
|
---|
426 | handle number. If FALSE, then all the
|
---|
427 | enabled APs execute the function specified
|
---|
428 | by Procedure simultaneously.
|
---|
429 | @param[in] WaitEvent The event created by the caller with
|
---|
430 | CreateEvent() service. If it is NULL,
|
---|
431 | then execute in blocking mode. BSP waits
|
---|
432 | until all APs finish or
|
---|
433 | TimeoutInMicroseconds expires. If it's
|
---|
434 | not NULL, then execute in non-blocking
|
---|
435 | mode. BSP requests the function specified
|
---|
436 | by Procedure to be started on all the
|
---|
437 | enabled APs, and go on executing
|
---|
438 | immediately. If all return from Procedure,
|
---|
439 | or TimeoutInMicroseconds expires, this
|
---|
440 | event is signaled. The BSP can use the
|
---|
441 | CheckEvent() or WaitForEvent()
|
---|
442 | services to check the state of event. Type
|
---|
443 | EFI_EVENT is defined in CreateEvent() in
|
---|
444 | the Unified Extensible Firmware Interface
|
---|
445 | Specification.
|
---|
446 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
|
---|
447 | for APs to return from Procedure, either
|
---|
448 | for blocking or non-blocking mode. Zero
|
---|
449 | means infinity. If the timeout expires
|
---|
450 | before all APs return from Procedure, then
|
---|
451 | Procedure on the failed APs is terminated.
|
---|
452 | All enabled APs are available for next
|
---|
453 | function assigned by
|
---|
454 | EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
---|
455 | or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
---|
456 | If the timeout expires in blocking mode,
|
---|
457 | BSP returns EFI_TIMEOUT. If the timeout
|
---|
458 | expires in non-blocking mode, WaitEvent
|
---|
459 | is signaled with SignalEvent().
|
---|
460 | @param[in] ProcedureArgument The parameter passed into Procedure for
|
---|
461 | all APs.
|
---|
462 | @param[out] FailedCpuList If NULL, this parameter is ignored.
|
---|
463 | Otherwise, if all APs finish successfully,
|
---|
464 | then its content is set to NULL. If not
|
---|
465 | all APs finish before timeout expires,
|
---|
466 | then its content is set to address of the
|
---|
467 | buffer holding handle numbers of the
|
---|
468 | failed APs.
|
---|
469 | The buffer is allocated by MP Service
|
---|
470 | Protocol, and it's the caller's
|
---|
471 | responsibility to free the buffer with
|
---|
472 | FreePool() service.
|
---|
473 | In blocking mode, it is ready for
|
---|
474 | consumption when the call returns. In
|
---|
475 | non-blocking mode, it is ready when
|
---|
476 | WaitEvent is signaled. The list of failed
|
---|
477 | CPU is terminated by END_OF_CPU_LIST.
|
---|
478 |
|
---|
479 | @retval EFI_SUCCESS In blocking mode, all APs have finished before
|
---|
480 | the timeout expired.
|
---|
481 | @retval EFI_SUCCESS In non-blocking mode, function has been
|
---|
482 | dispatched to all enabled APs.
|
---|
483 | @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
---|
484 | UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
---|
485 | signaled.
|
---|
486 | @retval EFI_DEVICE_ERROR Caller processor is AP.
|
---|
487 | @retval EFI_NOT_STARTED No enabled APs exist in the system.
|
---|
488 | @retval EFI_NOT_READY Any enabled APs are busy.
|
---|
489 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
---|
490 | all enabled APs have finished.
|
---|
491 | @retval EFI_INVALID_PARAMETER Procedure is NULL.
|
---|
492 |
|
---|
493 | **/
|
---|
494 | STATIC
|
---|
495 | EFI_STATUS
|
---|
496 | EFIAPI
|
---|
497 | StartupAllAPs (
|
---|
498 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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),
|
---|
538 | END_OF_CPU_LIST
|
---|
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) {
|
---|
552 | Status = StartupAllAPsWithWaitEvent (
|
---|
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 |
|
---|
587 | /**
|
---|
588 | This service lets the caller get one enabled AP to execute a caller-provided
|
---|
589 | function. The caller can request the BSP to either wait for the completion
|
---|
590 | of the AP or just proceed with the next task by using the EFI event mechanism.
|
---|
591 | See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
|
---|
592 | execution support. This service may only be called from the BSP.
|
---|
593 |
|
---|
594 | This function is used to dispatch one enabled AP to the function specified by
|
---|
595 | Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
|
---|
596 | is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
|
---|
597 | TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
|
---|
598 | BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
|
---|
599 | is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
|
---|
600 | then EFI_UNSUPPORTED must be returned.
|
---|
601 |
|
---|
602 | If the timeout specified by TimeoutInMicroseconds expires before the AP returns
|
---|
603 | from Procedure, then execution of Procedure by the AP is terminated. The AP is
|
---|
604 | available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
|
---|
605 | EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
---|
606 |
|
---|
607 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
---|
608 | instance.
|
---|
609 | @param[in] Procedure A pointer to the function to be run on
|
---|
610 | enabled APs of the system. See type
|
---|
611 | EFI_AP_PROCEDURE.
|
---|
612 | @param[in] ProcessorNumber The handle number of the AP. The range is
|
---|
613 | from 0 to the total number of logical
|
---|
614 | processors minus 1. The total number of
|
---|
615 | logical processors can be retrieved by
|
---|
616 | EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
---|
617 | @param[in] WaitEvent The event created by the caller with CreateEvent()
|
---|
618 | service. If it is NULL, then execute in
|
---|
619 | blocking mode. BSP waits until all APs finish
|
---|
620 | or TimeoutInMicroseconds expires. If it's
|
---|
621 | not NULL, then execute in non-blocking mode.
|
---|
622 | BSP requests the function specified by
|
---|
623 | Procedure to be started on all the enabled
|
---|
624 | APs, and go on executing immediately. If
|
---|
625 | all return from Procedure or TimeoutInMicroseconds
|
---|
626 | expires, this event is signaled. The BSP
|
---|
627 | can use the CheckEvent() or WaitForEvent()
|
---|
628 | services to check the state of event. Type
|
---|
629 | EFI_EVENT is defined in CreateEvent() in
|
---|
630 | the Unified Extensible Firmware Interface
|
---|
631 | Specification.
|
---|
632 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
|
---|
633 | APs to return from Procedure, either for
|
---|
634 | blocking or non-blocking mode. Zero means
|
---|
635 | infinity. If the timeout expires before
|
---|
636 | all APs return from Procedure, then Procedure
|
---|
637 | on the failed APs is terminated. All enabled
|
---|
638 | APs are available for next function assigned
|
---|
639 | by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
---|
640 | or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
---|
641 | If the timeout expires in blocking mode,
|
---|
642 | BSP returns EFI_TIMEOUT. If the timeout
|
---|
643 | expires in non-blocking mode, WaitEvent
|
---|
644 | is signaled with SignalEvent().
|
---|
645 | @param[in] ProcedureArgument The parameter passed into Procedure for
|
---|
646 | all APs.
|
---|
647 | @param[out] Finished If NULL, this parameter is ignored. In
|
---|
648 | blocking mode, this parameter is ignored.
|
---|
649 | In non-blocking mode, if AP returns from
|
---|
650 | Procedure before the timeout expires, its
|
---|
651 | content is set to TRUE. Otherwise, the
|
---|
652 | value is set to FALSE. The caller can
|
---|
653 | determine if the AP returned from Procedure
|
---|
654 | by evaluating this value.
|
---|
655 |
|
---|
656 | @retval EFI_SUCCESS In blocking mode, specified AP finished before
|
---|
657 | the timeout expires.
|
---|
658 | @retval EFI_SUCCESS In non-blocking mode, the function has been
|
---|
659 | dispatched to specified AP.
|
---|
660 | @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
---|
661 | UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
---|
662 | signaled.
|
---|
663 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
664 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
---|
665 | the specified AP has finished.
|
---|
666 | @retval EFI_NOT_READY The specified AP is busy.
|
---|
667 | @retval EFI_NOT_FOUND The processor with the handle specified by
|
---|
668 | ProcessorNumber does not exist.
|
---|
669 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
|
---|
670 | @retval EFI_INVALID_PARAMETER Procedure is NULL.
|
---|
671 |
|
---|
672 | **/
|
---|
673 | STATIC
|
---|
674 | EFI_STATUS
|
---|
675 | EFIAPI
|
---|
676 | StartupThisAP (
|
---|
677 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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 |
|
---|
728 | SetApProcedure (
|
---|
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,
|
---|
750 | TimerPeriodic,
|
---|
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 |
|
---|
774 | /**
|
---|
775 | This service switches the requested AP to be the BSP from that point onward.
|
---|
776 | This service changes the BSP for all purposes. This call can only be
|
---|
777 | performed by the current BSP.
|
---|
778 |
|
---|
779 | This service switches the requested AP to be the BSP from that point onward.
|
---|
780 | This service changes the BSP for all purposes. The new BSP can take over the
|
---|
781 | execution of the old BSP and continue seamlessly from where the old one left
|
---|
782 | off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
|
---|
783 | is signaled.
|
---|
784 |
|
---|
785 | If the BSP cannot be switched prior to the return from this service, then
|
---|
786 | EFI_UNSUPPORTED must be returned.
|
---|
787 |
|
---|
788 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
---|
789 | @param[in] ProcessorNumber The handle number of AP that is to become the new
|
---|
790 | BSP. The range is from 0 to the total number of
|
---|
791 | logical processors minus 1. The total number of
|
---|
792 | logical processors can be retrieved by
|
---|
793 | EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
---|
794 | @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
|
---|
795 | enabled AP. Otherwise, it will be disabled.
|
---|
796 |
|
---|
797 | @retval EFI_SUCCESS BSP successfully switched.
|
---|
798 | @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
|
---|
799 | this service returning.
|
---|
800 | @retval EFI_UNSUPPORTED Switching the BSP is not supported.
|
---|
801 | @retval EFI_SUCCESS The calling processor is an AP.
|
---|
802 | @retval EFI_NOT_FOUND The processor with the handle specified by
|
---|
803 | ProcessorNumber does not exist.
|
---|
804 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
|
---|
805 | a disabled AP.
|
---|
806 | @retval EFI_NOT_READY The specified AP is busy.
|
---|
807 |
|
---|
808 | **/
|
---|
809 | STATIC
|
---|
810 | EFI_STATUS
|
---|
811 | EFIAPI
|
---|
812 | SwitchBSP (
|
---|
813 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
814 | IN UINTN ProcessorNumber,
|
---|
815 | IN BOOLEAN EnableOldBSP
|
---|
816 | )
|
---|
817 | {
|
---|
818 | return EFI_UNSUPPORTED;
|
---|
819 | }
|
---|
820 |
|
---|
821 | /**
|
---|
822 | This service lets the caller enable or disable an AP from this point onward.
|
---|
823 | This service may only be called from the BSP.
|
---|
824 |
|
---|
825 | This service allows the caller enable or disable an AP from this point onward.
|
---|
826 | The caller can optionally specify the health status of the AP by Health. If
|
---|
827 | an AP is being disabled, then the state of the disabled AP is implementation
|
---|
828 | dependent. If an AP is enabled, then the implementation must guarantee that a
|
---|
829 | complete initialization sequence is performed on the AP, so the AP is in a state
|
---|
830 | that is compatible with an MP operating system. This service may not be supported
|
---|
831 | after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
|
---|
832 |
|
---|
833 | If the enable or disable AP operation cannot be completed prior to the return
|
---|
834 | from this service, then EFI_UNSUPPORTED must be returned.
|
---|
835 |
|
---|
836 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
---|
837 | @param[in] ProcessorNumber The handle number of AP that is to become the new
|
---|
838 | BSP. The range is from 0 to the total number of
|
---|
839 | logical processors minus 1. The total number of
|
---|
840 | logical processors can be retrieved by
|
---|
841 | EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
---|
842 | @param[in] EnableAP Specifies the new state for the processor for
|
---|
843 | enabled, FALSE for disabled.
|
---|
844 | @param[in] HealthFlag If not NULL, a pointer to a value that specifies
|
---|
845 | the new health status of the AP. This flag
|
---|
846 | corresponds to StatusFlag defined in
|
---|
847 | EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
|
---|
848 | the PROCESSOR_HEALTH_STATUS_BIT is used. All other
|
---|
849 | bits are ignored. If it is NULL, this parameter
|
---|
850 | is ignored.
|
---|
851 |
|
---|
852 | @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
|
---|
853 | @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
|
---|
854 | prior to this service returning.
|
---|
855 | @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
|
---|
856 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
857 | @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
|
---|
858 | does not exist.
|
---|
859 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
|
---|
860 |
|
---|
861 | **/
|
---|
862 | STATIC
|
---|
863 | EFI_STATUS
|
---|
864 | EFIAPI
|
---|
865 | EnableDisableAP (
|
---|
866 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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 |
|
---|
917 | /**
|
---|
918 | This return the handle number for the calling processor. This service may be
|
---|
919 | called from the BSP and APs.
|
---|
920 |
|
---|
921 | This service returns the processor handle number for the calling processor.
|
---|
922 | The returned value is in the range from 0 to the total number of logical
|
---|
923 | processors minus 1. The total number of logical processors can be retrieved
|
---|
924 | with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
|
---|
925 | called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
|
---|
926 | is returned. Otherwise, the current processors handle number is returned in
|
---|
927 | ProcessorNumber, and EFI_SUCCESS is returned.
|
---|
928 |
|
---|
929 | @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
---|
930 | @param[out] ProcessorNumber The handle number of AP that is to become the new
|
---|
931 | BSP. The range is from 0 to the total number of
|
---|
932 | logical processors minus 1. The total number of
|
---|
933 | logical processors can be retrieved by
|
---|
934 | EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
---|
935 |
|
---|
936 | @retval EFI_SUCCESS The current processor handle number was returned
|
---|
937 | in ProcessorNumber.
|
---|
938 | @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
|
---|
939 |
|
---|
940 | **/
|
---|
941 | STATIC
|
---|
942 | EFI_STATUS
|
---|
943 | EFIAPI
|
---|
944 | WhoAmI (
|
---|
945 | IN EFI_MP_SERVICES_PROTOCOL *This,
|
---|
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 |
|
---|
967 | STATIC EFI_MP_SERVICES_PROTOCOL mMpServicesProtocol = {
|
---|
968 | GetNumberOfProcessors,
|
---|
969 | GetProcessorInfo,
|
---|
970 | StartupAllAPs,
|
---|
971 | StartupThisAP,
|
---|
972 | SwitchBSP,
|
---|
973 | EnableDisableAP,
|
---|
974 | WhoAmI
|
---|
975 | };
|
---|
976 |
|
---|
977 | /** Adds the specified processor the list of failed processors.
|
---|
978 |
|
---|
979 | @param ProcessorIndex The processor index to add.
|
---|
980 | @param ApState Processor state.
|
---|
981 |
|
---|
982 | **/
|
---|
983 | STATIC
|
---|
984 | VOID
|
---|
985 | AddProcessorToFailedList (
|
---|
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 |
|
---|
1017 | /** Handles the StartupAllAPs case where the timeout has occurred.
|
---|
1018 |
|
---|
1019 | **/
|
---|
1020 | STATIC
|
---|
1021 | VOID
|
---|
1022 | ProcessStartupAllAPsTimeout (
|
---|
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 |
|
---|
1050 | /** Updates the status of the APs.
|
---|
1051 |
|
---|
1052 | @param[in] ProcessorIndex The index of the AP to update.
|
---|
1053 | **/
|
---|
1054 | STATIC
|
---|
1055 | VOID
|
---|
1056 | UpdateApStatus (
|
---|
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 |
|
---|
1089 | SetApProcedure (
|
---|
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 |
|
---|
1113 | /**
|
---|
1114 | If a timeout is specified in StartupAllAps(), a timer is set, which invokes
|
---|
1115 | this procedure periodically to check whether all APs have finished.
|
---|
1116 |
|
---|
1117 | @param[in] Event The WaitEvent the user supplied.
|
---|
1118 | @param[in] Context The event context.
|
---|
1119 | **/
|
---|
1120 | STATIC
|
---|
1121 | VOID
|
---|
1122 | EFIAPI
|
---|
1123 | CheckAllAPsStatus (
|
---|
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)) {
|
---|
1138 | ProcessStartupAllAPsTimeout ();
|
---|
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,
|
---|
1150 | TimerCancel,
|
---|
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 |
|
---|
1167 | /** Invoked periodically via a timer to check the state of the processor.
|
---|
1168 |
|
---|
1169 | @param Event The event supplied by the timer expiration.
|
---|
1170 | @param Context The processor context.
|
---|
1171 |
|
---|
1172 | **/
|
---|
1173 | STATIC
|
---|
1174 | VOID
|
---|
1175 | EFIAPI
|
---|
1176 | CheckThisAPStatus (
|
---|
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 |
|
---|
1217 | /**
|
---|
1218 | This function is called by all processors (both BSP and AP) once and collects
|
---|
1219 | MP related data.
|
---|
1220 |
|
---|
1221 | @param BSP TRUE if the processor is the BSP.
|
---|
1222 | @param Mpidr The MPIDR for the specified processor. This should be
|
---|
1223 | the full MPIDR and not only the affinity bits.
|
---|
1224 | @param ProcessorIndex The index of the processor.
|
---|
1225 |
|
---|
1226 | @return EFI_SUCCESS if the data for the processor collected and filled in.
|
---|
1227 |
|
---|
1228 | **/
|
---|
1229 | STATIC
|
---|
1230 | EFI_STATUS
|
---|
1231 | FillInProcessorInformation (
|
---|
1232 | IN BOOLEAN BSP,
|
---|
1233 | IN UINTN Mpidr,
|
---|
1234 | IN UINTN ProcessorIndex
|
---|
1235 | )
|
---|
1236 | {
|
---|
1237 | EFI_PROCESSOR_INFORMATION *CpuInfo;
|
---|
1238 |
|
---|
1239 | CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
|
---|
1240 |
|
---|
1241 | CpuInfo->ProcessorId = GET_MPIDR_AFFINITY_BITS (Mpidr);
|
---|
1242 | CpuInfo->StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
|
---|
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);
|
---|
1265 | CpuInfo->ExtendedInformation.Location2.Thread = 0;
|
---|
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 |
|
---|
1276 | /** Initializes the MP Services system data
|
---|
1277 |
|
---|
1278 | @param NumberOfProcessors The number of processors, both BSP and AP.
|
---|
1279 | @param CoreInfo CPU information gathered earlier during boot.
|
---|
1280 |
|
---|
1281 | **/
|
---|
1282 | STATIC
|
---|
1283 | EFI_STATUS
|
---|
1284 | MpServicesInitialize (
|
---|
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,
|
---|
1319 | CheckAllAPsStatus,
|
---|
1320 | NULL,
|
---|
1321 | &mCpuMpData.CheckAllAPsEvent
|
---|
1322 | );
|
---|
1323 | ASSERT_EFI_ERROR (Status);
|
---|
1324 |
|
---|
1325 | gApStacksBase = AllocatePages (
|
---|
1326 | EFI_SIZE_TO_PAGES (
|
---|
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,
|
---|
1347 | CheckThisAPStatus,
|
---|
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 |
|
---|
1367 | WriteBackDataCacheRange (
|
---|
1368 | gProcessorIDs,
|
---|
1369 | (mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64)
|
---|
1370 | );
|
---|
1371 |
|
---|
1372 | mNonBlockingModeAllowed = TRUE;
|
---|
1373 |
|
---|
1374 | Status = EfiCreateEventReadyToBootEx (
|
---|
1375 | TPL_CALLBACK,
|
---|
1376 | ReadyToBootSignaled,
|
---|
1377 | NULL,
|
---|
1378 | &ReadyToBootEvent
|
---|
1379 | );
|
---|
1380 | ASSERT_EFI_ERROR (Status);
|
---|
1381 |
|
---|
1382 | return EFI_SUCCESS;
|
---|
1383 | }
|
---|
1384 |
|
---|
1385 | /**
|
---|
1386 | Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
|
---|
1387 | signaled. After this point, non-blocking mode is no longer allowed.
|
---|
1388 |
|
---|
1389 | @param Event Event whose notification function is being invoked.
|
---|
1390 | @param Context The pointer to the notification function's context,
|
---|
1391 | which is implementation-dependent.
|
---|
1392 |
|
---|
1393 | **/
|
---|
1394 | STATIC
|
---|
1395 | VOID
|
---|
1396 | EFIAPI
|
---|
1397 | ReadyToBootSignaled (
|
---|
1398 | IN EFI_EVENT Event,
|
---|
1399 | IN VOID *Context
|
---|
1400 | )
|
---|
1401 | {
|
---|
1402 | mNonBlockingModeAllowed = FALSE;
|
---|
1403 | }
|
---|
1404 |
|
---|
1405 | /** Initialize multi-processor support.
|
---|
1406 |
|
---|
1407 | @param ImageHandle Image handle.
|
---|
1408 | @param SystemTable System table.
|
---|
1409 |
|
---|
1410 | @return EFI_SUCCESS on success, or an error code.
|
---|
1411 |
|
---|
1412 | **/
|
---|
1413 | EFI_STATUS
|
---|
1414 | EFIAPI
|
---|
1415 | ArmPsciMpServicesDxeInitialize (
|
---|
1416 | IN EFI_HANDLE ImageHandle,
|
---|
1417 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
1418 | )
|
---|
1419 | {
|
---|
1420 | EFI_STATUS Status;
|
---|
1421 | EFI_HANDLE Handle;
|
---|
1422 | UINTN MaxCpus;
|
---|
1423 | EFI_LOADED_IMAGE_PROTOCOL *Image;
|
---|
1424 | EFI_HOB_GENERIC_HEADER *Hob;
|
---|
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 | //
|
---|
1443 | WriteBackDataCacheRange (Image->ImageBase, Image->ImageSize);
|
---|
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 |
|
---|
1480 | /** AP exception handler.
|
---|
1481 |
|
---|
1482 | @param InterruptType The AArch64 CPU exception type.
|
---|
1483 | @param SystemContext System context.
|
---|
1484 |
|
---|
1485 | **/
|
---|
1486 | STATIC
|
---|
1487 | VOID
|
---|
1488 | EFIAPI
|
---|
1489 | ApExceptionHandler (
|
---|
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 |
|
---|
1526 | /** C entry-point for the AP.
|
---|
1527 | This function gets called from the assembly function ApEntryPoint.
|
---|
1528 |
|
---|
1529 | **/
|
---|
1530 | VOID
|
---|
1531 | ApProcedure (
|
---|
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 |
|
---|
1569 | /** Returns whether the processor executing this function is the BSP.
|
---|
1570 |
|
---|
1571 | @return Whether the current processor is the BSP.
|
---|
1572 | **/
|
---|
1573 | STATIC
|
---|
1574 | BOOLEAN
|
---|
1575 | IsCurrentProcessorBSP (
|
---|
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 |
|
---|
1591 | /** Returns whether the specified processor is enabled.
|
---|
1592 |
|
---|
1593 | @param[in] ProcessorIndex The index of the processor to check.
|
---|
1594 |
|
---|
1595 | @return TRUE if the processor is enabled, FALSE otherwise.
|
---|
1596 | **/
|
---|
1597 | STATIC
|
---|
1598 | BOOLEAN
|
---|
1599 | IsProcessorEnabled (
|
---|
1600 | UINTN ProcessorIndex
|
---|
1601 | )
|
---|
1602 | {
|
---|
1603 | EFI_PROCESSOR_INFORMATION *CpuInfo;
|
---|
1604 |
|
---|
1605 | CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
|
---|
1606 |
|
---|
1607 | return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0;
|
---|
1608 | }
|
---|
1609 |
|
---|
1610 | /** Sets up the state for the StartupAllAPs function.
|
---|
1611 |
|
---|
1612 | @param SingleThread Whether the APs will execute sequentially.
|
---|
1613 |
|
---|
1614 | **/
|
---|
1615 | STATIC
|
---|
1616 | VOID
|
---|
1617 | StartupAllAPsPrepareState (
|
---|
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 |
|
---|
1677 | /** Handles execution of StartupAllAPs when a WaitEvent has been specified.
|
---|
1678 |
|
---|
1679 | @param Procedure The user-supplied procedure.
|
---|
1680 | @param ProcedureArgument The user-supplied procedure argument.
|
---|
1681 | @param WaitEvent The wait event to be signaled when the work is
|
---|
1682 | complete or a timeout has occurred.
|
---|
1683 | @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
|
---|
1684 | indicates an infinite timeout.
|
---|
1685 | @param SingleThread Whether the APs will execute sequentially.
|
---|
1686 | @param FailedCpuList User-supplied pointer for list of failed CPUs.
|
---|
1687 |
|
---|
1688 | @return EFI_SUCCESS on success.
|
---|
1689 | **/
|
---|
1690 | STATIC
|
---|
1691 | EFI_STATUS
|
---|
1692 | StartupAllAPsWithWaitEvent (
|
---|
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,
|
---|
1745 | TimerPeriodic,
|
---|
1746 | POLL_INTERVAL_US
|
---|
1747 | );
|
---|
1748 |
|
---|
1749 | return Status;
|
---|
1750 | }
|
---|
1751 |
|
---|
1752 | /** Handles execution of StartupAllAPs when no wait event has been specified.
|
---|
1753 |
|
---|
1754 | @param Procedure The user-supplied procedure.
|
---|
1755 | @param ProcedureArgument The user-supplied procedure argument.
|
---|
1756 | @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
|
---|
1757 | indicates an infinite timeout.
|
---|
1758 | @param SingleThread Whether the APs will execute sequentially.
|
---|
1759 | @param FailedCpuList User-supplied pointer for list of failed CPUs.
|
---|
1760 |
|
---|
1761 | @return EFI_SUCCESS on success.
|
---|
1762 | **/
|
---|
1763 | STATIC
|
---|
1764 | EFI_STATUS
|
---|
1765 | StartupAllAPsNoWaitEvent (
|
---|
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 | }
|
---|