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