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