]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/CpuMpPei.c
8367f0573f22a394f3dd8338b12678495b5b5ed5
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
1 /** @file
2 CPU PEI Module installs CPU 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 #include "CpuMpPei.h"
16
17 //
18 // Global Descriptor Table (GDT)
19 //
20 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
21 /* selector { Global Segment Descriptor } */
22 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
23 /* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
24 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
25 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
26 /* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
27 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
28 /* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
29 /* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
30 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
31 };
32
33 //
34 // IA32 Gdt register
35 //
36 GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
37 sizeof (mGdtEntries) - 1,
38 (UINTN) mGdtEntries
39 };
40
41 /**
42 This function will be called from AP reset code if BSP uses WakeUpAP.
43
44 @param ExchangeInfo Pointer to the MP exchange info buffer
45 @param NumApsExecuting Number of curret executing AP
46 **/
47 VOID
48 EFIAPI
49 ApCFunction (
50 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
51 IN UINTN NumApsExecuting
52 )
53 {
54 PEI_CPU_MP_DATA *PeiCpuMpData;
55 UINTN BistData;
56
57 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
58 if (PeiCpuMpData->InitFlag) {
59 //
60 // This is first time AP wakeup, get BIST inforamtion from AP stack
61 //
62 BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
63 PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
64 PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
65 }
66
67 //
68 // AP finished executing C code
69 //
70 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
71
72 }
73
74 /**
75 This function will be called by BSP to wakeup AP.
76
77 @param PeiCpuMpData Pointer to PEI CPU MP Data
78 @param Broadcast TRUE: Send broadcast IPI to all APs
79 FALSE: Send IPI to AP by ApicId
80 @param ApicId Apic ID for the processor to be waked
81 @param Procedure The function to be invoked by AP
82 @param ProcedureArgument The argument to be passed into AP function
83 **/
84 VOID
85 WakeUpAP (
86 IN PEI_CPU_MP_DATA *PeiCpuMpData,
87 IN BOOLEAN Broadcast,
88 IN UINT32 ApicId,
89 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
90 IN VOID *ProcedureArgument OPTIONAL
91 )
92 {
93 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
94
95 PeiCpuMpData->ApFunction = (UINTN) Procedure;
96 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
97 PeiCpuMpData->FinishedCount = 0;
98
99 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
100 ExchangeInfo->Lock = 0;
101 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
102 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
103 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
104 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
105 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
106 ExchangeInfo->Cr3 = AsmReadCr3 ();
107 ExchangeInfo->CFunction = (UINTN) ApCFunction;
108 ExchangeInfo->NumApsExecuting = 0;
109 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
110
111 //
112 // Get the BSP's data of GDT and IDT
113 //
114 CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));
115 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
116
117 if (Broadcast) {
118 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
119 } else {
120 SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);
121 }
122
123 return ;
124 }
125
126 /**
127 Get available system memory below 1MB by specified size.
128
129 @param WakeupBufferSize Wakeup buffer size required
130
131 @retval other Return wakeup buffer address below 1MB.
132 @retval -1 Cannot find free memory below 1MB.
133 **/
134 UINTN
135 GetWakeupBuffer (
136 IN UINTN WakeupBufferSize
137 )
138 {
139 EFI_PEI_HOB_POINTERS Hob;
140 UINTN WakeupBufferStart;
141 UINTN WakeupBufferEnd;
142
143 //
144 // Get the HOB list for processing
145 //
146 Hob.Raw = GetHobList ();
147
148 //
149 // Collect memory ranges
150 //
151 while (!END_OF_HOB_LIST (Hob)) {
152 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
153 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
154 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
155 ((Hob.ResourceDescriptor->ResourceAttribute &
156 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
157 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
158 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
159 )) == 0)
160 ) {
161 //
162 // Need memory under 1MB to be collected here
163 //
164 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
165 if (WakeupBufferEnd > BASE_1MB) {
166 //
167 // Wakeup buffer should be under 1MB
168 //
169 WakeupBufferEnd = BASE_1MB;
170 }
171 //
172 // Wakeup buffer should be aligned on 4KB
173 //
174 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
175 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
176 continue;
177 }
178 //
179 // Create a memory allocation HOB.
180 //
181 BuildMemoryAllocationHob (
182 WakeupBufferStart,
183 WakeupBufferSize,
184 EfiBootServicesData
185 );
186 return WakeupBufferStart;
187 }
188 }
189 //
190 // Find the next HOB
191 //
192 Hob.Raw = GET_NEXT_HOB (Hob);
193 }
194
195 return (UINTN) -1;
196 }
197
198 /**
199 Get available system memory below 1MB by specified size.
200
201 @param PeiCpuMpData Pointer to PEI CPU MP Data
202 **/
203 VOID
204 BackupAndPrepareWakeupBuffer(
205 IN PEI_CPU_MP_DATA *PeiCpuMpData
206 )
207 {
208 CopyMem (
209 (VOID *) PeiCpuMpData->BackupBuffer,
210 (VOID *) PeiCpuMpData->WakeupBuffer,
211 PeiCpuMpData->BackupBufferSize
212 );
213 CopyMem (
214 (VOID *) PeiCpuMpData->WakeupBuffer,
215 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
216 PeiCpuMpData->AddressMap.RendezvousFunnelSize
217 );
218 }
219 /**
220 This function will get CPU count in the system.
221
222 @param PeiCpuMpData Pointer to PEI CPU MP Data
223
224 @return AP processor count
225 **/
226 UINT32
227 CountProcessorNumber (
228 IN PEI_CPU_MP_DATA *PeiCpuMpData
229 )
230 {
231
232 //
233 // Send broadcast IPI to APs to wakeup APs
234 //
235 PeiCpuMpData->InitFlag = 1;
236 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
237 //
238 // Wait for AP task to complete and then exit.
239 //
240 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
241 PeiCpuMpData->InitFlag = 0;
242 PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
243
244 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
245 return PeiCpuMpData->CpuCount;
246 }
247
248 /**
249 Prepare for AP wakeup buffer and copy AP reset code into it.
250
251 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
252
253 @return Pointer to PEI CPU MP Data
254 **/
255 PEI_CPU_MP_DATA *
256 PrepareAPStartupVector (
257 VOID
258 )
259 {
260 EFI_STATUS Status;
261 UINT32 MaxCpuCount;
262 PEI_CPU_MP_DATA *PeiCpuMpData;
263 EFI_PHYSICAL_ADDRESS Buffer;
264 UINTN BufferSize;
265 UINTN WakeupBuffer;
266 UINTN WakeupBufferSize;
267 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
268
269 AsmGetAddressMap (&AddressMap);
270 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
271 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
272 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
273
274 //
275 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
276 //
277 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
278 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
279 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
280 Status = PeiServicesAllocatePages (
281 EfiBootServicesData,
282 EFI_SIZE_TO_PAGES (BufferSize),
283 &Buffer
284 );
285 ASSERT_EFI_ERROR (Status);
286
287 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
288 PeiCpuMpData->Buffer = (UINTN) Buffer;
289 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
290 PeiCpuMpData->WakeupBuffer = WakeupBuffer;
291 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
292 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
293 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
294
295 PeiCpuMpData->CpuCount = 1;
296 PeiCpuMpData->BspNumber = 0;
297 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
298 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
299 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
300 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
301
302 //
303 // Backup original data and copy AP reset code in it
304 //
305 BackupAndPrepareWakeupBuffer(PeiCpuMpData);
306
307 return PeiCpuMpData;
308 }
309 /**
310 The Entry point of the MP CPU PEIM.
311
312 This function will wakeup APs and collect CPU AP count and install the
313 Mp Service Ppi.
314
315 @param FileHandle Handle of the file being invoked.
316 @param PeiServices Describes the list of possible PEI Services.
317
318 @retval EFI_SUCCESS MpServicePpi is installed successfully.
319
320 **/
321 EFI_STATUS
322 EFIAPI
323 CpuMpPeimInit (
324 IN EFI_PEI_FILE_HANDLE FileHandle,
325 IN CONST EFI_PEI_SERVICES **PeiServices
326 )
327 {
328
329 PEI_CPU_MP_DATA *PeiCpuMpData;
330 UINT32 ProcessorCount;
331
332 //
333 // Load new GDT table on BSP
334 //
335 AsmInitializeGdt (&mGdt);
336 //
337 // Get wakeup buffer and copy AP reset code in it
338 //
339 PeiCpuMpData = PrepareAPStartupVector ();
340 //
341 // Count processor number and collect processor information
342 //
343 ProcessorCount = CountProcessorNumber (PeiCpuMpData);
344
345 return EFI_SUCCESS;
346 }