1 /** @file
2
3 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php.
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include <Uefi.h>
15 #include <Library/BaseLib.h>
16 #include <Library/CacheLib.h>
17 #include <Library/CacheAsRamLib.h>
18 #include "CacheLibInternal.h"
19
20 /**
21 Search the memory cache type for specific memory from MTRR.
22
23 @param[in] MemoryAddress the address of target memory
24 @param[in] MemoryLength the length of target memory
25 @param[in] ValidMtrrAddressMask the MTRR address mask
26 @param[out] UsedMsrNum the used MSR number
27 @param[out] UsedMemoryCacheType the cache type for the target memory
28
29 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
30 @retval EFI_NOT_FOUND The memory is not found in MTRR
31
32 **/
33 EFI_STATUS
34 SearchForExactMtrr (
35 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
36 IN UINT64 MemoryLength,
37 IN UINT64 ValidMtrrAddressMask,
38 OUT UINT32 *UsedMsrNum,
39 OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType
40 );
41
42 /**
43 Check if CacheType match current default setting.
44
45 @param[in] MemoryCacheType input cache type to be checked.
46
47 @retval TRUE MemoryCacheType is default MTRR setting.
48 @retval FALSE MemoryCacheType is NOT default MTRR setting.
49 **/
50 BOOLEAN
51 IsDefaultType (
52 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
53 );
54
55 /**
56 Return MTRR alignment requirement for base address and size.
57
58 @param[in] BaseAddress Base address.
59 @param[in] Size Size.
60
61 @retval Zero Alligned.
62 @retval Non-Zero Not alligned.
63
64 **/
65 UINT32
66 CheckMtrrAlignment (
67 IN UINT64 BaseAddress,
68 IN UINT64 Size
69 );
70
71 typedef struct {
72 UINT32 Msr;
73 UINT32 BaseAddress;
74 UINT32 Length;
75 } EFI_FIXED_MTRR;
76
77 EFI_FIXED_MTRR mFixedMtrrTable[] = {
78 { EFI_MSR_IA32_MTRR_FIX64K_00000, 0, 0x10000},
79 { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000},
80 { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000},
81 { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000},
82 { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000},
83 { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000},
84 { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000},
85 { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000},
86 { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000},
87 { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000},
88 { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000}
89 };
90
91 /**
92 Given the input, check if the number of MTRR is lesser.
93 if positive or subtractive.
94
95 @param[in] Input Length of Memory to program MTRR.
96
97 @retval Zero do positive.
98 @retval Non-Zero do subtractive.
99
100 **/
101 INT8
CheckDirection(IN UINT64 Input)102 CheckDirection (
103 IN UINT64 Input
104 )
105 {
106 return 0;
107 }
108
109 /**
110 Disable cache and its mtrr.
111
112 @param[out] OldMtrr To return the Old MTRR value
113
114 **/
115 VOID
EfiDisableCacheMtrr(OUT UINT64 * OldMtrr)116 EfiDisableCacheMtrr (
117 OUT UINT64 *OldMtrr
118 )
119 {
120 UINT64 TempQword;
121
122 //
123 // Disable Cache MTRR
124 //
125 *OldMtrr = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
126 TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;
127 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
128 AsmDisableCache ();
129 }
130
131 /**
132 Recover cache MTRR.
133
134 @param[in] EnableMtrr Whether to enable the MTRR
135 @param[in] OldMtrr The saved old MTRR value to restore when not to enable the MTRR
136
137 **/
138 VOID
EfiRecoverCacheMtrr(IN BOOLEAN EnableMtrr,IN UINT64 OldMtrr)139 EfiRecoverCacheMtrr (
140 IN BOOLEAN EnableMtrr,
141 IN UINT64 OldMtrr
142 )
143 {
144 UINT64 TempQword;
145
146 //
147 // Enable Cache MTRR
148 //
149 if (EnableMtrr) {
150 TempQword = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
151 TempQword |= (UINT64)(B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);
152 } else {
153 TempQword = OldMtrr;
154 }
155
156 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
157
158 AsmEnableCache ();
159 }
160
161 /**
162 Programming MTRR according to Memory address, length, and type.
163
164 @param[in] MtrrNumber the variable MTRR index number
165 @param[in] MemoryAddress the address of target memory
166 @param[in] MemoryLength the length of target memory
167 @param[in] MemoryCacheType the cache type of target memory
168 @param[in] ValidMtrrAddressMask the MTRR address mask
169
170 **/
171 VOID
EfiProgramMtrr(IN UINTN MtrrNumber,IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,IN UINT64 ValidMtrrAddressMask)172 EfiProgramMtrr (
173 IN UINTN MtrrNumber,
174 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
175 IN UINT64 MemoryLength,
176 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,
177 IN UINT64 ValidMtrrAddressMask
178 )
179 {
180 UINT64 TempQword;
181 UINT64 OldMtrr;
182
183 if (MemoryLength == 0) {
184 return;
185 }
186
187 EfiDisableCacheMtrr (&OldMtrr);
188
189 //
190 // MTRR Physical Base
191 //
192 TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType;
193 AsmWriteMsr64 (MtrrNumber, TempQword);
194
195 //
196 // MTRR Physical Mask
197 //
198 TempQword = ~(MemoryLength - 1);
199 AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);
200
201 EfiRecoverCacheMtrr (TRUE, OldMtrr);
202 }
203
204 /**
205 Calculate the maximum value which is a power of 2, but less the MemoryLength.
206
207 @param[in] MemoryAddress Memory address.
208 @param[in] MemoryLength The number to pass in.
209
210 @return The maximum value which is align to power of 2 and less the MemoryLength
211
212 **/
213 UINT64
Power2MaxMemory(IN UINT64 MemoryAddress,IN UINT64 MemoryLength)214 Power2MaxMemory (
215 IN UINT64 MemoryAddress,
216 IN UINT64 MemoryLength
217 )
218 {
219 UINT64 Result;
220
221 if (MemoryLength == 0) {
222 return EFI_INVALID_PARAMETER;
223 }
224
225 //
226 // Compute inital power of 2 size to return
227 //
228 Result = GetPowerOfTwo64(MemoryLength);
229
230 //
231 // Special case base of 0 as all ranges are valid
232 //
233 if (MemoryAddress == 0) {
234 return Result;
235 }
236
237 //
238 // Loop till a value that can be mapped to this base address is found
239 //
240 while (CheckMtrrAlignment (MemoryAddress, Result) != 0) {
241 //
242 // Need to try the next smaller power of 2
243 //
244 Result = RShiftU64 (Result, 1);
245 }
246
247 return Result;
248 }
249
250 /**
251 Return MTRR alignment requirement for base address and size.
252
253 @param[in] BaseAddress Base address.
254 @param[in] Size Size.
255
256 @retval Zero Alligned.
257 @retval Non-Zero Not alligned.
258
259 **/
260 UINT32
CheckMtrrAlignment(IN UINT64 BaseAddress,IN UINT64 Size)261 CheckMtrrAlignment (
262 IN UINT64 BaseAddress,
263 IN UINT64 Size
264 )
265 {
266 UINT32 ShiftedBase;
267 UINT32 ShiftedSize;
268
269 //
270 // Shift base and size right 12 bits to allow for larger memory sizes. The
271 // MTRRs do not use the first 12 bits so this is safe for now. Only supports
272 // up to 52 bits of physical address space.
273 //
274 ShiftedBase = (UINT32) RShiftU64 (BaseAddress, 12);
275 ShiftedSize = (UINT32) RShiftU64 (Size, 12);
276
277 //
278 // Return the results to the caller of the MOD
279 //
280 return ShiftedBase % ShiftedSize;
281 }
282
283 /**
284 Programs fixed MTRRs registers.
285
286 @param[in] MemoryCacheType The memory type to set.
287 @param[in] Base The base address of memory range.
288 @param[in] Length The length of memory range.
289
290 @retval RETURN_SUCCESS The cache type was updated successfully
291 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
292 for the fixed MTRRs.
293
294 **/
295 EFI_STATUS
ProgramFixedMtrr(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,IN UINT64 * Base,IN UINT64 * Len)296 ProgramFixedMtrr (
297 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,
298 IN UINT64 *Base,
299 IN UINT64 *Len
300 )
301 {
302 UINT32 MsrNum;
303 UINT32 ByteShift;
304 UINT64 TempQword;
305 UINT64 OrMask;
306 UINT64 ClearMask;
307
308 TempQword = 0;
309 OrMask = 0;
310 ClearMask = 0;
311
312 for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {
313 if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&
314 (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))) {
315 break;
316 }
317 }
318 if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) {
319 return EFI_DEVICE_ERROR;
320 }
321 //
322 // We found the fixed MTRR to be programmed
323 //
324 for (ByteShift=0; ByteShift < 8; ByteShift++) {
325 if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {
326 break;
327 }
328 }
329 if (ByteShift == 8 ) {
330 return EFI_DEVICE_ERROR;
331 }
332 for (; ((ByteShift<8) && (*Len >= mFixedMtrrTable[MsrNum].Length));ByteShift++) {
333 OrMask |= LShiftU64((UINT64) MemoryCacheType, (UINT32) (ByteShift* 8));
334 ClearMask |= LShiftU64((UINT64) 0xFF, (UINT32) (ByteShift * 8));
335 *Len -= mFixedMtrrTable[MsrNum].Length;
336 *Base += mFixedMtrrTable[MsrNum].Length;
337 }
338 TempQword = (AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask)) | OrMask;
339 AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);
340
341 return EFI_SUCCESS;
342 }
343
344 /**
345 Check if there is a valid variable MTRR that overlaps the given range.
346
347 @param[in] Start Base Address of the range to check.
348 @param[in] End End address of the range to check.
349
350 @retval TRUE Mtrr overlap.
351 @retval FALSE Mtrr not overlap.
352 **/
353 BOOLEAN
CheckMtrrOverlap(IN EFI_PHYSICAL_ADDRESS Start,IN EFI_PHYSICAL_ADDRESS End)354 CheckMtrrOverlap (
355 IN EFI_PHYSICAL_ADDRESS Start,
356 IN EFI_PHYSICAL_ADDRESS End
357 )
358 {
359 return FALSE;
360 }
361
362 /**
363 Given the memory range and cache type, programs the MTRRs.
364
365 @param[in] MemoryAddress Base Address of Memory to program MTRR.
366 @param[in] MemoryLength Length of Memory to program MTRR.
367 @param[in] MemoryCacheType Cache Type.
368
369 @retval EFI_SUCCESS Mtrr are set successfully.
370 @retval EFI_LOAD_ERROR No empty MTRRs to use.
371 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
372 @retval others An error occurs when setting MTTR.
373
374 **/
375 EFI_STATUS
376 EFIAPI
SetCacheAttributes(IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)377 SetCacheAttributes (
378 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
379 IN UINT64 MemoryLength,
380 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
381 )
382 {
383 EFI_STATUS Status;
384 UINT32 MsrNum, MsrNumEnd;
385 UINT64 TempQword;
386 UINT32 LastVariableMtrrForBios;
387 UINT64 OldMtrr;
388 UINT32 UsedMsrNum;
389 EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType;
390 UINT64 ValidMtrrAddressMask;
391 UINT32 Cpuid_RegEax;
392
393 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL);
394 if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
395 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL);
396 ValidMtrrAddressMask = (LShiftU64((UINT64) 1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF);
397 } else {
398 ValidMtrrAddressMask = (LShiftU64((UINT64) 1, 36) - 1) & (~(UINT64)0x0FFF);
399 }
400
401 //
402 // Check for invalid parameter
403 //
404 if ((MemoryAddress & ~ValidMtrrAddressMask) != 0 || (MemoryLength & ~ValidMtrrAddressMask) != 0) {
405 return EFI_INVALID_PARAMETER;
406 }
407
408 if (MemoryLength == 0) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 switch (MemoryCacheType) {
413 case EFI_CACHE_UNCACHEABLE:
414 case EFI_CACHE_WRITECOMBINING:
415 case EFI_CACHE_WRITETHROUGH:
416 case EFI_CACHE_WRITEPROTECTED:
417 case EFI_CACHE_WRITEBACK:
418 break;
419
420 default:
421 return EFI_INVALID_PARAMETER;
422 }
423
424 //
425 // Check if Fixed MTRR
426 //
427 if ((MemoryAddress + MemoryLength) <= (1 << 20)) {
428 Status = EFI_SUCCESS;
429 EfiDisableCacheMtrr (&OldMtrr);
430 while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) {
431 Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength);
432 }
433 EfiRecoverCacheMtrr (TRUE, OldMtrr);
434 return Status;
435 }
436
437 //
438 // Search if the range attribute has been set before
439 //
440 Status = SearchForExactMtrr(
441 MemoryAddress,
442 MemoryLength,
443 ValidMtrrAddressMask,
444 &UsedMsrNum,
445 &UsedMemoryCacheType
446 );
447
448 if (!EFI_ERROR(Status)) {
449 //
450 // Compare if it has the same type as current setting
451 //
452 if (UsedMemoryCacheType == MemoryCacheType) {
453 return EFI_SUCCESS;
454 } else {
455 //
456 // Different type
457 //
458
459 //
460 // Check if the set type is the same as Default Type
461 //
462 if (IsDefaultType(MemoryCacheType)) {
463 //
464 // Clear the MTRR
465 //
466 AsmWriteMsr64(UsedMsrNum, 0);
467 AsmWriteMsr64(UsedMsrNum + 1, 0);
468
469 return EFI_SUCCESS;
470 } else {
471 //
472 // Modify the MTRR type
473 //
474 EfiProgramMtrr(UsedMsrNum,
475 MemoryAddress,
476 MemoryLength,
477 MemoryCacheType,
478 ValidMtrrAddressMask
479 );
480 return EFI_SUCCESS;
481 }
482 }
483 }
484
485 #if 0
486 //
487 // @bug - Need to create memory map so that when checking for overlap we
488 // can determine if an overlap exists based on all caching requests.
489 //
490 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
491 //
492 if (MemoryCacheType == (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE)) {
493 if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) {
494 return EFI_SUCCESS;
495 }
496 }
497 #endif
498
499 //
500 // Find first unused MTRR
501 //
502 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
503 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {
504 if ((AsmReadMsr64(MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) {
505 break;
506 }
507 }
508
509 //
510 // Reserve 1 MTRR pair for OS.
511 //
512 LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2);
513 if (MsrNum > LastVariableMtrrForBios) {
514 return EFI_LOAD_ERROR;
515 }
516
517 //
518 // Special case for 1 MB base address
519 //
520 if (MemoryAddress == BASE_1MB) {
521 MemoryAddress = 0;
522 }
523
524 //
525 // Program MTRRs
526 //
527 TempQword = MemoryLength;
528
529 if (TempQword == Power2MaxMemory(MemoryAddress, TempQword)) {
530 EfiProgramMtrr(MsrNum,
531 MemoryAddress,
532 MemoryLength,
533 MemoryCacheType,
534 ValidMtrrAddressMask
535 );
536
537 } else {
538 //
539 // Fill in MTRRs with values. Direction can not be checked for this method
540 // as we are using WB as the default cache type and only setting areas to UC.
541 //
542 do {
543 //
544 // Do boundary check so we don't go past last MTRR register
545 // for BIOS use. Leave one MTRR pair for OS use.
546 //
547 if (MsrNum > LastVariableMtrrForBios) {
548 return EFI_LOAD_ERROR;
549 }
550
551 //
552 // Set next power of 2 region
553 //
554 MemoryLength = Power2MaxMemory(MemoryAddress, TempQword);
555 EfiProgramMtrr(MsrNum,
556 MemoryAddress,
557 MemoryLength,
558 MemoryCacheType,
559 ValidMtrrAddressMask
560 );
561 MemoryAddress += MemoryLength;
562 TempQword -= MemoryLength;
563 MsrNum += 2;
564 } while (TempQword != 0);
565 }
566
567 return EFI_SUCCESS;
568 }
569
570 /**
571 Reset all the MTRRs to a known state.
572
573 @retval EFI_SUCCESS All MTRRs have been reset successfully.
574
575 **/
576 EFI_STATUS
577 EFIAPI
ResetCacheAttributes(VOID)578 ResetCacheAttributes (
579 VOID
580 )
581 {
582 UINT32 MsrNum, MsrNumEnd;
583 UINT16 Index;
584 UINT64 OldMtrr;
585 UINT64 CacheType;
586 BOOLEAN DisableCar;
587 Index = 0;
588 DisableCar = TRUE;
589
590 //
591 // Determine default cache type
592 //
593 CacheType = EFI_CACHE_UNCACHEABLE;
594
595 //
596 // Set default cache type
597 //
598 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType);
599
600 //
601 // Disable CAR
602 //
603 DisableCacheAsRam (DisableCar);
604
605 EfiDisableCacheMtrr (&OldMtrr);
606
607 //
608 // Reset Fixed MTRRs
609 //
610 for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {
611 AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0);
612 }
613
614 //
615 // Reset Variable MTRRs
616 //
617 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
618 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) {
619 AsmWriteMsr64 (MsrNum, 0);
620 }
621
622 //
623 // Enable Fixed and Variable MTRRs
624 //
625 EfiRecoverCacheMtrr (TRUE, OldMtrr);
626
627 return EFI_SUCCESS;
628 }
629
630 /**
631 Search the memory cache type for specific memory from MTRR.
632
633 @param[in] MemoryAddress the address of target memory
634 @param[in] MemoryLength the length of target memory
635 @param[in] ValidMtrrAddressMask the MTRR address mask
636 @param[out] UsedMsrNum the used MSR number
637 @param[out] UsedMemoryCacheType the cache type for the target memory
638
639 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
640 @retval EFI_NOT_FOUND The memory is not found in MTRR
641
642 **/
643 EFI_STATUS
SearchForExactMtrr(IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN UINT64 ValidMtrrAddressMask,OUT UINT32 * UsedMsrNum,OUT EFI_MEMORY_CACHE_TYPE * UsedMemoryCacheType)644 SearchForExactMtrr (
645 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
646 IN UINT64 MemoryLength,
647 IN UINT64 ValidMtrrAddressMask,
648 OUT UINT32 *UsedMsrNum,
649 OUT EFI_MEMORY_CACHE_TYPE *UsedMemoryCacheType
650 )
651 {
652 UINT32 MsrNum, MsrNumEnd;
653 UINT64 TempQword;
654
655 if (MemoryLength == 0) {
656 return EFI_INVALID_PARAMETER;
657 }
658
659 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
660 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {
661 TempQword = AsmReadMsr64(MsrNum+1);
662 if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
663 continue;
664 }
665
666 if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) {
667 continue;
668 }
669
670 TempQword = AsmReadMsr64 (MsrNum);
671 if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) {
672 continue;
673 }
674
675 *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE);
676 *UsedMsrNum = MsrNum;
677
678 return EFI_SUCCESS;
679 }
680
681 return EFI_NOT_FOUND;
682 }
683
684 /**
685 Check if CacheType match current default setting.
686
687 @param[in] MemoryCacheType input cache type to be checked.
688
689 @retval TRUE MemoryCacheType is default MTRR setting.
690 @retval TRUE MemoryCacheType is NOT default MTRR setting.
691 **/
692 BOOLEAN
IsDefaultType(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)693 IsDefaultType (
694 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
695 )
696 {
697 if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) {
698 return FALSE;
699 }
700
701 return TRUE;
702 }
703
704