]>
Commit | Line | Data |
---|---|---|
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 | 11 | MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {\r |
e17f459a | 12 | CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack\r |
053e878b | 13 | };\r |
e17f459a RN |
14 | \r |
15 | UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_MTRR];\r | |
16 | MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_VARIABLE_MTRR];\r | |
17 | MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_VARIABLE_MTRR];\r | |
18 | MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr;\r | |
19 | MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr;\r | |
20 | CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx;\r | |
21 | CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax;\r | |
22 | \r | |
053e878b MK |
23 | BOOLEAN mRandomInput;\r |
24 | UINTN mNumberIndex = 0;\r | |
25 | extern UINTN mNumbers[];\r | |
26 | extern 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 | |
36 | UINTN\r | |
37 | Rand (\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 | |
49 | CHAR8 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 | |
66 | VOID\r | |
67 | GenerateRandomNumbers (\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 | |
114 | UINT32\r | |
115 | EFIAPI\r | |
116 | UnitTestMtrrLibAsmCpuid (\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 | |
169 | UINT64\r | |
170 | EFIAPI\r | |
053e878b | 171 | UnitTestMtrrLibAsmReadMsr64 (\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 | |
227 | UINT64\r | |
228 | EFIAPI\r | |
053e878b MK |
229 | UnitTestMtrrLibAsmWriteMsr64 (\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 | |
279 | UNIT_TEST_STATUS\r | |
280 | EFIAPI\r | |
281 | InitializeMtrrRegs (\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 | |
332 | UNIT_TEST_STATUS\r | |
333 | EFIAPI\r | |
334 | InitializeSystem (\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 | |
352 | VOID\r | |
353 | CollectTestResult (\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 | |
396 | UINT32\r | |
397 | Random32 (\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 | |
412 | UINT64\r | |
413 | Random64 (\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 | |
429 | VOID\r | |
430 | GenerateRandomMtrrPair (\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 | |
487 | BOOLEAN\r | |
488 | RangesOverlap (\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 | |
521 | VOID\r | |
522 | GenerateValidAndConfigurableMtrrPairs (\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 | |
573 | MTRR_MEMORY_CACHE_TYPE\r | |
574 | GenerateRandomCacheType (\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 | |
595 | INT32\r | |
596 | CompareFuncUint64 (\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 | |
621 | VOID\r | |
622 | DetermineMemoryCacheType (\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 | |
654 | UINT32\r | |
655 | GetNextDifferentElementInSortedArray (\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 | |
677 | VOID\r | |
678 | RemoveDuplicatesInSortedArray (\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 | |
704 | BOOLEAN\r | |
705 | AddressInRange (\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 | |
720 | UINT64\r | |
721 | GetOverlapBitFlag (\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 | |
751 | UINT32\r | |
752 | CheckOverlapBitFlagsRelation (\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 | |
782 | BOOLEAN\r | |
783 | IsEndpointInRanges (\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 | |
808 | VOID\r | |
809 | CompactAndExtendEffectiveMtrrMemoryRanges (\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 | |
891 | VOID\r | |
892 | CollectEndpoints (\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 | |
924 | VOID\r | |
925 | GetEffectiveMemoryRanges (\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 |