1 /** @file
2 MTRR setting library
3 
4 Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Base.h>
10 
11 #include <Library/MtrrLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/CpuLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/QNCAccessLib.h>
17 
18 #define QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING         0x590
19 
20 #define CACHE_MTRR_ENABLED                            0x800
21 #define CACHE_FIXED_MTRR_ENABLED                      0x400
22 #define IA32_MTRR_CAP_VCNT_MASK                       0xFF
23 
24 //
25 // Context to save and restore when MTRRs are programmed
26 //
27 typedef struct {
28   UINTN    Cr4;
29   BOOLEAN  InterruptState;
30 } MTRR_CONTEXT;
31 
32 //
33 // This table defines the offset, base and length of the fixed MTRRs
34 //
35 CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {
36   { QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000, 0,       SIZE_64KB },
37   { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000, 0x80000, SIZE_16KB },
38   { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB },
39   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000,  0xC0000, SIZE_4KB  },
40   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000,  0xC8000, SIZE_4KB  },
41   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000,  0xD0000, SIZE_4KB  },
42   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000,  0xD8000, SIZE_4KB  },
43   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000,  0xE0000, SIZE_4KB  },
44   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000,  0xE8000, SIZE_4KB  },
45   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000,  0xF0000, SIZE_4KB  },
46   { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000,  0xF8000, SIZE_4KB  }
47 };
48 
49 //
50 // Lookup table used to print MTRRs
51 //
52 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
53   "UC",  // CacheUncacheable
54   "WC",  // CacheWriteCombining
55   "R*",  // Invalid
56   "R*",  // Invalid
57   "WT",  // CacheWriteThrough
58   "WP",  // CacheWriteProtected
59   "WB",  // CacheWriteBack
60   "R*"   // Invalid
61 };
62 
63 UINT64
MtrrRegisterRead(IN UINT32 MtrrRegister)64 MtrrRegisterRead (
65   IN  UINT32  MtrrRegister
66   )
67 {
68   UINT64  Result;
69 
70   Result = (UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister);
71   if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {
72     Result = Result | LShiftU64 ((UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1), 32);
73   }
74   return Result;
75 }
76 
77 UINT64
MtrrRegisterWrite(IN UINT32 MtrrRegister,IN UINT64 Value)78 MtrrRegisterWrite (
79   IN  UINT32  MtrrRegister,
80   IN  UINT64  Value
81   )
82 {
83   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister, (UINT32)Value);
84   if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {
85     QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1, (UINT32)RShiftU64 (Value, 32));
86   }
87   return Value;
88 }
89 
90 UINT64
MtrrRegisterBitFieldWrite(IN UINT32 MtrrRegister,IN UINTN StartBit,IN UINTN EndBit,IN UINT64 Value)91 MtrrRegisterBitFieldWrite (
92   IN  UINT32  MtrrRegister,
93   IN  UINTN   StartBit,
94   IN  UINTN   EndBit,
95   IN  UINT64  Value
96   )
97 {
98   return MtrrRegisterWrite (
99            MtrrRegister,
100            BitFieldWrite64 (
101              MtrrRegisterRead (MtrrRegister),
102              StartBit,
103              EndBit,
104              Value
105              )
106            );
107 }
108 
109 /**
110   Worker function returns the variable MTRR count for the CPU.
111 
112   @return Variable MTRR count
113 
114 **/
115 UINT32
GetVariableMtrrCountWorker(VOID)116 GetVariableMtrrCountWorker (
117   VOID
118   )
119 {
120   UINT32  VariableMtrrCount;
121 
122   VariableMtrrCount = (UINT32)(MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP) & IA32_MTRR_CAP_VCNT_MASK);
123   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
124   return VariableMtrrCount;
125 }
126 
127 /**
128   Returns the variable MTRR count for the CPU.
129 
130   @return Variable MTRR count
131 
132 **/
133 UINT32
134 EFIAPI
GetVariableMtrrCount(VOID)135 GetVariableMtrrCount (
136   VOID
137   )
138 {
139   if (!IsMtrrSupported ()) {
140     return 0;
141   }
142   return GetVariableMtrrCountWorker ();
143 }
144 
145 /**
146   Worker function returns the firmware usable variable MTRR count for the CPU.
147 
148   @return Firmware usable variable MTRR count
149 
150 **/
151 UINT32
GetFirmwareVariableMtrrCountWorker(VOID)152 GetFirmwareVariableMtrrCountWorker (
153   VOID
154   )
155 {
156   UINT32  VariableMtrrCount;
157   UINT32  ReservedMtrrNumber;
158 
159   VariableMtrrCount = GetVariableMtrrCountWorker ();
160   ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
161   if (VariableMtrrCount < ReservedMtrrNumber) {
162     return 0;
163   }
164 
165   return VariableMtrrCount - ReservedMtrrNumber;
166 }
167 
168 /**
169   Returns the firmware usable variable MTRR count for the CPU.
170 
171   @return Firmware usable variable MTRR count
172 
173 **/
174 UINT32
175 EFIAPI
GetFirmwareVariableMtrrCount(VOID)176 GetFirmwareVariableMtrrCount (
177   VOID
178   )
179 {
180   if (!IsMtrrSupported ()) {
181     return 0;
182   }
183   return GetFirmwareVariableMtrrCountWorker ();
184 }
185 
186 /**
187   Worker function returns the default MTRR cache type for the system.
188 
189   If MtrrSetting is not NULL, returns the default MTRR cache type from input
190   MTRR settings buffer.
191   If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
192 
193   @param[in]  MtrrSetting    A buffer holding all MTRRs content.
194 
195   @return  The default MTRR cache type.
196 
197 **/
198 MTRR_MEMORY_CACHE_TYPE
MtrrGetDefaultMemoryTypeWorker(IN MTRR_SETTINGS * MtrrSetting)199 MtrrGetDefaultMemoryTypeWorker (
200   IN MTRR_SETTINGS      *MtrrSetting
201   )
202 {
203   if (MtrrSetting == NULL) {
204     return (MTRR_MEMORY_CACHE_TYPE) (MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE) & 0x7);
205   } else {
206     return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
207   }
208 }
209 
210 
211 /**
212   Returns the default MTRR cache type for the system.
213 
214   @return  The default MTRR cache type.
215 
216 **/
217 MTRR_MEMORY_CACHE_TYPE
218 EFIAPI
MtrrGetDefaultMemoryType(VOID)219 MtrrGetDefaultMemoryType (
220   VOID
221   )
222 {
223   if (!IsMtrrSupported ()) {
224     return CacheUncacheable;
225   }
226   return MtrrGetDefaultMemoryTypeWorker (NULL);
227 }
228 
229 /**
230   Preparation before programming MTRR.
231 
232   This function will do some preparation for programming MTRRs:
233   disable cache, invalid cache and disable MTRR caching functionality
234 
235   @param[out] MtrrContext  Pointer to context to save
236 
237 **/
238 VOID
PreMtrrChange(OUT MTRR_CONTEXT * MtrrContext)239 PreMtrrChange (
240   OUT MTRR_CONTEXT  *MtrrContext
241   )
242 {
243   //
244   // Disable interrupts and save current interrupt state
245   //
246   MtrrContext->InterruptState = SaveAndDisableInterrupts();
247 
248   //
249   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
250   //
251   AsmDisableCache ();
252 
253   //
254   // Save original CR4 value and clear PGE flag (Bit 7)
255   //
256   MtrrContext->Cr4 = AsmReadCr4 ();
257   AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
258 
259   //
260   // Flush all TLBs
261   //
262   CpuFlushTlb ();
263 
264   //
265   // Disable MTRRs
266   //
267   MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 0);
268 }
269 
270 /**
271   Cleaning up after programming MTRRs.
272 
273   This function will do some clean up after programming MTRRs:
274   Flush all TLBs,  re-enable caching, restore CR4.
275 
276   @param[in] MtrrContext  Pointer to context to restore
277 
278 **/
279 VOID
PostMtrrChangeEnableCache(IN MTRR_CONTEXT * MtrrContext)280 PostMtrrChangeEnableCache (
281   IN MTRR_CONTEXT  *MtrrContext
282   )
283 {
284   //
285   // Flush all TLBs
286   //
287   CpuFlushTlb ();
288 
289   //
290   // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
291   //
292   AsmEnableCache ();
293 
294   //
295   // Restore original CR4 value
296   //
297   AsmWriteCr4 (MtrrContext->Cr4);
298 
299   //
300   // Restore original interrupt state
301   //
302   SetInterruptState (MtrrContext->InterruptState);
303 }
304 
305 /**
306   Cleaning up after programming MTRRs.
307 
308   This function will do some clean up after programming MTRRs:
309   enable MTRR caching functionality, and enable cache
310 
311   @param[in] MtrrContext  Pointer to context to restore
312 
313 **/
314 VOID
PostMtrrChange(IN MTRR_CONTEXT * MtrrContext)315 PostMtrrChange (
316   IN MTRR_CONTEXT  *MtrrContext
317   )
318 {
319   //
320   // Enable Cache MTRR
321   //
322   MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 3);
323 
324   PostMtrrChangeEnableCache (MtrrContext);
325 }
326 
327 /**
328   Worker function gets the content in fixed MTRRs
329 
330   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
331 
332   @retval The pointer of FixedSettings
333 
334 **/
335 MTRR_FIXED_SETTINGS*
MtrrGetFixedMtrrWorker(OUT MTRR_FIXED_SETTINGS * FixedSettings)336 MtrrGetFixedMtrrWorker (
337   OUT MTRR_FIXED_SETTINGS         *FixedSettings
338   )
339 {
340   UINT32  Index;
341 
342   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
343       FixedSettings->Mtrr[Index] =
344         MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);
345   }
346 
347   return FixedSettings;
348 }
349 
350 
351 /**
352   This function gets the content in fixed MTRRs
353 
354   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
355 
356   @retval The pointer of FixedSettings
357 
358 **/
359 MTRR_FIXED_SETTINGS*
360 EFIAPI
MtrrGetFixedMtrr(OUT MTRR_FIXED_SETTINGS * FixedSettings)361 MtrrGetFixedMtrr (
362   OUT MTRR_FIXED_SETTINGS         *FixedSettings
363   )
364 {
365   if (!IsMtrrSupported ()) {
366     return FixedSettings;
367   }
368 
369   return MtrrGetFixedMtrrWorker (FixedSettings);
370 }
371 
372 
373 /**
374   Worker function will get the raw value in variable MTRRs
375 
376   If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
377   MTRR settings buffer.
378   If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
379 
380   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
381   @param[in]  VariableMtrrCount  Number of variable MTRRs.
382   @param[out] VariableSettings   A buffer to hold variable MTRRs content.
383 
384   @return The VariableSettings input pointer
385 
386 **/
387 MTRR_VARIABLE_SETTINGS*
MtrrGetVariableMtrrWorker(IN MTRR_SETTINGS * MtrrSetting,IN UINT32 VariableMtrrCount,OUT MTRR_VARIABLE_SETTINGS * VariableSettings)388 MtrrGetVariableMtrrWorker (
389   IN  MTRR_SETTINGS           *MtrrSetting,
390   IN  UINT32                  VariableMtrrCount,
391   OUT MTRR_VARIABLE_SETTINGS  *VariableSettings
392   )
393 {
394   UINT32  Index;
395 
396   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
397 
398   for (Index = 0; Index < VariableMtrrCount; Index++) {
399     if (MtrrSetting == NULL) {
400       VariableSettings->Mtrr[Index].Base =
401         MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1));
402       VariableSettings->Mtrr[Index].Mask =
403         MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1);
404     } else {
405       VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
406       VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
407     }
408   }
409 
410   return  VariableSettings;
411 }
412 
413 /**
414   This function will get the raw value in variable MTRRs
415 
416   @param[out]  VariableSettings   A buffer to hold variable MTRRs content.
417 
418   @return The VariableSettings input pointer
419 
420 **/
421 MTRR_VARIABLE_SETTINGS*
422 EFIAPI
MtrrGetVariableMtrr(OUT MTRR_VARIABLE_SETTINGS * VariableSettings)423 MtrrGetVariableMtrr (
424   OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
425   )
426 {
427   if (!IsMtrrSupported ()) {
428     return VariableSettings;
429   }
430 
431   return MtrrGetVariableMtrrWorker (
432            NULL,
433            GetVariableMtrrCountWorker (),
434            VariableSettings
435            );
436 }
437 
438 /**
439   Programs fixed MTRRs registers.
440 
441   @param[in]      MemoryCacheType  The memory type to set.
442   @param[in, out] Base             The base address of memory range.
443   @param[in, out] Length           The length of memory range.
444   @param[out]     ReturnMsrNum     The index of the fixed MTRR MSR to program.
445   @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.
446   @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.
447 
448   @retval RETURN_SUCCESS      The cache type was updated successfully
449   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
450                               for the fixed MTRRs.
451 
452 **/
453 RETURN_STATUS
ProgramFixedMtrr(IN UINT64 MemoryCacheType,IN OUT UINT64 * Base,IN OUT UINT64 * Length,OUT UINT32 * ReturnMsrNum,OUT UINT64 * ReturnClearMask,OUT UINT64 * ReturnOrMask)454 ProgramFixedMtrr (
455   IN     UINT64               MemoryCacheType,
456   IN OUT UINT64               *Base,
457   IN OUT UINT64               *Length,
458   OUT    UINT32               *ReturnMsrNum,
459   OUT    UINT64               *ReturnClearMask,
460   OUT    UINT64               *ReturnOrMask
461   )
462 {
463   UINT32  MsrNum;
464   UINT32  ByteShift;
465   UINT64  OrMask;
466   UINT64  ClearMask;
467 
468   OrMask    = 0;
469   ClearMask = 0;
470 
471   for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
472     if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
473         (*Base <
474             (
475               mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
476               (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
477             )
478           )
479         ) {
480       break;
481     }
482   }
483 
484   if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
485     return RETURN_UNSUPPORTED;
486   }
487 
488   //
489   // We found the fixed MTRR to be programmed
490   //
491   for (ByteShift = 0; ByteShift < 8; ByteShift++) {
492     if (*Base ==
493          (
494            mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
495            (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
496          )
497        ) {
498       break;
499     }
500   }
501 
502   if (ByteShift == 8) {
503     return RETURN_UNSUPPORTED;
504   }
505 
506   for (
507         ;
508         ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
509         ByteShift++
510       ) {
511     OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
512     ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
513     *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
514     *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
515   }
516 
517   if (ByteShift < 8 && (*Length != 0)) {
518     return RETURN_UNSUPPORTED;
519   }
520 
521   *ReturnMsrNum    = MsrNum;
522   *ReturnClearMask = ClearMask;
523   *ReturnOrMask    = OrMask;
524 
525   return RETURN_SUCCESS;
526 }
527 
528 
529 /**
530   Worker function gets the attribute of variable MTRRs.
531 
532   This function shadows the content of variable MTRRs into an
533   internal array: VariableMtrr.
534 
535   @param[in]   VariableSettings           The variable MTRR values to shadow
536   @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware
537   @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR
538   @param[in]   MtrrValidAddressMask       The valid address mask for MTRR
539   @param[out]  VariableMtrr               The array to shadow variable MTRRs content
540 
541   @return                       The return value of this parameter indicates the
542                                 number of MTRRs which has been used.
543 
544 **/
545 UINT32
MtrrGetMemoryAttributeInVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN FirmwareVariableMtrrCount,IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)546 MtrrGetMemoryAttributeInVariableMtrrWorker (
547   IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,
548   IN  UINTN                   FirmwareVariableMtrrCount,
549   IN  UINT64                  MtrrValidBitsMask,
550   IN  UINT64                  MtrrValidAddressMask,
551   OUT VARIABLE_MTRR           *VariableMtrr
552   )
553 {
554   UINTN   Index;
555   UINT32  UsedMtrr;
556 
557   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
558   for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
559     if ((VariableSettings->Mtrr[Index].Mask & CACHE_MTRR_ENABLED) != 0) {
560       VariableMtrr[Index].Msr         = (UINT32)Index;
561       VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
562       VariableMtrr[Index].Length      = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
563       VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);
564       VariableMtrr[Index].Valid       = TRUE;
565       VariableMtrr[Index].Used        = TRUE;
566       UsedMtrr++;
567     }
568   }
569   return UsedMtrr;
570 }
571 
572 
573 /**
574   Gets the attribute of variable MTRRs.
575 
576   This function shadows the content of variable MTRRs into an
577   internal array: VariableMtrr.
578 
579   @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
580   @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
581   @param[out]  VariableMtrr          The array to shadow variable MTRRs content
582 
583   @return                       The return value of this parameter indicates the
584                                 number of MTRRs which has been used.
585 
586 **/
587 UINT32
588 EFIAPI
MtrrGetMemoryAttributeInVariableMtrr(IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)589 MtrrGetMemoryAttributeInVariableMtrr (
590   IN  UINT64                    MtrrValidBitsMask,
591   IN  UINT64                    MtrrValidAddressMask,
592   OUT VARIABLE_MTRR             *VariableMtrr
593   )
594 {
595   MTRR_VARIABLE_SETTINGS  VariableSettings;
596 
597   if (!IsMtrrSupported ()) {
598     return 0;
599   }
600 
601   MtrrGetVariableMtrrWorker (
602     NULL,
603     GetVariableMtrrCountWorker (),
604     &VariableSettings
605     );
606 
607   return MtrrGetMemoryAttributeInVariableMtrrWorker (
608            &VariableSettings,
609            GetFirmwareVariableMtrrCountWorker (),
610            MtrrValidBitsMask,
611            MtrrValidAddressMask,
612            VariableMtrr
613            );
614 }
615 
616 
617 /**
618   Checks overlap between given memory range and MTRRs.
619 
620   @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available
621                                          to firmware.
622   @param[in]  Start                      The start address of memory range.
623   @param[in]  End                        The end address of memory range.
624   @param[in]  VariableMtrr               The array to shadow variable MTRRs content
625 
626   @retval TRUE             Overlap exists.
627   @retval FALSE            No overlap.
628 
629 **/
630 BOOLEAN
CheckMemoryAttributeOverlap(IN UINTN FirmwareVariableMtrrCount,IN PHYSICAL_ADDRESS Start,IN PHYSICAL_ADDRESS End,IN VARIABLE_MTRR * VariableMtrr)631 CheckMemoryAttributeOverlap (
632   IN UINTN             FirmwareVariableMtrrCount,
633   IN PHYSICAL_ADDRESS  Start,
634   IN PHYSICAL_ADDRESS  End,
635   IN VARIABLE_MTRR     *VariableMtrr
636   )
637 {
638   UINT32  Index;
639 
640   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
641     if (
642          VariableMtrr[Index].Valid &&
643          !(
644            (Start > (VariableMtrr[Index].BaseAddress +
645                      VariableMtrr[Index].Length - 1)
646            ) ||
647            (End < VariableMtrr[Index].BaseAddress)
648          )
649        ) {
650       return TRUE;
651     }
652   }
653 
654   return FALSE;
655 }
656 
657 
658 /**
659   Marks a variable MTRR as non-valid.
660 
661   @param[in]   Index         The index of the array VariableMtrr to be invalidated
662   @param[in]   VariableMtrr  The array to shadow variable MTRRs content
663   @param[out]  UsedMtrr      The number of MTRRs which has already been used
664 
665 **/
666 VOID
InvalidateShadowMtrr(IN UINTN Index,IN VARIABLE_MTRR * VariableMtrr,OUT UINT32 * UsedMtrr)667 InvalidateShadowMtrr (
668   IN   UINTN              Index,
669   IN   VARIABLE_MTRR      *VariableMtrr,
670   OUT  UINT32             *UsedMtrr
671   )
672 {
673   VariableMtrr[Index].Valid = FALSE;
674   *UsedMtrr = *UsedMtrr - 1;
675 }
676 
677 
678 /**
679   Combines memory attributes.
680 
681   If overlap exists between given memory range and MTRRs, try to combine them.
682 
683   @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs
684                                               available to firmware.
685   @param[in]       Attributes                 The memory type to set.
686   @param[in, out]  Base                       The base address of memory range.
687   @param[in, out]  Length                     The length of memory range.
688   @param[in]       VariableMtrr               The array to shadow variable MTRRs content
689   @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used
690   @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used
691 
692   @retval EFI_SUCCESS            Memory region successfully combined.
693   @retval EFI_ACCESS_DENIED      Memory region cannot be combined.
694 
695 **/
696 RETURN_STATUS
CombineMemoryAttribute(IN UINT32 FirmwareVariableMtrrCount,IN UINT64 Attributes,IN OUT UINT64 * Base,IN OUT UINT64 * Length,IN VARIABLE_MTRR * VariableMtrr,IN OUT UINT32 * UsedMtrr,OUT BOOLEAN * OverwriteExistingMtrr)697 CombineMemoryAttribute (
698   IN     UINT32             FirmwareVariableMtrrCount,
699   IN     UINT64             Attributes,
700   IN OUT UINT64             *Base,
701   IN OUT UINT64             *Length,
702   IN     VARIABLE_MTRR      *VariableMtrr,
703   IN OUT UINT32             *UsedMtrr,
704   OUT    BOOLEAN            *OverwriteExistingMtrr
705   )
706 {
707   UINT32  Index;
708   UINT64  CombineStart;
709   UINT64  CombineEnd;
710   UINT64  MtrrEnd;
711   UINT64  EndAddress;
712   BOOLEAN CoveredByExistingMtrr;
713 
714   *OverwriteExistingMtrr = FALSE;
715   CoveredByExistingMtrr = FALSE;
716   EndAddress = *Base +*Length - 1;
717 
718   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
719 
720     MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
721     if (
722          !VariableMtrr[Index].Valid ||
723          (
724            *Base > (MtrrEnd) ||
725            (EndAddress < VariableMtrr[Index].BaseAddress)
726          )
727        ) {
728       continue;
729     }
730 
731     //
732     // Combine same attribute MTRR range
733     //
734     if (Attributes == VariableMtrr[Index].Type) {
735       //
736       // if the MTRR range contain the request range, set a flag, then continue to
737       // invalidate any MTRR of the same request range with higher priority cache type.
738       //
739       if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
740         CoveredByExistingMtrr = TRUE;
741         continue;
742       }
743       //
744       // invalid this MTRR, and program the combine range
745       //
746       CombineStart  =
747         (*Base) < VariableMtrr[Index].BaseAddress ?
748           (*Base) :
749           VariableMtrr[Index].BaseAddress;
750       CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
751 
752       //
753       // Record the MTRR usage status in VariableMtrr array.
754       //
755       InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
756       *Base       = CombineStart;
757       *Length     = CombineEnd - CombineStart + 1;
758       EndAddress  = CombineEnd;
759       *OverwriteExistingMtrr = TRUE;
760       continue;
761     } else {
762       //
763       // The cache type is different, but the range is convered by one MTRR
764       //
765       if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
766         InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
767         continue;
768       }
769 
770     }
771 
772     if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
773          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
774         (Attributes == MTRR_CACHE_WRITE_BACK &&
775          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
776         (Attributes == MTRR_CACHE_UNCACHEABLE) ||
777         (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
778      ) {
779       *OverwriteExistingMtrr = TRUE;
780       continue;
781     }
782     //
783     // Other type memory overlap is invalid
784     //
785     return RETURN_ACCESS_DENIED;
786   }
787 
788   if (CoveredByExistingMtrr) {
789     *Length = 0;
790   }
791 
792   return RETURN_SUCCESS;
793 }
794 
795 
796 /**
797   Calculates the maximum value which is a power of 2, but less the MemoryLength.
798 
799   @param[in]  MemoryLength        The number to pass in.
800 
801   @return The maximum value which is align to power of 2 and less the MemoryLength
802 
803 **/
804 UINT64
Power2MaxMemory(IN UINT64 MemoryLength)805 Power2MaxMemory (
806   IN UINT64                     MemoryLength
807   )
808 {
809   UINT64  Result;
810 
811   if (RShiftU64 (MemoryLength, 32) != 0) {
812     Result = LShiftU64 (
813                (UINT64) GetPowerOfTwo32 (
814                           (UINT32) RShiftU64 (MemoryLength, 32)
815                           ),
816                32
817                );
818   } else {
819     Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
820   }
821 
822   return Result;
823 }
824 
825 
826 /**
827   Determines the MTRR numbers used to program a memory range.
828 
829   This function first checks the alignment of the base address.
830   If the alignment of the base address <= Length, cover the memory range
831  (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
832   Length -= alignment. Repeat the step until alignment > Length.
833 
834   Then this function determines which direction of programming the variable
835   MTRRs for the remaining length will use fewer MTRRs.
836 
837   @param[in]  BaseAddress Length of Memory to program MTRR
838   @param[in]  Length      Length of Memory to program MTRR
839   @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs
840 
841   @retval TRUE        Positive direction is better.
842           FALSE       Negative direction is better.
843 
844 **/
845 BOOLEAN
GetMtrrNumberAndDirection(IN UINT64 BaseAddress,IN UINT64 Length,IN UINTN * MtrrNumber)846 GetMtrrNumberAndDirection (
847   IN UINT64      BaseAddress,
848   IN UINT64      Length,
849   IN UINTN       *MtrrNumber
850   )
851 {
852   UINT64  TempQword;
853   UINT64  Alignment;
854   UINT32  Positive;
855   UINT32  Subtractive;
856 
857   *MtrrNumber = 0;
858 
859   if (BaseAddress != 0) {
860     do {
861       //
862       // Calculate the alignment of the base address.
863       //
864       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
865 
866       if (Alignment > Length) {
867         break;
868       }
869 
870       (*MtrrNumber)++;
871       BaseAddress += Alignment;
872       Length -= Alignment;
873     } while (TRUE);
874 
875     if (Length == 0) {
876       return TRUE;
877     }
878   }
879 
880   TempQword   = Length;
881   Positive    = 0;
882   Subtractive = 0;
883 
884   do {
885     TempQword -= Power2MaxMemory (TempQword);
886     Positive++;
887   } while (TempQword != 0);
888 
889   TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
890   Subtractive++;
891   do {
892     TempQword -= Power2MaxMemory (TempQword);
893     Subtractive++;
894   } while (TempQword != 0);
895 
896   if (Positive <= Subtractive) {
897     *MtrrNumber += Positive;
898     return TRUE;
899   } else {
900     *MtrrNumber += Subtractive;
901     return FALSE;
902   }
903 }
904 
905 /**
906   Invalid variable MTRRs according to the value in the shadow array.
907 
908   This function programs MTRRs according to the values specified
909   in the shadow array.
910 
911   @param[in, out]  VariableSettings   Variable MTRR settings
912   @param[in]       VariableMtrrCount  Number of variable MTRRs
913   @param[in, out]  VariableMtrr       Shadow of variable MTRR contents
914 
915 **/
916 VOID
InvalidateMtrr(IN OUT MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN VariableMtrrCount,IN OUT VARIABLE_MTRR * VariableMtrr)917 InvalidateMtrr (
918   IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
919   IN     UINTN                   VariableMtrrCount,
920   IN OUT VARIABLE_MTRR           *VariableMtrr
921   )
922 {
923   UINTN         Index;
924 
925   for (Index = 0; Index < VariableMtrrCount; Index++) {
926     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
927        VariableSettings->Mtrr[Index].Base = 0;
928        VariableSettings->Mtrr[Index].Mask = 0;
929        VariableMtrr[Index].Used = FALSE;
930     }
931   }
932 }
933 
934 
935 /**
936   Programs variable MTRRs
937 
938   This function programs variable MTRRs
939 
940   @param[in, out]  VariableSettings      Variable MTRR settings.
941   @param[in]       MtrrNumber            Index of MTRR to program.
942   @param[in]       BaseAddress           Base address of memory region.
943   @param[in]       Length                Length of memory region.
944   @param[in]       MemoryCacheType       Memory type to set.
945   @param[in]       MtrrValidAddressMask  The valid address mask for MTRR
946 
947 **/
948 VOID
ProgramVariableMtrr(IN OUT MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN MtrrNumber,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 MemoryCacheType,IN UINT64 MtrrValidAddressMask)949 ProgramVariableMtrr (
950   IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
951   IN     UINTN                   MtrrNumber,
952   IN     PHYSICAL_ADDRESS        BaseAddress,
953   IN     UINT64                  Length,
954   IN     UINT64                  MemoryCacheType,
955   IN     UINT64                  MtrrValidAddressMask
956   )
957 {
958   UINT64        TempQword;
959 
960   //
961   // MTRR Physical Base
962   //
963   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
964   VariableSettings->Mtrr[MtrrNumber].Base = TempQword;
965 
966   //
967   // MTRR Physical Mask
968   //
969   TempQword = ~(Length - 1);
970   VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | CACHE_MTRR_ENABLED;
971 }
972 
973 
974 /**
975   Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
976 
977   If MtrrSetting is not NULL, gets the default memory attribute from input
978   MTRR settings buffer.
979   If MtrrSetting is NULL, gets the default memory attribute from MSR.
980 
981   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
982   @param[in]  MtrrType           MTRR memory type
983 
984   @return The enum item in MTRR_MEMORY_CACHE_TYPE
985 
986 **/
987 MTRR_MEMORY_CACHE_TYPE
GetMemoryCacheTypeFromMtrrType(IN MTRR_SETTINGS * MtrrSetting,IN UINT64 MtrrType)988 GetMemoryCacheTypeFromMtrrType (
989   IN MTRR_SETTINGS         *MtrrSetting,
990   IN UINT64                MtrrType
991   )
992 {
993   switch (MtrrType) {
994   case MTRR_CACHE_UNCACHEABLE:
995     return CacheUncacheable;
996   case MTRR_CACHE_WRITE_COMBINING:
997     return CacheWriteCombining;
998   case MTRR_CACHE_WRITE_THROUGH:
999     return CacheWriteThrough;
1000   case MTRR_CACHE_WRITE_PROTECTED:
1001     return CacheWriteProtected;
1002   case MTRR_CACHE_WRITE_BACK:
1003     return CacheWriteBack;
1004   default:
1005     //
1006     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
1007     // no MTRR covers the range
1008     //
1009     return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
1010   }
1011 }
1012 
1013 /**
1014   Initializes the valid bits mask and valid address mask for MTRRs.
1015 
1016   This function initializes the valid bits mask and valid address mask for MTRRs.
1017 
1018   @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR
1019   @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR
1020 
1021 **/
1022 VOID
MtrrLibInitializeMtrrMask(OUT UINT64 * MtrrValidBitsMask,OUT UINT64 * MtrrValidAddressMask)1023 MtrrLibInitializeMtrrMask (
1024   OUT UINT64 *MtrrValidBitsMask,
1025   OUT UINT64 *MtrrValidAddressMask
1026   )
1027 {
1028   UINT32  RegEax;
1029   UINT8   PhysicalAddressBits;
1030 
1031   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1032 
1033   if (RegEax >= 0x80000008) {
1034     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1035 
1036     PhysicalAddressBits = (UINT8) RegEax;
1037   } else {
1038     PhysicalAddressBits = 36;
1039   }
1040 
1041   *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
1042   *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
1043 }
1044 
1045 
1046 /**
1047   Determines the real attribute of a memory range.
1048 
1049   This function is to arbitrate the real attribute of the memory when
1050   there are 2 MTRRs covers the same memory range.  For further details,
1051   please refer the IA32 Software Developer's Manual, Volume 3,
1052   Section 10.11.4.1.
1053 
1054   @param[in]  MtrrType1    The first kind of Memory type
1055   @param[in]  MtrrType2    The second kind of memory type
1056 
1057 **/
1058 UINT64
MtrrPrecedence(IN UINT64 MtrrType1,IN UINT64 MtrrType2)1059 MtrrPrecedence (
1060   IN UINT64    MtrrType1,
1061   IN UINT64    MtrrType2
1062   )
1063 {
1064   UINT64 MtrrType;
1065 
1066   MtrrType = MTRR_CACHE_INVALID_TYPE;
1067   switch (MtrrType1) {
1068   case MTRR_CACHE_UNCACHEABLE:
1069     MtrrType = MTRR_CACHE_UNCACHEABLE;
1070     break;
1071   case MTRR_CACHE_WRITE_COMBINING:
1072     if (
1073          MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
1074          MtrrType2==MTRR_CACHE_UNCACHEABLE
1075        ) {
1076       MtrrType = MtrrType2;
1077     }
1078     break;
1079   case MTRR_CACHE_WRITE_THROUGH:
1080     if (
1081          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1082          MtrrType2==MTRR_CACHE_WRITE_BACK
1083        ) {
1084       MtrrType = MTRR_CACHE_WRITE_THROUGH;
1085     } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
1086       MtrrType = MTRR_CACHE_UNCACHEABLE;
1087     }
1088     break;
1089   case MTRR_CACHE_WRITE_PROTECTED:
1090     if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
1091         MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
1092       MtrrType = MtrrType2;
1093     }
1094     break;
1095   case MTRR_CACHE_WRITE_BACK:
1096     if (
1097          MtrrType2== MTRR_CACHE_UNCACHEABLE ||
1098          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1099          MtrrType2== MTRR_CACHE_WRITE_BACK
1100        ) {
1101       MtrrType = MtrrType2;
1102     }
1103     break;
1104   case MTRR_CACHE_INVALID_TYPE:
1105     MtrrType = MtrrType2;
1106     break;
1107   default:
1108     break;
1109   }
1110 
1111   if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
1112     MtrrType = MtrrType1;
1113   }
1114   return MtrrType;
1115 }
1116 
1117 /**
1118   Worker function will get the memory cache type of the specific address.
1119 
1120   If MtrrSetting is not NULL, gets the memory cache type from input
1121   MTRR settings buffer.
1122   If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1123 
1124   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
1125   @param[in]  Address            The specific address
1126 
1127   @return Memory cache type of the specific address
1128 
1129 **/
1130 MTRR_MEMORY_CACHE_TYPE
MtrrGetMemoryAttributeByAddressWorker(IN MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS Address)1131 MtrrGetMemoryAttributeByAddressWorker (
1132   IN MTRR_SETTINGS      *MtrrSetting,
1133   IN PHYSICAL_ADDRESS   Address
1134   )
1135 {
1136   UINT64                  TempQword;
1137   UINTN                   Index;
1138   UINTN                   SubIndex;
1139   UINT64                  MtrrType;
1140   UINT64                  TempMtrrType;
1141   MTRR_MEMORY_CACHE_TYPE  CacheType;
1142   VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1143   UINT64                  MtrrValidBitsMask;
1144   UINT64                  MtrrValidAddressMask;
1145   UINTN                   VariableMtrrCount;
1146   MTRR_VARIABLE_SETTINGS  VariableSettings;
1147 
1148   //
1149   // Check if MTRR is enabled, if not, return UC as attribute
1150   //
1151   if (MtrrSetting == NULL) {
1152     TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);
1153   } else {
1154     TempQword = MtrrSetting->MtrrDefType;
1155   }
1156   MtrrType = MTRR_CACHE_INVALID_TYPE;
1157 
1158   if ((TempQword & CACHE_MTRR_ENABLED) == 0) {
1159     return CacheUncacheable;
1160   }
1161 
1162   //
1163   // If address is less than 1M, then try to go through the fixed MTRR
1164   //
1165   if (Address < BASE_1MB) {
1166     if ((TempQword & CACHE_FIXED_MTRR_ENABLED) != 0) {
1167       //
1168       // Go through the fixed MTRR
1169       //
1170       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1171          if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1172              Address  < (
1173                           mMtrrLibFixedMtrrTable[Index].BaseAddress +
1174                           (mMtrrLibFixedMtrrTable[Index].Length * 8)
1175                         )
1176             ) {
1177            SubIndex =
1178              ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1179                mMtrrLibFixedMtrrTable[Index].Length;
1180            if (MtrrSetting == NULL) {
1181              TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);
1182            } else {
1183              TempQword = MtrrSetting->Fixed.Mtrr[Index];
1184            }
1185            MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1186            return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1187          }
1188       }
1189     }
1190   }
1191   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1192 
1193   MtrrGetVariableMtrrWorker (
1194     MtrrSetting,
1195     GetVariableMtrrCountWorker (),
1196     &VariableSettings
1197     );
1198 
1199   MtrrGetMemoryAttributeInVariableMtrrWorker (
1200            &VariableSettings,
1201            GetFirmwareVariableMtrrCountWorker (),
1202            MtrrValidBitsMask,
1203            MtrrValidAddressMask,
1204            VariableMtrr
1205            );
1206 
1207   //
1208   // Go through the variable MTRR
1209   //
1210   VariableMtrrCount = GetVariableMtrrCountWorker ();
1211   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1212 
1213   for (Index = 0; Index < VariableMtrrCount; Index++) {
1214     if (VariableMtrr[Index].Valid) {
1215       if (Address >= VariableMtrr[Index].BaseAddress &&
1216           Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1217         TempMtrrType = VariableMtrr[Index].Type;
1218         MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1219       }
1220     }
1221   }
1222   CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1223 
1224   return CacheType;
1225 }
1226 
1227 
1228 /**
1229   This function will get the memory cache type of the specific address.
1230 
1231   This function is mainly for debug purpose.
1232 
1233   @param[in]  Address   The specific address
1234 
1235   @return Memory cache type of the specific address
1236 
1237 **/
1238 MTRR_MEMORY_CACHE_TYPE
1239 EFIAPI
MtrrGetMemoryAttribute(IN PHYSICAL_ADDRESS Address)1240 MtrrGetMemoryAttribute (
1241   IN PHYSICAL_ADDRESS   Address
1242   )
1243 {
1244   if (!IsMtrrSupported ()) {
1245     return CacheUncacheable;
1246   }
1247 
1248   return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1249 }
1250 
1251 /**
1252   Worker function prints all MTRRs for debugging.
1253 
1254   If MtrrSetting is not NULL, print MTRR settings from from input MTRR
1255   settings buffer.
1256   If MtrrSetting is NULL, print MTRR settings from MTRRs.
1257 
1258   @param  MtrrSetting    A buffer holding all MTRRs content.
1259 **/
1260 VOID
MtrrDebugPrintAllMtrrsWorker(IN MTRR_SETTINGS * MtrrSetting)1261 MtrrDebugPrintAllMtrrsWorker (
1262   IN MTRR_SETTINGS    *MtrrSetting
1263   )
1264 {
1265   DEBUG_CODE (
1266     MTRR_SETTINGS  LocalMtrrs;
1267     MTRR_SETTINGS  *Mtrrs;
1268     UINTN          Index;
1269     UINTN          Index1;
1270     UINTN          VariableMtrrCount;
1271     UINT64         Base;
1272     UINT64         Limit;
1273     UINT64         MtrrBase;
1274     UINT64         MtrrLimit;
1275     UINT64         RangeBase;
1276     UINT64         RangeLimit;
1277     UINT64         NoRangeBase;
1278     UINT64         NoRangeLimit;
1279     UINT32         RegEax;
1280     UINTN          MemoryType;
1281     UINTN          PreviousMemoryType;
1282     BOOLEAN        Found;
1283 
1284     if (!IsMtrrSupported ()) {
1285       return;
1286     }
1287 
1288     DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1289     DEBUG((DEBUG_CACHE, "=============\n"));
1290 
1291     if (MtrrSetting != NULL) {
1292       Mtrrs = MtrrSetting;
1293     } else {
1294       MtrrGetAllMtrrs (&LocalMtrrs);
1295       Mtrrs = &LocalMtrrs;
1296     }
1297 
1298     DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
1299     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1300       DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
1301     }
1302 
1303     VariableMtrrCount = GetVariableMtrrCount ();
1304     for (Index = 0; Index < VariableMtrrCount; Index++) {
1305       DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1306         Index,
1307         Mtrrs->Variables.Mtrr[Index].Base,
1308         Mtrrs->Variables.Mtrr[Index].Mask
1309         ));
1310     }
1311     DEBUG((DEBUG_CACHE, "\n"));
1312     DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1313     DEBUG((DEBUG_CACHE, "====================================\n"));
1314 
1315     Base = 0;
1316     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1317     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1318       Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1319       for (Index1 = 0; Index1 < 8; Index1++) {
1320       MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1321         if (MemoryType > CacheWriteBack) {
1322           MemoryType = MTRR_CACHE_INVALID_TYPE;
1323         }
1324         if (MemoryType != PreviousMemoryType) {
1325           if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1326             DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1327           }
1328           PreviousMemoryType = MemoryType;
1329           DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1330         }
1331         Base += mMtrrLibFixedMtrrTable[Index].Length;
1332       }
1333     }
1334     DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1335 
1336     VariableMtrrCount = GetVariableMtrrCount ();
1337 
1338     Limit        = BIT36 - 1;
1339     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1340     if (RegEax >= 0x80000008) {
1341       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1342       Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1343     }
1344     Base = BASE_1MB;
1345     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1346     do {
1347       MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
1348       if (MemoryType > CacheWriteBack) {
1349         MemoryType = MTRR_CACHE_INVALID_TYPE;
1350       }
1351 
1352       if (MemoryType != PreviousMemoryType) {
1353         if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1354           DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1355         }
1356         PreviousMemoryType = MemoryType;
1357         DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1358       }
1359 
1360       RangeBase    = BASE_1MB;
1361       NoRangeBase  = BASE_1MB;
1362       RangeLimit   = Limit;
1363       NoRangeLimit = Limit;
1364 
1365       for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1366         if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
1367           //
1368           // If mask is not valid, then do not display range
1369           //
1370           continue;
1371         }
1372         MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1373         MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1374 
1375         if (Base >= MtrrBase && Base < MtrrLimit) {
1376           Found = TRUE;
1377         }
1378 
1379         if (Base >= MtrrBase && MtrrBase > RangeBase) {
1380           RangeBase = MtrrBase;
1381         }
1382         if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1383           RangeBase = MtrrLimit + 1;
1384         }
1385         if (Base < MtrrBase && MtrrBase < RangeLimit) {
1386           RangeLimit = MtrrBase - 1;
1387         }
1388         if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1389           RangeLimit = MtrrLimit;
1390         }
1391 
1392         if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1393           NoRangeBase = MtrrLimit + 1;
1394         }
1395         if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1396           NoRangeLimit = MtrrBase - 1;
1397         }
1398       }
1399 
1400       if (Found) {
1401         Base = RangeLimit + 1;
1402       } else {
1403         Base = NoRangeLimit + 1;
1404       }
1405     } while (Base < Limit);
1406     DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1407   );
1408 }
1409 
1410 
1411 /**
1412   This function prints all MTRRs for debugging.
1413 **/
1414 VOID
1415 EFIAPI
MtrrDebugPrintAllMtrrs(VOID)1416 MtrrDebugPrintAllMtrrs (
1417   VOID
1418   )
1419 {
1420   MtrrDebugPrintAllMtrrsWorker (NULL);
1421 }
1422 
1423 
1424 /**
1425   Worker function attempts to set the attributes for a memory range.
1426 
1427   If MtrrSettings is not NULL, set the attributes into the input MTRR
1428   settings buffer.
1429   If MtrrSettings is NULL, set the attributes into MTRRs registers.
1430 
1431   @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.
1432   @param[in]       BaseAddress       The physical address that is the start
1433                                      address of a memory region.
1434   @param[in]       Length            The size in bytes of the memory region.
1435   @param[in]       Attribute         The bit mask of attributes to set for the
1436                                      memory region.
1437 
1438   @retval RETURN_SUCCESS            The attributes were set for the memory
1439                                     region.
1440   @retval RETURN_INVALID_PARAMETER  Length is zero.
1441   @retval RETURN_UNSUPPORTED        The processor does not support one or
1442                                     more bytes of the memory resource range
1443                                     specified by BaseAddress and Length.
1444   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
1445                                     for the memory resource range specified
1446                                     by BaseAddress and Length.
1447   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
1448                                     range specified by BaseAddress and Length
1449                                     cannot be modified.
1450   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
1451                                     modify the attributes of the memory
1452                                     resource range.
1453 
1454 **/
1455 RETURN_STATUS
MtrrSetMemoryAttributeWorker(IN OUT MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1456 MtrrSetMemoryAttributeWorker (
1457   IN OUT MTRR_SETTINGS           *MtrrSetting,
1458   IN PHYSICAL_ADDRESS            BaseAddress,
1459   IN UINT64                      Length,
1460   IN MTRR_MEMORY_CACHE_TYPE      Attribute
1461   )
1462 {
1463   UINT64                    TempQword;
1464   RETURN_STATUS             Status;
1465   UINT64                    MemoryType;
1466   UINT64                    Alignment;
1467   BOOLEAN                   OverLap;
1468   BOOLEAN                   Positive;
1469   UINT32                    MsrNum;
1470   UINTN                     MtrrNumber;
1471   VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1472   UINT32                    UsedMtrr;
1473   UINT64                    MtrrValidBitsMask;
1474   UINT64                    MtrrValidAddressMask;
1475   BOOLEAN                   OverwriteExistingMtrr;
1476   UINT32                    FirmwareVariableMtrrCount;
1477   MTRR_CONTEXT              MtrrContext;
1478   BOOLEAN                   MtrrContextValid;
1479   BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
1480   BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
1481   MTRR_FIXED_SETTINGS       WorkingFixedSettings;
1482   UINT32                    VariableMtrrCount;
1483   MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;
1484   BOOLEAN                   ProgramVariableSettings;
1485   MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;
1486   UINT32                    Index;
1487   UINT64                    ClearMask;
1488   UINT64                    OrMask;
1489   UINT64                    NewValue;
1490   MTRR_VARIABLE_SETTINGS    *VariableSettings;
1491 
1492   MtrrContextValid  = FALSE;
1493   VariableMtrrCount = 0;
1494   ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
1495   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1496     FixedSettingsValid[Index]    = FALSE;
1497     FixedSettingsModified[Index] = FALSE;
1498   }
1499   ProgramVariableSettings = FALSE;
1500 
1501   if (!IsMtrrSupported ()) {
1502     Status = RETURN_UNSUPPORTED;
1503     goto Done;
1504   }
1505 
1506   MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1507 
1508   TempQword = 0;
1509   MemoryType = (UINT64)Attribute;
1510   OverwriteExistingMtrr = FALSE;
1511 
1512   //
1513   // Check for an invalid parameter
1514   //
1515   if (Length == 0) {
1516     Status = RETURN_INVALID_PARAMETER;
1517     goto Done;
1518   }
1519 
1520   if (
1521        (BaseAddress & ~MtrrValidAddressMask) != 0 ||
1522        (Length & ~MtrrValidAddressMask) != 0
1523      ) {
1524     Status = RETURN_UNSUPPORTED;
1525     goto Done;
1526   }
1527 
1528   //
1529   // Check if Fixed MTRR
1530   //
1531   Status = RETURN_SUCCESS;
1532   if (BaseAddress < BASE_1MB) {
1533     while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
1534       Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);
1535       if (RETURN_ERROR (Status)) {
1536         goto Done;
1537       }
1538       if (MtrrSetting != NULL) {
1539         MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1540         MtrrSetting->MtrrDefType |= CACHE_FIXED_MTRR_ENABLED;
1541       } else {
1542         if (!FixedSettingsValid[MsrNum]) {
1543           WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);
1544           FixedSettingsValid[MsrNum] = TRUE;
1545         }
1546         NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1547         if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {
1548           WorkingFixedSettings.Mtrr[MsrNum] = NewValue;
1549           FixedSettingsModified[MsrNum] = TRUE;
1550         }
1551       }
1552     }
1553 
1554     if (Length == 0) {
1555       //
1556       // A Length of 0 can only make sense for fixed MTTR ranges.
1557       // Since we just handled the fixed MTRRs, we can skip the
1558       // variable MTRR section.
1559       //
1560       goto Done;
1561     }
1562   }
1563 
1564   //
1565   // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1566   // we can set the base to 0 to save variable MTRRs.
1567   //
1568   if (BaseAddress == BASE_1MB) {
1569     BaseAddress = 0;
1570     Length += SIZE_1MB;
1571   }
1572 
1573   //
1574   // Read all variable MTRRs
1575   //
1576   VariableMtrrCount = GetVariableMtrrCountWorker ();
1577   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1578   if (MtrrSetting != NULL) {
1579     VariableSettings = &MtrrSetting->Variables;
1580   } else {
1581     MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);
1582     CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));
1583     ProgramVariableSettings = TRUE;
1584     VariableSettings = &WorkingVariableSettings;
1585   }
1586 
1587   //
1588   // Check for overlap
1589   //
1590   UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (
1591                VariableSettings,
1592                FirmwareVariableMtrrCount,
1593                MtrrValidBitsMask,
1594                MtrrValidAddressMask,
1595                VariableMtrr
1596                );
1597   OverLap = CheckMemoryAttributeOverlap (
1598               FirmwareVariableMtrrCount,
1599               BaseAddress,
1600               BaseAddress + Length - 1,
1601               VariableMtrr
1602               );
1603   if (OverLap) {
1604     Status = CombineMemoryAttribute (
1605                FirmwareVariableMtrrCount,
1606                MemoryType,
1607                &BaseAddress,
1608                &Length,
1609                VariableMtrr,
1610                &UsedMtrr,
1611                &OverwriteExistingMtrr
1612                );
1613     if (RETURN_ERROR (Status)) {
1614       goto Done;
1615     }
1616 
1617     if (Length == 0) {
1618       //
1619       // Combined successfully, invalidate the now-unused MTRRs
1620       //
1621       InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1622       Status = RETURN_SUCCESS;
1623       goto Done;
1624     }
1625   }
1626 
1627   //
1628   // The memory type is the same with the type specified by
1629   // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1630   //
1631   if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {
1632     //
1633     // Invalidate the now-unused MTRRs
1634     //
1635     InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1636     goto Done;
1637   }
1638 
1639   Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
1640 
1641   if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1642     Status = RETURN_OUT_OF_RESOURCES;
1643     goto Done;
1644   }
1645 
1646   //
1647   // Invalidate the now-unused MTRRs
1648   //
1649   InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1650 
1651   //
1652   // Find first unused MTRR
1653   //
1654   for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {
1655     if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
1656       break;
1657     }
1658   }
1659 
1660   if (BaseAddress != 0) {
1661     do {
1662       //
1663       // Calculate the alignment of the base address.
1664       //
1665       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
1666 
1667       if (Alignment > Length) {
1668         break;
1669       }
1670 
1671       //
1672       // Find unused MTRR
1673       //
1674       for (; MsrNum < VariableMtrrCount; MsrNum++) {
1675         if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
1676           break;
1677         }
1678       }
1679 
1680       ProgramVariableMtrr (
1681         VariableSettings,
1682         MsrNum,
1683         BaseAddress,
1684         Alignment,
1685         MemoryType,
1686         MtrrValidAddressMask
1687         );
1688       BaseAddress += Alignment;
1689       Length -= Alignment;
1690     } while (TRUE);
1691 
1692     if (Length == 0) {
1693       goto Done;
1694     }
1695   }
1696 
1697   TempQword = Length;
1698 
1699   if (!Positive) {
1700     Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1701 
1702     //
1703     // Find unused MTRR
1704     //
1705     for (; MsrNum < VariableMtrrCount; MsrNum++) {
1706       if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
1707         break;
1708       }
1709     }
1710 
1711     ProgramVariableMtrr (
1712       VariableSettings,
1713       MsrNum,
1714       BaseAddress,
1715       Length,
1716       MemoryType,
1717       MtrrValidAddressMask
1718       );
1719     BaseAddress += Length;
1720     TempQword   = Length - TempQword;
1721     MemoryType  = MTRR_CACHE_UNCACHEABLE;
1722   }
1723 
1724   do {
1725     //
1726     // Find unused MTRR
1727     //
1728     for (; MsrNum < VariableMtrrCount; MsrNum++) {
1729       if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
1730         break;
1731       }
1732     }
1733 
1734     Length = Power2MaxMemory (TempQword);
1735     if (!Positive) {
1736       BaseAddress -= Length;
1737     }
1738 
1739     ProgramVariableMtrr (
1740       VariableSettings,
1741       MsrNum,
1742       BaseAddress,
1743       Length,
1744       MemoryType,
1745       MtrrValidAddressMask
1746       );
1747 
1748     if (Positive) {
1749       BaseAddress += Length;
1750     }
1751     TempQword -= Length;
1752 
1753   } while (TempQword > 0);
1754 
1755 Done:
1756 
1757   //
1758   // Write fixed MTRRs that have been modified
1759   //
1760   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1761     if (FixedSettingsModified[Index]) {
1762       if (!MtrrContextValid) {
1763         PreMtrrChange (&MtrrContext);
1764         MtrrContextValid = TRUE;
1765       }
1766       MtrrRegisterWrite (
1767         mMtrrLibFixedMtrrTable[Index].Msr,
1768         WorkingFixedSettings.Mtrr[Index]
1769         );
1770     }
1771   }
1772 
1773   //
1774   // Write variable MTRRs
1775   //
1776   if (ProgramVariableSettings) {
1777     for (Index = 0; Index < VariableMtrrCount; Index++) {
1778       if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||
1779           WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {
1780         if (!MtrrContextValid) {
1781           PreMtrrChange (&MtrrContext);
1782           MtrrContextValid = TRUE;
1783         }
1784         MtrrRegisterWrite (
1785           QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),
1786           WorkingVariableSettings.Mtrr[Index].Base
1787           );
1788         MtrrRegisterWrite (
1789           QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,
1790           WorkingVariableSettings.Mtrr[Index].Mask
1791           );
1792       }
1793     }
1794   }
1795   if (MtrrContextValid) {
1796     PostMtrrChange (&MtrrContext);
1797   }
1798 
1799   DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));
1800   if (!RETURN_ERROR (Status)) {
1801     if (MtrrSetting != NULL) {
1802       MtrrSetting->MtrrDefType |= CACHE_MTRR_ENABLED;
1803     }
1804     MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
1805   }
1806 
1807   return Status;
1808 }
1809 
1810 /**
1811   This function attempts to set the attributes for a memory range.
1812 
1813   @param[in]  BaseAddress        The physical address that is the start
1814                                  address of a memory region.
1815   @param[in]  Length             The size in bytes of the memory region.
1816   @param[in]  Attributes         The bit mask of attributes to set for the
1817                                  memory region.
1818 
1819   @retval RETURN_SUCCESS            The attributes were set for the memory
1820                                     region.
1821   @retval RETURN_INVALID_PARAMETER  Length is zero.
1822   @retval RETURN_UNSUPPORTED        The processor does not support one or
1823                                     more bytes of the memory resource range
1824                                     specified by BaseAddress and Length.
1825   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
1826                                     for the memory resource range specified
1827                                     by BaseAddress and Length.
1828   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
1829                                     range specified by BaseAddress and Length
1830                                     cannot be modified.
1831   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
1832                                     modify the attributes of the memory
1833                                     resource range.
1834 
1835 **/
1836 RETURN_STATUS
1837 EFIAPI
MtrrSetMemoryAttribute(IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1838 MtrrSetMemoryAttribute (
1839   IN PHYSICAL_ADDRESS        BaseAddress,
1840   IN UINT64                  Length,
1841   IN MTRR_MEMORY_CACHE_TYPE  Attribute
1842   )
1843 {
1844   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1845   return MtrrSetMemoryAttributeWorker (
1846            NULL,
1847            BaseAddress,
1848            Length,
1849            Attribute
1850            );
1851 }
1852 
1853 /**
1854   This function attempts to set the attributes into MTRR setting buffer for a memory range.
1855 
1856   @param[in, out]  MtrrSetting  MTRR setting buffer to be set.
1857   @param[in]       BaseAddress  The physical address that is the start address
1858                                 of a memory region.
1859   @param[in]       Length       The size in bytes of the memory region.
1860   @param[in]       Attribute    The bit mask of attributes to set for the
1861                                 memory region.
1862 
1863   @retval RETURN_SUCCESS            The attributes were set for the memory region.
1864   @retval RETURN_INVALID_PARAMETER  Length is zero.
1865   @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the
1866                                     memory resource range specified by BaseAddress and Length.
1867   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource
1868                                     range specified by BaseAddress and Length.
1869   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by
1870                                     BaseAddress and Length cannot be modified.
1871   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of
1872                                     the memory resource range.
1873 
1874 **/
1875 RETURN_STATUS
1876 EFIAPI
MtrrSetMemoryAttributeInMtrrSettings(IN OUT MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1877 MtrrSetMemoryAttributeInMtrrSettings (
1878   IN OUT MTRR_SETTINGS       *MtrrSetting,
1879   IN PHYSICAL_ADDRESS        BaseAddress,
1880   IN UINT64                  Length,
1881   IN MTRR_MEMORY_CACHE_TYPE  Attribute
1882   )
1883 {
1884   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1885   return MtrrSetMemoryAttributeWorker (
1886            MtrrSetting,
1887            BaseAddress,
1888            Length,
1889            Attribute
1890            );
1891 }
1892 
1893 /**
1894   Worker function setting variable MTRRs
1895 
1896   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
1897 
1898 **/
1899 VOID
MtrrSetVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings)1900 MtrrSetVariableMtrrWorker (
1901   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1902   )
1903 {
1904   UINT32  Index;
1905   UINT32  VariableMtrrCount;
1906 
1907   VariableMtrrCount = GetVariableMtrrCountWorker ();
1908   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1909 
1910   for (Index = 0; Index < VariableMtrrCount; Index++) {
1911     MtrrRegisterWrite (
1912       QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),
1913       VariableSettings->Mtrr[Index].Base
1914       );
1915     MtrrRegisterWrite (
1916       QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,
1917       VariableSettings->Mtrr[Index].Mask
1918       );
1919   }
1920 }
1921 
1922 
1923 /**
1924   This function sets variable MTRRs
1925 
1926   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
1927 
1928   @return The pointer of VariableSettings
1929 
1930 **/
1931 MTRR_VARIABLE_SETTINGS*
1932 EFIAPI
MtrrSetVariableMtrr(IN MTRR_VARIABLE_SETTINGS * VariableSettings)1933 MtrrSetVariableMtrr (
1934   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1935   )
1936 {
1937   MTRR_CONTEXT  MtrrContext;
1938 
1939   if (!IsMtrrSupported ()) {
1940     return VariableSettings;
1941   }
1942 
1943   PreMtrrChange (&MtrrContext);
1944   MtrrSetVariableMtrrWorker (VariableSettings);
1945   PostMtrrChange (&MtrrContext);
1946   MtrrDebugPrintAllMtrrs ();
1947 
1948   return  VariableSettings;
1949 }
1950 
1951 /**
1952   Worker function setting fixed MTRRs
1953 
1954   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
1955 
1956 **/
1957 VOID
MtrrSetFixedMtrrWorker(IN MTRR_FIXED_SETTINGS * FixedSettings)1958 MtrrSetFixedMtrrWorker (
1959   IN MTRR_FIXED_SETTINGS          *FixedSettings
1960   )
1961 {
1962   UINT32  Index;
1963 
1964   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1965      MtrrRegisterWrite (
1966        mMtrrLibFixedMtrrTable[Index].Msr,
1967        FixedSettings->Mtrr[Index]
1968        );
1969   }
1970 }
1971 
1972 
1973 /**
1974   This function sets fixed MTRRs
1975 
1976   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
1977 
1978   @retval The pointer of FixedSettings
1979 
1980 **/
1981 MTRR_FIXED_SETTINGS*
1982 EFIAPI
MtrrSetFixedMtrr(IN MTRR_FIXED_SETTINGS * FixedSettings)1983 MtrrSetFixedMtrr (
1984   IN MTRR_FIXED_SETTINGS          *FixedSettings
1985   )
1986 {
1987   MTRR_CONTEXT  MtrrContext;
1988 
1989   if (!IsMtrrSupported ()) {
1990     return FixedSettings;
1991   }
1992 
1993   PreMtrrChange (&MtrrContext);
1994   MtrrSetFixedMtrrWorker (FixedSettings);
1995   PostMtrrChange (&MtrrContext);
1996   MtrrDebugPrintAllMtrrs ();
1997 
1998   return FixedSettings;
1999 }
2000 
2001 
2002 /**
2003   This function gets the content in all MTRRs (variable and fixed)
2004 
2005   @param[out]  MtrrSetting  A buffer to hold all MTRRs content.
2006 
2007   @retval the pointer of MtrrSetting
2008 
2009 **/
2010 MTRR_SETTINGS *
2011 EFIAPI
MtrrGetAllMtrrs(OUT MTRR_SETTINGS * MtrrSetting)2012 MtrrGetAllMtrrs (
2013   OUT MTRR_SETTINGS                *MtrrSetting
2014   )
2015 {
2016   if (!IsMtrrSupported ()) {
2017     return MtrrSetting;
2018   }
2019 
2020   //
2021   // Get fixed MTRRs
2022   //
2023   MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2024 
2025   //
2026   // Get variable MTRRs
2027   //
2028   MtrrGetVariableMtrrWorker (
2029     NULL,
2030     GetVariableMtrrCountWorker (),
2031     &MtrrSetting->Variables
2032     );
2033 
2034   //
2035   // Get MTRR_DEF_TYPE value
2036   //
2037   MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);
2038 
2039   return MtrrSetting;
2040 }
2041 
2042 
2043 /**
2044   This function sets all MTRRs (variable and fixed)
2045 
2046   @param[in]  MtrrSetting  A buffer holding all MTRRs content.
2047 
2048   @retval The pointer of MtrrSetting
2049 
2050 **/
2051 MTRR_SETTINGS *
2052 EFIAPI
MtrrSetAllMtrrs(IN MTRR_SETTINGS * MtrrSetting)2053 MtrrSetAllMtrrs (
2054   IN MTRR_SETTINGS                *MtrrSetting
2055   )
2056 {
2057   MTRR_CONTEXT  MtrrContext;
2058 
2059   if (!IsMtrrSupported ()) {
2060     return MtrrSetting;
2061   }
2062 
2063   PreMtrrChange (&MtrrContext);
2064 
2065   //
2066   // Set fixed MTRRs
2067   //
2068   MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2069 
2070   //
2071   // Set variable MTRRs
2072   //
2073   MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2074 
2075   //
2076   // Set MTRR_DEF_TYPE value
2077   //
2078   MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2079 
2080   PostMtrrChangeEnableCache (&MtrrContext);
2081 
2082   MtrrDebugPrintAllMtrrs ();
2083 
2084   return MtrrSetting;
2085 }
2086 
2087 
2088 /**
2089   Checks if MTRR is supported.
2090 
2091   @retval TRUE  MTRR is supported.
2092   @retval FALSE MTRR is not supported.
2093 
2094 **/
2095 BOOLEAN
2096 EFIAPI
IsMtrrSupported(VOID)2097 IsMtrrSupported (
2098   VOID
2099   )
2100 {
2101   UINT32  RegEax;
2102 
2103   //
2104   // Check CPUID(1).EAX[0..11] for Quark SoC
2105   //
2106   AsmCpuid (1, &RegEax, NULL, NULL, NULL);
2107   if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {
2108     return TRUE;
2109   }
2110 
2111   return FALSE;
2112 }
2113