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