]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c
UefiCpuPkg: Apply uncrustify changes
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / UnitTest / Support.c
CommitLineData
e17f459a
RN
1/** @file\r
2 Unit tests of the MtrrLib instance of the MtrrLib class\r
3\r
4 Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "MtrrLibUnitTest.h"\r
10\r
053e878b 11MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {\r
e17f459a 12 CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack\r
053e878b 13};\r
e17f459a
RN
14\r
15UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_MTRR];\r
16MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
17MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
18MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr;\r
19MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr;\r
20CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx;\r
21CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax;\r
22\r
053e878b
MK
23BOOLEAN mRandomInput;\r
24UINTN mNumberIndex = 0;\r
25extern UINTN mNumbers[];\r
26extern UINTN mNumberCount;\r
65904cdb
RN
27\r
28/**\r
29 Return a random number between 0 and RAND_MAX.\r
30\r
31 If mRandomInput is TRUE, the routine directly calls rand().\r
32 Otherwise, the routine returns the pre-generated numbers.\r
33\r
34 @return a number between 0 and RAND_MAX.\r
35**/\r
36UINTN\r
37Rand (\r
38 VOID\r
39 )\r
40{\r
41 if (mRandomInput) {\r
42 return rand ();\r
43 } else {\r
44 DEBUG ((DEBUG_INFO, "random: %d\n", mNumberIndex));\r
45 return mNumbers[mNumberIndex++ % (mNumberCount - 1)];\r
46 }\r
47}\r
48\r
49CHAR8 mContentTemplate[] = {\r
50 "/** @file\n"\r
51 " Pre-generated random number used by MtrrLib test.\n"\r
52 "\n"\r
53 " Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\n"\r
54 " SPDX-License-Identifier: BSD-2-Clause-Patent\n"\r
55 "**/\n"\r
56 "UINTN mNumberCount = %d;\n"\r
57 "UINTN mNumbers[] = {"\r
58};\r
59\r
60/**\r
61 Generate Count random numbers in FilePath.\r
62\r
63 @param FilePath The file path to put the generated random numbers.\r
64 @param Count Count of random numbers.\r
65**/\r
66VOID\r
67GenerateRandomNumbers (\r
053e878b
MK
68 CHAR8 *FilePath,\r
69 UINTN Count\r
65904cdb
RN
70 )\r
71{\r
72 FILE *File;\r
73 UINTN Index;\r
74\r
75 File = fopen (FilePath, "w");\r
76 fprintf (File, mContentTemplate, Count);\r
77 for (Index = 0; Index < Count; Index++) {\r
78 if (Index % 10 == 0) {\r
79 fprintf (File, "\n ");\r
80 }\r
053e878b 81\r
65904cdb
RN
82 fprintf (File, " %d,", rand ());\r
83 }\r
053e878b 84\r
65904cdb
RN
85 fprintf (File, "\n};\n");\r
86 fclose (File);\r
87}\r
88\r
e17f459a
RN
89/**\r
90 Retrieves CPUID information.\r
91\r
92 Executes the CPUID instruction with EAX set to the value specified by Index.\r
93 This function always returns Index.\r
94 If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.\r
95 If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.\r
96 If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.\r
97 If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.\r
98 This function is only available on IA-32 and x64.\r
99\r
100 @param Index The 32-bit value to load into EAX prior to invoking the CPUID\r
101 instruction.\r
102 @param Eax The pointer to the 32-bit EAX value returned by the CPUID\r
103 instruction. This is an optional parameter that may be NULL.\r
104 @param Ebx The pointer to the 32-bit EBX value returned by the CPUID\r
105 instruction. This is an optional parameter that may be NULL.\r
106 @param Ecx The pointer to the 32-bit ECX value returned by the CPUID\r
107 instruction. This is an optional parameter that may be NULL.\r
108 @param Edx The pointer to the 32-bit EDX value returned by the CPUID\r
109 instruction. This is an optional parameter that may be NULL.\r
110\r
111 @return Index.\r
112\r
113**/\r
114UINT32\r
115EFIAPI\r
116UnitTestMtrrLibAsmCpuid (\r
053e878b
MK
117 IN UINT32 Index,\r
118 OUT UINT32 *Eax OPTIONAL,\r
119 OUT UINT32 *Ebx OPTIONAL,\r
120 OUT UINT32 *Ecx OPTIONAL,\r
121 OUT UINT32 *Edx OPTIONAL\r
e17f459a
RN
122 )\r
123{\r
124 switch (Index) {\r
053e878b
MK
125 case CPUID_VERSION_INFO:\r
126 if (Edx != NULL) {\r
127 *Edx = mCpuidVersionInfoEdx.Uint32;\r
128 }\r
129\r
130 return Index;\r
131 break;\r
132 case CPUID_EXTENDED_FUNCTION:\r
133 if (Eax != NULL) {\r
134 *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;\r
135 }\r
136\r
137 return Index;\r
138 break;\r
139 case CPUID_VIR_PHY_ADDRESS_SIZE:\r
140 if (Eax != NULL) {\r
141 *Eax = mCpuidVirPhyAddressSizeEax.Uint32;\r
142 }\r
143\r
144 return Index;\r
145 break;\r
e17f459a
RN
146 }\r
147\r
148 //\r
149 // Should never fall through to here\r
150 //\r
053e878b 151 ASSERT (FALSE);\r
e17f459a
RN
152 return Index;\r
153}\r
154\r
155/**\r
156 Returns a 64-bit Machine Specific Register(MSR).\r
157\r
158 Reads and returns the 64-bit MSR specified by Index. No parameter checking is\r
159 performed on Index, and some Index values may cause CPU exceptions. The\r
160 caller must either guarantee that Index is valid, or the caller must set up\r
161 exception handlers to catch the exceptions. This function is only available\r
162 on IA-32 and x64.\r
163\r
164 @param MsrIndex The 32-bit MSR index to read.\r
165\r
166 @return The value of the MSR identified by MsrIndex.\r
167\r
168**/\r
169UINT64\r
170EFIAPI\r
053e878b 171UnitTestMtrrLibAsmReadMsr64 (\r
e17f459a
RN
172 IN UINT32 MsrIndex\r
173 )\r
174{\r
053e878b 175 UINT32 Index;\r
e17f459a
RN
176\r
177 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {\r
178 if (MsrIndex == mFixedMtrrsIndex[Index]) {\r
179 return mFixedMtrrsValue[Index];\r
180 }\r
181 }\r
182\r
183 if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&\r
053e878b
MK
184 (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1)))\r
185 {\r
e17f459a
RN
186 if (MsrIndex % 2 == 0) {\r
187 Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;\r
188 return mVariableMtrrsPhysBase[Index].Uint64;\r
189 } else {\r
190 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;\r
191 return mVariableMtrrsPhysMask[Index].Uint64;\r
192 }\r
193 }\r
194\r
195 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {\r
196 return mDefTypeMsr.Uint64;\r
197 }\r
198\r
199 if (MsrIndex == MSR_IA32_MTRRCAP) {\r
200 return mMtrrCapMsr.Uint64;\r
201 }\r
202\r
203 //\r
204 // Should never fall through to here\r
205 //\r
053e878b 206 ASSERT (FALSE);\r
e17f459a
RN
207 return 0;\r
208}\r
209\r
210/**\r
211 Writes a 64-bit value to a Machine Specific Register(MSR), and returns the\r
212 value.\r
213\r
214 Writes the 64-bit value specified by Value to the MSR specified by Index. The\r
215 64-bit value written to the MSR is returned. No parameter checking is\r
216 performed on Index or Value, and some of these may cause CPU exceptions. The\r
217 caller must either guarantee that Index and Value are valid, or the caller\r
218 must establish proper exception handlers. This function is only available on\r
219 IA-32 and x64.\r
220\r
221 @param MsrIndex The 32-bit MSR index to write.\r
222 @param Value The 64-bit value to write to the MSR.\r
223\r
224 @return Value\r
225\r
226**/\r
227UINT64\r
228EFIAPI\r
053e878b
MK
229UnitTestMtrrLibAsmWriteMsr64 (\r
230 IN UINT32 MsrIndex,\r
231 IN UINT64 Value\r
e17f459a
RN
232 )\r
233{\r
053e878b 234 UINT32 Index;\r
e17f459a
RN
235\r
236 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {\r
237 if (MsrIndex == mFixedMtrrsIndex[Index]) {\r
238 mFixedMtrrsValue[Index] = Value;\r
239 return Value;\r
240 }\r
241 }\r
242\r
243 if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&\r
053e878b
MK
244 (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1)))\r
245 {\r
e17f459a 246 if (MsrIndex % 2 == 0) {\r
053e878b 247 Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;\r
e17f459a
RN
248 mVariableMtrrsPhysBase[Index].Uint64 = Value;\r
249 return Value;\r
250 } else {\r
053e878b 251 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;\r
e17f459a
RN
252 mVariableMtrrsPhysMask[Index].Uint64 = Value;\r
253 return Value;\r
254 }\r
255 }\r
256\r
257 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {\r
258 mDefTypeMsr.Uint64 = Value;\r
259 return Value;\r
260 }\r
261\r
262 if (MsrIndex == MSR_IA32_MTRRCAP) {\r
263 mMtrrCapMsr.Uint64 = Value;\r
264 return Value;\r
265 }\r
266\r
267 //\r
268 // Should never fall through to here\r
269 //\r
053e878b 270 ASSERT (FALSE);\r
e17f459a
RN
271 return 0;\r
272}\r
273\r
274/**\r
275 Initialize the MTRR registers.\r
276\r
277 @param SystemParameter System parameter that controls the MTRR registers initialization.\r
278**/\r
279UNIT_TEST_STATUS\r
280EFIAPI\r
281InitializeMtrrRegs (\r
282 IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter\r
283 )\r
284{\r
053e878b 285 UINT32 Index;\r
e17f459a
RN
286\r
287 SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);\r
288\r
289 for (Index = 0; Index < ARRAY_SIZE (mVariableMtrrsPhysBase); Index++) {\r
290 mVariableMtrrsPhysBase[Index].Uint64 = 0;\r
291 mVariableMtrrsPhysBase[Index].Bits.Type = SystemParameter->DefaultCacheType;\r
292 mVariableMtrrsPhysBase[Index].Bits.Reserved1 = 0;\r
293\r
294 mVariableMtrrsPhysMask[Index].Uint64 = 0;\r
295 mVariableMtrrsPhysMask[Index].Bits.V = 0;\r
296 mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;\r
297 }\r
298\r
299 mDefTypeMsr.Bits.E = 1;\r
300 mDefTypeMsr.Bits.FE = 1;\r
301 mDefTypeMsr.Bits.Type = SystemParameter->DefaultCacheType;\r
302 mDefTypeMsr.Bits.Reserved1 = 0;\r
303 mDefTypeMsr.Bits.Reserved2 = 0;\r
304 mDefTypeMsr.Bits.Reserved3 = 0;\r
305\r
306 mMtrrCapMsr.Bits.SMRR = 0;\r
307 mMtrrCapMsr.Bits.WC = 0;\r
308 mMtrrCapMsr.Bits.VCNT = SystemParameter->VariableMtrrCount;\r
309 mMtrrCapMsr.Bits.FIX = SystemParameter->FixedMtrrSupported;\r
310 mMtrrCapMsr.Bits.Reserved1 = 0;\r
311 mMtrrCapMsr.Bits.Reserved2 = 0;\r
312 mMtrrCapMsr.Bits.Reserved3 = 0;\r
313\r
314 mCpuidVersionInfoEdx.Bits.MTRR = SystemParameter->MtrrSupported;\r
315 mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;\r
316\r
317 //\r
318 // Hook BaseLib functions used by MtrrLib that require some emulation.\r
319 //\r
320 gUnitTestHostBaseLib.X86->AsmCpuid = UnitTestMtrrLibAsmCpuid;\r
321 gUnitTestHostBaseLib.X86->AsmReadMsr64 = UnitTestMtrrLibAsmReadMsr64;\r
322 gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;\r
323\r
324 return UNIT_TEST_PASSED;\r
325}\r
326\r
327/**\r
328 Initialize the MTRR registers.\r
329\r
330 @param Context System parameter that controls the MTRR registers initialization.\r
331**/\r
332UNIT_TEST_STATUS\r
333EFIAPI\r
334InitializeSystem (\r
053e878b 335 IN UNIT_TEST_CONTEXT Context\r
e17f459a
RN
336 )\r
337{\r
053e878b 338 return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *)Context);\r
e17f459a
RN
339}\r
340\r
341/**\r
342 Collect the test result.\r
343\r
344 @param DefaultType Default memory type.\r
345 @param PhysicalAddressBits Physical address bits.\r
346 @param VariableMtrrCount Count of variable MTRRs.\r
347 @param Mtrrs MTRR settings to collect from.\r
348 @param Ranges Return the memory ranges.\r
349 @param RangeCount Return the count of memory ranges.\r
350 @param MtrrCount Return the count of variable MTRRs being used.\r
351**/\r
352VOID\r
353CollectTestResult (\r
053e878b
MK
354 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
355 IN UINT32 PhysicalAddressBits,\r
356 IN UINT32 VariableMtrrCount,\r
357 IN MTRR_SETTINGS *Mtrrs,\r
358 OUT MTRR_MEMORY_RANGE *Ranges,\r
359 IN OUT UINTN *RangeCount,\r
360 OUT UINT32 *MtrrCount\r
e17f459a
RN
361 )\r
362{\r
053e878b
MK
363 UINTN Index;\r
364 UINT64 MtrrValidBitsMask;\r
365 UINT64 MtrrValidAddressMask;\r
366 MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
e17f459a
RN
367\r
368 ASSERT (Mtrrs != NULL);\r
369 ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));\r
370\r
053e878b 371 MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;\r
e17f459a
RN
372 MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;\r
373\r
374 *MtrrCount = 0;\r
375 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
053e878b 376 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 1) {\r
e17f459a
RN
377 RawMemoryRanges[*MtrrCount].BaseAddress = Mtrrs->Variables.Mtrr[Index].Base & MtrrValidAddressMask;\r
378 RawMemoryRanges[*MtrrCount].Type =\r
053e878b
MK
379 ((MSR_IA32_MTRR_PHYSBASE_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Base)->Bits.Type;\r
380 RawMemoryRanges[*MtrrCount].Length =\r
381 ((~(Mtrrs->Variables.Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
e17f459a
RN
382 (*MtrrCount)++;\r
383 }\r
384 }\r
385\r
386 GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);\r
387}\r
388\r
389/**\r
390 Return a 32bit random number.\r
391\r
392 @param Start Start of the random number range.\r
393 @param Limit Limit of the random number range.\r
394 @return 32bit random number\r
395**/\r
396UINT32\r
397Random32 (\r
398 UINT32 Start,\r
399 UINT32 Limit\r
400 )\r
401{\r
053e878b 402 return (UINT32)(((double)Rand () / RAND_MAX) * (Limit - Start)) + Start;\r
e17f459a
RN
403}\r
404\r
405/**\r
406 Return a 64bit random number.\r
407\r
408 @param Start Start of the random number range.\r
409 @param Limit Limit of the random number range.\r
410 @return 64bit random number\r
411**/\r
412UINT64\r
413Random64 (\r
414 UINT64 Start,\r
415 UINT64 Limit\r
416 )\r
417{\r
053e878b 418 return (UINT64)(((double)Rand () / RAND_MAX) * (Limit - Start)) + Start;\r
e17f459a
RN
419}\r
420\r
421/**\r
422 Generate random MTRR BASE/MASK for a specified type.\r
423\r
424 @param PhysicalAddressBits Physical address bits.\r
425 @param CacheType Cache type.\r
426 @param MtrrPair Return the random MTRR.\r
427 @param MtrrMemoryRange Return the random memory range.\r
428**/\r
429VOID\r
430GenerateRandomMtrrPair (\r
053e878b
MK
431 IN UINT32 PhysicalAddressBits,\r
432 IN MTRR_MEMORY_CACHE_TYPE CacheType,\r
433 OUT MTRR_VARIABLE_SETTING *MtrrPair OPTIONAL,\r
434 OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL\r
e17f459a
RN
435 )\r
436{\r
053e878b
MK
437 MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;\r
438 MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;\r
439 UINT32 SizeShift;\r
440 UINT32 BaseShift;\r
441 UINT64 RandomBoundary;\r
442 UINT64 MaxPhysicalAddress;\r
443 UINT64 RangeSize;\r
444 UINT64 RangeBase;\r
445 UINT64 PhysBasePhyMaskValidBitsMask;\r
e17f459a
RN
446\r
447 MaxPhysicalAddress = 1ull << PhysicalAddressBits;\r
448 do {\r
449 SizeShift = Random32 (12, PhysicalAddressBits - 1);\r
450 RangeSize = 1ull << SizeShift;\r
451\r
053e878b 452 BaseShift = Random32 (SizeShift, PhysicalAddressBits - 1);\r
e17f459a 453 RandomBoundary = Random64 (0, 1ull << (PhysicalAddressBits - BaseShift));\r
053e878b 454 RangeBase = RandomBoundary << BaseShift;\r
e17f459a
RN
455 } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1);\r
456\r
457 PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;\r
458\r
459 PhysBase.Uint64 = 0;\r
460 PhysBase.Bits.Type = CacheType;\r
461 PhysBase.Uint64 |= RangeBase & PhysBasePhyMaskValidBitsMask;\r
462 PhysMask.Uint64 = 0;\r
463 PhysMask.Bits.V = 1;\r
464 PhysMask.Uint64 |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;\r
465\r
466 if (MtrrPair != NULL) {\r
467 MtrrPair->Base = PhysBase.Uint64;\r
468 MtrrPair->Mask = PhysMask.Uint64;\r
469 }\r
470\r
471 if (MtrrMemoryRange != NULL) {\r
472 MtrrMemoryRange->BaseAddress = RangeBase;\r
473 MtrrMemoryRange->Length = RangeSize;\r
474 MtrrMemoryRange->Type = CacheType;\r
475 }\r
476}\r
477\r
e17f459a
RN
478/**\r
479 Check whether the Range overlaps with any one in Ranges.\r
480\r
481 @param Range The memory range to check.\r
482 @param Ranges The memory ranges.\r
483 @param Count Count of memory ranges.\r
484\r
485 @return TRUE when overlap exists.\r
486**/\r
487BOOLEAN\r
488RangesOverlap (\r
053e878b
MK
489 IN MTRR_MEMORY_RANGE *Range,\r
490 IN MTRR_MEMORY_RANGE *Ranges,\r
491 IN UINTN Count\r
e17f459a
RN
492 )\r
493{\r
494 while (Count-- != 0) {\r
495 //\r
496 // Two ranges overlap when:\r
497 // 1. range#2.base is in the middle of range#1\r
498 // 2. range#1.base is in the middle of range#2\r
499 //\r
053e878b
MK
500 if ( ((Range->BaseAddress <= Ranges[Count].BaseAddress) && (Ranges[Count].BaseAddress < Range->BaseAddress + Range->Length))\r
501 || ((Ranges[Count].BaseAddress <= Range->BaseAddress) && (Range->BaseAddress < Ranges[Count].BaseAddress + Ranges[Count].Length)))\r
502 {\r
e17f459a
RN
503 return TRUE;\r
504 }\r
505 }\r
053e878b 506\r
e17f459a
RN
507 return FALSE;\r
508}\r
509\r
510/**\r
511 Generate random MTRRs.\r
512\r
513 @param PhysicalAddressBits Physical address bits.\r
514 @param RawMemoryRanges Return the randomly generated MTRRs.\r
515 @param UcCount Count of Uncacheable MTRRs.\r
516 @param WtCount Count of Write Through MTRRs.\r
517 @param WbCount Count of Write Back MTRRs.\r
518 @param WpCount Count of Write Protected MTRRs.\r
519 @param WcCount Count of Write Combine MTRRs.\r
520**/\r
521VOID\r
522GenerateValidAndConfigurableMtrrPairs (\r
053e878b
MK
523 IN UINT32 PhysicalAddressBits,\r
524 IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,\r
525 IN UINT32 UcCount,\r
526 IN UINT32 WtCount,\r
527 IN UINT32 WbCount,\r
528 IN UINT32 WpCount,\r
529 IN UINT32 WcCount\r
e17f459a
RN
530 )\r
531{\r
053e878b 532 UINT32 Index;\r
e17f459a
RN
533\r
534 //\r
535 // 1. Generate UC, WT, WB in order.\r
536 //\r
537 for (Index = 0; Index < UcCount; Index++) {\r
538 GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);\r
539 }\r
540\r
541 for (Index = UcCount; Index < UcCount + WtCount; Index++) {\r
542 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);\r
543 }\r
544\r
545 for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {\r
546 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);\r
547 }\r
548\r
549 //\r
550 // 2. Generate WP MTRR and DO NOT overlap with WT, WB.\r
551 //\r
552 for (Index = UcCount + WtCount + WbCount; Index < UcCount + WtCount + WbCount + WpCount; Index++) {\r
553 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);\r
554 while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount)) {\r
555 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);\r
556 }\r
557 }\r
558\r
559 //\r
560 // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.\r
561 //\r
562 for (Index = UcCount + WtCount + WbCount + WpCount; Index < UcCount + WtCount + WbCount + WpCount + WcCount; Index++) {\r
563 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);\r
564 while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount + WpCount)) {\r
565 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);\r
566 }\r
567 }\r
568}\r
569\r
570/**\r
571 Return a random memory cache type.\r
572**/\r
573MTRR_MEMORY_CACHE_TYPE\r
574GenerateRandomCacheType (\r
575 VOID\r
576 )\r
577{\r
053e878b 578 return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];\r
e17f459a
RN
579}\r
580\r
581/**\r
582 Compare function used by qsort().\r
583**/\r
584\r
585/**\r
586 Compare function used by qsort().\r
587\r
588 @param Left Left operand to compare.\r
589 @param Right Right operand to compare.\r
590\r
591 @retval 0 Left == Right\r
592 @retval -1 Left < Right\r
593 @retval 1 Left > Right\r
594**/\r
595INT32\r
596CompareFuncUint64 (\r
053e878b
MK
597 CONST VOID *Left,\r
598 CONST VOID *Right\r
e17f459a
RN
599 )\r
600{\r
053e878b
MK
601 INT64 Delta;\r
602\r
603 Delta = (*(UINT64 *)Left - *(UINT64 *)Right);\r
604 if (Delta > 0) {\r
605 return 1;\r
606 } else if (Delta == 0) {\r
607 return 0;\r
608 } else {\r
609 return -1;\r
610 }\r
e17f459a
RN
611}\r
612\r
613/**\r
614 Determin the memory cache type for the Range.\r
615\r
616 @param DefaultType Default cache type.\r
617 @param Range The memory range to determin the cache type.\r
618 @param Ranges The entire memory ranges.\r
619 @param RangeCount Count of the entire memory ranges.\r
620**/\r
621VOID\r
622DetermineMemoryCacheType (\r
053e878b
MK
623 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
624 IN OUT MTRR_MEMORY_RANGE *Range,\r
625 IN MTRR_MEMORY_RANGE *Ranges,\r
626 IN UINT32 RangeCount\r
e17f459a
RN
627 )\r
628{\r
053e878b
MK
629 UINT32 Index;\r
630\r
e17f459a
RN
631 Range->Type = CacheInvalid;\r
632 for (Index = 0; Index < RangeCount; Index++) {\r
633 if (RangesOverlap (Range, &Ranges[Index], 1)) {\r
634 if (Ranges[Index].Type < Range->Type) {\r
635 Range->Type = Ranges[Index].Type;\r
636 }\r
637 }\r
638 }\r
639\r
640 if (Range->Type == CacheInvalid) {\r
641 Range->Type = DefaultType;\r
642 }\r
643}\r
644\r
645/**\r
646 Get the index of the element that does NOT equals to Array[Index].\r
647\r
648 @param Index Current element.\r
649 @param Array Array to scan.\r
650 @param Count Count of the array.\r
651\r
652 @return Next element that doesn't equal to current one.\r
653**/\r
654UINT32\r
655GetNextDifferentElementInSortedArray (\r
053e878b
MK
656 IN UINT32 Index,\r
657 IN UINT64 *Array,\r
658 IN UINT32 Count\r
e17f459a
RN
659 )\r
660{\r
053e878b
MK
661 UINT64 CurrentElement;\r
662\r
e17f459a
RN
663 CurrentElement = Array[Index];\r
664 while (CurrentElement == Array[Index] && Index < Count) {\r
665 Index++;\r
666 }\r
053e878b 667\r
e17f459a
RN
668 return Index;\r
669}\r
670\r
671/**\r
672 Remove the duplicates from the array.\r
673\r
674 @param Array The array to operate on.\r
675 @param Count Count of the array.\r
676**/\r
677VOID\r
678RemoveDuplicatesInSortedArray (\r
053e878b
MK
679 IN OUT UINT64 *Array,\r
680 IN OUT UINT32 *Count\r
e17f459a
RN
681 )\r
682{\r
053e878b
MK
683 UINT32 Index;\r
684 UINT32 NewCount;\r
e17f459a
RN
685\r
686 Index = 0;\r
687 NewCount = 0;\r
688 while (Index < *Count) {\r
689 Array[NewCount] = Array[Index];\r
690 NewCount++;\r
691 Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);\r
692 }\r
053e878b 693\r
e17f459a
RN
694 *Count = NewCount;\r
695}\r
696\r
697/**\r
698 Return TRUE when Address is in the Range.\r
699\r
700 @param Address The address to check.\r
701 @param Range The range to check.\r
702 @return TRUE when Address is in the Range.\r
703**/\r
704BOOLEAN\r
705AddressInRange (\r
053e878b
MK
706 IN UINT64 Address,\r
707 IN MTRR_MEMORY_RANGE Range\r
e17f459a
RN
708 )\r
709{\r
053e878b 710 return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);\r
e17f459a
RN
711}\r
712\r
713/**\r
714 Get the overlap bit flag.\r
715\r
716 @param RawMemoryRanges Raw memory ranges.\r
717 @param RawMemoryRangeCount Count of raw memory ranges.\r
718 @param Address The address to check.\r
719**/\r
720UINT64\r
721GetOverlapBitFlag (\r
053e878b
MK
722 IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
723 IN UINT32 RawMemoryRangeCount,\r
724 IN UINT64 Address\r
e17f459a
RN
725 )\r
726{\r
053e878b
MK
727 UINT64 OverlapBitFlag;\r
728 UINT32 Index;\r
729\r
e17f459a
RN
730 OverlapBitFlag = 0;\r
731 for (Index = 0; Index < RawMemoryRangeCount; Index++) {\r
732 if (AddressInRange (Address, RawMemoryRanges[Index])) {\r
733 OverlapBitFlag |= (1ull << Index);\r
734 }\r
735 }\r
736\r
737 return OverlapBitFlag;\r
738}\r
739\r
740/**\r
741 Return the relationship between flags.\r
742\r
743 @param Flag1 Flag 1\r
744 @param Flag2 Flag 2\r
745\r
746 @retval 0 Flag1 == Flag2\r
747 @retval 1 Flag1 is a subset of Flag2\r
748 @retval 2 Flag2 is a subset of Flag1\r
749 @retval 3 No subset relations between Flag1 and Flag2.\r
750**/\r
751UINT32\r
752CheckOverlapBitFlagsRelation (\r
053e878b
MK
753 IN UINT64 Flag1,\r
754 IN UINT64 Flag2\r
e17f459a
RN
755 )\r
756{\r
053e878b
MK
757 if (Flag1 == Flag2) {\r
758 return 0;\r
759 }\r
760\r
761 if ((Flag1 | Flag2) == Flag2) {\r
762 return 1;\r
763 }\r
764\r
765 if ((Flag1 | Flag2) == Flag1) {\r
766 return 2;\r
767 }\r
768\r
769 return 3;\r
e17f459a
RN
770}\r
771\r
772/**\r
773 Return TRUE when the Endpoint is in any of the Ranges.\r
774\r
775 @param Endpoint The endpoint to check.\r
776 @param Ranges The memory ranges.\r
777 @param RangeCount Count of memory ranges.\r
778\r
779 @retval TRUE Endpoint is in one of the range.\r
780 @retval FALSE Endpoint is not in any of the ranges.\r
781**/\r
782BOOLEAN\r
783IsEndpointInRanges (\r
053e878b
MK
784 IN UINT64 Endpoint,\r
785 IN MTRR_MEMORY_RANGE *Ranges,\r
786 IN UINTN RangeCount\r
e17f459a
RN
787 )\r
788{\r
053e878b
MK
789 UINT32 Index;\r
790\r
791 for (Index = 0; Index < RangeCount; Index++) {\r
792 if (AddressInRange (Endpoint, Ranges[Index])) {\r
793 return TRUE;\r
e17f459a 794 }\r
053e878b 795 }\r
e17f459a 796\r
053e878b
MK
797 return FALSE;\r
798}\r
e17f459a
RN
799\r
800/**\r
801 Compact adjacent ranges of the same type.\r
802\r
803 @param DefaultType Default memory type.\r
804 @param PhysicalAddressBits Physical address bits.\r
805 @param EffectiveMtrrMemoryRanges Memory ranges to compact.\r
806 @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.\r
807**/\r
808VOID\r
809CompactAndExtendEffectiveMtrrMemoryRanges (\r
053e878b
MK
810 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
811 IN UINT32 PhysicalAddressBits,\r
812 IN OUT MTRR_MEMORY_RANGE **EffectiveMtrrMemoryRanges,\r
813 IN OUT UINTN *EffectiveMtrrMemoryRangesCount\r
e17f459a
RN
814 )\r
815{\r
053e878b
MK
816 UINT64 MaxAddress;\r
817 UINTN NewRangesCountAtMost;\r
818 MTRR_MEMORY_RANGE *NewRanges;\r
819 UINTN NewRangesCountActual;\r
820 MTRR_MEMORY_RANGE *CurrentRangeInNewRanges;\r
821 MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges;\r
e17f459a 822\r
053e878b
MK
823 MTRR_MEMORY_RANGE *OldRanges;\r
824 MTRR_MEMORY_RANGE OldLastRange;\r
825 UINTN OldRangesIndex;\r
e17f459a
RN
826\r
827 NewRangesCountActual = 0;\r
828 NewRangesCountAtMost = *EffectiveMtrrMemoryRangesCount + 2; // At most with 2 more range entries.\r
053e878b 829 NewRanges = (MTRR_MEMORY_RANGE *)calloc (NewRangesCountAtMost, sizeof (MTRR_MEMORY_RANGE));\r
e17f459a
RN
830 OldRanges = *EffectiveMtrrMemoryRanges;\r
831 if (OldRanges[0].BaseAddress > 0) {\r
832 NewRanges[NewRangesCountActual].BaseAddress = 0;\r
833 NewRanges[NewRangesCountActual].Length = OldRanges[0].BaseAddress;\r
834 NewRanges[NewRangesCountActual].Type = DefaultType;\r
835 NewRangesCountActual++;\r
836 }\r
837\r
838 OldRangesIndex = 0;\r
839 while (OldRangesIndex < *EffectiveMtrrMemoryRangesCount) {\r
840 CurrentRangeTypeInOldRanges = OldRanges[OldRangesIndex].Type;\r
053e878b
MK
841 CurrentRangeInNewRanges = NULL;\r
842 if (NewRangesCountActual > 0) {\r
843 // We need to check CurrentNewRange first before generate a new NewRange.\r
e17f459a
RN
844 CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];\r
845 }\r
053e878b
MK
846\r
847 if ((CurrentRangeInNewRanges != NULL) && (CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges)) {\r
e17f459a
RN
848 CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;\r
849 } else {\r
850 NewRanges[NewRangesCountActual].BaseAddress = OldRanges[OldRangesIndex].BaseAddress;\r
851 NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;\r
852 NewRanges[NewRangesCountActual].Type = CurrentRangeTypeInOldRanges;\r
053e878b 853 while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && OldRanges[OldRangesIndex + 1].Type == CurrentRangeTypeInOldRanges) {\r
e17f459a
RN
854 OldRangesIndex++;\r
855 NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;\r
856 }\r
053e878b 857\r
e17f459a
RN
858 NewRangesCountActual++;\r
859 }\r
860\r
861 OldRangesIndex++;\r
862 }\r
863\r
053e878b
MK
864 MaxAddress = (1ull << PhysicalAddressBits) - 1;\r
865 OldLastRange = OldRanges[(*EffectiveMtrrMemoryRangesCount) - 1];\r
e17f459a
RN
866 CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];\r
867 if (OldLastRange.BaseAddress + OldLastRange.Length - 1 < MaxAddress) {\r
868 if (CurrentRangeInNewRanges->Type == DefaultType) {\r
869 CurrentRangeInNewRanges->Length = MaxAddress - CurrentRangeInNewRanges->BaseAddress + 1;\r
870 } else {\r
871 NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;\r
053e878b
MK
872 NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;\r
873 NewRanges[NewRangesCountActual].Type = DefaultType;\r
e17f459a
RN
874 NewRangesCountActual++;\r
875 }\r
876 }\r
877\r
878 free (*EffectiveMtrrMemoryRanges);\r
053e878b 879 *EffectiveMtrrMemoryRanges = NewRanges;\r
e17f459a
RN
880 *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;\r
881}\r
882\r
883/**\r
884 Collect all the endpoints in the raw memory ranges.\r
885\r
886 @param Endpoints Return the collected endpoints.\r
887 @param EndPointCount Return the count of endpoints.\r
888 @param RawMemoryRanges Raw memory ranges.\r
889 @param RawMemoryRangeCount Count of raw memory ranges.\r
890**/\r
891VOID\r
892CollectEndpoints (\r
053e878b
MK
893 IN OUT UINT64 *Endpoints,\r
894 IN OUT UINT32 *EndPointCount,\r
895 IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
896 IN UINT32 RawMemoryRangeCount\r
e17f459a
RN
897 )\r
898{\r
053e878b
MK
899 UINT32 Index;\r
900 UINT32 RawRangeIndex;\r
e17f459a
RN
901\r
902 ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);\r
903\r
904 for (Index = 0; Index < *EndPointCount; Index += 2) {\r
053e878b
MK
905 RawRangeIndex = Index >> 1;\r
906 Endpoints[Index] = RawMemoryRanges[RawRangeIndex].BaseAddress;\r
e17f459a
RN
907 Endpoints[Index + 1] = RawMemoryRanges[RawRangeIndex].BaseAddress + RawMemoryRanges[RawRangeIndex].Length - 1;\r
908 }\r
909\r
910 qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);\r
911 RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);\r
912}\r
913\r
914/**\r
915 Convert the MTRR BASE/MASK array to memory ranges.\r
916\r
917 @param DefaultType Default memory type.\r
918 @param PhysicalAddressBits Physical address bits.\r
919 @param RawMemoryRanges Raw memory ranges.\r
920 @param RawMemoryRangeCount Count of raw memory ranges.\r
921 @param MemoryRanges Memory ranges.\r
922 @param MemoryRangeCount Count of memory ranges.\r
923**/\r
924VOID\r
925GetEffectiveMemoryRanges (\r
053e878b
MK
926 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
927 IN UINT32 PhysicalAddressBits,\r
928 IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
929 IN UINT32 RawMemoryRangeCount,\r
930 OUT MTRR_MEMORY_RANGE *MemoryRanges,\r
931 OUT UINTN *MemoryRangeCount\r
e17f459a
RN
932 )\r
933{\r
053e878b
MK
934 UINTN Index;\r
935 UINT32 AllEndPointsCount;\r
936 UINT64 *AllEndPointsInclusive;\r
937 UINT32 AllRangePiecesCountMax;\r
938 MTRR_MEMORY_RANGE *AllRangePieces;\r
939 UINTN AllRangePiecesCountActual;\r
940 UINT64 OverlapBitFlag1;\r
941 UINT64 OverlapBitFlag2;\r
942 INT32 OverlapFlagRelation;\r
e17f459a
RN
943\r
944 if (RawMemoryRangeCount == 0) {\r
945 MemoryRanges[0].BaseAddress = 0;\r
946 MemoryRanges[0].Length = (1ull << PhysicalAddressBits);\r
947 MemoryRanges[0].Type = DefaultType;\r
053e878b 948 *MemoryRangeCount = 1;\r
e17f459a
RN
949 return;\r
950 }\r
951\r
053e878b
MK
952 AllEndPointsCount = RawMemoryRangeCount << 1;\r
953 AllEndPointsInclusive = calloc (AllEndPointsCount, sizeof (UINT64));\r
954 AllRangePiecesCountMax = RawMemoryRangeCount * 3 + 1;\r
955 AllRangePieces = calloc (AllRangePiecesCountMax, sizeof (MTRR_MEMORY_RANGE));\r
e17f459a
RN
956 CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemoryRanges, RawMemoryRangeCount);\r
957\r
958 for (Index = 0, AllRangePiecesCountActual = 0; Index < AllEndPointsCount - 1; Index++) {\r
053e878b
MK
959 OverlapBitFlag1 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index]);\r
960 OverlapBitFlag2 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index + 1]);\r
e17f459a
RN
961 OverlapFlagRelation = CheckOverlapBitFlagsRelation (OverlapBitFlag1, OverlapBitFlag2);\r
962 switch (OverlapFlagRelation) {\r
963 case 0: // [1, 2]\r
964 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
965 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;\r
966 AllRangePiecesCountActual++;\r
967 break;\r
968 case 1: // [1, 2)\r
969 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
970 AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;\r
971 AllRangePiecesCountActual++;\r
972 break;\r
973 case 2: // (1, 2]\r
974 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;\r
975 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;\r
976 AllRangePiecesCountActual++;\r
977\r
978 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {\r
979 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
980 AllRangePieces[AllRangePiecesCountActual].Length = 1;\r
981 AllRangePiecesCountActual++;\r
982 }\r
053e878b 983\r
e17f459a
RN
984 break;\r
985 case 3: // (1, 2)\r
986 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;\r
987 AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - (AllEndPointsInclusive[Index] + 1) + 1;\r
053e878b
MK
988 if (AllRangePieces[AllRangePiecesCountActual].Length == 0) {\r
989 // Only in case 3 can exists Length=0, we should skip such "segment".\r
e17f459a 990 break;\r
053e878b
MK
991 }\r
992\r
e17f459a
RN
993 AllRangePiecesCountActual++;\r
994 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {\r
995 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
996 AllRangePieces[AllRangePiecesCountActual].Length = 1;\r
997 AllRangePiecesCountActual++;\r
998 }\r
053e878b 999\r
e17f459a
RN
1000 break;\r
1001 default:\r
1002 ASSERT (FALSE);\r
1003 }\r
1004 }\r
1005\r
1006 for (Index = 0; Index < AllRangePiecesCountActual; Index++) {\r
1007 DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);\r
1008 }\r
1009\r
1010 CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);\r
1011 ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);\r
1012 memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));\r
1013 *MemoryRangeCount = AllRangePiecesCountActual;\r
1014\r
1015 free (AllEndPointsInclusive);\r
1016 free (AllRangePieces);\r
1017}\r