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