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