]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Fix a MTRR calculation bug
[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 Vertices[Index].Previous = VertexCount;
1175 Mandatory = Weight[M(Start,Index)];
1176 Vertices[Index].Weight = Mandatory;
1177 if (Mandatory != MAX_WEIGHT) {
1178 Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;
1179 Vertices[Index].Weight += Optional;
1180 ASSERT (Vertices[Index].Weight >= Optional);
1181 }
1182 }
1183
1184 MinI = Start;
1185 MinWeight = 0;
1186 while (!Vertices[Stop].Visited) {
1187 //
1188 // Update the weight from the shortest vertex to other unvisited vertices
1189 //
1190 for (Index = Start + 1; Index <= Stop; Index++) {
1191 if (!Vertices[Index].Visited) {
1192 Mandatory = Weight[M(MinI, Index)];
1193 if (Mandatory != MAX_WEIGHT) {
1194 Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;
1195 if (MinWeight + Mandatory + Optional <= Vertices[Index].Weight) {
1196 Vertices[Index].Weight = MinWeight + Mandatory + Optional;
1197 Vertices[Index].Previous = MinI; // Previous is Start based.
1198 }
1199 }
1200 }
1201 }
1202
1203 //
1204 // Find the shortest vertex from Start
1205 //
1206 MinI = VertexCount;
1207 MinWeight = MAX_WEIGHT;
1208 for (Index = Start + 1; Index <= Stop; Index++) {
1209 if (!Vertices[Index].Visited && MinWeight > Vertices[Index].Weight) {
1210 MinI = Index;
1211 MinWeight = Vertices[Index].Weight;
1212 }
1213 }
1214
1215 //
1216 // Mark the shortest vertex from Start as visited
1217 //
1218 Vertices[MinI].Visited = TRUE;
1219 }
1220 }
1221
1222 /**
1223 Append the MTRR setting to MTRR setting array.
1224
1225 @param Mtrrs Array holding all MTRR settings.
1226 @param MtrrCapacity Capacity of the MTRR array.
1227 @param MtrrCount The count of MTRR settings in array.
1228 @param BaseAddress Base address.
1229 @param Length Length.
1230 @param Type Memory type.
1231
1232 @retval RETURN_SUCCESS MTRR setting is appended to array.
1233 @retval RETURN_OUT_OF_RESOURCES Array is full.
1234 **/
1235 RETURN_STATUS
1236 MtrrLibAppendVariableMtrr (
1237 IN OUT MTRR_MEMORY_RANGE *Mtrrs,
1238 IN UINT32 MtrrCapacity,
1239 IN OUT UINT32 *MtrrCount,
1240 IN UINT64 BaseAddress,
1241 IN UINT64 Length,
1242 IN MTRR_MEMORY_CACHE_TYPE Type
1243 )
1244 {
1245 if (*MtrrCount == MtrrCapacity) {
1246 return RETURN_OUT_OF_RESOURCES;
1247 }
1248
1249 Mtrrs[*MtrrCount].BaseAddress = BaseAddress;
1250 Mtrrs[*MtrrCount].Length = Length;
1251 Mtrrs[*MtrrCount].Type = Type;
1252 (*MtrrCount)++;
1253 return RETURN_SUCCESS;
1254 }
1255
1256 /**
1257 Return the memory type that has the least precedence.
1258
1259 @param TypeBits Bit mask of memory type.
1260
1261 @retval Memory type that has the least precedence.
1262 **/
1263 MTRR_MEMORY_CACHE_TYPE
1264 MtrrLibLowestType (
1265 IN UINT8 TypeBits
1266 )
1267 {
1268 INT8 Type;
1269
1270 ASSERT (TypeBits != 0);
1271 for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);
1272 return (MTRR_MEMORY_CACHE_TYPE)Type;
1273 }
1274
1275 /**
1276 Return TRUE when the Operand is exactly power of 2.
1277
1278 @retval TRUE Operand is exactly power of 2.
1279 @retval FALSE Operand is not power of 2.
1280 **/
1281 BOOLEAN
1282 MtrrLibIsPowerOfTwo (
1283 IN UINT64 Operand
1284 )
1285 {
1286 ASSERT (Operand != 0);
1287 return (BOOLEAN) ((Operand & (Operand - 1)) == 0);
1288 }
1289
1290 /**
1291 Calculate the subtractive path from vertex Start to Stop.
1292
1293 @param DefaultType Default memory type.
1294 @param A0 Alignment to use when base address is 0.
1295 @param Ranges Array holding memory type settings for all memory regions.
1296 @param RangeCount The count of memory ranges the array holds.
1297 @param VertexCount The count of vertices in the graph.
1298 @param Vertices Array holding all vertices.
1299 @param Weight 2-dimention array holding weights between vertices.
1300 @param Start Start vertex.
1301 @param Stop Stop vertex.
1302 @param Types Type bit mask of memory range from Start to Stop.
1303 @param TypeCount Number of different memory types from Start to Stop.
1304 @param Mtrrs Array holding all MTRR settings.
1305 @param MtrrCapacity Capacity of the MTRR array.
1306 @param MtrrCount The count of MTRR settings in array.
1307
1308 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1309 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1310
1311 **/
1312 RETURN_STATUS
1313 MtrrLibCalculateSubtractivePath (
1314 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1315 IN UINT64 A0,
1316 IN CONST MTRR_MEMORY_RANGE *Ranges,
1317 IN UINTN RangeCount,
1318 IN UINT16 VertexCount,
1319 IN MTRR_LIB_ADDRESS *Vertices,
1320 IN OUT UINT8 *Weight,
1321 IN UINT16 Start,
1322 IN UINT16 Stop,
1323 IN UINT8 Types,
1324 IN UINT8 TypeCount,
1325 IN OUT MTRR_MEMORY_RANGE *Mtrrs, OPTIONAL
1326 IN UINT32 MtrrCapacity, OPTIONAL
1327 IN OUT UINT32 *MtrrCount OPTIONAL
1328 )
1329 {
1330 RETURN_STATUS Status;
1331 UINT64 Base;
1332 UINT64 Length;
1333 UINT8 PrecedentTypes;
1334 UINTN Index;
1335 UINT64 HBase;
1336 UINT64 HLength;
1337 UINT64 SubLength;
1338 UINT16 SubStart;
1339 UINT16 SubStop;
1340 UINT16 Cur;
1341 UINT16 Pre;
1342 MTRR_MEMORY_CACHE_TYPE LowestType;
1343 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType;
1344
1345 Base = Vertices[Start].Address;
1346 Length = Vertices[Stop].Address - Base;
1347
1348 LowestType = MtrrLibLowestType (Types);
1349
1350 //
1351 // Clear the lowest type (highest bit) to get the precedent types
1352 //
1353 PrecedentTypes = ~(1 << LowestType) & Types;
1354 LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);
1355
1356 if (Mtrrs == NULL) {
1357 Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);
1358 Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);
1359 }
1360
1361 // Add all high level ranges
1362 HBase = MAX_UINT64;
1363 HLength = 0;
1364 for (Index = 0; Index < RangeCount; Index++) {
1365 if (Length == 0) {
1366 break;
1367 }
1368 if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {
1369 continue;
1370 }
1371
1372 //
1373 // Base is in the Range[Index]
1374 //
1375 if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
1376 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;
1377 } else {
1378 SubLength = Length;
1379 }
1380 if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {
1381 //
1382 // Meet a range whose types take precedence.
1383 // Update the [HBase, HBase + HLength) to include the range,
1384 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1385 //
1386 if (HBase == MAX_UINT64) {
1387 HBase = Base;
1388 }
1389 HLength += SubLength;
1390 }
1391
1392 Base += SubLength;
1393 Length -= SubLength;
1394
1395 if (HLength == 0) {
1396 continue;
1397 }
1398
1399 if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end
1400
1401 //
1402 // Add the MTRRs for each high priority type range
1403 // the range[HBase, HBase + HLength) contains only two types.
1404 // We might use positive or subtractive, depending on which way uses less MTRR
1405 //
1406 for (SubStart = Start; SubStart <= Stop; SubStart++) {
1407 if (Vertices[SubStart].Address == HBase) {
1408 break;
1409 }
1410 }
1411
1412 for (SubStop = SubStart; SubStop <= Stop; SubStop++) {
1413 if (Vertices[SubStop].Address == HBase + HLength) {
1414 break;
1415 }
1416 }
1417 ASSERT (Vertices[SubStart].Address == HBase);
1418 ASSERT (Vertices[SubStop].Address == HBase + HLength);
1419
1420 if ((TypeCount == 2) || (SubStart == SubStop - 1)) {
1421 //
1422 // add subtractive MTRRs for [HBase, HBase + HLength)
1423 // [HBase, HBase + HLength) contains only one type.
1424 // while - loop is to split the range to MTRR - compliant aligned range.
1425 //
1426 if (Mtrrs == NULL) {
1427 Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);
1428 } else {
1429 while (SubStart != SubStop) {
1430 Status = MtrrLibAppendVariableMtrr (
1431 Mtrrs, MtrrCapacity, MtrrCount,
1432 Vertices[SubStart].Address, Vertices[SubStart].Length, Vertices[SubStart].Type
1433 );
1434 if (RETURN_ERROR (Status)) {
1435 return Status;
1436 }
1437 SubStart++;
1438 }
1439 }
1440 } else {
1441 ASSERT (TypeCount == 3);
1442 MtrrLibCalculateLeastMtrrs (VertexCount, Vertices, Weight, SubStart, SubStop, TRUE);
1443
1444 if (Mtrrs == NULL) {
1445 Weight[M (Start, Stop)] += Vertices[SubStop].Weight;
1446 } else {
1447 // When we need to collect the optimal path from SubStart to SubStop
1448 while (SubStop != SubStart) {
1449 Cur = SubStop;
1450 Pre = Vertices[Cur].Previous;
1451 SubStop = Pre;
1452
1453 if (Weight[M (Pre, Cur)] + Weight[O (Pre, Cur)] != 0) {
1454 Status = MtrrLibAppendVariableMtrr (
1455 Mtrrs, MtrrCapacity, MtrrCount,
1456 Vertices[Pre].Address, Vertices[Cur].Address - Vertices[Pre].Address,
1457 (Pre != Cur - 1) ? LowestPrecedentType : Vertices[Pre].Type
1458 );
1459 if (RETURN_ERROR (Status)) {
1460 return Status;
1461 }
1462 }
1463 if (Pre != Cur - 1) {
1464 Status = MtrrLibCalculateSubtractivePath (
1465 DefaultType, A0,
1466 Ranges, RangeCount,
1467 VertexCount, Vertices, Weight,
1468 Pre, Cur, PrecedentTypes, 2,
1469 Mtrrs, MtrrCapacity, MtrrCount
1470 );
1471 if (RETURN_ERROR (Status)) {
1472 return Status;
1473 }
1474 }
1475 }
1476 }
1477
1478 }
1479 //
1480 // Reset HBase, HLength
1481 //
1482 HBase = MAX_UINT64;
1483 HLength = 0;
1484 }
1485 }
1486 return RETURN_SUCCESS;
1487 }
1488
1489 /**
1490 Calculate MTRR settings to cover the specified memory ranges.
1491
1492 @param DefaultType Default memory type.
1493 @param A0 Alignment to use when base address is 0.
1494 @param Ranges Memory range array holding the memory type
1495 settings for all memory address.
1496 @param RangeCount Count of memory ranges.
1497 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1498 This is an optional parameter that may be NULL.
1499 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1500 It may be updated to the actual required size when the calculation
1501 needs more scratch buffer.
1502 @param Mtrrs Array holding all MTRR settings.
1503 @param MtrrCapacity Capacity of the MTRR array.
1504 @param MtrrCount The count of MTRR settings in array.
1505
1506 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1507 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1508 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1509 **/
1510 RETURN_STATUS
1511 MtrrLibCalculateMtrrs (
1512 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1513 IN UINT64 A0,
1514 IN CONST MTRR_MEMORY_RANGE *Ranges,
1515 IN UINTN RangeCount,
1516 IN VOID *Scratch,
1517 IN OUT UINTN *ScratchSize,
1518 IN OUT MTRR_MEMORY_RANGE *Mtrrs,
1519 IN UINT32 MtrrCapacity,
1520 IN OUT UINT32 *MtrrCount
1521 )
1522 {
1523 UINT64 Base0;
1524 UINT64 Base1;
1525 UINTN Index;
1526 UINT64 Base;
1527 UINT64 Length;
1528 UINT64 Alignment;
1529 UINT64 SubLength;
1530 MTRR_LIB_ADDRESS *Vertices;
1531 UINT8 *Weight;
1532 UINT32 VertexIndex;
1533 UINT32 VertexCount;
1534 UINTN RequiredScratchSize;
1535 UINT8 TypeCount;
1536 UINT16 Start;
1537 UINT16 Stop;
1538 UINT8 Type;
1539 RETURN_STATUS Status;
1540
1541 Base0 = Ranges[0].BaseAddress;
1542 Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;
1543 MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);
1544
1545 //
1546 // Count the number of vertices.
1547 //
1548 Vertices = (MTRR_LIB_ADDRESS*)Scratch;
1549 for (VertexIndex = 0, Index = 0; Index < RangeCount; Index++) {
1550 Base = Ranges[Index].BaseAddress;
1551 Length = Ranges[Index].Length;
1552 while (Length != 0) {
1553 Alignment = MtrrLibBiggestAlignment (Base, A0);
1554 SubLength = Alignment;
1555 if (SubLength > Length) {
1556 SubLength = GetPowerOfTwo64 (Length);
1557 }
1558 if (VertexIndex < *ScratchSize / sizeof (*Vertices)) {
1559 Vertices[VertexIndex].Address = Base;
1560 Vertices[VertexIndex].Alignment = Alignment;
1561 Vertices[VertexIndex].Type = Ranges[Index].Type;
1562 Vertices[VertexIndex].Length = SubLength;
1563 }
1564 Base += SubLength;
1565 Length -= SubLength;
1566 VertexIndex++;
1567 }
1568 }
1569 //
1570 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1571 //
1572 VertexCount = VertexIndex + 1;
1573 DEBUG ((
1574 DEBUG_CACHE, " Count of vertices (%016llx - %016llx) = %d\n",
1575 Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VertexCount
1576 ));
1577 ASSERT (VertexCount < MAX_UINT16);
1578
1579 RequiredScratchSize = VertexCount * sizeof (*Vertices) + VertexCount * VertexCount * sizeof (*Weight);
1580 if (*ScratchSize < RequiredScratchSize) {
1581 *ScratchSize = RequiredScratchSize;
1582 return RETURN_BUFFER_TOO_SMALL;
1583 }
1584 Vertices[VertexCount - 1].Address = Base1;
1585
1586 Weight = (UINT8 *) &Vertices[VertexCount];
1587 for (VertexIndex = 0; VertexIndex < VertexCount; VertexIndex++) {
1588 //
1589 // Set optional weight between vertices and self->self to 0
1590 //
1591 SetMem (&Weight[M(VertexIndex, 0)], VertexIndex + 1, 0);
1592 //
1593 // Set mandatory weight between vertices to MAX_WEIGHT
1594 //
1595 SetMem (&Weight[M (VertexIndex, VertexIndex + 1)], VertexCount - VertexIndex - 1, MAX_WEIGHT);
1596
1597 // Final result looks like:
1598 // 00 FF FF FF
1599 // 00 00 FF FF
1600 // 00 00 00 FF
1601 // 00 00 00 00
1602 }
1603
1604 //
1605 // Set mandatory weight and optional weight for adjacent vertices
1606 //
1607 for (VertexIndex = 0; VertexIndex < VertexCount - 1; VertexIndex++) {
1608 if (Vertices[VertexIndex].Type != DefaultType) {
1609 Weight[M (VertexIndex, VertexIndex + 1)] = 1;
1610 Weight[O (VertexIndex, VertexIndex + 1)] = 0;
1611 } else {
1612 Weight[M (VertexIndex, VertexIndex + 1)] = 0;
1613 Weight[O (VertexIndex, VertexIndex + 1)] = 1;
1614 }
1615 }
1616
1617 for (TypeCount = 2; TypeCount <= 3; TypeCount++) {
1618 for (Start = 0; Start < VertexCount; Start++) {
1619 for (Stop = Start + 2; Stop < VertexCount; Stop++) {
1620 ASSERT (Vertices[Stop].Address > Vertices[Start].Address);
1621 Length = Vertices[Stop].Address - Vertices[Start].Address;
1622 if (Length > Vertices[Start].Alignment) {
1623 //
1624 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1625 //
1626 break;
1627 }
1628 if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {
1629 if (MtrrLibGetNumberOfTypes (
1630 Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
1631 ) == TypeCount) {
1632 //
1633 // Update the Weight[Start, Stop] using subtractive path.
1634 //
1635 MtrrLibCalculateSubtractivePath (
1636 DefaultType, A0,
1637 Ranges, RangeCount,
1638 (UINT16)VertexCount, Vertices, Weight,
1639 Start, Stop, Type, TypeCount,
1640 NULL, 0, NULL
1641 );
1642 } else if (TypeCount == 2) {
1643 //
1644 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1645 // Because no matter how Stop is increased, we always meet 3-type range.
1646 //
1647 break;
1648 }
1649 }
1650 }
1651 }
1652 }
1653
1654 Status = RETURN_SUCCESS;
1655 MtrrLibCalculateLeastMtrrs ((UINT16) VertexCount, Vertices, Weight, 0, (UINT16) VertexCount - 1, FALSE);
1656 Stop = (UINT16) VertexCount - 1;
1657 while (Stop != 0) {
1658 Start = Vertices[Stop].Previous;
1659 TypeCount = MAX_UINT8;
1660 Type = 0;
1661 if (Weight[M(Start, Stop)] != 0) {
1662 TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type);
1663 Status = MtrrLibAppendVariableMtrr (
1664 Mtrrs, MtrrCapacity, MtrrCount,
1665 Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address,
1666 MtrrLibLowestType (Type)
1667 );
1668 if (RETURN_ERROR (Status)) {
1669 break;
1670 }
1671 }
1672
1673 if (Start != Stop - 1) {
1674 //
1675 // substractive path
1676 //
1677 if (TypeCount == MAX_UINT8) {
1678 TypeCount = MtrrLibGetNumberOfTypes (
1679 Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
1680 );
1681 }
1682 Status = MtrrLibCalculateSubtractivePath (
1683 DefaultType, A0,
1684 Ranges, RangeCount,
1685 (UINT16) VertexCount, Vertices, Weight, Start, Stop,
1686 Type, TypeCount,
1687 Mtrrs, MtrrCapacity, MtrrCount
1688 );
1689 if (RETURN_ERROR (Status)) {
1690 break;
1691 }
1692 }
1693 Stop = Start;
1694 }
1695 return Status;
1696 }
1697
1698
1699 /**
1700 Apply the fixed MTRR settings to memory range array.
1701
1702 @param Fixed The fixed MTRR settings.
1703 @param Ranges Return the memory range array holding memory type
1704 settings for all memory address.
1705 @param RangeCapacity The capacity of memory range array.
1706 @param RangeCount Return the count of memory range.
1707
1708 @retval RETURN_SUCCESS The memory range array is returned successfully.
1709 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1710 **/
1711 RETURN_STATUS
1712 MtrrLibApplyFixedMtrrs (
1713 IN MTRR_FIXED_SETTINGS *Fixed,
1714 IN OUT MTRR_MEMORY_RANGE *Ranges,
1715 IN UINTN RangeCapacity,
1716 IN OUT UINTN *RangeCount
1717 )
1718 {
1719 RETURN_STATUS Status;
1720 UINTN MsrIndex;
1721 UINTN Index;
1722 MTRR_MEMORY_CACHE_TYPE MemoryType;
1723 UINT64 Base;
1724
1725 Base = 0;
1726 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
1727 ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);
1728 for (Index = 0; Index < sizeof (UINT64); Index++) {
1729 MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];
1730 Status = MtrrLibSetMemoryType (
1731 Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType
1732 );
1733 if (Status == RETURN_OUT_OF_RESOURCES) {
1734 return Status;
1735 }
1736 Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;
1737 }
1738 }
1739 ASSERT (Base == BASE_1MB);
1740 return RETURN_SUCCESS;
1741 }
1742
1743 /**
1744 Apply the variable MTRR settings to memory range array.
1745
1746 @param VariableMtrr The variable MTRR array.
1747 @param VariableMtrrCount The count of variable MTRRs.
1748 @param Ranges Return the memory range array with new MTRR settings applied.
1749 @param RangeCapacity The capacity of memory range array.
1750 @param RangeCount Return the count of memory range.
1751
1752 @retval RETURN_SUCCESS The memory range array is returned successfully.
1753 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1754 **/
1755 RETURN_STATUS
1756 MtrrLibApplyVariableMtrrs (
1757 IN CONST MTRR_MEMORY_RANGE *VariableMtrr,
1758 IN UINT32 VariableMtrrCount,
1759 IN OUT MTRR_MEMORY_RANGE *Ranges,
1760 IN UINTN RangeCapacity,
1761 IN OUT UINTN *RangeCount
1762 )
1763 {
1764 RETURN_STATUS Status;
1765 UINTN Index;
1766
1767 //
1768 // WT > WB
1769 // UC > *
1770 // UC > * (except WB, UC) > WB
1771 //
1772
1773 //
1774 // 1. Set WB
1775 //
1776 for (Index = 0; Index < VariableMtrrCount; Index++) {
1777 if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {
1778 Status = MtrrLibSetMemoryType (
1779 Ranges, RangeCapacity, RangeCount,
1780 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1781 );
1782 if (Status == RETURN_OUT_OF_RESOURCES) {
1783 return Status;
1784 }
1785 }
1786 }
1787
1788 //
1789 // 2. Set other types than WB or UC
1790 //
1791 for (Index = 0; Index < VariableMtrrCount; Index++) {
1792 if ((VariableMtrr[Index].Length != 0) &&
1793 (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {
1794 Status = MtrrLibSetMemoryType (
1795 Ranges, RangeCapacity, RangeCount,
1796 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1797 );
1798 if (Status == RETURN_OUT_OF_RESOURCES) {
1799 return Status;
1800 }
1801 }
1802 }
1803
1804 //
1805 // 3. Set UC
1806 //
1807 for (Index = 0; Index < VariableMtrrCount; Index++) {
1808 if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {
1809 Status = MtrrLibSetMemoryType (
1810 Ranges, RangeCapacity, RangeCount,
1811 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1812 );
1813 if (Status == RETURN_OUT_OF_RESOURCES) {
1814 return Status;
1815 }
1816 }
1817 }
1818 return RETURN_SUCCESS;
1819 }
1820
1821 /**
1822 Return the memory type bit mask that's compatible to first type in the Ranges.
1823
1824 @param Ranges Memory range array holding the memory type
1825 settings for all memory address.
1826 @param RangeCount Count of memory ranges.
1827
1828 @return Compatible memory type bit mask.
1829 **/
1830 UINT8
1831 MtrrLibGetCompatibleTypes (
1832 IN CONST MTRR_MEMORY_RANGE *Ranges,
1833 IN UINTN RangeCount
1834 )
1835 {
1836 ASSERT (RangeCount != 0);
1837
1838 switch (Ranges[0].Type) {
1839 case CacheWriteBack:
1840 case CacheWriteThrough:
1841 return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);
1842 break;
1843
1844 case CacheWriteCombining:
1845 case CacheWriteProtected:
1846 return (1 << Ranges[0].Type) | (1 << CacheUncacheable);
1847 break;
1848
1849 case CacheUncacheable:
1850 if (RangeCount == 1) {
1851 return (1 << CacheUncacheable);
1852 }
1853 return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);
1854 break;
1855
1856 case CacheInvalid:
1857 default:
1858 ASSERT (FALSE);
1859 break;
1860 }
1861 return 0;
1862 }
1863
1864 /**
1865 Overwrite the destination MTRR settings with the source MTRR settings.
1866 This routine is to make sure the modification to destination MTRR settings
1867 is as small as possible.
1868
1869 @param DstMtrrs Destination MTRR settings.
1870 @param DstMtrrCount Count of destination MTRR settings.
1871 @param SrcMtrrs Source MTRR settings.
1872 @param SrcMtrrCount Count of source MTRR settings.
1873 @param Modified Flag array to indicate which destination MTRR setting is modified.
1874 **/
1875 VOID
1876 MtrrLibMergeVariableMtrr (
1877 MTRR_MEMORY_RANGE *DstMtrrs,
1878 UINT32 DstMtrrCount,
1879 MTRR_MEMORY_RANGE *SrcMtrrs,
1880 UINT32 SrcMtrrCount,
1881 BOOLEAN *Modified
1882 )
1883 {
1884 UINT32 DstIndex;
1885 UINT32 SrcIndex;
1886
1887 ASSERT (SrcMtrrCount <= DstMtrrCount);
1888
1889 for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {
1890 Modified[DstIndex] = FALSE;
1891
1892 if (DstMtrrs[DstIndex].Length == 0) {
1893 continue;
1894 }
1895 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
1896 if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&
1897 DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&
1898 DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {
1899 break;
1900 }
1901 }
1902
1903 if (SrcIndex == SrcMtrrCount) {
1904 //
1905 // Remove the one from DstMtrrs which is not in SrcMtrrs
1906 //
1907 DstMtrrs[DstIndex].Length = 0;
1908 Modified[DstIndex] = TRUE;
1909 } else {
1910 //
1911 // Remove the one from SrcMtrrs which is also in DstMtrrs
1912 //
1913 SrcMtrrs[SrcIndex].Length = 0;
1914 }
1915 }
1916
1917 //
1918 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1919 // Merge MTRRs from SrcMtrrs to DstMtrrs
1920 //
1921 DstIndex = 0;
1922 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
1923 if (SrcMtrrs[SrcIndex].Length != 0) {
1924
1925 //
1926 // Find the empty slot in DstMtrrs
1927 //
1928 while (DstIndex < DstMtrrCount) {
1929 if (DstMtrrs[DstIndex].Length == 0) {
1930 break;
1931 }
1932 DstIndex++;
1933 }
1934 ASSERT (DstIndex < DstMtrrCount);
1935 CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));
1936 Modified[DstIndex] = TRUE;
1937 }
1938 }
1939 }
1940
1941 /**
1942 Calculate the variable MTRR settings for all memory ranges.
1943
1944 @param DefaultType Default memory type.
1945 @param A0 Alignment to use when base address is 0.
1946 @param Ranges Memory range array holding the memory type
1947 settings for all memory address.
1948 @param RangeCount Count of memory ranges.
1949 @param Scratch Scratch buffer to be used in MTRR calculation.
1950 @param ScratchSize Pointer to the size of scratch buffer.
1951 @param VariableMtrr Array holding all MTRR settings.
1952 @param VariableMtrrCapacity Capacity of the MTRR array.
1953 @param VariableMtrrCount The count of MTRR settings in array.
1954
1955 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1956 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1957 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1958 The required scratch buffer size is returned through ScratchSize.
1959 **/
1960 RETURN_STATUS
1961 MtrrLibSetMemoryRanges (
1962 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1963 IN UINT64 A0,
1964 IN MTRR_MEMORY_RANGE *Ranges,
1965 IN UINTN RangeCount,
1966 IN VOID *Scratch,
1967 IN OUT UINTN *ScratchSize,
1968 OUT MTRR_MEMORY_RANGE *VariableMtrr,
1969 IN UINT32 VariableMtrrCapacity,
1970 OUT UINT32 *VariableMtrrCount
1971 )
1972 {
1973 RETURN_STATUS Status;
1974 UINT32 Index;
1975 UINT64 Base0;
1976 UINT64 Base1;
1977 UINT64 Alignment;
1978 UINT8 CompatibleTypes;
1979 UINT64 Length;
1980 UINT32 End;
1981 UINTN ActualScratchSize;
1982 UINTN BiggestScratchSize;
1983
1984 *VariableMtrrCount = 0;
1985
1986 //
1987 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
1988 // Each call needs different scratch buffer size.
1989 // When the provided scratch buffer size is not sufficient in any call,
1990 // set the GetActualScratchSize to TRUE, and following calls will only
1991 // calculate the actual scratch size for the caller.
1992 //
1993 BiggestScratchSize = 0;
1994
1995 for (Index = 0; Index < RangeCount;) {
1996 Base0 = Ranges[Index].BaseAddress;
1997
1998 //
1999 // Full step is optimal
2000 //
2001 while (Index < RangeCount) {
2002 ASSERT (Ranges[Index].BaseAddress == Base0);
2003 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2004 while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {
2005 if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {
2006 Status = MtrrLibAppendVariableMtrr (
2007 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
2008 Base0, Alignment, Ranges[Index].Type
2009 );
2010 if (RETURN_ERROR (Status)) {
2011 return Status;
2012 }
2013 }
2014 Base0 += Alignment;
2015 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2016 }
2017
2018 //
2019 // Remove the above range from Ranges[Index]
2020 //
2021 Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;
2022 Ranges[Index].BaseAddress = Base0;
2023 if (Ranges[Index].Length != 0) {
2024 break;
2025 } else {
2026 Index++;
2027 }
2028 }
2029
2030 if (Index == RangeCount) {
2031 break;
2032 }
2033
2034 //
2035 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2036 // Per SDM, the compatible types between[B0, B1) are:
2037 // UC, *
2038 // WB, WT
2039 // UC, WB, WT
2040 //
2041 CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);
2042
2043 End = Index; // End points to last one that matches the CompatibleTypes.
2044 while (End + 1 < RangeCount) {
2045 if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {
2046 break;
2047 }
2048 End++;
2049 }
2050 Alignment = MtrrLibBiggestAlignment (Base0, A0);
2051 Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);
2052 Base1 = Base0 + MIN (Alignment, Length);
2053
2054 //
2055 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2056 //
2057 End = Index;
2058 while (End + 1 < RangeCount) {
2059 if (Base1 <= Ranges[End + 1].BaseAddress) {
2060 break;
2061 }
2062 End++;
2063 }
2064
2065 Length = Ranges[End].Length;
2066 Ranges[End].Length = Base1 - Ranges[End].BaseAddress;
2067 ActualScratchSize = *ScratchSize;
2068 Status = MtrrLibCalculateMtrrs (
2069 DefaultType, A0,
2070 &Ranges[Index], End + 1 - Index,
2071 Scratch, &ActualScratchSize,
2072 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount
2073 );
2074 if (Status == RETURN_BUFFER_TOO_SMALL) {
2075 BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);
2076 //
2077 // Ignore this error, because we need to calculate the biggest
2078 // scratch buffer size.
2079 //
2080 Status = RETURN_SUCCESS;
2081 }
2082 if (RETURN_ERROR (Status)) {
2083 return Status;
2084 }
2085
2086 if (Length != Ranges[End].Length) {
2087 Ranges[End].BaseAddress = Base1;
2088 Ranges[End].Length = Length - Ranges[End].Length;
2089 Index = End;
2090 } else {
2091 Index = End + 1;
2092 }
2093 }
2094
2095 if (*ScratchSize < BiggestScratchSize) {
2096 *ScratchSize = BiggestScratchSize;
2097 return RETURN_BUFFER_TOO_SMALL;
2098 }
2099 return RETURN_SUCCESS;
2100 }
2101
2102 /**
2103 Set the below-1MB memory attribute to fixed MTRR buffer.
2104 Modified flag array indicates which fixed MTRR is modified.
2105
2106 @param [in, out] FixedSettings Fixed MTRR buffer.
2107 @param [out] Modified Flag array indicating which MTRR is modified.
2108 @param [in] BaseAddress Base address.
2109 @param [in] Length Length.
2110 @param [in] Type Memory type.
2111
2112 @retval RETURN_SUCCESS The memory attribute is set successfully.
2113 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2114 for the fixed MTRRs.
2115 **/
2116 RETURN_STATUS
2117 MtrrLibSetBelow1MBMemoryAttribute (
2118 IN OUT MTRR_FIXED_SETTINGS *FixedSettings,
2119 OUT BOOLEAN *Modified,
2120 IN PHYSICAL_ADDRESS BaseAddress,
2121 IN UINT64 Length,
2122 IN MTRR_MEMORY_CACHE_TYPE Type
2123 )
2124 {
2125 RETURN_STATUS Status;
2126 UINT32 MsrIndex;
2127 UINT64 ClearMask;
2128 UINT64 OrMask;
2129 UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2130 UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2131 BOOLEAN LocalModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2132
2133 ASSERT (BaseAddress < BASE_1MB);
2134
2135 SetMem (LocalModified, sizeof (LocalModified), FALSE);
2136
2137 //
2138 // (Value & ~0 | 0) still equals to (Value)
2139 //
2140 SetMem (ClearMasks, sizeof (ClearMasks), 0);
2141 SetMem (OrMasks, sizeof (OrMasks), 0);
2142
2143 MsrIndex = (UINT32)-1;
2144 while ((BaseAddress < BASE_1MB) && (Length != 0)) {
2145 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
2146 if (RETURN_ERROR (Status)) {
2147 return Status;
2148 }
2149 ClearMasks[MsrIndex] = ClearMask;
2150 OrMasks[MsrIndex] = OrMask;
2151 Modified[MsrIndex] = TRUE;
2152 LocalModified[MsrIndex] = TRUE;
2153 }
2154
2155 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
2156 if (LocalModified[MsrIndex]) {
2157 FixedSettings->Mtrr[MsrIndex] = (FixedSettings->Mtrr[MsrIndex] & ~ClearMasks[MsrIndex]) | OrMasks[MsrIndex];
2158 }
2159 }
2160 return RETURN_SUCCESS;
2161 }
2162
2163 /**
2164 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2165
2166 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2167 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2168 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2169 It may be updated to the actual required size when the calculation
2170 needs more scratch buffer.
2171 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2172 When range overlap happens, the last one takes higher priority.
2173 When the function returns, either all the attributes are set successfully,
2174 or none of them is set.
2175 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2176
2177 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2178 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2179 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2180 memory resource range specified by BaseAddress and Length in any range.
2181 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2182 range specified by BaseAddress and Length in any range.
2183 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2184 the memory resource ranges.
2185 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2186 BaseAddress and Length cannot be modified.
2187 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2188 **/
2189 RETURN_STATUS
2190 EFIAPI
2191 MtrrSetMemoryAttributesInMtrrSettings (
2192 IN OUT MTRR_SETTINGS *MtrrSetting,
2193 IN VOID *Scratch,
2194 IN OUT UINTN *ScratchSize,
2195 IN CONST MTRR_MEMORY_RANGE *Ranges,
2196 IN UINTN RangeCount
2197 )
2198 {
2199 RETURN_STATUS Status;
2200 UINT32 Index;
2201 UINT64 BaseAddress;
2202 UINT64 Length;
2203 BOOLEAN Above1MbExist;
2204
2205 UINT64 MtrrValidBitsMask;
2206 UINT64 MtrrValidAddressMask;
2207 MTRR_MEMORY_CACHE_TYPE DefaultType;
2208 MTRR_VARIABLE_SETTINGS VariableSettings;
2209 MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];
2210 UINTN WorkingRangeCount;
2211 BOOLEAN Modified;
2212 MTRR_VARIABLE_SETTING VariableSetting;
2213 UINT32 OriginalVariableMtrrCount;
2214 UINT32 FirmwareVariableMtrrCount;
2215 UINT32 WorkingVariableMtrrCount;
2216 MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2217 MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2218 BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2219
2220 BOOLEAN FixedSettingsModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2221 MTRR_FIXED_SETTINGS WorkingFixedSettings;
2222
2223 MTRR_CONTEXT MtrrContext;
2224 BOOLEAN MtrrContextValid;
2225
2226 Status = RETURN_SUCCESS;
2227 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
2228
2229 //
2230 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2231 //
2232 SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);
2233 //
2234 // TRUE indicating the accordingly Fixed setting needs modification in WorkingFixedSettings.
2235 //
2236 SetMem (FixedSettingsModified, ARRAY_SIZE (FixedSettingsModified), FALSE);
2237
2238 //
2239 // TRUE indicating the caller requests to set variable MTRRs.
2240 //
2241 Above1MbExist = FALSE;
2242 OriginalVariableMtrrCount = 0;
2243
2244 //
2245 // 0. Dump the requests.
2246 //
2247 DEBUG_CODE (
2248 DEBUG ((DEBUG_CACHE, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2249 (MtrrSetting == NULL) ? "Hardware" : "Buffer", *ScratchSize,
2250 (RangeCount <= 1) ? "," : "\n"
2251 ));
2252 for (Index = 0; Index < RangeCount; Index++) {
2253 DEBUG ((DEBUG_CACHE, " %a: [%016lx, %016lx)\n",
2254 mMtrrMemoryCacheTypeShortName[MIN (Ranges[Index].Type, CacheInvalid)],
2255 Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length
2256 ));
2257 }
2258 );
2259
2260 //
2261 // 1. Validate the parameters.
2262 //
2263 if (!IsMtrrSupported ()) {
2264 Status = RETURN_UNSUPPORTED;
2265 goto Exit;
2266 }
2267
2268 for (Index = 0; Index < RangeCount; Index++) {
2269 if (Ranges[Index].Length == 0) {
2270 Status = RETURN_INVALID_PARAMETER;
2271 goto Exit;
2272 }
2273 if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||
2274 ((((Ranges[Index].BaseAddress + Ranges[Index].Length) & ~MtrrValidAddressMask) != 0) &&
2275 (Ranges[Index].BaseAddress + Ranges[Index].Length) != MtrrValidBitsMask + 1)
2276 ) {
2277 //
2278 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2279 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2280 //
2281 Status = RETURN_UNSUPPORTED;
2282 goto Exit;
2283 }
2284 if ((Ranges[Index].Type != CacheUncacheable) &&
2285 (Ranges[Index].Type != CacheWriteCombining) &&
2286 (Ranges[Index].Type != CacheWriteThrough) &&
2287 (Ranges[Index].Type != CacheWriteProtected) &&
2288 (Ranges[Index].Type != CacheWriteBack)) {
2289 Status = RETURN_INVALID_PARAMETER;
2290 goto Exit;
2291 }
2292 if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {
2293 Above1MbExist = TRUE;
2294 }
2295 }
2296
2297 //
2298 // 2. Apply the above-1MB memory attribute settings.
2299 //
2300 if (Above1MbExist) {
2301 //
2302 // 2.1. Read all variable MTRRs and convert to Ranges.
2303 //
2304 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();
2305 MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);
2306 MtrrLibGetRawVariableRanges (
2307 &VariableSettings, OriginalVariableMtrrCount,
2308 MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr
2309 );
2310
2311 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
2312 WorkingRangeCount = 1;
2313 WorkingRanges[0].BaseAddress = 0;
2314 WorkingRanges[0].Length = MtrrValidBitsMask + 1;
2315 WorkingRanges[0].Type = DefaultType;
2316
2317 Status = MtrrLibApplyVariableMtrrs (
2318 OriginalVariableMtrr, OriginalVariableMtrrCount,
2319 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);
2320 ASSERT_RETURN_ERROR (Status);
2321
2322 ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));
2323 FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
2324 ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);
2325
2326 //
2327 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2328 //
2329 Status = MtrrLibSetMemoryType (
2330 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
2331 0, SIZE_1MB, CacheUncacheable
2332 );
2333 ASSERT (Status != RETURN_OUT_OF_RESOURCES);
2334
2335 //
2336 // 2.3. Apply the new memory attribute settings to Ranges.
2337 //
2338 Modified = FALSE;
2339 for (Index = 0; Index < RangeCount; Index++) {
2340 BaseAddress = Ranges[Index].BaseAddress;
2341 Length = Ranges[Index].Length;
2342 if (BaseAddress < BASE_1MB) {
2343 if (Length <= BASE_1MB - BaseAddress) {
2344 continue;
2345 }
2346 Length -= BASE_1MB - BaseAddress;
2347 BaseAddress = BASE_1MB;
2348 }
2349 Status = MtrrLibSetMemoryType (
2350 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
2351 BaseAddress, Length, Ranges[Index].Type
2352 );
2353 if (Status == RETURN_ALREADY_STARTED) {
2354 Status = RETURN_SUCCESS;
2355 } else if (Status == RETURN_OUT_OF_RESOURCES) {
2356 goto Exit;
2357 } else {
2358 ASSERT_RETURN_ERROR (Status);
2359 Modified = TRUE;
2360 }
2361 }
2362
2363 if (Modified) {
2364 //
2365 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2366 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2367 //
2368 Status = MtrrLibSetMemoryRanges (
2369 DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,
2370 Scratch, ScratchSize,
2371 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount
2372 );
2373 if (RETURN_ERROR (Status)) {
2374 goto Exit;
2375 }
2376
2377 //
2378 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2379 //
2380 for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {
2381 if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {
2382 ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);
2383 WorkingVariableMtrrCount--;
2384 CopyMem (
2385 &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],
2386 (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])
2387 );
2388 break;
2389 }
2390 }
2391
2392 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
2393 Status = RETURN_OUT_OF_RESOURCES;
2394 goto Exit;
2395 }
2396
2397 //
2398 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2399 // Make sure least modification is made to OriginalVariableMtrr.
2400 //
2401 MtrrLibMergeVariableMtrr (
2402 OriginalVariableMtrr, OriginalVariableMtrrCount,
2403 WorkingVariableMtrr, WorkingVariableMtrrCount,
2404 VariableSettingModified
2405 );
2406 }
2407 }
2408
2409 //
2410 // 3. Apply the below-1MB memory attribute settings.
2411 //
2412 ZeroMem (WorkingFixedSettings.Mtrr, sizeof (WorkingFixedSettings.Mtrr));
2413 for (Index = 0; Index < RangeCount; Index++) {
2414 if (Ranges[Index].BaseAddress >= BASE_1MB) {
2415 continue;
2416 }
2417
2418 Status = MtrrLibSetBelow1MBMemoryAttribute (
2419 &WorkingFixedSettings, FixedSettingsModified,
2420 Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type
2421 );
2422 if (RETURN_ERROR (Status)) {
2423 goto Exit;
2424 }
2425 }
2426
2427 MtrrContextValid = FALSE;
2428 //
2429 // 4. Write fixed MTRRs that have been modified
2430 //
2431 for (Index = 0; Index < ARRAY_SIZE (FixedSettingsModified); Index++) {
2432 if (FixedSettingsModified[Index]) {
2433 if (MtrrSetting != NULL) {
2434 MtrrSetting->Fixed.Mtrr[Index] = WorkingFixedSettings.Mtrr[Index];
2435 } else {
2436 if (!MtrrContextValid) {
2437 MtrrLibPreMtrrChange (&MtrrContext);
2438 MtrrContextValid = TRUE;
2439 }
2440 AsmWriteMsr64 (
2441 mMtrrLibFixedMtrrTable[Index].Msr,
2442 WorkingFixedSettings.Mtrr[Index]
2443 );
2444 }
2445 }
2446 }
2447
2448 //
2449 // 5. Write variable MTRRs that have been modified
2450 //
2451 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2452 if (VariableSettingModified[Index]) {
2453 if (OriginalVariableMtrr[Index].Length != 0) {
2454 VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)
2455 | (UINT8)OriginalVariableMtrr[Index].Type;
2456 VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;
2457 } else {
2458 VariableSetting.Base = 0;
2459 VariableSetting.Mask = 0;
2460 }
2461 if (MtrrSetting != NULL) {
2462 CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));
2463 } else {
2464 if (!MtrrContextValid) {
2465 MtrrLibPreMtrrChange (&MtrrContext);
2466 MtrrContextValid = TRUE;
2467 }
2468 AsmWriteMsr64 (
2469 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2470 VariableSetting.Base
2471 );
2472 AsmWriteMsr64 (
2473 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2474 VariableSetting.Mask
2475 );
2476 }
2477 }
2478 }
2479
2480 if (MtrrSetting != NULL) {
2481 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;
2482 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;
2483 } else {
2484 if (MtrrContextValid) {
2485 MtrrLibPostMtrrChange (&MtrrContext);
2486 }
2487 }
2488
2489 Exit:
2490 DEBUG ((DEBUG_CACHE, " Result = %r\n", Status));
2491 if (!RETURN_ERROR (Status)) {
2492 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
2493 }
2494 return Status;
2495 }
2496
2497 /**
2498 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2499
2500 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2501 @param[in] BaseAddress The physical address that is the start address
2502 of a memory range.
2503 @param[in] Length The size in bytes of the memory range.
2504 @param[in] Attribute The bit mask of attributes to set for the
2505 memory range.
2506
2507 @retval RETURN_SUCCESS The attributes were set for the memory range.
2508 @retval RETURN_INVALID_PARAMETER Length is zero.
2509 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2510 memory resource range specified by BaseAddress and Length.
2511 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2512 range specified by BaseAddress and Length.
2513 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2514 BaseAddress and Length cannot be modified.
2515 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2516 the memory resource range.
2517 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2518 **/
2519 RETURN_STATUS
2520 EFIAPI
2521 MtrrSetMemoryAttributeInMtrrSettings (
2522 IN OUT MTRR_SETTINGS *MtrrSetting,
2523 IN PHYSICAL_ADDRESS BaseAddress,
2524 IN UINT64 Length,
2525 IN MTRR_MEMORY_CACHE_TYPE Attribute
2526 )
2527 {
2528 UINT8 Scratch[SCRATCH_BUFFER_SIZE];
2529 UINTN ScratchSize;
2530 MTRR_MEMORY_RANGE Range;
2531
2532 Range.BaseAddress = BaseAddress;
2533 Range.Length = Length;
2534 Range.Type = Attribute;
2535 ScratchSize = sizeof (Scratch);
2536 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);
2537 }
2538
2539 /**
2540 This function attempts to set the attributes for a memory range.
2541
2542 @param[in] BaseAddress The physical address that is the start
2543 address of a memory range.
2544 @param[in] Length The size in bytes of the memory range.
2545 @param[in] Attributes The bit mask of attributes to set for the
2546 memory range.
2547
2548 @retval RETURN_SUCCESS The attributes were set for the memory
2549 range.
2550 @retval RETURN_INVALID_PARAMETER Length is zero.
2551 @retval RETURN_UNSUPPORTED The processor does not support one or
2552 more bytes of the memory resource range
2553 specified by BaseAddress and Length.
2554 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2555 for the memory resource range specified
2556 by BaseAddress and Length.
2557 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2558 range specified by BaseAddress and Length
2559 cannot be modified.
2560 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2561 modify the attributes of the memory
2562 resource range.
2563 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2564 **/
2565 RETURN_STATUS
2566 EFIAPI
2567 MtrrSetMemoryAttribute (
2568 IN PHYSICAL_ADDRESS BaseAddress,
2569 IN UINT64 Length,
2570 IN MTRR_MEMORY_CACHE_TYPE Attribute
2571 )
2572 {
2573 return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);
2574 }
2575
2576 /**
2577 Worker function setting variable MTRRs
2578
2579 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2580
2581 **/
2582 VOID
2583 MtrrSetVariableMtrrWorker (
2584 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2585 )
2586 {
2587 UINT32 Index;
2588 UINT32 VariableMtrrCount;
2589
2590 VariableMtrrCount = GetVariableMtrrCountWorker ();
2591 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
2592
2593 for (Index = 0; Index < VariableMtrrCount; Index++) {
2594 //
2595 // Mask MSR is always updated since caller might need to invalidate the MSR pair.
2596 // Base MSR is skipped when Mask.V is not set.
2597 //
2598 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSettings->Mtrr[Index].Mask);
2599 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
2600 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSettings->Mtrr[Index].Base);
2601 }
2602 }
2603 }
2604
2605
2606 /**
2607 This function sets variable MTRRs
2608
2609 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2610
2611 @return The pointer of VariableSettings
2612
2613 **/
2614 MTRR_VARIABLE_SETTINGS*
2615 EFIAPI
2616 MtrrSetVariableMtrr (
2617 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2618 )
2619 {
2620 MTRR_CONTEXT MtrrContext;
2621
2622 if (!IsMtrrSupported ()) {
2623 return VariableSettings;
2624 }
2625
2626 MtrrLibPreMtrrChange (&MtrrContext);
2627 MtrrSetVariableMtrrWorker (VariableSettings);
2628 MtrrLibPostMtrrChange (&MtrrContext);
2629 MtrrDebugPrintAllMtrrs ();
2630
2631 return VariableSettings;
2632 }
2633
2634 /**
2635 Worker function setting fixed MTRRs
2636
2637 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2638
2639 **/
2640 VOID
2641 MtrrSetFixedMtrrWorker (
2642 IN MTRR_FIXED_SETTINGS *FixedSettings
2643 )
2644 {
2645 UINT32 Index;
2646
2647 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2648 AsmWriteMsr64 (
2649 mMtrrLibFixedMtrrTable[Index].Msr,
2650 FixedSettings->Mtrr[Index]
2651 );
2652 }
2653 }
2654
2655
2656 /**
2657 This function sets fixed MTRRs
2658
2659 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2660
2661 @retval The pointer of FixedSettings
2662
2663 **/
2664 MTRR_FIXED_SETTINGS*
2665 EFIAPI
2666 MtrrSetFixedMtrr (
2667 IN MTRR_FIXED_SETTINGS *FixedSettings
2668 )
2669 {
2670 MTRR_CONTEXT MtrrContext;
2671
2672 if (!IsMtrrSupported ()) {
2673 return FixedSettings;
2674 }
2675
2676 MtrrLibPreMtrrChange (&MtrrContext);
2677 MtrrSetFixedMtrrWorker (FixedSettings);
2678 MtrrLibPostMtrrChange (&MtrrContext);
2679 MtrrDebugPrintAllMtrrs ();
2680
2681 return FixedSettings;
2682 }
2683
2684
2685 /**
2686 This function gets the content in all MTRRs (variable and fixed)
2687
2688 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2689
2690 @retval the pointer of MtrrSetting
2691
2692 **/
2693 MTRR_SETTINGS *
2694 EFIAPI
2695 MtrrGetAllMtrrs (
2696 OUT MTRR_SETTINGS *MtrrSetting
2697 )
2698 {
2699 if (!IsMtrrSupported ()) {
2700 return MtrrSetting;
2701 }
2702
2703 //
2704 // Get fixed MTRRs
2705 //
2706 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2707
2708 //
2709 // Get variable MTRRs
2710 //
2711 MtrrGetVariableMtrrWorker (
2712 NULL,
2713 GetVariableMtrrCountWorker (),
2714 &MtrrSetting->Variables
2715 );
2716
2717 //
2718 // Get MTRR_DEF_TYPE value
2719 //
2720 MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
2721
2722 return MtrrSetting;
2723 }
2724
2725
2726 /**
2727 This function sets all MTRRs (variable and fixed)
2728
2729 @param[in] MtrrSetting A buffer holding all MTRRs content.
2730
2731 @retval The pointer of MtrrSetting
2732
2733 **/
2734 MTRR_SETTINGS *
2735 EFIAPI
2736 MtrrSetAllMtrrs (
2737 IN MTRR_SETTINGS *MtrrSetting
2738 )
2739 {
2740 MTRR_CONTEXT MtrrContext;
2741
2742 if (!IsMtrrSupported ()) {
2743 return MtrrSetting;
2744 }
2745
2746 MtrrLibPreMtrrChange (&MtrrContext);
2747
2748 //
2749 // Set fixed MTRRs
2750 //
2751 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2752
2753 //
2754 // Set variable MTRRs
2755 //
2756 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2757
2758 //
2759 // Set MTRR_DEF_TYPE value
2760 //
2761 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2762
2763 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
2764
2765 return MtrrSetting;
2766 }
2767
2768
2769 /**
2770 Checks if MTRR is supported.
2771
2772 @retval TRUE MTRR is supported.
2773 @retval FALSE MTRR is not supported.
2774
2775 **/
2776 BOOLEAN
2777 EFIAPI
2778 IsMtrrSupported (
2779 VOID
2780 )
2781 {
2782 CPUID_VERSION_INFO_EDX Edx;
2783 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
2784
2785 //
2786 // Check CPUID(1).EDX[12] for MTRR capability
2787 //
2788 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
2789 if (Edx.Bits.MTRR == 0) {
2790 return FALSE;
2791 }
2792
2793 //
2794 // Check number of variable MTRRs and fixed MTRRs existence.
2795 // If number of variable MTRRs is zero, or fixed MTRRs do not
2796 // exist, return false.
2797 //
2798 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
2799 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
2800 return FALSE;
2801 }
2802 return TRUE;
2803 }
2804
2805
2806 /**
2807 Worker function prints all MTRRs for debugging.
2808
2809 If MtrrSetting is not NULL, print MTRR settings from input MTRR
2810 settings buffer.
2811 If MtrrSetting is NULL, print MTRR settings from MTRRs.
2812
2813 @param MtrrSetting A buffer holding all MTRRs content.
2814 **/
2815 VOID
2816 MtrrDebugPrintAllMtrrsWorker (
2817 IN MTRR_SETTINGS *MtrrSetting
2818 )
2819 {
2820 DEBUG_CODE (
2821 MTRR_SETTINGS LocalMtrrs;
2822 MTRR_SETTINGS *Mtrrs;
2823 UINTN Index;
2824 UINTN RangeCount;
2825 UINT64 MtrrValidBitsMask;
2826 UINT64 MtrrValidAddressMask;
2827 UINT32 VariableMtrrCount;
2828 BOOLEAN ContainVariableMtrr;
2829 MTRR_MEMORY_RANGE Ranges[
2830 ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1
2831 ];
2832 MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
2833
2834 if (!IsMtrrSupported ()) {
2835 return;
2836 }
2837
2838 VariableMtrrCount = GetVariableMtrrCountWorker ();
2839
2840 if (MtrrSetting != NULL) {
2841 Mtrrs = MtrrSetting;
2842 } else {
2843 MtrrGetAllMtrrs (&LocalMtrrs);
2844 Mtrrs = &LocalMtrrs;
2845 }
2846
2847 //
2848 // Dump RAW MTRR contents
2849 //
2850 DEBUG ((DEBUG_CACHE, "MTRR Settings:\n"));
2851 DEBUG ((DEBUG_CACHE, "=============\n"));
2852 DEBUG ((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
2853 for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {
2854 DEBUG ((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
2855 }
2856 ContainVariableMtrr = FALSE;
2857 for (Index = 0; Index < VariableMtrrCount; Index++) {
2858 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 0) {
2859 //
2860 // If mask is not valid, then do not display range
2861 //
2862 continue;
2863 }
2864 ContainVariableMtrr = TRUE;
2865 DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2866 Index,
2867 Mtrrs->Variables.Mtrr[Index].Base,
2868 Mtrrs->Variables.Mtrr[Index].Mask
2869 ));
2870 }
2871 if (!ContainVariableMtrr) {
2872 DEBUG ((DEBUG_CACHE, "Variable MTRR : None.\n"));
2873 }
2874 DEBUG((DEBUG_CACHE, "\n"));
2875
2876 //
2877 // Dump MTRR setting in ranges
2878 //
2879 DEBUG((DEBUG_CACHE, "Memory Ranges:\n"));
2880 DEBUG((DEBUG_CACHE, "====================================\n"));
2881 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
2882 Ranges[0].BaseAddress = 0;
2883 Ranges[0].Length = MtrrValidBitsMask + 1;
2884 Ranges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs);
2885 RangeCount = 1;
2886
2887 MtrrLibGetRawVariableRanges (
2888 &Mtrrs->Variables, VariableMtrrCount,
2889 MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges
2890 );
2891 MtrrLibApplyVariableMtrrs (
2892 RawVariableRanges, VariableMtrrCount,
2893 Ranges, ARRAY_SIZE (Ranges), &RangeCount
2894 );
2895
2896 MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);
2897
2898 for (Index = 0; Index < RangeCount; Index++) {
2899 DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",
2900 mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],
2901 Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1
2902 ));
2903 }
2904 );
2905 }
2906
2907 /**
2908 This function prints all MTRRs for debugging.
2909 **/
2910 VOID
2911 EFIAPI
2912 MtrrDebugPrintAllMtrrs (
2913 VOID
2914 )
2915 {
2916 MtrrDebugPrintAllMtrrsWorker (NULL);
2917 }