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