1 /** @file
2   CPU DXE Module.
3 
4   Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "CpuDxe.h"
16 #include "CpuMp.h"
17 
18 //
19 // Global Variables
20 //
21 BOOLEAN                   InterruptState = FALSE;
22 EFI_HANDLE                mCpuHandle = NULL;
23 BOOLEAN                   mIsFlushingGCD;
24 UINT64                    mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
25 UINT64                    mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;
26 
27 FIXED_MTRR    mFixedMtrrTable[] = {
28   {
29     MTRR_LIB_IA32_MTRR_FIX64K_00000,
30     0,
31     0x10000
32   },
33   {
34     MTRR_LIB_IA32_MTRR_FIX16K_80000,
35     0x80000,
36     0x4000
37   },
38   {
39     MTRR_LIB_IA32_MTRR_FIX16K_A0000,
40     0xA0000,
41     0x4000
42   },
43   {
44     MTRR_LIB_IA32_MTRR_FIX4K_C0000,
45     0xC0000,
46     0x1000
47   },
48   {
49     MTRR_LIB_IA32_MTRR_FIX4K_C8000,
50     0xC8000,
51     0x1000
52   },
53   {
54     MTRR_LIB_IA32_MTRR_FIX4K_D0000,
55     0xD0000,
56     0x1000
57   },
58   {
59     MTRR_LIB_IA32_MTRR_FIX4K_D8000,
60     0xD8000,
61     0x1000
62   },
63   {
64     MTRR_LIB_IA32_MTRR_FIX4K_E0000,
65     0xE0000,
66     0x1000
67   },
68   {
69     MTRR_LIB_IA32_MTRR_FIX4K_E8000,
70     0xE8000,
71     0x1000
72   },
73   {
74     MTRR_LIB_IA32_MTRR_FIX4K_F0000,
75     0xF0000,
76     0x1000
77   },
78   {
79     MTRR_LIB_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   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       //
308       // BugBug: Hard coded. Don't know how to do this generically
309       //
310       *TimerPeriod = 1000000000;
311   }
312 
313   return EFI_SUCCESS;
314 }
315 
316 
317 /**
318   Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
319 
320   This function modifies the attributes for the memory region specified by BaseAddress and
321   Length from their current attributes to the attributes specified by Attributes.
322 
323   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
324   @param  BaseAddress      The physical address that is the start address of a memory region.
325   @param  Length           The size in bytes of the memory region.
326   @param  Attributes       The bit mask of attributes to set for the memory region.
327 
328   @retval EFI_SUCCESS           The attributes were set for the memory region.
329   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
330                                 BaseAddress and Length cannot be modified.
331   @retval EFI_INVALID_PARAMETER Length is zero.
332                                 Attributes specified an illegal combination of attributes that
333                                 cannot be set together.
334   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
335                                 the memory resource range.
336   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
337                                 resource range specified by BaseAddress and Length.
338                                 The bit mask of attributes is not support for the memory resource
339                                 range specified by BaseAddress and Length.
340 
341 **/
342 EFI_STATUS
343 EFIAPI
CpuSetMemoryAttributes(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)344 CpuSetMemoryAttributes (
345   IN EFI_CPU_ARCH_PROTOCOL     *This,
346   IN EFI_PHYSICAL_ADDRESS      BaseAddress,
347   IN UINT64                    Length,
348   IN UINT64                    Attributes
349   )
350 {
351   RETURN_STATUS             Status;
352   MTRR_MEMORY_CACHE_TYPE    CacheType;
353   EFI_STATUS                MpStatus;
354   EFI_MP_SERVICES_PROTOCOL  *MpService;
355   MTRR_SETTINGS             MtrrSettings;
356 
357   if (!IsMtrrSupported ()) {
358     return EFI_UNSUPPORTED;
359   }
360 
361   //
362   // If this function is called because GCD SetMemorySpaceAttributes () is called
363   // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory
364   // map with MTRR values. So there is no need to modify MTRRs, just return immediately
365   // to avoid unnecessary computing.
366   //
367   if (mIsFlushingGCD) {
368     DEBUG((EFI_D_INFO, "  Flushing GCD\n"));
369     return EFI_SUCCESS;
370   }
371 
372   switch (Attributes) {
373   case EFI_MEMORY_UC:
374     CacheType = CacheUncacheable;
375     break;
376 
377   case EFI_MEMORY_WC:
378     CacheType = CacheWriteCombining;
379     break;
380 
381   case EFI_MEMORY_WT:
382     CacheType = CacheWriteThrough;
383     break;
384 
385   case EFI_MEMORY_WP:
386     CacheType = CacheWriteProtected;
387     break;
388 
389   case EFI_MEMORY_WB:
390     CacheType = CacheWriteBack;
391     break;
392 
393   case EFI_MEMORY_UCE:
394   case EFI_MEMORY_RP:
395   case EFI_MEMORY_XP:
396   case EFI_MEMORY_RUNTIME:
397     return EFI_UNSUPPORTED;
398 
399   default:
400     return EFI_INVALID_PARAMETER;
401   }
402   //
403   // call MTRR libary function
404   //
405   Status = MtrrSetMemoryAttribute (
406              BaseAddress,
407              Length,
408              CacheType
409              );
410 
411   if (!RETURN_ERROR (Status)) {
412     MpStatus = gBS->LocateProtocol (
413                       &gEfiMpServiceProtocolGuid,
414                       NULL,
415                       (VOID **)&MpService
416                       );
417     //
418     // Synchronize the update with all APs
419     //
420     if (!EFI_ERROR (MpStatus)) {
421       MtrrGetAllMtrrs (&MtrrSettings);
422       MpStatus = MpService->StartupAllAPs (
423                               MpService,          // This
424                               SetMtrrsFromBuffer, // Procedure
425                               TRUE,               // SingleThread
426                               NULL,               // WaitEvent
427                               0,                  // TimeoutInMicrosecsond
428                               &MtrrSettings,      // ProcedureArgument
429                               NULL                // FailedCpuList
430                               );
431       ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
432     }
433   }
434   return (EFI_STATUS) Status;
435 }
436 
437 /**
438   Initializes the valid bits mask and valid address mask for MTRRs.
439 
440   This function initializes the valid bits mask and valid address mask for MTRRs.
441 
442 **/
443 VOID
InitializeMtrrMask(VOID)444 InitializeMtrrMask (
445   VOID
446   )
447 {
448   UINT32                              RegEax;
449   UINT8                               PhysicalAddressBits;
450 
451   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
452 
453   if (RegEax >= 0x80000008) {
454     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
455 
456     PhysicalAddressBits = (UINT8) RegEax;
457 
458     mValidMtrrBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
459     mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
460   } else {
461     mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;
462     mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
463   }
464 }
465 
466 /**
467   Gets GCD Mem Space type from MTRR Type.
468 
469   This function gets GCD Mem Space type from MTRR Type.
470 
471   @param  MtrrAttributes  MTRR memory type
472 
473   @return GCD Mem Space type
474 
475 **/
476 UINT64
GetMemorySpaceAttributeFromMtrrType(IN UINT8 MtrrAttributes)477 GetMemorySpaceAttributeFromMtrrType (
478   IN UINT8                MtrrAttributes
479   )
480 {
481   switch (MtrrAttributes) {
482   case MTRR_CACHE_UNCACHEABLE:
483     return EFI_MEMORY_UC;
484   case MTRR_CACHE_WRITE_COMBINING:
485     return EFI_MEMORY_WC;
486   case MTRR_CACHE_WRITE_THROUGH:
487     return EFI_MEMORY_WT;
488   case MTRR_CACHE_WRITE_PROTECTED:
489     return EFI_MEMORY_WP;
490   case MTRR_CACHE_WRITE_BACK:
491     return EFI_MEMORY_WB;
492   default:
493     return 0;
494   }
495 }
496 
497 /**
498   Searches memory descriptors covered by given memory range.
499 
500   This function searches into the Gcd Memory Space for descriptors
501   (from StartIndex to EndIndex) that contains the memory range
502   specified by BaseAddress and Length.
503 
504   @param  MemorySpaceMap       Gcd Memory Space Map as array.
505   @param  NumberOfDescriptors  Number of descriptors in map.
506   @param  BaseAddress          BaseAddress for the requested range.
507   @param  Length               Length for the requested range.
508   @param  StartIndex           Start index into the Gcd Memory Space Map.
509   @param  EndIndex             End index into the Gcd Memory Space Map.
510 
511   @retval EFI_SUCCESS          Search successfully.
512   @retval EFI_NOT_FOUND        The requested descriptors does not exist.
513 
514 **/
515 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)516 SearchGcdMemorySpaces (
517   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
518   IN UINTN                               NumberOfDescriptors,
519   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
520   IN UINT64                              Length,
521   OUT UINTN                              *StartIndex,
522   OUT UINTN                              *EndIndex
523   )
524 {
525   UINTN           Index;
526 
527   *StartIndex = 0;
528   *EndIndex   = 0;
529   for (Index = 0; Index < NumberOfDescriptors; Index++) {
530     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
531         BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
532       *StartIndex = Index;
533     }
534     if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
535         BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
536       *EndIndex = Index;
537       return EFI_SUCCESS;
538     }
539   }
540   return EFI_NOT_FOUND;
541 }
542 
543 /**
544   Sets the attributes for a specified range in Gcd Memory Space Map.
545 
546   This function sets the attributes for a specified range in
547   Gcd Memory Space Map.
548 
549   @param  MemorySpaceMap       Gcd Memory Space Map as array
550   @param  NumberOfDescriptors  Number of descriptors in map
551   @param  BaseAddress          BaseAddress for the range
552   @param  Length               Length for the range
553   @param  Attributes           Attributes to set
554 
555   @retval EFI_SUCCESS          Memory attributes set successfully
556   @retval EFI_NOT_FOUND        The specified range does not exist in Gcd Memory Space
557 
558 **/
559 EFI_STATUS
SetGcdMemorySpaceAttributes(IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR * MemorySpaceMap,IN UINTN NumberOfDescriptors,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)560 SetGcdMemorySpaceAttributes (
561   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
562   IN UINTN                               NumberOfDescriptors,
563   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
564   IN UINT64                              Length,
565   IN UINT64                              Attributes
566   )
567 {
568   EFI_STATUS            Status;
569   UINTN                 Index;
570   UINTN                 StartIndex;
571   UINTN                 EndIndex;
572   EFI_PHYSICAL_ADDRESS  RegionStart;
573   UINT64                RegionLength;
574 
575   //
576   // Get all memory descriptors covered by the memory range
577   //
578   Status = SearchGcdMemorySpaces (
579              MemorySpaceMap,
580              NumberOfDescriptors,
581              BaseAddress,
582              Length,
583              &StartIndex,
584              &EndIndex
585              );
586   if (EFI_ERROR (Status)) {
587     return Status;
588   }
589 
590   //
591   // Go through all related descriptors and set attributes accordingly
592   //
593   for (Index = StartIndex; Index <= EndIndex; Index++) {
594     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
595       continue;
596     }
597     //
598     // Calculate the start and end address of the overlapping range
599     //
600     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
601       RegionStart = BaseAddress;
602     } else {
603       RegionStart = MemorySpaceMap[Index].BaseAddress;
604     }
605     if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
606       RegionLength = BaseAddress + Length - RegionStart;
607     } else {
608       RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
609     }
610     //
611     // Set memory attributes according to MTRR attribute and the original attribute of descriptor
612     //
613     gDS->SetMemorySpaceAttributes (
614            RegionStart,
615            RegionLength,
616            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
617            );
618   }
619 
620   return EFI_SUCCESS;
621 }
622 
623 
624 /**
625   Refreshes the GCD Memory Space attributes according to MTRRs.
626 
627   This function refreshes the GCD Memory Space attributes according to MTRRs.
628 
629 **/
630 VOID
RefreshGcdMemoryAttributes(VOID)631 RefreshGcdMemoryAttributes (
632   VOID
633   )
634 {
635   EFI_STATUS                          Status;
636   UINTN                               Index;
637   UINTN                               SubIndex;
638   UINT64                              RegValue;
639   EFI_PHYSICAL_ADDRESS                BaseAddress;
640   UINT64                              Length;
641   UINT64                              Attributes;
642   UINT64                              CurrentAttributes;
643   UINT8                               MtrrType;
644   UINTN                               NumberOfDescriptors;
645   EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap;
646   UINT64                              DefaultAttributes;
647   VARIABLE_MTRR                       VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
648   MTRR_FIXED_SETTINGS                 MtrrFixedSettings;
649   UINT32                              FirmwareVariableMtrrCount;
650   UINT8                               DefaultMemoryType;
651 
652   if (!IsMtrrSupported ()) {
653     return;
654   }
655 
656   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
657   ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
658 
659   mIsFlushingGCD = TRUE;
660   MemorySpaceMap = NULL;
661 
662   //
663   // Initialize the valid bits mask and valid address mask for MTRRs
664   //
665   InitializeMtrrMask ();
666 
667   //
668   // Get the memory attribute of variable MTRRs
669   //
670   MtrrGetMemoryAttributeInVariableMtrr (
671     mValidMtrrBitsMask,
672     mValidMtrrAddressMask,
673     VariableMtrr
674     );
675 
676   //
677   // Get the memory space map from GCD
678   //
679   Status = gDS->GetMemorySpaceMap (
680                   &NumberOfDescriptors,
681                   &MemorySpaceMap
682                   );
683   ASSERT_EFI_ERROR (Status);
684 
685   DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();
686   DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
687 
688   //
689   // Set default attributes to all spaces.
690   //
691   for (Index = 0; Index < NumberOfDescriptors; Index++) {
692     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
693       continue;
694     }
695     gDS->SetMemorySpaceAttributes (
696            MemorySpaceMap[Index].BaseAddress,
697            MemorySpaceMap[Index].Length,
698            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
699            (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
700            );
701   }
702 
703   //
704   // Go for variable MTRRs with WB attribute
705   //
706   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
707     if (VariableMtrr[Index].Valid &&
708         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {
709       SetGcdMemorySpaceAttributes (
710         MemorySpaceMap,
711         NumberOfDescriptors,
712         VariableMtrr[Index].BaseAddress,
713         VariableMtrr[Index].Length,
714         EFI_MEMORY_WB
715         );
716     }
717   }
718 
719   //
720   // Go for variable MTRRs with the attribute except for WB and UC attributes
721   //
722   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
723     if (VariableMtrr[Index].Valid &&
724         VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&
725         VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {
726       Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);
727       SetGcdMemorySpaceAttributes (
728         MemorySpaceMap,
729         NumberOfDescriptors,
730         VariableMtrr[Index].BaseAddress,
731         VariableMtrr[Index].Length,
732         Attributes
733         );
734     }
735   }
736 
737   //
738   // Go for variable MTRRs with UC attribute
739   //
740   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
741     if (VariableMtrr[Index].Valid &&
742         VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {
743       SetGcdMemorySpaceAttributes (
744         MemorySpaceMap,
745         NumberOfDescriptors,
746         VariableMtrr[Index].BaseAddress,
747         VariableMtrr[Index].Length,
748         EFI_MEMORY_UC
749         );
750     }
751   }
752 
753   //
754   // Go for fixed MTRRs
755   //
756   Attributes  = 0;
757   BaseAddress = 0;
758   Length      = 0;
759   MtrrGetFixedMtrr (&MtrrFixedSettings);
760   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
761     RegValue = MtrrFixedSettings.Mtrr[Index];
762     //
763     // Check for continuous fixed MTRR sections
764     //
765     for (SubIndex = 0; SubIndex < 8; SubIndex++) {
766       MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);
767       CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
768       if (Length == 0) {
769         //
770         // A new MTRR attribute begins
771         //
772         Attributes = CurrentAttributes;
773       } else {
774         //
775         // If fixed MTRR attribute changed, then set memory attribute for previous atrribute
776         //
777         if (CurrentAttributes != Attributes) {
778           SetGcdMemorySpaceAttributes (
779             MemorySpaceMap,
780             NumberOfDescriptors,
781             BaseAddress,
782             Length,
783             Attributes
784             );
785           BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
786           Length = 0;
787           Attributes = CurrentAttributes;
788         }
789       }
790       Length += mFixedMtrrTable[Index].Length;
791     }
792   }
793   //
794   // Handle the last fixed MTRR region
795   //
796   SetGcdMemorySpaceAttributes (
797     MemorySpaceMap,
798     NumberOfDescriptors,
799     BaseAddress,
800     Length,
801     Attributes
802     );
803 
804   //
805   // Free memory space map allocated by GCD service GetMemorySpaceMap ()
806   //
807   if (MemorySpaceMap != NULL) {
808     FreePool (MemorySpaceMap);
809   }
810 
811   mIsFlushingGCD = FALSE;
812 }
813 
814 /**
815   Initialize Interrupt Descriptor Table for interrupt handling.
816 
817 **/
818 VOID
InitInterruptDescriptorTable(VOID)819 InitInterruptDescriptorTable (
820   VOID
821   )
822 {
823   EFI_STATUS                     Status;
824   EFI_VECTOR_HANDOFF_INFO        *VectorInfoList;
825   EFI_VECTOR_HANDOFF_INFO        *VectorInfo;
826 
827   VectorInfo = NULL;
828   Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorInfoList);
829   if (Status == EFI_SUCCESS && VectorInfoList != NULL) {
830     VectorInfo = VectorInfoList;
831   }
832   Status = InitializeCpuInterruptHandlers (VectorInfo);
833   ASSERT_EFI_ERROR (Status);
834 }
835 
836 
837 /**
838   Callback function for idle events.
839 
840   @param  Event                 Event whose notification function is being invoked.
841   @param  Context               The pointer to the notification function's context,
842                                 which is implementation-dependent.
843 
844 **/
845 VOID
846 EFIAPI
IdleLoopEventCallback(IN EFI_EVENT Event,IN VOID * Context)847 IdleLoopEventCallback (
848   IN EFI_EVENT                Event,
849   IN VOID                     *Context
850   )
851 {
852   CpuSleep ();
853 }
854 
855 
856 /**
857   Initialize the state information for the CPU Architectural Protocol.
858 
859   @param ImageHandle     Image handle this driver.
860   @param SystemTable     Pointer to the System Table.
861 
862   @retval EFI_SUCCESS           Thread can be successfully created
863   @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
864   @retval EFI_DEVICE_ERROR      Cannot create the thread
865 
866 **/
867 EFI_STATUS
868 EFIAPI
InitializeCpu(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)869 InitializeCpu (
870   IN EFI_HANDLE                            ImageHandle,
871   IN EFI_SYSTEM_TABLE                      *SystemTable
872   )
873 {
874   EFI_STATUS  Status;
875   EFI_EVENT   IdleLoopEvent;
876 
877   InitializeFloatingPointUnits ();
878 
879   //
880   // Make sure interrupts are disabled
881   //
882   DisableInterrupts ();
883 
884   //
885   // Init GDT for DXE
886   //
887   InitGlobalDescriptorTable ();
888 
889   //
890   // Setup IDT pointer, IDT and interrupt entry points
891   //
892   InitInterruptDescriptorTable ();
893 
894   //
895   // Enable the local APIC for Virtual Wire Mode.
896   //
897   ProgramVirtualWireMode ();
898 
899   //
900   // Install CPU Architectural Protocol
901   //
902   Status = gBS->InstallMultipleProtocolInterfaces (
903                   &mCpuHandle,
904                   &gEfiCpuArchProtocolGuid, &gCpu,
905                   NULL
906                   );
907   ASSERT_EFI_ERROR (Status);
908 
909   //
910   // Refresh GCD memory space map according to MTRR value.
911   //
912   RefreshGcdMemoryAttributes ();
913 
914   //
915   // Setup a callback for idle events
916   //
917   Status = gBS->CreateEventEx (
918                   EVT_NOTIFY_SIGNAL,
919                   TPL_NOTIFY,
920                   IdleLoopEventCallback,
921                   NULL,
922                   &gIdleLoopEventGuid,
923                   &IdleLoopEvent
924                   );
925   ASSERT_EFI_ERROR (Status);
926 
927   InitializeMpSupport ();
928 
929   return Status;
930 }
931 
932