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