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