Add array index check to avoid potential buffer overflow.
[efi/edk2/.git] / edk2 / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
1 /** @file\r
2   MTRR setting library\r
3 \r
4   Copyright (c) 2008 - 2010, Intel Corporation\r
5   All rights reserved. This program and the accompanying materials\r
6   are licensed and made available under the terms and conditions of the BSD License\r
7   which accompanies this distribution.  The full text of the license may be found at\r
8   http://opensource.org/licenses/bsd-license.php\r
9 \r
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include <Base.h>\r
16 \r
17 #include <Library/MtrrLib.h>\r
18 #include <Library/BaseLib.h>\r
19 #include <Library/CpuLib.h>\r
20 #include <Library/BaseMemoryLib.h>\r
21 #include <Library/DebugLib.h>\r
22 \r
23 //\r
24 // This table defines the offset, base and length of the fixed MTRRs\r
25 //\r
26 STATIC\r
27 FIXED_MTRR    MtrrLibFixedMtrrTable[] = {\r
28   {\r
29     MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
30     0,\r
31     SIZE_64KB\r
32   },\r
33   {\r
34     MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
35     0x80000,\r
36     SIZE_16KB\r
37   },\r
38   {\r
39     MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
40     0xA0000,\r
41     SIZE_16KB\r
42   },\r
43   {\r
44     MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
45     0xC0000,\r
46     SIZE_4KB\r
47   },\r
48   {\r
49     MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
50     0xC8000,\r
51     SIZE_4KB\r
52   },\r
53   {\r
54     MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
55     0xD0000,\r
56     SIZE_4KB\r
57   },\r
58   {\r
59     MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
60     0xD8000,\r
61     SIZE_4KB\r
62   },\r
63   {\r
64     MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
65     0xE0000,\r
66     SIZE_4KB\r
67   },\r
68   {\r
69     MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
70     0xE8000,\r
71     SIZE_4KB\r
72   },\r
73   {\r
74     MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
75     0xF0000,\r
76     SIZE_4KB\r
77   },\r
78   {\r
79     MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
80     0xF8000,\r
81     SIZE_4KB\r
82   },\r
83 };\r
84 \r
85 /**\r
86   Returns the variable MTRR count for the CPU.\r
87 \r
88   @return Variable MTRR count\r
89 \r
90 **/\r
91 UINT32\r
92 GetVariableMtrrCount (\r
93   VOID\r
94   )\r
95 {\r
96   return (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
97 }\r
98 \r
99 /**\r
100   Returns the firmware usable variable MTRR count for the CPU.\r
101 \r
102   @return Firmware usable variable MTRR count\r
103 \r
104 **/\r
105 UINT32\r
106 GetFirmwareVariableMtrrCount (\r
107   VOID\r
108   )\r
109 {\r
110   return GetVariableMtrrCount () - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;\r
111 }\r
112 \r
113 /**\r
114   Returns the default MTRR cache type for the system.\r
115 \r
116   @return  MTRR default type\r
117 \r
118 **/\r
119 UINT64\r
120 GetMtrrDefaultMemoryType (\r
121   VOID\r
122 )\r
123 {\r
124   return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);\r
125 }\r
126 \r
127 \r
128 /**\r
129   Preparation before programming MTRR.\r
130 \r
131   This function will do some preparation for programming MTRRs:\r
132   disable cache, invalid cache and disable MTRR caching functionality\r
133 \r
134   @return  CR4 value before changing.\r
135 \r
136 **/\r
137 UINTN\r
138 PreMtrrChange (\r
139   VOID\r
140   )\r
141 {\r
142   UINTN  Value;\r
143 \r
144   //\r
145   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
146   //\r
147   AsmDisableCache ();\r
148 \r
149   //\r
150   // Save original CR4 value and clear PGE flag (Bit 7)\r
151   //\r
152   Value = AsmReadCr4 ();\r
153   AsmWriteCr4 (Value & (~BIT7));\r
154 \r
155   //\r
156   // Flush all TLBs\r
157   //\r
158   CpuFlushTlb ();\r
159 \r
160   //\r
161   // Disable Mtrrs\r
162   //\r
163   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
164 \r
165   //\r
166   // Return original CR4 value\r
167   //\r
168   return Value;\r
169 }\r
170 \r
171 \r
172 /**\r
173   Cleaning up after programming MTRRs.\r
174 \r
175   This function will do some clean up after programming MTRRs:\r
176   enable MTRR caching functionality, and enable cache\r
177 \r
178   @param  Cr4  CR4 value to restore\r
179 \r
180 **/\r
181 VOID\r
182 PostMtrrChange (\r
183   UINTN Cr4\r
184   )\r
185 {\r
186   //\r
187   // Enable Cache MTRR\r
188   //\r
189   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
190 \r
191   //\r
192   // Flush all TLBs \r
193   //\r
194   CpuFlushTlb ();\r
195 \r
196   //\r
197   // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
198   //\r
199   AsmEnableCache ();\r
200 \r
201   //\r
202   // Restore original CR4 value\r
203   //\r
204   AsmWriteCr4 (Cr4);\r
205 }\r
206 \r
207 \r
208 /**\r
209   Programs fixed MTRRs registers.\r
210 \r
211   @param  MemoryCacheType  The memory type to set.\r
212   @param  Base             The base address of memory range.\r
213   @param  Length           The length of memory range.\r
214 \r
215   @retval RETURN_SUCCESS      The cache type was updated successfully\r
216   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
217                               for the fixed MTRRs.\r
218 \r
219 **/\r
220 RETURN_STATUS\r
221 ProgramFixedMtrr (\r
222   IN     UINT64     MemoryCacheType,\r
223   IN OUT UINT64     *Base,\r
224   IN OUT UINT64     *Length\r
225   )\r
226 {\r
227   UINT32  MsrNum;\r
228   UINT32  ByteShift;\r
229   UINT64  TempQword;\r
230   UINT64  OrMask;\r
231   UINT64  ClearMask;\r
232 \r
233   TempQword = 0;\r
234   OrMask    = 0;\r
235   ClearMask = 0;\r
236 \r
237   for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
238     if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
239         (*Base <\r
240             (\r
241               MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
242               (8 * MtrrLibFixedMtrrTable[MsrNum].Length)\r
243             )\r
244           )\r
245         ) {\r
246       break;\r
247     }\r
248   }\r
249 \r
250   if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
251     return RETURN_UNSUPPORTED;\r
252   }\r
253 \r
254   //\r
255   // We found the fixed MTRR to be programmed\r
256   //\r
257   for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
258     if (*Base ==\r
259          (\r
260            MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
261            (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)\r
262          )\r
263        ) {\r
264       break;\r
265     }\r
266   }\r
267 \r
268   if (ByteShift == 8) {\r
269     return RETURN_UNSUPPORTED;\r
270   }\r
271 \r
272   for (\r
273         ;\r
274         ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));\r
275         ByteShift++\r
276       ) {\r
277     OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
278     ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
279     *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;\r
280     *Base += MtrrLibFixedMtrrTable[MsrNum].Length;\r
281   }\r
282 \r
283   if (ByteShift < 8 && (*Length != 0)) {\r
284     return RETURN_UNSUPPORTED;\r
285   }\r
286 \r
287   TempQword =\r
288     (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
289   AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
290   return RETURN_SUCCESS;\r
291 }\r
292 \r
293 \r
294 /**\r
295   Get the attribute of variable MTRRs.\r
296 \r
297   This function shadows the content of variable MTRRs into an\r
298   internal array: VariableMtrr.\r
299 \r
300   @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
301   @param  MtrrValidAddressMask  The valid address mask for MTRR\r
302   @param  VariableMtrr          The array to shadow variable MTRRs content\r
303 \r
304   @return                       The return value of this paramter indicates the\r
305                                 number of MTRRs which has been used.\r
306 \r
307 **/\r
308 UINT32\r
309 EFIAPI\r
310 MtrrGetMemoryAttributeInVariableMtrr (\r
311   IN  UINT64                    MtrrValidBitsMask,\r
312   IN  UINT64                    MtrrValidAddressMask,\r
313   OUT VARIABLE_MTRR             *VariableMtrr\r
314   )\r
315 {\r
316   UINTN   Index;\r
317   UINT32  MsrNum;\r
318   UINT32  UsedMtrr;\r
319   UINT32  FirmwareVariableMtrrCount;\r
320   UINT32  VariableMtrrEnd;\r
321 \r
322   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
323   VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
324 \r
325   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
326   UsedMtrr = 0;\r
327 \r
328   for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
329        (\r
330          (MsrNum < VariableMtrrEnd) &&\r
331          (Index < FirmwareVariableMtrrCount)\r
332        );\r
333        MsrNum += 2\r
334       ) {\r
335     if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
336       VariableMtrr[Index].Msr          = MsrNum;\r
337       VariableMtrr[Index].BaseAddress  = (AsmReadMsr64 (MsrNum) &\r
338                                           MtrrValidAddressMask);\r
339       VariableMtrr[Index].Length       = ((~(AsmReadMsr64 (MsrNum + 1) &\r
340                                              MtrrValidAddressMask)\r
341                                           ) &\r
342                                           MtrrValidBitsMask\r
343                                          ) + 1;\r
344       VariableMtrr[Index].Type         = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
345       VariableMtrr[Index].Valid        = TRUE;\r
346       VariableMtrr[Index].Used         = TRUE;\r
347       UsedMtrr = UsedMtrr  + 1;\r
348       Index++;\r
349     }\r
350   }\r
351   return UsedMtrr;\r
352 }\r
353 \r
354 \r
355 /**\r
356   Checks overlap between given memory range and MTRRs.\r
357 \r
358   @param  Start            The start address of memory range.\r
359   @param  End              The end address of memory range.\r
360   @param  VariableMtrr     The array to shadow variable MTRRs content\r
361 \r
362   @retval TRUE             Overlap exists.\r
363   @retval FALSE            No overlap.\r
364 \r
365 **/\r
366 BOOLEAN\r
367 CheckMemoryAttributeOverlap (\r
368   IN PHYSICAL_ADDRESS     Start,\r
369   IN PHYSICAL_ADDRESS     End,\r
370   IN VARIABLE_MTRR      *VariableMtrr\r
371   )\r
372 {\r
373   UINT32  Index;\r
374 \r
375   for (Index = 0; Index < 6; Index++) {\r
376     if (\r
377          VariableMtrr[Index].Valid &&\r
378          !(\r
379            (Start > (VariableMtrr[Index].BaseAddress +\r
380                      VariableMtrr[Index].Length - 1)\r
381            ) ||\r
382            (End < VariableMtrr[Index].BaseAddress)\r
383          )\r
384        ) {\r
385       return TRUE;\r
386     }\r
387   }\r
388 \r
389   return FALSE;\r
390 }\r
391 \r
392 \r
393 /**\r
394   Marks a variable MTRR as non-valid.\r
395 \r
396   @param  Index         The index of the array VariableMtrr to be invalidated\r
397   @param  VariableMtrr  The array to shadow variable MTRRs content\r
398   @param  UsedMtrr      The number of MTRRs which has already been used\r
399 \r
400 **/\r
401 VOID\r
402 InvalidateShadowMtrr (\r
403   IN   UINTN              Index,\r
404   IN   VARIABLE_MTRR      *VariableMtrr,\r
405   OUT  UINT32             *UsedMtrr\r
406   )\r
407 {\r
408   VariableMtrr[Index].Valid = FALSE;\r
409   *UsedMtrr = *UsedMtrr - 1;\r
410 }\r
411 \r
412 \r
413 /**\r
414   Combine memory attributes.\r
415 \r
416   If overlap exists between given memory range and MTRRs, try to combine them.\r
417 \r
418   @param  Attributes             The memory type to set.\r
419   @param  Base                   The base address of memory range.\r
420   @param  Length                 The length of memory range.\r
421   @param  VariableMtrr           The array to shadow variable MTRRs content\r
422   @param  UsedMtrr               The number of MTRRs which has already been used\r
423   @param  OverwriteExistingMtrr  Returns whether an existing MTRR was used\r
424 \r
425   @retval EFI_SUCCESS            Memory region successfully combined.\r
426   @retval EFI_ACCESS_DENIED      Memory region cannot be combined.\r
427 \r
428 **/\r
429 RETURN_STATUS\r
430 CombineMemoryAttribute (\r
431   IN     UINT64             Attributes,\r
432   IN OUT UINT64             *Base,\r
433   IN OUT UINT64             *Length,\r
434   IN     VARIABLE_MTRR      *VariableMtrr,\r
435   IN OUT UINT32             *UsedMtrr,\r
436   OUT    BOOLEAN            *OverwriteExistingMtrr\r
437   )\r
438 {\r
439   UINT32  Index;\r
440   UINT64  CombineStart;\r
441   UINT64  CombineEnd;\r
442   UINT64  MtrrEnd;\r
443   UINT64  EndAddress;\r
444   UINT32  FirmwareVariableMtrrCount;\r
445 \r
446   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
447 \r
448   *OverwriteExistingMtrr = FALSE;\r
449   EndAddress = *Base +*Length - 1;\r
450 \r
451   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
452 \r
453     MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
454     if (\r
455          !VariableMtrr[Index].Valid ||\r
456          (\r
457            *Base > (MtrrEnd) ||\r
458            (EndAddress < VariableMtrr[Index].BaseAddress)\r
459          )\r
460        ) {\r
461       continue;\r
462     }\r
463 \r
464     //\r
465     // Combine same attribute MTRR range\r
466     //\r
467     if (Attributes == VariableMtrr[Index].Type) {\r
468       //\r
469       // if the Mtrr range contain the request range, return RETURN_SUCCESS\r
470       //\r
471       if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
472         *Length = 0;\r
473         return RETURN_SUCCESS;\r
474       }\r
475       //\r
476       // invalid this MTRR, and program the combine range\r
477       //\r
478       CombineStart  =\r
479         (*Base) < VariableMtrr[Index].BaseAddress ?\r
480           (*Base) :\r
481           VariableMtrr[Index].BaseAddress;\r
482       CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
483 \r
484       //\r
485       // Record the MTRR usage status in VariableMtrr array.\r
486       //\r
487       InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
488       *Base       = CombineStart;\r
489       *Length     = CombineEnd - CombineStart + 1;\r
490       EndAddress  = CombineEnd;\r
491       *OverwriteExistingMtrr = TRUE;\r
492       continue;\r
493     } else {\r
494       //\r
495       // The cache type is different, but the range is convered by one MTRR\r
496       //\r
497       if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
498         InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
499         continue;\r
500       }\r
501 \r
502     }\r
503 \r
504     if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
505          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
506         (Attributes == MTRR_CACHE_WRITE_BACK &&\r
507          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
508         (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
509         (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
510      ) {\r
511       *OverwriteExistingMtrr = TRUE;\r
512       continue;\r
513     }\r
514     //\r
515     // Other type memory overlap is invalid\r
516     //\r
517     return RETURN_ACCESS_DENIED;\r
518   }\r
519 \r
520   return RETURN_SUCCESS;\r
521 }\r
522 \r
523 \r
524 /**\r
525   Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
526 \r
527   @param  MemoryLength        The number to pass in.\r
528   @return The maximum value which is align to power of 2 and less the MemoryLength\r
529 \r
530 **/\r
531 UINT64\r
532 Power2MaxMemory (\r
533   IN UINT64                     MemoryLength\r
534   )\r
535 {\r
536   UINT64  Result;\r
537 \r
538   if (RShiftU64 (MemoryLength, 32)) {\r
539     Result = LShiftU64 (\r
540                (UINT64) GetPowerOfTwo32 (\r
541                           (UINT32) RShiftU64 (MemoryLength, 32)\r
542                           ),\r
543                32\r
544                );\r
545   } else {\r
546     Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
547   }\r
548 \r
549   return Result;\r
550 }\r
551 \r
552 \r
553 /**\r
554   Check the direction to program variable MTRRs.\r
555 \r
556   This function determines which direction of programming the variable\r
557   MTRRs will use fewer MTRRs.\r
558 \r
559   @param  Input       Length of Memory to program MTRR\r
560   @param  MtrrNumber  Pointer to the number of necessary MTRRs\r
561 \r
562   @retval TRUE        Positive direction is better.\r
563           FALSE       Negtive direction is better.\r
564 \r
565 **/\r
566 BOOLEAN\r
567 GetDirection (\r
568   IN UINT64      Input,\r
569   IN UINTN       *MtrrNumber\r
570   )\r
571 {\r
572   UINT64  TempQword;\r
573   UINT32  Positive;\r
574   UINT32  Subtractive;\r
575 \r
576   TempQword   = Input;\r
577   Positive    = 0;\r
578   Subtractive = 0;\r
579 \r
580   do {\r
581     TempQword -= Power2MaxMemory (TempQword);\r
582     Positive++;\r
583   } while (TempQword != 0);\r
584 \r
585   TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\r
586   Subtractive++;\r
587   do {\r
588     TempQword -= Power2MaxMemory (TempQword);\r
589     Subtractive++;\r
590   } while (TempQword != 0);\r
591 \r
592   if (Positive <= Subtractive) {\r
593     *MtrrNumber = Positive;\r
594     return TRUE;\r
595   } else {\r
596     *MtrrNumber = Subtractive;\r
597     return FALSE;\r
598   }\r
599 }\r
600 \r
601 /**\r
602   Invalid variable MTRRs according to the value in the shadow array.\r
603 \r
604   This function programs MTRRs according to the values specified\r
605   in the shadow array.\r
606 \r
607   @param  VariableMtrr   The array to shadow variable MTRRs content\r
608 \r
609 **/\r
610 STATIC\r
611 VOID\r
612 InvalidateMtrr (\r
613    IN     VARIABLE_MTRR      *VariableMtrr\r
614    )\r
615 {\r
616   UINTN Index;\r
617   UINTN Cr4;\r
618   UINTN VariableMtrrCount;\r
619 \r
620   Cr4 = PreMtrrChange ();\r
621   Index = 0;\r
622   VariableMtrrCount = GetVariableMtrrCount ();\r
623   while (Index < VariableMtrrCount) {\r
624     if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
625        AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
626        AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
627        VariableMtrr[Index].Used = FALSE;\r
628     }\r
629     Index ++;\r
630   }\r
631   PostMtrrChange (Cr4);\r
632 }\r
633 \r
634 \r
635 /**\r
636   Programs variable MTRRs\r
637 \r
638   This function programs variable MTRRs\r
639 \r
640   @param  MtrrNumber            Index of MTRR to program.\r
641   @param  BaseAddress           Base address of memory region.\r
642   @param  Length                Length of memory region.\r
643   @param  MemoryCacheType       Memory type to set.\r
644   @param  MtrrValidAddressMask  The valid address mask for MTRR\r
645 \r
646 **/\r
647 STATIC\r
648 VOID\r
649 ProgramVariableMtrr (\r
650   IN UINTN                    MtrrNumber,\r
651   IN PHYSICAL_ADDRESS         BaseAddress,\r
652   IN UINT64                   Length,\r
653   IN UINT64                   MemoryCacheType,\r
654   IN UINT64                   MtrrValidAddressMask\r
655   )\r
656 {\r
657   UINT64  TempQword;\r
658   UINTN   Cr4;\r
659 \r
660   Cr4 = PreMtrrChange ();\r
661 \r
662   //\r
663   // MTRR Physical Base\r
664   //\r
665   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
666   AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
667 \r
668   //\r
669   // MTRR Physical Mask\r
670   //\r
671   TempQword = ~(Length - 1);\r
672   AsmWriteMsr64 (\r
673     (UINT32) (MtrrNumber + 1),\r
674     (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
675     );\r
676 \r
677   PostMtrrChange (Cr4);\r
678 }\r
679 \r
680 \r
681 /**\r
682   Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
683 \r
684   @param  MtrrType  MTRR memory type\r
685 \r
686   @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
687 \r
688 **/\r
689 STATIC\r
690 MTRR_MEMORY_CACHE_TYPE\r
691 GetMemoryCacheTypeFromMtrrType (\r
692   IN UINT64                MtrrType\r
693   )\r
694 {\r
695   switch (MtrrType) {\r
696   case MTRR_CACHE_UNCACHEABLE:\r
697     return CacheUncacheable;\r
698   case MTRR_CACHE_WRITE_COMBINING:\r
699     return CacheWriteCombining;\r
700   case MTRR_CACHE_WRITE_THROUGH:\r
701     return CacheWriteThrough;\r
702   case MTRR_CACHE_WRITE_PROTECTED:\r
703     return CacheWriteProtected;\r
704   case MTRR_CACHE_WRITE_BACK:\r
705     return CacheWriteBack;\r
706   default:\r
707     //\r
708     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
709     // no mtrr covers the range\r
710     //\r
711     return CacheUncacheable;\r
712   }\r
713 }\r
714 \r
715 /**\r
716   Initializes the valid bits mask and valid address mask for MTRRs.\r
717 \r
718   This function initializes the valid bits mask and valid address mask for MTRRs.\r
719 \r
720   @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
721   @param  MtrrValidAddressMask  The valid address mask for the MTRR\r
722 \r
723 **/\r
724 STATIC\r
725 VOID\r
726 MtrrLibInitializeMtrrMask (\r
727   OUT UINT64 *MtrrValidBitsMask,\r
728   OUT UINT64 *MtrrValidAddressMask\r
729   )\r
730 {\r
731   UINT32                              RegEax;\r
732   UINT8                               PhysicalAddressBits;\r
733 \r
734   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
735 \r
736   if (RegEax >= 0x80000008) {\r
737     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
738 \r
739     PhysicalAddressBits = (UINT8) RegEax;\r
740 \r
741     *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;\r
742     *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
743   } else {\r
744     *MtrrValidBitsMask    = MTRR_LIB_CACHE_VALID_ADDRESS;\r
745     *MtrrValidAddressMask = 0xFFFFFFFF;\r
746   }\r
747 }\r
748 \r
749 \r
750 /**\r
751   Determing the real attribute of a memory range.\r
752 \r
753   This function is to arbitrate the real attribute of the memory when\r
754   there are 2 MTRR covers the same memory range.  For further details,\r
755   please refer the IA32 Software Developer's Manual, Volume 3,\r
756   Section 10.11.4.1.\r
757 \r
758   @param  MtrrType1    the first kind of Memory type\r
759   @param  MtrrType2    the second kind of memory type\r
760 \r
761 **/\r
762 UINT64\r
763 MtrrPrecedence (\r
764   UINT64    MtrrType1,\r
765   UINT64    MtrrType2\r
766   )\r
767 {\r
768   UINT64 MtrrType;\r
769 \r
770   MtrrType = MTRR_CACHE_INVALID_TYPE;\r
771   switch (MtrrType1) {\r
772   case MTRR_CACHE_UNCACHEABLE:\r
773     MtrrType = MTRR_CACHE_UNCACHEABLE;\r
774     break;\r
775   case MTRR_CACHE_WRITE_COMBINING:\r
776     if (\r
777          MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
778          MtrrType2==MTRR_CACHE_UNCACHEABLE\r
779        ) {\r
780       MtrrType = MtrrType2;\r
781     }\r
782     break;\r
783   case MTRR_CACHE_WRITE_THROUGH:\r
784     if (\r
785          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
786          MtrrType2==MTRR_CACHE_WRITE_BACK\r
787        ) {\r
788       MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
789     } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
790       MtrrType = MTRR_CACHE_UNCACHEABLE;\r
791     }\r
792     break;\r
793   case MTRR_CACHE_WRITE_PROTECTED:\r
794     if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
795         MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
796       MtrrType = MtrrType2;\r
797     }\r
798     break;\r
799   case MTRR_CACHE_WRITE_BACK:\r
800     if (\r
801          MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
802          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
803          MtrrType2== MTRR_CACHE_WRITE_BACK\r
804        ) {\r
805       MtrrType = MtrrType2;\r
806     }\r
807     break;\r
808   case MTRR_CACHE_INVALID_TYPE:\r
809     MtrrType = MtrrType2;\r
810     break;\r
811   default:\r
812     break;\r
813   }\r
814 \r
815   if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
816     MtrrType = MtrrType1;\r
817   }\r
818   return MtrrType;\r
819 }\r
820 \r
821 \r
822 /**\r
823   This function attempts to set the attributes for a memory range.\r
824 \r
825   @param  BaseAddress            The physical address that is the start\r
826                                  address of a memory region.\r
827   @param  Length                 The size in bytes of the memory region.\r
828   @param  Attributes             The bit mask of attributes to set for the\r
829                                  memory region.\r
830 \r
831   @retval RETURN_SUCCESS            The attributes were set for the memory\r
832                                     region.\r
833   @retval RETURN_INVALID_PARAMETER  Length is zero.\r
834   @retval RETURN_UNSUPPORTED        The processor does not support one or\r
835                                     more bytes of the memory resource range\r
836                                     specified by BaseAddress and Length.\r
837   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
838                                     for the memory resource range specified\r
839                                     by BaseAddress and Length.\r
840   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource\r
841                                     range specified by BaseAddress and Length\r
842                                     cannot be modified.\r
843   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
844                                     modify the attributes of the memory\r
845                                     resource range.\r
846 \r
847 **/\r
848 RETURN_STATUS\r
849 EFIAPI\r
850 MtrrSetMemoryAttribute (\r
851   IN PHYSICAL_ADDRESS        BaseAddress,\r
852   IN UINT64                  Length,\r
853   IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
854   )\r
855 {\r
856   UINT64                    TempQword;\r
857   RETURN_STATUS             Status;\r
858   UINT64                    MemoryType;\r
859   UINT64                    Remainder;\r
860   BOOLEAN                   OverLap;\r
861   BOOLEAN                   Positive;\r
862   UINT32                    MsrNum;\r
863   UINTN                     MtrrNumber;\r
864   VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
865   UINT32                    UsedMtrr;\r
866   UINT64                    MtrrValidBitsMask;\r
867   UINT64                    MtrrValidAddressMask;\r
868   UINTN                     Cr4;\r
869   BOOLEAN                   OverwriteExistingMtrr;\r
870   UINT32                    FirmwareVariableMtrrCount;\r
871   UINT32                    VariableMtrrEnd;\r
872 \r
873   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
874   VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
875 \r
876   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
877 \r
878   TempQword = 0;\r
879   MemoryType = (UINT64)Attribute;\r
880   OverwriteExistingMtrr = FALSE;\r
881 \r
882   //\r
883   // Check for an invalid parameter\r
884   //\r
885   if (Length == 0) {\r
886     return RETURN_INVALID_PARAMETER;\r
887   }\r
888 \r
889   if (\r
890        (BaseAddress &~MtrrValidAddressMask) != 0 ||\r
891        (Length &~MtrrValidAddressMask) != 0\r
892      ) {\r
893     return RETURN_UNSUPPORTED;\r
894   }\r
895 \r
896   //\r
897   // Check if Fixed MTRR\r
898   //\r
899   Status = RETURN_SUCCESS;\r
900   while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
901     Cr4 = PreMtrrChange ();\r
902     Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
903     PostMtrrChange (Cr4);\r
904     if (RETURN_ERROR (Status)) {\r
905       return Status;\r
906     }\r
907   }\r
908 \r
909   if (Length == 0) {\r
910     //\r
911     // A Length of 0 can only make sense for fixed MTTR ranges.\r
912     // Since we just handled the fixed MTRRs, we can skip the\r
913     // variable MTRR section.\r
914     //\r
915     goto Done;\r
916   }\r
917 \r
918   //\r
919   // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
920   // we can set the bade to 0 to save variable MTRRs.\r
921   //\r
922   if (BaseAddress == BASE_1MB) {\r
923     BaseAddress = 0;\r
924     Length += SIZE_1MB;\r
925   }\r
926 \r
927   //\r
928   // Check memory base address alignment\r
929   //\r
930   DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);\r
931   if (Remainder != 0) {\r
932     DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);\r
933     if (Remainder != 0) {\r
934       Status = RETURN_UNSUPPORTED;\r
935       goto Done;\r
936     }\r
937   }\r
938 \r
939   //\r
940   // Check for overlap\r
941   //\r
942   UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
943   OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
944   if (OverLap) {\r
945     Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
946     if (RETURN_ERROR (Status)) {\r
947       goto Done;\r
948     }\r
949 \r
950     if (Length == 0) {\r
951       //\r
952       // Combined successfully\r
953       //\r
954       Status = RETURN_SUCCESS;\r
955       goto Done;\r
956     }\r
957   }\r
958 \r
959   //\r
960   // Program Variable MTRRs\r
961   //\r
962   // Avoid hardcode here and read data dynamically\r
963   //\r
964   if (UsedMtrr >= FirmwareVariableMtrrCount) {\r
965     Status = RETURN_OUT_OF_RESOURCES;\r
966     goto Done;\r
967   }\r
968 \r
969   //\r
970   // The memory type is the same with the type specified by\r
971   // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
972   //\r
973   if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {\r
974     //\r
975     // Invalidate the now-unused MTRRs\r
976     //\r
977     InvalidateMtrr(VariableMtrr);\r
978     goto Done;\r
979   }\r
980 \r
981   TempQword = Length;\r
982 \r
983 \r
984   if (TempQword == Power2MaxMemory (TempQword)) {\r
985     //\r
986     // Invalidate the now-unused MTRRs\r
987     //\r
988     InvalidateMtrr(VariableMtrr);\r
989 \r
990     //\r
991     // Find first unused MTRR\r
992     //\r
993     for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
994          MsrNum < VariableMtrrEnd;\r
995          MsrNum += 2\r
996         ) {\r
997       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
998         break;\r
999       }\r
1000     }\r
1001 \r
1002     ProgramVariableMtrr (\r
1003       MsrNum,\r
1004       BaseAddress,\r
1005       Length,\r
1006       MemoryType,\r
1007       MtrrValidAddressMask\r
1008       );\r
1009   } else {\r
1010 \r
1011     Positive = GetDirection (TempQword, &MtrrNumber);\r
1012 \r
1013     if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1014       Status = RETURN_OUT_OF_RESOURCES;\r
1015       goto Done;\r
1016     }\r
1017 \r
1018     //\r
1019     // Invalidate the now-unused MTRRs\r
1020     //\r
1021     InvalidateMtrr(VariableMtrr);\r
1022 \r
1023     //\r
1024     // Find first unused MTRR\r
1025     //\r
1026     for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
1027          MsrNum < VariableMtrrEnd;\r
1028          MsrNum += 2\r
1029         ) {\r
1030       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1031         break;\r
1032       }\r
1033     }\r
1034 \r
1035     if (!Positive) {\r
1036       Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
1037       ProgramVariableMtrr (\r
1038         MsrNum,\r
1039         BaseAddress,\r
1040         Length,\r
1041         MemoryType,\r
1042         MtrrValidAddressMask\r
1043         );\r
1044       BaseAddress += Length;\r
1045       TempQword   = Length - TempQword;\r
1046       MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
1047     }\r
1048 \r
1049     do {\r
1050       //\r
1051       // Find unused MTRR\r
1052       //\r
1053       for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
1054         if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1055           break;\r
1056         }\r
1057       }\r
1058 \r
1059       Length = Power2MaxMemory (TempQword);\r
1060       if (!Positive) {\r
1061         BaseAddress -= Length;\r
1062       }\r
1063 \r
1064       ProgramVariableMtrr (\r
1065         MsrNum,\r
1066         BaseAddress,\r
1067         Length,\r
1068         MemoryType,\r
1069         MtrrValidAddressMask\r
1070         );\r
1071 \r
1072       if (Positive) {\r
1073         BaseAddress += Length;\r
1074       }\r
1075       TempQword -= Length;\r
1076 \r
1077     } while (TempQword > 0);\r
1078   }\r
1079 \r
1080 Done:\r
1081   return Status;\r
1082 \r
1083 }\r
1084 \r
1085 \r
1086 /**\r
1087   This function will get the memory cache type of the specific address.\r
1088 \r
1089   This function is mainly for debug purpose.\r
1090 \r
1091   @param  Address   The specific address\r
1092 \r
1093   @return Memory cache type of the sepcific address\r
1094 \r
1095 **/\r
1096 MTRR_MEMORY_CACHE_TYPE\r
1097 EFIAPI\r
1098 MtrrGetMemoryAttribute (\r
1099   IN PHYSICAL_ADDRESS   Address\r
1100   )\r
1101 {\r
1102   UINT64                  TempQword;\r
1103   UINTN                   Index;\r
1104   UINTN                   SubIndex;\r
1105   UINT64                  MtrrType;\r
1106   UINT64                  TempMtrrType;\r
1107   MTRR_MEMORY_CACHE_TYPE  CacheType;\r
1108   VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1109   UINT64                  MtrrValidBitsMask;\r
1110   UINT64                  MtrrValidAddressMask;\r
1111   UINTN                   VariableMtrrCount;\r
1112 \r
1113   //\r
1114   // Check if MTRR is enabled, if not, return UC as attribute\r
1115   //\r
1116   TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1117   MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1118 \r
1119   if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1120     return CacheUncacheable;\r
1121   }\r
1122 \r
1123   //\r
1124   // If address is less than 1M, then try to go through the fixed MTRR\r
1125   //\r
1126   if (Address < BASE_1MB) {\r
1127     if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1128       //\r
1129       // Go through the fixed MTRR\r
1130       //\r
1131       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1132          if (Address >= MtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1133              Address  < (\r
1134                           MtrrLibFixedMtrrTable[Index].BaseAddress +\r
1135                           (MtrrLibFixedMtrrTable[Index].Length * 8)\r
1136                         )\r
1137             ) {\r
1138            SubIndex =\r
1139              ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1140                MtrrLibFixedMtrrTable[Index].Length;\r
1141            TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
1142            MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1143            return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1144          }\r
1145       }\r
1146     }\r
1147   }\r
1148   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1149   MtrrGetMemoryAttributeInVariableMtrr(\r
1150     MtrrValidBitsMask,\r
1151     MtrrValidAddressMask,\r
1152     VariableMtrr\r
1153     );\r
1154 \r
1155   //\r
1156   // Go through the variable MTRR\r
1157   //\r
1158   VariableMtrrCount = GetVariableMtrrCount ();\r
1159   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1160 \r
1161   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1162     if (VariableMtrr[Index].Valid) {\r
1163       if (Address >= VariableMtrr[Index].BaseAddress &&\r
1164           Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1165         TempMtrrType = VariableMtrr[Index].Type;\r
1166         MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1167       }\r
1168     }\r
1169   }\r
1170   CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1171 \r
1172   return CacheType;\r
1173 }\r
1174 \r
1175 \r
1176 /**\r
1177   This function will get the raw value in variable MTRRs\r
1178 \r
1179   @param  VariableSettings   A buffer to hold variable MTRRs content.\r
1180 \r
1181   @return The VariableSettings input pointer\r
1182 \r
1183 **/\r
1184 MTRR_VARIABLE_SETTINGS*\r
1185 EFIAPI\r
1186 MtrrGetVariableMtrr (\r
1187   OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\r
1188   )\r
1189 {\r
1190   UINT32  Index;\r
1191   UINT32  VariableMtrrCount;\r
1192 \r
1193   VariableMtrrCount = GetVariableMtrrCount ();\r
1194   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1195 \r
1196   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1197     VariableSettings->Mtrr[Index].Base =\r
1198       AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
1199     VariableSettings->Mtrr[Index].Mask =\r
1200       AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
1201   }\r
1202 \r
1203   return  VariableSettings;\r
1204 }\r
1205 \r
1206 \r
1207 /**\r
1208   Worker function setting variable MTRRs\r
1209 \r
1210   @param  VariableSettings   A buffer to hold variable MTRRs content.\r
1211 \r
1212 **/\r
1213 VOID\r
1214 MtrrSetVariableMtrrWorker (\r
1215   IN MTRR_VARIABLE_SETTINGS         *VariableSettings\r
1216   )\r
1217 {\r
1218   UINT32  Index;\r
1219   UINT32  VariableMtrrCount;\r
1220 \r
1221   VariableMtrrCount = GetVariableMtrrCount ();\r
1222   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1223 \r
1224   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1225     AsmWriteMsr64 (\r
1226       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1227       VariableSettings->Mtrr[Index].Base\r
1228       );\r
1229     AsmWriteMsr64 (\r
1230       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1231       VariableSettings->Mtrr[Index].Mask\r
1232       );\r
1233   }\r
1234 }\r
1235 \r
1236 \r
1237 /**\r
1238   This function sets variable MTRRs\r
1239 \r
1240   @param  VariableSettings   A buffer to hold variable MTRRs content.\r
1241 \r
1242   @return The pointer of VariableSettings\r
1243 \r
1244 **/\r
1245 MTRR_VARIABLE_SETTINGS*\r
1246 EFIAPI\r
1247 MtrrSetVariableMtrr (\r
1248   IN MTRR_VARIABLE_SETTINGS         *VariableSettings\r
1249   )\r
1250 {\r
1251   UINTN  Cr4;\r
1252 \r
1253   Cr4 = PreMtrrChange ();\r
1254   MtrrSetVariableMtrrWorker (VariableSettings);\r
1255   PostMtrrChange (Cr4);\r
1256   return  VariableSettings;\r
1257 }\r
1258 \r
1259 \r
1260 /**\r
1261   This function gets the content in fixed MTRRs\r
1262 \r
1263   @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
1264 \r
1265   @retval The pointer of FixedSettings\r
1266 \r
1267 **/\r
1268 MTRR_FIXED_SETTINGS*\r
1269 EFIAPI\r
1270 MtrrGetFixedMtrr (\r
1271   OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
1272   )\r
1273 {\r
1274   UINT32  Index;\r
1275 \r
1276   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1277       FixedSettings->Mtrr[Index] =\r
1278         AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
1279   };\r
1280 \r
1281   return FixedSettings;\r
1282 }\r
1283 \r
1284 /**\r
1285   Worker function setting fixed MTRRs\r
1286 \r
1287   @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
1288 \r
1289 **/\r
1290 VOID\r
1291 MtrrSetFixedMtrrWorker (\r
1292   IN MTRR_FIXED_SETTINGS          *FixedSettings\r
1293   )\r
1294 {\r
1295   UINT32  Index;\r
1296 \r
1297   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1298      AsmWriteMsr64 (\r
1299        MtrrLibFixedMtrrTable[Index].Msr,\r
1300        FixedSettings->Mtrr[Index]\r
1301        );\r
1302   }\r
1303 }\r
1304 \r
1305 \r
1306 /**\r
1307   This function sets fixed MTRRs\r
1308 \r
1309   @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
1310 \r
1311   @retval The pointer of FixedSettings\r
1312 \r
1313 **/\r
1314 MTRR_FIXED_SETTINGS*\r
1315 EFIAPI\r
1316 MtrrSetFixedMtrr (\r
1317   IN MTRR_FIXED_SETTINGS          *FixedSettings\r
1318   )\r
1319 {\r
1320   UINTN  Cr4;\r
1321 \r
1322   Cr4 = PreMtrrChange ();\r
1323   MtrrSetFixedMtrrWorker (FixedSettings);\r
1324   PostMtrrChange (Cr4);\r
1325 \r
1326   return FixedSettings;\r
1327 }\r
1328 \r
1329 \r
1330 /**\r
1331   This function gets the content in all MTRRs (variable and fixed)\r
1332 \r
1333   @param  MtrrSetting  A buffer to hold all Mtrrs content.\r
1334 \r
1335   @retval the pointer of MtrrSetting\r
1336 \r
1337 **/\r
1338 MTRR_SETTINGS *\r
1339 EFIAPI\r
1340 MtrrGetAllMtrrs (\r
1341   OUT MTRR_SETTINGS                *MtrrSetting\r
1342   )\r
1343 {\r
1344   //\r
1345   // Get fixed MTRRs\r
1346   //\r
1347   MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
1348 \r
1349   //\r
1350   // Get variable MTRRs\r
1351   //\r
1352   MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
1353 \r
1354   //\r
1355   // Get MTRR_DEF_TYPE value\r
1356   //\r
1357   MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1358 \r
1359   return MtrrSetting;\r
1360 }\r
1361 \r
1362 \r
1363 /**\r
1364   This function sets all MTRRs (variable and fixed)\r
1365 \r
1366   @param  MtrrSetting  A buffer holding all MTRRs content.\r
1367 \r
1368   @retval The pointer of MtrrSetting\r
1369 \r
1370 **/\r
1371 MTRR_SETTINGS *\r
1372 EFIAPI\r
1373 MtrrSetAllMtrrs (\r
1374   IN MTRR_SETTINGS                *MtrrSetting\r
1375   )\r
1376 {\r
1377   UINTN  Cr4;\r
1378 \r
1379   Cr4 = PreMtrrChange ();\r
1380 \r
1381   //\r
1382   // Set fixed MTRRs\r
1383   //\r
1384   MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
1385 \r
1386   //\r
1387   // Set variable MTRRs\r
1388   //\r
1389   MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
1390 \r
1391   //\r
1392   // Set MTRR_DEF_TYPE value\r
1393   //\r
1394   AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
1395 \r
1396   PostMtrrChange (Cr4);\r
1397 \r
1398   return MtrrSetting;\r
1399 }\r
1400 \r
1401 \r
1402 /**\r
1403   This function prints all MTRRs for debugging.\r
1404 **/\r
1405 VOID\r
1406 MtrrDebugPrintAllMtrrs (\r
1407   )\r
1408 {\r
1409   DEBUG_CODE (\r
1410     {\r
1411       MTRR_SETTINGS  MtrrSettings;\r
1412       UINTN          Index;\r
1413       UINTN          VariableMtrrCount;\r
1414 \r
1415       MtrrGetAllMtrrs (&MtrrSettings);\r
1416       DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));\r
1417       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1418         DEBUG((\r
1419           EFI_D_ERROR, "Fixed[%02d] = %016lx\n",\r
1420           Index,\r
1421           MtrrSettings.Fixed.Mtrr[Index]\r
1422           ));\r
1423       }\r
1424 \r
1425       VariableMtrrCount = GetVariableMtrrCount ();\r
1426       for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1427         DEBUG((\r
1428           EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",\r
1429           Index,\r
1430           MtrrSettings.Variables.Mtrr[Index].Base,\r
1431           MtrrSettings.Variables.Mtrr[Index].Mask\r
1432           ));\r
1433       }\r
1434     }\r
1435   );\r
1436 }\r
1437 \r