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