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