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