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