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