VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 7 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 92.9 KB
 
1/** @file
2 MTRR setting library
3
4 @par Note:
5 Most of services in this library instance are suggested to be invoked by BSP only,
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
7
8 Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11**/
12
13#include <Uefi.h>
14#include <Register/Intel/Cpuid.h>
15#include <Register/Intel/Msr.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#define OR_SEED 0x0101010101010101ull
24#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
25#define MAX_WEIGHT MAX_UINT8
26#define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)
27#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
28
29#define M(x, y) ((x) * VertexCount + (y))
30#define O(x, y) ((y) * VertexCount + (x))
31
32//
33// Context to save and restore when MTRRs are programmed
34//
35typedef struct {
36 UINTN Cr4;
37 BOOLEAN InterruptState;
38 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
39} MTRR_CONTEXT;
40
41typedef struct {
42 UINT64 Address;
43 UINT64 Alignment;
44 UINT64 Length;
45 MTRR_MEMORY_CACHE_TYPE Type : 7;
46
47 //
48 // Temprary use for calculating the best MTRR settings.
49 //
50 BOOLEAN Visited : 1;
51 UINT8 Weight;
52 UINT16 Previous;
53} MTRR_LIB_ADDRESS;
54
55//
56// This table defines the offset, base and length of the fixed MTRRs
57//
58CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
59 {
60 MSR_IA32_MTRR_FIX64K_00000,
61 0,
62 SIZE_64KB
63 },
64 {
65 MSR_IA32_MTRR_FIX16K_80000,
66 0x80000,
67 SIZE_16KB
68 },
69 {
70 MSR_IA32_MTRR_FIX16K_A0000,
71 0xA0000,
72 SIZE_16KB
73 },
74 {
75 MSR_IA32_MTRR_FIX4K_C0000,
76 0xC0000,
77 SIZE_4KB
78 },
79 {
80 MSR_IA32_MTRR_FIX4K_C8000,
81 0xC8000,
82 SIZE_4KB
83 },
84 {
85 MSR_IA32_MTRR_FIX4K_D0000,
86 0xD0000,
87 SIZE_4KB
88 },
89 {
90 MSR_IA32_MTRR_FIX4K_D8000,
91 0xD8000,
92 SIZE_4KB
93 },
94 {
95 MSR_IA32_MTRR_FIX4K_E0000,
96 0xE0000,
97 SIZE_4KB
98 },
99 {
100 MSR_IA32_MTRR_FIX4K_E8000,
101 0xE8000,
102 SIZE_4KB
103 },
104 {
105 MSR_IA32_MTRR_FIX4K_F0000,
106 0xF0000,
107 SIZE_4KB
108 },
109 {
110 MSR_IA32_MTRR_FIX4K_F8000,
111 0xF8000,
112 SIZE_4KB
113 }
114};
115
116//
117// Lookup table used to print MTRRs
118//
119GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
120 "UC", // CacheUncacheable
121 "WC", // CacheWriteCombining
122 "R*", // Invalid
123 "R*", // Invalid
124 "WT", // CacheWriteThrough
125 "WP", // CacheWriteProtected
126 "WB", // CacheWriteBack
127 "R*" // Invalid
128};
129
130/**
131 Worker function prints all MTRRs for debugging.
132
133 If MtrrSetting is not NULL, print MTRR settings from input MTRR
134 settings buffer.
135 If MtrrSetting is NULL, print MTRR settings from MTRRs.
136
137 @param MtrrSetting A buffer holding all MTRRs content.
138**/
139VOID
140MtrrDebugPrintAllMtrrsWorker (
141 IN MTRR_SETTINGS *MtrrSetting
142 );
143
144/**
145 Return whether MTRR is supported.
146
147 @param[out] FixedMtrrSupported Return whether fixed MTRR is supported.
148 @param[out] VariableMtrrCount Return the max number of variable MTRRs.
149
150 @retval TRUE MTRR is supported when either fixed MTRR is supported or max number
151 of variable MTRRs is not 0.
152 @retval FALSE MTRR is not supported when both fixed MTRR is not supported and max
153 number of variable MTRRs is 0.
154**/
155BOOLEAN
156MtrrLibIsMtrrSupported (
157 OUT BOOLEAN *FixedMtrrSupported OPTIONAL,
158 OUT UINT32 *VariableMtrrCount OPTIONAL
159 )
160{
161 CPUID_VERSION_INFO_EDX Edx;
162 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
163
164 //
165 // Check CPUID(1).EDX[12] for MTRR capability
166 //
167 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
168 if (Edx.Bits.MTRR == 0) {
169 if (FixedMtrrSupported != NULL) {
170 *FixedMtrrSupported = FALSE;
171 }
172
173 if (VariableMtrrCount != NULL) {
174 *VariableMtrrCount = 0;
175 }
176
177 return FALSE;
178 }
179
180 //
181 // Check the number of variable MTRRs and determine whether fixed MTRRs exist.
182 // If the count of variable MTRRs is zero and there are no fixed MTRRs,
183 // then return false
184 //
185 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
186 ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *)0)->Mtrr));
187 if (FixedMtrrSupported != NULL) {
188 *FixedMtrrSupported = (BOOLEAN)(MtrrCap.Bits.FIX == 1);
189 }
190
191 if (VariableMtrrCount != NULL) {
192 *VariableMtrrCount = MtrrCap.Bits.VCNT;
193 }
194
195 if ((MtrrCap.Bits.VCNT == 0) && (MtrrCap.Bits.FIX == 0)) {
196 return FALSE;
197 }
198
199 return TRUE;
200}
201
202/**
203 Worker function returns the variable MTRR count for the CPU.
204
205 @return Variable MTRR count
206
207**/
208UINT32
209GetVariableMtrrCountWorker (
210 VOID
211 )
212{
213 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
214
215 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
216 ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *)0)->Mtrr));
217 return MtrrCap.Bits.VCNT;
218}
219
220/**
221 Returns the variable MTRR count for the CPU.
222
223 @return Variable MTRR count
224
225**/
226UINT32
227EFIAPI
228GetVariableMtrrCount (
229 VOID
230 )
231{
232 if (!IsMtrrSupported ()) {
233 return 0;
234 }
235
236 return GetVariableMtrrCountWorker ();
237}
238
239/**
240 Worker function returns the firmware usable variable MTRR count for the CPU.
241
242 @return Firmware usable variable MTRR count
243
244**/
245UINT32
246GetFirmwareVariableMtrrCountWorker (
247 VOID
248 )
249{
250 UINT32 VariableMtrrCount;
251 UINT32 ReservedMtrrNumber;
252
253 VariableMtrrCount = GetVariableMtrrCountWorker ();
254 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
255 if (VariableMtrrCount < ReservedMtrrNumber) {
256 return 0;
257 }
258
259 return VariableMtrrCount - ReservedMtrrNumber;
260}
261
262/**
263 Returns the firmware usable variable MTRR count for the CPU.
264
265 @return Firmware usable variable MTRR count
266
267**/
268UINT32
269EFIAPI
270GetFirmwareVariableMtrrCount (
271 VOID
272 )
273{
274 if (!IsMtrrSupported ()) {
275 return 0;
276 }
277
278 return GetFirmwareVariableMtrrCountWorker ();
279}
280
281/**
282 Worker function returns the default MTRR cache type for the system.
283
284 If MtrrSetting is not NULL, returns the default MTRR cache type from input
285 MTRR settings buffer.
286 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
287
288 @param[in] MtrrSetting A buffer holding all MTRRs content.
289
290 @return The default MTRR cache type.
291
292**/
293MTRR_MEMORY_CACHE_TYPE
294MtrrGetDefaultMemoryTypeWorker (
295 IN CONST MTRR_SETTINGS *MtrrSetting
296 )
297{
298 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
299
300 if (MtrrSetting == NULL) {
301 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
302 } else {
303 DefType.Uint64 = MtrrSetting->MtrrDefType;
304 }
305
306 return (MTRR_MEMORY_CACHE_TYPE)DefType.Bits.Type;
307}
308
309/**
310 Returns the default MTRR cache type for the system.
311
312 @return The default MTRR cache type.
313
314**/
315MTRR_MEMORY_CACHE_TYPE
316EFIAPI
317MtrrGetDefaultMemoryType (
318 VOID
319 )
320{
321 if (!IsMtrrSupported ()) {
322 return CacheUncacheable;
323 }
324
325 return MtrrGetDefaultMemoryTypeWorker (NULL);
326}
327
328/**
329 Preparation before programming MTRR.
330
331 This function will do some preparation for programming MTRRs:
332 disable cache, invalid cache and disable MTRR caching functionality
333
334 @param[out] MtrrContext Pointer to context to save
335
336**/
337VOID
338MtrrLibPreMtrrChange (
339 OUT MTRR_CONTEXT *MtrrContext
340 )
341{
342 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
343
344 //
345 // Disable interrupts and save current interrupt state
346 //
347 MtrrContext->InterruptState = SaveAndDisableInterrupts ();
348
349 //
350 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
351 //
352 AsmDisableCache ();
353
354 //
355 // Save original CR4 value and clear PGE flag (Bit 7)
356 //
357 MtrrContext->Cr4 = AsmReadCr4 ();
358 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
359
360 //
361 // Flush all TLBs
362 //
363 CpuFlushTlb ();
364
365 //
366 // Save current MTRR default type and disable MTRRs
367 //
368 MtrrContext->DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
369 DefType.Uint64 = MtrrContext->DefType.Uint64;
370 DefType.Bits.E = 0;
371 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);
372}
373
374/**
375 Cleaning up after programming MTRRs.
376
377 This function will do some clean up after programming MTRRs:
378 Flush all TLBs, re-enable caching, restore CR4.
379
380 @param[in] MtrrContext Pointer to context to restore
381
382**/
383VOID
384MtrrLibPostMtrrChangeEnableCache (
385 IN MTRR_CONTEXT *MtrrContext
386 )
387{
388 //
389 // Flush all TLBs
390 //
391 CpuFlushTlb ();
392
393 //
394 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
395 //
396 AsmEnableCache ();
397
398 //
399 // Restore original CR4 value
400 //
401 AsmWriteCr4 (MtrrContext->Cr4);
402
403 //
404 // Restore original interrupt state
405 //
406 SetInterruptState (MtrrContext->InterruptState);
407}
408
409/**
410 Cleaning up after programming MTRRs.
411
412 This function will do some clean up after programming MTRRs:
413 enable MTRR caching functionality, and enable cache
414
415 @param[in] MtrrContext Pointer to context to restore
416
417**/
418VOID
419MtrrLibPostMtrrChange (
420 IN MTRR_CONTEXT *MtrrContext
421 )
422{
423 //
424 // Enable Cache MTRR
425 // Note: It's possible that MTRR was not enabled earlier.
426 // But it will be enabled here unconditionally.
427 //
428 MtrrContext->DefType.Bits.E = 1;
429 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrContext->DefType.Uint64);
430
431 MtrrLibPostMtrrChangeEnableCache (MtrrContext);
432}
433
434/**
435 Worker function gets the content in fixed MTRRs
436
437 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
438
439 @retval The pointer of FixedSettings
440
441**/
442MTRR_FIXED_SETTINGS *
443MtrrGetFixedMtrrWorker (
444 OUT MTRR_FIXED_SETTINGS *FixedSettings
445 )
446{
447 UINT32 Index;
448
449 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
450 FixedSettings->Mtrr[Index] =
451 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
452 }
453
454 return FixedSettings;
455}
456
457/**
458 This function gets the content in fixed MTRRs
459
460 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
461
462 @retval The pointer of FixedSettings
463
464**/
465MTRR_FIXED_SETTINGS *
466EFIAPI
467MtrrGetFixedMtrr (
468 OUT MTRR_FIXED_SETTINGS *FixedSettings
469 )
470{
471 BOOLEAN FixedMtrrSupported;
472
473 MtrrLibIsMtrrSupported (&FixedMtrrSupported, NULL);
474
475 if (!FixedMtrrSupported) {
476 return FixedSettings;
477 }
478
479 return MtrrGetFixedMtrrWorker (FixedSettings);
480}
481
482/**
483 Worker function will get the raw value in variable MTRRs
484
485 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
486 MTRR settings buffer.
487 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
488
489 @param[in] MtrrSetting A buffer holding all MTRRs content.
490 @param[in] VariableMtrrCount Number of variable MTRRs.
491 @param[out] VariableSettings A buffer to hold variable MTRRs content.
492
493 @return The VariableSettings input pointer
494
495**/
496MTRR_VARIABLE_SETTINGS *
497MtrrGetVariableMtrrWorker (
498 IN MTRR_SETTINGS *MtrrSetting,
499 IN UINT32 VariableMtrrCount,
500 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
501 )
502{
503 UINT32 Index;
504
505 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
506
507 for (Index = 0; Index < VariableMtrrCount; Index++) {
508 if (MtrrSetting == NULL) {
509 VariableSettings->Mtrr[Index].Base =
510 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));
511 VariableSettings->Mtrr[Index].Mask =
512 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));
513 } else {
514 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
515 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
516 }
517 }
518
519 return VariableSettings;
520}
521
522/**
523 Programs fixed MTRRs registers.
524
525 @param[in] Type The memory type to set.
526 @param[in, out] Base The base address of memory range.
527 @param[in, out] Length The length of memory range.
528 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
529 On return, the current index of the fixed MTRR MSR to program.
530 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
531 @param[out] OrMask The bits to set in the fixed MTRR MSR.
532
533 @retval RETURN_SUCCESS The cache type was updated successfully
534 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
535 for the fixed MTRRs.
536
537**/
538RETURN_STATUS
539MtrrLibProgramFixedMtrr (
540 IN MTRR_MEMORY_CACHE_TYPE Type,
541 IN OUT UINT64 *Base,
542 IN OUT UINT64 *Length,
543 IN OUT UINT32 *LastMsrIndex,
544 OUT UINT64 *ClearMask,
545 OUT UINT64 *OrMask
546 )
547{
548 UINT32 MsrIndex;
549 UINT32 LeftByteShift;
550 UINT32 RightByteShift;
551 UINT64 SubLength;
552
553 //
554 // Find the fixed MTRR index to be programmed
555 //
556 for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
557 if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&
558 (*Base <
559 (
560 mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +
561 (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)
562 )
563 )
564 )
565 {
566 break;
567 }
568 }
569
570 ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));
571
572 //
573 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
574 //
575 if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
576 //
577 // Base address should be aligned to the begin of a certain Fixed MTRR range.
578 //
579 return RETURN_UNSUPPORTED;
580 }
581
582 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
583 ASSERT (LeftByteShift < 8);
584
585 //
586 // Find the end offset in fixed MTRR and calculate byte offset of right shift
587 //
588 SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);
589 if (*Length >= SubLength) {
590 RightByteShift = 0;
591 } else {
592 if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
593 //
594 // Length should be aligned to the end of a certain Fixed MTRR range.
595 //
596 return RETURN_UNSUPPORTED;
597 }
598
599 RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
600 //
601 // Update SubLength by actual length
602 //
603 SubLength = *Length;
604 }
605
606 *ClearMask = CLEAR_SEED;
607 *OrMask = MultU64x32 (OR_SEED, (UINT32)Type);
608
609 if (LeftByteShift != 0) {
610 //
611 // Clear the low bits by LeftByteShift
612 //
613 *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);
614 *OrMask &= LShiftU64 (*OrMask, LeftByteShift * 8);
615 }
616
617 if (RightByteShift != 0) {
618 //
619 // Clear the high bits by RightByteShift
620 //
621 *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);
622 *OrMask &= RShiftU64 (*OrMask, RightByteShift * 8);
623 }
624
625 *Length -= SubLength;
626 *Base += SubLength;
627
628 *LastMsrIndex = MsrIndex;
629
630 return RETURN_SUCCESS;
631}
632
633/**
634 Worker function gets the attribute of variable MTRRs.
635
636 This function shadows the content of variable MTRRs into an
637 internal array: VariableMtrr.
638
639 @param[in] VariableSettings The variable MTRR values to shadow
640 @param[in] VariableMtrrCount The number of variable MTRRs
641 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
642 @param[in] MtrrValidAddressMask The valid address mask for MTRR
643 @param[out] VariableMtrr The array to shadow variable MTRRs content
644
645 @return Number of MTRRs which has been used.
646
647**/
648UINT32
649MtrrGetMemoryAttributeInVariableMtrrWorker (
650 IN MTRR_VARIABLE_SETTINGS *VariableSettings,
651 IN UINTN VariableMtrrCount,
652 IN UINT64 MtrrValidBitsMask,
653 IN UINT64 MtrrValidAddressMask,
654 OUT VARIABLE_MTRR *VariableMtrr
655 )
656{
657 UINTN Index;
658 UINT32 UsedMtrr;
659
660 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));
661 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
662 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
663 VariableMtrr[Index].Msr = (UINT32)Index;
664 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
665 VariableMtrr[Index].Length =
666 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
667 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);
668 VariableMtrr[Index].Valid = TRUE;
669 VariableMtrr[Index].Used = TRUE;
670 UsedMtrr++;
671 }
672 }
673
674 return UsedMtrr;
675}
676
677/**
678 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
679 One MTRR_MEMORY_RANGE element is created for each MTRR setting.
680 The routine doesn't remove the overlap or combine the near-by region.
681
682 @param[in] VariableSettings The variable MTRR values to shadow
683 @param[in] VariableMtrrCount The number of variable MTRRs
684 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
685 @param[in] MtrrValidAddressMask The valid address mask for MTRR
686 @param[out] VariableMtrr The array to shadow variable MTRRs content
687
688 @return Number of MTRRs which has been used.
689
690**/
691UINT32
692MtrrLibGetRawVariableRanges (
693 IN CONST MTRR_VARIABLE_SETTINGS *VariableSettings,
694 IN UINTN VariableMtrrCount,
695 IN UINT64 MtrrValidBitsMask,
696 IN UINT64 MtrrValidAddressMask,
697 OUT MTRR_MEMORY_RANGE *VariableMtrr
698 )
699{
700 UINTN Index;
701 UINT32 UsedMtrr;
702
703 ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));
704 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
705 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
706 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
707 VariableMtrr[Index].Length =
708 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
709 VariableMtrr[Index].Type = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);
710 UsedMtrr++;
711 }
712 }
713
714 return UsedMtrr;
715}
716
717/**
718 Gets the attribute of variable MTRRs.
719
720 This function shadows the content of variable MTRRs into an
721 internal array: VariableMtrr.
722
723 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
724 @param[in] MtrrValidAddressMask The valid address mask for MTRR
725 @param[out] VariableMtrr The array to shadow variable MTRRs content
726
727 @return The return value of this parameter indicates the
728 number of MTRRs which has been used.
729
730**/
731UINT32
732EFIAPI
733MtrrGetMemoryAttributeInVariableMtrr (
734 IN UINT64 MtrrValidBitsMask,
735 IN UINT64 MtrrValidAddressMask,
736 OUT VARIABLE_MTRR *VariableMtrr
737 )
738{
739 MTRR_VARIABLE_SETTINGS VariableSettings;
740
741 if (!IsMtrrSupported ()) {
742 return 0;
743 }
744
745 MtrrGetVariableMtrrWorker (
746 NULL,
747 GetVariableMtrrCountWorker (),
748 &VariableSettings
749 );
750
751 return MtrrGetMemoryAttributeInVariableMtrrWorker (
752 &VariableSettings,
753 GetFirmwareVariableMtrrCountWorker (),
754 MtrrValidBitsMask,
755 MtrrValidAddressMask,
756 VariableMtrr
757 );
758}
759
760/**
761 Return the biggest alignment (lowest set bit) of address.
762 The function is equivalent to: 1 << LowBitSet64 (Address).
763
764 @param Address The address to return the alignment.
765 @param Alignment0 The alignment to return when Address is 0.
766
767 @return The least alignment of the Address.
768**/
769UINT64
770MtrrLibBiggestAlignment (
771 UINT64 Address,
772 UINT64 Alignment0
773 )
774{
775 if (Address == 0) {
776 return Alignment0;
777 }
778
779 return Address & ((~Address) + 1);
780}
781
782/**
783 Return whether the left MTRR type precedes the right MTRR type.
784
785 The MTRR type precedence rules are:
786 1. UC precedes any other type
787 2. WT precedes WB
788 For further details, please refer the IA32 Software Developer's Manual,
789 Volume 3, Section "MTRR Precedences".
790
791 @param Left The left MTRR type.
792 @param Right The right MTRR type.
793
794 @retval TRUE Left precedes Right.
795 @retval FALSE Left doesn't precede Right.
796**/
797BOOLEAN
798MtrrLibTypeLeftPrecedeRight (
799 IN MTRR_MEMORY_CACHE_TYPE Left,
800 IN MTRR_MEMORY_CACHE_TYPE Right
801 )
802{
803 return (BOOLEAN)(Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));
804}
805
806/**
807 Initializes the valid bits mask and valid address mask for MTRRs.
808
809 This function initializes the valid bits mask and valid address mask for MTRRs.
810
811 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
812 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
813
814**/
815VOID
816MtrrLibInitializeMtrrMask (
817 OUT UINT64 *MtrrValidBitsMask,
818 OUT UINT64 *MtrrValidAddressMask
819 )
820{
821 UINT32 MaxExtendedFunction;
822 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;
823 UINT32 MaxFunction;
824 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX ExtendedFeatureFlagsEcx;
825 MSR_IA32_TME_ACTIVATE_REGISTER TmeActivate;
826
827 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
828
829 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
830 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
831 } else {
832 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
833 }
834
835 //
836 // CPUID enumeration of MAX_PA is unaffected by TME-MK activation and will continue
837 // to report the maximum physical address bits available for software to use,
838 // irrespective of the number of KeyID bits.
839 // So, we need to check if TME is enabled and adjust the PA size accordingly.
840 //
841 AsmCpuid (CPUID_SIGNATURE, &MaxFunction, NULL, NULL, NULL);
842 if (MaxFunction >= CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
843 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0, NULL, NULL, &ExtendedFeatureFlagsEcx.Uint32, NULL);
844 if (ExtendedFeatureFlagsEcx.Bits.TME_EN == 1) {
845 TmeActivate.Uint64 = AsmReadMsr64 (MSR_IA32_TME_ACTIVATE);
846 if (TmeActivate.Bits.TmeEnable == 1) {
847 VirPhyAddressSize.Bits.PhysicalAddressBits -= TmeActivate.Bits.MkTmeKeyidBits;
848 }
849 }
850 }
851
852 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;
853 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
854}
855
856/**
857 Determines the real attribute of a memory range.
858
859 This function is to arbitrate the real attribute of the memory when
860 there are 2 MTRRs covers the same memory range. For further details,
861 please refer the IA32 Software Developer's Manual, Volume 3,
862 Section "MTRR Precedences".
863
864 @param[in] MtrrType1 The first kind of Memory type
865 @param[in] MtrrType2 The second kind of memory type
866
867**/
868MTRR_MEMORY_CACHE_TYPE
869MtrrLibPrecedence (
870 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,
871 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
872 )
873{
874 if (MtrrType1 == MtrrType2) {
875 return MtrrType1;
876 }
877
878 ASSERT (
879 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||
880 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)
881 );
882
883 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {
884 return MtrrType1;
885 } else {
886 return MtrrType2;
887 }
888}
889
890/**
891 Worker function will get the memory cache type of the specific address.
892
893 If MtrrSetting is not NULL, gets the memory cache type from input
894 MTRR settings buffer.
895 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
896
897 @param[in] MtrrSetting A buffer holding all MTRRs content.
898 @param[in] Address The specific address
899
900 @return Memory cache type of the specific address
901
902**/
903MTRR_MEMORY_CACHE_TYPE
904MtrrGetMemoryAttributeByAddressWorker (
905 IN MTRR_SETTINGS *MtrrSetting,
906 IN PHYSICAL_ADDRESS Address
907 )
908{
909 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
910 UINT64 FixedMtrr;
911 UINTN Index;
912 UINTN SubIndex;
913 MTRR_MEMORY_CACHE_TYPE MtrrType;
914 MTRR_MEMORY_RANGE VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
915 UINT64 MtrrValidBitsMask;
916 UINT64 MtrrValidAddressMask;
917 UINT32 VariableMtrrCount;
918 MTRR_VARIABLE_SETTINGS VariableSettings;
919
920 //
921 // Check if MTRR is enabled, if not, return UC as attribute
922 //
923 if (MtrrSetting == NULL) {
924 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
925 } else {
926 DefType.Uint64 = MtrrSetting->MtrrDefType;
927 }
928
929 if (DefType.Bits.E == 0) {
930 return CacheUncacheable;
931 }
932
933 //
934 // If address is less than 1M, then try to go through the fixed MTRR
935 //
936 if (Address < BASE_1MB) {
937 if (DefType.Bits.FE != 0) {
938 //
939 // Go through the fixed MTRR
940 //
941 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
942 if ((Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress) &&
943 (Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +
944 (mMtrrLibFixedMtrrTable[Index].Length * 8)))
945 {
946 SubIndex =
947 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
948 mMtrrLibFixedMtrrTable[Index].Length;
949 if (MtrrSetting == NULL) {
950 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
951 } else {
952 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];
953 }
954
955 return (MTRR_MEMORY_CACHE_TYPE)(RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);
956 }
957 }
958 }
959 }
960
961 VariableMtrrCount = GetVariableMtrrCountWorker ();
962 ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));
963 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);
964
965 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
966 MtrrLibGetRawVariableRanges (
967 &VariableSettings,
968 VariableMtrrCount,
969 MtrrValidBitsMask,
970 MtrrValidAddressMask,
971 VariableMtrr
972 );
973
974 //
975 // Go through the variable MTRR
976 //
977 MtrrType = CacheInvalid;
978 for (Index = 0; Index < VariableMtrrCount; Index++) {
979 if (VariableMtrr[Index].Length != 0) {
980 if ((Address >= VariableMtrr[Index].BaseAddress) &&
981 (Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length))
982 {
983 if (MtrrType == CacheInvalid) {
984 MtrrType = (MTRR_MEMORY_CACHE_TYPE)VariableMtrr[Index].Type;
985 } else {
986 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE)VariableMtrr[Index].Type);
987 }
988 }
989 }
990 }
991
992 //
993 // If there is no MTRR which covers the Address, use the default MTRR type.
994 //
995 if (MtrrType == CacheInvalid) {
996 MtrrType = (MTRR_MEMORY_CACHE_TYPE)DefType.Bits.Type;
997 }
998
999 return MtrrType;
1000}
1001
1002/**
1003 This function will get the memory cache type of the specific address.
1004
1005 This function is mainly for debug purpose.
1006
1007 @param[in] Address The specific address
1008
1009 @return Memory cache type of the specific address
1010
1011**/
1012MTRR_MEMORY_CACHE_TYPE
1013EFIAPI
1014MtrrGetMemoryAttribute (
1015 IN PHYSICAL_ADDRESS Address
1016 )
1017{
1018 if (!IsMtrrSupported ()) {
1019 return CacheUncacheable;
1020 }
1021
1022 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1023}
1024
1025/**
1026 Update the Ranges array to change the specified range identified by
1027 BaseAddress and Length to Type.
1028
1029 @param Ranges Array holding memory type settings for all memory regions.
1030 @param Capacity The maximum count of memory ranges the array can hold.
1031 @param Count Return the new memory range count in the array.
1032 @param BaseAddress The base address of the memory range to change type.
1033 @param Length The length of the memory range to change type.
1034 @param Type The new type of the specified memory range.
1035
1036 @retval RETURN_SUCCESS The type of the specified memory range is
1037 changed successfully.
1038 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
1039 to the desired type.
1040 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1041 range exceeds capacity.
1042**/
1043RETURN_STATUS
1044MtrrLibSetMemoryType (
1045 IN MTRR_MEMORY_RANGE *Ranges,
1046 IN UINTN Capacity,
1047 IN OUT UINTN *Count,
1048 IN UINT64 BaseAddress,
1049 IN UINT64 Length,
1050 IN MTRR_MEMORY_CACHE_TYPE Type
1051 )
1052{
1053 UINTN Index;
1054 UINT64 Limit;
1055 UINT64 LengthLeft;
1056 UINT64 LengthRight;
1057 UINTN StartIndex;
1058 UINTN EndIndex;
1059 UINTN DeltaCount;
1060
1061 ASSERT (Length != 0);
1062
1063 LengthRight = 0;
1064 LengthLeft = 0;
1065 Limit = BaseAddress + Length;
1066 StartIndex = *Count;
1067 EndIndex = *Count;
1068 for (Index = 0; Index < *Count; Index++) {
1069 if ((StartIndex == *Count) &&
1070 (Ranges[Index].BaseAddress <= BaseAddress) &&
1071 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length))
1072 {
1073 StartIndex = Index;
1074 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;
1075 }
1076
1077 if ((EndIndex == *Count) &&
1078 (Ranges[Index].BaseAddress < Limit) &&
1079 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length))
1080 {
1081 EndIndex = Index;
1082 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;
1083 break;
1084 }
1085 }
1086
1087 ASSERT (StartIndex != *Count && EndIndex != *Count);
1088 if ((StartIndex == EndIndex) && (Ranges[StartIndex].Type == Type)) {
1089 return RETURN_ALREADY_STARTED;
1090 }
1091
1092 //
1093 // The type change may cause merging with previous range or next range.
1094 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1095 // logic doesn't need to consider merging.
1096 //
1097 if (StartIndex != 0) {
1098 if ((LengthLeft == 0) && (Ranges[StartIndex - 1].Type == Type)) {
1099 StartIndex--;
1100 Length += Ranges[StartIndex].Length;
1101 BaseAddress -= Ranges[StartIndex].Length;
1102 }
1103 }
1104
1105 if (EndIndex != (*Count) - 1) {
1106 if ((LengthRight == 0) && (Ranges[EndIndex + 1].Type == Type)) {
1107 EndIndex++;
1108 Length += Ranges[EndIndex].Length;
1109 }
1110 }
1111
1112 //
1113 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1114 // |++++++++++++++++++| 0 3 1=3-0-2 3
1115 // |+++++++| 0 1 -1=1-0-2 5
1116 // |+| 0 0 -2=0-0-2 6
1117 // |+++| 0 0 -1=0-0-2+1 5
1118 //
1119 //
1120 DeltaCount = EndIndex - StartIndex - 2;
1121 if (LengthLeft == 0) {
1122 DeltaCount++;
1123 }
1124
1125 if (LengthRight == 0) {
1126 DeltaCount++;
1127 }
1128
1129 if (*Count - DeltaCount > Capacity) {
1130 return RETURN_OUT_OF_RESOURCES;
1131 }
1132
1133 //
1134 // Reserve (-DeltaCount) space
1135 //
1136 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));
1137 *Count -= DeltaCount;
1138
1139 if (LengthLeft != 0) {
1140 Ranges[StartIndex].Length = LengthLeft;
1141 StartIndex++;
1142 }
1143
1144 if (LengthRight != 0) {
1145 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;
1146 Ranges[EndIndex - DeltaCount].Length = LengthRight;
1147 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;
1148 }
1149
1150 Ranges[StartIndex].BaseAddress = BaseAddress;
1151 Ranges[StartIndex].Length = Length;
1152 Ranges[StartIndex].Type = Type;
1153 return RETURN_SUCCESS;
1154}
1155
1156/**
1157 Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1158
1159 @param Ranges Array holding memory type settings for all memory regions.
1160 @param RangeCount The count of memory ranges the array holds.
1161 @param BaseAddress Base address.
1162 @param Length Length.
1163 @param Types Return bit mask to indicate all memory types in the specified range.
1164
1165 @retval Number of memory types.
1166**/
1167UINT8
1168MtrrLibGetNumberOfTypes (
1169 IN CONST MTRR_MEMORY_RANGE *Ranges,
1170 IN UINTN RangeCount,
1171 IN UINT64 BaseAddress,
1172 IN UINT64 Length,
1173 IN OUT UINT8 *Types OPTIONAL
1174 )
1175{
1176 UINTN Index;
1177 UINT8 TypeCount;
1178 UINT8 LocalTypes;
1179
1180 TypeCount = 0;
1181 LocalTypes = 0;
1182 for (Index = 0; Index < RangeCount; Index++) {
1183 if ((Ranges[Index].BaseAddress <= BaseAddress) &&
1184 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)
1185 )
1186 {
1187 if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {
1188 LocalTypes |= (UINT8)(1 << Ranges[Index].Type);
1189 TypeCount++;
1190 }
1191
1192 if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
1193 Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;
1194 BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;
1195 } else {
1196 break;
1197 }
1198 }
1199 }
1200
1201 if (Types != NULL) {
1202 *Types = LocalTypes;
1203 }
1204
1205 return TypeCount;
1206}
1207
1208/**
1209 Calculate the least MTRR number from vertex Start to Stop and update
1210 the Previous of all vertices from Start to Stop is updated to reflect
1211 how the memory range is covered by MTRR.
1212
1213 @param VertexCount The count of vertices in the graph.
1214 @param Vertices Array holding all vertices.
1215 @param Weight 2-dimention array holding weights between vertices.
1216 @param Start Start vertex.
1217 @param Stop Stop vertex.
1218 @param IncludeOptional TRUE to count the optional weight.
1219**/
1220VOID
1221MtrrLibCalculateLeastMtrrs (
1222 IN UINT16 VertexCount,
1223 IN MTRR_LIB_ADDRESS *Vertices,
1224 IN OUT CONST UINT8 *Weight,
1225 IN UINT16 Start,
1226 IN UINT16 Stop,
1227 IN BOOLEAN IncludeOptional
1228 )
1229{
1230 UINT16 Index;
1231 UINT8 MinWeight;
1232 UINT16 MinI;
1233 UINT8 Mandatory;
1234 UINT8 Optional;
1235
1236 for (Index = Start; Index <= Stop; Index++) {
1237 Vertices[Index].Visited = FALSE;
1238 Mandatory = Weight[M (Start, Index)];
1239 Vertices[Index].Weight = Mandatory;
1240 if (Mandatory != MAX_WEIGHT) {
1241 Optional = IncludeOptional ? Weight[O (Start, Index)] : 0;
1242 Vertices[Index].Weight += Optional;
1243 ASSERT (Vertices[Index].Weight >= Optional);
1244 }
1245 }
1246
1247 MinI = Start;
1248 MinWeight = 0;
1249 while (!Vertices[Stop].Visited) {
1250 //
1251 // Update the weight from the shortest vertex to other unvisited vertices
1252 //
1253 for (Index = Start + 1; Index <= Stop; Index++) {
1254 if (!Vertices[Index].Visited) {
1255 Mandatory = Weight[M (MinI, Index)];
1256 if (Mandatory != MAX_WEIGHT) {
1257 Optional = IncludeOptional ? Weight[O (MinI, Index)] : 0;
1258 if (MinWeight + Mandatory + Optional <= Vertices[Index].Weight) {
1259 Vertices[Index].Weight = MinWeight + Mandatory + Optional;
1260 Vertices[Index].Previous = MinI; // Previous is Start based.
1261 }
1262 }
1263 }
1264 }
1265
1266 //
1267 // Find the shortest vertex from Start
1268 //
1269 MinI = VertexCount;
1270 MinWeight = MAX_WEIGHT;
1271 for (Index = Start + 1; Index <= Stop; Index++) {
1272 if (!Vertices[Index].Visited && (MinWeight > Vertices[Index].Weight)) {
1273 MinI = Index;
1274 MinWeight = Vertices[Index].Weight;
1275 }
1276 }
1277
1278 //
1279 // Mark the shortest vertex from Start as visited
1280 //
1281 Vertices[MinI].Visited = TRUE;
1282 }
1283}
1284
1285/**
1286 Append the MTRR setting to MTRR setting array.
1287
1288 @param Mtrrs Array holding all MTRR settings.
1289 @param MtrrCapacity Capacity of the MTRR array.
1290 @param MtrrCount The count of MTRR settings in array.
1291 @param BaseAddress Base address.
1292 @param Length Length.
1293 @param Type Memory type.
1294
1295 @retval RETURN_SUCCESS MTRR setting is appended to array.
1296 @retval RETURN_OUT_OF_RESOURCES Array is full.
1297**/
1298RETURN_STATUS
1299MtrrLibAppendVariableMtrr (
1300 IN OUT MTRR_MEMORY_RANGE *Mtrrs,
1301 IN UINT32 MtrrCapacity,
1302 IN OUT UINT32 *MtrrCount,
1303 IN UINT64 BaseAddress,
1304 IN UINT64 Length,
1305 IN MTRR_MEMORY_CACHE_TYPE Type
1306 )
1307{
1308 if (*MtrrCount == MtrrCapacity) {
1309 return RETURN_OUT_OF_RESOURCES;
1310 }
1311
1312 Mtrrs[*MtrrCount].BaseAddress = BaseAddress;
1313 Mtrrs[*MtrrCount].Length = Length;
1314 Mtrrs[*MtrrCount].Type = Type;
1315 (*MtrrCount)++;
1316 return RETURN_SUCCESS;
1317}
1318
1319/**
1320 Return the memory type that has the least precedence.
1321
1322 @param TypeBits Bit mask of memory type.
1323
1324 @retval Memory type that has the least precedence.
1325**/
1326MTRR_MEMORY_CACHE_TYPE
1327MtrrLibLowestType (
1328 IN UINT8 TypeBits
1329 )
1330{
1331 INT8 Type;
1332
1333 ASSERT (TypeBits != 0);
1334 for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1) {
1335 }
1336
1337 return (MTRR_MEMORY_CACHE_TYPE)Type;
1338}
1339
1340/**
1341 Calculate the subtractive path from vertex Start to Stop.
1342
1343 @param DefaultType Default memory type.
1344 @param A0 Alignment to use when base address is 0.
1345 @param Ranges Array holding memory type settings for all memory regions.
1346 @param RangeCount The count of memory ranges the array holds.
1347 @param VertexCount The count of vertices in the graph.
1348 @param Vertices Array holding all vertices.
1349 @param Weight 2-dimention array holding weights between vertices.
1350 @param Start Start vertex.
1351 @param Stop Stop vertex.
1352 @param Types Type bit mask of memory range from Start to Stop.
1353 @param TypeCount Number of different memory types from Start to Stop.
1354 @param Mtrrs Array holding all MTRR settings.
1355 @param MtrrCapacity Capacity of the MTRR array.
1356 @param MtrrCount The count of MTRR settings in array.
1357
1358 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1359 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1360
1361**/
1362RETURN_STATUS
1363MtrrLibCalculateSubtractivePath (
1364 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1365 IN UINT64 A0,
1366 IN CONST MTRR_MEMORY_RANGE *Ranges,
1367 IN UINTN RangeCount,
1368 IN UINT16 VertexCount,
1369 IN MTRR_LIB_ADDRESS *Vertices,
1370 IN OUT UINT8 *Weight,
1371 IN UINT16 Start,
1372 IN UINT16 Stop,
1373 IN UINT8 Types,
1374 IN UINT8 TypeCount,
1375 IN OUT MTRR_MEMORY_RANGE *Mtrrs OPTIONAL,
1376 IN UINT32 MtrrCapacity OPTIONAL,
1377 IN OUT UINT32 *MtrrCount OPTIONAL
1378 )
1379{
1380 RETURN_STATUS Status;
1381 UINT64 Base;
1382 UINT64 Length;
1383 UINT8 PrecedentTypes;
1384 UINTN Index;
1385 UINT64 HBase;
1386 UINT64 HLength;
1387 UINT64 SubLength;
1388 UINT16 SubStart;
1389 UINT16 SubStop;
1390 UINT16 Cur;
1391 UINT16 Pre;
1392 MTRR_MEMORY_CACHE_TYPE LowestType;
1393 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType;
1394
1395 Base = Vertices[Start].Address;
1396 Length = Vertices[Stop].Address - Base;
1397
1398 LowestType = MtrrLibLowestType (Types);
1399
1400 //
1401 // Clear the lowest type (highest bit) to get the precedent types
1402 //
1403 PrecedentTypes = ~(1 << LowestType) & Types;
1404 LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);
1405
1406 if (Mtrrs == NULL) {
1407 Weight[M (Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);
1408 Weight[O (Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);
1409 }
1410
1411 // Add all high level ranges
1412 HBase = MAX_UINT64;
1413 HLength = 0;
1414 for (Index = 0; Index < RangeCount; Index++) {
1415 if (Length == 0) {
1416 break;
1417 }
1418
1419 if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {
1420 continue;
1421 }
1422
1423 //
1424 // Base is in the Range[Index]
1425 //
1426 if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
1427 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;
1428 } else {
1429 SubLength = Length;
1430 }
1431
1432 if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {
1433 //
1434 // Meet a range whose types take precedence.
1435 // Update the [HBase, HBase + HLength) to include the range,
1436 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1437 //
1438 if (HBase == MAX_UINT64) {
1439 HBase = Base;
1440 }
1441
1442 HLength += SubLength;
1443 }
1444
1445 Base += SubLength;
1446 Length -= SubLength;
1447
1448 if (HLength == 0) {
1449 continue;
1450 }
1451
1452 if ((Ranges[Index].Type == LowestType) || (Length == 0)) {
1453 // meet low type or end
1454
1455 //
1456 // Add the MTRRs for each high priority type range
1457 // the range[HBase, HBase + HLength) contains only two types.
1458 // We might use positive or subtractive, depending on which way uses less MTRR
1459 //
1460 for (SubStart = Start; SubStart <= Stop; SubStart++) {
1461 if (Vertices[SubStart].Address == HBase) {
1462 break;
1463 }
1464 }
1465
1466 for (SubStop = SubStart; SubStop <= Stop; SubStop++) {
1467 if (Vertices[SubStop].Address == HBase + HLength) {
1468 break;
1469 }
1470 }
1471
1472 ASSERT (Vertices[SubStart].Address == HBase);
1473 ASSERT (Vertices[SubStop].Address == HBase + HLength);
1474
1475 if ((TypeCount == 2) || (SubStart == SubStop - 1)) {
1476 //
1477 // add subtractive MTRRs for [HBase, HBase + HLength)
1478 // [HBase, HBase + HLength) contains only one type.
1479 // while - loop is to split the range to MTRR - compliant aligned range.
1480 //
1481 if (Mtrrs == NULL) {
1482 Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);
1483 } else {
1484 while (SubStart != SubStop) {
1485 Status = MtrrLibAppendVariableMtrr (
1486 Mtrrs,
1487 MtrrCapacity,
1488 MtrrCount,
1489 Vertices[SubStart].Address,
1490 Vertices[SubStart].Length,
1491 Vertices[SubStart].Type
1492 );
1493 if (RETURN_ERROR (Status)) {
1494 return Status;
1495 }
1496
1497 SubStart++;
1498 }
1499 }
1500 } else {
1501 ASSERT (TypeCount == 3);
1502 MtrrLibCalculateLeastMtrrs (VertexCount, Vertices, Weight, SubStart, SubStop, TRUE);
1503
1504 if (Mtrrs == NULL) {
1505 Weight[M (Start, Stop)] += Vertices[SubStop].Weight;
1506 } else {
1507 // When we need to collect the optimal path from SubStart to SubStop
1508 while (SubStop != SubStart) {
1509 Cur = SubStop;
1510 Pre = Vertices[Cur].Previous;
1511 SubStop = Pre;
1512
1513 if (Weight[M (Pre, Cur)] + Weight[O (Pre, Cur)] != 0) {
1514 Status = MtrrLibAppendVariableMtrr (
1515 Mtrrs,
1516 MtrrCapacity,
1517 MtrrCount,
1518 Vertices[Pre].Address,
1519 Vertices[Cur].Address - Vertices[Pre].Address,
1520 (Pre != Cur - 1) ? LowestPrecedentType : Vertices[Pre].Type
1521 );
1522 if (RETURN_ERROR (Status)) {
1523 return Status;
1524 }
1525 }
1526
1527 if (Pre != Cur - 1) {
1528 Status = MtrrLibCalculateSubtractivePath (
1529 DefaultType,
1530 A0,
1531 Ranges,
1532 RangeCount,
1533 VertexCount,
1534 Vertices,
1535 Weight,
1536 Pre,
1537 Cur,
1538 PrecedentTypes,
1539 2,
1540 Mtrrs,
1541 MtrrCapacity,
1542 MtrrCount
1543 );
1544 if (RETURN_ERROR (Status)) {
1545 return Status;
1546 }
1547 }
1548 }
1549 }
1550 }
1551
1552 //
1553 // Reset HBase, HLength
1554 //
1555 HBase = MAX_UINT64;
1556 HLength = 0;
1557 }
1558 }
1559
1560 return RETURN_SUCCESS;
1561}
1562
1563/**
1564 Calculate MTRR settings to cover the specified memory ranges.
1565
1566 @param DefaultType Default memory type.
1567 @param A0 Alignment to use when base address is 0.
1568 @param Ranges Memory range array holding the memory type
1569 settings for all memory address.
1570 @param RangeCount Count of memory ranges.
1571 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1572 This is an optional parameter that may be NULL.
1573 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1574 It may be updated to the actual required size when the calculation
1575 needs more scratch buffer.
1576 @param Mtrrs Array holding all MTRR settings.
1577 @param MtrrCapacity Capacity of the MTRR array.
1578 @param MtrrCount The count of MTRR settings in array.
1579
1580 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1581 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1582 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1583**/
1584RETURN_STATUS
1585MtrrLibCalculateMtrrs (
1586 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1587 IN UINT64 A0,
1588 IN CONST MTRR_MEMORY_RANGE *Ranges,
1589 IN UINTN RangeCount,
1590 IN VOID *Scratch,
1591 IN OUT UINTN *ScratchSize,
1592 IN OUT MTRR_MEMORY_RANGE *Mtrrs,
1593 IN UINT32 MtrrCapacity,
1594 IN OUT UINT32 *MtrrCount
1595 )
1596{
1597 UINT64 Base0;
1598 UINT64 Base1;
1599 UINTN Index;
1600 UINT64 Base;
1601 UINT64 Length;
1602 UINT64 Alignment;
1603 UINT64 SubLength;
1604 MTRR_LIB_ADDRESS *Vertices;
1605 UINT8 *Weight;
1606 UINT32 VertexIndex;
1607 UINT32 VertexCount;
1608 UINTN RequiredScratchSize;
1609 UINT8 TypeCount;
1610 UINT16 Start;
1611 UINT16 Stop;
1612 UINT8 Type;
1613 RETURN_STATUS Status;
1614
1615 Base0 = Ranges[0].BaseAddress;
1616 Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;
1617 MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);
1618
1619 //
1620 // Count the number of vertices.
1621 //
1622 Vertices = (MTRR_LIB_ADDRESS *)Scratch;
1623 for (VertexIndex = 0, Index = 0; Index < RangeCount; Index++) {
1624 Base = Ranges[Index].BaseAddress;
1625 Length = Ranges[Index].Length;
1626 while (Length != 0) {
1627 Alignment = MtrrLibBiggestAlignment (Base, A0);
1628 SubLength = Alignment;
1629 if (SubLength > Length) {
1630 SubLength = GetPowerOfTwo64 (Length);
1631 }
1632
1633 if (VertexIndex < *ScratchSize / sizeof (*Vertices)) {
1634 Vertices[VertexIndex].Address = Base;
1635 Vertices[VertexIndex].Alignment = Alignment;
1636 Vertices[VertexIndex].Type = Ranges[Index].Type;
1637 Vertices[VertexIndex].Length = SubLength;
1638 }
1639
1640 Base += SubLength;
1641 Length -= SubLength;
1642 VertexIndex++;
1643 }
1644 }
1645
1646 //
1647 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1648 //
1649 VertexCount = VertexIndex + 1;
1650 DEBUG ((
1651 DEBUG_CACHE,
1652 " Count of vertices (%016llx - %016llx) = %d\n",
1653 Ranges[0].BaseAddress,
1654 Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length,
1655 VertexCount
1656 ));
1657 ASSERT (VertexCount < MAX_UINT16);
1658
1659 RequiredScratchSize = VertexCount * sizeof (*Vertices) + VertexCount * VertexCount * sizeof (*Weight);
1660 if (*ScratchSize < RequiredScratchSize) {
1661 *ScratchSize = RequiredScratchSize;
1662 return RETURN_BUFFER_TOO_SMALL;
1663 }
1664
1665 Vertices[VertexCount - 1].Address = Base1;
1666
1667 Weight = (UINT8 *)&Vertices[VertexCount];
1668 for (VertexIndex = 0; VertexIndex < VertexCount; VertexIndex++) {
1669 //
1670 // Set optional weight between vertices and self->self to 0
1671 //
1672 SetMem (&Weight[M (VertexIndex, 0)], VertexIndex + 1, 0);
1673 //
1674 // Set mandatory weight between vertices to MAX_WEIGHT
1675 //
1676 SetMem (&Weight[M (VertexIndex, VertexIndex + 1)], VertexCount - VertexIndex - 1, MAX_WEIGHT);
1677
1678 // Final result looks like:
1679 // 00 FF FF FF
1680 // 00 00 FF FF
1681 // 00 00 00 FF
1682 // 00 00 00 00
1683 }
1684
1685 //
1686 // Set mandatory weight and optional weight for adjacent vertices
1687 //
1688 for (VertexIndex = 0; VertexIndex < VertexCount - 1; VertexIndex++) {
1689 if (Vertices[VertexIndex].Type != DefaultType) {
1690 Weight[M (VertexIndex, VertexIndex + 1)] = 1;
1691 Weight[O (VertexIndex, VertexIndex + 1)] = 0;
1692 } else {
1693 Weight[M (VertexIndex, VertexIndex + 1)] = 0;
1694 Weight[O (VertexIndex, VertexIndex + 1)] = 1;
1695 }
1696 }
1697
1698 for (TypeCount = 2; TypeCount <= 3; TypeCount++) {
1699 for (Start = 0; Start < VertexCount; Start++) {
1700 for (Stop = Start + 2; Stop < VertexCount; Stop++) {
1701 ASSERT (Vertices[Stop].Address > Vertices[Start].Address);
1702 Length = Vertices[Stop].Address - Vertices[Start].Address;
1703 if (Length > Vertices[Start].Alignment) {
1704 //
1705 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1706 //
1707 break;
1708 }
1709
1710 if ((Weight[M (Start, Stop)] == MAX_WEIGHT) && IS_POW2 (Length)) {
1711 if (MtrrLibGetNumberOfTypes (
1712 Ranges,
1713 RangeCount,
1714 Vertices[Start].Address,
1715 Vertices[Stop].Address - Vertices[Start].Address,
1716 &Type
1717 ) == TypeCount)
1718 {
1719 //
1720 // Update the Weight[Start, Stop] using subtractive path.
1721 //
1722 MtrrLibCalculateSubtractivePath (
1723 DefaultType,
1724 A0,
1725 Ranges,
1726 RangeCount,
1727 (UINT16)VertexCount,
1728 Vertices,
1729 Weight,
1730 Start,
1731 Stop,
1732 Type,
1733 TypeCount,
1734 NULL,
1735 0,
1736 NULL
1737 );
1738 } else if (TypeCount == 2) {
1739 //
1740 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1741 // Because no matter how Stop is increased, we always meet 3-type range.
1742 //
1743 break;
1744 }
1745 }
1746 }
1747 }
1748 }
1749
1750 Status = RETURN_SUCCESS;
1751 MtrrLibCalculateLeastMtrrs ((UINT16)VertexCount, Vertices, Weight, 0, (UINT16)VertexCount - 1, FALSE);
1752 Stop = (UINT16)VertexCount - 1;
1753 while (Stop != 0) {
1754 Start = Vertices[Stop].Previous;
1755 TypeCount = MAX_UINT8;
1756 Type = 0;
1757 if (Weight[M (Start, Stop)] != 0) {
1758 TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type);
1759 Status = MtrrLibAppendVariableMtrr (
1760 Mtrrs,
1761 MtrrCapacity,
1762 MtrrCount,
1763 Vertices[Start].Address,
1764 Vertices[Stop].Address - Vertices[Start].Address,
1765 MtrrLibLowestType (Type)
1766 );
1767 if (RETURN_ERROR (Status)) {
1768 break;
1769 }
1770 }
1771
1772 if (Start != Stop - 1) {
1773 //
1774 // substractive path
1775 //
1776 if (TypeCount == MAX_UINT8) {
1777 TypeCount = MtrrLibGetNumberOfTypes (
1778 Ranges,
1779 RangeCount,
1780 Vertices[Start].Address,
1781 Vertices[Stop].Address - Vertices[Start].Address,
1782 &Type
1783 );
1784 }
1785
1786 Status = MtrrLibCalculateSubtractivePath (
1787 DefaultType,
1788 A0,
1789 Ranges,
1790 RangeCount,
1791 (UINT16)VertexCount,
1792 Vertices,
1793 Weight,
1794 Start,
1795 Stop,
1796 Type,
1797 TypeCount,
1798 Mtrrs,
1799 MtrrCapacity,
1800 MtrrCount
1801 );
1802 if (RETURN_ERROR (Status)) {
1803 break;
1804 }
1805 }
1806
1807 Stop = Start;
1808 }
1809
1810 return Status;
1811}
1812
1813/**
1814 Apply the fixed MTRR settings to memory range array.
1815
1816 @param Fixed The fixed MTRR settings.
1817 @param Ranges Return the memory range array holding memory type
1818 settings for all memory address.
1819 @param RangeCapacity The capacity of memory range array.
1820 @param RangeCount Return the count of memory range.
1821
1822 @retval RETURN_SUCCESS The memory range array is returned successfully.
1823 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1824**/
1825RETURN_STATUS
1826MtrrLibApplyFixedMtrrs (
1827 IN CONST MTRR_FIXED_SETTINGS *Fixed,
1828 IN OUT MTRR_MEMORY_RANGE *Ranges,
1829 IN UINTN RangeCapacity,
1830 IN OUT UINTN *RangeCount
1831 )
1832{
1833 RETURN_STATUS Status;
1834 UINTN MsrIndex;
1835 UINTN Index;
1836 MTRR_MEMORY_CACHE_TYPE MemoryType;
1837 UINT64 Base;
1838
1839 Base = 0;
1840 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
1841 ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);
1842 for (Index = 0; Index < sizeof (UINT64); Index++) {
1843 MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];
1844 Status = MtrrLibSetMemoryType (
1845 Ranges,
1846 RangeCapacity,
1847 RangeCount,
1848 Base,
1849 mMtrrLibFixedMtrrTable[MsrIndex].Length,
1850 MemoryType
1851 );
1852 if (Status == RETURN_OUT_OF_RESOURCES) {
1853 return Status;
1854 }
1855
1856 Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;
1857 }
1858 }
1859
1860 ASSERT (Base == BASE_1MB);
1861 return RETURN_SUCCESS;
1862}
1863
1864/**
1865 Apply the variable MTRR settings to memory range array.
1866
1867 @param VariableMtrr The variable MTRR array.
1868 @param VariableMtrrCount The count of variable MTRRs.
1869 @param Ranges Return the memory range array with new MTRR settings applied.
1870 @param RangeCapacity The capacity of memory range array.
1871 @param RangeCount Return the count of memory range.
1872
1873 @retval RETURN_SUCCESS The memory range array is returned successfully.
1874 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1875**/
1876RETURN_STATUS
1877MtrrLibApplyVariableMtrrs (
1878 IN CONST MTRR_MEMORY_RANGE *VariableMtrr,
1879 IN UINT32 VariableMtrrCount,
1880 IN OUT MTRR_MEMORY_RANGE *Ranges,
1881 IN UINTN RangeCapacity,
1882 IN OUT UINTN *RangeCount
1883 )
1884{
1885 RETURN_STATUS Status;
1886 UINTN Index;
1887
1888 //
1889 // WT > WB
1890 // UC > *
1891 // UC > * (except WB, UC) > WB
1892 //
1893
1894 //
1895 // 1. Set WB
1896 //
1897 for (Index = 0; Index < VariableMtrrCount; Index++) {
1898 if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {
1899 Status = MtrrLibSetMemoryType (
1900 Ranges,
1901 RangeCapacity,
1902 RangeCount,
1903 VariableMtrr[Index].BaseAddress,
1904 VariableMtrr[Index].Length,
1905 VariableMtrr[Index].Type
1906 );
1907 if (Status == RETURN_OUT_OF_RESOURCES) {
1908 return Status;
1909 }
1910 }
1911 }
1912
1913 //
1914 // 2. Set other types than WB or UC
1915 //
1916 for (Index = 0; Index < VariableMtrrCount; Index++) {
1917 if ((VariableMtrr[Index].Length != 0) &&
1918 (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable))
1919 {
1920 Status = MtrrLibSetMemoryType (
1921 Ranges,
1922 RangeCapacity,
1923 RangeCount,
1924 VariableMtrr[Index].BaseAddress,
1925 VariableMtrr[Index].Length,
1926 VariableMtrr[Index].Type
1927 );
1928 if (Status == RETURN_OUT_OF_RESOURCES) {
1929 return Status;
1930 }
1931 }
1932 }
1933
1934 //
1935 // 3. Set UC
1936 //
1937 for (Index = 0; Index < VariableMtrrCount; Index++) {
1938 if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheUncacheable)) {
1939 Status = MtrrLibSetMemoryType (
1940 Ranges,
1941 RangeCapacity,
1942 RangeCount,
1943 VariableMtrr[Index].BaseAddress,
1944 VariableMtrr[Index].Length,
1945 VariableMtrr[Index].Type
1946 );
1947 if (Status == RETURN_OUT_OF_RESOURCES) {
1948 return Status;
1949 }
1950 }
1951 }
1952
1953 return RETURN_SUCCESS;
1954}
1955
1956/**
1957 Return the memory type bit mask that's compatible to first type in the Ranges.
1958
1959 @param Ranges Memory range array holding the memory type
1960 settings for all memory address.
1961 @param RangeCount Count of memory ranges.
1962
1963 @return Compatible memory type bit mask.
1964**/
1965UINT8
1966MtrrLibGetCompatibleTypes (
1967 IN CONST MTRR_MEMORY_RANGE *Ranges,
1968 IN UINTN RangeCount
1969 )
1970{
1971 ASSERT (RangeCount != 0);
1972
1973 switch (Ranges[0].Type) {
1974 case CacheWriteBack:
1975 case CacheWriteThrough:
1976 return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);
1977 break;
1978
1979 case CacheWriteCombining:
1980 case CacheWriteProtected:
1981 return (1 << Ranges[0].Type) | (1 << CacheUncacheable);
1982 break;
1983
1984 case CacheUncacheable:
1985 if (RangeCount == 1) {
1986 return (1 << CacheUncacheable);
1987 }
1988
1989 return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);
1990 break;
1991
1992 case CacheInvalid:
1993 default:
1994 ASSERT (FALSE);
1995 break;
1996 }
1997
1998 return 0;
1999}
2000
2001/**
2002 Overwrite the destination MTRR settings with the source MTRR settings.
2003 This routine is to make sure the modification to destination MTRR settings
2004 is as small as possible.
2005
2006 @param DstMtrrs Destination MTRR settings.
2007 @param DstMtrrCount Count of destination MTRR settings.
2008 @param SrcMtrrs Source MTRR settings.
2009 @param SrcMtrrCount Count of source MTRR settings.
2010 @param Modified Flag array to indicate which destination MTRR setting is modified.
2011**/
2012VOID
2013MtrrLibMergeVariableMtrr (
2014 MTRR_MEMORY_RANGE *DstMtrrs,
2015 UINT32 DstMtrrCount,
2016 MTRR_MEMORY_RANGE *SrcMtrrs,
2017 UINT32 SrcMtrrCount,
2018 BOOLEAN *Modified
2019 )
2020{
2021 UINT32 DstIndex;
2022 UINT32 SrcIndex;
2023
2024 ASSERT (SrcMtrrCount <= DstMtrrCount);
2025
2026 for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {
2027 Modified[DstIndex] = FALSE;
2028
2029 if (DstMtrrs[DstIndex].Length == 0) {
2030 continue;
2031 }
2032
2033 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
2034 if ((DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress) &&
2035 (DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length) &&
2036 (DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type))
2037 {
2038 break;
2039 }
2040 }
2041
2042 if (SrcIndex == SrcMtrrCount) {
2043 //
2044 // Remove the one from DstMtrrs which is not in SrcMtrrs
2045 //
2046 DstMtrrs[DstIndex].Length = 0;
2047 Modified[DstIndex] = TRUE;
2048 } else {
2049 //
2050 // Remove the one from SrcMtrrs which is also in DstMtrrs
2051 //
2052 SrcMtrrs[SrcIndex].Length = 0;
2053 }
2054 }
2055
2056 //
2057 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
2058 // Merge MTRRs from SrcMtrrs to DstMtrrs
2059 //
2060 DstIndex = 0;
2061 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
2062 if (SrcMtrrs[SrcIndex].Length != 0) {
2063 //
2064 // Find the empty slot in DstMtrrs
2065 //
2066 while (DstIndex < DstMtrrCount) {
2067 if (DstMtrrs[DstIndex].Length == 0) {
2068 break;
2069 }
2070
2071 DstIndex++;
2072 }
2073
2074 ASSERT (DstIndex < DstMtrrCount);
2075 CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));
2076 Modified[DstIndex] = TRUE;
2077 }
2078 }
2079}
2080
2081/**
2082 Calculate the variable MTRR settings for all memory ranges.
2083
2084 @param DefaultType Default memory type.
2085 @param A0 Alignment to use when base address is 0.
2086 @param Ranges Memory range array holding the memory type
2087 settings for all memory address.
2088 @param RangeCount Count of memory ranges.
2089 @param Scratch Scratch buffer to be used in MTRR calculation.
2090 @param ScratchSize Pointer to the size of scratch buffer.
2091 @param VariableMtrr Array holding all MTRR settings.
2092 @param VariableMtrrCapacity Capacity of the MTRR array.
2093 @param VariableMtrrCount The count of MTRR settings in array.
2094
2095 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
2096 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
2097 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2098 The required scratch buffer size is returned through ScratchSize.
2099**/
2100RETURN_STATUS
2101MtrrLibSetMemoryRanges (
2102 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
2103 IN UINT64 A0,
2104 IN MTRR_MEMORY_RANGE *Ranges,
2105 IN UINTN RangeCount,
2106 IN VOID *Scratch,
2107 IN OUT UINTN *ScratchSize,
2108 OUT MTRR_MEMORY_RANGE *VariableMtrr,
2109 IN UINT32 VariableMtrrCapacity,
2110 OUT UINT32 *VariableMtrrCount
2111 )
2112{
2113 RETURN_STATUS Status;
2114 UINT32 Index;
2115 UINT64 Base0;
2116 UINT64 Base1;
2117 UINT64 Alignment;
2118 UINT8 CompatibleTypes;
2119 UINT64 Length;
2120 UINT32 End;
2121 UINTN ActualScratchSize;
2122 UINTN BiggestScratchSize;
2123
2124 *VariableMtrrCount = 0;
2125
2126 //
2127 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
2128 // Each call needs different scratch buffer size.
2129 // When the provided scratch buffer size is not sufficient in any call,
2130 // set the GetActualScratchSize to TRUE, and following calls will only
2131 // calculate the actual scratch size for the caller.
2132 //
2133 BiggestScratchSize = 0;
2134
2135 for (Index = 0; Index < RangeCount;) {
2136 Base0 = Ranges[Index].BaseAddress;
2137
2138 //
2139 // Full step is optimal
2140 //
2141 while (Index < RangeCount) {
2142 ASSERT (Ranges[Index].BaseAddress == Base0);
2143 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2144 while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {
2145 if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {
2146 Status = MtrrLibAppendVariableMtrr (
2147 VariableMtrr,
2148 VariableMtrrCapacity,
2149 VariableMtrrCount,
2150 Base0,
2151 Alignment,
2152 Ranges[Index].Type
2153 );
2154 if (RETURN_ERROR (Status)) {
2155 return Status;
2156 }
2157 }
2158
2159 Base0 += Alignment;
2160 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2161 }
2162
2163 //
2164 // Remove the above range from Ranges[Index]
2165 //
2166 Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;
2167 Ranges[Index].BaseAddress = Base0;
2168 if (Ranges[Index].Length != 0) {
2169 break;
2170 } else {
2171 Index++;
2172 }
2173 }
2174
2175 if (Index == RangeCount) {
2176 break;
2177 }
2178
2179 //
2180 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2181 // Per SDM, the compatible types between[B0, B1) are:
2182 // UC, *
2183 // WB, WT
2184 // UC, WB, WT
2185 //
2186 CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);
2187
2188 End = Index; // End points to last one that matches the CompatibleTypes.
2189 while (End + 1 < RangeCount) {
2190 if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {
2191 break;
2192 }
2193
2194 End++;
2195 }
2196
2197 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2198 Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);
2199 Base1 = Base0 + MIN (Alignment, Length);
2200
2201 //
2202 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2203 //
2204 End = Index;
2205 while (End + 1 < RangeCount) {
2206 if (Base1 <= Ranges[End + 1].BaseAddress) {
2207 break;
2208 }
2209
2210 End++;
2211 }
2212
2213 Length = Ranges[End].Length;
2214 Ranges[End].Length = Base1 - Ranges[End].BaseAddress;
2215 ActualScratchSize = *ScratchSize;
2216 Status = MtrrLibCalculateMtrrs (
2217 DefaultType,
2218 A0,
2219 &Ranges[Index],
2220 End + 1 - Index,
2221 Scratch,
2222 &ActualScratchSize,
2223 VariableMtrr,
2224 VariableMtrrCapacity,
2225 VariableMtrrCount
2226 );
2227 if (Status == RETURN_BUFFER_TOO_SMALL) {
2228 BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);
2229 //
2230 // Ignore this error, because we need to calculate the biggest
2231 // scratch buffer size.
2232 //
2233 Status = RETURN_SUCCESS;
2234 }
2235
2236 if (RETURN_ERROR (Status)) {
2237 return Status;
2238 }
2239
2240 if (Length != Ranges[End].Length) {
2241 Ranges[End].BaseAddress = Base1;
2242 Ranges[End].Length = Length - Ranges[End].Length;
2243 Index = End;
2244 } else {
2245 Index = End + 1;
2246 }
2247 }
2248
2249 if (*ScratchSize < BiggestScratchSize) {
2250 *ScratchSize = BiggestScratchSize;
2251 return RETURN_BUFFER_TOO_SMALL;
2252 }
2253
2254 return RETURN_SUCCESS;
2255}
2256
2257/**
2258 Set the below-1MB memory attribute to fixed MTRR buffer.
2259 Modified flag array indicates which fixed MTRR is modified.
2260
2261 @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
2262 @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
2263 @param [in] BaseAddress Base address.
2264 @param [in] Length Length.
2265 @param [in] Type Memory type.
2266
2267 @retval RETURN_SUCCESS The memory attribute is set successfully.
2268 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2269 for the fixed MTRRs.
2270**/
2271RETURN_STATUS
2272MtrrLibSetBelow1MBMemoryAttribute (
2273 IN OUT UINT64 *ClearMasks,
2274 IN OUT UINT64 *OrMasks,
2275 IN PHYSICAL_ADDRESS BaseAddress,
2276 IN UINT64 Length,
2277 IN MTRR_MEMORY_CACHE_TYPE Type
2278 )
2279{
2280 RETURN_STATUS Status;
2281 UINT32 MsrIndex;
2282 UINT64 ClearMask;
2283 UINT64 OrMask;
2284
2285 ASSERT (BaseAddress < BASE_1MB);
2286
2287 MsrIndex = (UINT32)-1;
2288 while ((BaseAddress < BASE_1MB) && (Length != 0)) {
2289 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
2290 if (RETURN_ERROR (Status)) {
2291 return Status;
2292 }
2293
2294 ClearMasks[MsrIndex] = ClearMasks[MsrIndex] | ClearMask;
2295 OrMasks[MsrIndex] = (OrMasks[MsrIndex] & ~ClearMask) | OrMask;
2296 }
2297
2298 return RETURN_SUCCESS;
2299}
2300
2301/**
2302 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2303
2304 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2305 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2306 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2307 It may be updated to the actual required size when the calculation
2308 needs more scratch buffer.
2309 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2310 When range overlap happens, the last one takes higher priority.
2311 When the function returns, either all the attributes are set successfully,
2312 or none of them is set.
2313 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2314
2315 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2316 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2317 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2318 memory resource range specified by BaseAddress and Length in any range.
2319 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2320 range specified by BaseAddress and Length in any range.
2321 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2322 the memory resource ranges.
2323 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2324 BaseAddress and Length cannot be modified.
2325 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2326**/
2327RETURN_STATUS
2328EFIAPI
2329MtrrSetMemoryAttributesInMtrrSettings (
2330 IN OUT MTRR_SETTINGS *MtrrSetting,
2331 IN VOID *Scratch,
2332 IN OUT UINTN *ScratchSize,
2333 IN CONST MTRR_MEMORY_RANGE *Ranges,
2334 IN UINTN RangeCount
2335 )
2336{
2337 RETURN_STATUS Status;
2338 UINT32 Index;
2339 UINT64 BaseAddress;
2340 UINT64 Length;
2341 BOOLEAN VariableMtrrNeeded;
2342
2343 UINT64 MtrrValidBitsMask;
2344 UINT64 MtrrValidAddressMask;
2345 MTRR_MEMORY_CACHE_TYPE DefaultType;
2346 MTRR_VARIABLE_SETTINGS VariableSettings;
2347 MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];
2348 UINTN WorkingRangeCount;
2349 BOOLEAN Modified;
2350 MTRR_VARIABLE_SETTING VariableSetting;
2351 UINT32 OriginalVariableMtrrCount;
2352 UINT32 FirmwareVariableMtrrCount;
2353 UINT32 WorkingVariableMtrrCount;
2354 MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2355 MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2356 BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2357
2358 UINT64 FixedMtrrMemoryLimit;
2359 BOOLEAN FixedMtrrSupported;
2360 UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2361 UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2362
2363 MTRR_CONTEXT MtrrContext;
2364 BOOLEAN MtrrContextValid;
2365
2366 Status = RETURN_SUCCESS;
2367 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
2368
2369 //
2370 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2371 //
2372 SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);
2373
2374 //
2375 // TRUE indicating the caller requests to set variable MTRRs.
2376 //
2377 VariableMtrrNeeded = FALSE;
2378 OriginalVariableMtrrCount = 0;
2379
2380 //
2381 // 0. Dump the requests.
2382 //
2383 DEBUG_CODE_BEGIN ();
2384 DEBUG ((
2385 DEBUG_CACHE,
2386 "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2387 (MtrrSetting == NULL) ? "Hardware" : "Buffer",
2388 *ScratchSize,
2389 (RangeCount <= 1) ? "," : "\n"
2390 ));
2391 for (Index = 0; Index < RangeCount; Index++) {
2392 DEBUG ((
2393 DEBUG_CACHE,
2394 " %a: [%016lx, %016lx)\n",
2395 mMtrrMemoryCacheTypeShortName[MIN (Ranges[Index].Type, CacheInvalid)],
2396 Ranges[Index].BaseAddress,
2397 Ranges[Index].BaseAddress + Ranges[Index].Length
2398 ));
2399 }
2400
2401 DEBUG_CODE_END ();
2402
2403 //
2404 // 1. Validate the parameters.
2405 //
2406 if (!MtrrLibIsMtrrSupported (&FixedMtrrSupported, &OriginalVariableMtrrCount)) {
2407 Status = RETURN_UNSUPPORTED;
2408 goto Exit;
2409 }
2410
2411 FixedMtrrMemoryLimit = FixedMtrrSupported ? BASE_1MB : 0;
2412
2413 for (Index = 0; Index < RangeCount; Index++) {
2414 if (Ranges[Index].Length == 0) {
2415 Status = RETURN_INVALID_PARAMETER;
2416 goto Exit;
2417 }
2418
2419 if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||
2420 ((((Ranges[Index].BaseAddress + Ranges[Index].Length) & ~MtrrValidAddressMask) != 0) &&
2421 ((Ranges[Index].BaseAddress + Ranges[Index].Length) != MtrrValidBitsMask + 1))
2422 )
2423 {
2424 //
2425 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2426 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2427 //
2428 Status = RETURN_UNSUPPORTED;
2429 goto Exit;
2430 }
2431
2432 if ((Ranges[Index].Type != CacheUncacheable) &&
2433 (Ranges[Index].Type != CacheWriteCombining) &&
2434 (Ranges[Index].Type != CacheWriteThrough) &&
2435 (Ranges[Index].Type != CacheWriteProtected) &&
2436 (Ranges[Index].Type != CacheWriteBack))
2437 {
2438 Status = RETURN_INVALID_PARAMETER;
2439 goto Exit;
2440 }
2441
2442 if (Ranges[Index].BaseAddress + Ranges[Index].Length > FixedMtrrMemoryLimit) {
2443 VariableMtrrNeeded = TRUE;
2444 }
2445 }
2446
2447 //
2448 // 2. Apply the above-1MB memory attribute settings.
2449 //
2450 if (VariableMtrrNeeded) {
2451 //
2452 // 2.1. Read all variable MTRRs and convert to Ranges.
2453 //
2454 MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);
2455 MtrrLibGetRawVariableRanges (
2456 &VariableSettings,
2457 OriginalVariableMtrrCount,
2458 MtrrValidBitsMask,
2459 MtrrValidAddressMask,
2460 OriginalVariableMtrr
2461 );
2462
2463 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
2464 WorkingRangeCount = 1;
2465 WorkingRanges[0].BaseAddress = 0;
2466 WorkingRanges[0].Length = MtrrValidBitsMask + 1;
2467 WorkingRanges[0].Type = DefaultType;
2468
2469 Status = MtrrLibApplyVariableMtrrs (
2470 OriginalVariableMtrr,
2471 OriginalVariableMtrrCount,
2472 WorkingRanges,
2473 ARRAY_SIZE (WorkingRanges),
2474 &WorkingRangeCount
2475 );
2476 ASSERT_RETURN_ERROR (Status);
2477
2478 ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));
2479 FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
2480 ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);
2481
2482 //
2483 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2484 //
2485 if (FixedMtrrMemoryLimit != 0) {
2486 Status = MtrrLibSetMemoryType (
2487 WorkingRanges,
2488 ARRAY_SIZE (WorkingRanges),
2489 &WorkingRangeCount,
2490 0,
2491 FixedMtrrMemoryLimit,
2492 CacheUncacheable
2493 );
2494 ASSERT (Status != RETURN_OUT_OF_RESOURCES);
2495 }
2496
2497 //
2498 // 2.3. Apply the new memory attribute settings to Ranges.
2499 //
2500 Modified = FALSE;
2501 for (Index = 0; Index < RangeCount; Index++) {
2502 BaseAddress = Ranges[Index].BaseAddress;
2503 Length = Ranges[Index].Length;
2504 if (BaseAddress < FixedMtrrMemoryLimit) {
2505 if (Length <= FixedMtrrMemoryLimit - BaseAddress) {
2506 continue;
2507 }
2508
2509 Length -= FixedMtrrMemoryLimit - BaseAddress;
2510 BaseAddress = FixedMtrrMemoryLimit;
2511 }
2512
2513 Status = MtrrLibSetMemoryType (
2514 WorkingRanges,
2515 ARRAY_SIZE (WorkingRanges),
2516 &WorkingRangeCount,
2517 BaseAddress,
2518 Length,
2519 Ranges[Index].Type
2520 );
2521 if (Status == RETURN_ALREADY_STARTED) {
2522 Status = RETURN_SUCCESS;
2523 } else if (Status == RETURN_OUT_OF_RESOURCES) {
2524 goto Exit;
2525 } else {
2526 ASSERT_RETURN_ERROR (Status);
2527 Modified = TRUE;
2528 }
2529 }
2530
2531 if (Modified) {
2532 //
2533 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2534 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2535 //
2536 Status = MtrrLibSetMemoryRanges (
2537 DefaultType,
2538 LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)),
2539 WorkingRanges,
2540 WorkingRangeCount,
2541 Scratch,
2542 ScratchSize,
2543 WorkingVariableMtrr,
2544 FirmwareVariableMtrrCount + 1,
2545 &WorkingVariableMtrrCount
2546 );
2547 if (RETURN_ERROR (Status)) {
2548 goto Exit;
2549 }
2550
2551 //
2552 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2553 //
2554 for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {
2555 if ((WorkingVariableMtrr[Index].BaseAddress == 0) && (WorkingVariableMtrr[Index].Length == FixedMtrrMemoryLimit)) {
2556 ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);
2557 WorkingVariableMtrrCount--;
2558 CopyMem (
2559 &WorkingVariableMtrr[Index],
2560 &WorkingVariableMtrr[Index + 1],
2561 (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])
2562 );
2563 break;
2564 }
2565 }
2566
2567 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
2568 Status = RETURN_OUT_OF_RESOURCES;
2569 goto Exit;
2570 }
2571
2572 //
2573 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2574 // Make sure least modification is made to OriginalVariableMtrr.
2575 //
2576 MtrrLibMergeVariableMtrr (
2577 OriginalVariableMtrr,
2578 OriginalVariableMtrrCount,
2579 WorkingVariableMtrr,
2580 WorkingVariableMtrrCount,
2581 VariableSettingModified
2582 );
2583 }
2584 }
2585
2586 //
2587 // 3. Apply the below-1MB memory attribute settings.
2588 //
2589 // (Value & ~0 | 0) still equals to (Value)
2590 //
2591 ZeroMem (ClearMasks, sizeof (ClearMasks));
2592 ZeroMem (OrMasks, sizeof (OrMasks));
2593 for (Index = 0; Index < RangeCount; Index++) {
2594 if (Ranges[Index].BaseAddress >= FixedMtrrMemoryLimit) {
2595 continue;
2596 }
2597
2598 Status = MtrrLibSetBelow1MBMemoryAttribute (
2599 ClearMasks,
2600 OrMasks,
2601 Ranges[Index].BaseAddress,
2602 Ranges[Index].Length,
2603 Ranges[Index].Type
2604 );
2605 if (RETURN_ERROR (Status)) {
2606 goto Exit;
2607 }
2608 }
2609
2610 MtrrContextValid = FALSE;
2611 //
2612 // 4. Write fixed MTRRs that have been modified
2613 //
2614 for (Index = 0; Index < ARRAY_SIZE (ClearMasks); Index++) {
2615 if (ClearMasks[Index] != 0) {
2616 if (MtrrSetting != NULL) {
2617 //
2618 // Fixed MTRR is modified indicating fixed MTRR should be enabled in the end of MTRR programming.
2619 //
2620 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;
2621 MtrrSetting->Fixed.Mtrr[Index] = (MtrrSetting->Fixed.Mtrr[Index] & ~ClearMasks[Index]) | OrMasks[Index];
2622 } else {
2623 if (!MtrrContextValid) {
2624 MtrrLibPreMtrrChange (&MtrrContext);
2625 //
2626 // Fixed MTRR is modified indicating fixed MTRR should be enabled in the end of MTRR programming.
2627 //
2628 MtrrContext.DefType.Bits.FE = 1;
2629 MtrrContextValid = TRUE;
2630 }
2631
2632 AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable[Index].Msr, ~ClearMasks[Index], OrMasks[Index]);
2633 }
2634 }
2635 }
2636
2637 //
2638 // 5. Write variable MTRRs that have been modified
2639 //
2640 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2641 if (VariableSettingModified[Index]) {
2642 if (OriginalVariableMtrr[Index].Length != 0) {
2643 VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)
2644 | (UINT8)OriginalVariableMtrr[Index].Type;
2645 VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;
2646 } else {
2647 VariableSetting.Base = 0;
2648 VariableSetting.Mask = 0;
2649 }
2650
2651 if (MtrrSetting != NULL) {
2652 CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));
2653 } else {
2654 if (!MtrrContextValid) {
2655 MtrrLibPreMtrrChange (&MtrrContext);
2656 MtrrContextValid = TRUE;
2657 }
2658
2659 AsmWriteMsr64 (
2660 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2661 VariableSetting.Base
2662 );
2663 AsmWriteMsr64 (
2664 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2665 VariableSetting.Mask
2666 );
2667 }
2668 }
2669 }
2670
2671 if (MtrrSetting != NULL) {
2672 //
2673 // Enable MTRR unconditionally
2674 //
2675 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;
2676 } else {
2677 if (MtrrContextValid) {
2678 MtrrLibPostMtrrChange (&MtrrContext);
2679 }
2680 }
2681
2682Exit:
2683 DEBUG ((DEBUG_CACHE, " Result = %r\n", Status));
2684 if (!RETURN_ERROR (Status)) {
2685 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
2686 }
2687
2688 return Status;
2689}
2690
2691/**
2692 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2693
2694 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2695 @param[in] BaseAddress The physical address that is the start address
2696 of a memory range.
2697 @param[in] Length The size in bytes of the memory range.
2698 @param[in] Attribute The bit mask of attributes to set for the
2699 memory range.
2700
2701 @retval RETURN_SUCCESS The attributes were set for the memory range.
2702 @retval RETURN_INVALID_PARAMETER Length is zero.
2703 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2704 memory resource range specified by BaseAddress and Length.
2705 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2706 range specified by BaseAddress and Length.
2707 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2708 BaseAddress and Length cannot be modified.
2709 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2710 the memory resource range.
2711 Multiple memory range attributes setting by calling this API multiple
2712 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2713 the number of CPU MTRRs are too small to set such memory attributes.
2714 Pass the multiple memory range attributes to one call of
2715 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2716 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2717 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2718 external scratch buffer.
2719**/
2720RETURN_STATUS
2721EFIAPI
2722MtrrSetMemoryAttributeInMtrrSettings (
2723 IN OUT MTRR_SETTINGS *MtrrSetting,
2724 IN PHYSICAL_ADDRESS BaseAddress,
2725 IN UINT64 Length,
2726 IN MTRR_MEMORY_CACHE_TYPE Attribute
2727 )
2728{
2729 UINT8 Scratch[SCRATCH_BUFFER_SIZE];
2730 UINTN ScratchSize;
2731 MTRR_MEMORY_RANGE Range;
2732
2733 Range.BaseAddress = BaseAddress;
2734 Range.Length = Length;
2735 Range.Type = Attribute;
2736 ScratchSize = sizeof (Scratch);
2737 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);
2738}
2739
2740/**
2741 This function attempts to set the attributes for a memory range.
2742
2743 @param[in] BaseAddress The physical address that is the start
2744 address of a memory range.
2745 @param[in] Length The size in bytes of the memory range.
2746 @param[in] Attributes The bit mask of attributes to set for the
2747 memory range.
2748
2749 @retval RETURN_SUCCESS The attributes were set for the memory
2750 range.
2751 @retval RETURN_INVALID_PARAMETER Length is zero.
2752 @retval RETURN_UNSUPPORTED The processor does not support one or
2753 more bytes of the memory resource range
2754 specified by BaseAddress and Length.
2755 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2756 for the memory resource range specified
2757 by BaseAddress and Length.
2758 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2759 range specified by BaseAddress and Length
2760 cannot be modified.
2761 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2762 modify the attributes of the memory
2763 resource range.
2764 Multiple memory range attributes setting by calling this API multiple
2765 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2766 the number of CPU MTRRs are too small to set such memory attributes.
2767 Pass the multiple memory range attributes to one call of
2768 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2769 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2770 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2771 external scratch buffer.
2772**/
2773RETURN_STATUS
2774EFIAPI
2775MtrrSetMemoryAttribute (
2776 IN PHYSICAL_ADDRESS BaseAddress,
2777 IN UINT64 Length,
2778 IN MTRR_MEMORY_CACHE_TYPE Attribute
2779 )
2780{
2781 return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);
2782}
2783
2784/**
2785 Worker function setting variable MTRRs
2786
2787 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2788
2789**/
2790VOID
2791MtrrSetVariableMtrrWorker (
2792 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2793 )
2794{
2795 UINT32 Index;
2796 UINT32 VariableMtrrCount;
2797
2798 VariableMtrrCount = GetVariableMtrrCountWorker ();
2799 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
2800
2801 for (Index = 0; Index < VariableMtrrCount; Index++) {
2802 AsmWriteMsr64 (
2803 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2804 VariableSettings->Mtrr[Index].Base
2805 );
2806 AsmWriteMsr64 (
2807 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2808 VariableSettings->Mtrr[Index].Mask
2809 );
2810 }
2811}
2812
2813/**
2814 Worker function setting fixed MTRRs
2815
2816 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2817
2818**/
2819VOID
2820MtrrSetFixedMtrrWorker (
2821 IN MTRR_FIXED_SETTINGS *FixedSettings
2822 )
2823{
2824 UINT32 Index;
2825
2826 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2827 AsmWriteMsr64 (
2828 mMtrrLibFixedMtrrTable[Index].Msr,
2829 FixedSettings->Mtrr[Index]
2830 );
2831 }
2832}
2833
2834/**
2835 This function gets the content in all MTRRs (variable and fixed)
2836
2837 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2838
2839 @retval the pointer of MtrrSetting
2840
2841**/
2842MTRR_SETTINGS *
2843EFIAPI
2844MtrrGetAllMtrrs (
2845 OUT MTRR_SETTINGS *MtrrSetting
2846 )
2847{
2848 BOOLEAN FixedMtrrSupported;
2849 UINT32 VariableMtrrCount;
2850 MSR_IA32_MTRR_DEF_TYPE_REGISTER *MtrrDefType;
2851
2852 ZeroMem (MtrrSetting, sizeof (*MtrrSetting));
2853
2854 MtrrDefType = (MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType;
2855 if (!MtrrLibIsMtrrSupported (&FixedMtrrSupported, &VariableMtrrCount)) {
2856 return MtrrSetting;
2857 }
2858
2859 //
2860 // Get MTRR_DEF_TYPE value
2861 //
2862 MtrrDefType->Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
2863
2864 //
2865 // Enabling the Fixed MTRR bit when unsupported is not allowed.
2866 //
2867 ASSERT (FixedMtrrSupported || (MtrrDefType->Bits.FE == 0));
2868
2869 //
2870 // Get fixed MTRRs
2871 //
2872 if (MtrrDefType->Bits.FE == 1) {
2873 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2874 }
2875
2876 //
2877 // Get variable MTRRs
2878 //
2879 MtrrGetVariableMtrrWorker (
2880 NULL,
2881 VariableMtrrCount,
2882 &MtrrSetting->Variables
2883 );
2884
2885 return MtrrSetting;
2886}
2887
2888/**
2889 This function sets all MTRRs includes Variable and Fixed.
2890
2891 The behavior of this function is to program everything in MtrrSetting to hardware.
2892 MTRRs might not be enabled because the enable bit is clear in MtrrSetting->MtrrDefType.
2893
2894 @param[in] MtrrSetting A buffer holding all MTRRs content.
2895
2896 @retval The pointer of MtrrSetting
2897
2898**/
2899MTRR_SETTINGS *
2900EFIAPI
2901MtrrSetAllMtrrs (
2902 IN MTRR_SETTINGS *MtrrSetting
2903 )
2904{
2905 BOOLEAN FixedMtrrSupported;
2906 MSR_IA32_MTRR_DEF_TYPE_REGISTER *MtrrDefType;
2907 MTRR_CONTEXT MtrrContext;
2908
2909 MtrrDefType = (MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType;
2910 if (!MtrrLibIsMtrrSupported (&FixedMtrrSupported, NULL)) {
2911 return MtrrSetting;
2912 }
2913
2914 MtrrLibPreMtrrChange (&MtrrContext);
2915
2916 //
2917 // Enabling the Fixed MTRR bit when unsupported is not allowed.
2918 //
2919 ASSERT (FixedMtrrSupported || (MtrrDefType->Bits.FE == 0));
2920
2921 //
2922 // If the hardware supports Fixed MTRR, it is sufficient
2923 // to set MTRRs regardless of whether Fixed MTRR bit is enabled.
2924 //
2925 if (FixedMtrrSupported) {
2926 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2927 }
2928
2929 //
2930 // Set Variable MTRRs
2931 //
2932 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2933
2934 //
2935 // Set MTRR_DEF_TYPE value
2936 //
2937 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2938
2939 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
2940
2941 return MtrrSetting;
2942}
2943
2944/**
2945 Checks if MTRR is supported.
2946
2947 @retval TRUE MTRR is supported.
2948 @retval FALSE MTRR is not supported.
2949
2950**/
2951BOOLEAN
2952EFIAPI
2953IsMtrrSupported (
2954 VOID
2955 )
2956{
2957 return MtrrLibIsMtrrSupported (NULL, NULL);
2958}
2959
2960/**
2961 This function returns a Ranges array containing the memory cache types
2962 of all memory addresses.
2963
2964 @param[in] MtrrSetting MTRR setting buffer to parse.
2965 @param[out] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2966 @param[in,out] RangeCount Count of MTRR_MEMORY_RANGE.
2967 On input, the maximum entries the Ranges can hold.
2968 On output, the actual entries that the function returns.
2969
2970 @retval RETURN_INVALID_PARAMETER RangeCount is NULL.
2971 @retval RETURN_INVALID_PARAMETER *RangeCount is not 0 but Ranges is NULL.
2972 @retval RETURN_BUFFER_TOO_SMALL *RangeCount is too small.
2973 @retval RETURN_SUCCESS Ranges are successfully returned.
2974**/
2975RETURN_STATUS
2976EFIAPI
2977MtrrGetMemoryAttributesInMtrrSettings (
2978 IN CONST MTRR_SETTINGS *MtrrSetting OPTIONAL,
2979 OUT MTRR_MEMORY_RANGE *Ranges,
2980 IN OUT UINTN *RangeCount
2981 )
2982{
2983 RETURN_STATUS Status;
2984 MTRR_SETTINGS LocalMtrrs;
2985 CONST MTRR_SETTINGS *Mtrrs;
2986 MSR_IA32_MTRR_DEF_TYPE_REGISTER *MtrrDefType;
2987 UINTN LocalRangeCount;
2988 UINT64 MtrrValidBitsMask;
2989 UINT64 MtrrValidAddressMask;
2990 UINT32 VariableMtrrCount;
2991 MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
2992 MTRR_MEMORY_RANGE LocalRanges[
2993 ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1
2994 ];
2995
2996 if (RangeCount == NULL) {
2997 return RETURN_INVALID_PARAMETER;
2998 }
2999
3000 if ((*RangeCount != 0) && (Ranges == NULL)) {
3001 return RETURN_INVALID_PARAMETER;
3002 }
3003
3004 if (MtrrSetting != NULL) {
3005 Mtrrs = MtrrSetting;
3006 } else {
3007 MtrrGetAllMtrrs (&LocalMtrrs);
3008 Mtrrs = &LocalMtrrs;
3009 }
3010
3011 MtrrDefType = (MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&Mtrrs->MtrrDefType;
3012
3013 LocalRangeCount = 1;
3014 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
3015 LocalRanges[0].BaseAddress = 0;
3016 LocalRanges[0].Length = MtrrValidBitsMask + 1;
3017
3018 if (MtrrDefType->Bits.E == 0) {
3019 LocalRanges[0].Type = CacheUncacheable;
3020 } else {
3021 LocalRanges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs);
3022
3023 VariableMtrrCount = GetVariableMtrrCountWorker ();
3024 ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));
3025
3026 MtrrLibGetRawVariableRanges (
3027 &Mtrrs->Variables,
3028 VariableMtrrCount,
3029 MtrrValidBitsMask,
3030 MtrrValidAddressMask,
3031 RawVariableRanges
3032 );
3033 Status = MtrrLibApplyVariableMtrrs (
3034 RawVariableRanges,
3035 VariableMtrrCount,
3036 LocalRanges,
3037 ARRAY_SIZE (LocalRanges),
3038 &LocalRangeCount
3039 );
3040 ASSERT_RETURN_ERROR (Status);
3041
3042 if (MtrrDefType->Bits.FE == 1) {
3043 MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, LocalRanges, ARRAY_SIZE (LocalRanges), &LocalRangeCount);
3044 }
3045 }
3046
3047 if (*RangeCount < LocalRangeCount) {
3048 *RangeCount = LocalRangeCount;
3049 return RETURN_BUFFER_TOO_SMALL;
3050 }
3051
3052 CopyMem (Ranges, LocalRanges, LocalRangeCount * sizeof (LocalRanges[0]));
3053 *RangeCount = LocalRangeCount;
3054 return RETURN_SUCCESS;
3055}
3056
3057/**
3058 Worker function prints all MTRRs for debugging.
3059
3060 If MtrrSetting is not NULL, print MTRR settings from input MTRR
3061 settings buffer.
3062 If MtrrSetting is NULL, print MTRR settings from MTRRs.
3063
3064 @param MtrrSetting A buffer holding all MTRRs content.
3065**/
3066VOID
3067MtrrDebugPrintAllMtrrsWorker (
3068 IN MTRR_SETTINGS *MtrrSetting
3069 )
3070{
3071 DEBUG_CODE_BEGIN ();
3072 UINT32 Index;
3073 MTRR_SETTINGS LocalMtrrs;
3074 MTRR_SETTINGS *Mtrrs;
3075 RETURN_STATUS Status;
3076 UINTN RangeCount;
3077 BOOLEAN ContainVariableMtrr;
3078 MTRR_MEMORY_RANGE Ranges[
3079 ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1
3080 ];
3081
3082 if (MtrrSetting != NULL) {
3083 Mtrrs = MtrrSetting;
3084 } else {
3085 MtrrGetAllMtrrs (&LocalMtrrs);
3086 Mtrrs = &LocalMtrrs;
3087 }
3088
3089 RangeCount = ARRAY_SIZE (Ranges);
3090 Status = MtrrGetMemoryAttributesInMtrrSettings (Mtrrs, Ranges, &RangeCount);
3091 if (RETURN_ERROR (Status)) {
3092 DEBUG ((DEBUG_CACHE, "MTRR is not enabled.\n"));
3093 return;
3094 }
3095
3096 //
3097 // Dump RAW MTRR contents
3098 //
3099 DEBUG ((DEBUG_CACHE, "MTRR Settings:\n"));
3100 DEBUG ((DEBUG_CACHE, "=============\n"));
3101 DEBUG ((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
3102 for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {
3103 DEBUG ((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
3104 }
3105
3106 ContainVariableMtrr = FALSE;
3107 for (Index = 0; Index < ARRAY_SIZE (Mtrrs->Variables.Mtrr); Index++) {
3108 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
3109 //
3110 // If mask is not valid, then do not display range
3111 //
3112 continue;
3113 }
3114
3115 ContainVariableMtrr = TRUE;
3116 DEBUG ((
3117 DEBUG_CACHE,
3118 "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
3119 Index,
3120 Mtrrs->Variables.Mtrr[Index].Base,
3121 Mtrrs->Variables.Mtrr[Index].Mask
3122 ));
3123 }
3124
3125 if (!ContainVariableMtrr) {
3126 DEBUG ((DEBUG_CACHE, "Variable MTRR : None.\n"));
3127 }
3128
3129 DEBUG ((DEBUG_CACHE, "\n"));
3130
3131 //
3132 // Dump MTRR setting in ranges
3133 //
3134 DEBUG ((DEBUG_CACHE, "Memory Ranges:\n"));
3135 DEBUG ((DEBUG_CACHE, "====================================\n"));
3136 for (Index = 0; Index < RangeCount; Index++) {
3137 DEBUG ((
3138 DEBUG_CACHE,
3139 "%a:%016lx-%016lx\n",
3140 mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],
3141 Ranges[Index].BaseAddress,
3142 Ranges[Index].BaseAddress + Ranges[Index].Length - 1
3143 ));
3144 }
3145
3146 DEBUG_CODE_END ();
3147}
3148
3149/**
3150 This function prints all MTRRs for debugging.
3151**/
3152VOID
3153EFIAPI
3154MtrrDebugPrintAllMtrrs (
3155 VOID
3156 )
3157{
3158 MtrrDebugPrintAllMtrrsWorker (NULL);
3159}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette