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