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