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