]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/MemoryTest.c
IntelFrameworkModulePkg BdsDxe: Fix ASSERT in BdsMemoryTest
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / MemoryTest.c
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
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
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 PcdSetBool(PcdBootState, FALSE);
430 }
431
432 return ReturnStatus;
433 }