]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
Update DXE Core to be compatible with PI 1.2 SMM Drivers.
[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
147 Value = AsmReadCr0 ();\r
148 Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 1);\r
149 Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
150 AsmWriteCr0 (Value);\r
151 //\r
152 // Flush cache\r
153 //\r
154 AsmWbinvd ();\r
155 //\r
156 // Clear PGE flag Bit 7\r
157 //\r
158 Value = AsmReadCr4 ();\r
159 AsmWriteCr4 ((UINTN) BitFieldWrite64 (Value, 7, 7, 0));\r
160 //\r
161 // Flush all TLBs\r
162 //\r
163 CpuFlushTlb ();\r
164 //\r
165 // Disable Mtrrs\r
166 //\r
167 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
168\r
169 return Value;\r
170}\r
171\r
172\r
173/**\r
174 Cleaning up after programming MTRRs.\r
175\r
176 This function will do some clean up after programming MTRRs:\r
177 enable MTRR caching functionality, and enable cache\r
178\r
179 @param Cr4 CR4 value to restore\r
180\r
181**/\r
182VOID\r
183PostMtrrChange (\r
184 UINTN Cr4\r
185 )\r
186{\r
187 UINTN Value;\r
188\r
189 //\r
190 // Enable Cache MTRR\r
191 //\r
192 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
193\r
194 //\r
195 // Flush all TLBs and cache the second time\r
196 //\r
197 AsmWbinvd ();\r
198 CpuFlushTlb ();\r
199\r
200 //\r
201 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
202 //\r
203 Value = AsmReadCr0 ();\r
204 Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 0);\r
205 Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
206 AsmWriteCr0 (Value);\r
207\r
208 AsmWriteCr4 (Cr4);\r
209\r
210 return ;\r
211}\r
212\r
213\r
214/**\r
215 Programs fixed MTRRs registers.\r
216\r
217 @param MemoryCacheType The memory type to set.\r
218 @param Base The base address of memory range.\r
219 @param Length The length of memory range.\r
220\r
221 @retval RETURN_SUCCESS The cache type was updated successfully\r
222 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
223 for the fixed MTRRs.\r
224\r
225**/\r
226RETURN_STATUS\r
227ProgramFixedMtrr (\r
228 IN UINT64 MemoryCacheType,\r
229 IN OUT UINT64 *Base,\r
230 IN OUT UINT64 *Length\r
231 )\r
232{\r
233 UINT32 MsrNum;\r
234 UINT32 ByteShift;\r
235 UINT64 TempQword;\r
236 UINT64 OrMask;\r
237 UINT64 ClearMask;\r
238\r
239 TempQword = 0;\r
240 OrMask = 0;\r
241 ClearMask = 0;\r
242\r
243 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
244 if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
245 (*Base <\r
246 (\r
247 MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
248 (8 * MtrrLibFixedMtrrTable[MsrNum].Length)\r
249 )\r
250 )\r
251 ) {\r
252 break;\r
253 }\r
254 }\r
255\r
256 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
257 return RETURN_UNSUPPORTED;\r
258 }\r
259\r
260 //\r
261 // We found the fixed MTRR to be programmed\r
262 //\r
263 for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
264 if (*Base ==\r
265 (\r
266 MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
267 (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)\r
268 )\r
269 ) {\r
270 break;\r
271 }\r
272 }\r
273\r
274 if (ByteShift == 8) {\r
275 return RETURN_UNSUPPORTED;\r
276 }\r
277\r
278 for (\r
279 ;\r
280 ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));\r
281 ByteShift++\r
282 ) {\r
283 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
284 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
285 *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;\r
286 *Base += MtrrLibFixedMtrrTable[MsrNum].Length;\r
287 }\r
288\r
289 if (ByteShift < 8 && (*Length != 0)) {\r
290 return RETURN_UNSUPPORTED;\r
291 }\r
292\r
293 TempQword =\r
294 (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
295 AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
296 return RETURN_SUCCESS;\r
297}\r
298\r
299\r
300/**\r
301 Get the attribute of variable MTRRs.\r
302\r
3ba736f3
JY
303 This function shadows the content of variable MTRRs into an\r
304 internal array: VariableMtrr.\r
e50466da 305\r
3ba736f3
JY
306 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
307 @param MtrrValidAddressMask The valid address mask for MTRR\r
308 @param VariableMtrr The array to shadow variable MTRRs content\r
e50466da 309\r
3ba736f3
JY
310 @return The return value of this paramter indicates the\r
311 number of MTRRs which has been used.\r
e50466da 312\r
313**/\r
3ba736f3 314UINT32\r
e50466da 315EFIAPI\r
316MtrrGetMemoryAttributeInVariableMtrr (\r
317 IN UINT64 MtrrValidBitsMask,\r
318 IN UINT64 MtrrValidAddressMask,\r
319 OUT VARIABLE_MTRR *VariableMtrr\r
320 )\r
321{\r
322 UINTN Index;\r
323 UINT32 MsrNum;\r
324 UINT32 UsedMtrr;\r
3ba736f3 325 UINT32 FirmwareVariableMtrrCount;\r
3b9be416
JY
326 UINT32 VariableMtrrEnd;\r
327\r
3b9be416 328 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
3b9be416 329 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 330\r
3ba736f3 331 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
e50466da 332 UsedMtrr = 0;\r
333\r
334 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
335 (\r
3b9be416
JY
336 (MsrNum < VariableMtrrEnd) &&\r
337 (Index < FirmwareVariableMtrrCount)\r
e50466da 338 );\r
339 MsrNum += 2\r
340 ) {\r
341 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
342 VariableMtrr[Index].Msr = MsrNum;\r
343 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &\r
344 MtrrValidAddressMask);\r
345 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &\r
346 MtrrValidAddressMask)\r
347 ) &\r
348 MtrrValidBitsMask\r
349 ) + 1;\r
350 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
351 VariableMtrr[Index].Valid = TRUE;\r
352 VariableMtrr[Index].Used = TRUE;\r
353 UsedMtrr = UsedMtrr + 1;\r
354 Index++;\r
355 }\r
356 }\r
3ba736f3 357 return UsedMtrr;\r
e50466da 358}\r
359\r
360\r
361/**\r
362 Checks overlap between given memory range and MTRRs.\r
363\r
364 @param Start The start address of memory range.\r
365 @param End The end address of memory range.\r
366 @param VariableMtrr The array to shadow variable MTRRs content\r
367\r
368 @retval TRUE Overlap exists.\r
369 @retval FALSE No overlap.\r
370\r
371**/\r
372BOOLEAN\r
373CheckMemoryAttributeOverlap (\r
374 IN PHYSICAL_ADDRESS Start,\r
375 IN PHYSICAL_ADDRESS End,\r
376 IN VARIABLE_MTRR *VariableMtrr\r
377 )\r
378{\r
379 UINT32 Index;\r
380\r
381 for (Index = 0; Index < 6; Index++) {\r
382 if (\r
383 VariableMtrr[Index].Valid &&\r
384 !(\r
385 (Start > (VariableMtrr[Index].BaseAddress +\r
386 VariableMtrr[Index].Length - 1)\r
387 ) ||\r
388 (End < VariableMtrr[Index].BaseAddress)\r
389 )\r
390 ) {\r
391 return TRUE;\r
392 }\r
393 }\r
394\r
395 return FALSE;\r
396}\r
397\r
398\r
399/**\r
400 Marks a variable MTRR as non-valid.\r
401\r
402 @param Index The index of the array VariableMtrr to be invalidated\r
403 @param VariableMtrr The array to shadow variable MTRRs content\r
404 @param UsedMtrr The number of MTRRs which has already been used\r
405\r
406**/\r
407VOID\r
408InvalidateShadowMtrr (\r
409 IN UINTN Index,\r
410 IN VARIABLE_MTRR *VariableMtrr,\r
411 OUT UINT32 *UsedMtrr\r
412 )\r
413{\r
414 VariableMtrr[Index].Valid = FALSE;\r
415 *UsedMtrr = *UsedMtrr - 1;\r
416}\r
417\r
418\r
419/**\r
420 Combine memory attributes.\r
421\r
422 If overlap exists between given memory range and MTRRs, try to combine them.\r
423\r
424 @param Attributes The memory type to set.\r
425 @param Base The base address of memory range.\r
426 @param Length The length of memory range.\r
427 @param VariableMtrr The array to shadow variable MTRRs content\r
428 @param UsedMtrr The number of MTRRs which has already been used\r
429 @param OverwriteExistingMtrr Returns whether an existing MTRR was used\r
430\r
431 @retval EFI_SUCCESS Memory region successfully combined.\r
432 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
433\r
434**/\r
435RETURN_STATUS\r
436CombineMemoryAttribute (\r
437 IN UINT64 Attributes,\r
438 IN OUT UINT64 *Base,\r
439 IN OUT UINT64 *Length,\r
440 IN VARIABLE_MTRR *VariableMtrr,\r
441 IN OUT UINT32 *UsedMtrr,\r
442 OUT BOOLEAN *OverwriteExistingMtrr\r
443 )\r
444{\r
445 UINT32 Index;\r
446 UINT64 CombineStart;\r
447 UINT64 CombineEnd;\r
448 UINT64 MtrrEnd;\r
449 UINT64 EndAddress;\r
3b9be416
JY
450 UINT32 FirmwareVariableMtrrCount;\r
451\r
452 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
e50466da 453\r
454 *OverwriteExistingMtrr = FALSE;\r
455 EndAddress = *Base +*Length - 1;\r
456\r
3b9be416 457 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 458\r
459 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
460 if (\r
461 !VariableMtrr[Index].Valid ||\r
462 (\r
463 *Base > (MtrrEnd) ||\r
464 (EndAddress < VariableMtrr[Index].BaseAddress)\r
465 )\r
466 ) {\r
467 continue;\r
468 }\r
469\r
470 //\r
471 // Combine same attribute MTRR range\r
472 //\r
473 if (Attributes == VariableMtrr[Index].Type) {\r
474 //\r
475 // if the Mtrr range contain the request range, return RETURN_SUCCESS\r
476 //\r
477 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
478 *Length = 0;\r
479 return RETURN_SUCCESS;\r
480 }\r
481 //\r
482 // invalid this MTRR, and program the combine range\r
483 //\r
484 CombineStart =\r
485 (*Base) < VariableMtrr[Index].BaseAddress ?\r
486 (*Base) :\r
487 VariableMtrr[Index].BaseAddress;\r
488 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
489\r
490 //\r
491 // Record the MTRR usage status in VariableMtrr array.\r
492 //\r
493 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
494 *Base = CombineStart;\r
495 *Length = CombineEnd - CombineStart + 1;\r
496 EndAddress = CombineEnd;\r
497 *OverwriteExistingMtrr = TRUE;\r
498 continue;\r
499 } else {\r
500 //\r
501 // The cache type is different, but the range is convered by one MTRR\r
502 //\r
503 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
504 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
505 continue;\r
506 }\r
507\r
508 }\r
509\r
510 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
511 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
512 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
513 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
514 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
515 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
516 ) {\r
517 *OverwriteExistingMtrr = TRUE;\r
518 continue;\r
519 }\r
520 //\r
521 // Other type memory overlap is invalid\r
522 //\r
523 return RETURN_ACCESS_DENIED;\r
524 }\r
525\r
526 return RETURN_SUCCESS;\r
527}\r
528\r
529\r
530/**\r
531 Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
532\r
533 @param MemoryLength The number to pass in.\r
534 @return The maximum value which is align to power of 2 and less the MemoryLength\r
535\r
536**/\r
537UINT64\r
538Power2MaxMemory (\r
539 IN UINT64 MemoryLength\r
540 )\r
541{\r
542 UINT64 Result;\r
543\r
544 if (RShiftU64 (MemoryLength, 32)) {\r
545 Result = LShiftU64 (\r
546 (UINT64) GetPowerOfTwo32 (\r
547 (UINT32) RShiftU64 (MemoryLength, 32)\r
548 ),\r
549 32\r
550 );\r
551 } else {\r
552 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
553 }\r
554\r
555 return Result;\r
556}\r
557\r
558\r
559/**\r
560 Check the direction to program variable MTRRs.\r
561\r
562 This function determines which direction of programming the variable\r
563 MTRRs will use fewer MTRRs.\r
564\r
565 @param Input Length of Memory to program MTRR\r
566 @param MtrrNumber Pointer to the number of necessary MTRRs\r
567\r
568 @retval TRUE Positive direction is better.\r
569 FALSE Negtive direction is better.\r
570\r
571**/\r
572BOOLEAN\r
573GetDirection (\r
574 IN UINT64 Input,\r
575 IN UINTN *MtrrNumber\r
576 )\r
577{\r
578 UINT64 TempQword;\r
579 UINT32 Positive;\r
580 UINT32 Subtractive;\r
581\r
582 TempQword = Input;\r
583 Positive = 0;\r
584 Subtractive = 0;\r
585\r
586 do {\r
587 TempQword -= Power2MaxMemory (TempQword);\r
588 Positive++;\r
589 } while (TempQword != 0);\r
590\r
591 TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\r
592 Subtractive++;\r
593 do {\r
594 TempQword -= Power2MaxMemory (TempQword);\r
595 Subtractive++;\r
596 } while (TempQword != 0);\r
597\r
598 if (Positive <= Subtractive) {\r
599 *MtrrNumber = Positive;\r
600 return TRUE;\r
601 } else {\r
602 *MtrrNumber = Subtractive;\r
603 return FALSE;\r
604 }\r
605}\r
606\r
607/**\r
608 Invalid variable MTRRs according to the value in the shadow array.\r
609\r
610 This function programs MTRRs according to the values specified\r
611 in the shadow array.\r
612\r
613 @param VariableMtrr The array to shadow variable MTRRs content\r
614\r
615**/\r
616STATIC\r
617VOID\r
618InvalidateMtrr (\r
619 IN VARIABLE_MTRR *VariableMtrr\r
620 )\r
621{\r
622 UINTN Index;\r
623 UINTN Cr4;\r
3b9be416 624 UINTN VariableMtrrCount;\r
e50466da 625\r
626 Cr4 = PreMtrrChange ();\r
627 Index = 0;\r
3b9be416
JY
628 VariableMtrrCount = GetVariableMtrrCount ();\r
629 while (Index < VariableMtrrCount) {\r
e50466da 630 if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
631 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
632 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
633 VariableMtrr[Index].Used = FALSE;\r
634 }\r
635 Index ++;\r
636 }\r
637 PostMtrrChange (Cr4);\r
638}\r
639\r
640\r
641/**\r
642 Programs variable MTRRs\r
643\r
644 This function programs variable MTRRs\r
645\r
646 @param MtrrNumber Index of MTRR to program.\r
647 @param BaseAddress Base address of memory region.\r
648 @param Length Length of memory region.\r
649 @param MemoryCacheType Memory type to set.\r
650 @param MtrrValidAddressMask The valid address mask for MTRR\r
651\r
652**/\r
653STATIC\r
654VOID\r
655ProgramVariableMtrr (\r
656 IN UINTN MtrrNumber,\r
657 IN PHYSICAL_ADDRESS BaseAddress,\r
658 IN UINT64 Length,\r
659 IN UINT64 MemoryCacheType,\r
660 IN UINT64 MtrrValidAddressMask\r
661 )\r
662{\r
663 UINT64 TempQword;\r
664 UINTN Cr4;\r
665\r
666 Cr4 = PreMtrrChange ();\r
667\r
668 //\r
669 // MTRR Physical Base\r
670 //\r
671 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
672 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
673\r
674 //\r
675 // MTRR Physical Mask\r
676 //\r
677 TempQword = ~(Length - 1);\r
678 AsmWriteMsr64 (\r
679 (UINT32) (MtrrNumber + 1),\r
680 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
681 );\r
682\r
683 PostMtrrChange (Cr4);\r
684}\r
685\r
686\r
687/**\r
688 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
689\r
690 @param MtrrType MTRR memory type\r
691\r
692 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
693\r
694**/\r
695STATIC\r
696MTRR_MEMORY_CACHE_TYPE\r
697GetMemoryCacheTypeFromMtrrType (\r
698 IN UINT64 MtrrType\r
699 )\r
700{\r
701 switch (MtrrType) {\r
702 case MTRR_CACHE_UNCACHEABLE:\r
703 return CacheUncacheable;\r
704 case MTRR_CACHE_WRITE_COMBINING:\r
705 return CacheWriteCombining;\r
706 case MTRR_CACHE_WRITE_THROUGH:\r
707 return CacheWriteThrough;\r
708 case MTRR_CACHE_WRITE_PROTECTED:\r
709 return CacheWriteProtected;\r
710 case MTRR_CACHE_WRITE_BACK:\r
711 return CacheWriteBack;\r
712 default:\r
713 //\r
714 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
715 // no mtrr covers the range\r
716 //\r
717 return CacheUncacheable;\r
718 }\r
719}\r
720\r
721/**\r
722 Initializes the valid bits mask and valid address mask for MTRRs.\r
723\r
724 This function initializes the valid bits mask and valid address mask for MTRRs.\r
725\r
726 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
727 @param MtrrValidAddressMask The valid address mask for the MTRR\r
728\r
729**/\r
730STATIC\r
731VOID\r
732MtrrLibInitializeMtrrMask (\r
733 OUT UINT64 *MtrrValidBitsMask,\r
734 OUT UINT64 *MtrrValidAddressMask\r
735 )\r
736{\r
737 UINT32 RegEax;\r
738 UINT8 PhysicalAddressBits;\r
739\r
740 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
741\r
742 if (RegEax >= 0x80000008) {\r
743 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
744\r
745 PhysicalAddressBits = (UINT8) RegEax;\r
746\r
747 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
748 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
749 } else {\r
750 *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
751 *MtrrValidAddressMask = 0xFFFFFFFF;\r
752 }\r
753}\r
754\r
755\r
756/**\r
757 Determing the real attribute of a memory range.\r
758\r
759 This function is to arbitrate the real attribute of the memory when\r
760 there are 2 MTRR covers the same memory range. For further details,\r
761 please refer the IA32 Software Developer's Manual, Volume 3,\r
762 Section 10.11.4.1.\r
763\r
764 @param MtrrType1 the first kind of Memory type\r
765 @param MtrrType2 the second kind of memory type\r
766\r
767**/\r
768UINT64\r
769MtrrPrecedence (\r
770 UINT64 MtrrType1,\r
771 UINT64 MtrrType2\r
772 )\r
773{\r
774 UINT64 MtrrType;\r
775\r
776 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
777 switch (MtrrType1) {\r
778 case MTRR_CACHE_UNCACHEABLE:\r
779 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
780 break;\r
781 case MTRR_CACHE_WRITE_COMBINING:\r
782 if (\r
783 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
784 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
785 ) {\r
786 MtrrType = MtrrType2;\r
787 }\r
788 break;\r
789 case MTRR_CACHE_WRITE_THROUGH:\r
790 if (\r
791 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
792 MtrrType2==MTRR_CACHE_WRITE_BACK\r
793 ) {\r
794 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
795 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
796 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
797 }\r
798 break;\r
799 case MTRR_CACHE_WRITE_PROTECTED:\r
800 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
801 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
802 MtrrType = MtrrType2;\r
803 }\r
804 break;\r
805 case MTRR_CACHE_WRITE_BACK:\r
806 if (\r
807 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
808 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
809 MtrrType2== MTRR_CACHE_WRITE_BACK\r
810 ) {\r
811 MtrrType = MtrrType2;\r
812 }\r
813 break;\r
814 case MTRR_CACHE_INVALID_TYPE:\r
815 MtrrType = MtrrType2;\r
816 break;\r
817 default:\r
818 break;\r
819 }\r
820\r
821 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
822 MtrrType = MtrrType1;\r
823 }\r
824 return MtrrType;\r
825}\r
826\r
827\r
828/**\r
829 This function attempts to set the attributes for a memory range.\r
830\r
831 @param BaseAddress The physical address that is the start\r
832 address of a memory region.\r
833 @param Length The size in bytes of the memory region.\r
834 @param Attributes The bit mask of attributes to set for the\r
835 memory region.\r
836\r
837 @retval RETURN_SUCCESS The attributes were set for the memory\r
838 region.\r
839 @retval RETURN_INVALID_PARAMETER Length is zero.\r
840 @retval RETURN_UNSUPPORTED The processor does not support one or\r
841 more bytes of the memory resource range\r
842 specified by BaseAddress and Length.\r
843 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
844 for the memory resource range specified\r
845 by BaseAddress and Length.\r
846 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
847 range specified by BaseAddress and Length\r
848 cannot be modified.\r
849 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
850 modify the attributes of the memory\r
851 resource range.\r
852\r
853**/\r
854RETURN_STATUS\r
855EFIAPI\r
856MtrrSetMemoryAttribute (\r
857 IN PHYSICAL_ADDRESS BaseAddress,\r
858 IN UINT64 Length,\r
859 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
860 )\r
861{\r
862 UINT64 TempQword;\r
863 RETURN_STATUS Status;\r
864 UINT64 MemoryType;\r
865 UINT64 Remainder;\r
866 BOOLEAN OverLap;\r
867 BOOLEAN Positive;\r
868 UINT32 MsrNum;\r
869 UINTN MtrrNumber;\r
3ba736f3 870 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 871 UINT32 UsedMtrr;\r
872 UINT64 MtrrValidBitsMask;\r
873 UINT64 MtrrValidAddressMask;\r
874 UINTN Cr4;\r
875 BOOLEAN OverwriteExistingMtrr;\r
3b9be416
JY
876 UINT32 FirmwareVariableMtrrCount;\r
877 UINT32 VariableMtrrEnd;\r
878\r
879 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
880 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 881\r
882 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
883\r
884 TempQword = 0;\r
885 MemoryType = (UINT64)Attribute;\r
886 OverwriteExistingMtrr = FALSE;\r
887\r
888 //\r
889 // Check for an invalid parameter\r
890 //\r
891 if (Length == 0) {\r
892 return RETURN_INVALID_PARAMETER;\r
893 }\r
894\r
895 if (\r
896 (BaseAddress &~MtrrValidAddressMask) != 0 ||\r
897 (Length &~MtrrValidAddressMask) != 0\r
898 ) {\r
899 return RETURN_UNSUPPORTED;\r
900 }\r
901\r
902 //\r
903 // Check if Fixed MTRR\r
904 //\r
905 Status = RETURN_SUCCESS;\r
906 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
907 Cr4 = PreMtrrChange ();\r
908 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
909 PostMtrrChange (Cr4);\r
910 if (RETURN_ERROR (Status)) {\r
911 return Status;\r
912 }\r
913 }\r
914\r
915 if (Length == 0) {\r
916 //\r
917 // A Length of 0 can only make sense for fixed MTTR ranges.\r
918 // Since we just handled the fixed MTRRs, we can skip the\r
919 // variable MTRR section.\r
920 //\r
921 goto Done;\r
922 }\r
923\r
924 //\r
925 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
926 // we can set the bade to 0 to save variable MTRRs.\r
927 //\r
928 if (BaseAddress == BASE_1MB) {\r
929 BaseAddress = 0;\r
930 Length += SIZE_1MB;\r
931 }\r
932\r
933 //\r
934 // Check memory base address alignment\r
935 //\r
936 DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);\r
937 if (Remainder != 0) {\r
938 DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);\r
939 if (Remainder != 0) {\r
940 Status = RETURN_UNSUPPORTED;\r
941 goto Done;\r
942 }\r
943 }\r
944\r
945 //\r
946 // Check for overlap\r
947 //\r
3ba736f3 948 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
e50466da 949 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
950 if (OverLap) {\r
951 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
952 if (RETURN_ERROR (Status)) {\r
953 goto Done;\r
954 }\r
955\r
956 if (Length == 0) {\r
957 //\r
958 // Combined successfully\r
959 //\r
960 Status = RETURN_SUCCESS;\r
961 goto Done;\r
962 }\r
963 }\r
964\r
965 //\r
966 // Program Variable MTRRs\r
967 //\r
968 // Avoid hardcode here and read data dynamically\r
969 //\r
3b9be416 970 if (UsedMtrr >= FirmwareVariableMtrrCount) {\r
e50466da 971 Status = RETURN_OUT_OF_RESOURCES;\r
972 goto Done;\r
973 }\r
974\r
975 //\r
976 // The memory type is the same with the type specified by\r
977 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
978 //\r
979 if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {\r
980 //\r
981 // Invalidate the now-unused MTRRs\r
982 //\r
983 InvalidateMtrr(VariableMtrr);\r
984 goto Done;\r
985 }\r
986\r
987 TempQword = Length;\r
988\r
989\r
990 if (TempQword == Power2MaxMemory (TempQword)) {\r
991 //\r
992 // Invalidate the now-unused MTRRs\r
993 //\r
994 InvalidateMtrr(VariableMtrr);\r
995\r
996 //\r
997 // Find first unused MTRR\r
998 //\r
999 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
3b9be416 1000 MsrNum < VariableMtrrEnd;\r
e50466da 1001 MsrNum += 2\r
1002 ) {\r
1003 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1004 break;\r
1005 }\r
1006 }\r
1007\r
1008 ProgramVariableMtrr (\r
1009 MsrNum,\r
1010 BaseAddress,\r
1011 Length,\r
1012 MemoryType,\r
1013 MtrrValidAddressMask\r
1014 );\r
1015 } else {\r
1016\r
1017 Positive = GetDirection (TempQword, &MtrrNumber);\r
1018\r
3b9be416 1019 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
e50466da 1020 Status = RETURN_OUT_OF_RESOURCES;\r
1021 goto Done;\r
1022 }\r
1023\r
1024 //\r
1025 // Invalidate the now-unused MTRRs\r
1026 //\r
1027 InvalidateMtrr(VariableMtrr);\r
1028\r
1029 //\r
1030 // Find first unused MTRR\r
1031 //\r
1032 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
3b9be416 1033 MsrNum < VariableMtrrEnd;\r
e50466da 1034 MsrNum += 2\r
1035 ) {\r
1036 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1037 break;\r
1038 }\r
1039 }\r
1040\r
1041 if (!Positive) {\r
1042 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
1043 ProgramVariableMtrr (\r
1044 MsrNum,\r
1045 BaseAddress,\r
1046 Length,\r
1047 MemoryType,\r
1048 MtrrValidAddressMask\r
1049 );\r
1050 BaseAddress += Length;\r
1051 TempQword = Length - TempQword;\r
1052 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1053 }\r
1054\r
1055 do {\r
1056 //\r
1057 // Find unused MTRR\r
1058 //\r
3b9be416 1059 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1060 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1061 break;\r
1062 }\r
1063 }\r
1064\r
1065 Length = Power2MaxMemory (TempQword);\r
1066 if (!Positive) {\r
1067 BaseAddress -= Length;\r
1068 }\r
1069\r
1070 ProgramVariableMtrr (\r
1071 MsrNum,\r
1072 BaseAddress,\r
1073 Length,\r
1074 MemoryType,\r
1075 MtrrValidAddressMask\r
1076 );\r
1077\r
1078 if (Positive) {\r
1079 BaseAddress += Length;\r
1080 }\r
1081 TempQword -= Length;\r
1082\r
1083 } while (TempQword > 0);\r
1084 }\r
1085\r
1086Done:\r
1087 return Status;\r
1088\r
1089}\r
1090\r
1091\r
1092/**\r
1093 This function will get the memory cache type of the specific address.\r
1094\r
1095 This function is mainly for debug purpose.\r
1096\r
1097 @param Address The specific address\r
1098\r
1099 @return Memory cache type of the sepcific address\r
1100\r
1101**/\r
1102MTRR_MEMORY_CACHE_TYPE\r
1103EFIAPI\r
1104MtrrGetMemoryAttribute (\r
1105 IN PHYSICAL_ADDRESS Address\r
1106 )\r
1107{\r
1108 UINT64 TempQword;\r
1109 UINTN Index;\r
1110 UINTN SubIndex;\r
1111 UINT64 MtrrType;\r
1112 UINT64 TempMtrrType;\r
1113 MTRR_MEMORY_CACHE_TYPE CacheType;\r
3ba736f3 1114 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 1115 UINT64 MtrrValidBitsMask;\r
1116 UINT64 MtrrValidAddressMask;\r
3b9be416 1117 UINTN VariableMtrrCount;\r
e50466da 1118\r
1119 //\r
1120 // Check if MTRR is enabled, if not, return UC as attribute\r
1121 //\r
1122 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1123 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1124\r
1125 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1126 return CacheUncacheable;\r
1127 }\r
1128\r
1129 //\r
1130 // If address is less than 1M, then try to go through the fixed MTRR\r
1131 //\r
1132 if (Address < BASE_1MB) {\r
1133 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1134 //\r
1135 // Go through the fixed MTRR\r
1136 //\r
1137 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1138 if (Address >= MtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1139 Address < (\r
1140 MtrrLibFixedMtrrTable[Index].BaseAddress +\r
1141 (MtrrLibFixedMtrrTable[Index].Length * 8)\r
1142 )\r
1143 ) {\r
1144 SubIndex =\r
1145 ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1146 MtrrLibFixedMtrrTable[Index].Length;\r
1147 TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
1148 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1149 return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1150 }\r
1151 }\r
1152 }\r
1153 }\r
1154 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1155 MtrrGetMemoryAttributeInVariableMtrr(\r
1156 MtrrValidBitsMask,\r
1157 MtrrValidAddressMask,\r
1158 VariableMtrr\r
1159 );\r
1160\r
1161 //\r
1162 // Go through the variable MTRR\r
1163 //\r
3b9be416
JY
1164 VariableMtrrCount = GetVariableMtrrCount ();\r
1165 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1166 if (VariableMtrr[Index].Valid) {\r
1167 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1168 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1169 TempMtrrType = VariableMtrr[Index].Type;\r
1170 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1171 }\r
1172 }\r
1173 }\r
1174 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1175\r
1176 return CacheType;\r
1177}\r
1178\r
1179\r
1180/**\r
1181 This function will get the raw value in variable MTRRs\r
1182\r
1183 @param VariableSettings A buffer to hold variable MTRRs content.\r
1184\r
1185 @return The VariableSettings input pointer\r
1186\r
1187**/\r
1188MTRR_VARIABLE_SETTINGS*\r
1189EFIAPI\r
1190MtrrGetVariableMtrr (\r
1191 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
1192 )\r
1193{\r
1194 UINT32 Index;\r
3b9be416 1195 UINT32 VariableMtrrCount;\r
e50466da 1196\r
3b9be416
JY
1197 VariableMtrrCount = GetVariableMtrrCount ();\r
1198 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1199 VariableSettings->Mtrr[Index].Base =\r
1200 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
1201 VariableSettings->Mtrr[Index].Mask =\r
1202 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
1203 }\r
1204\r
1205 return VariableSettings;\r
1206}\r
1207\r
1208\r
1209/**\r
1210 Worker function setting variable MTRRs\r
1211\r
1212 @param VariableSettings A buffer to hold variable MTRRs content.\r
1213\r
1214**/\r
1215VOID\r
1216MtrrSetVariableMtrrWorker (\r
1217 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1218 )\r
1219{\r
1220 UINT32 Index;\r
3b9be416 1221 UINT32 VariableMtrrCount;\r
e50466da 1222\r
3b9be416
JY
1223 VariableMtrrCount = GetVariableMtrrCount ();\r
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