]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/CpuDxe.c
ArmPkg/ArmGicLib: select GICv2 mode if SRE is present but unavailable
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuDxe.c
CommitLineData
a47463f2 1/** @file\r
2 CPU DXE Module.\r
3\r
e41aad15 4 Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>\r
01a1c0fc 5 This program and the accompanying materials\r
a47463f2 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuDxe.h"\r
16\r
17//\r
18// Global Variables\r
19//\r
a47463f2 20BOOLEAN InterruptState = FALSE;\r
21EFI_HANDLE mCpuHandle = NULL;\r
22BOOLEAN mIsFlushingGCD;\r
a47463f2 23UINT64 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
24UINT64 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
25\r
26FIXED_MTRR mFixedMtrrTable[] = {\r
27 {\r
28 MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
29 0,\r
30 0x10000\r
31 },\r
32 {\r
33 MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
34 0x80000,\r
35 0x4000\r
36 },\r
37 {\r
38 MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
39 0xA0000,\r
40 0x4000\r
41 },\r
42 {\r
43 MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
44 0xC0000,\r
45 0x1000\r
46 },\r
47 {\r
48 MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
49 0xC8000,\r
50 0x1000\r
51 },\r
52 {\r
53 MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
54 0xD0000,\r
55 0x1000\r
56 },\r
57 {\r
58 MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
59 0xD8000,\r
60 0x1000\r
61 },\r
62 {\r
63 MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
64 0xE0000,\r
65 0x1000\r
66 },\r
67 {\r
68 MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
69 0xE8000,\r
70 0x1000\r
71 },\r
72 {\r
73 MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
74 0xF0000,\r
75 0x1000\r
76 },\r
77 {\r
78 MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
79 0xF8000,\r
80 0x1000\r
81 },\r
82};\r
83\r
84\r
85EFI_CPU_ARCH_PROTOCOL gCpu = {\r
86 CpuFlushCpuDataCache,\r
87 CpuEnableInterrupt,\r
88 CpuDisableInterrupt,\r
89 CpuGetInterruptState,\r
90 CpuInit,\r
91 CpuRegisterInterruptHandler,\r
92 CpuGetTimerValue,\r
93 CpuSetMemoryAttributes,\r
94 1, // NumberOfTimers\r
95 4 // DmaBufferAlignment\r
96};\r
97\r
a47463f2 98//\r
99// CPU Arch Protocol Functions\r
100//\r
101\r
a47463f2 102/**\r
103 Flush CPU data cache. If the instruction cache is fully coherent\r
104 with all DMA operations then function can just return EFI_SUCCESS.\r
105\r
106 @param This Protocol instance structure\r
107 @param Start Physical address to start flushing from.\r
108 @param Length Number of bytes to flush. Round up to chipset\r
109 granularity.\r
110 @param FlushType Specifies the type of flush operation to perform.\r
111\r
112 @retval EFI_SUCCESS If cache was flushed\r
113 @retval EFI_UNSUPPORTED If flush type is not supported.\r
114 @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
115\r
116**/\r
117EFI_STATUS\r
118EFIAPI\r
119CpuFlushCpuDataCache (\r
120 IN EFI_CPU_ARCH_PROTOCOL *This,\r
121 IN EFI_PHYSICAL_ADDRESS Start,\r
122 IN UINT64 Length,\r
123 IN EFI_CPU_FLUSH_TYPE FlushType\r
124 )\r
125{\r
126 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {\r
127 AsmWbinvd ();\r
128 return EFI_SUCCESS;\r
129 } else if (FlushType == EfiCpuFlushTypeInvalidate) {\r
130 AsmInvd ();\r
131 return EFI_SUCCESS;\r
132 } else {\r
133 return EFI_UNSUPPORTED;\r
134 }\r
135}\r
136\r
137\r
138/**\r
139 Enables CPU interrupts.\r
140\r
141 @param This Protocol instance structure\r
142\r
143 @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
144 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
145\r
146**/\r
147EFI_STATUS\r
148EFIAPI\r
149CpuEnableInterrupt (\r
150 IN EFI_CPU_ARCH_PROTOCOL *This\r
151 )\r
152{\r
153 EnableInterrupts ();\r
154\r
155 InterruptState = TRUE;\r
156 return EFI_SUCCESS;\r
157}\r
158\r
159\r
160/**\r
161 Disables CPU interrupts.\r
162\r
163 @param This Protocol instance structure\r
164\r
165 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
166 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
167\r
168**/\r
169EFI_STATUS\r
170EFIAPI\r
171CpuDisableInterrupt (\r
172 IN EFI_CPU_ARCH_PROTOCOL *This\r
173 )\r
174{\r
175 DisableInterrupts ();\r
176\r
177 InterruptState = FALSE;\r
178 return EFI_SUCCESS;\r
179}\r
180\r
181\r
182/**\r
183 Return the state of interrupts.\r
184\r
185 @param This Protocol instance structure\r
186 @param State Pointer to the CPU's current interrupt state\r
187\r
188 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
189 @retval EFI_INVALID_PARAMETER State is NULL.\r
190\r
191**/\r
192EFI_STATUS\r
193EFIAPI\r
194CpuGetInterruptState (\r
195 IN EFI_CPU_ARCH_PROTOCOL *This,\r
196 OUT BOOLEAN *State\r
197 )\r
198{\r
199 if (State == NULL) {\r
200 return EFI_INVALID_PARAMETER;\r
201 }\r
202\r
203 *State = InterruptState;\r
204 return EFI_SUCCESS;\r
205}\r
206\r
207\r
208/**\r
209 Generates an INIT to the CPU.\r
210\r
211 @param This Protocol instance structure\r
212 @param InitType Type of CPU INIT to perform\r
213\r
214 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
215 seen.\r
216 @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
217 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
218\r
219**/\r
220EFI_STATUS\r
221EFIAPI\r
222CpuInit (\r
223 IN EFI_CPU_ARCH_PROTOCOL *This,\r
224 IN EFI_CPU_INIT_TYPE InitType\r
225 )\r
226{\r
227 return EFI_UNSUPPORTED;\r
228}\r
229\r
230\r
231/**\r
232 Registers a function to be called from the CPU interrupt handler.\r
233\r
234 @param This Protocol instance structure\r
235 @param InterruptType Defines which interrupt to hook. IA-32\r
236 valid range is 0x00 through 0xFF\r
237 @param InterruptHandler A pointer to a function of type\r
238 EFI_CPU_INTERRUPT_HANDLER that is called\r
239 when a processor interrupt occurs. A null\r
240 pointer is an error condition.\r
241\r
242 @retval EFI_SUCCESS If handler installed or uninstalled.\r
243 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
244 for InterruptType was previously installed.\r
245 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
246 InterruptType was not previously installed.\r
247 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
248 is not supported.\r
249\r
250**/\r
251EFI_STATUS\r
252EFIAPI\r
253CpuRegisterInterruptHandler (\r
254 IN EFI_CPU_ARCH_PROTOCOL *This,\r
255 IN EFI_EXCEPTION_TYPE InterruptType,\r
256 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
257 )\r
258{\r
e41aad15 259 return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);\r
a47463f2 260}\r
261\r
262\r
263/**\r
264 Returns a timer value from one of the CPU's internal timers. There is no\r
265 inherent time interval between ticks but is a function of the CPU frequency.\r
266\r
267 @param This - Protocol instance structure.\r
268 @param TimerIndex - Specifies which CPU timer is requested.\r
269 @param TimerValue - Pointer to the returned timer value.\r
270 @param TimerPeriod - A pointer to the amount of time that passes\r
271 in femtoseconds (10-15) for each increment\r
272 of TimerValue. If TimerValue does not\r
273 increment at a predictable rate, then 0 is\r
274 returned. The amount of time that has\r
275 passed between two calls to GetTimerValue()\r
276 can be calculated with the formula\r
277 (TimerValue2 - TimerValue1) * TimerPeriod.\r
278 This parameter is optional and may be NULL.\r
279\r
280 @retval EFI_SUCCESS - If the CPU timer count was returned.\r
281 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
282 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
283 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
284\r
285**/\r
286EFI_STATUS\r
287EFIAPI\r
288CpuGetTimerValue (\r
289 IN EFI_CPU_ARCH_PROTOCOL *This,\r
290 IN UINT32 TimerIndex,\r
291 OUT UINT64 *TimerValue,\r
292 OUT UINT64 *TimerPeriod OPTIONAL\r
293 )\r
294{\r
295 if (TimerValue == NULL) {\r
296 return EFI_INVALID_PARAMETER;\r
297 }\r
298\r
299 if (TimerIndex != 0) {\r
300 return EFI_INVALID_PARAMETER;\r
301 }\r
302\r
303 *TimerValue = AsmReadTsc ();\r
304\r
305 if (TimerPeriod != NULL) {\r
306 //\r
307 // BugBug: Hard coded. Don't know how to do this generically\r
308 //\r
309 *TimerPeriod = 1000000000;\r
310 }\r
311\r
312 return EFI_SUCCESS;\r
313}\r
314\r
315\r
316/**\r
4ec21e8b 317 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.\r
318\r
319 This function modifies the attributes for the memory region specified by BaseAddress and\r
320 Length from their current attributes to the attributes specified by Attributes.\r
321\r
322 @param This The EFI_CPU_ARCH_PROTOCOL instance.\r
323 @param BaseAddress The physical address that is the start address of a memory region.\r
324 @param Length The size in bytes of the memory region.\r
325 @param Attributes The bit mask of attributes to set for the memory region.\r
326\r
327 @retval EFI_SUCCESS The attributes were set for the memory region.\r
328 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
329 BaseAddress and Length cannot be modified.\r
330 @retval EFI_INVALID_PARAMETER Length is zero.\r
331 Attributes specified an illegal combination of attributes that\r
332 cannot be set together.\r
333 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
334 the memory resource range.\r
335 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
336 resource range specified by BaseAddress and Length.\r
337 The bit mask of attributes is not support for the memory resource\r
338 range specified by BaseAddress and Length.\r
a47463f2 339\r
340**/\r
341EFI_STATUS\r
342EFIAPI\r
343CpuSetMemoryAttributes (\r
344 IN EFI_CPU_ARCH_PROTOCOL *This,\r
345 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
346 IN UINT64 Length,\r
347 IN UINT64 Attributes\r
348 )\r
349{\r
350 RETURN_STATUS Status;\r
351 MTRR_MEMORY_CACHE_TYPE CacheType;\r
352\r
947a573a 353 if (!IsMtrrSupported ()) {\r
354 return EFI_UNSUPPORTED;\r
355 }\r
356\r
a47463f2 357 //\r
358 // If this function is called because GCD SetMemorySpaceAttributes () is called\r
359 // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory\r
360 // map with MTRR values. So there is no need to modify MTRRs, just return immediately\r
361 // to avoid unnecessary computing.\r
362 //\r
363 if (mIsFlushingGCD) {\r
79aca636
SEHM
364 DEBUG((EFI_D_INFO, " Flushing GCD\n"));\r
365 return EFI_SUCCESS;\r
366 }\r
a47463f2 367\r
368 switch (Attributes) {\r
369 case EFI_MEMORY_UC:\r
370 CacheType = CacheUncacheable;\r
371 break;\r
372\r
373 case EFI_MEMORY_WC:\r
374 CacheType = CacheWriteCombining;\r
375 break;\r
376\r
377 case EFI_MEMORY_WT:\r
378 CacheType = CacheWriteThrough;\r
379 break;\r
380\r
381 case EFI_MEMORY_WP:\r
382 CacheType = CacheWriteProtected;\r
383 break;\r
384\r
385 case EFI_MEMORY_WB:\r
386 CacheType = CacheWriteBack;\r
387 break;\r
388\r
4ec21e8b 389 case EFI_MEMORY_UCE:\r
390 case EFI_MEMORY_RP:\r
391 case EFI_MEMORY_XP:\r
392 case EFI_MEMORY_RUNTIME:\r
a47463f2 393 return EFI_UNSUPPORTED;\r
4ec21e8b 394\r
395 default:\r
396 return EFI_INVALID_PARAMETER;\r
a47463f2 397 }\r
398 //\r
399 // call MTRR libary function\r
400 //\r
f877f300 401 Status = MtrrSetMemoryAttribute (\r
a47463f2 402 BaseAddress,\r
403 Length,\r
404 CacheType\r
405 );\r
406\r
a47463f2 407 return (EFI_STATUS) Status;\r
408}\r
409\r
410/**\r
411 Initializes the valid bits mask and valid address mask for MTRRs.\r
412\r
413 This function initializes the valid bits mask and valid address mask for MTRRs.\r
414\r
415**/\r
416VOID\r
417InitializeMtrrMask (\r
418 VOID\r
419 )\r
420{\r
421 UINT32 RegEax;\r
422 UINT8 PhysicalAddressBits;\r
423\r
424 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
425\r
426 if (RegEax >= 0x80000008) {\r
427 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
428\r
429 PhysicalAddressBits = (UINT8) RegEax;\r
430\r
431 mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
432 mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;\r
433 } else {\r
434 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
435 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
436 }\r
437}\r
438\r
439/**\r
430fbbe0 440 Gets GCD Mem Space type from MTRR Type.\r
a47463f2 441\r
430fbbe0 442 This function gets GCD Mem Space type from MTRR Type.\r
a47463f2 443\r
430fbbe0 444 @param MtrrAttributes MTRR memory type\r
a47463f2 445\r
446 @return GCD Mem Space type\r
447\r
448**/\r
449UINT64\r
450GetMemorySpaceAttributeFromMtrrType (\r
2c4b1bdc 451 IN UINT8 MtrrAttributes\r
a47463f2 452 )\r
453{\r
454 switch (MtrrAttributes) {\r
455 case MTRR_CACHE_UNCACHEABLE:\r
456 return EFI_MEMORY_UC;\r
457 case MTRR_CACHE_WRITE_COMBINING:\r
458 return EFI_MEMORY_WC;\r
459 case MTRR_CACHE_WRITE_THROUGH:\r
460 return EFI_MEMORY_WT;\r
461 case MTRR_CACHE_WRITE_PROTECTED:\r
462 return EFI_MEMORY_WP;\r
463 case MTRR_CACHE_WRITE_BACK:\r
464 return EFI_MEMORY_WB;\r
465 default:\r
466 return 0;\r
467 }\r
468}\r
469\r
470/**\r
471 Searches memory descriptors covered by given memory range.\r
472\r
473 This function searches into the Gcd Memory Space for descriptors\r
474 (from StartIndex to EndIndex) that contains the memory range\r
475 specified by BaseAddress and Length.\r
476\r
477 @param MemorySpaceMap Gcd Memory Space Map as array.\r
478 @param NumberOfDescriptors Number of descriptors in map.\r
479 @param BaseAddress BaseAddress for the requested range.\r
480 @param Length Length for the requested range.\r
481 @param StartIndex Start index into the Gcd Memory Space Map.\r
482 @param EndIndex End index into the Gcd Memory Space Map.\r
483\r
484 @retval EFI_SUCCESS Search successfully.\r
485 @retval EFI_NOT_FOUND The requested descriptors does not exist.\r
486\r
487**/\r
488EFI_STATUS\r
489SearchGcdMemorySpaces (\r
490 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
491 IN UINTN NumberOfDescriptors,\r
492 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
493 IN UINT64 Length,\r
494 OUT UINTN *StartIndex,\r
495 OUT UINTN *EndIndex\r
496 )\r
497{\r
498 UINTN Index;\r
499\r
500 *StartIndex = 0;\r
501 *EndIndex = 0;\r
502 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
503 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&\r
504 BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
505 *StartIndex = Index;\r
506 }\r
507 if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&\r
508 BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
509 *EndIndex = Index;\r
510 return EFI_SUCCESS;\r
511 }\r
512 }\r
513 return EFI_NOT_FOUND;\r
514}\r
515\r
516/**\r
517 Sets the attributes for a specified range in Gcd Memory Space Map.\r
518\r
519 This function sets the attributes for a specified range in\r
520 Gcd Memory Space Map.\r
521\r
522 @param MemorySpaceMap Gcd Memory Space Map as array\r
523 @param NumberOfDescriptors Number of descriptors in map\r
524 @param BaseAddress BaseAddress for the range\r
525 @param Length Length for the range\r
526 @param Attributes Attributes to set\r
527\r
528 @retval EFI_SUCCESS Memory attributes set successfully\r
529 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space\r
530\r
531**/\r
532EFI_STATUS\r
533SetGcdMemorySpaceAttributes (\r
534 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
535 IN UINTN NumberOfDescriptors,\r
536 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
537 IN UINT64 Length,\r
538 IN UINT64 Attributes\r
539 )\r
540{\r
541 EFI_STATUS Status;\r
542 UINTN Index;\r
543 UINTN StartIndex;\r
544 UINTN EndIndex;\r
545 EFI_PHYSICAL_ADDRESS RegionStart;\r
546 UINT64 RegionLength;\r
547\r
548 //\r
549 // Get all memory descriptors covered by the memory range\r
550 //\r
551 Status = SearchGcdMemorySpaces (\r
552 MemorySpaceMap,\r
553 NumberOfDescriptors,\r
554 BaseAddress,\r
555 Length,\r
556 &StartIndex,\r
557 &EndIndex\r
558 );\r
559 if (EFI_ERROR (Status)) {\r
560 return Status;\r
561 }\r
562\r
563 //\r
564 // Go through all related descriptors and set attributes accordingly\r
565 //\r
566 for (Index = StartIndex; Index <= EndIndex; Index++) {\r
567 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
568 continue;\r
569 }\r
570 //\r
571 // Calculate the start and end address of the overlapping range\r
572 //\r
573 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {\r
574 RegionStart = BaseAddress;\r
575 } else {\r
576 RegionStart = MemorySpaceMap[Index].BaseAddress;\r
577 }\r
578 if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
579 RegionLength = BaseAddress + Length - RegionStart;\r
580 } else {\r
581 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;\r
582 }\r
583 //\r
584 // Set memory attributes according to MTRR attribute and the original attribute of descriptor\r
585 //\r
586 gDS->SetMemorySpaceAttributes (\r
587 RegionStart,\r
588 RegionLength,\r
589 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)\r
590 );\r
591 }\r
592\r
593 return EFI_SUCCESS;\r
594}\r
595\r
596\r
597/**\r
598 Refreshes the GCD Memory Space attributes according to MTRRs.\r
599\r
600 This function refreshes the GCD Memory Space attributes according to MTRRs.\r
601\r
602**/\r
603VOID\r
604RefreshGcdMemoryAttributes (\r
605 VOID\r
606 )\r
607{\r
608 EFI_STATUS Status;\r
609 UINTN Index;\r
610 UINTN SubIndex;\r
611 UINT64 RegValue;\r
612 EFI_PHYSICAL_ADDRESS BaseAddress;\r
613 UINT64 Length;\r
614 UINT64 Attributes;\r
615 UINT64 CurrentAttributes;\r
2c4b1bdc 616 UINT8 MtrrType;\r
a47463f2 617 UINTN NumberOfDescriptors;\r
618 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
619 UINT64 DefaultAttributes;\r
6640eb36 620 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
a47463f2 621 MTRR_FIXED_SETTINGS MtrrFixedSettings;\r
3b9be416 622 UINT32 FirmwareVariableMtrrCount;\r
2c4b1bdc 623 UINT8 DefaultMemoryType;\r
3b9be416 624\r
947a573a 625 if (!IsMtrrSupported ()) {\r
626 return;\r
627 }\r
628\r
3b9be416 629 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
5bdfa4e5 630 ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
a47463f2 631\r
91ec7824 632 mIsFlushingGCD = TRUE;\r
a47463f2 633 MemorySpaceMap = NULL;\r
634\r
635 //\r
636 // Initialize the valid bits mask and valid address mask for MTRRs\r
637 //\r
638 InitializeMtrrMask ();\r
639\r
640 //\r
641 // Get the memory attribute of variable MTRRs\r
642 //\r
643 MtrrGetMemoryAttributeInVariableMtrr (\r
644 mValidMtrrBitsMask,\r
645 mValidMtrrAddressMask,\r
646 VariableMtrr\r
647 );\r
648\r
649 //\r
650 // Get the memory space map from GCD\r
651 //\r
652 Status = gDS->GetMemorySpaceMap (\r
653 &NumberOfDescriptors,\r
654 &MemorySpaceMap\r
655 );\r
656 ASSERT_EFI_ERROR (Status);\r
657\r
2c4b1bdc 658 DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();\r
91ec7824 659 DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);\r
a47463f2 660\r
661 //\r
662 // Set default attributes to all spaces.\r
663 //\r
664 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
665 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
666 continue;\r
667 }\r
668 gDS->SetMemorySpaceAttributes (\r
669 MemorySpaceMap[Index].BaseAddress,\r
670 MemorySpaceMap[Index].Length,\r
671 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |\r
672 (MemorySpaceMap[Index].Capabilities & DefaultAttributes)\r
673 );\r
674 }\r
675\r
676 //\r
677 // Go for variable MTRRs with WB attribute\r
678 //\r
3b9be416 679 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
a47463f2 680 if (VariableMtrr[Index].Valid &&\r
681 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {\r
682 SetGcdMemorySpaceAttributes (\r
683 MemorySpaceMap,\r
684 NumberOfDescriptors,\r
685 VariableMtrr[Index].BaseAddress,\r
686 VariableMtrr[Index].Length,\r
687 EFI_MEMORY_WB\r
688 );\r
689 }\r
690 }\r
91ec7824 691\r
a47463f2 692 //\r
91ec7824 693 // Go for variable MTRRs with the attribute except for WB and UC attributes\r
a47463f2 694 //\r
3b9be416 695 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
d4605c23 696 if (VariableMtrr[Index].Valid &&\r
91ec7824 697 VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&\r
698 VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {\r
2c4b1bdc 699 Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);\r
a47463f2 700 SetGcdMemorySpaceAttributes (\r
701 MemorySpaceMap,\r
702 NumberOfDescriptors,\r
703 VariableMtrr[Index].BaseAddress,\r
704 VariableMtrr[Index].Length,\r
705 Attributes\r
706 );\r
707 }\r
708 }\r
709\r
91ec7824 710 //\r
711 // Go for variable MTRRs with UC attribute\r
712 //\r
713 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
714 if (VariableMtrr[Index].Valid &&\r
715 VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {\r
716 SetGcdMemorySpaceAttributes (\r
717 MemorySpaceMap,\r
718 NumberOfDescriptors,\r
719 VariableMtrr[Index].BaseAddress,\r
720 VariableMtrr[Index].Length,\r
721 EFI_MEMORY_UC\r
722 );\r
723 }\r
724 }\r
725\r
a47463f2 726 //\r
727 // Go for fixed MTRRs\r
728 //\r
729 Attributes = 0;\r
730 BaseAddress = 0;\r
731 Length = 0;\r
732 MtrrGetFixedMtrr (&MtrrFixedSettings);\r
733 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
734 RegValue = MtrrFixedSettings.Mtrr[Index];\r
735 //\r
736 // Check for continuous fixed MTRR sections\r
737 //\r
738 for (SubIndex = 0; SubIndex < 8; SubIndex++) {\r
2c4b1bdc 739 MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);\r
a47463f2 740 CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);\r
741 if (Length == 0) {\r
742 //\r
743 // A new MTRR attribute begins\r
744 //\r
745 Attributes = CurrentAttributes;\r
746 } else {\r
747 //\r
748 // If fixed MTRR attribute changed, then set memory attribute for previous atrribute\r
749 //\r
750 if (CurrentAttributes != Attributes) {\r
751 SetGcdMemorySpaceAttributes (\r
752 MemorySpaceMap,\r
753 NumberOfDescriptors,\r
754 BaseAddress,\r
755 Length,\r
756 Attributes\r
757 );\r
758 BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;\r
759 Length = 0;\r
760 Attributes = CurrentAttributes;\r
761 }\r
762 }\r
763 Length += mFixedMtrrTable[Index].Length;\r
764 }\r
765 }\r
766 //\r
767 // Handle the last fixed MTRR region\r
768 //\r
769 SetGcdMemorySpaceAttributes (\r
770 MemorySpaceMap,\r
771 NumberOfDescriptors,\r
772 BaseAddress,\r
773 Length,\r
774 Attributes\r
775 );\r
776\r
777 //\r
778 // Free memory space map allocated by GCD service GetMemorySpaceMap ()\r
779 //\r
780 if (MemorySpaceMap != NULL) {\r
781 FreePool (MemorySpaceMap);\r
782 }\r
783\r
784 mIsFlushingGCD = FALSE;\r
785}\r
786\r
a47463f2 787/**\r
788 Initialize Interrupt Descriptor Table for interrupt handling.\r
789\r
790**/\r
a47463f2 791VOID\r
792InitInterruptDescriptorTable (\r
793 VOID\r
794 )\r
795{\r
e41aad15
JF
796 EFI_STATUS Status;\r
797 EFI_VECTOR_HANDOFF_INFO *VectorInfoList;\r
798 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
799\r
800 VectorInfo = NULL;\r
801 Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorInfoList);\r
802 if (Status == EFI_SUCCESS && VectorInfoList != NULL) {\r
803 VectorInfo = VectorInfoList;\r
a47463f2 804 }\r
e41aad15
JF
805 Status = InitializeCpuInterruptHandlers (VectorInfo);\r
806 ASSERT_EFI_ERROR (Status);\r
a47463f2 807}\r
808\r
809\r
32394027 810/**\r
811 Callback function for idle events.\r
d4605c23 812\r
32394027 813 @param Event Event whose notification function is being invoked.\r
814 @param Context The pointer to the notification function's context,\r
815 which is implementation-dependent.\r
816\r
817**/\r
818VOID\r
819EFIAPI\r
820IdleLoopEventCallback (\r
821 IN EFI_EVENT Event,\r
822 IN VOID *Context\r
823 )\r
824{\r
825 CpuSleep ();\r
826}\r
827\r
828\r
a47463f2 829/**\r
830 Initialize the state information for the CPU Architectural Protocol.\r
831\r
832 @param ImageHandle Image handle this driver.\r
833 @param SystemTable Pointer to the System Table.\r
834\r
835 @retval EFI_SUCCESS Thread can be successfully created\r
836 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
837 @retval EFI_DEVICE_ERROR Cannot create the thread\r
838\r
839**/\r
840EFI_STATUS\r
841EFIAPI\r
842InitializeCpu (\r
843 IN EFI_HANDLE ImageHandle,\r
844 IN EFI_SYSTEM_TABLE *SystemTable\r
845 )\r
846{\r
847 EFI_STATUS Status;\r
32394027 848 EFI_EVENT IdleLoopEvent;\r
a47463f2 849\r
661cab5d 850 InitializeFloatingPointUnits ();\r
851\r
a47463f2 852 //\r
853 // Make sure interrupts are disabled\r
854 //\r
855 DisableInterrupts ();\r
856\r
857 //\r
858 // Init GDT for DXE\r
859 //\r
860 InitGlobalDescriptorTable ();\r
861\r
862 //\r
863 // Setup IDT pointer, IDT and interrupt entry points\r
864 //\r
865 InitInterruptDescriptorTable ();\r
866\r
d4605c23
EB
867 //\r
868 // Enable the local APIC for Virtual Wire Mode.\r
869 //\r
870 ProgramVirtualWireMode ();\r
871\r
a47463f2 872 //\r
873 // Install CPU Architectural Protocol\r
874 //\r
875 Status = gBS->InstallMultipleProtocolInterfaces (\r
876 &mCpuHandle,\r
877 &gEfiCpuArchProtocolGuid, &gCpu,\r
878 NULL\r
879 );\r
880 ASSERT_EFI_ERROR (Status);\r
881\r
882 //\r
883 // Refresh GCD memory space map according to MTRR value.\r
884 //\r
885 RefreshGcdMemoryAttributes ();\r
886\r
32394027 887 //\r
888 // Setup a callback for idle events\r
889 //\r
890 Status = gBS->CreateEventEx (\r
891 EVT_NOTIFY_SIGNAL,\r
892 TPL_NOTIFY,\r
893 IdleLoopEventCallback,\r
894 NULL,\r
895 &gIdleLoopEventGuid,\r
896 &IdleLoopEvent\r
897 );\r
898 ASSERT_EFI_ERROR (Status);\r
899\r
a47463f2 900 return Status;\r
901}\r
902\r