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