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