]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/CpuDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuDxe.c
CommitLineData
a47463f2 1/** @file\r
7fadaacd 2 CPU DXE Module to produce CPU ARCH Protocol.\r
a47463f2 3\r
2a09527e 4 Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a47463f2 6\r
7**/\r
8\r
9#include "CpuDxe.h"\r
6022e28c 10#include "CpuMp.h"\r
22292ed3
JY
11#include "CpuPageTable.h"\r
12\r
2a09527e
RN
13#define CPU_INTERRUPT_NUM 256\r
14\r
a47463f2 15//\r
16// Global Variables\r
17//\r
053e878b
MK
18BOOLEAN InterruptState = FALSE;\r
19EFI_HANDLE mCpuHandle = NULL;\r
20BOOLEAN mIsFlushingGCD;\r
21BOOLEAN mIsAllocatingPageTable = FALSE;\r
22UINT64 mValidMtrrAddressMask;\r
23UINT64 mValidMtrrBitsMask;\r
24UINT64 mTimerPeriod = 0;\r
25\r
26FIXED_MTRR mFixedMtrrTable[] = {\r
a47463f2 27 {\r
b1bd0d74 28 MSR_IA32_MTRR_FIX64K_00000,\r
a47463f2 29 0,\r
30 0x10000\r
31 },\r
32 {\r
b1bd0d74 33 MSR_IA32_MTRR_FIX16K_80000,\r
a47463f2 34 0x80000,\r
35 0x4000\r
36 },\r
37 {\r
b1bd0d74 38 MSR_IA32_MTRR_FIX16K_A0000,\r
a47463f2 39 0xA0000,\r
40 0x4000\r
41 },\r
42 {\r
b1bd0d74 43 MSR_IA32_MTRR_FIX4K_C0000,\r
a47463f2 44 0xC0000,\r
45 0x1000\r
46 },\r
47 {\r
b1bd0d74 48 MSR_IA32_MTRR_FIX4K_C8000,\r
a47463f2 49 0xC8000,\r
50 0x1000\r
51 },\r
52 {\r
b1bd0d74 53 MSR_IA32_MTRR_FIX4K_D0000,\r
a47463f2 54 0xD0000,\r
55 0x1000\r
56 },\r
57 {\r
b1bd0d74 58 MSR_IA32_MTRR_FIX4K_D8000,\r
a47463f2 59 0xD8000,\r
60 0x1000\r
61 },\r
62 {\r
b1bd0d74 63 MSR_IA32_MTRR_FIX4K_E0000,\r
a47463f2 64 0xE0000,\r
65 0x1000\r
66 },\r
67 {\r
b1bd0d74 68 MSR_IA32_MTRR_FIX4K_E8000,\r
a47463f2 69 0xE8000,\r
70 0x1000\r
71 },\r
72 {\r
b1bd0d74 73 MSR_IA32_MTRR_FIX4K_F0000,\r
a47463f2 74 0xF0000,\r
75 0x1000\r
76 },\r
77 {\r
b1bd0d74 78 MSR_IA32_MTRR_FIX4K_F8000,\r
a47463f2 79 0xF8000,\r
80 0x1000\r
81 },\r
82};\r
83\r
a47463f2 84EFI_CPU_ARCH_PROTOCOL gCpu = {\r
85 CpuFlushCpuDataCache,\r
86 CpuEnableInterrupt,\r
87 CpuDisableInterrupt,\r
88 CpuGetInterruptState,\r
89 CpuInit,\r
90 CpuRegisterInterruptHandler,\r
91 CpuGetTimerValue,\r
92 CpuSetMemoryAttributes,\r
93 1, // NumberOfTimers\r
94 4 // DmaBufferAlignment\r
95};\r
96\r
a47463f2 97//\r
98// CPU Arch Protocol Functions\r
99//\r
100\r
a47463f2 101/**\r
102 Flush CPU data cache. If the instruction cache is fully coherent\r
103 with all DMA operations then function can just return EFI_SUCCESS.\r
104\r
105 @param This Protocol instance structure\r
106 @param Start Physical address to start flushing from.\r
107 @param Length Number of bytes to flush. Round up to chipset\r
108 granularity.\r
109 @param FlushType Specifies the type of flush operation to perform.\r
110\r
111 @retval EFI_SUCCESS If cache was flushed\r
112 @retval EFI_UNSUPPORTED If flush type is not supported.\r
113 @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
114\r
115**/\r
116EFI_STATUS\r
117EFIAPI\r
118CpuFlushCpuDataCache (\r
053e878b
MK
119 IN EFI_CPU_ARCH_PROTOCOL *This,\r
120 IN EFI_PHYSICAL_ADDRESS Start,\r
121 IN UINT64 Length,\r
122 IN EFI_CPU_FLUSH_TYPE FlushType\r
a47463f2 123 )\r
124{\r
125 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {\r
126 AsmWbinvd ();\r
127 return EFI_SUCCESS;\r
128 } else if (FlushType == EfiCpuFlushTypeInvalidate) {\r
129 AsmInvd ();\r
130 return EFI_SUCCESS;\r
131 } else {\r
132 return EFI_UNSUPPORTED;\r
133 }\r
134}\r
135\r
a47463f2 136/**\r
137 Enables CPU interrupts.\r
138\r
139 @param This Protocol instance structure\r
140\r
141 @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
142 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
143\r
144**/\r
145EFI_STATUS\r
146EFIAPI\r
147CpuEnableInterrupt (\r
053e878b 148 IN EFI_CPU_ARCH_PROTOCOL *This\r
a47463f2 149 )\r
150{\r
151 EnableInterrupts ();\r
152\r
153 InterruptState = TRUE;\r
154 return EFI_SUCCESS;\r
155}\r
156\r
a47463f2 157/**\r
158 Disables CPU interrupts.\r
159\r
160 @param This Protocol instance structure\r
161\r
162 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
163 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
164\r
165**/\r
166EFI_STATUS\r
167EFIAPI\r
168CpuDisableInterrupt (\r
053e878b 169 IN EFI_CPU_ARCH_PROTOCOL *This\r
a47463f2 170 )\r
171{\r
172 DisableInterrupts ();\r
173\r
174 InterruptState = FALSE;\r
175 return EFI_SUCCESS;\r
176}\r
177\r
a47463f2 178/**\r
179 Return the state of interrupts.\r
180\r
181 @param This Protocol instance structure\r
182 @param State Pointer to the CPU's current interrupt state\r
183\r
184 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
185 @retval EFI_INVALID_PARAMETER State is NULL.\r
186\r
187**/\r
188EFI_STATUS\r
189EFIAPI\r
190CpuGetInterruptState (\r
053e878b
MK
191 IN EFI_CPU_ARCH_PROTOCOL *This,\r
192 OUT BOOLEAN *State\r
a47463f2 193 )\r
194{\r
195 if (State == NULL) {\r
196 return EFI_INVALID_PARAMETER;\r
197 }\r
198\r
199 *State = InterruptState;\r
200 return EFI_SUCCESS;\r
201}\r
202\r
a47463f2 203/**\r
204 Generates an INIT to the CPU.\r
205\r
206 @param This Protocol instance structure\r
207 @param InitType Type of CPU INIT to perform\r
208\r
209 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
210 seen.\r
211 @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
212 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
213\r
214**/\r
215EFI_STATUS\r
216EFIAPI\r
217CpuInit (\r
053e878b
MK
218 IN EFI_CPU_ARCH_PROTOCOL *This,\r
219 IN EFI_CPU_INIT_TYPE InitType\r
a47463f2 220 )\r
221{\r
222 return EFI_UNSUPPORTED;\r
223}\r
224\r
a47463f2 225/**\r
226 Registers a function to be called from the CPU interrupt handler.\r
227\r
228 @param This Protocol instance structure\r
229 @param InterruptType Defines which interrupt to hook. IA-32\r
230 valid range is 0x00 through 0xFF\r
231 @param InterruptHandler A pointer to a function of type\r
232 EFI_CPU_INTERRUPT_HANDLER that is called\r
233 when a processor interrupt occurs. A null\r
234 pointer is an error condition.\r
235\r
236 @retval EFI_SUCCESS If handler installed or uninstalled.\r
237 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
238 for InterruptType was previously installed.\r
239 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
240 InterruptType was not previously installed.\r
241 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
242 is not supported.\r
243\r
244**/\r
245EFI_STATUS\r
246EFIAPI\r
247CpuRegisterInterruptHandler (\r
053e878b
MK
248 IN EFI_CPU_ARCH_PROTOCOL *This,\r
249 IN EFI_EXCEPTION_TYPE InterruptType,\r
250 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
a47463f2 251 )\r
252{\r
e41aad15 253 return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);\r
a47463f2 254}\r
255\r
a47463f2 256/**\r
257 Returns a timer value from one of the CPU's internal timers. There is no\r
258 inherent time interval between ticks but is a function of the CPU frequency.\r
259\r
260 @param This - Protocol instance structure.\r
261 @param TimerIndex - Specifies which CPU timer is requested.\r
262 @param TimerValue - Pointer to the returned timer value.\r
263 @param TimerPeriod - A pointer to the amount of time that passes\r
264 in femtoseconds (10-15) for each increment\r
265 of TimerValue. If TimerValue does not\r
266 increment at a predictable rate, then 0 is\r
267 returned. The amount of time that has\r
268 passed between two calls to GetTimerValue()\r
269 can be calculated with the formula\r
270 (TimerValue2 - TimerValue1) * TimerPeriod.\r
271 This parameter is optional and may be NULL.\r
272\r
273 @retval EFI_SUCCESS - If the CPU timer count was returned.\r
274 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
275 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
276 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
277\r
278**/\r
279EFI_STATUS\r
280EFIAPI\r
281CpuGetTimerValue (\r
053e878b
MK
282 IN EFI_CPU_ARCH_PROTOCOL *This,\r
283 IN UINT32 TimerIndex,\r
284 OUT UINT64 *TimerValue,\r
285 OUT UINT64 *TimerPeriod OPTIONAL\r
a47463f2 286 )\r
287{\r
053e878b
MK
288 UINT64 BeginValue;\r
289 UINT64 EndValue;\r
7537f8c0 290\r
a47463f2 291 if (TimerValue == NULL) {\r
292 return EFI_INVALID_PARAMETER;\r
293 }\r
294\r
295 if (TimerIndex != 0) {\r
296 return EFI_INVALID_PARAMETER;\r
297 }\r
298\r
299 *TimerValue = AsmReadTsc ();\r
300\r
301 if (TimerPeriod != NULL) {\r
7537f8c0
JF
302 if (mTimerPeriod == 0) {\r
303 //\r
304 // Read time stamp counter before and after delay of 100 microseconds\r
305 //\r
306 BeginValue = AsmReadTsc ();\r
307 MicroSecondDelay (100);\r
053e878b 308 EndValue = AsmReadTsc ();\r
a47463f2 309 //\r
7537f8c0 310 // Calculate the actual frequency\r
a47463f2 311 //\r
7537f8c0
JF
312 mTimerPeriod = DivU64x64Remainder (\r
313 MultU64x32 (\r
314 1000 * 1000 * 1000,\r
315 100\r
316 ),\r
317 EndValue - BeginValue,\r
318 NULL\r
319 );\r
320 }\r
053e878b 321\r
7537f8c0 322 *TimerPeriod = mTimerPeriod;\r
a47463f2 323 }\r
324\r
325 return EFI_SUCCESS;\r
326}\r
327\r
0b9f0dd6
JF
328/**\r
329 A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to\r
330 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.\r
331\r
332 @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to\r
333 MtrrSetAllMtrrs().\r
334**/\r
335VOID\r
336EFIAPI\r
337SetMtrrsFromBuffer (\r
053e878b 338 IN VOID *Buffer\r
0b9f0dd6
JF
339 )\r
340{\r
341 MtrrSetAllMtrrs (Buffer);\r
342}\r
a47463f2 343\r
344/**\r
4ec21e8b 345 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.\r
346\r
347 This function modifies the attributes for the memory region specified by BaseAddress and\r
348 Length from their current attributes to the attributes specified by Attributes.\r
349\r
350 @param This The EFI_CPU_ARCH_PROTOCOL instance.\r
351 @param BaseAddress The physical address that is the start address of a memory region.\r
352 @param Length The size in bytes of the memory region.\r
353 @param Attributes The bit mask of attributes to set for the memory region.\r
354\r
355 @retval EFI_SUCCESS The attributes were set for the memory region.\r
356 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
357 BaseAddress and Length cannot be modified.\r
358 @retval EFI_INVALID_PARAMETER Length is zero.\r
359 Attributes specified an illegal combination of attributes that\r
360 cannot be set together.\r
361 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
362 the memory resource range.\r
363 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
364 resource range specified by BaseAddress and Length.\r
365 The bit mask of attributes is not support for the memory resource\r
366 range specified by BaseAddress and Length.\r
a47463f2 367\r
368**/\r
369EFI_STATUS\r
370EFIAPI\r
371CpuSetMemoryAttributes (\r
053e878b
MK
372 IN EFI_CPU_ARCH_PROTOCOL *This,\r
373 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
374 IN UINT64 Length,\r
375 IN UINT64 Attributes\r
a47463f2 376 )\r
377{\r
378 RETURN_STATUS Status;\r
379 MTRR_MEMORY_CACHE_TYPE CacheType;\r
94941c88
LE
380 EFI_STATUS MpStatus;\r
381 EFI_MP_SERVICES_PROTOCOL *MpService;\r
382 MTRR_SETTINGS MtrrSettings;\r
22292ed3
JY
383 UINT64 CacheAttributes;\r
384 UINT64 MemoryAttributes;\r
385 MTRR_MEMORY_CACHE_TYPE CurrentCacheType;\r
947a573a 386\r
a47463f2 387 //\r
388 // If this function is called because GCD SetMemorySpaceAttributes () is called\r
f60f4cfe 389 // by RefreshGcdMemoryAttributes (), then we are just synchronizing GCD memory\r
a47463f2 390 // map with MTRR values. So there is no need to modify MTRRs, just return immediately\r
391 // to avoid unnecessary computing.\r
392 //\r
393 if (mIsFlushingGCD) {\r
053e878b 394 DEBUG ((DEBUG_VERBOSE, " Flushing GCD\n"));\r
79aca636
SEHM
395 return EFI_SUCCESS;\r
396 }\r
a47463f2 397\r
147fd35c
JW
398 //\r
399 // During memory attributes updating, new pages may be allocated to setup\r
400 // smaller granularity of page table. Page allocation action might then cause\r
401 // another calling of CpuSetMemoryAttributes() recursively, due to memory\r
402 // protection policy configured (such as PcdDxeNxMemoryProtectionPolicy).\r
403 // Since this driver will always protect memory used as page table by itself,\r
404 // there's no need to apply protection policy requested from memory service.\r
405 // So it's safe to just return EFI_SUCCESS if this time of calling is caused\r
406 // by page table memory allocation.\r
407 //\r
408 if (mIsAllocatingPageTable) {\r
053e878b 409 DEBUG ((DEBUG_VERBOSE, " Allocating page table memory\n"));\r
147fd35c
JW
410 return EFI_SUCCESS;\r
411 }\r
a47463f2 412\r
053e878b 413 CacheAttributes = Attributes & EFI_CACHE_ATTRIBUTE_MASK;\r
e77966b3 414 MemoryAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;\r
a47463f2 415\r
22292ed3
JY
416 if (Attributes != (CacheAttributes | MemoryAttributes)) {\r
417 return EFI_INVALID_PARAMETER;\r
418 }\r
a47463f2 419\r
22292ed3
JY
420 if (CacheAttributes != 0) {\r
421 if (!IsMtrrSupported ()) {\r
422 return EFI_UNSUPPORTED;\r
423 }\r
a47463f2 424\r
22292ed3 425 switch (CacheAttributes) {\r
053e878b
MK
426 case EFI_MEMORY_UC:\r
427 CacheType = CacheUncacheable;\r
428 break;\r
a47463f2 429\r
053e878b
MK
430 case EFI_MEMORY_WC:\r
431 CacheType = CacheWriteCombining;\r
432 break;\r
4ec21e8b 433\r
053e878b
MK
434 case EFI_MEMORY_WT:\r
435 CacheType = CacheWriteThrough;\r
436 break;\r
a47463f2 437\r
053e878b
MK
438 case EFI_MEMORY_WP:\r
439 CacheType = CacheWriteProtected;\r
440 break;\r
22292ed3 441\r
053e878b
MK
442 case EFI_MEMORY_WB:\r
443 CacheType = CacheWriteBack;\r
444 break;\r
22292ed3 445\r
053e878b
MK
446 default:\r
447 return EFI_INVALID_PARAMETER;\r
22292ed3 448 }\r
053e878b
MK
449\r
450 CurrentCacheType = MtrrGetMemoryAttribute (BaseAddress);\r
22292ed3
JY
451 if (CurrentCacheType != CacheType) {\r
452 //\r
f60f4cfe 453 // call MTRR library function\r
22292ed3
JY
454 //\r
455 Status = MtrrSetMemoryAttribute (\r
456 BaseAddress,\r
457 Length,\r
458 CacheType\r
459 );\r
460\r
461 if (!RETURN_ERROR (Status)) {\r
462 MpStatus = gBS->LocateProtocol (\r
463 &gEfiMpServiceProtocolGuid,\r
464 NULL,\r
465 (VOID **)&MpService\r
466 );\r
467 //\r
468 // Synchronize the update with all APs\r
469 //\r
470 if (!EFI_ERROR (MpStatus)) {\r
471 MtrrGetAllMtrrs (&MtrrSettings);\r
472 MpStatus = MpService->StartupAllAPs (\r
473 MpService, // This\r
474 SetMtrrsFromBuffer, // Procedure\r
475 FALSE, // SingleThread\r
476 NULL, // WaitEvent\r
477 0, // TimeoutInMicrosecsond\r
478 &MtrrSettings, // ProcedureArgument\r
479 NULL // FailedCpuList\r
480 );\r
481 ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);\r
482 }\r
483 }\r
053e878b
MK
484\r
485 if (EFI_ERROR (Status)) {\r
22292ed3
JY
486 return Status;\r
487 }\r
94941c88
LE
488 }\r
489 }\r
22292ed3
JY
490\r
491 //\r
492 // Set memory attribute by page table\r
493 //\r
147fd35c 494 return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);\r
a47463f2 495}\r
496\r
497/**\r
498 Initializes the valid bits mask and valid address mask for MTRRs.\r
499\r
500 This function initializes the valid bits mask and valid address mask for MTRRs.\r
501\r
502**/\r
503VOID\r
504InitializeMtrrMask (\r
505 VOID\r
506 )\r
507{\r
053e878b
MK
508 UINT32 RegEax;\r
509 UINT8 PhysicalAddressBits;\r
a47463f2 510\r
511 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
512\r
513 if (RegEax >= 0x80000008) {\r
514 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
515\r
053e878b 516 PhysicalAddressBits = (UINT8)RegEax;\r
a47463f2 517 } else {\r
c894f83f 518 PhysicalAddressBits = 36;\r
a47463f2 519 }\r
c894f83f
ED
520\r
521 mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
522 mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;\r
a47463f2 523}\r
524\r
525/**\r
430fbbe0 526 Gets GCD Mem Space type from MTRR Type.\r
a47463f2 527\r
430fbbe0 528 This function gets GCD Mem Space type from MTRR Type.\r
a47463f2 529\r
430fbbe0 530 @param MtrrAttributes MTRR memory type\r
a47463f2 531\r
532 @return GCD Mem Space type\r
533\r
534**/\r
535UINT64\r
536GetMemorySpaceAttributeFromMtrrType (\r
053e878b 537 IN UINT8 MtrrAttributes\r
a47463f2 538 )\r
539{\r
540 switch (MtrrAttributes) {\r
053e878b
MK
541 case MTRR_CACHE_UNCACHEABLE:\r
542 return EFI_MEMORY_UC;\r
543 case MTRR_CACHE_WRITE_COMBINING:\r
544 return EFI_MEMORY_WC;\r
545 case MTRR_CACHE_WRITE_THROUGH:\r
546 return EFI_MEMORY_WT;\r
547 case MTRR_CACHE_WRITE_PROTECTED:\r
548 return EFI_MEMORY_WP;\r
549 case MTRR_CACHE_WRITE_BACK:\r
550 return EFI_MEMORY_WB;\r
551 default:\r
552 return 0;\r
a47463f2 553 }\r
554}\r
555\r
556/**\r
557 Searches memory descriptors covered by given memory range.\r
558\r
559 This function searches into the Gcd Memory Space for descriptors\r
560 (from StartIndex to EndIndex) that contains the memory range\r
561 specified by BaseAddress and Length.\r
562\r
563 @param MemorySpaceMap Gcd Memory Space Map as array.\r
564 @param NumberOfDescriptors Number of descriptors in map.\r
565 @param BaseAddress BaseAddress for the requested range.\r
566 @param Length Length for the requested range.\r
567 @param StartIndex Start index into the Gcd Memory Space Map.\r
568 @param EndIndex End index into the Gcd Memory Space Map.\r
569\r
570 @retval EFI_SUCCESS Search successfully.\r
571 @retval EFI_NOT_FOUND The requested descriptors does not exist.\r
572\r
573**/\r
574EFI_STATUS\r
575SearchGcdMemorySpaces (\r
053e878b
MK
576 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
577 IN UINTN NumberOfDescriptors,\r
578 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
579 IN UINT64 Length,\r
580 OUT UINTN *StartIndex,\r
581 OUT UINTN *EndIndex\r
a47463f2 582 )\r
583{\r
053e878b 584 UINTN Index;\r
a47463f2 585\r
586 *StartIndex = 0;\r
587 *EndIndex = 0;\r
588 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
053e878b
MK
589 if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&\r
590 (BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))\r
591 {\r
a47463f2 592 *StartIndex = Index;\r
593 }\r
053e878b
MK
594\r
595 if ((BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress) &&\r
596 (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))\r
597 {\r
a47463f2 598 *EndIndex = Index;\r
599 return EFI_SUCCESS;\r
600 }\r
601 }\r
053e878b 602\r
a47463f2 603 return EFI_NOT_FOUND;\r
604}\r
605\r
606/**\r
607 Sets the attributes for a specified range in Gcd Memory Space Map.\r
608\r
609 This function sets the attributes for a specified range in\r
610 Gcd Memory Space Map.\r
611\r
612 @param MemorySpaceMap Gcd Memory Space Map as array\r
613 @param NumberOfDescriptors Number of descriptors in map\r
614 @param BaseAddress BaseAddress for the range\r
615 @param Length Length for the range\r
616 @param Attributes Attributes to set\r
617\r
618 @retval EFI_SUCCESS Memory attributes set successfully\r
619 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space\r
620\r
621**/\r
622EFI_STATUS\r
623SetGcdMemorySpaceAttributes (\r
053e878b
MK
624 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
625 IN UINTN NumberOfDescriptors,\r
626 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
627 IN UINT64 Length,\r
628 IN UINT64 Attributes\r
a47463f2 629 )\r
630{\r
631 EFI_STATUS Status;\r
632 UINTN Index;\r
633 UINTN StartIndex;\r
634 UINTN EndIndex;\r
635 EFI_PHYSICAL_ADDRESS RegionStart;\r
636 UINT64 RegionLength;\r
637\r
638 //\r
639 // Get all memory descriptors covered by the memory range\r
640 //\r
641 Status = SearchGcdMemorySpaces (\r
642 MemorySpaceMap,\r
643 NumberOfDescriptors,\r
644 BaseAddress,\r
645 Length,\r
646 &StartIndex,\r
647 &EndIndex\r
648 );\r
649 if (EFI_ERROR (Status)) {\r
650 return Status;\r
651 }\r
652\r
653 //\r
654 // Go through all related descriptors and set attributes accordingly\r
655 //\r
656 for (Index = StartIndex; Index <= EndIndex; Index++) {\r
657 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
658 continue;\r
659 }\r
053e878b 660\r
a47463f2 661 //\r
662 // Calculate the start and end address of the overlapping range\r
663 //\r
664 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {\r
665 RegionStart = BaseAddress;\r
666 } else {\r
667 RegionStart = MemorySpaceMap[Index].BaseAddress;\r
668 }\r
053e878b 669\r
a47463f2 670 if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
671 RegionLength = BaseAddress + Length - RegionStart;\r
672 } else {\r
673 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;\r
674 }\r
053e878b 675\r
a47463f2 676 //\r
677 // Set memory attributes according to MTRR attribute and the original attribute of descriptor\r
678 //\r
679 gDS->SetMemorySpaceAttributes (\r
680 RegionStart,\r
681 RegionLength,\r
e77966b3 682 (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)\r
a47463f2 683 );\r
684 }\r
685\r
686 return EFI_SUCCESS;\r
687}\r
688\r
a47463f2 689/**\r
690 Refreshes the GCD Memory Space attributes according to MTRRs.\r
691\r
692 This function refreshes the GCD Memory Space attributes according to MTRRs.\r
693\r
694**/\r
695VOID\r
c46bced2 696RefreshMemoryAttributesFromMtrr (\r
a47463f2 697 VOID\r
698 )\r
699{\r
053e878b
MK
700 EFI_STATUS Status;\r
701 UINTN Index;\r
702 UINTN SubIndex;\r
703 UINT64 RegValue;\r
704 EFI_PHYSICAL_ADDRESS BaseAddress;\r
705 UINT64 Length;\r
706 UINT64 Attributes;\r
707 UINT64 CurrentAttributes;\r
708 UINT8 MtrrType;\r
709 UINTN NumberOfDescriptors;\r
710 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
711 UINT64 DefaultAttributes;\r
712 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
713 MTRR_FIXED_SETTINGS MtrrFixedSettings;\r
714 UINT32 FirmwareVariableMtrrCount;\r
715 UINT8 DefaultMemoryType;\r
3b9be416
JY
716\r
717 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
5bdfa4e5 718 ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
a47463f2 719\r
a47463f2 720 MemorySpaceMap = NULL;\r
721\r
722 //\r
723 // Initialize the valid bits mask and valid address mask for MTRRs\r
724 //\r
725 InitializeMtrrMask ();\r
726\r
727 //\r
728 // Get the memory attribute of variable MTRRs\r
729 //\r
730 MtrrGetMemoryAttributeInVariableMtrr (\r
731 mValidMtrrBitsMask,\r
732 mValidMtrrAddressMask,\r
733 VariableMtrr\r
734 );\r
735\r
736 //\r
737 // Get the memory space map from GCD\r
738 //\r
739 Status = gDS->GetMemorySpaceMap (\r
740 &NumberOfDescriptors,\r
741 &MemorySpaceMap\r
742 );\r
743 ASSERT_EFI_ERROR (Status);\r
744\r
053e878b 745 DefaultMemoryType = (UINT8)MtrrGetDefaultMemoryType ();\r
91ec7824 746 DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);\r
a47463f2 747\r
748 //\r
749 // Set default attributes to all spaces.\r
750 //\r
751 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
752 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
753 continue;\r
754 }\r
053e878b 755\r
a47463f2 756 gDS->SetMemorySpaceAttributes (\r
757 MemorySpaceMap[Index].BaseAddress,\r
758 MemorySpaceMap[Index].Length,\r
e77966b3 759 (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) |\r
a47463f2 760 (MemorySpaceMap[Index].Capabilities & DefaultAttributes)\r
761 );\r
762 }\r
763\r
764 //\r
765 // Go for variable MTRRs with WB attribute\r
766 //\r
3b9be416 767 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
a47463f2 768 if (VariableMtrr[Index].Valid &&\r
053e878b
MK
769 (VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK))\r
770 {\r
a47463f2 771 SetGcdMemorySpaceAttributes (\r
772 MemorySpaceMap,\r
773 NumberOfDescriptors,\r
774 VariableMtrr[Index].BaseAddress,\r
775 VariableMtrr[Index].Length,\r
776 EFI_MEMORY_WB\r
777 );\r
778 }\r
779 }\r
91ec7824 780\r
a47463f2 781 //\r
91ec7824 782 // Go for variable MTRRs with the attribute except for WB and UC attributes\r
a47463f2 783 //\r
3b9be416 784 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
d4605c23 785 if (VariableMtrr[Index].Valid &&\r
053e878b
MK
786 (VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) &&\r
787 (VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE))\r
788 {\r
789 Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8)VariableMtrr[Index].Type);\r
a47463f2 790 SetGcdMemorySpaceAttributes (\r
791 MemorySpaceMap,\r
792 NumberOfDescriptors,\r
793 VariableMtrr[Index].BaseAddress,\r
794 VariableMtrr[Index].Length,\r
795 Attributes\r
796 );\r
797 }\r
798 }\r
799\r
91ec7824 800 //\r
801 // Go for variable MTRRs with UC attribute\r
802 //\r
803 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
804 if (VariableMtrr[Index].Valid &&\r
053e878b
MK
805 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE))\r
806 {\r
91ec7824 807 SetGcdMemorySpaceAttributes (\r
808 MemorySpaceMap,\r
809 NumberOfDescriptors,\r
810 VariableMtrr[Index].BaseAddress,\r
811 VariableMtrr[Index].Length,\r
812 EFI_MEMORY_UC\r
813 );\r
814 }\r
815 }\r
816\r
a47463f2 817 //\r
818 // Go for fixed MTRRs\r
819 //\r
820 Attributes = 0;\r
821 BaseAddress = 0;\r
822 Length = 0;\r
823 MtrrGetFixedMtrr (&MtrrFixedSettings);\r
824 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
825 RegValue = MtrrFixedSettings.Mtrr[Index];\r
826 //\r
827 // Check for continuous fixed MTRR sections\r
828 //\r
829 for (SubIndex = 0; SubIndex < 8; SubIndex++) {\r
053e878b 830 MtrrType = (UINT8)RShiftU64 (RegValue, SubIndex * 8);\r
a47463f2 831 CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);\r
832 if (Length == 0) {\r
833 //\r
834 // A new MTRR attribute begins\r
835 //\r
836 Attributes = CurrentAttributes;\r
837 } else {\r
838 //\r
f60f4cfe 839 // If fixed MTRR attribute changed, then set memory attribute for previous attribute\r
a47463f2 840 //\r
841 if (CurrentAttributes != Attributes) {\r
842 SetGcdMemorySpaceAttributes (\r
843 MemorySpaceMap,\r
844 NumberOfDescriptors,\r
845 BaseAddress,\r
846 Length,\r
847 Attributes\r
848 );\r
849 BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;\r
053e878b
MK
850 Length = 0;\r
851 Attributes = CurrentAttributes;\r
a47463f2 852 }\r
853 }\r
053e878b 854\r
a47463f2 855 Length += mFixedMtrrTable[Index].Length;\r
856 }\r
857 }\r
053e878b 858\r
a47463f2 859 //\r
860 // Handle the last fixed MTRR region\r
861 //\r
862 SetGcdMemorySpaceAttributes (\r
863 MemorySpaceMap,\r
864 NumberOfDescriptors,\r
865 BaseAddress,\r
866 Length,\r
867 Attributes\r
868 );\r
869\r
870 //\r
871 // Free memory space map allocated by GCD service GetMemorySpaceMap ()\r
872 //\r
873 if (MemorySpaceMap != NULL) {\r
874 FreePool (MemorySpaceMap);\r
875 }\r
c46bced2 876}\r
a47463f2 877\r
c46bced2
JW
878/**\r
879 Check if paging is enabled or not.\r
880**/\r
881BOOLEAN\r
882IsPagingAndPageAddressExtensionsEnabled (\r
883 VOID\r
884 )\r
885{\r
886 IA32_CR0 Cr0;\r
887 IA32_CR4 Cr4;\r
888\r
889 Cr0.UintN = AsmReadCr0 ();\r
890 Cr4.UintN = AsmReadCr4 ();\r
891\r
892 return ((Cr0.Bits.PG != 0) && (Cr4.Bits.PAE != 0));\r
893}\r
894\r
895/**\r
896 Refreshes the GCD Memory Space attributes according to MTRRs and Paging.\r
897\r
898 This function refreshes the GCD Memory Space attributes according to MTRRs\r
899 and page tables.\r
900\r
901**/\r
902VOID\r
903RefreshGcdMemoryAttributes (\r
904 VOID\r
905 )\r
906{\r
907 mIsFlushingGCD = TRUE;\r
908\r
909 if (IsMtrrSupported ()) {\r
910 RefreshMemoryAttributesFromMtrr ();\r
911 }\r
912\r
913 if (IsPagingAndPageAddressExtensionsEnabled ()) {\r
914 RefreshGcdMemoryAttributesFromPaging ();\r
915 }\r
c1cab54c 916\r
a47463f2 917 mIsFlushingGCD = FALSE;\r
918}\r
919\r
a47463f2 920/**\r
921 Initialize Interrupt Descriptor Table for interrupt handling.\r
922\r
923**/\r
a47463f2 924VOID\r
925InitInterruptDescriptorTable (\r
926 VOID\r
927 )\r
928{\r
2a09527e
RN
929 EFI_STATUS Status;\r
930 EFI_VECTOR_HANDOFF_INFO *VectorInfoList;\r
931 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
932 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
933 IA32_DESCRIPTOR IdtDescriptor;\r
934 UINTN IdtEntryCount;\r
e41aad15
JF
935\r
936 VectorInfo = NULL;\r
053e878b
MK
937 Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);\r
938 if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {\r
e41aad15 939 VectorInfo = VectorInfoList;\r
a47463f2 940 }\r
053e878b 941\r
2a09527e
RN
942 AsmReadIdtr (&IdtDescriptor);\r
943 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
944 if (IdtEntryCount < CPU_INTERRUPT_NUM) {\r
945 //\r
946 // Increase Interrupt Descriptor Table and Copy the old IDT table in\r
947 //\r
948 IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);\r
949 ASSERT (IdtTable != NULL);\r
950 CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);\r
951\r
952 //\r
953 // Load Interrupt Descriptor Table\r
954 //\r
955 IdtDescriptor.Base = (UINTN)IdtTable;\r
956 IdtDescriptor.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);\r
957 AsmWriteIdtr (&IdtDescriptor);\r
958 }\r
959\r
960 Status = InitializeCpuExceptionHandlers (VectorInfo);\r
e41aad15 961 ASSERT_EFI_ERROR (Status);\r
a47463f2 962}\r
963\r
32394027 964/**\r
965 Callback function for idle events.\r
d4605c23 966\r
32394027 967 @param Event Event whose notification function is being invoked.\r
968 @param Context The pointer to the notification function's context,\r
969 which is implementation-dependent.\r
970\r
971**/\r
972VOID\r
973EFIAPI\r
974IdleLoopEventCallback (\r
053e878b
MK
975 IN EFI_EVENT Event,\r
976 IN VOID *Context\r
32394027 977 )\r
978{\r
979 CpuSleep ();\r
980}\r
981\r
410590f1
JF
982/**\r
983 Ensure the compatibility of a memory space descriptor with the MMIO aperture.\r
984\r
985 The memory space descriptor can come from the GCD memory space map, or it can\r
986 represent a gap between two neighboring memory space descriptors. In the\r
987 latter case, the GcdMemoryType field is expected to be\r
988 EfiGcdMemoryTypeNonExistent.\r
989\r
990 If the memory space descriptor already has type\r
991 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the\r
992 required capabilities, then no action is taken -- it is by definition\r
993 compatible with the aperture.\r
994\r
995 Otherwise, the intersection of the memory space descriptor is calculated with\r
996 the aperture. If the intersection is the empty set (no overlap), no action is\r
997 taken; the memory space descriptor is compatible with the aperture.\r
998\r
999 Otherwise, the type of the descriptor is investigated again. If the type is\r
1000 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with\r
1001 such a type), then an attempt is made to add the intersection as MMIO space\r
1002 to the GCD memory space map, with the specified capabilities. This ensures\r
1003 continuity for the aperture, and the descriptor is deemed compatible with the\r
1004 aperture.\r
1005\r
1006 Otherwise, the memory space descriptor is incompatible with the MMIO\r
1007 aperture.\r
1008\r
1009 @param[in] Base Base address of the aperture.\r
1010 @param[in] Length Length of the aperture.\r
1011 @param[in] Capabilities Capabilities required by the aperture.\r
1012 @param[in] Descriptor The descriptor to ensure compatibility with the\r
1013 aperture for.\r
1014\r
1015 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory\r
1016 space map may have been updated, for\r
1017 continuity within the aperture.\r
1018 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.\r
1019 @return Error codes from gDS->AddMemorySpace().\r
1020**/\r
1021EFI_STATUS\r
1022IntersectMemoryDescriptor (\r
053e878b
MK
1023 IN UINT64 Base,\r
1024 IN UINT64 Length,\r
1025 IN UINT64 Capabilities,\r
1026 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor\r
410590f1
JF
1027 )\r
1028{\r
053e878b
MK
1029 UINT64 IntersectionBase;\r
1030 UINT64 IntersectionEnd;\r
1031 EFI_STATUS Status;\r
410590f1 1032\r
053e878b
MK
1033 if ((Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
1034 ((Descriptor->Capabilities & Capabilities) == Capabilities))\r
1035 {\r
410590f1
JF
1036 return EFI_SUCCESS;\r
1037 }\r
1038\r
1039 IntersectionBase = MAX (Base, Descriptor->BaseAddress);\r
053e878b
MK
1040 IntersectionEnd = MIN (\r
1041 Base + Length,\r
1042 Descriptor->BaseAddress + Descriptor->Length\r
1043 );\r
410590f1
JF
1044 if (IntersectionBase >= IntersectionEnd) {\r
1045 //\r
1046 // The descriptor and the aperture don't overlap.\r
1047 //\r
1048 return EFI_SUCCESS;\r
1049 }\r
1050\r
1051 if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
053e878b
MK
1052 Status = gDS->AddMemorySpace (\r
1053 EfiGcdMemoryTypeMemoryMappedIo,\r
1054 IntersectionBase,\r
1055 IntersectionEnd - IntersectionBase,\r
1056 Capabilities\r
1057 );\r
1058\r
1059 DEBUG ((\r
1060 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
1061 "%a: %a: add [%Lx, %Lx): %r\n",\r
1062 gEfiCallerBaseName,\r
1063 __FUNCTION__,\r
1064 IntersectionBase,\r
1065 IntersectionEnd,\r
1066 Status\r
1067 ));\r
410590f1
JF
1068 return Status;\r
1069 }\r
1070\r
053e878b
MK
1071 DEBUG ((\r
1072 DEBUG_ERROR,\r
1073 "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "\r
1074 "with aperture [%Lx, %Lx) cap %Lx\n",\r
1075 gEfiCallerBaseName,\r
1076 __FUNCTION__,\r
1077 Descriptor->BaseAddress,\r
1078 Descriptor->BaseAddress + Descriptor->Length,\r
1079 (UINT32)Descriptor->GcdMemoryType,\r
1080 Descriptor->Capabilities,\r
1081 Base,\r
1082 Base + Length,\r
1083 Capabilities\r
1084 ));\r
410590f1
JF
1085 return EFI_INVALID_PARAMETER;\r
1086}\r
1087\r
1088/**\r
1089 Add MMIO space to GCD.\r
1090 The routine checks the GCD database and only adds those which are\r
1091 not added in the specified range to GCD.\r
1092\r
1093 @param Base Base address of the MMIO space.\r
1094 @param Length Length of the MMIO space.\r
1095 @param Capabilities Capabilities of the MMIO space.\r
1096\r
f60f4cfe 1097 @retval EFI_SUCCESS The MMIO space was added successfully.\r
410590f1
JF
1098**/\r
1099EFI_STATUS\r
1100AddMemoryMappedIoSpace (\r
053e878b
MK
1101 IN UINT64 Base,\r
1102 IN UINT64 Length,\r
1103 IN UINT64 Capabilities\r
410590f1
JF
1104 )\r
1105{\r
053e878b
MK
1106 EFI_STATUS Status;\r
1107 UINTN Index;\r
1108 UINTN NumberOfDescriptors;\r
1109 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
410590f1
JF
1110\r
1111 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
1112 if (EFI_ERROR (Status)) {\r
053e878b
MK
1113 DEBUG ((\r
1114 DEBUG_ERROR,\r
1115 "%a: %a: GetMemorySpaceMap(): %r\n",\r
1116 gEfiCallerBaseName,\r
1117 __FUNCTION__,\r
1118 Status\r
1119 ));\r
410590f1
JF
1120 return Status;\r
1121 }\r
1122\r
1123 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
053e878b
MK
1124 Status = IntersectMemoryDescriptor (\r
1125 Base,\r
1126 Length,\r
1127 Capabilities,\r
1128 &MemorySpaceMap[Index]\r
1129 );\r
410590f1
JF
1130 if (EFI_ERROR (Status)) {\r
1131 goto FreeMemorySpaceMap;\r
1132 }\r
1133 }\r
1134\r
7c2a6033 1135 DEBUG_CODE_BEGIN ();\r
053e878b
MK
1136 //\r
1137 // Make sure there are adjacent descriptors covering [Base, Base + Length).\r
1138 // It is possible that they have not been merged; merging can be prevented\r
1139 // by allocation and different capabilities.\r
1140 //\r
1141 UINT64 CheckBase;\r
1142 EFI_STATUS CheckStatus;\r
1143 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1144\r
1145 for (CheckBase = Base;\r
1146 CheckBase < Base + Length;\r
1147 CheckBase = Descriptor.BaseAddress + Descriptor.Length)\r
1148 {\r
1149 CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);\r
1150 ASSERT_EFI_ERROR (CheckStatus);\r
1151 ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);\r
1152 ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);\r
1153 }\r
1154\r
7c2a6033 1155 DEBUG_CODE_END ();\r
410590f1
JF
1156\r
1157FreeMemorySpaceMap:\r
1158 FreePool (MemorySpaceMap);\r
1159\r
1160 return Status;\r
1161}\r
32394027 1162\r
14f92ded 1163/**\r
7367cc6c 1164 Add and allocate CPU local APIC memory mapped space.\r
14f92ded
JF
1165\r
1166 @param[in]ImageHandle Image handle this driver.\r
1167\r
1168**/\r
1169VOID\r
1170AddLocalApicMemorySpace (\r
053e878b 1171 IN EFI_HANDLE ImageHandle\r
14f92ded
JF
1172 )\r
1173{\r
053e878b
MK
1174 EFI_STATUS Status;\r
1175 EFI_PHYSICAL_ADDRESS BaseAddress;\r
14f92ded 1176\r
053e878b
MK
1177 BaseAddress = (EFI_PHYSICAL_ADDRESS)GetLocalApicBaseAddress ();\r
1178 Status = AddMemoryMappedIoSpace (BaseAddress, SIZE_4KB, EFI_MEMORY_UC);\r
14f92ded
JF
1179 ASSERT_EFI_ERROR (Status);\r
1180\r
29c90f14 1181 //\r
7367cc6c 1182 // Try to allocate APIC memory mapped space, does not check return\r
29c90f14
JF
1183 // status because it may be allocated by other driver, or DXE Core if\r
1184 // this range is built into Memory Allocation HOB.\r
1185 //\r
14f92ded
JF
1186 Status = gDS->AllocateMemorySpace (\r
1187 EfiGcdAllocateAddress,\r
1188 EfiGcdMemoryTypeMemoryMappedIo,\r
1189 0,\r
1190 SIZE_4KB,\r
1191 &BaseAddress,\r
1192 ImageHandle,\r
1193 NULL\r
1194 );\r
29c90f14 1195 if (EFI_ERROR (Status)) {\r
053e878b
MK
1196 DEBUG ((\r
1197 DEBUG_INFO,\r
1198 "%a: %a: AllocateMemorySpace() Status - %r\n",\r
1199 gEfiCallerBaseName,\r
1200 __FUNCTION__,\r
1201 Status\r
1202 ));\r
29c90f14 1203 }\r
14f92ded
JF
1204}\r
1205\r
a47463f2 1206/**\r
1207 Initialize the state information for the CPU Architectural Protocol.\r
1208\r
1209 @param ImageHandle Image handle this driver.\r
1210 @param SystemTable Pointer to the System Table.\r
1211\r
1212 @retval EFI_SUCCESS Thread can be successfully created\r
1213 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
1214 @retval EFI_DEVICE_ERROR Cannot create the thread\r
1215\r
1216**/\r
1217EFI_STATUS\r
1218EFIAPI\r
1219InitializeCpu (\r
053e878b
MK
1220 IN EFI_HANDLE ImageHandle,\r
1221 IN EFI_SYSTEM_TABLE *SystemTable\r
a47463f2 1222 )\r
1223{\r
1224 EFI_STATUS Status;\r
32394027 1225 EFI_EVENT IdleLoopEvent;\r
7367cc6c 1226\r
053e878b 1227 InitializePageTableLib ();\r
a47463f2 1228\r
661cab5d 1229 InitializeFloatingPointUnits ();\r
1230\r
a47463f2 1231 //\r
1232 // Make sure interrupts are disabled\r
1233 //\r
1234 DisableInterrupts ();\r
1235\r
1236 //\r
1237 // Init GDT for DXE\r
1238 //\r
1239 InitGlobalDescriptorTable ();\r
1240\r
1241 //\r
1242 // Setup IDT pointer, IDT and interrupt entry points\r
1243 //\r
1244 InitInterruptDescriptorTable ();\r
1245\r
1246 //\r
1247 // Install CPU Architectural Protocol\r
1248 //\r
1249 Status = gBS->InstallMultipleProtocolInterfaces (\r
1250 &mCpuHandle,\r
053e878b
MK
1251 &gEfiCpuArchProtocolGuid,\r
1252 &gCpu,\r
a47463f2 1253 NULL\r
1254 );\r
1255 ASSERT_EFI_ERROR (Status);\r
1256\r
1257 //\r
1258 // Refresh GCD memory space map according to MTRR value.\r
1259 //\r
1260 RefreshGcdMemoryAttributes ();\r
1261\r
14f92ded
JF
1262 //\r
1263 // Add and allocate local APIC memory mapped space\r
1264 //\r
1265 AddLocalApicMemorySpace (ImageHandle);\r
1266\r
32394027 1267 //\r
1268 // Setup a callback for idle events\r
1269 //\r
1270 Status = gBS->CreateEventEx (\r
1271 EVT_NOTIFY_SIGNAL,\r
1272 TPL_NOTIFY,\r
1273 IdleLoopEventCallback,\r
1274 NULL,\r
1275 &gIdleLoopEventGuid,\r
1276 &IdleLoopEvent\r
1277 );\r
1278 ASSERT_EFI_ERROR (Status);\r
1279\r
6022e28c
JJ
1280 InitializeMpSupport ();\r
1281\r
a47463f2 1282 return Status;\r
1283}\r