]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg: Add some CPUID definitions
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
CommitLineData
65e79f93
JF
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
f9d30595
JF
17//
18// Global Descriptor Table (GDT)
19//
20GLOBAL_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//
36GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
37 sizeof (mGdtEntries) - 1,
38 (UINTN) mGdtEntries
39 };
40
f8e4e86b
JF
41/**
42 Sort the APIC ID of all processors.
43
44 This function sorts the APIC ID of all processors so that processor number is
45 assigned in the ascending order of APIC ID which eases MP debugging.
46
47 @param PeiCpuMpData Pointer to PEI CPU MP Data
48**/
49VOID
50SortApicId (
51 IN PEI_CPU_MP_DATA *PeiCpuMpData
52 )
53{
54 UINTN Index1;
55 UINTN Index2;
56 UINTN Index3;
57 UINT32 ApicId;
58 EFI_HEALTH_FLAGS Health;
59 UINT32 ApCount;
60
61 ApCount = PeiCpuMpData->CpuCount - 1;
62
63 if (ApCount != 0) {
64 for (Index1 = 0; Index1 < ApCount; Index1++) {
65 Index3 = Index1;
66 //
67 // Sort key is the hardware default APIC ID
68 //
69 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
70 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
71 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
72 Index3 = Index2;
73 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
74 }
75 }
76 if (Index3 != Index1) {
77 PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
78 PeiCpuMpData->CpuData[Index1].ApicId = ApicId;
79 Health = PeiCpuMpData->CpuData[Index3].Health;
80 PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health;
81 PeiCpuMpData->CpuData[Index1].Health = Health;
82 }
83 }
84
85 //
86 // Get the processor number for the BSP
87 //
88 ApicId = GetInitialApicId ();
89 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
90 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
91 PeiCpuMpData->BspNumber = (UINT32) Index1;
92 break;
93 }
94 }
95 }
96}
7d51bf5c
JF
97/**
98 This function will be called from AP reset code if BSP uses WakeUpAP.
99
100 @param ExchangeInfo Pointer to the MP exchange info buffer
101 @param NumApsExecuting Number of curret executing AP
102**/
103VOID
104EFIAPI
105ApCFunction (
106 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
107 IN UINTN NumApsExecuting
108 )
109{
110 PEI_CPU_MP_DATA *PeiCpuMpData;
111 UINTN BistData;
112
113 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
114 if (PeiCpuMpData->InitFlag) {
115 //
116 // This is first time AP wakeup, get BIST inforamtion from AP stack
117 //
118 BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
119 PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
120 PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
b4cd9f78
JF
121 //
122 // Sync BSP's Mtrr table to all wakeup APs
123 //
124 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
7d51bf5c
JF
125 }
126
127 //
128 // AP finished executing C code
129 //
130 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
131
132}
133
134/**
135 This function will be called by BSP to wakeup AP.
136
137 @param PeiCpuMpData Pointer to PEI CPU MP Data
138 @param Broadcast TRUE: Send broadcast IPI to all APs
139 FALSE: Send IPI to AP by ApicId
140 @param ApicId Apic ID for the processor to be waked
141 @param Procedure The function to be invoked by AP
142 @param ProcedureArgument The argument to be passed into AP function
143**/
144VOID
145WakeUpAP (
146 IN PEI_CPU_MP_DATA *PeiCpuMpData,
147 IN BOOLEAN Broadcast,
148 IN UINT32 ApicId,
149 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
150 IN VOID *ProcedureArgument OPTIONAL
151 )
152{
153 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
154
155 PeiCpuMpData->ApFunction = (UINTN) Procedure;
156 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
157 PeiCpuMpData->FinishedCount = 0;
158
159 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
160 ExchangeInfo->Lock = 0;
161 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
162 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
163 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
164 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
165 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
166 ExchangeInfo->Cr3 = AsmReadCr3 ();
167 ExchangeInfo->CFunction = (UINTN) ApCFunction;
168 ExchangeInfo->NumApsExecuting = 0;
169 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
170
171 //
172 // Get the BSP's data of GDT and IDT
173 //
174 CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));
175 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
176
177 if (Broadcast) {
178 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
179 } else {
180 SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);
181 }
182
183 return ;
184}
185
05e107f8
JF
186/**
187 Get available system memory below 1MB by specified size.
188
189 @param WakeupBufferSize Wakeup buffer size required
190
191 @retval other Return wakeup buffer address below 1MB.
192 @retval -1 Cannot find free memory below 1MB.
193**/
194UINTN
195GetWakeupBuffer (
196 IN UINTN WakeupBufferSize
197 )
198{
199 EFI_PEI_HOB_POINTERS Hob;
200 UINTN WakeupBufferStart;
201 UINTN WakeupBufferEnd;
202
203 //
204 // Get the HOB list for processing
205 //
206 Hob.Raw = GetHobList ();
207
208 //
209 // Collect memory ranges
210 //
211 while (!END_OF_HOB_LIST (Hob)) {
212 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
213 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
214 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
215 ((Hob.ResourceDescriptor->ResourceAttribute &
216 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
217 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
218 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
219 )) == 0)
220 ) {
221 //
222 // Need memory under 1MB to be collected here
223 //
224 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
225 if (WakeupBufferEnd > BASE_1MB) {
226 //
227 // Wakeup buffer should be under 1MB
228 //
229 WakeupBufferEnd = BASE_1MB;
230 }
231 //
232 // Wakeup buffer should be aligned on 4KB
233 //
234 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
235 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
236 continue;
237 }
238 //
239 // Create a memory allocation HOB.
240 //
241 BuildMemoryAllocationHob (
242 WakeupBufferStart,
243 WakeupBufferSize,
244 EfiBootServicesData
245 );
246 return WakeupBufferStart;
247 }
248 }
249 //
250 // Find the next HOB
251 //
252 Hob.Raw = GET_NEXT_HOB (Hob);
253 }
254
255 return (UINTN) -1;
256}
65e79f93 257
e66d675d
JF
258/**
259 Get available system memory below 1MB by specified size.
260
261 @param PeiCpuMpData Pointer to PEI CPU MP Data
262**/
263VOID
264BackupAndPrepareWakeupBuffer(
265 IN PEI_CPU_MP_DATA *PeiCpuMpData
266 )
267{
268 CopyMem (
269 (VOID *) PeiCpuMpData->BackupBuffer,
270 (VOID *) PeiCpuMpData->WakeupBuffer,
271 PeiCpuMpData->BackupBufferSize
272 );
273 CopyMem (
274 (VOID *) PeiCpuMpData->WakeupBuffer,
275 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
276 PeiCpuMpData->AddressMap.RendezvousFunnelSize
277 );
278}
7d51bf5c
JF
279/**
280 This function will get CPU count in the system.
281
282 @param PeiCpuMpData Pointer to PEI CPU MP Data
283
284 @return AP processor count
285**/
286UINT32
287CountProcessorNumber (
288 IN PEI_CPU_MP_DATA *PeiCpuMpData
289 )
290{
291
b4cd9f78
JF
292 //
293 // Store BSP's MTRR setting
294 //
295 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
7d51bf5c
JF
296 //
297 // Send broadcast IPI to APs to wakeup APs
298 //
299 PeiCpuMpData->InitFlag = 1;
300 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
301 //
302 // Wait for AP task to complete and then exit.
303 //
304 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
305 PeiCpuMpData->InitFlag = 0;
306 PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
f8e4e86b
JF
307 //
308 // Sort BSP/Aps by CPU APIC ID in ascending order
309 //
310 SortApicId (PeiCpuMpData);
7d51bf5c
JF
311
312 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
313 return PeiCpuMpData->CpuCount;
314}
315
e66d675d
JF
316/**
317 Prepare for AP wakeup buffer and copy AP reset code into it.
318
319 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
320
321 @return Pointer to PEI CPU MP Data
322**/
323PEI_CPU_MP_DATA *
324PrepareAPStartupVector (
325 VOID
326 )
327{
328 EFI_STATUS Status;
329 UINT32 MaxCpuCount;
330 PEI_CPU_MP_DATA *PeiCpuMpData;
331 EFI_PHYSICAL_ADDRESS Buffer;
332 UINTN BufferSize;
333 UINTN WakeupBuffer;
334 UINTN WakeupBufferSize;
335 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
336
337 AsmGetAddressMap (&AddressMap);
338 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
339 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
340 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
341
342 //
343 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
344 //
345 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
346 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
347 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
348 Status = PeiServicesAllocatePages (
349 EfiBootServicesData,
350 EFI_SIZE_TO_PAGES (BufferSize),
351 &Buffer
352 );
353 ASSERT_EFI_ERROR (Status);
354
355 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
356 PeiCpuMpData->Buffer = (UINTN) Buffer;
357 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
358 PeiCpuMpData->WakeupBuffer = WakeupBuffer;
359 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
360 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
361 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
362
363 PeiCpuMpData->CpuCount = 1;
364 PeiCpuMpData->BspNumber = 0;
365 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
366 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
367 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
368 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
369
370 //
371 // Backup original data and copy AP reset code in it
372 //
373 BackupAndPrepareWakeupBuffer(PeiCpuMpData);
374
375 return PeiCpuMpData;
376}
65e79f93
JF
377/**
378 The Entry point of the MP CPU PEIM.
379
380 This function will wakeup APs and collect CPU AP count and install the
381 Mp Service Ppi.
382
383 @param FileHandle Handle of the file being invoked.
384 @param PeiServices Describes the list of possible PEI Services.
385
386 @retval EFI_SUCCESS MpServicePpi is installed successfully.
387
388**/
389EFI_STATUS
390EFIAPI
391CpuMpPeimInit (
392 IN EFI_PEI_FILE_HANDLE FileHandle,
393 IN CONST EFI_PEI_SERVICES **PeiServices
394 )
395{
396
e66d675d 397 PEI_CPU_MP_DATA *PeiCpuMpData;
7d51bf5c 398 UINT32 ProcessorCount;
65e79f93 399
f9d30595
JF
400 //
401 // Load new GDT table on BSP
402 //
403 AsmInitializeGdt (&mGdt);
e66d675d
JF
404 //
405 // Get wakeup buffer and copy AP reset code in it
406 //
407 PeiCpuMpData = PrepareAPStartupVector ();
7d51bf5c
JF
408 //
409 // Count processor number and collect processor information
410 //
411 ProcessorCount = CountProcessorNumber (PeiCpuMpData);
65e79f93
JF
412
413 return EFI_SUCCESS;
414}