• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Perform the platform memory test
3 
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Bds.h"
16 #include "String.h"
17 
18 //
19 // BDS Platform Functions
20 //
21 /**
22 
23   Show progress bar with title above it. It only works in Graphics mode.
24 
25 
26   @param TitleForeground Foreground color for Title.
27   @param TitleBackground Background color for Title.
28   @param Title           Title above progress bar.
29   @param ProgressColor   Progress bar color.
30   @param Progress        Progress (0-100)
31   @param PreviousValue   The previous value of the progress.
32 
33   @retval  EFI_STATUS       Success update the progress bar
34 
35 **/
36 EFI_STATUS
PlatformBdsShowProgress(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,IN CHAR16 * Title,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,IN UINTN Progress,IN UINTN PreviousValue)37 PlatformBdsShowProgress (
38   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
39   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
40   IN CHAR16                        *Title,
41   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
42   IN UINTN                         Progress,
43   IN UINTN                         PreviousValue
44   )
45 {
46   EFI_STATUS                     Status;
47   EFI_GRAPHICS_OUTPUT_PROTOCOL   *GraphicsOutput;
48   EFI_UGA_DRAW_PROTOCOL          *UgaDraw;
49   UINT32                         SizeOfX;
50   UINT32                         SizeOfY;
51   UINT32                         ColorDepth;
52   UINT32                         RefreshRate;
53   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;
54   UINTN                          BlockHeight;
55   UINTN                          BlockWidth;
56   UINTN                          BlockNum;
57   UINTN                          PosX;
58   UINTN                          PosY;
59   UINTN                          Index;
60 
61   if (Progress > 100) {
62     return EFI_INVALID_PARAMETER;
63   }
64 
65   UgaDraw = NULL;
66   Status = gBS->HandleProtocol (
67                   gST->ConsoleOutHandle,
68                   &gEfiGraphicsOutputProtocolGuid,
69                   (VOID **) &GraphicsOutput
70                   );
71   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
72     GraphicsOutput = NULL;
73 
74     Status = gBS->HandleProtocol (
75                     gST->ConsoleOutHandle,
76                     &gEfiUgaDrawProtocolGuid,
77                     (VOID **) &UgaDraw
78                     );
79   }
80   if (EFI_ERROR (Status)) {
81     return EFI_UNSUPPORTED;
82   }
83 
84   SizeOfX = 0;
85   SizeOfY = 0;
86   if (GraphicsOutput != NULL) {
87     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
88     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
89   } else if (UgaDraw != NULL) {
90     Status = UgaDraw->GetMode (
91                         UgaDraw,
92                         &SizeOfX,
93                         &SizeOfY,
94                         &ColorDepth,
95                         &RefreshRate
96                         );
97     if (EFI_ERROR (Status)) {
98       return EFI_UNSUPPORTED;
99     }
100   } else {
101     return EFI_UNSUPPORTED;
102   }
103 
104   BlockWidth  = SizeOfX / 100;
105   BlockHeight = SizeOfY / 50;
106 
107   BlockNum    = Progress;
108 
109   PosX        = 0;
110   PosY        = SizeOfY * 48 / 50;
111 
112   if (BlockNum == 0) {
113     //
114     // Clear progress area
115     //
116     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
117 
118     if (GraphicsOutput != NULL) {
119       Status = GraphicsOutput->Blt (
120                           GraphicsOutput,
121                           &Color,
122                           EfiBltVideoFill,
123                           0,
124                           0,
125                           0,
126                           PosY - EFI_GLYPH_HEIGHT - 1,
127                           SizeOfX,
128                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
129                           SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
130                           );
131     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
132       Status = UgaDraw->Blt (
133                           UgaDraw,
134                           (EFI_UGA_PIXEL *) &Color,
135                           EfiUgaVideoFill,
136                           0,
137                           0,
138                           0,
139                           PosY - EFI_GLYPH_HEIGHT - 1,
140                           SizeOfX,
141                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
142                           SizeOfX * sizeof (EFI_UGA_PIXEL)
143                           );
144     } else {
145       return EFI_UNSUPPORTED;
146     }
147   }
148   //
149   // Show progress by drawing blocks
150   //
151   for (Index = PreviousValue; Index < BlockNum; Index++) {
152     PosX = Index * BlockWidth;
153     if (GraphicsOutput != NULL) {
154       Status = GraphicsOutput->Blt (
155                           GraphicsOutput,
156                           &ProgressColor,
157                           EfiBltVideoFill,
158                           0,
159                           0,
160                           PosX,
161                           PosY,
162                           BlockWidth - 1,
163                           BlockHeight,
164                           (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
165                           );
166     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
167       Status = UgaDraw->Blt (
168                           UgaDraw,
169                           (EFI_UGA_PIXEL *) &ProgressColor,
170                           EfiUgaVideoFill,
171                           0,
172                           0,
173                           PosX,
174                           PosY,
175                           BlockWidth - 1,
176                           BlockHeight,
177                           (BlockWidth) * sizeof (EFI_UGA_PIXEL)
178                           );
179     } else {
180       return EFI_UNSUPPORTED;
181     }
182   }
183 
184   PrintXY (
185     (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
186     PosY - EFI_GLYPH_HEIGHT - 1,
187     &TitleForeground,
188     &TitleBackground,
189     Title
190     );
191 
192   return EFI_SUCCESS;
193 }
194 
195 /**
196   Perform the memory test base on the memory test intensive level,
197   and update the memory resource.
198 
199   @param  Level         The memory test intensive level.
200 
201   @retval EFI_STATUS    Success test all the system memory and update
202                         the memory resource
203 
204 **/
205 EFI_STATUS
206 EFIAPI
BdsMemoryTest(IN EXTENDMEM_COVERAGE_LEVEL Level)207 BdsMemoryTest (
208   IN EXTENDMEM_COVERAGE_LEVEL Level
209   )
210 {
211   EFI_STATUS                        Status;
212   EFI_STATUS                        KeyStatus;
213   EFI_STATUS                        InitStatus;
214   EFI_STATUS                        ReturnStatus;
215   BOOLEAN                           RequireSoftECCInit;
216   EFI_GENERIC_MEMORY_TEST_PROTOCOL  *GenMemoryTest;
217   UINT64                            TestedMemorySize;
218   UINT64                            TotalMemorySize;
219   UINTN                             TestPercent;
220   UINT64                            PreviousValue;
221   BOOLEAN                           ErrorOut;
222   BOOLEAN                           TestAbort;
223   EFI_INPUT_KEY                     Key;
224   CHAR16                            StrPercent[80];
225   CHAR16                            *StrTotalMemory;
226   CHAR16                            *Pos;
227   CHAR16                            *TmpStr;
228   EFI_GRAPHICS_OUTPUT_BLT_PIXEL     Foreground;
229   EFI_GRAPHICS_OUTPUT_BLT_PIXEL     Background;
230   EFI_GRAPHICS_OUTPUT_BLT_PIXEL     Color;
231   BOOLEAN                           IsFirstBoot;
232   UINT32                            TempData;
233   UINTN                             StrTotalMemorySize;
234 
235   ReturnStatus = EFI_SUCCESS;
236   ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
237 
238   StrTotalMemorySize = 128;
239   Pos = AllocateZeroPool (StrTotalMemorySize);
240 
241   if (Pos == NULL) {
242     return ReturnStatus;
243   }
244 
245   StrTotalMemory    = Pos;
246 
247   TestedMemorySize  = 0;
248   TotalMemorySize   = 0;
249   PreviousValue     = 0;
250   ErrorOut          = FALSE;
251   TestAbort         = FALSE;
252 
253   SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
254   SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
255   SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
256 
257   RequireSoftECCInit = FALSE;
258 
259   Status = gBS->LocateProtocol (
260                   &gEfiGenericMemTestProtocolGuid,
261                   NULL,
262                   (VOID **) &GenMemoryTest
263                   );
264   if (EFI_ERROR (Status)) {
265     FreePool (Pos);
266     return EFI_SUCCESS;
267   }
268 
269   InitStatus = GenMemoryTest->MemoryTestInit (
270                                 GenMemoryTest,
271                                 Level,
272                                 &RequireSoftECCInit
273                                 );
274   if (InitStatus == EFI_NO_MEDIA) {
275     //
276     // The PEI codes also have the relevant memory test code to check the memory,
277     // it can select to test some range of the memory or all of them. If PEI code
278     // checks all the memory, this BDS memory test will has no not-test memory to
279     // do the test, and then the status of EFI_NO_MEDIA will be returned by
280     // "MemoryTestInit". So it does not need to test memory again, just return.
281     //
282     FreePool (Pos);
283     return EFI_SUCCESS;
284   }
285 
286   if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
287     TmpStr = GetStringById (STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST));
288 
289     if (TmpStr != NULL) {
290       PrintXY (10, 10, NULL, NULL, TmpStr);
291       FreePool (TmpStr);
292     }
293   } else {
294     DEBUG ((EFI_D_INFO, "Enter memory test.\n"));
295   }
296   do {
297     Status = GenMemoryTest->PerformMemoryTest (
298                               GenMemoryTest,
299                               &TestedMemorySize,
300                               &TotalMemorySize,
301                               &ErrorOut,
302                               TestAbort
303                               );
304     if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
305       TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR));
306       if (TmpStr != NULL) {
307         PrintXY (10, 10, NULL, NULL, TmpStr);
308         FreePool (TmpStr);
309       }
310 
311       ASSERT (0);
312     }
313 
314     if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
315       TempData = (UINT32) DivU64x32 (TotalMemorySize, 16);
316       TestPercent = (UINTN) DivU64x32 (
317                               DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16),
318                               TempData
319                               );
320       if (TestPercent != PreviousValue) {
321         UnicodeValueToString (StrPercent, 0, TestPercent, 0);
322         TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
323         if (TmpStr != NULL) {
324           //
325           // TmpStr size is 64, StrPercent is reserved to 16.
326           //
327           StrnCatS (
328             StrPercent,
329             sizeof (StrPercent) / sizeof (CHAR16),
330             TmpStr,
331             sizeof (StrPercent) / sizeof (CHAR16) - StrLen (StrPercent) - 1
332             );
333           PrintXY (10, 10, NULL, NULL, StrPercent);
334           FreePool (TmpStr);
335         }
336 
337         TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
338         if (TmpStr != NULL) {
339           PlatformBdsShowProgress (
340             Foreground,
341             Background,
342             TmpStr,
343             Color,
344             TestPercent,
345             (UINTN) PreviousValue
346             );
347           FreePool (TmpStr);
348         }
349       }
350 
351       PreviousValue = TestPercent;
352     } else {
353       DEBUG ((EFI_D_INFO, "Perform memory test (ESC to skip).\n"));
354     }
355 
356     if (!PcdGetBool (PcdConInConnectOnDemand)) {
357       KeyStatus     = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
358       if (!EFI_ERROR (KeyStatus) && (Key.ScanCode == SCAN_ESC)) {
359         if (!RequireSoftECCInit) {
360           if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
361             TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
362             if (TmpStr != NULL) {
363               PlatformBdsShowProgress (
364                 Foreground,
365                 Background,
366                 TmpStr,
367                 Color,
368                 100,
369                 (UINTN) PreviousValue
370                 );
371               FreePool (TmpStr);
372             }
373 
374             PrintXY (10, 10, NULL, NULL, L"100");
375           }
376           Status = GenMemoryTest->Finished (GenMemoryTest);
377           goto Done;
378         }
379 
380         TestAbort = TRUE;
381       }
382     }
383   } while (Status != EFI_NOT_FOUND);
384 
385   Status = GenMemoryTest->Finished (GenMemoryTest);
386 
387 Done:
388   if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
389     UnicodeValueToString (StrTotalMemory, COMMA_TYPE, TotalMemorySize, 0);
390     if (StrTotalMemory[0] == L',') {
391       StrTotalMemory++;
392       StrTotalMemorySize -= sizeof (CHAR16);
393     }
394 
395     TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED));
396     if (TmpStr != NULL) {
397       StrnCatS (
398         StrTotalMemory,
399         StrTotalMemorySize / sizeof (CHAR16),
400         TmpStr,
401         StrTotalMemorySize / sizeof (CHAR16) - StrLen (StrTotalMemory) - 1
402         );
403       FreePool (TmpStr);
404     }
405 
406     PrintXY (10, 10, NULL, NULL, StrTotalMemory);
407     PlatformBdsShowProgress (
408       Foreground,
409       Background,
410       StrTotalMemory,
411       Color,
412       100,
413       (UINTN) PreviousValue
414       );
415 
416   } else {
417     DEBUG ((EFI_D_INFO, "%d bytes of system memory tested OK\r\n", TotalMemorySize));
418   }
419 
420   FreePool (Pos);
421 
422 
423   //
424   // Use a DynamicHii type pcd to save the boot status, which is used to
425   // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
426   //
427   IsFirstBoot = PcdGetBool(PcdBootState);
428   if (IsFirstBoot) {
429     Status = PcdSetBoolS(PcdBootState, FALSE);
430     if (EFI_ERROR (Status)) {
431       DEBUG ((EFI_D_ERROR, "Set PcdBootState to FALSE failed.\n"));
432     }
433   }
434 
435   return ReturnStatus;
436 }
437