]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
Update so Windows build works like Cygwin buid
[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
3b9be416
JY
303 This function shadows the content of variable MTRRs into\r
304 an internal array: VariableMtrr\r
e50466da 305\r
3b9be416
JY
306 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
307 @param MtrrValidAddressMask The valid address mask for MTRR since the base address in\r
308 MTRR must align to 4K, so valid address mask equal to\r
309 MtrrValidBitsMask & 0xfffffffffffff000ULL\r
310 @param VariableMtrrCount On input, it means the array number of variable MTRRs passed in.\r
311 On output, it means the number of MTRRs which has been used if EFI_SUCCESS,\r
312 or the number of MTRR required if BUFFER_TOO_SMALL.\r
313 @param VariableMtrr The array to shadow variable MTRRs content\r
e50466da 314\r
3b9be416
JY
315 @retval RETURN_SUCCESS The variable MTRRs are returned.\r
316 @retval RETURN_BUFFER_TOO_SMALL The input buffer is too small to hold the variable MTRRs.\r
e50466da 317\r
318**/\r
3b9be416 319RETURN_STATUS\r
e50466da 320EFIAPI\r
321MtrrGetMemoryAttributeInVariableMtrr (\r
322 IN UINT64 MtrrValidBitsMask,\r
323 IN UINT64 MtrrValidAddressMask,\r
3b9be416 324 IN OUT UINT32 *VariableMtrrCount,\r
e50466da 325 OUT VARIABLE_MTRR *VariableMtrr\r
326 )\r
327{\r
328 UINTN Index;\r
329 UINT32 MsrNum;\r
330 UINT32 UsedMtrr;\r
3b9be416
JY
331 UINTN FirmwareVariableMtrrCount;\r
332 UINT32 VariableMtrrEnd;\r
333\r
334 //\r
335 // Check if input buffer is large enough\r
336 //\r
337 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
338 if (*VariableMtrrCount < FirmwareVariableMtrrCount) {\r
339 *VariableMtrrCount = (UINT32)FirmwareVariableMtrrCount;\r
340 return RETURN_BUFFER_TOO_SMALL;\r
341 }\r
342\r
343 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 344\r
3b9be416 345 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * (*VariableMtrrCount));\r
e50466da 346 UsedMtrr = 0;\r
347\r
348 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
349 (\r
3b9be416
JY
350 (MsrNum < VariableMtrrEnd) &&\r
351 (Index < FirmwareVariableMtrrCount)\r
e50466da 352 );\r
353 MsrNum += 2\r
354 ) {\r
355 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
356 VariableMtrr[Index].Msr = MsrNum;\r
357 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &\r
358 MtrrValidAddressMask);\r
359 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &\r
360 MtrrValidAddressMask)\r
361 ) &\r
362 MtrrValidBitsMask\r
363 ) + 1;\r
364 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
365 VariableMtrr[Index].Valid = TRUE;\r
366 VariableMtrr[Index].Used = TRUE;\r
367 UsedMtrr = UsedMtrr + 1;\r
368 Index++;\r
369 }\r
370 }\r
3b9be416
JY
371 *VariableMtrrCount = UsedMtrr;\r
372 return RETURN_SUCCESS;\r
e50466da 373}\r
374\r
375\r
376/**\r
377 Checks overlap between given memory range and MTRRs.\r
378\r
379 @param Start The start address of memory range.\r
380 @param End The end address of memory range.\r
381 @param VariableMtrr The array to shadow variable MTRRs content\r
382\r
383 @retval TRUE Overlap exists.\r
384 @retval FALSE No overlap.\r
385\r
386**/\r
387BOOLEAN\r
388CheckMemoryAttributeOverlap (\r
389 IN PHYSICAL_ADDRESS Start,\r
390 IN PHYSICAL_ADDRESS End,\r
391 IN VARIABLE_MTRR *VariableMtrr\r
392 )\r
393{\r
394 UINT32 Index;\r
395\r
396 for (Index = 0; Index < 6; Index++) {\r
397 if (\r
398 VariableMtrr[Index].Valid &&\r
399 !(\r
400 (Start > (VariableMtrr[Index].BaseAddress +\r
401 VariableMtrr[Index].Length - 1)\r
402 ) ||\r
403 (End < VariableMtrr[Index].BaseAddress)\r
404 )\r
405 ) {\r
406 return TRUE;\r
407 }\r
408 }\r
409\r
410 return FALSE;\r
411}\r
412\r
413\r
414/**\r
415 Marks a variable MTRR as non-valid.\r
416\r
417 @param Index The index of the array VariableMtrr to be invalidated\r
418 @param VariableMtrr The array to shadow variable MTRRs content\r
419 @param UsedMtrr The number of MTRRs which has already been used\r
420\r
421**/\r
422VOID\r
423InvalidateShadowMtrr (\r
424 IN UINTN Index,\r
425 IN VARIABLE_MTRR *VariableMtrr,\r
426 OUT UINT32 *UsedMtrr\r
427 )\r
428{\r
429 VariableMtrr[Index].Valid = FALSE;\r
430 *UsedMtrr = *UsedMtrr - 1;\r
431}\r
432\r
433\r
434/**\r
435 Combine memory attributes.\r
436\r
437 If overlap exists between given memory range and MTRRs, try to combine them.\r
438\r
439 @param Attributes The memory type to set.\r
440 @param Base The base address of memory range.\r
441 @param Length The length of memory range.\r
442 @param VariableMtrr The array to shadow variable MTRRs content\r
443 @param UsedMtrr The number of MTRRs which has already been used\r
444 @param OverwriteExistingMtrr Returns whether an existing MTRR was used\r
445\r
446 @retval EFI_SUCCESS Memory region successfully combined.\r
447 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
448\r
449**/\r
450RETURN_STATUS\r
451CombineMemoryAttribute (\r
452 IN UINT64 Attributes,\r
453 IN OUT UINT64 *Base,\r
454 IN OUT UINT64 *Length,\r
455 IN VARIABLE_MTRR *VariableMtrr,\r
456 IN OUT UINT32 *UsedMtrr,\r
457 OUT BOOLEAN *OverwriteExistingMtrr\r
458 )\r
459{\r
460 UINT32 Index;\r
461 UINT64 CombineStart;\r
462 UINT64 CombineEnd;\r
463 UINT64 MtrrEnd;\r
464 UINT64 EndAddress;\r
3b9be416
JY
465 UINT32 FirmwareVariableMtrrCount;\r
466\r
467 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
e50466da 468\r
469 *OverwriteExistingMtrr = FALSE;\r
470 EndAddress = *Base +*Length - 1;\r
471\r
3b9be416 472 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 473\r
474 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
475 if (\r
476 !VariableMtrr[Index].Valid ||\r
477 (\r
478 *Base > (MtrrEnd) ||\r
479 (EndAddress < VariableMtrr[Index].BaseAddress)\r
480 )\r
481 ) {\r
482 continue;\r
483 }\r
484\r
485 //\r
486 // Combine same attribute MTRR range\r
487 //\r
488 if (Attributes == VariableMtrr[Index].Type) {\r
489 //\r
490 // if the Mtrr range contain the request range, return RETURN_SUCCESS\r
491 //\r
492 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
493 *Length = 0;\r
494 return RETURN_SUCCESS;\r
495 }\r
496 //\r
497 // invalid this MTRR, and program the combine range\r
498 //\r
499 CombineStart =\r
500 (*Base) < VariableMtrr[Index].BaseAddress ?\r
501 (*Base) :\r
502 VariableMtrr[Index].BaseAddress;\r
503 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
504\r
505 //\r
506 // Record the MTRR usage status in VariableMtrr array.\r
507 //\r
508 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
509 *Base = CombineStart;\r
510 *Length = CombineEnd - CombineStart + 1;\r
511 EndAddress = CombineEnd;\r
512 *OverwriteExistingMtrr = TRUE;\r
513 continue;\r
514 } else {\r
515 //\r
516 // The cache type is different, but the range is convered by one MTRR\r
517 //\r
518 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
519 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
520 continue;\r
521 }\r
522\r
523 }\r
524\r
525 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
526 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
527 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
528 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
529 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
530 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
531 ) {\r
532 *OverwriteExistingMtrr = TRUE;\r
533 continue;\r
534 }\r
535 //\r
536 // Other type memory overlap is invalid\r
537 //\r
538 return RETURN_ACCESS_DENIED;\r
539 }\r
540\r
541 return RETURN_SUCCESS;\r
542}\r
543\r
544\r
545/**\r
546 Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
547\r
548 @param MemoryLength The number to pass in.\r
549 @return The maximum value which is align to power of 2 and less the MemoryLength\r
550\r
551**/\r
552UINT64\r
553Power2MaxMemory (\r
554 IN UINT64 MemoryLength\r
555 )\r
556{\r
557 UINT64 Result;\r
558\r
559 if (RShiftU64 (MemoryLength, 32)) {\r
560 Result = LShiftU64 (\r
561 (UINT64) GetPowerOfTwo32 (\r
562 (UINT32) RShiftU64 (MemoryLength, 32)\r
563 ),\r
564 32\r
565 );\r
566 } else {\r
567 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
568 }\r
569\r
570 return Result;\r
571}\r
572\r
573\r
574/**\r
575 Check the direction to program variable MTRRs.\r
576\r
577 This function determines which direction of programming the variable\r
578 MTRRs will use fewer MTRRs.\r
579\r
580 @param Input Length of Memory to program MTRR\r
581 @param MtrrNumber Pointer to the number of necessary MTRRs\r
582\r
583 @retval TRUE Positive direction is better.\r
584 FALSE Negtive direction is better.\r
585\r
586**/\r
587BOOLEAN\r
588GetDirection (\r
589 IN UINT64 Input,\r
590 IN UINTN *MtrrNumber\r
591 )\r
592{\r
593 UINT64 TempQword;\r
594 UINT32 Positive;\r
595 UINT32 Subtractive;\r
596\r
597 TempQword = Input;\r
598 Positive = 0;\r
599 Subtractive = 0;\r
600\r
601 do {\r
602 TempQword -= Power2MaxMemory (TempQword);\r
603 Positive++;\r
604 } while (TempQword != 0);\r
605\r
606 TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\r
607 Subtractive++;\r
608 do {\r
609 TempQword -= Power2MaxMemory (TempQword);\r
610 Subtractive++;\r
611 } while (TempQword != 0);\r
612\r
613 if (Positive <= Subtractive) {\r
614 *MtrrNumber = Positive;\r
615 return TRUE;\r
616 } else {\r
617 *MtrrNumber = Subtractive;\r
618 return FALSE;\r
619 }\r
620}\r
621\r
622/**\r
623 Invalid variable MTRRs according to the value in the shadow array.\r
624\r
625 This function programs MTRRs according to the values specified\r
626 in the shadow array.\r
627\r
628 @param VariableMtrr The array to shadow variable MTRRs content\r
629\r
630**/\r
631STATIC\r
632VOID\r
633InvalidateMtrr (\r
634 IN VARIABLE_MTRR *VariableMtrr\r
635 )\r
636{\r
637 UINTN Index;\r
638 UINTN Cr4;\r
3b9be416 639 UINTN VariableMtrrCount;\r
e50466da 640\r
641 Cr4 = PreMtrrChange ();\r
642 Index = 0;\r
3b9be416
JY
643 VariableMtrrCount = GetVariableMtrrCount ();\r
644 while (Index < VariableMtrrCount) {\r
e50466da 645 if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
646 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
647 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
648 VariableMtrr[Index].Used = FALSE;\r
649 }\r
650 Index ++;\r
651 }\r
652 PostMtrrChange (Cr4);\r
653}\r
654\r
655\r
656/**\r
657 Programs variable MTRRs\r
658\r
659 This function programs variable MTRRs\r
660\r
661 @param MtrrNumber Index of MTRR to program.\r
662 @param BaseAddress Base address of memory region.\r
663 @param Length Length of memory region.\r
664 @param MemoryCacheType Memory type to set.\r
665 @param MtrrValidAddressMask The valid address mask for MTRR\r
666\r
667**/\r
668STATIC\r
669VOID\r
670ProgramVariableMtrr (\r
671 IN UINTN MtrrNumber,\r
672 IN PHYSICAL_ADDRESS BaseAddress,\r
673 IN UINT64 Length,\r
674 IN UINT64 MemoryCacheType,\r
675 IN UINT64 MtrrValidAddressMask\r
676 )\r
677{\r
678 UINT64 TempQword;\r
679 UINTN Cr4;\r
680\r
681 Cr4 = PreMtrrChange ();\r
682\r
683 //\r
684 // MTRR Physical Base\r
685 //\r
686 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
687 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
688\r
689 //\r
690 // MTRR Physical Mask\r
691 //\r
692 TempQword = ~(Length - 1);\r
693 AsmWriteMsr64 (\r
694 (UINT32) (MtrrNumber + 1),\r
695 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
696 );\r
697\r
698 PostMtrrChange (Cr4);\r
699}\r
700\r
701\r
702/**\r
703 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
704\r
705 @param MtrrType MTRR memory type\r
706\r
707 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
708\r
709**/\r
710STATIC\r
711MTRR_MEMORY_CACHE_TYPE\r
712GetMemoryCacheTypeFromMtrrType (\r
713 IN UINT64 MtrrType\r
714 )\r
715{\r
716 switch (MtrrType) {\r
717 case MTRR_CACHE_UNCACHEABLE:\r
718 return CacheUncacheable;\r
719 case MTRR_CACHE_WRITE_COMBINING:\r
720 return CacheWriteCombining;\r
721 case MTRR_CACHE_WRITE_THROUGH:\r
722 return CacheWriteThrough;\r
723 case MTRR_CACHE_WRITE_PROTECTED:\r
724 return CacheWriteProtected;\r
725 case MTRR_CACHE_WRITE_BACK:\r
726 return CacheWriteBack;\r
727 default:\r
728 //\r
729 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
730 // no mtrr covers the range\r
731 //\r
732 return CacheUncacheable;\r
733 }\r
734}\r
735\r
736/**\r
737 Initializes the valid bits mask and valid address mask for MTRRs.\r
738\r
739 This function initializes the valid bits mask and valid address mask for MTRRs.\r
740\r
741 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
742 @param MtrrValidAddressMask The valid address mask for the MTRR\r
743\r
744**/\r
745STATIC\r
746VOID\r
747MtrrLibInitializeMtrrMask (\r
748 OUT UINT64 *MtrrValidBitsMask,\r
749 OUT UINT64 *MtrrValidAddressMask\r
750 )\r
751{\r
752 UINT32 RegEax;\r
753 UINT8 PhysicalAddressBits;\r
754\r
755 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
756\r
757 if (RegEax >= 0x80000008) {\r
758 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
759\r
760 PhysicalAddressBits = (UINT8) RegEax;\r
761\r
762 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
763 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
764 } else {\r
765 *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
766 *MtrrValidAddressMask = 0xFFFFFFFF;\r
767 }\r
768}\r
769\r
770\r
771/**\r
772 Determing the real attribute of a memory range.\r
773\r
774 This function is to arbitrate the real attribute of the memory when\r
775 there are 2 MTRR covers the same memory range. For further details,\r
776 please refer the IA32 Software Developer's Manual, Volume 3,\r
777 Section 10.11.4.1.\r
778\r
779 @param MtrrType1 the first kind of Memory type\r
780 @param MtrrType2 the second kind of memory type\r
781\r
782**/\r
783UINT64\r
784MtrrPrecedence (\r
785 UINT64 MtrrType1,\r
786 UINT64 MtrrType2\r
787 )\r
788{\r
789 UINT64 MtrrType;\r
790\r
791 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
792 switch (MtrrType1) {\r
793 case MTRR_CACHE_UNCACHEABLE:\r
794 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
795 break;\r
796 case MTRR_CACHE_WRITE_COMBINING:\r
797 if (\r
798 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
799 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
800 ) {\r
801 MtrrType = MtrrType2;\r
802 }\r
803 break;\r
804 case MTRR_CACHE_WRITE_THROUGH:\r
805 if (\r
806 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
807 MtrrType2==MTRR_CACHE_WRITE_BACK\r
808 ) {\r
809 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
810 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
811 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
812 }\r
813 break;\r
814 case MTRR_CACHE_WRITE_PROTECTED:\r
815 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
816 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
817 MtrrType = MtrrType2;\r
818 }\r
819 break;\r
820 case MTRR_CACHE_WRITE_BACK:\r
821 if (\r
822 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
823 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
824 MtrrType2== MTRR_CACHE_WRITE_BACK\r
825 ) {\r
826 MtrrType = MtrrType2;\r
827 }\r
828 break;\r
829 case MTRR_CACHE_INVALID_TYPE:\r
830 MtrrType = MtrrType2;\r
831 break;\r
832 default:\r
833 break;\r
834 }\r
835\r
836 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
837 MtrrType = MtrrType1;\r
838 }\r
839 return MtrrType;\r
840}\r
841\r
842\r
843/**\r
844 This function attempts to set the attributes for a memory range.\r
845\r
846 @param BaseAddress The physical address that is the start\r
847 address of a memory region.\r
848 @param Length The size in bytes of the memory region.\r
849 @param Attributes The bit mask of attributes to set for the\r
850 memory region.\r
851\r
852 @retval RETURN_SUCCESS The attributes were set for the memory\r
853 region.\r
854 @retval RETURN_INVALID_PARAMETER Length is zero.\r
855 @retval RETURN_UNSUPPORTED The processor does not support one or\r
856 more bytes of the memory resource range\r
857 specified by BaseAddress and Length.\r
858 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
859 for the memory resource range specified\r
860 by BaseAddress and Length.\r
861 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
862 range specified by BaseAddress and Length\r
863 cannot be modified.\r
864 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
865 modify the attributes of the memory\r
866 resource range.\r
867\r
868**/\r
869RETURN_STATUS\r
870EFIAPI\r
871MtrrSetMemoryAttribute (\r
872 IN PHYSICAL_ADDRESS BaseAddress,\r
873 IN UINT64 Length,\r
874 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
875 )\r
876{\r
877 UINT64 TempQword;\r
878 RETURN_STATUS Status;\r
879 UINT64 MemoryType;\r
880 UINT64 Remainder;\r
881 BOOLEAN OverLap;\r
882 BOOLEAN Positive;\r
883 UINT32 MsrNum;\r
884 UINTN MtrrNumber;\r
3b9be416 885 VARIABLE_MTRR VariableMtrr[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 886 UINT32 UsedMtrr;\r
887 UINT64 MtrrValidBitsMask;\r
888 UINT64 MtrrValidAddressMask;\r
889 UINTN Cr4;\r
890 BOOLEAN OverwriteExistingMtrr;\r
3b9be416
JY
891 UINT32 FirmwareVariableMtrrCount;\r
892 UINT32 VariableMtrrEnd;\r
893\r
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
3b9be416
JY
963 UsedMtrr = MAX_MTRR_NUMBER_OF_VARIABLE_MTRR;\r
964 MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, &UsedMtrr, VariableMtrr);\r
e50466da 965 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
966 if (OverLap) {\r
967 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
968 if (RETURN_ERROR (Status)) {\r
969 goto Done;\r
970 }\r
971\r
972 if (Length == 0) {\r
973 //\r
974 // Combined successfully\r
975 //\r
976 Status = RETURN_SUCCESS;\r
977 goto Done;\r
978 }\r
979 }\r
980\r
981 //\r
982 // Program Variable MTRRs\r
983 //\r
984 // Avoid hardcode here and read data dynamically\r
985 //\r
3b9be416 986 if (UsedMtrr >= FirmwareVariableMtrrCount) {\r
e50466da 987 Status = RETURN_OUT_OF_RESOURCES;\r
988 goto Done;\r
989 }\r
990\r
991 //\r
992 // The memory type is the same with the type specified by\r
993 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
994 //\r
995 if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {\r
996 //\r
997 // Invalidate the now-unused MTRRs\r
998 //\r
999 InvalidateMtrr(VariableMtrr);\r
1000 goto Done;\r
1001 }\r
1002\r
1003 TempQword = Length;\r
1004\r
1005\r
1006 if (TempQword == Power2MaxMemory (TempQword)) {\r
1007 //\r
1008 // Invalidate the now-unused MTRRs\r
1009 //\r
1010 InvalidateMtrr(VariableMtrr);\r
1011\r
1012 //\r
1013 // Find first unused MTRR\r
1014 //\r
1015 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
3b9be416 1016 MsrNum < VariableMtrrEnd;\r
e50466da 1017 MsrNum += 2\r
1018 ) {\r
1019 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1020 break;\r
1021 }\r
1022 }\r
1023\r
1024 ProgramVariableMtrr (\r
1025 MsrNum,\r
1026 BaseAddress,\r
1027 Length,\r
1028 MemoryType,\r
1029 MtrrValidAddressMask\r
1030 );\r
1031 } else {\r
1032\r
1033 Positive = GetDirection (TempQword, &MtrrNumber);\r
1034\r
3b9be416 1035 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
e50466da 1036 Status = RETURN_OUT_OF_RESOURCES;\r
1037 goto Done;\r
1038 }\r
1039\r
1040 //\r
1041 // Invalidate the now-unused MTRRs\r
1042 //\r
1043 InvalidateMtrr(VariableMtrr);\r
1044\r
1045 //\r
1046 // Find first unused MTRR\r
1047 //\r
1048 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
3b9be416 1049 MsrNum < VariableMtrrEnd;\r
e50466da 1050 MsrNum += 2\r
1051 ) {\r
1052 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1053 break;\r
1054 }\r
1055 }\r
1056\r
1057 if (!Positive) {\r
1058 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
1059 ProgramVariableMtrr (\r
1060 MsrNum,\r
1061 BaseAddress,\r
1062 Length,\r
1063 MemoryType,\r
1064 MtrrValidAddressMask\r
1065 );\r
1066 BaseAddress += Length;\r
1067 TempQword = Length - TempQword;\r
1068 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1069 }\r
1070\r
1071 do {\r
1072 //\r
1073 // Find unused MTRR\r
1074 //\r
3b9be416 1075 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1076 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1077 break;\r
1078 }\r
1079 }\r
1080\r
1081 Length = Power2MaxMemory (TempQword);\r
1082 if (!Positive) {\r
1083 BaseAddress -= Length;\r
1084 }\r
1085\r
1086 ProgramVariableMtrr (\r
1087 MsrNum,\r
1088 BaseAddress,\r
1089 Length,\r
1090 MemoryType,\r
1091 MtrrValidAddressMask\r
1092 );\r
1093\r
1094 if (Positive) {\r
1095 BaseAddress += Length;\r
1096 }\r
1097 TempQword -= Length;\r
1098\r
1099 } while (TempQword > 0);\r
1100 }\r
1101\r
1102Done:\r
1103 return Status;\r
1104\r
1105}\r
1106\r
1107\r
1108/**\r
1109 This function will get the memory cache type of the specific address.\r
1110\r
1111 This function is mainly for debug purpose.\r
1112\r
1113 @param Address The specific address\r
1114\r
1115 @return Memory cache type of the sepcific address\r
1116\r
1117**/\r
1118MTRR_MEMORY_CACHE_TYPE\r
1119EFIAPI\r
1120MtrrGetMemoryAttribute (\r
1121 IN PHYSICAL_ADDRESS Address\r
1122 )\r
1123{\r
1124 UINT64 TempQword;\r
1125 UINTN Index;\r
1126 UINTN SubIndex;\r
1127 UINT64 MtrrType;\r
1128 UINT64 TempMtrrType;\r
1129 MTRR_MEMORY_CACHE_TYPE CacheType;\r
3b9be416 1130 VARIABLE_MTRR VariableMtrr[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 1131 UINT64 MtrrValidBitsMask;\r
1132 UINT64 MtrrValidAddressMask;\r
3b9be416
JY
1133 UINTN VariableMtrrCount;\r
1134 UINT32 UsedMtrr;\r
e50466da 1135\r
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
3b9be416 1172 UsedMtrr = MAX_MTRR_NUMBER_OF_VARIABLE_MTRR;\r
e50466da 1173 MtrrGetMemoryAttributeInVariableMtrr(\r
1174 MtrrValidBitsMask,\r
1175 MtrrValidAddressMask,\r
3b9be416 1176 &UsedMtrr,\r
e50466da 1177 VariableMtrr\r
1178 );\r
1179\r
1180 //\r
1181 // Go through the variable MTRR\r
1182 //\r
3b9be416
JY
1183 VariableMtrrCount = GetVariableMtrrCount ();\r
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
3b9be416
JY
1216 VariableMtrrCount = GetVariableMtrrCount ();\r
1217 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1218 VariableSettings->Mtrr[Index].Base =\r
1219 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
1220 VariableSettings->Mtrr[Index].Mask =\r
1221 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
1222 }\r
1223\r
1224 return VariableSettings;\r
1225}\r
1226\r
1227\r
1228/**\r
1229 Worker function setting variable MTRRs\r
1230\r
1231 @param VariableSettings A buffer to hold variable MTRRs content.\r
1232\r
1233**/\r
1234VOID\r
1235MtrrSetVariableMtrrWorker (\r
1236 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1237 )\r
1238{\r
1239 UINT32 Index;\r
3b9be416 1240 UINT32 VariableMtrrCount;\r
e50466da 1241\r
3b9be416
JY
1242 VariableMtrrCount = GetVariableMtrrCount ();\r
1243 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1244 AsmWriteMsr64 (\r
1245 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1246 VariableSettings->Mtrr[Index].Base\r
1247 );\r
1248 AsmWriteMsr64 (\r
1249 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1250 VariableSettings->Mtrr[Index].Mask\r
1251 );\r
1252 }\r
1253}\r
1254\r
1255\r
1256/**\r
1257 This function sets variable MTRRs\r
1258\r
1259 @param VariableSettings A buffer to hold variable MTRRs content.\r
1260\r
1261 @return The pointer of VariableSettings\r
1262\r
1263**/\r
1264MTRR_VARIABLE_SETTINGS*\r
1265EFIAPI\r
1266MtrrSetVariableMtrr (\r
1267 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1268 )\r
1269{\r
1270 UINTN Cr4;\r
1271\r
1272 Cr4 = PreMtrrChange ();\r
1273 MtrrSetVariableMtrrWorker (VariableSettings);\r
1274 PostMtrrChange (Cr4);\r
1275 return VariableSettings;\r
1276}\r
1277\r
1278\r
1279/**\r
1280 This function gets the content in fixed MTRRs\r
1281\r
1282 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1283\r
1284 @retval The pointer of FixedSettings\r
1285\r
1286**/\r
1287MTRR_FIXED_SETTINGS*\r
1288EFIAPI\r
1289MtrrGetFixedMtrr (\r
1290 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
1291 )\r
1292{\r
1293 UINT32 Index;\r
1294\r
1295 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1296 FixedSettings->Mtrr[Index] =\r
1297 AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
1298 };\r
1299\r
1300 return FixedSettings;\r
1301}\r
1302\r
1303/**\r
1304 Worker function setting fixed MTRRs\r
1305\r
1306 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1307\r
1308**/\r
1309VOID\r
1310MtrrSetFixedMtrrWorker (\r
1311 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1312 )\r
1313{\r
1314 UINT32 Index;\r
1315\r
1316 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1317 AsmWriteMsr64 (\r
1318 MtrrLibFixedMtrrTable[Index].Msr,\r
1319 FixedSettings->Mtrr[Index]\r
1320 );\r
1321 }\r
1322}\r
1323\r
1324\r
1325/**\r
1326 This function sets fixed MTRRs\r
1327\r
1328 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1329\r
1330 @retval The pointer of FixedSettings\r
1331\r
1332**/\r
1333MTRR_FIXED_SETTINGS*\r
1334EFIAPI\r
1335MtrrSetFixedMtrr (\r
1336 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1337 )\r
1338{\r
1339 UINTN Cr4;\r
1340\r
1341 Cr4 = PreMtrrChange ();\r
1342 MtrrSetFixedMtrrWorker (FixedSettings);\r
1343 PostMtrrChange (Cr4);\r
1344\r
1345 return FixedSettings;\r
1346}\r
1347\r
1348\r
1349/**\r
1350 This function gets the content in all MTRRs (variable and fixed)\r
1351\r
1352 @param MtrrSetting A buffer to hold all Mtrrs content.\r
1353\r
1354 @retval the pointer of MtrrSetting\r
1355\r
1356**/\r
1357MTRR_SETTINGS *\r
1358EFIAPI\r
1359MtrrGetAllMtrrs (\r
1360 OUT MTRR_SETTINGS *MtrrSetting\r
1361 )\r
1362{\r
1363 //\r
1364 // Get fixed MTRRs\r
1365 //\r
1366 MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
1367\r
1368 //\r
1369 // Get variable MTRRs\r
1370 //\r
1371 MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
1372\r
1373 //\r
1374 // Get MTRR_DEF_TYPE value\r
1375 //\r
1376 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1377\r
1378 return MtrrSetting;\r
1379}\r
1380\r
1381\r
1382/**\r
1383 This function sets all MTRRs (variable and fixed)\r
1384\r
1385 @param MtrrSetting A buffer holding all MTRRs content.\r
1386\r
1387 @retval The pointer of MtrrSetting\r
1388\r
1389**/\r
1390MTRR_SETTINGS *\r
1391EFIAPI\r
1392MtrrSetAllMtrrs (\r
1393 IN MTRR_SETTINGS *MtrrSetting\r
1394 )\r
1395{\r
1396 UINTN Cr4;\r
1397\r
1398 Cr4 = PreMtrrChange ();\r
1399\r
1400 //\r
1401 // Set fixed MTRRs\r
1402 //\r
1403 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
1404\r
1405 //\r
1406 // Set variable MTRRs\r
1407 //\r
1408 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
1409\r
1410 //\r
1411 // Set MTRR_DEF_TYPE value\r
1412 //\r
1413 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
1414\r
1415 PostMtrrChange (Cr4);\r
1416\r
1417 return MtrrSetting;\r
1418}\r
1419\r
1420\r
1421/**\r
1422 This function prints all MTRRs for debugging.\r
1423**/\r
1424VOID\r
1425MtrrDebugPrintAllMtrrs (\r
1426 )\r
1427{\r
1428 DEBUG_CODE (\r
1429 {\r
1430 MTRR_SETTINGS MtrrSettings;\r
1431 UINTN Index;\r
3b9be416 1432 UINTN VariableMtrrCount;\r
e50466da 1433\r
1434 MtrrGetAllMtrrs (&MtrrSettings);\r
1435 DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));\r
1436 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1437 DEBUG((\r
1438 EFI_D_ERROR, "Fixed[%02d] = %016lx\n",\r
1439 Index,\r
1440 MtrrSettings.Fixed.Mtrr[Index]\r
1441 ));\r
1442 }\r
3b9be416
JY
1443\r
1444 VariableMtrrCount = GetVariableMtrrCount ();\r
1445 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1446 DEBUG((\r
1447 EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",\r
1448 Index,\r
1449 MtrrSettings.Variables.Mtrr[Index].Base,\r
1450 MtrrSettings.Variables.Mtrr[Index].Mask\r
1451 ));\r
1452 }\r
1453 }\r
1454 );\r
1455}\r
1456\r