]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/CpuMpPei.c
45243d804ee8fb7ac1a0306b5ef97f7b5dc068b4
[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 Get available system memory below 1MB by specified size.
43
44 @param WakeupBufferSize Wakeup buffer size required
45
46 @retval other Return wakeup buffer address below 1MB.
47 @retval -1 Cannot find free memory below 1MB.
48 **/
49 UINTN
50 GetWakeupBuffer (
51 IN UINTN WakeupBufferSize
52 )
53 {
54 EFI_PEI_HOB_POINTERS Hob;
55 UINTN WakeupBufferStart;
56 UINTN WakeupBufferEnd;
57
58 //
59 // Get the HOB list for processing
60 //
61 Hob.Raw = GetHobList ();
62
63 //
64 // Collect memory ranges
65 //
66 while (!END_OF_HOB_LIST (Hob)) {
67 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
68 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
69 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
70 ((Hob.ResourceDescriptor->ResourceAttribute &
71 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
72 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
73 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
74 )) == 0)
75 ) {
76 //
77 // Need memory under 1MB to be collected here
78 //
79 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
80 if (WakeupBufferEnd > BASE_1MB) {
81 //
82 // Wakeup buffer should be under 1MB
83 //
84 WakeupBufferEnd = BASE_1MB;
85 }
86 //
87 // Wakeup buffer should be aligned on 4KB
88 //
89 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
90 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
91 continue;
92 }
93 //
94 // Create a memory allocation HOB.
95 //
96 BuildMemoryAllocationHob (
97 WakeupBufferStart,
98 WakeupBufferSize,
99 EfiBootServicesData
100 );
101 return WakeupBufferStart;
102 }
103 }
104 //
105 // Find the next HOB
106 //
107 Hob.Raw = GET_NEXT_HOB (Hob);
108 }
109
110 return (UINTN) -1;
111 }
112
113 /**
114 Get available system memory below 1MB by specified size.
115
116 @param PeiCpuMpData Pointer to PEI CPU MP Data
117 **/
118 VOID
119 BackupAndPrepareWakeupBuffer(
120 IN PEI_CPU_MP_DATA *PeiCpuMpData
121 )
122 {
123 CopyMem (
124 (VOID *) PeiCpuMpData->BackupBuffer,
125 (VOID *) PeiCpuMpData->WakeupBuffer,
126 PeiCpuMpData->BackupBufferSize
127 );
128 CopyMem (
129 (VOID *) PeiCpuMpData->WakeupBuffer,
130 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
131 PeiCpuMpData->AddressMap.RendezvousFunnelSize
132 );
133 }
134 /**
135 Prepare for AP wakeup buffer and copy AP reset code into it.
136
137 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
138
139 @return Pointer to PEI CPU MP Data
140 **/
141 PEI_CPU_MP_DATA *
142 PrepareAPStartupVector (
143 VOID
144 )
145 {
146 EFI_STATUS Status;
147 UINT32 MaxCpuCount;
148 PEI_CPU_MP_DATA *PeiCpuMpData;
149 EFI_PHYSICAL_ADDRESS Buffer;
150 UINTN BufferSize;
151 UINTN WakeupBuffer;
152 UINTN WakeupBufferSize;
153 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
154
155 AsmGetAddressMap (&AddressMap);
156 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
157 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
158 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
159
160 //
161 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
162 //
163 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
164 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
165 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
166 Status = PeiServicesAllocatePages (
167 EfiBootServicesData,
168 EFI_SIZE_TO_PAGES (BufferSize),
169 &Buffer
170 );
171 ASSERT_EFI_ERROR (Status);
172
173 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
174 PeiCpuMpData->Buffer = (UINTN) Buffer;
175 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
176 PeiCpuMpData->WakeupBuffer = WakeupBuffer;
177 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
178 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
179 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
180
181 PeiCpuMpData->CpuCount = 1;
182 PeiCpuMpData->BspNumber = 0;
183 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
184 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
185 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
186 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
187
188 //
189 // Backup original data and copy AP reset code in it
190 //
191 BackupAndPrepareWakeupBuffer(PeiCpuMpData);
192
193 return PeiCpuMpData;
194 }
195 /**
196 The Entry point of the MP CPU PEIM.
197
198 This function will wakeup APs and collect CPU AP count and install the
199 Mp Service Ppi.
200
201 @param FileHandle Handle of the file being invoked.
202 @param PeiServices Describes the list of possible PEI Services.
203
204 @retval EFI_SUCCESS MpServicePpi is installed successfully.
205
206 **/
207 EFI_STATUS
208 EFIAPI
209 CpuMpPeimInit (
210 IN EFI_PEI_FILE_HANDLE FileHandle,
211 IN CONST EFI_PEI_SERVICES **PeiServices
212 )
213 {
214
215 PEI_CPU_MP_DATA *PeiCpuMpData;
216
217 //
218 // Load new GDT table on BSP
219 //
220 AsmInitializeGdt (&mGdt);
221 //
222 // Get wakeup buffer and copy AP reset code in it
223 //
224 PeiCpuMpData = PrepareAPStartupVector ();
225
226 return EFI_SUCCESS;
227 }