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