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
CpuFlushCpuDataCache(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS Start,IN UINT64 Length,IN EFI_CPU_FLUSH_TYPE FlushType)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
CpuEnableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)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
CpuDisableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)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
CpuGetInterruptState(IN EFI_CPU_ARCH_PROTOCOL * This,OUT BOOLEAN * State)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
CpuInit(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_CPU_INIT_TYPE InitType)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
CpuRegisterInterruptHandler(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_EXCEPTION_TYPE InterruptType,IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler)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
CpuGetTimerValue(IN EFI_CPU_ARCH_PROTOCOL * This,IN UINT32 TimerIndex,OUT UINT64 * TimerValue,OUT UINT64 * TimerPeriod OPTIONAL)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
SetMtrrsFromBuffer(IN VOID * Buffer)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
CpuSetMemoryAttributes(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)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 synchronzing 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 libary 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
InitializeMtrrMask(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
GetMemorySpaceAttributeFromMtrrType(IN UINT8 MtrrAttributes)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
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)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
SetGcdMemorySpaceAttributes(IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR * MemorySpaceMap,IN UINTN NumberOfDescriptors,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)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
RefreshMemoryAttributesFromMtrr(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 atrribute
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
IsPagingAndPageAddressExtensionsEnabled(VOID)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
RefreshGcdMemoryAttributes(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
InitInterruptDescriptorTable(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
IdleLoopEventCallback(IN EFI_EVENT Event,IN VOID * Context)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
IntersectMemoryDescriptor(IN UINT64 Base,IN UINT64 Length,IN UINT64 Capabilities,IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR * Descriptor)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_SUCCES The MMIO space was added successfully.
1049 **/
1050 EFI_STATUS
AddMemoryMappedIoSpace(IN UINT64 Base,IN UINT64 Length,IN UINT64 Capabilities)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
AddLocalApicMemorySpace(IN EFI_HANDLE ImageHandle)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
InitializeCpu(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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 
1219