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