1 /** @file
2   Definitions to install Multiple Processor PPI.
3 
4   Copyright (c) 2015, 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 _CPU_MP_PEI_H_
16 #define _CPU_MP_PEI_H_
17 
18 #include <PiPei.h>
19 
20 #include <Ppi/MpServices.h>
21 #include <Ppi/SecPlatformInformation.h>
22 #include <Ppi/SecPlatformInformation2.h>
23 #include <Ppi/EndOfPeiPhase.h>
24 
25 #include <Register/Cpuid.h>
26 #include <Register/LocalApic.h>
27 
28 #include <Library/BaseLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/HobLib.h>
32 #include <Library/LocalApicLib.h>
33 #include <Library/MtrrLib.h>
34 #include <Library/PcdLib.h>
35 #include <Library/PeimEntryPoint.h>
36 #include <Library/PeiServicesLib.h>
37 #include <Library/ReportStatusCodeLib.h>
38 #include <Library/SynchronizationLib.h>
39 #include <Library/TimerLib.h>
40 #include <Library/UefiCpuLib.h>
41 #include <Library/CpuLib.h>
42 
43 #include "Microcode.h"
44 
45 //
46 // AP state
47 //
48 typedef enum {
49   CpuStateIdle,
50   CpuStateBusy,
51   CpuStateDisabled
52 } CPU_STATE;
53 
54 #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
55 
56 typedef enum {
57   ApInHltLoop   = 1,
58   ApInMwaitLoop = 2,
59   ApInRunLoop   = 3
60 } AP_LOOP_MODE;
61 
62 //
63 // AP reset code information
64 //
65 typedef struct {
66   UINT8             *RendezvousFunnelAddress;
67   UINTN             PModeEntryOffset;
68   UINTN             LModeEntryOffset;
69   UINTN             RendezvousFunnelSize;
70 } MP_ASSEMBLY_ADDRESS_MAP;
71 
72 //
73 // CPU exchange information for switch BSP
74 //
75 typedef struct {
76   UINT8             State;        // offset 0
77   UINTN             StackPointer; // offset 4 / 8
78   IA32_DESCRIPTOR   Gdtr;         // offset 8 / 16
79   IA32_DESCRIPTOR   Idtr;         // offset 14 / 26
80 } CPU_EXCHANGE_ROLE_INFO;
81 
82 typedef struct _PEI_CPU_MP_DATA  PEI_CPU_MP_DATA;
83 
84 #pragma pack(1)
85 
86 typedef union {
87   struct {
88     UINT32  LimitLow    : 16;
89     UINT32  BaseLow     : 16;
90     UINT32  BaseMid     : 8;
91     UINT32  Type        : 4;
92     UINT32  System      : 1;
93     UINT32  Dpl         : 2;
94     UINT32  Present     : 1;
95     UINT32  LimitHigh   : 4;
96     UINT32  Software    : 1;
97     UINT32  Reserved    : 1;
98     UINT32  DefaultSize : 1;
99     UINT32  Granularity : 1;
100     UINT32  BaseHigh    : 8;
101   } Bits;
102   UINT64  Uint64;
103 } IA32_GDT;
104 
105 //
106 // MP CPU exchange information for AP reset code
107 // This structure is required to be packed because fixed field offsets
108 // into this structure are used in assembly code in this module
109 //
110 typedef struct {
111   UINTN                 Lock;
112   UINTN                 StackStart;
113   UINTN                 StackSize;
114   UINTN                 CFunction;
115   IA32_DESCRIPTOR       GdtrProfile;
116   IA32_DESCRIPTOR       IdtrProfile;
117   UINTN                 BufferStart;
118   UINTN                 PmodeOffset;
119   UINTN                 NumApsExecuting;
120   UINTN                 LmodeOffset;
121   UINTN                 Cr3;
122   PEI_CPU_MP_DATA       *PeiCpuMpData;
123 } MP_CPU_EXCHANGE_INFO;
124 
125 #pragma pack()
126 
127 typedef struct {
128   UINTN                          Cr0;
129   UINTN                          Cr3;
130   UINTN                          Cr4;
131   UINTN                          Dr0;
132   UINTN                          Dr1;
133   UINTN                          Dr2;
134   UINTN                          Dr3;
135   UINTN                          Dr6;
136   UINTN                          Dr7;
137 } CPU_VOLATILE_REGISTERS;
138 
139 typedef struct {
140   volatile UINT32                *StartupApSignal;
141   UINT32                         ApicId;
142   EFI_HEALTH_FLAGS               Health;
143   CPU_STATE                      State;
144   BOOLEAN                        CpuHealthy;
145   CPU_VOLATILE_REGISTERS         VolatileRegisters;
146 } PEI_CPU_DATA;
147 
148 //
149 // PEI CPU MP Data save in memory
150 //
151 struct _PEI_CPU_MP_DATA {
152   SPIN_LOCK                      MpLock;
153   UINT32                         CpuCount;
154   UINT32                         BspNumber;
155   UINTN                          Buffer;
156   UINTN                          CpuApStackSize;
157   MP_ASSEMBLY_ADDRESS_MAP        AddressMap;
158   UINTN                          WakeupBuffer;
159   UINTN                          BackupBuffer;
160   UINTN                          BackupBufferSize;
161   UINTN                          ApFunction;
162   UINTN                          ApFunctionArgument;
163   volatile UINT32                FinishedCount;
164   BOOLEAN                        EndOfPeiFlag;
165   BOOLEAN                        InitFlag;
166   BOOLEAN                        X2ApicEnable;
167   CPU_EXCHANGE_ROLE_INFO         BSPInfo;
168   CPU_EXCHANGE_ROLE_INFO         APInfo;
169   MTRR_SETTINGS                  MtrrTable;
170   UINT8                          ApLoopMode;
171   UINT8                          ApTargetCState;
172   PEI_CPU_DATA                   *CpuData;
173   volatile MP_CPU_EXCHANGE_INFO  *MpCpuExchangeInfo;
174 };
175 extern EFI_PEI_PPI_DESCRIPTOR   mPeiCpuMpPpiDesc;
176 
177 
178 /**
179   Assembly code to get starting address and size of the rendezvous entry for APs.
180   Information for fixing a jump instruction in the code is also returned.
181 
182   @param AddressMap  Output buffer for address map information.
183 **/
184 VOID
185 EFIAPI
186 AsmGetAddressMap (
187   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap
188   );
189 
190 /**
191   Assembly code to load GDT table and update segment accordingly.
192 
193   @param Gdtr   Pointer to GDT descriptor
194 **/
195 VOID
196 EFIAPI
197 AsmInitializeGdt (
198   IN IA32_DESCRIPTOR  *Gdtr
199   );
200 
201 /**
202   Get available system memory below 1MB by specified size.
203 
204   @param PeiCpuMpData        Pointer to PEI CPU MP Data
205 **/
206 VOID
207 BackupAndPrepareWakeupBuffer(
208   IN PEI_CPU_MP_DATA         *PeiCpuMpData
209   );
210 
211 /**
212   Restore wakeup buffer data.
213 
214   @param PeiCpuMpData        Pointer to PEI CPU MP Data
215 **/
216 VOID
217 RestoreWakeupBuffer(
218   IN PEI_CPU_MP_DATA         *PeiCpuMpData
219   );
220 
221 /**
222   Notify function on End Of Pei PPI.
223 
224   On S3 boot, this function will restore wakeup buffer data.
225   On normal boot, this function will flag wakeup buffer to be un-used type.
226 
227   @param  PeiServices        The pointer to the PEI Services Table.
228   @param  NotifyDescriptor   Address of the notification descriptor data structure.
229   @param  Ppi                Address of the PPI that was installed.
230 
231   @retval EFI_SUCCESS        When everything is OK.
232 
233 **/
234 EFI_STATUS
235 EFIAPI
236 CpuMpEndOfPeiCallback (
237   IN      EFI_PEI_SERVICES        **PeiServices,
238   IN EFI_PEI_NOTIFY_DESCRIPTOR    *NotifyDescriptor,
239   IN VOID                         *Ppi
240   );
241 
242 /**
243   This function will be called by BSP to wakeup AP.
244 
245   @param PeiCpuMpData       Pointer to PEI CPU MP Data
246   @param Broadcast          TRUE:  Send broadcast IPI to all APs
247                             FALSE: Send IPI to AP by ApicId
248   @param ProcessorNumber    The handle number of specified processor
249   @param Procedure          The function to be invoked by AP
250   @param ProcedureArgument  The argument to be passed into AP function
251 **/
252 VOID
253 WakeUpAP (
254   IN PEI_CPU_MP_DATA           *PeiCpuMpData,
255   IN BOOLEAN                   Broadcast,
256   IN UINTN                     ProcessorNumber,
257   IN EFI_AP_PROCEDURE          Procedure,              OPTIONAL
258   IN VOID                      *ProcedureArgument      OPTIONAL
259   );
260 
261 /**
262   Get CPU MP Data pointer from the Guided HOB.
263 
264   @return  Pointer to Pointer to PEI CPU MP Data
265 **/
266 PEI_CPU_MP_DATA *
267 GetMpHobData (
268   VOID
269   );
270 
271 /**
272   Find the current Processor number by APIC ID.
273 
274   @param PeiCpuMpData        Pointer to PEI CPU MP Data
275   @param ProcessorNumber     Return the pocessor number found
276 
277   @retval EFI_SUCCESS        ProcessorNumber is found and returned.
278   @retval EFI_NOT_FOUND      ProcessorNumber is not found.
279 **/
280 EFI_STATUS
281 GetProcessorNumber (
282   IN PEI_CPU_MP_DATA         *PeiCpuMpData,
283   OUT UINTN                  *ProcessorNumber
284   );
285 
286 /**
287   Collects BIST data from PPI.
288 
289   This function collects BIST data from Sec Platform Information2 PPI
290   or SEC Platform Information PPI.
291 
292   @param PeiServices         Pointer to PEI Services Table
293   @param PeiCpuMpData        Pointer to PEI CPU MP Data
294 
295 **/
296 VOID
297 CollectBistDataFromPpi (
298   IN CONST EFI_PEI_SERVICES             **PeiServices,
299   IN PEI_CPU_MP_DATA                    *PeiCpuMpData
300   );
301 
302 /**
303   Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
304 
305   @param  PeiServices                The pointer to the PEI Services Table.
306   @param  StructureSize              The pointer to the variable describing size of the input buffer.
307   @param  PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
308 
309   @retval EFI_SUCCESS                The data was successfully returned.
310   @retval EFI_BUFFER_TOO_SMALL       The buffer was too small. The current buffer size needed to
311                                      hold the record is returned in StructureSize.
312 
313 **/
314 EFI_STATUS
315 EFIAPI
316 SecPlatformInformation2 (
317   IN CONST EFI_PEI_SERVICES                   **PeiServices,
318   IN OUT UINT64                               *StructureSize,
319      OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
320   );
321 
322 #endif
323