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