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