]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
Use atomic AsmDisableCache() and AsmDisableCache() functions instead of AsmWriteCr0...
[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 for (Index = 0; Index < VariableMtrrCount; Index++) {
1160 if (VariableMtrr[Index].Valid) {
1161 if (Address >= VariableMtrr[Index].BaseAddress &&
1162 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1163 TempMtrrType = VariableMtrr[Index].Type;
1164 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1165 }
1166 }
1167 }
1168 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
1169
1170 return CacheType;
1171 }
1172
1173
1174 /**
1175 This function will get the raw value in variable MTRRs
1176
1177 @param VariableSettings A buffer to hold variable MTRRs content.
1178
1179 @return The VariableSettings input pointer
1180
1181 **/
1182 MTRR_VARIABLE_SETTINGS*
1183 EFIAPI
1184 MtrrGetVariableMtrr (
1185 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
1186 )
1187 {
1188 UINT32 Index;
1189 UINT32 VariableMtrrCount;
1190
1191 VariableMtrrCount = GetVariableMtrrCount ();
1192 for (Index = 0; Index < VariableMtrrCount; Index++) {
1193 VariableSettings->Mtrr[Index].Base =
1194 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
1195 VariableSettings->Mtrr[Index].Mask =
1196 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
1197 }
1198
1199 return VariableSettings;
1200 }
1201
1202
1203 /**
1204 Worker function setting variable MTRRs
1205
1206 @param VariableSettings A buffer to hold variable MTRRs content.
1207
1208 **/
1209 VOID
1210 MtrrSetVariableMtrrWorker (
1211 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1212 )
1213 {
1214 UINT32 Index;
1215 UINT32 VariableMtrrCount;
1216
1217 VariableMtrrCount = GetVariableMtrrCount ();
1218 for (Index = 0; Index < VariableMtrrCount; Index++) {
1219 AsmWriteMsr64 (
1220 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1221 VariableSettings->Mtrr[Index].Base
1222 );
1223 AsmWriteMsr64 (
1224 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1225 VariableSettings->Mtrr[Index].Mask
1226 );
1227 }
1228 }
1229
1230
1231 /**
1232 This function sets variable MTRRs
1233
1234 @param VariableSettings A buffer to hold variable MTRRs content.
1235
1236 @return The pointer of VariableSettings
1237
1238 **/
1239 MTRR_VARIABLE_SETTINGS*
1240 EFIAPI
1241 MtrrSetVariableMtrr (
1242 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1243 )
1244 {
1245 UINTN Cr4;
1246
1247 Cr4 = PreMtrrChange ();
1248 MtrrSetVariableMtrrWorker (VariableSettings);
1249 PostMtrrChange (Cr4);
1250 return VariableSettings;
1251 }
1252
1253
1254 /**
1255 This function gets the content in fixed MTRRs
1256
1257 @param FixedSettings A buffer to hold fixed Mtrrs content.
1258
1259 @retval The pointer of FixedSettings
1260
1261 **/
1262 MTRR_FIXED_SETTINGS*
1263 EFIAPI
1264 MtrrGetFixedMtrr (
1265 OUT MTRR_FIXED_SETTINGS *FixedSettings
1266 )
1267 {
1268 UINT32 Index;
1269
1270 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1271 FixedSettings->Mtrr[Index] =
1272 AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);
1273 };
1274
1275 return FixedSettings;
1276 }
1277
1278 /**
1279 Worker function setting fixed MTRRs
1280
1281 @param FixedSettings A buffer to hold fixed Mtrrs content.
1282
1283 **/
1284 VOID
1285 MtrrSetFixedMtrrWorker (
1286 IN MTRR_FIXED_SETTINGS *FixedSettings
1287 )
1288 {
1289 UINT32 Index;
1290
1291 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1292 AsmWriteMsr64 (
1293 MtrrLibFixedMtrrTable[Index].Msr,
1294 FixedSettings->Mtrr[Index]
1295 );
1296 }
1297 }
1298
1299
1300 /**
1301 This function sets fixed MTRRs
1302
1303 @param FixedSettings A buffer to hold fixed Mtrrs content.
1304
1305 @retval The pointer of FixedSettings
1306
1307 **/
1308 MTRR_FIXED_SETTINGS*
1309 EFIAPI
1310 MtrrSetFixedMtrr (
1311 IN MTRR_FIXED_SETTINGS *FixedSettings
1312 )
1313 {
1314 UINTN Cr4;
1315
1316 Cr4 = PreMtrrChange ();
1317 MtrrSetFixedMtrrWorker (FixedSettings);
1318 PostMtrrChange (Cr4);
1319
1320 return FixedSettings;
1321 }
1322
1323
1324 /**
1325 This function gets the content in all MTRRs (variable and fixed)
1326
1327 @param MtrrSetting A buffer to hold all Mtrrs content.
1328
1329 @retval the pointer of MtrrSetting
1330
1331 **/
1332 MTRR_SETTINGS *
1333 EFIAPI
1334 MtrrGetAllMtrrs (
1335 OUT MTRR_SETTINGS *MtrrSetting
1336 )
1337 {
1338 //
1339 // Get fixed MTRRs
1340 //
1341 MtrrGetFixedMtrr (&MtrrSetting->Fixed);
1342
1343 //
1344 // Get variable MTRRs
1345 //
1346 MtrrGetVariableMtrr (&MtrrSetting->Variables);
1347
1348 //
1349 // Get MTRR_DEF_TYPE value
1350 //
1351 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1352
1353 return MtrrSetting;
1354 }
1355
1356
1357 /**
1358 This function sets all MTRRs (variable and fixed)
1359
1360 @param MtrrSetting A buffer holding all MTRRs content.
1361
1362 @retval The pointer of MtrrSetting
1363
1364 **/
1365 MTRR_SETTINGS *
1366 EFIAPI
1367 MtrrSetAllMtrrs (
1368 IN MTRR_SETTINGS *MtrrSetting
1369 )
1370 {
1371 UINTN Cr4;
1372
1373 Cr4 = PreMtrrChange ();
1374
1375 //
1376 // Set fixed MTRRs
1377 //
1378 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
1379
1380 //
1381 // Set variable MTRRs
1382 //
1383 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
1384
1385 //
1386 // Set MTRR_DEF_TYPE value
1387 //
1388 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
1389
1390 PostMtrrChange (Cr4);
1391
1392 return MtrrSetting;
1393 }
1394
1395
1396 /**
1397 This function prints all MTRRs for debugging.
1398 **/
1399 VOID
1400 MtrrDebugPrintAllMtrrs (
1401 )
1402 {
1403 DEBUG_CODE (
1404 {
1405 MTRR_SETTINGS MtrrSettings;
1406 UINTN Index;
1407 UINTN VariableMtrrCount;
1408
1409 MtrrGetAllMtrrs (&MtrrSettings);
1410 DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));
1411 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1412 DEBUG((
1413 EFI_D_ERROR, "Fixed[%02d] = %016lx\n",
1414 Index,
1415 MtrrSettings.Fixed.Mtrr[Index]
1416 ));
1417 }
1418
1419 VariableMtrrCount = GetVariableMtrrCount ();
1420 for (Index = 0; Index < VariableMtrrCount; Index++) {
1421 DEBUG((
1422 EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",
1423 Index,
1424 MtrrSettings.Variables.Mtrr[Index].Base,
1425 MtrrSettings.Variables.Mtrr[Index].Mask
1426 ));
1427 }
1428 }
1429 );
1430 }
1431