]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / MemoryTest / GenericMemoryTestDxe / LightMemoryTest.c
CommitLineData
7c636bd0 1/** @file\r
2\r
f469c702 3 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
7c636bd0 4\r
9d510e61 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7c636bd0 6\r
7**/\r
8\r
9#include "LightMemoryTest.h"\r
10\r
11//\r
12// Global:\r
13// Since this driver will only ever produce one instance of the memory test\r
14// protocol, so we do not need to dynamically allocate the PrivateData.\r
15//\r
16EFI_PHYSICAL_ADDRESS mCurrentAddress;\r
1436aea4 17LIST_ENTRY *mCurrentLink;\r
7c636bd0 18NONTESTED_MEMORY_RANGE *mCurrentRange;\r
19UINT64 mTestedSystemMemory;\r
20UINT64 mNonTestedSystemMemory;\r
21\r
1436aea4 22UINT32 GenericMemoryTestMonoPattern[GENERIC_CACHELINE_SIZE / 4] = {\r
7c636bd0 23 0x5a5a5a5a,\r
24 0xa5a5a5a5,\r
25 0x5a5a5a5a,\r
26 0xa5a5a5a5,\r
27 0x5a5a5a5a,\r
28 0xa5a5a5a5,\r
29 0x5a5a5a5a,\r
30 0xa5a5a5a5,\r
31 0x5a5a5a5a,\r
32 0xa5a5a5a5,\r
33 0x5a5a5a5a,\r
34 0xa5a5a5a5,\r
35 0x5a5a5a5a,\r
36 0xa5a5a5a5,\r
37 0x5a5a5a5a,\r
38 0xa5a5a5a5\r
39};\r
40\r
41/**\r
42 Compares the contents of two buffers.\r
43\r
44 This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.\r
45 If all Length bytes of the two buffers are identical, then 0 is returned. Otherwise, the\r
46 value returned is the first mismatched byte in SourceBuffer subtracted from the first\r
47 mismatched byte in DestinationBuffer.\r
d1102dba 48\r
7c636bd0 49 If Length = 0, then ASSERT().\r
50\r
51 @param[in] DestinationBuffer The pointer to the destination buffer to compare.\r
52 @param[in] SourceBuffer The pointer to the source buffer to compare.\r
53 @param[in] Length The number of bytes to compare.\r
54\r
55 @return 0 All Length bytes of the two buffers are identical.\r
56 @retval Non-zero The first mismatched byte in SourceBuffer subtracted from the first\r
57 mismatched byte in DestinationBuffer.\r
d1102dba 58\r
7c636bd0 59**/\r
60INTN\r
61EFIAPI\r
62CompareMemWithoutCheckArgument (\r
1436aea4
MK
63 IN CONST VOID *DestinationBuffer,\r
64 IN CONST VOID *SourceBuffer,\r
65 IN UINTN Length\r
7c636bd0 66 )\r
67{\r
68 ASSERT (Length > 0);\r
69 while ((--Length != 0) &&\r
1436aea4
MK
70 (*(INT8 *)DestinationBuffer == *(INT8 *)SourceBuffer))\r
71 {\r
72 DestinationBuffer = (INT8 *)DestinationBuffer + 1;\r
73 SourceBuffer = (INT8 *)SourceBuffer + 1;\r
7c636bd0 74 }\r
1436aea4
MK
75\r
76 return (INTN)*(UINT8 *)DestinationBuffer - (INTN)*(UINT8 *)SourceBuffer;\r
7c636bd0 77}\r
78\r
79/**\r
80 Construct the system base memory range through GCD service.\r
81\r
82 @param[in] Private Point to generic memory test driver's private data.\r
83\r
84 @retval EFI_SUCCESS Successful construct the base memory range through GCD service.\r
85 @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.\r
86 @retval Others Failed to construct base memory range through GCD service.\r
d1102dba 87\r
7c636bd0 88**/\r
89EFI_STATUS\r
90ConstructBaseMemoryRange (\r
91 IN GENERIC_MEMORY_TEST_PRIVATE *Private\r
92 )\r
93{\r
1436aea4
MK
94 UINTN NumberOfDescriptors;\r
95 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
96 UINTN Index;\r
7c636bd0 97\r
98 //\r
99 // Base memory will always below 4G\r
100 //\r
101 gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
102\r
103 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
2e5fb984 104 if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||\r
1436aea4
MK
105 (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable))\r
106 {\r
7c636bd0 107 Private->BaseMemorySize += MemorySpaceMap[Index].Length;\r
108 }\r
109 }\r
110\r
111 return EFI_SUCCESS;\r
112}\r
113\r
114/**\r
115 Destroy the link list base on the correspond link list type.\r
116\r
117 @param[in] Private Point to generic memory test driver's private data.\r
d1102dba 118\r
7c636bd0 119**/\r
120VOID\r
121DestroyLinkList (\r
122 IN GENERIC_MEMORY_TEST_PRIVATE *Private\r
123 )\r
124{\r
1436aea4 125 LIST_ENTRY *Link;\r
7c636bd0 126 NONTESTED_MEMORY_RANGE *NontestedRange;\r
127\r
128 Link = Private->NonTestedMemRanList.BackLink;\r
129\r
130 while (Link != &Private->NonTestedMemRanList) {\r
131 RemoveEntryList (Link);\r
132 NontestedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);\r
133 gBS->FreePool (NontestedRange);\r
1436aea4 134 Link = Private->NonTestedMemRanList.BackLink;\r
7c636bd0 135 }\r
136}\r
137\r
2e5fb984
RN
138/**\r
139 Convert the memory range to tested.\r
140\r
141 @param BaseAddress Base address of the memory range.\r
142 @param Length Length of the memory range.\r
143 @param Capabilities Capabilities of the memory range.\r
144\r
145 @retval EFI_SUCCESS The memory range is converted to tested.\r
146 @retval others Error happens.\r
147**/\r
148EFI_STATUS\r
149ConvertToTestedMemory (\r
1436aea4
MK
150 IN UINT64 BaseAddress,\r
151 IN UINT64 Length,\r
152 IN UINT64 Capabilities\r
2e5fb984
RN
153 )\r
154{\r
1436aea4
MK
155 EFI_STATUS Status;\r
156\r
2e5fb984
RN
157 Status = gDS->RemoveMemorySpace (\r
158 BaseAddress,\r
159 Length\r
160 );\r
161 if (!EFI_ERROR (Status)) {\r
162 Status = gDS->AddMemorySpace (\r
163 ((Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) ?\r
164 EfiGcdMemoryTypeMoreReliable : EfiGcdMemoryTypeSystemMemory,\r
165 BaseAddress,\r
166 Length,\r
167 Capabilities &~\r
168 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
169 );\r
170 }\r
1436aea4 171\r
2e5fb984
RN
172 return Status;\r
173}\r
174\r
7c636bd0 175/**\r
176 Add the extened memory to whole system memory map.\r
177\r
178 @param[in] Private Point to generic memory test driver's private data.\r
179\r
180 @retval EFI_SUCCESS Successful add all the extended memory to system memory map.\r
181 @retval Others Failed to add the tested extended memory.\r
d1102dba 182\r
7c636bd0 183**/\r
184EFI_STATUS\r
185UpdateMemoryMap (\r
186 IN GENERIC_MEMORY_TEST_PRIVATE *Private\r
187 )\r
188{\r
1436aea4 189 LIST_ENTRY *Link;\r
7c636bd0 190 NONTESTED_MEMORY_RANGE *Range;\r
191\r
192 Link = Private->NonTestedMemRanList.ForwardLink;\r
193\r
194 while (Link != &Private->NonTestedMemRanList) {\r
195 Range = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);\r
196\r
2e5fb984
RN
197 ConvertToTestedMemory (\r
198 Range->StartAddress,\r
199 Range->Length,\r
200 Range->Capabilities &~\r
201 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
202 );\r
7c636bd0 203 Link = Link->ForwardLink;\r
204 }\r
205\r
206 return EFI_SUCCESS;\r
207}\r
208\r
209/**\r
210 Test a range of the memory directly .\r
211\r
212 @param[in] Private Point to generic memory test driver's private data.\r
213 @param[in] StartAddress Starting address of the memory range to be tested.\r
214 @param[in] Length Length in bytes of the memory range to be tested.\r
215 @param[in] Capabilities The bit mask of attributes that the memory range supports.\r
216\r
217 @retval EFI_SUCCESS Successful test the range of memory.\r
218 @retval Others Failed to test the range of memory.\r
d1102dba 219\r
7c636bd0 220**/\r
221EFI_STATUS\r
222DirectRangeTest (\r
223 IN GENERIC_MEMORY_TEST_PRIVATE *Private,\r
224 IN EFI_PHYSICAL_ADDRESS StartAddress,\r
225 IN UINT64 Length,\r
226 IN UINT64 Capabilities\r
227 )\r
228{\r
229 EFI_STATUS Status;\r
230\r
231 //\r
232 // Perform a dummy memory test, so directly write the pattern to all range\r
233 //\r
234 WriteMemory (Private, StartAddress, Length);\r
235\r
236 //\r
237 // Verify the memory range\r
238 //\r
239 Status = VerifyMemory (Private, StartAddress, Length);\r
240 if (EFI_ERROR (Status)) {\r
241 return Status;\r
242 }\r
1436aea4 243\r
7c636bd0 244 //\r
245 // Add the tested compatible memory to system memory using GCD service\r
246 //\r
2e5fb984 247 ConvertToTestedMemory (\r
1436aea4
MK
248 StartAddress,\r
249 Length,\r
250 Capabilities &~\r
251 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
252 );\r
7c636bd0 253\r
254 return EFI_SUCCESS;\r
255}\r
256\r
257/**\r
258 Construct the system non-tested memory range through GCD service.\r
259\r
260 @param[in] Private Point to generic memory test driver's private data.\r
261\r
262 @retval EFI_SUCCESS Successful construct the non-tested memory range through GCD service.\r
263 @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.\r
264 @retval Others Failed to construct non-tested memory range through GCD service.\r
d1102dba 265\r
7c636bd0 266**/\r
267EFI_STATUS\r
268ConstructNonTestedMemoryRange (\r
269 IN GENERIC_MEMORY_TEST_PRIVATE *Private\r
270 )\r
271{\r
1436aea4
MK
272 NONTESTED_MEMORY_RANGE *Range;\r
273 BOOLEAN NoFound;\r
274 UINTN NumberOfDescriptors;\r
275 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
276 UINTN Index;\r
7c636bd0 277\r
278 //\r
279 // Non tested memory range may be span 4G here\r
280 //\r
281 NoFound = TRUE;\r
282\r
283 gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
284\r
285 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
1436aea4
MK
286 if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&\r
287 ((MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
288 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))\r
289 )\r
290 {\r
7c636bd0 291 NoFound = FALSE;\r
292 //\r
293 // Light version do not need to process >4G memory range\r
294 //\r
295 gBS->AllocatePool (\r
1436aea4
MK
296 EfiBootServicesData,\r
297 sizeof (NONTESTED_MEMORY_RANGE),\r
298 (VOID **)&Range\r
299 );\r
7c636bd0 300\r
301 Range->Signature = EFI_NONTESTED_MEMORY_RANGE_SIGNATURE;\r
302 Range->StartAddress = MemorySpaceMap[Index].BaseAddress;\r
303 Range->Length = MemorySpaceMap[Index].Length;\r
304 Range->Capabilities = MemorySpaceMap[Index].Capabilities;\r
305\r
306 mNonTestedSystemMemory += MemorySpaceMap[Index].Length;\r
307 InsertTailList (&Private->NonTestedMemRanList, &Range->Link);\r
308 }\r
309 }\r
310\r
311 if (NoFound) {\r
312 return EFI_NOT_FOUND;\r
313 }\r
314\r
315 return EFI_SUCCESS;\r
316}\r
317\r
318/**\r
319 Write the memory test pattern into a range of physical memory.\r
320\r
321 @param[in] Private Point to generic memory test driver's private data.\r
322 @param[in] Start The memory range's start address.\r
323 @param[in] Size The memory range's size.\r
324\r
325 @retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.\r
326 @retval Others The test pattern may not really write into the physical memory.\r
d1102dba 327\r
7c636bd0 328**/\r
329EFI_STATUS\r
330WriteMemory (\r
331 IN GENERIC_MEMORY_TEST_PRIVATE *Private,\r
332 IN EFI_PHYSICAL_ADDRESS Start,\r
333 IN UINT64 Size\r
334 )\r
335{\r
336 EFI_PHYSICAL_ADDRESS Address;\r
337\r
338 Address = Start;\r
339\r
340 //\r
341 // Add 4G memory address check for IA32 platform\r
342 // NOTE: Without page table, there is no way to use memory above 4G.\r
343 //\r
344 if (Start + Size > MAX_ADDRESS) {\r
345 return EFI_SUCCESS;\r
346 }\r
347\r
348 while (Address < (Start + Size)) {\r
1436aea4 349 CopyMem ((VOID *)(UINTN)Address, Private->MonoPattern, Private->MonoTestSize);\r
7c636bd0 350 Address += Private->CoverageSpan;\r
351 }\r
1436aea4 352\r
7c636bd0 353 //\r
354 // bug bug: we may need GCD service to make the code cache and data uncache,\r
355 // if GCD do not support it or return fail, then just flush the whole cache.\r
356 //\r
357 if (Private->Cpu != NULL) {\r
358 Private->Cpu->FlushDataCache (Private->Cpu, Start, Size, EfiCpuFlushTypeWriteBackInvalidate);\r
359 }\r
360\r
361 return EFI_SUCCESS;\r
362}\r
363\r
364/**\r
365 Verify the range of physical memory which covered by memory test pattern.\r
366\r
367 This function will also do not return any informatin just cause system reset,\r
368 because the handle error encount fatal error and disable the bad DIMMs.\r
369\r
370 @param[in] Private Point to generic memory test driver's private data.\r
371 @param[in] Start The memory range's start address.\r
372 @param[in] Size The memory range's size.\r
373\r
374 @retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.\r
375 @retval Others The range of memory have errors contained.\r
d1102dba 376\r
7c636bd0 377**/\r
378EFI_STATUS\r
379VerifyMemory (\r
380 IN GENERIC_MEMORY_TEST_PRIVATE *Private,\r
381 IN EFI_PHYSICAL_ADDRESS Start,\r
382 IN UINT64 Size\r
383 )\r
384{\r
385 EFI_PHYSICAL_ADDRESS Address;\r
386 INTN ErrorFound;\r
387 EFI_MEMORY_EXTENDED_ERROR_DATA *ExtendedErrorData;\r
388\r
389 Address = Start;\r
390 ExtendedErrorData = NULL;\r
391\r
392 //\r
393 // Add 4G memory address check for IA32 platform\r
394 // NOTE: Without page table, there is no way to use memory above 4G.\r
395 //\r
396 if (Start + Size > MAX_ADDRESS) {\r
397 return EFI_SUCCESS;\r
398 }\r
399\r
400 //\r
401 // Use the software memory test to check whether have detected miscompare\r
402 // error here. If there is miscompare error here then check if generic\r
403 // memory test driver can disable the bad DIMM.\r
404 //\r
405 while (Address < (Start + Size)) {\r
406 ErrorFound = CompareMemWithoutCheckArgument (\r
1436aea4
MK
407 (VOID *)(UINTN)(Address),\r
408 Private->MonoPattern,\r
409 Private->MonoTestSize\r
410 );\r
7c636bd0 411 if (ErrorFound != 0) {\r
412 //\r
413 // Report uncorrectable errors\r
414 //\r
415 ExtendedErrorData = AllocateZeroPool (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA));\r
416 if (ExtendedErrorData == NULL) {\r
417 return EFI_OUT_OF_RESOURCES;\r
418 }\r
419\r
1436aea4
MK
420 ExtendedErrorData->DataHeader.HeaderSize = (UINT16)sizeof (EFI_STATUS_CODE_DATA);\r
421 ExtendedErrorData->DataHeader.Size = (UINT16)(sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA));\r
422 ExtendedErrorData->Granularity = EFI_MEMORY_ERROR_DEVICE;\r
423 ExtendedErrorData->Operation = EFI_MEMORY_OPERATION_READ;\r
424 ExtendedErrorData->Syndrome = 0x0;\r
425 ExtendedErrorData->Address = Address;\r
426 ExtendedErrorData->Resolution = 0x40;\r
7c636bd0 427\r
428 REPORT_STATUS_CODE_EX (\r
1436aea4
MK
429 EFI_ERROR_CODE,\r
430 EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE,\r
431 0,\r
432 &gEfiGenericMemTestProtocolGuid,\r
433 NULL,\r
434 (UINT8 *)ExtendedErrorData + sizeof (EFI_STATUS_CODE_DATA),\r
435 ExtendedErrorData->DataHeader.Size\r
436 );\r
7c636bd0 437\r
438 return EFI_DEVICE_ERROR;\r
439 }\r
440\r
441 Address += Private->CoverageSpan;\r
442 }\r
443\r
444 return EFI_SUCCESS;\r
445}\r
446\r
447/**\r
448 Initialize the generic memory test.\r
449\r
d1102dba
LG
450 @param[in] This The protocol instance pointer.\r
451 @param[in] Level The coverage level of the memory test.\r
452 @param[out] RequireSoftECCInit Indicate if the memory need software ECC init.\r
7c636bd0 453\r
d1102dba
LG
454 @retval EFI_SUCCESS The generic memory test is initialized correctly.\r
455 @retval EFI_NO_MEDIA The system had no memory to be tested.\r
7c636bd0 456\r
457**/\r
458EFI_STATUS\r
459EFIAPI\r
460InitializeMemoryTest (\r
1436aea4
MK
461 IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,\r
462 IN EXTENDMEM_COVERAGE_LEVEL Level,\r
463 OUT BOOLEAN *RequireSoftECCInit\r
7c636bd0 464 )\r
465{\r
1436aea4
MK
466 EFI_STATUS Status;\r
467 GENERIC_MEMORY_TEST_PRIVATE *Private;\r
468 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
7c636bd0 469\r
470 Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);\r
471 *RequireSoftECCInit = FALSE;\r
472\r
473 //\r
474 // This is initialize for default value, but some value may be reset base on\r
475 // platform memory test driver.\r
476 //\r
477 Private->CoverLevel = Level;\r
478 Private->BdsBlockSize = TEST_BLOCK_SIZE;\r
479 Private->MonoPattern = GenericMemoryTestMonoPattern;\r
480 Private->MonoTestSize = GENERIC_CACHELINE_SIZE;\r
481\r
482 //\r
483 // Initialize several internal link list\r
484 //\r
485 InitializeListHead (&Private->NonTestedMemRanList);\r
486\r
487 //\r
488 // Construct base memory range\r
489 //\r
490 ConstructBaseMemoryRange (Private);\r
491\r
492 //\r
493 // get the cpu arch protocol to support flash cache\r
494 //\r
495 Status = gBS->LocateProtocol (\r
496 &gEfiCpuArchProtocolGuid,\r
497 NULL,\r
1436aea4 498 (VOID **)&Cpu\r
7c636bd0 499 );\r
500 if (!EFI_ERROR (Status)) {\r
501 Private->Cpu = Cpu;\r
502 }\r
1436aea4 503\r
7c636bd0 504 //\r
505 // Create the CoverageSpan of the memory test base on the coverage level\r
506 //\r
507 switch (Private->CoverLevel) {\r
1436aea4
MK
508 case EXTENSIVE:\r
509 Private->CoverageSpan = GENERIC_CACHELINE_SIZE;\r
510 break;\r
7c636bd0 511\r
1436aea4
MK
512 case SPARSE:\r
513 Private->CoverageSpan = SPARSE_SPAN_SIZE;\r
514 break;\r
7c636bd0 515\r
1436aea4
MK
516 //\r
517 // Even the BDS do not need to test any memory, but in some case it\r
518 // still need to init ECC memory.\r
519 //\r
520 default:\r
521 Private->CoverageSpan = QUICK_SPAN_SIZE;\r
522 break;\r
7c636bd0 523 }\r
1436aea4 524\r
7c636bd0 525 //\r
526 // This is the first time we construct the non-tested memory range, if no\r
527 // extended memory found, we know the system have not any extended memory\r
528 // need to be test\r
529 //\r
530 Status = ConstructNonTestedMemoryRange (Private);\r
531 if (Status == EFI_NOT_FOUND) {\r
532 return EFI_NO_MEDIA;\r
533 }\r
1436aea4 534\r
7c636bd0 535 //\r
536 // ready to perform the R/W/V memory test\r
537 //\r
538 mTestedSystemMemory = Private->BaseMemorySize;\r
539 mCurrentLink = Private->NonTestedMemRanList.ForwardLink;\r
540 mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);\r
541 mCurrentAddress = mCurrentRange->StartAddress;\r
542\r
543 return EFI_SUCCESS;\r
544}\r
545\r
546/**\r
547 Perform the memory test.\r
548\r
d1102dba
LG
549 @param[in] This The protocol instance pointer.\r
550 @param[out] TestedMemorySize Return the tested extended memory size.\r
551 @param[out] TotalMemorySize Return the whole system physical memory size.\r
552 The total memory size does not include memory in a slot with a disabled DIMM.\r
d181539b 553 @param[out] ErrorOut TRUE if the memory error occurred.\r
d1102dba 554 @param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.\r
7c636bd0 555\r
556 @retval EFI_SUCCESS One block of memory passed the test.\r
557 @retval EFI_NOT_FOUND All memory blocks have already been tested.\r
d181539b 558 @retval EFI_DEVICE_ERROR Memory device error occurred, and no agent can handle it.\r
7c636bd0 559\r
560**/\r
561EFI_STATUS\r
562EFIAPI\r
563GenPerformMemoryTest (\r
1436aea4
MK
564 IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,\r
565 OUT UINT64 *TestedMemorySize,\r
566 OUT UINT64 *TotalMemorySize,\r
567 OUT BOOLEAN *ErrorOut,\r
568 IN BOOLEAN TestAbort\r
7c636bd0 569 )\r
570{\r
571 EFI_STATUS Status;\r
572 GENERIC_MEMORY_TEST_PRIVATE *Private;\r
573 EFI_MEMORY_RANGE_EXTENDED_DATA *RangeData;\r
574 UINT64 BlockBoundary;\r
575\r
576 Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);\r
577 *ErrorOut = FALSE;\r
578 RangeData = NULL;\r
579 BlockBoundary = 0;\r
580\r
581 //\r
582 // In extensive mode the boundary of "mCurrentRange->Length" may will lost\r
0a18956d 583 // some range that is not Private->BdsBlockSize size boundary, so need\r
7c636bd0 584 // the software mechanism to confirm all memory location be covered.\r
585 //\r
586 if (mCurrentAddress < (mCurrentRange->StartAddress + mCurrentRange->Length)) {\r
587 if ((mCurrentAddress + Private->BdsBlockSize) <= (mCurrentRange->StartAddress + mCurrentRange->Length)) {\r
588 BlockBoundary = Private->BdsBlockSize;\r
589 } else {\r
590 BlockBoundary = mCurrentRange->StartAddress + mCurrentRange->Length - mCurrentAddress;\r
591 }\r
1436aea4 592\r
7c636bd0 593 //\r
594 // If TestAbort is true, means user cancel the memory test\r
595 //\r
1436aea4 596 if (!TestAbort && (Private->CoverLevel != IGNORE)) {\r
7c636bd0 597 //\r
598 // Report status code of every memory range\r
599 //\r
1436aea4 600 RangeData = AllocateZeroPool (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA));\r
7c636bd0 601 if (RangeData == NULL) {\r
602 return EFI_OUT_OF_RESOURCES;\r
603 }\r
1436aea4
MK
604\r
605 RangeData->DataHeader.HeaderSize = (UINT16)sizeof (EFI_STATUS_CODE_DATA);\r
606 RangeData->DataHeader.Size = (UINT16)(sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA));\r
607 RangeData->Start = mCurrentAddress;\r
608 RangeData->Length = BlockBoundary;\r
7c636bd0 609\r
610 REPORT_STATUS_CODE_EX (\r
1436aea4
MK
611 EFI_PROGRESS_CODE,\r
612 EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST,\r
613 0,\r
614 &gEfiGenericMemTestProtocolGuid,\r
615 NULL,\r
616 (UINT8 *)RangeData + sizeof (EFI_STATUS_CODE_DATA),\r
617 RangeData->DataHeader.Size\r
618 );\r
7c636bd0 619\r
620 //\r
621 // The software memory test (R/W/V) perform here. It will detect the\r
622 // memory mis-compare error.\r
623 //\r
624 WriteMemory (Private, mCurrentAddress, BlockBoundary);\r
625\r
626 Status = VerifyMemory (Private, mCurrentAddress, BlockBoundary);\r
627 if (EFI_ERROR (Status)) {\r
628 //\r
629 // If perform here, means there is mis-compare error, and no agent can\r
630 // handle it, so we return to BDS EFI_DEVICE_ERROR.\r
631 //\r
632 *ErrorOut = TRUE;\r
633 return EFI_DEVICE_ERROR;\r
634 }\r
635 }\r
636\r
637 mTestedSystemMemory += BlockBoundary;\r
1436aea4 638 *TestedMemorySize = mTestedSystemMemory;\r
7c636bd0 639\r
640 //\r
641 // If the memory test restart after the platform driver disable dimms,\r
642 // the NonTestSystemMemory may be changed, but the base memory size will\r
643 // not changed, so we can get the current total memory size.\r
644 //\r
645 *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;\r
646\r
647 //\r
648 // Update the current test address pointing to next BDS BLOCK\r
649 //\r
650 mCurrentAddress += Private->BdsBlockSize;\r
651\r
652 return EFI_SUCCESS;\r
653 }\r
1436aea4 654\r
7c636bd0 655 //\r
656 // Change to next non tested memory range\r
657 //\r
658 mCurrentLink = mCurrentLink->ForwardLink;\r
659 if (mCurrentLink != &Private->NonTestedMemRanList) {\r
660 mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);\r
661 mCurrentAddress = mCurrentRange->StartAddress;\r
662 return EFI_SUCCESS;\r
663 } else {\r
664 //\r
665 // Here means all the memory test have finished\r
666 //\r
667 *TestedMemorySize = mTestedSystemMemory;\r
668 *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;\r
669 return EFI_NOT_FOUND;\r
670 }\r
7c636bd0 671}\r
672\r
673/**\r
674 Finish the memory test.\r
675\r
d1102dba 676 @param[in] This The protocol instance pointer.\r
7c636bd0 677\r
678 @retval EFI_SUCCESS Success. All resources used in the memory test are freed.\r
679\r
680**/\r
681EFI_STATUS\r
682EFIAPI\r
683GenMemoryTestFinished (\r
1436aea4 684 IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This\r
7c636bd0 685 )\r
686{\r
1436aea4
MK
687 EFI_STATUS Status;\r
688 GENERIC_MEMORY_TEST_PRIVATE *Private;\r
7c636bd0 689\r
690 Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);\r
691\r
692 //\r
f469c702 693 // Perform Data and Address line test only if not ignore memory test\r
7c636bd0 694 //\r
f469c702
HL
695 if (Private->CoverLevel != IGNORE) {\r
696 Status = PerformAddressDataLineTest (Private);\r
697 ASSERT_EFI_ERROR (Status);\r
698 }\r
7c636bd0 699\r
700 //\r
701 // Add the non tested memory range to system memory map through GCD service\r
702 //\r
703 UpdateMemoryMap (Private);\r
704\r
705 //\r
706 // we need to free all the memory allocate\r
707 //\r
708 DestroyLinkList (Private);\r
709\r
710 return EFI_SUCCESS;\r
711}\r
712\r
713/**\r
714 Provides the capability to test the compatible range used by some special drivers.\r
715\r
d1102dba 716 @param[in] This The protocol instance pointer.\r
7c636bd0 717 @param[in] StartAddress The start address of the compatible memory range that\r
718 must be below 16M.\r
d1102dba
LG
719 @param[in] Length The compatible memory range's length.\r
720\r
721 @retval EFI_SUCCESS The compatible memory range pass the memory test.\r
7c636bd0 722 @retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.\r
723\r
724**/\r
725EFI_STATUS\r
726EFIAPI\r
727GenCompatibleRangeTest (\r
1436aea4
MK
728 IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,\r
729 IN EFI_PHYSICAL_ADDRESS StartAddress,\r
730 IN UINT64 Length\r
7c636bd0 731 )\r
732{\r
1436aea4
MK
733 EFI_STATUS Status;\r
734 GENERIC_MEMORY_TEST_PRIVATE *Private;\r
735 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
736 EFI_PHYSICAL_ADDRESS CurrentBase;\r
737 UINT64 CurrentLength;\r
7c636bd0 738\r
739 Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);\r
740\r
741 //\r
742 // Check if the parameter is below 16MB\r
743 //\r
744 if (StartAddress + Length > 0x1000000) {\r
745 return EFI_INVALID_PARAMETER;\r
746 }\r
1436aea4 747\r
7c636bd0 748 CurrentBase = StartAddress;\r
749 do {\r
750 //\r
751 // Check the required memory range status; if the required memory range span\r
752 // the different GCD memory descriptor, it may be cause different action.\r
753 //\r
754 Status = gDS->GetMemorySpaceDescriptor (\r
755 CurrentBase,\r
756 &Descriptor\r
757 );\r
758 if (EFI_ERROR (Status)) {\r
759 return Status;\r
760 }\r
761\r
1436aea4
MK
762 if ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeReserved) &&\r
763 ((Descriptor.Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
764 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))\r
765 )\r
766 {\r
7c636bd0 767 CurrentLength = Descriptor.BaseAddress + Descriptor.Length - CurrentBase;\r
768 if (CurrentBase + CurrentLength > StartAddress + Length) {\r
769 CurrentLength = StartAddress + Length - CurrentBase;\r
770 }\r
1436aea4 771\r
7c636bd0 772 Status = DirectRangeTest (\r
773 Private,\r
774 CurrentBase,\r
775 CurrentLength,\r
776 Descriptor.Capabilities\r
777 );\r
778 if (EFI_ERROR (Status)) {\r
779 return Status;\r
780 }\r
781 }\r
1436aea4 782\r
7c636bd0 783 CurrentBase = Descriptor.BaseAddress + Descriptor.Length;\r
784 } while (CurrentBase < StartAddress + Length);\r
1436aea4 785\r
7c636bd0 786 //\r
787 // Here means the required range already be tested, so just return success.\r
788 //\r
789 return EFI_SUCCESS;\r
790}\r
791\r
792/**\r
793 Perform the address line walking ones test.\r
794\r
795 @param[in] Private Point to generic memory test driver's private data.\r
d1102dba
LG
796\r
797 @retval EFI_SUCCESS Successful finished walking ones test.\r
798 @retval EFI_OUT_OF_RESOURCE Could not get resource in base memory.\r
7c636bd0 799 @retval EFI_ACCESS_DENIED Code may can not run here because if walking one test\r
800 failed, system may be already halt.\r
801\r
802**/\r
803EFI_STATUS\r
804PerformAddressDataLineTest (\r
1436aea4 805 IN GENERIC_MEMORY_TEST_PRIVATE *Private\r
7c636bd0 806 )\r
807{\r
808 LIST_ENTRY *ExtendedLink;\r
809 NONTESTED_MEMORY_RANGE *ExtendedRange;\r
810 BOOLEAN InExtendedRange;\r
811 EFI_PHYSICAL_ADDRESS TestAddress;\r
812\r
813 //\r
814 // Light version no data line test, only perform the address line test\r
815 //\r
1436aea4 816 TestAddress = (EFI_PHYSICAL_ADDRESS)0x1;\r
7c636bd0 817 while (TestAddress < MAX_ADDRESS && TestAddress > 0) {\r
818 //\r
819 // only test if the address falls in the enabled range\r
820 //\r
821 InExtendedRange = FALSE;\r
822 ExtendedLink = Private->NonTestedMemRanList.BackLink;\r
823 while (ExtendedLink != &Private->NonTestedMemRanList) {\r
824 ExtendedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (ExtendedLink);\r
825 if ((TestAddress >= ExtendedRange->StartAddress) &&\r
826 (TestAddress < (ExtendedRange->StartAddress + ExtendedRange->Length))\r
1436aea4
MK
827 )\r
828 {\r
7c636bd0 829 InExtendedRange = TRUE;\r
830 }\r
831\r
832 ExtendedLink = ExtendedLink->BackLink;\r
833 }\r
834\r
835 if (InExtendedRange) {\r
1436aea4 836 *(EFI_PHYSICAL_ADDRESS *)(UINTN)TestAddress = TestAddress;\r
7c636bd0 837 Private->Cpu->FlushDataCache (Private->Cpu, TestAddress, 1, EfiCpuFlushTypeWriteBackInvalidate);\r
1436aea4 838 if (*(EFI_PHYSICAL_ADDRESS *)(UINTN)TestAddress != TestAddress) {\r
7c636bd0 839 return EFI_ACCESS_DENIED;\r
840 }\r
841 }\r
842\r
843 TestAddress = LShiftU64 (TestAddress, 1);\r
844 }\r
845\r
846 return EFI_SUCCESS;\r
847}\r
1436aea4 848\r
7c636bd0 849//\r
850// Driver entry here\r
851//\r
1436aea4 852GENERIC_MEMORY_TEST_PRIVATE mGenericMemoryTestPrivate = {\r
7c636bd0 853 EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE,\r
854 NULL,\r
855 NULL,\r
856 {\r
857 InitializeMemoryTest,\r
858 GenPerformMemoryTest,\r
859 GenMemoryTestFinished,\r
860 GenCompatibleRangeTest\r
861 },\r
1436aea4 862 (EXTENDMEM_COVERAGE_LEVEL)0,\r
7c636bd0 863 0,\r
864 0,\r
865 NULL,\r
866 0,\r
867 0,\r
868 {\r
869 NULL,\r
870 NULL\r
871 }\r
872};\r
873\r
874/**\r
875 The generic memory test driver's entry point.\r
876\r
877 It initializes private data to default value.\r
878\r
d1102dba 879 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
7c636bd0 880 @param[in] SystemTable A pointer to the EFI System Table.\r
d1102dba 881\r
7c636bd0 882 @retval EFI_SUCCESS The entry point is executed successfully.\r
883 @retval EFI_NOT_FOUND Can't find HandOff Hob in HobList.\r
884 @retval other Some error occurs when executing this entry point.\r
885\r
886**/\r
887EFI_STATUS\r
888EFIAPI\r
889GenericMemoryTestEntryPoint (\r
1436aea4
MK
890 IN EFI_HANDLE ImageHandle,\r
891 IN EFI_SYSTEM_TABLE *SystemTable\r
7c636bd0 892 )\r
893{\r
894 EFI_STATUS Status;\r
895 VOID *HobList;\r
896 EFI_BOOT_MODE BootMode;\r
897 EFI_PEI_HOB_POINTERS Hob;\r
898\r
899 //\r
900 // Use the generic pattern to test compatible memory range\r
901 //\r
1436aea4
MK
902 mGenericMemoryTestPrivate.MonoPattern = GenericMemoryTestMonoPattern;\r
903 mGenericMemoryTestPrivate.MonoTestSize = GENERIC_CACHELINE_SIZE;\r
7c636bd0 904\r
905 //\r
906 // Get the platform boot mode\r
907 //\r
908 HobList = GetHobList ();\r
909\r
910 Hob.Raw = HobList;\r
911 if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) {\r
912 return EFI_NOT_FOUND;\r
913 }\r
914\r
915 BootMode = Hob.HandoffInformationTable->BootMode;\r
916\r
917 //\r
918 // Get the platform boot mode and create the default memory test coverage\r
919 // level and span size for compatible memory test using\r
920 //\r
921 switch (BootMode) {\r
1436aea4
MK
922 case BOOT_WITH_FULL_CONFIGURATION:\r
923 case BOOT_WITH_DEFAULT_SETTINGS:\r
924 mGenericMemoryTestPrivate.CoverageSpan = SPARSE_SPAN_SIZE;\r
925 break;\r
926\r
927 case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:\r
928 mGenericMemoryTestPrivate.CoverageSpan = GENERIC_CACHELINE_SIZE;\r
929 break;\r
930\r
931 default:\r
932 mGenericMemoryTestPrivate.CoverageSpan = QUICK_SPAN_SIZE;\r
933 break;\r
7c636bd0 934 }\r
1436aea4 935\r
7c636bd0 936 //\r
937 // Install the protocol\r
938 //\r
939 Status = gBS->InstallProtocolInterface (\r
940 &mGenericMemoryTestPrivate.Handle,\r
941 &gEfiGenericMemTestProtocolGuid,\r
942 EFI_NATIVE_INTERFACE,\r
943 &mGenericMemoryTestPrivate.GenericMemoryTest\r
944 );\r
945\r
946 return Status;\r
947}\r