1 /** @file
2   Common header file for MP Initialize Library.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #ifndef _MP_LIB_H_
16 #define _MP_LIB_H_
17 
18 #include <PiPei.h>
19 
20 #include <Register/Cpuid.h>
21 #include <Register/Msr.h>
22 #include <Register/LocalApic.h>
23 #include <Register/Microcode.h>
24 
25 #include <Library/MpInitLib.h>
26 #include <Library/BaseLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/LocalApicLib.h>
31 #include <Library/CpuLib.h>
32 #include <Library/UefiCpuLib.h>
33 #include <Library/TimerLib.h>
34 #include <Library/SynchronizationLib.h>
35 #include <Library/MtrrLib.h>
36 #include <Library/HobLib.h>
37 
38 #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
39 
40 #define CPU_INIT_MP_LIB_HOB_GUID \
41   { \
42     0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
43   }
44 
45 //
46 //  The MP data for switch BSP
47 //
48 #define CPU_SWITCH_STATE_IDLE   0
49 #define CPU_SWITCH_STATE_STORED 1
50 #define CPU_SWITCH_STATE_LOADED 2
51 
52 //
53 // CPU exchange information for switch BSP
54 //
55 typedef struct {
56   UINT8             State;        // offset 0
57   UINTN             StackPointer; // offset 4 / 8
58   IA32_DESCRIPTOR   Gdtr;         // offset 8 / 16
59   IA32_DESCRIPTOR   Idtr;         // offset 14 / 26
60 } CPU_EXCHANGE_ROLE_INFO;
61 
62 //
63 // AP loop state when APs are in idle state
64 // It's value is the same with PcdCpuApLoopMode
65 //
66 typedef enum {
67   ApInHltLoop   = 1,
68   ApInMwaitLoop = 2,
69   ApInRunLoop   = 3
70 } AP_LOOP_MODE;
71 
72 //
73 // AP initialization state during APs wakeup
74 //
75 typedef enum {
76   ApInitConfig   = 1,
77   ApInitReconfig = 2,
78   ApInitDone     = 3
79 } AP_INIT_STATE;
80 
81 //
82 // AP state
83 //
84 typedef enum {
85   CpuStateIdle,
86   CpuStateReady,
87   CpuStateBusy,
88   CpuStateFinished,
89   CpuStateDisabled
90 } CPU_STATE;
91 
92 //
93 // CPU volatile registers around INIT-SIPI-SIPI
94 //
95 typedef struct {
96   UINTN                          Cr0;
97   UINTN                          Cr3;
98   UINTN                          Cr4;
99   UINTN                          Dr0;
100   UINTN                          Dr1;
101   UINTN                          Dr2;
102   UINTN                          Dr3;
103   UINTN                          Dr6;
104   UINTN                          Dr7;
105 } CPU_VOLATILE_REGISTERS;
106 
107 //
108 // AP related data
109 //
110 typedef struct {
111   SPIN_LOCK                      ApLock;
112   volatile UINT32                *StartupApSignal;
113   volatile UINTN                 ApFunction;
114   volatile UINTN                 ApFunctionArgument;
115   BOOLEAN                        CpuHealthy;
116   volatile CPU_STATE             State;
117   CPU_VOLATILE_REGISTERS         VolatileRegisters;
118   BOOLEAN                        Waiting;
119   BOOLEAN                        *Finished;
120   UINT64                         ExpectedTime;
121   UINT64                         CurrentTime;
122   UINT64                         TotalTime;
123   EFI_EVENT                      WaitEvent;
124 } CPU_AP_DATA;
125 
126 //
127 // Basic CPU information saved in Guided HOB.
128 // Because the contents will be shard between PEI and DXE,
129 // we need to make sure the each fields offset same in different
130 // architecture.
131 //
132 #pragma pack (1)
133 typedef struct {
134   UINT32                         InitialApicId;
135   UINT32                         ApicId;
136   UINT32                         Health;
137   UINT64                         ApTopOfStack;
138 } CPU_INFO_IN_HOB;
139 #pragma pack ()
140 
141 //
142 // AP reset code information including code address and size,
143 // this structure will be shared be C code and assembly code.
144 // It is natural aligned by design.
145 //
146 typedef struct {
147   UINT8             *RendezvousFunnelAddress;
148   UINTN             ModeEntryOffset;
149   UINTN             RendezvousFunnelSize;
150   UINT8             *RelocateApLoopFuncAddress;
151   UINTN             RelocateApLoopFuncSize;
152 } MP_ASSEMBLY_ADDRESS_MAP;
153 
154 typedef struct _CPU_MP_DATA  CPU_MP_DATA;
155 
156 #pragma pack(1)
157 
158 //
159 // MP CPU exchange information for AP reset code
160 // This structure is required to be packed because fixed field offsets
161 // into this structure are used in assembly code in this module
162 //
163 typedef struct {
164   UINTN                 Lock;
165   UINTN                 StackStart;
166   UINTN                 StackSize;
167   UINTN                 CFunction;
168   IA32_DESCRIPTOR       GdtrProfile;
169   IA32_DESCRIPTOR       IdtrProfile;
170   UINTN                 BufferStart;
171   UINTN                 ModeOffset;
172   UINTN                 NumApsExecuting;
173   UINTN                 CodeSegment;
174   UINTN                 DataSegment;
175   UINTN                 EnableExecuteDisable;
176   UINTN                 Cr3;
177   UINTN                 InitFlag;
178   CPU_INFO_IN_HOB       *CpuInfo;
179   CPU_MP_DATA           *CpuMpData;
180 } MP_CPU_EXCHANGE_INFO;
181 
182 #pragma pack()
183 
184 //
185 // CPU MP Data save in memory
186 //
187 struct _CPU_MP_DATA {
188   UINT64                         CpuInfoInHob;
189   UINT32                         CpuCount;
190   UINT32                         BspNumber;
191   //
192   // The above fields data will be passed from PEI to DXE
193   // Please make sure the fields offset same in the different
194   // architecture.
195   //
196   SPIN_LOCK                      MpLock;
197   UINTN                          Buffer;
198   UINTN                          CpuApStackSize;
199   MP_ASSEMBLY_ADDRESS_MAP        AddressMap;
200   UINTN                          WakeupBuffer;
201   UINTN                          BackupBuffer;
202   UINTN                          BackupBufferSize;
203   BOOLEAN                        SaveRestoreFlag;
204 
205   volatile UINT32                StartCount;
206   volatile UINT32                FinishedCount;
207   volatile UINT32                RunningCount;
208   BOOLEAN                        SingleThread;
209   EFI_AP_PROCEDURE               Procedure;
210   VOID                           *ProcArguments;
211   BOOLEAN                        *Finished;
212   UINT64                         ExpectedTime;
213   UINT64                         CurrentTime;
214   UINT64                         TotalTime;
215   EFI_EVENT                      WaitEvent;
216   UINTN                          **FailedCpuList;
217 
218   AP_INIT_STATE                  InitFlag;
219   BOOLEAN                        X2ApicEnable;
220   BOOLEAN                        SwitchBspFlag;
221   UINTN                          NewBspNumber;
222   CPU_EXCHANGE_ROLE_INFO         BSPInfo;
223   CPU_EXCHANGE_ROLE_INFO         APInfo;
224   MTRR_SETTINGS                  MtrrTable;
225   UINT8                          ApLoopMode;
226   UINT8                          ApTargetCState;
227   UINT16                         PmCodeSegment;
228   CPU_AP_DATA                    *CpuData;
229   volatile MP_CPU_EXCHANGE_INFO  *MpCpuExchangeInfo;
230 
231   UINT32                         CurrentTimerCount;
232   UINTN                          DivideValue;
233   UINT8                          Vector;
234   BOOLEAN                        PeriodicMode;
235   BOOLEAN                        TimerInterruptState;
236 };
237 
238 extern EFI_GUID mCpuInitMpLibHobGuid;
239 
240 /**
241   Assembly code to place AP into safe loop mode.
242 
243   Place AP into targeted C-State if MONITOR is supported, otherwise
244   place AP into hlt state.
245   Place AP in protected mode if the current is long mode. Due to AP maybe
246   wakeup by some hardware event. It could avoid accessing page table that
247   may not available during booting to OS.
248 
249   @param[in] MwaitSupport    TRUE indicates MONITOR is supported.
250                              FALSE indicates MONITOR is not supported.
251   @param[in] ApTargetCState  Target C-State value.
252   @param[in] PmCodeSegment   Protected mode code segment value.
253 **/
254 typedef
255 VOID
256 (EFIAPI * ASM_RELOCATE_AP_LOOP) (
257   IN BOOLEAN                 MwaitSupport,
258   IN UINTN                   ApTargetCState,
259   IN UINTN                   PmCodeSegment,
260   IN UINTN                   TopOfApStack,
261   IN UINTN                   NumberToFinish
262   );
263 
264 /**
265   Assembly code to get starting address and size of the rendezvous entry for APs.
266   Information for fixing a jump instruction in the code is also returned.
267 
268   @param[out] AddressMap  Output buffer for address map information.
269 **/
270 VOID
271 EFIAPI
272 AsmGetAddressMap (
273   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap
274   );
275 
276 /**
277   This function is called by both the BSP and the AP which is to become the BSP to
278   Exchange execution context including stack between them. After return from this
279   function, the BSP becomes AP and the AP becomes the BSP.
280 
281   @param[in] MyInfo      Pointer to buffer holding the exchanging information for the executing processor.
282   @param[in] OthersInfo  Pointer to buffer holding the exchanging information for the peer.
283 
284 **/
285 VOID
286 EFIAPI
287 AsmExchangeRole (
288   IN CPU_EXCHANGE_ROLE_INFO    *MyInfo,
289   IN CPU_EXCHANGE_ROLE_INFO    *OthersInfo
290   );
291 
292 /**
293   Get the pointer to CPU MP Data structure.
294 
295   @return  The pointer to CPU MP Data structure.
296 **/
297 CPU_MP_DATA *
298 GetCpuMpData (
299   VOID
300   );
301 
302 /**
303   Save the pointer to CPU MP Data structure.
304 
305   @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
306 **/
307 VOID
308 SaveCpuMpData (
309   IN CPU_MP_DATA   *CpuMpData
310   );
311 
312 /**
313   Allocate reset vector buffer.
314 
315   @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.
316 **/
317 VOID
318 AllocateResetVector (
319   IN OUT CPU_MP_DATA          *CpuMpData
320   );
321 
322 /**
323   Free AP reset vector buffer.
324 
325   @param[in]  CpuMpData  The pointer to CPU MP Data structure.
326 **/
327 VOID
328 FreeResetVector (
329   IN CPU_MP_DATA              *CpuMpData
330   );
331 
332 /**
333   This function will be called by BSP to wakeup AP.
334 
335   @param[in] CpuMpData          Pointer to CPU MP Data
336   @param[in] Broadcast          TRUE:  Send broadcast IPI to all APs
337                                 FALSE: Send IPI to AP by ApicId
338   @param[in] ProcessorNumber    The handle number of specified processor
339   @param[in] Procedure          The function to be invoked by AP
340   @param[in] ProcedureArgument  The argument to be passed into AP function
341 **/
342 VOID
343 WakeUpAP (
344   IN CPU_MP_DATA               *CpuMpData,
345   IN BOOLEAN                   Broadcast,
346   IN UINTN                     ProcessorNumber,
347   IN EFI_AP_PROCEDURE          Procedure,              OPTIONAL
348   IN VOID                      *ProcedureArgument      OPTIONAL
349   );
350 
351 /**
352   Initialize global data for MP support.
353 
354   @param[in] CpuMpData  The pointer to CPU MP Data structure.
355 **/
356 VOID
357 InitMpGlobalData (
358   IN CPU_MP_DATA               *CpuMpData
359   );
360 
361 /**
362   Worker function to execute a caller provided function on all enabled APs.
363 
364   @param[in]  Procedure               A pointer to the function to be run on
365                                       enabled APs of the system.
366   @param[in]  SingleThread            If TRUE, then all the enabled APs execute
367                                       the function specified by Procedure one by
368                                       one, in ascending order of processor handle
369                                       number.  If FALSE, then all the enabled APs
370                                       execute the function specified by Procedure
371                                       simultaneously.
372   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
373                                       service.
374   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
375                                       APs to return from Procedure, either for
376                                       blocking or non-blocking mode.
377   @param[in]  ProcedureArgument       The parameter passed into Procedure for
378                                       all APs.
379   @param[out] FailedCpuList           If all APs finish successfully, then its
380                                       content is set to NULL. If not all APs
381                                       finish before timeout expires, then its
382                                       content is set to address of the buffer
383                                       holding handle numbers of the failed APs.
384 
385   @retval EFI_SUCCESS             In blocking mode, all APs have finished before
386                                   the timeout expired.
387   @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
388                                   to all enabled APs.
389   @retval others                  Failed to Startup all APs.
390 
391 **/
392 EFI_STATUS
393 StartupAllAPsWorker (
394   IN  EFI_AP_PROCEDURE          Procedure,
395   IN  BOOLEAN                   SingleThread,
396   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
397   IN  UINTN                     TimeoutInMicroseconds,
398   IN  VOID                      *ProcedureArgument      OPTIONAL,
399   OUT UINTN                     **FailedCpuList         OPTIONAL
400   );
401 
402 /**
403   Worker function to let the caller get one enabled AP to execute a caller-provided
404   function.
405 
406   @param[in]  Procedure               A pointer to the function to be run on
407                                       enabled APs of the system.
408   @param[in]  ProcessorNumber         The handle number of the AP.
409   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
410                                       service.
411   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
412                                       APs to return from Procedure, either for
413                                       blocking or non-blocking mode.
414   @param[in]  ProcedureArgument       The parameter passed into Procedure for
415                                       all APs.
416   @param[out] Finished                If AP returns from Procedure before the
417                                       timeout expires, its content is set to TRUE.
418                                       Otherwise, the value is set to FALSE.
419 
420   @retval EFI_SUCCESS             In blocking mode, specified AP finished before
421                                   the timeout expires.
422   @retval others                  Failed to Startup AP.
423 
424 **/
425 EFI_STATUS
426 StartupThisAPWorker (
427   IN  EFI_AP_PROCEDURE          Procedure,
428   IN  UINTN                     ProcessorNumber,
429   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
430   IN  UINTN                     TimeoutInMicroseconds,
431   IN  VOID                      *ProcedureArgument      OPTIONAL,
432   OUT BOOLEAN                   *Finished               OPTIONAL
433   );
434 
435 /**
436   Worker function to switch the requested AP to be the BSP from that point onward.
437 
438   @param[in] ProcessorNumber   The handle number of AP that is to become the new BSP.
439   @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
440                                enabled AP. Otherwise, it will be disabled.
441 
442   @retval EFI_SUCCESS          BSP successfully switched.
443   @retval others               Failed to switch BSP.
444 
445 **/
446 EFI_STATUS
447 SwitchBSPWorker (
448   IN UINTN                     ProcessorNumber,
449   IN BOOLEAN                   EnableOldBSP
450   );
451 
452 /**
453   Worker function to let the caller enable or disable an AP from this point onward.
454   This service may only be called from the BSP.
455 
456   @param[in] ProcessorNumber   The handle number of AP.
457   @param[in] EnableAP          Specifies the new state for the processor for
458                                enabled, FALSE for disabled.
459   @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
460                                the new health status of the AP.
461 
462   @retval EFI_SUCCESS          The specified AP was enabled or disabled successfully.
463   @retval others               Failed to Enable/Disable AP.
464 
465 **/
466 EFI_STATUS
467 EnableDisableApWorker (
468   IN  UINTN                     ProcessorNumber,
469   IN  BOOLEAN                   EnableAP,
470   IN  UINT32                    *HealthFlag OPTIONAL
471   );
472 
473 /**
474   Get pointer to CPU MP Data structure from GUIDed HOB.
475 
476   @return  The pointer to CPU MP Data structure.
477 **/
478 CPU_MP_DATA *
479 GetCpuMpDataFromGuidedHob (
480   VOID
481   );
482 
483 /** Checks status of specified AP.
484 
485   This function checks whether the specified AP has finished the task assigned
486   by StartupThisAP(), and whether timeout expires.
487 
488   @param[in]  ProcessorNumber       The handle number of processor.
489 
490   @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().
491   @retval EFI_TIMEOUT           The timeout expires.
492   @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.
493 **/
494 EFI_STATUS
495 CheckThisAP (
496   IN UINTN        ProcessorNumber
497   );
498 
499 /**
500   Checks status of all APs.
501 
502   This function checks whether all APs have finished task assigned by StartupAllAPs(),
503   and whether timeout expires.
504 
505   @retval EFI_SUCCESS           All APs have finished task assigned by StartupAllAPs().
506   @retval EFI_TIMEOUT           The timeout expires.
507   @retval EFI_NOT_READY         APs have not finished task and timeout has not expired.
508 **/
509 EFI_STATUS
510 CheckAllAPs (
511   VOID
512   );
513 
514 /**
515   Checks APs status and updates APs status if needed.
516 
517 **/
518 VOID
519 CheckAndUpdateApsStatus (
520   VOID
521   );
522 
523 /**
524   Detect whether specified processor can find matching microcode patch and load it.
525 
526   @param[in]  CpuMpData  The pointer to CPU MP Data structure.
527 **/
528 VOID
529 MicrocodeDetect (
530   IN CPU_MP_DATA             *CpuMpData
531   );
532 
533 /**
534   Detect whether Mwait-monitor feature is supported.
535 
536   @retval TRUE    Mwait-monitor feature is supported.
537   @retval FALSE   Mwait-monitor feature is not supported.
538 **/
539 BOOLEAN
540 IsMwaitSupport (
541   VOID
542   );
543 
544 /**
545   Notify function on End Of PEI PPI.
546 
547   On S3 boot, this function will restore wakeup buffer data.
548   On normal boot, this function will flag wakeup buffer to be un-used type.
549 
550   @param[in]  PeiServices        The pointer to the PEI Services Table.
551   @param[in]  NotifyDescriptor   Address of the notification descriptor data structure.
552   @param[in]  Ppi                Address of the PPI that was installed.
553 
554   @retval EFI_SUCCESS        When everything is OK.
555 **/
556 EFI_STATUS
557 EFIAPI
558 CpuMpEndOfPeiCallback (
559   IN EFI_PEI_SERVICES             **PeiServices,
560   IN EFI_PEI_NOTIFY_DESCRIPTOR    *NotifyDescriptor,
561   IN VOID                         *Ppi
562   );
563 
564 /**
565   Get available system memory below 1MB by specified size.
566 
567   @param[in]  CpuMpData  The pointer to CPU MP Data structure.
568 **/
569 VOID
570 BackupAndPrepareWakeupBuffer(
571   IN CPU_MP_DATA              *CpuMpData
572   );
573 
574 /**
575   Restore wakeup buffer data.
576 
577   @param[in]  CpuMpData  The pointer to CPU MP Data structure.
578 **/
579 VOID
580 RestoreWakeupBuffer(
581   IN CPU_MP_DATA              *CpuMpData
582   );
583 
584 /**
585   Enable Debug Agent to support source debugging on AP function.
586 
587 **/
588 VOID
589 EnableDebugAgent (
590   VOID
591   );
592 
593 #endif
594 
595