1 | /** @file
|
---|
2 | SMM Relocation Lib for each processor.
|
---|
3 |
|
---|
4 | This Lib produces the SMM_BASE_HOB in HOB database which tells
|
---|
5 | the PiSmmCpuDxeSmm driver (runs at a later phase) about the new
|
---|
6 | SMBASE for each processor. PiSmmCpuDxeSmm driver installs the
|
---|
7 | SMI handler at the SMM_BASE_HOB.SmBase[Index]+0x8000 for processor
|
---|
8 | Index.
|
---|
9 |
|
---|
10 | Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
|
---|
11 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
12 |
|
---|
13 | **/
|
---|
14 | #include "InternalSmmRelocationLib.h"
|
---|
15 |
|
---|
16 | UINTN mMaxNumberOfCpus = 1;
|
---|
17 | UINTN mNumberOfCpus = 1;
|
---|
18 |
|
---|
19 | //
|
---|
20 | // IDT used during SMM Init
|
---|
21 | //
|
---|
22 | IA32_DESCRIPTOR gcSmmInitIdtr;
|
---|
23 |
|
---|
24 | //
|
---|
25 | // Smbase for current CPU
|
---|
26 | //
|
---|
27 | UINT64 mSmBase;
|
---|
28 |
|
---|
29 | //
|
---|
30 | // SmBase Rebased flag for current CPU
|
---|
31 | //
|
---|
32 | volatile BOOLEAN mRebased;
|
---|
33 |
|
---|
34 | /**
|
---|
35 | This function will get the SmBase for CpuIndex.
|
---|
36 |
|
---|
37 | @param[in] CpuIndex The processor index.
|
---|
38 | @param[in] SmmRelocationStart The start address of Smm relocated memory in SMRAM.
|
---|
39 | @param[in] TileSize The total size required for a CPU save state, any
|
---|
40 | additional CPU-specific context and the size of code
|
---|
41 | for the SMI entry point.
|
---|
42 |
|
---|
43 | @retval The value of SmBase for CpuIndex.
|
---|
44 |
|
---|
45 | **/
|
---|
46 | UINTN
|
---|
47 | GetSmBase (
|
---|
48 | IN UINTN CpuIndex,
|
---|
49 | IN EFI_PHYSICAL_ADDRESS SmmRelocationStart,
|
---|
50 | IN UINTN TileSize
|
---|
51 | )
|
---|
52 | {
|
---|
53 | return (UINTN)(SmmRelocationStart) + CpuIndex * TileSize - SMM_HANDLER_OFFSET;
|
---|
54 | }
|
---|
55 |
|
---|
56 | /**
|
---|
57 | This function will create SmBase for all CPUs.
|
---|
58 |
|
---|
59 | @param[in] SmmRelocationStart The start address of Smm relocated memory in SMRAM.
|
---|
60 | @param[in] TileSize The total size required for a CPU save state, any
|
---|
61 | additional CPU-specific context and the size of code
|
---|
62 | for the SMI entry point.
|
---|
63 |
|
---|
64 | @retval EFI_SUCCESS Create SmBase for all CPUs successfully.
|
---|
65 | @retval Others Failed to create SmBase for all CPUs.
|
---|
66 |
|
---|
67 | **/
|
---|
68 | EFI_STATUS
|
---|
69 | CreateSmmBaseHob (
|
---|
70 | IN EFI_PHYSICAL_ADDRESS SmmRelocationStart,
|
---|
71 | IN UINTN TileSize
|
---|
72 | )
|
---|
73 | {
|
---|
74 | UINTN Index;
|
---|
75 | SMM_BASE_HOB_DATA *SmmBaseHobData;
|
---|
76 | UINT32 CpuCount;
|
---|
77 | UINT32 NumberOfProcessorsInHob;
|
---|
78 | UINT32 MaxCapOfProcessorsInHob;
|
---|
79 | UINT32 HobCount;
|
---|
80 |
|
---|
81 | SmmBaseHobData = NULL;
|
---|
82 | CpuCount = 0;
|
---|
83 | NumberOfProcessorsInHob = 0;
|
---|
84 | MaxCapOfProcessorsInHob = 0;
|
---|
85 | HobCount = 0;
|
---|
86 |
|
---|
87 | //
|
---|
88 | // Count the HOB instance maximum capacity of CPU (MaxCapOfProcessorsInHob) since the max HobLength is 0xFFF8.
|
---|
89 | //
|
---|
90 | MaxCapOfProcessorsInHob = (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE) - sizeof (SMM_BASE_HOB_DATA)) / sizeof (UINT64) + 1;
|
---|
91 | DEBUG ((DEBUG_INFO, "CreateSmmBaseHob - MaxCapOfProcessorsInHob: %d\n", MaxCapOfProcessorsInHob));
|
---|
92 |
|
---|
93 | //
|
---|
94 | // Create Guided SMM Base HOB Instances.
|
---|
95 | //
|
---|
96 | while (CpuCount != mMaxNumberOfCpus) {
|
---|
97 | NumberOfProcessorsInHob = MIN ((UINT32)mMaxNumberOfCpus - CpuCount, MaxCapOfProcessorsInHob);
|
---|
98 |
|
---|
99 | SmmBaseHobData = BuildGuidHob (
|
---|
100 | &gSmmBaseHobGuid,
|
---|
101 | sizeof (SMM_BASE_HOB_DATA) + sizeof (UINT64) * NumberOfProcessorsInHob
|
---|
102 | );
|
---|
103 | if (SmmBaseHobData == NULL) {
|
---|
104 | return EFI_OUT_OF_RESOURCES;
|
---|
105 | }
|
---|
106 |
|
---|
107 | SmmBaseHobData->ProcessorIndex = CpuCount;
|
---|
108 | SmmBaseHobData->NumberOfProcessors = NumberOfProcessorsInHob;
|
---|
109 |
|
---|
110 | DEBUG ((DEBUG_INFO, "CreateSmmBaseHob - SmmBaseHobData[%d]->ProcessorIndex: %d\n", HobCount, SmmBaseHobData->ProcessorIndex));
|
---|
111 | DEBUG ((DEBUG_INFO, "CreateSmmBaseHob - SmmBaseHobData[%d]->NumberOfProcessors: %d\n", HobCount, SmmBaseHobData->NumberOfProcessors));
|
---|
112 | for (Index = 0; Index < SmmBaseHobData->NumberOfProcessors; Index++) {
|
---|
113 | //
|
---|
114 | // Calculate the new SMBASE address
|
---|
115 | //
|
---|
116 | SmmBaseHobData->SmBase[Index] = GetSmBase (Index + CpuCount, SmmRelocationStart, TileSize);
|
---|
117 | DEBUG ((DEBUG_INFO, "CreateSmmBaseHob - SmmBaseHobData[%d]->SmBase[%d]: 0x%08x\n", HobCount, Index, SmmBaseHobData->SmBase[Index]));
|
---|
118 | }
|
---|
119 |
|
---|
120 | CpuCount += NumberOfProcessorsInHob;
|
---|
121 | HobCount++;
|
---|
122 | SmmBaseHobData = NULL;
|
---|
123 | }
|
---|
124 |
|
---|
125 | return EFI_SUCCESS;
|
---|
126 | }
|
---|
127 |
|
---|
128 | /**
|
---|
129 | C function for SMI handler. To change all processor's SMMBase Register.
|
---|
130 |
|
---|
131 | **/
|
---|
132 | VOID
|
---|
133 | EFIAPI
|
---|
134 | SmmInitHandler (
|
---|
135 | VOID
|
---|
136 | )
|
---|
137 | {
|
---|
138 | //
|
---|
139 | // Update SMM IDT entries' code segment and load IDT
|
---|
140 | //
|
---|
141 | AsmWriteIdtr (&gcSmmInitIdtr);
|
---|
142 |
|
---|
143 | //
|
---|
144 | // Configure SmBase.
|
---|
145 | //
|
---|
146 | ConfigureSmBase (mSmBase);
|
---|
147 |
|
---|
148 | //
|
---|
149 | // Hook return after RSM to set SMM re-based flag
|
---|
150 | // SMM re-based flag can't be set before RSM, because SMM save state context might be override
|
---|
151 | // by next AP flow before it take effect.
|
---|
152 | //
|
---|
153 | SemaphoreHook (&mRebased);
|
---|
154 | }
|
---|
155 |
|
---|
156 | /**
|
---|
157 | Relocate SmmBases for each processor.
|
---|
158 | Execute on first boot and all S3 resumes
|
---|
159 |
|
---|
160 | @param[in] MpServices2 Pointer to this instance of the MpServices.
|
---|
161 | @param[in] SmmRelocationStart The start address of Smm relocated memory in SMRAM.
|
---|
162 | @param[in] TileSize The total size required for a CPU save state, any
|
---|
163 | additional CPU-specific context and the size of code
|
---|
164 | for the SMI entry point.
|
---|
165 |
|
---|
166 | **/
|
---|
167 | VOID
|
---|
168 | SmmRelocateBases (
|
---|
169 | IN EDKII_PEI_MP_SERVICES2_PPI *MpServices2,
|
---|
170 | IN EFI_PHYSICAL_ADDRESS SmmRelocationStart,
|
---|
171 | IN UINTN TileSize
|
---|
172 | )
|
---|
173 | {
|
---|
174 | EFI_STATUS Status;
|
---|
175 | UINT8 BakBuf[BACK_BUF_SIZE];
|
---|
176 | SMRAM_SAVE_STATE_MAP BakBuf2;
|
---|
177 | SMRAM_SAVE_STATE_MAP *CpuStatePtr;
|
---|
178 | UINT8 *U8Ptr;
|
---|
179 | UINTN Index;
|
---|
180 | UINTN BspIndex;
|
---|
181 | UINT32 BspApicId;
|
---|
182 | EFI_PROCESSOR_INFORMATION ProcessorInfo;
|
---|
183 |
|
---|
184 | //
|
---|
185 | // Make sure the reserved size is large enough for procedure SmmInitTemplate.
|
---|
186 | //
|
---|
187 | ASSERT (sizeof (BakBuf) >= gcSmmInitSize);
|
---|
188 |
|
---|
189 | //
|
---|
190 | // Patch ASM code template with current CR0, CR3, and CR4 values
|
---|
191 | //
|
---|
192 | PatchInstructionX86 (gPatchSmmInitCr0, AsmReadCr0 (), 4);
|
---|
193 | PatchInstructionX86 (gPatchSmmInitCr3, AsmReadCr3 (), 4);
|
---|
194 | PatchInstructionX86 (gPatchSmmInitCr4, AsmReadCr4 () & (~CR4_CET_ENABLE), 4);
|
---|
195 |
|
---|
196 | U8Ptr = (UINT8 *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET);
|
---|
197 | CpuStatePtr = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
|
---|
198 |
|
---|
199 | //
|
---|
200 | // Backup original contents at address 0x38000
|
---|
201 | //
|
---|
202 | CopyMem (BakBuf, U8Ptr, sizeof (BakBuf));
|
---|
203 | CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2));
|
---|
204 |
|
---|
205 | //
|
---|
206 | // Load image for relocation
|
---|
207 | //
|
---|
208 | CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize);
|
---|
209 |
|
---|
210 | //
|
---|
211 | // Retrieve the local APIC ID of current processor
|
---|
212 | //
|
---|
213 | BspApicId = GetApicId ();
|
---|
214 |
|
---|
215 | //
|
---|
216 | // Relocate SM bases for all APs
|
---|
217 | // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overridden by gcSmmInitTemplate
|
---|
218 | //
|
---|
219 | BspIndex = (UINTN)-1;
|
---|
220 | for (Index = 0; Index < mNumberOfCpus; Index++) {
|
---|
221 | Status = MpServices2->GetProcessorInfo (MpServices2, Index | CPU_V2_EXTENDED_TOPOLOGY, &ProcessorInfo);
|
---|
222 | ASSERT_EFI_ERROR (Status);
|
---|
223 |
|
---|
224 | if (BspApicId != (UINT32)ProcessorInfo.ProcessorId) {
|
---|
225 | mRebased = FALSE;
|
---|
226 | mSmBase = GetSmBase (Index, SmmRelocationStart, TileSize);
|
---|
227 | SendSmiIpi ((UINT32)ProcessorInfo.ProcessorId);
|
---|
228 | //
|
---|
229 | // Wait for this AP to finish its 1st SMI
|
---|
230 | //
|
---|
231 | while (!mRebased) {
|
---|
232 | }
|
---|
233 | } else {
|
---|
234 | //
|
---|
235 | // BSP will be Relocated later
|
---|
236 | //
|
---|
237 | BspIndex = Index;
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | //
|
---|
242 | // Relocate BSP's SMM base
|
---|
243 | //
|
---|
244 | ASSERT (BspIndex != (UINTN)-1);
|
---|
245 | mRebased = FALSE;
|
---|
246 | mSmBase = GetSmBase (BspIndex, SmmRelocationStart, TileSize);
|
---|
247 | SendSmiIpi (BspApicId);
|
---|
248 |
|
---|
249 | //
|
---|
250 | // Wait for the BSP to finish its 1st SMI
|
---|
251 | //
|
---|
252 | while (!mRebased) {
|
---|
253 | }
|
---|
254 |
|
---|
255 | //
|
---|
256 | // Restore contents at address 0x38000
|
---|
257 | //
|
---|
258 | CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2));
|
---|
259 | CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));
|
---|
260 | }
|
---|
261 |
|
---|
262 | /**
|
---|
263 | Initialize IDT to setup exception handlers in SMM.
|
---|
264 |
|
---|
265 | **/
|
---|
266 | VOID
|
---|
267 | InitSmmIdt (
|
---|
268 | VOID
|
---|
269 | )
|
---|
270 | {
|
---|
271 | EFI_STATUS Status;
|
---|
272 | BOOLEAN InterruptState;
|
---|
273 | IA32_DESCRIPTOR PeiIdtr;
|
---|
274 | CONST EFI_PEI_SERVICES **PeiServices;
|
---|
275 |
|
---|
276 | //
|
---|
277 | // There are 32 (not 255) entries in it since only processor
|
---|
278 | // generated exceptions will be handled.
|
---|
279 | //
|
---|
280 | gcSmmInitIdtr.Limit = (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32) - 1;
|
---|
281 |
|
---|
282 | //
|
---|
283 | // Allocate for IDT.
|
---|
284 | // sizeof (UINTN) is for the PEI Services Table pointer.
|
---|
285 | //
|
---|
286 | gcSmmInitIdtr.Base = (UINTN)AllocateZeroPool (gcSmmInitIdtr.Limit + 1 + sizeof (UINTN));
|
---|
287 | ASSERT (gcSmmInitIdtr.Base != 0);
|
---|
288 | gcSmmInitIdtr.Base += sizeof (UINTN);
|
---|
289 |
|
---|
290 | //
|
---|
291 | // Disable Interrupt, save InterruptState and save PEI IDT table
|
---|
292 | //
|
---|
293 | InterruptState = SaveAndDisableInterrupts ();
|
---|
294 | AsmReadIdtr (&PeiIdtr);
|
---|
295 |
|
---|
296 | //
|
---|
297 | // Save the PEI Services Table pointer
|
---|
298 | // The PEI Services Table pointer will be stored in the sizeof (UINTN) bytes
|
---|
299 | // immediately preceding the IDT in memory.
|
---|
300 | //
|
---|
301 | PeiServices = (CONST EFI_PEI_SERVICES **)(*(UINTN *)(PeiIdtr.Base - sizeof (UINTN)));
|
---|
302 | (*(UINTN *)(gcSmmInitIdtr.Base - sizeof (UINTN))) = (UINTN)PeiServices;
|
---|
303 |
|
---|
304 | //
|
---|
305 | // Load SMM temporary IDT table
|
---|
306 | //
|
---|
307 | AsmWriteIdtr (&gcSmmInitIdtr);
|
---|
308 |
|
---|
309 | //
|
---|
310 | // Setup SMM default exception handlers, SMM IDT table
|
---|
311 | // will be updated and saved in gcSmmInitIdtr
|
---|
312 | //
|
---|
313 | Status = InitializeCpuExceptionHandlers (NULL);
|
---|
314 | ASSERT_EFI_ERROR (Status);
|
---|
315 |
|
---|
316 | //
|
---|
317 | // Restore PEI IDT table and CPU InterruptState
|
---|
318 | //
|
---|
319 | AsmWriteIdtr ((IA32_DESCRIPTOR *)&PeiIdtr);
|
---|
320 | SetInterruptState (InterruptState);
|
---|
321 | }
|
---|
322 |
|
---|
323 | /**
|
---|
324 | This routine will split SmramReserve HOB to reserve SmmRelocationSize for Smm relocated memory.
|
---|
325 |
|
---|
326 | @param[in] SmmRelocationSize SmmRelocationSize for all processors.
|
---|
327 | @param[in,out] SmmRelocationStart Return the start address of Smm relocated memory in SMRAM.
|
---|
328 |
|
---|
329 | @retval EFI_SUCCESS The gEfiSmmSmramMemoryGuid is split successfully.
|
---|
330 | @retval EFI_DEVICE_ERROR Failed to build new HOB for gEfiSmmSmramMemoryGuid.
|
---|
331 | @retval EFI_NOT_FOUND The gEfiSmmSmramMemoryGuid is not found.
|
---|
332 |
|
---|
333 | **/
|
---|
334 | EFI_STATUS
|
---|
335 | SplitSmramHobForSmmRelocation (
|
---|
336 | IN UINT64 SmmRelocationSize,
|
---|
337 | IN OUT EFI_PHYSICAL_ADDRESS *SmmRelocationStart
|
---|
338 | )
|
---|
339 | {
|
---|
340 | EFI_HOB_GUID_TYPE *GuidHob;
|
---|
341 | EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *Block;
|
---|
342 | EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *NewBlock;
|
---|
343 | UINTN NewBlockSize;
|
---|
344 |
|
---|
345 | ASSERT (SmmRelocationStart != NULL);
|
---|
346 |
|
---|
347 | //
|
---|
348 | // Retrieve the GUID HOB data that contains the set of SMRAM descriptors
|
---|
349 | //
|
---|
350 | GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
|
---|
351 | if (GuidHob == NULL) {
|
---|
352 | return EFI_NOT_FOUND;
|
---|
353 | }
|
---|
354 |
|
---|
355 | Block = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob);
|
---|
356 |
|
---|
357 | //
|
---|
358 | // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe smram carved out for all SMBASE
|
---|
359 | //
|
---|
360 | NewBlockSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + (Block->NumberOfSmmReservedRegions * sizeof (EFI_SMRAM_DESCRIPTOR));
|
---|
361 |
|
---|
362 | NewBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)BuildGuidHob (
|
---|
363 | &gEfiSmmSmramMemoryGuid,
|
---|
364 | NewBlockSize
|
---|
365 | );
|
---|
366 | ASSERT (NewBlock != NULL);
|
---|
367 | if (NewBlock == NULL) {
|
---|
368 | return EFI_DEVICE_ERROR;
|
---|
369 | }
|
---|
370 |
|
---|
371 | //
|
---|
372 | // Copy old EFI_SMRAM_HOB_DESCRIPTOR_BLOCK to new allocated region
|
---|
373 | //
|
---|
374 | CopyMem ((VOID *)NewBlock, Block, NewBlockSize - sizeof (EFI_SMRAM_DESCRIPTOR));
|
---|
375 |
|
---|
376 | //
|
---|
377 | // Increase the number of SMRAM descriptors by 1 to make room for the ALLOCATED descriptor of size EFI_PAGE_SIZE
|
---|
378 | //
|
---|
379 | NewBlock->NumberOfSmmReservedRegions = (UINT32)(Block->NumberOfSmmReservedRegions + 1);
|
---|
380 |
|
---|
381 | ASSERT (Block->NumberOfSmmReservedRegions >= 1);
|
---|
382 | //
|
---|
383 | // Copy last entry to the end - we assume TSEG is last entry.
|
---|
384 | //
|
---|
385 | CopyMem (&NewBlock->Descriptor[Block->NumberOfSmmReservedRegions], &NewBlock->Descriptor[Block->NumberOfSmmReservedRegions - 1], sizeof (EFI_SMRAM_DESCRIPTOR));
|
---|
386 |
|
---|
387 | //
|
---|
388 | // Update the entry in the array with a size of SmmRelocationSize and put into the ALLOCATED state
|
---|
389 | //
|
---|
390 | NewBlock->Descriptor[Block->NumberOfSmmReservedRegions - 1].PhysicalSize = SmmRelocationSize;
|
---|
391 | NewBlock->Descriptor[Block->NumberOfSmmReservedRegions - 1].RegionState |= EFI_ALLOCATED;
|
---|
392 |
|
---|
393 | //
|
---|
394 | // Return the start address of Smm relocated memory in SMRAM.
|
---|
395 | //
|
---|
396 | *SmmRelocationStart = NewBlock->Descriptor[Block->NumberOfSmmReservedRegions - 1].CpuStart;
|
---|
397 |
|
---|
398 | //
|
---|
399 | // Reduce the size of the last SMRAM descriptor by SmmRelocationSize
|
---|
400 | //
|
---|
401 | NewBlock->Descriptor[Block->NumberOfSmmReservedRegions].PhysicalStart += SmmRelocationSize;
|
---|
402 | NewBlock->Descriptor[Block->NumberOfSmmReservedRegions].CpuStart += SmmRelocationSize;
|
---|
403 | NewBlock->Descriptor[Block->NumberOfSmmReservedRegions].PhysicalSize -= SmmRelocationSize;
|
---|
404 |
|
---|
405 | //
|
---|
406 | // Last step, we can scrub old one
|
---|
407 | //
|
---|
408 | ZeroMem (&GuidHob->Name, sizeof (GuidHob->Name));
|
---|
409 |
|
---|
410 | return EFI_SUCCESS;
|
---|
411 | }
|
---|
412 |
|
---|
413 | /**
|
---|
414 | CPU SmmBase Relocation Init.
|
---|
415 |
|
---|
416 | This function is to relocate CPU SmmBase.
|
---|
417 |
|
---|
418 | @param[in] MpServices2 Pointer to this instance of the MpServices.
|
---|
419 |
|
---|
420 | @retval EFI_SUCCESS CPU SmmBase Relocated successfully.
|
---|
421 | @retval Others CPU SmmBase Relocation failed.
|
---|
422 |
|
---|
423 | **/
|
---|
424 | EFI_STATUS
|
---|
425 | EFIAPI
|
---|
426 | SmmRelocationInit (
|
---|
427 | IN EDKII_PEI_MP_SERVICES2_PPI *MpServices2
|
---|
428 | )
|
---|
429 | {
|
---|
430 | EFI_STATUS Status;
|
---|
431 | UINTN NumberOfEnabledCpus;
|
---|
432 | UINTN TileSize;
|
---|
433 | UINT64 SmmRelocationSize;
|
---|
434 | EFI_PHYSICAL_ADDRESS SmmRelocationStart;
|
---|
435 | UINTN SmmStackSize;
|
---|
436 | UINT8 *SmmStacks;
|
---|
437 |
|
---|
438 | SmmRelocationStart = 0;
|
---|
439 | SmmStacks = NULL;
|
---|
440 |
|
---|
441 | DEBUG ((DEBUG_INFO, "SmmRelocationInit Start \n"));
|
---|
442 | if (MpServices2 == NULL) {
|
---|
443 | return EFI_INVALID_PARAMETER;
|
---|
444 | }
|
---|
445 |
|
---|
446 | //
|
---|
447 | // Get the number of processors
|
---|
448 | //
|
---|
449 | Status = MpServices2->GetNumberOfProcessors (
|
---|
450 | MpServices2,
|
---|
451 | &mNumberOfCpus,
|
---|
452 | &NumberOfEnabledCpus
|
---|
453 | );
|
---|
454 | if (EFI_ERROR (Status)) {
|
---|
455 | goto ON_EXIT;
|
---|
456 | }
|
---|
457 |
|
---|
458 | if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
|
---|
459 | mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
|
---|
460 | } else {
|
---|
461 | mMaxNumberOfCpus = mNumberOfCpus;
|
---|
462 | }
|
---|
463 |
|
---|
464 | ASSERT (mNumberOfCpus <= mMaxNumberOfCpus);
|
---|
465 |
|
---|
466 | //
|
---|
467 | // Calculate SmmRelocationSize for all of the tiles.
|
---|
468 | //
|
---|
469 | // The CPU save state and code for the SMI entry point are tiled within an SMRAM
|
---|
470 | // allocated buffer. The minimum size of this buffer for a uniprocessor system
|
---|
471 | // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area
|
---|
472 | // just below SMBASE + 64KB. If more than one CPU is present in the platform,
|
---|
473 | // then the SMI entry point and the CPU save state areas can be tiles to minimize
|
---|
474 | // the total amount SMRAM required for all the CPUs. The tile size can be computed
|
---|
475 | // by adding the CPU save state size, any extra CPU specific context, and
|
---|
476 | // the size of code that must be placed at the SMI entry point to transfer
|
---|
477 | // control to a C function in the native SMM execution mode. This size is
|
---|
478 | // rounded up to the nearest power of 2 to give the tile size for a each CPU.
|
---|
479 | // The total amount of memory required is the maximum number of CPUs that
|
---|
480 | // platform supports times the tile size.
|
---|
481 | //
|
---|
482 | TileSize = SIZE_8KB;
|
---|
483 | SmmRelocationSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1)));
|
---|
484 |
|
---|
485 | //
|
---|
486 | // Split SmramReserve HOB to reserve SmmRelocationSize for Smm relocated memory
|
---|
487 | //
|
---|
488 | Status = SplitSmramHobForSmmRelocation (
|
---|
489 | SmmRelocationSize,
|
---|
490 | &SmmRelocationStart
|
---|
491 | );
|
---|
492 | if (EFI_ERROR (Status)) {
|
---|
493 | goto ON_EXIT;
|
---|
494 | }
|
---|
495 |
|
---|
496 | ASSERT (SmmRelocationStart != 0);
|
---|
497 | DEBUG ((DEBUG_INFO, "SmmRelocationInit - SmmRelocationSize: 0x%08x\n", SmmRelocationSize));
|
---|
498 | DEBUG ((DEBUG_INFO, "SmmRelocationInit - SmmRelocationStart: 0x%08x\n", SmmRelocationStart));
|
---|
499 |
|
---|
500 | //
|
---|
501 | // Fix up the address of the global variable or function referred in
|
---|
502 | // SmmInit assembly files to be the absolute address
|
---|
503 | //
|
---|
504 | SmmInitFixupAddress ();
|
---|
505 |
|
---|
506 | //
|
---|
507 | // Patch SMI stack for SMM base relocation
|
---|
508 | // Note: No need allocate stack for all CPUs since the relocation
|
---|
509 | // occurs serially for each CPU
|
---|
510 | //
|
---|
511 | SmmStackSize = EFI_PAGE_SIZE;
|
---|
512 | SmmStacks = (UINT8 *)AllocatePages (EFI_SIZE_TO_PAGES (SmmStackSize));
|
---|
513 | if (SmmStacks == NULL) {
|
---|
514 | Status = EFI_OUT_OF_RESOURCES;
|
---|
515 | goto ON_EXIT;
|
---|
516 | }
|
---|
517 |
|
---|
518 | DEBUG ((DEBUG_INFO, "SmmRelocationInit - SmmStackSize: 0x%08x\n", SmmStackSize));
|
---|
519 | DEBUG ((DEBUG_INFO, "SmmRelocationInit - SmmStacks: 0x%08x\n", SmmStacks));
|
---|
520 |
|
---|
521 | PatchInstructionX86 (
|
---|
522 | gPatchSmmInitStack,
|
---|
523 | (UINTN)(SmmStacks + SmmStackSize - sizeof (UINTN)),
|
---|
524 | sizeof (UINTN)
|
---|
525 | );
|
---|
526 |
|
---|
527 | //
|
---|
528 | // Initialize the SMM IDT for SMM base relocation
|
---|
529 | //
|
---|
530 | InitSmmIdt ();
|
---|
531 |
|
---|
532 | //
|
---|
533 | // Relocate SmmBases for each processor.
|
---|
534 | //
|
---|
535 | SmmRelocateBases (MpServices2, SmmRelocationStart, TileSize);
|
---|
536 |
|
---|
537 | //
|
---|
538 | // Create the SmBase HOB for all CPUs
|
---|
539 | //
|
---|
540 | Status = CreateSmmBaseHob (SmmRelocationStart, TileSize);
|
---|
541 |
|
---|
542 | ON_EXIT:
|
---|
543 | if (SmmStacks != NULL) {
|
---|
544 | FreePages (SmmStacks, EFI_SIZE_TO_PAGES (SmmStackSize));
|
---|
545 | }
|
---|
546 |
|
---|
547 | DEBUG ((DEBUG_INFO, "SmmRelocationInit Done\n"));
|
---|
548 | return Status;
|
---|
549 | }
|
---|