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