]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/CpuDxe.c
UefiCpuPkg/CpuDxe: Add Local APIC memory mapped space in GCD
[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
410590f1
JF
891/**\r
892 Ensure the compatibility of a memory space descriptor with the MMIO aperture.\r
893\r
894 The memory space descriptor can come from the GCD memory space map, or it can\r
895 represent a gap between two neighboring memory space descriptors. In the\r
896 latter case, the GcdMemoryType field is expected to be\r
897 EfiGcdMemoryTypeNonExistent.\r
898\r
899 If the memory space descriptor already has type\r
900 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the\r
901 required capabilities, then no action is taken -- it is by definition\r
902 compatible with the aperture.\r
903\r
904 Otherwise, the intersection of the memory space descriptor is calculated with\r
905 the aperture. If the intersection is the empty set (no overlap), no action is\r
906 taken; the memory space descriptor is compatible with the aperture.\r
907\r
908 Otherwise, the type of the descriptor is investigated again. If the type is\r
909 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with\r
910 such a type), then an attempt is made to add the intersection as MMIO space\r
911 to the GCD memory space map, with the specified capabilities. This ensures\r
912 continuity for the aperture, and the descriptor is deemed compatible with the\r
913 aperture.\r
914\r
915 Otherwise, the memory space descriptor is incompatible with the MMIO\r
916 aperture.\r
917\r
918 @param[in] Base Base address of the aperture.\r
919 @param[in] Length Length of the aperture.\r
920 @param[in] Capabilities Capabilities required by the aperture.\r
921 @param[in] Descriptor The descriptor to ensure compatibility with the\r
922 aperture for.\r
923\r
924 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory\r
925 space map may have been updated, for\r
926 continuity within the aperture.\r
927 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.\r
928 @return Error codes from gDS->AddMemorySpace().\r
929**/\r
930EFI_STATUS\r
931IntersectMemoryDescriptor (\r
932 IN UINT64 Base,\r
933 IN UINT64 Length,\r
934 IN UINT64 Capabilities,\r
935 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor\r
936 )\r
937{\r
938 UINT64 IntersectionBase;\r
939 UINT64 IntersectionEnd;\r
940 EFI_STATUS Status;\r
941\r
942 if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo &&\r
943 (Descriptor->Capabilities & Capabilities) == Capabilities) {\r
944 return EFI_SUCCESS;\r
945 }\r
946\r
947 IntersectionBase = MAX (Base, Descriptor->BaseAddress);\r
948 IntersectionEnd = MIN (Base + Length,\r
949 Descriptor->BaseAddress + Descriptor->Length);\r
950 if (IntersectionBase >= IntersectionEnd) {\r
951 //\r
952 // The descriptor and the aperture don't overlap.\r
953 //\r
954 return EFI_SUCCESS;\r
955 }\r
956\r
957 if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
958 Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,\r
959 IntersectionBase, IntersectionEnd - IntersectionBase,\r
960 Capabilities);\r
961\r
962 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,\r
963 "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,\r
964 IntersectionBase, IntersectionEnd, Status));\r
965 return Status;\r
966 }\r
967\r
968 DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "\r
969 "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName, __FUNCTION__,\r
970 Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,\r
971 (UINT32)Descriptor->GcdMemoryType, Descriptor->Capabilities,\r
972 Base, Base + Length, Capabilities));\r
973 return EFI_INVALID_PARAMETER;\r
974}\r
975\r
976/**\r
977 Add MMIO space to GCD.\r
978 The routine checks the GCD database and only adds those which are\r
979 not added in the specified range to GCD.\r
980\r
981 @param Base Base address of the MMIO space.\r
982 @param Length Length of the MMIO space.\r
983 @param Capabilities Capabilities of the MMIO space.\r
984\r
985 @retval EFI_SUCCES The MMIO space was added successfully.\r
986**/\r
987EFI_STATUS\r
988AddMemoryMappedIoSpace (\r
989 IN UINT64 Base,\r
990 IN UINT64 Length,\r
991 IN UINT64 Capabilities\r
992 )\r
993{\r
994 EFI_STATUS Status;\r
995 UINTN Index;\r
996 UINTN NumberOfDescriptors;\r
997 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
998\r
999 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
1000 if (EFI_ERROR (Status)) {\r
1001 DEBUG ((EFI_D_ERROR, "%a: %a: GetMemorySpaceMap(): %r\n",\r
1002 gEfiCallerBaseName, __FUNCTION__, Status));\r
1003 return Status;\r
1004 }\r
1005\r
1006 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
1007 Status = IntersectMemoryDescriptor (Base, Length, Capabilities,\r
1008 &MemorySpaceMap[Index]);\r
1009 if (EFI_ERROR (Status)) {\r
1010 goto FreeMemorySpaceMap;\r
1011 }\r
1012 }\r
1013\r
1014 DEBUG_CODE (\r
1015 //\r
1016 // Make sure there are adjacent descriptors covering [Base, Base + Length).\r
1017 // It is possible that they have not been merged; merging can be prevented\r
1018 // by allocation and different capabilities.\r
1019 //\r
1020 UINT64 CheckBase;\r
1021 EFI_STATUS CheckStatus;\r
1022 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1023\r
1024 for (CheckBase = Base;\r
1025 CheckBase < Base + Length;\r
1026 CheckBase = Descriptor.BaseAddress + Descriptor.Length) {\r
1027 CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);\r
1028 ASSERT_EFI_ERROR (CheckStatus);\r
1029 ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);\r
1030 ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);\r
1031 }\r
1032 );\r
1033\r
1034FreeMemorySpaceMap:\r
1035 FreePool (MemorySpaceMap);\r
1036\r
1037 return Status;\r
1038}\r
32394027 1039\r
14f92ded
JF
1040/**\r
1041 Add and allocate CPU local APIC memory mapped space. \r
1042\r
1043 @param[in]ImageHandle Image handle this driver.\r
1044\r
1045**/\r
1046VOID\r
1047AddLocalApicMemorySpace (\r
1048 IN EFI_HANDLE ImageHandle\r
1049 )\r
1050{\r
1051 EFI_STATUS Status;\r
1052 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1053\r
1054 BaseAddress = (EFI_PHYSICAL_ADDRESS) GetLocalApicBaseAddress();\r
1055 Status = AddMemoryMappedIoSpace (BaseAddress, SIZE_4KB, EFI_MEMORY_UC);\r
1056 ASSERT_EFI_ERROR (Status);\r
1057\r
1058 Status = gDS->AllocateMemorySpace (\r
1059 EfiGcdAllocateAddress,\r
1060 EfiGcdMemoryTypeMemoryMappedIo,\r
1061 0,\r
1062 SIZE_4KB,\r
1063 &BaseAddress,\r
1064 ImageHandle,\r
1065 NULL\r
1066 );\r
1067 ASSERT_EFI_ERROR (Status);\r
1068}\r
1069\r
a47463f2 1070/**\r
1071 Initialize the state information for the CPU Architectural Protocol.\r
1072\r
1073 @param ImageHandle Image handle this driver.\r
1074 @param SystemTable Pointer to the System Table.\r
1075\r
1076 @retval EFI_SUCCESS Thread can be successfully created\r
1077 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
1078 @retval EFI_DEVICE_ERROR Cannot create the thread\r
1079\r
1080**/\r
1081EFI_STATUS\r
1082EFIAPI\r
1083InitializeCpu (\r
1084 IN EFI_HANDLE ImageHandle,\r
1085 IN EFI_SYSTEM_TABLE *SystemTable\r
1086 )\r
1087{\r
1088 EFI_STATUS Status;\r
32394027 1089 EFI_EVENT IdleLoopEvent;\r
22292ed3
JY
1090 \r
1091 InitializePageTableLib();\r
a47463f2 1092\r
661cab5d 1093 InitializeFloatingPointUnits ();\r
1094\r
a47463f2 1095 //\r
1096 // Make sure interrupts are disabled\r
1097 //\r
1098 DisableInterrupts ();\r
1099\r
1100 //\r
1101 // Init GDT for DXE\r
1102 //\r
1103 InitGlobalDescriptorTable ();\r
1104\r
1105 //\r
1106 // Setup IDT pointer, IDT and interrupt entry points\r
1107 //\r
1108 InitInterruptDescriptorTable ();\r
1109\r
d4605c23
EB
1110 //\r
1111 // Enable the local APIC for Virtual Wire Mode.\r
1112 //\r
1113 ProgramVirtualWireMode ();\r
1114\r
a47463f2 1115 //\r
1116 // Install CPU Architectural Protocol\r
1117 //\r
1118 Status = gBS->InstallMultipleProtocolInterfaces (\r
1119 &mCpuHandle,\r
1120 &gEfiCpuArchProtocolGuid, &gCpu,\r
1121 NULL\r
1122 );\r
1123 ASSERT_EFI_ERROR (Status);\r
1124\r
1125 //\r
1126 // Refresh GCD memory space map according to MTRR value.\r
1127 //\r
1128 RefreshGcdMemoryAttributes ();\r
1129\r
14f92ded
JF
1130 //\r
1131 // Add and allocate local APIC memory mapped space\r
1132 //\r
1133 AddLocalApicMemorySpace (ImageHandle);\r
1134\r
32394027 1135 //\r
1136 // Setup a callback for idle events\r
1137 //\r
1138 Status = gBS->CreateEventEx (\r
1139 EVT_NOTIFY_SIGNAL,\r
1140 TPL_NOTIFY,\r
1141 IdleLoopEventCallback,\r
1142 NULL,\r
1143 &gIdleLoopEventGuid,\r
1144 &IdleLoopEvent\r
1145 );\r
1146 ASSERT_EFI_ERROR (Status);\r
1147\r
6022e28c
JJ
1148 InitializeMpSupport ();\r
1149\r
a47463f2 1150 return Status;\r
1151}\r
1152\r