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