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