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