]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c
Nt32Pkg: Keep boot behavior using new BDS almost same as that using old BDS
[mirror_edk2.git] / Nt32Pkg / Library / PlatformBootManagerLib / 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 "PlatformBootManager.h"
16
17 EFI_HII_HANDLE gStringPackHandle = NULL;
18 EFI_GUID mPlatformBootManagerStringPackGuid = {
19 0x154dd51, 0x9079, 0x4a10, { 0x89, 0x5c, 0x9c, 0x7, 0x72, 0x81, 0x57, 0x88 }
20 };
21 // extern UINT8 BdsDxeStrings[];
22
23 //
24 // BDS Platform Functions
25 //
26 /**
27
28 Show progress bar with title above it. It only works in Graphics mode.
29
30
31 @param TitleForeground Foreground color for Title.
32 @param TitleBackground Background color for Title.
33 @param Title Title above progress bar.
34 @param ProgressColor Progress bar color.
35 @param Progress Progress (0-100)
36 @param PreviousValue The previous value of the progress.
37
38 @retval EFI_STATUS Success update the progress bar
39
40 **/
41 EFI_STATUS
42 PlatformBootManagerShowProgress (
43 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
44 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
45 IN CHAR16 *Title,
46 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
47 IN UINTN Progress,
48 IN UINTN PreviousValue
49 )
50 {
51 EFI_STATUS Status;
52 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
53 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
54 UINT32 SizeOfX;
55 UINT32 SizeOfY;
56 UINT32 ColorDepth;
57 UINT32 RefreshRate;
58 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
59 UINTN BlockHeight;
60 UINTN BlockWidth;
61 UINTN BlockNum;
62 UINTN PosX;
63 UINTN PosY;
64 UINTN Index;
65
66 if (Progress > 100) {
67 return EFI_INVALID_PARAMETER;
68 }
69
70 UgaDraw = NULL;
71 Status = gBS->HandleProtocol (
72 gST->ConsoleOutHandle,
73 &gEfiGraphicsOutputProtocolGuid,
74 (VOID **) &GraphicsOutput
75 );
76 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
77 GraphicsOutput = NULL;
78
79 Status = gBS->HandleProtocol (
80 gST->ConsoleOutHandle,
81 &gEfiUgaDrawProtocolGuid,
82 (VOID **) &UgaDraw
83 );
84 }
85 if (EFI_ERROR (Status)) {
86 return EFI_UNSUPPORTED;
87 }
88
89 SizeOfX = 0;
90 SizeOfY = 0;
91 if (GraphicsOutput != NULL) {
92 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
93 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
94 } else if (UgaDraw != NULL) {
95 Status = UgaDraw->GetMode (
96 UgaDraw,
97 &SizeOfX,
98 &SizeOfY,
99 &ColorDepth,
100 &RefreshRate
101 );
102 if (EFI_ERROR (Status)) {
103 return EFI_UNSUPPORTED;
104 }
105 } else {
106 return EFI_UNSUPPORTED;
107 }
108
109 BlockWidth = SizeOfX / 100;
110 BlockHeight = SizeOfY / 50;
111
112 BlockNum = Progress;
113
114 PosX = 0;
115 PosY = SizeOfY * 48 / 50;
116
117 if (BlockNum == 0) {
118 //
119 // Clear progress area
120 //
121 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
122
123 if (GraphicsOutput != NULL) {
124 Status = GraphicsOutput->Blt (
125 GraphicsOutput,
126 &Color,
127 EfiBltVideoFill,
128 0,
129 0,
130 0,
131 PosY - EFI_GLYPH_HEIGHT - 1,
132 SizeOfX,
133 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
134 SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
135 );
136 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
137 Status = UgaDraw->Blt (
138 UgaDraw,
139 (EFI_UGA_PIXEL *) &Color,
140 EfiUgaVideoFill,
141 0,
142 0,
143 0,
144 PosY - EFI_GLYPH_HEIGHT - 1,
145 SizeOfX,
146 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
147 SizeOfX * sizeof (EFI_UGA_PIXEL)
148 );
149 } else {
150 return EFI_UNSUPPORTED;
151 }
152 }
153 //
154 // Show progress by drawing blocks
155 //
156 for (Index = PreviousValue; Index < BlockNum; Index++) {
157 PosX = Index * BlockWidth;
158 if (GraphicsOutput != NULL) {
159 Status = GraphicsOutput->Blt (
160 GraphicsOutput,
161 &ProgressColor,
162 EfiBltVideoFill,
163 0,
164 0,
165 PosX,
166 PosY,
167 BlockWidth - 1,
168 BlockHeight,
169 (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
170 );
171 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
172 Status = UgaDraw->Blt (
173 UgaDraw,
174 (EFI_UGA_PIXEL *) &ProgressColor,
175 EfiUgaVideoFill,
176 0,
177 0,
178 PosX,
179 PosY,
180 BlockWidth - 1,
181 BlockHeight,
182 (BlockWidth) * sizeof (EFI_UGA_PIXEL)
183 );
184 } else {
185 return EFI_UNSUPPORTED;
186 }
187 }
188
189 PrintXY (
190 (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
191 PosY - EFI_GLYPH_HEIGHT - 1,
192 &TitleForeground,
193 &TitleBackground,
194 Title
195 );
196
197 return EFI_SUCCESS;
198 }
199
200 /**
201 Perform the memory test base on the memory test intensive level,
202 and update the memory resource.
203
204 @param Level The memory test intensive level.
205
206 @retval EFI_STATUS Success test all the system memory and update
207 the memory resource
208
209 **/
210 EFI_STATUS
211 PlatformBootManagerMemoryTest (
212 IN EXTENDMEM_COVERAGE_LEVEL Level
213 )
214 {
215 EFI_STATUS Status;
216 EFI_STATUS KeyStatus;
217 EFI_STATUS InitStatus;
218 EFI_STATUS ReturnStatus;
219 BOOLEAN RequireSoftECCInit;
220 EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
221 UINT64 TestedMemorySize;
222 UINT64 TotalMemorySize;
223 UINTN TestPercent;
224 UINT64 PreviousValue;
225 BOOLEAN ErrorOut;
226 BOOLEAN TestAbort;
227 EFI_INPUT_KEY Key;
228 CHAR16 StrPercent[80];
229 CHAR16 *StrTotalMemory;
230 CHAR16 *Pos;
231 CHAR16 *TmpStr;
232 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
233 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
234 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
235 UINT32 TempData;
236 UINTN StrTotalMemorySize;
237
238 ReturnStatus = EFI_SUCCESS;
239 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
240
241 StrTotalMemorySize = 128;
242 Pos = AllocateZeroPool (StrTotalMemorySize);
243 ASSERT (Pos != NULL);
244
245 if (gStringPackHandle == NULL) {
246 gStringPackHandle = HiiAddPackages (
247 &mPlatformBootManagerStringPackGuid,
248 gImageHandle,
249 PlatformBootManagerLibStrings,
250 NULL
251 );
252 ASSERT (gStringPackHandle != NULL);
253 }
254
255 StrTotalMemory = Pos;
256
257 TestedMemorySize = 0;
258 TotalMemorySize = 0;
259 PreviousValue = 0;
260 ErrorOut = FALSE;
261 TestAbort = FALSE;
262
263 SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
264 SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
265 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
266
267 RequireSoftECCInit = FALSE;
268
269 Status = gBS->LocateProtocol (
270 &gEfiGenericMemTestProtocolGuid,
271 NULL,
272 (VOID **) &GenMemoryTest
273 );
274 if (EFI_ERROR (Status)) {
275 FreePool (Pos);
276 return EFI_SUCCESS;
277 }
278
279 InitStatus = GenMemoryTest->MemoryTestInit (
280 GenMemoryTest,
281 Level,
282 &RequireSoftECCInit
283 );
284 if (InitStatus == EFI_NO_MEDIA) {
285 //
286 // The PEI codes also have the relevant memory test code to check the memory,
287 // it can select to test some range of the memory or all of them. If PEI code
288 // checks all the memory, this BDS memory test will has no not-test memory to
289 // do the test, and then the status of EFI_NO_MEDIA will be returned by
290 // "MemoryTestInit". So it does not need to test memory again, just return.
291 //
292 FreePool (Pos);
293 return EFI_SUCCESS;
294 }
295
296 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
297 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST), NULL);
298
299 if (TmpStr != NULL) {
300 PrintXY (10, 10, NULL, NULL, TmpStr);
301 FreePool (TmpStr);
302 }
303 } else {
304 DEBUG ((EFI_D_INFO, "Enter memory test.\n"));
305 }
306 do {
307 Status = GenMemoryTest->PerformMemoryTest (
308 GenMemoryTest,
309 &TestedMemorySize,
310 &TotalMemorySize,
311 &ErrorOut,
312 TestAbort
313 );
314 if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
315 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_SYSTEM_MEM_ERROR), NULL);
316 if (TmpStr != NULL) {
317 PrintXY (10, 10, NULL, NULL, TmpStr);
318 FreePool (TmpStr);
319 }
320
321 ASSERT (0);
322 }
323
324 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
325 TempData = (UINT32) DivU64x32 (TotalMemorySize, 16);
326 TestPercent = (UINTN) DivU64x32 (
327 DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16),
328 TempData
329 );
330 if (TestPercent != PreviousValue) {
331 UnicodeValueToString (StrPercent, 0, TestPercent, 0);
332 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MEMORY_TEST_PERCENT), NULL);
333 if (TmpStr != NULL) {
334 //
335 // TmpStr size is 64, StrPercent is reserved to 16.
336 //
337 StrnCatS (
338 StrPercent,
339 sizeof (StrPercent) / sizeof (CHAR16),
340 TmpStr,
341 sizeof (StrPercent) / sizeof (CHAR16) - StrLen (StrPercent) - 1
342 );
343 PrintXY (10, 10, NULL, NULL, StrPercent);
344 FreePool (TmpStr);
345 }
346
347 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL);
348 if (TmpStr != NULL) {
349 PlatformBootManagerShowProgress (
350 Foreground,
351 Background,
352 TmpStr,
353 Color,
354 TestPercent,
355 (UINTN) PreviousValue
356 );
357 FreePool (TmpStr);
358 }
359 }
360
361 PreviousValue = TestPercent;
362 } else {
363 DEBUG ((EFI_D_INFO, "Perform memory test (ESC to skip).\n"));
364 }
365
366 if (!PcdGetBool (PcdConInConnectOnDemand)) {
367 KeyStatus = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
368 if (!EFI_ERROR (KeyStatus) && (Key.ScanCode == SCAN_ESC)) {
369 if (!RequireSoftECCInit) {
370 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
371 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL);
372 if (TmpStr != NULL) {
373 PlatformBootManagerShowProgress (
374 Foreground,
375 Background,
376 TmpStr,
377 Color,
378 100,
379 (UINTN) PreviousValue
380 );
381 FreePool (TmpStr);
382 }
383
384 PrintXY (10, 10, NULL, NULL, L"100");
385 }
386 Status = GenMemoryTest->Finished (GenMemoryTest);
387 goto Done;
388 }
389
390 TestAbort = TRUE;
391 }
392 }
393 } while (Status != EFI_NOT_FOUND);
394
395 Status = GenMemoryTest->Finished (GenMemoryTest);
396
397 Done:
398 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
399 UnicodeValueToString (StrTotalMemory, COMMA_TYPE, TotalMemorySize, 0);
400 if (StrTotalMemory[0] == L',') {
401 StrTotalMemory++;
402 StrTotalMemorySize -= sizeof (CHAR16);
403 }
404
405 TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MEM_TEST_COMPLETED), NULL);
406 if (TmpStr != NULL) {
407 StrnCatS (
408 StrTotalMemory,
409 StrTotalMemorySize / sizeof (CHAR16),
410 TmpStr,
411 StrTotalMemorySize / sizeof (CHAR16) - StrLen (StrTotalMemory) - 1
412 );
413 FreePool (TmpStr);
414 }
415
416 PrintXY (10, 10, NULL, NULL, StrTotalMemory);
417 PlatformBootManagerShowProgress (
418 Foreground,
419 Background,
420 StrTotalMemory,
421 Color,
422 100,
423 (UINTN) PreviousValue
424 );
425
426 } else {
427 DEBUG ((EFI_D_INFO, "%d bytes of system memory tested OK\r\n", TotalMemorySize));
428 }
429
430 FreePool (Pos);
431 return ReturnStatus;
432 }
433
434 /**
435 Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
436 is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
437 buffer is passed in it will be used if it is big enough.
438
439 @param BmpImage Pointer to BMP file
440 @param BmpImageSize Number of bytes in BmpImage
441 @param GopBlt Buffer containing GOP version of BmpImage.
442 @param GopBltSize Size of GopBlt in bytes.
443 @param PixelHeight Height of GopBlt/BmpImage in pixels
444 @param PixelWidth Width of GopBlt/BmpImage in pixels
445
446 @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
447 @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
448 @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
449 GopBltSize will contain the required size.
450 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
451
452 **/
453 EFI_STATUS
454 PlatformBootManagerConvertBmpToGopBlt (
455 IN VOID *BmpImage,
456 IN UINTN BmpImageSize,
457 IN OUT VOID **GopBlt,
458 IN OUT UINTN *GopBltSize,
459 OUT UINTN *PixelHeight,
460 OUT UINTN *PixelWidth
461 )
462 {
463 UINT8 *Image;
464 UINT8 *ImageHeader;
465 BMP_IMAGE_HEADER *BmpHeader;
466 BMP_COLOR_MAP *BmpColorMap;
467 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
468 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
469 UINT64 BltBufferSize;
470 UINTN Index;
471 UINTN Height;
472 UINTN Width;
473 UINTN ImageIndex;
474 UINT32 DataSizePerLine;
475 BOOLEAN IsAllocated;
476 UINT32 ColorMapNum;
477
478 if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
479 return EFI_INVALID_PARAMETER;
480 }
481
482 BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
483
484 if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
485 return EFI_UNSUPPORTED;
486 }
487
488 //
489 // Doesn't support compress.
490 //
491 if (BmpHeader->CompressionType != 0) {
492 return EFI_UNSUPPORTED;
493 }
494
495 //
496 // Only support BITMAPINFOHEADER format.
497 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
498 //
499 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
500 return EFI_UNSUPPORTED;
501 }
502
503 //
504 // The data size in each line must be 4 byte alignment.
505 //
506 DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
507 BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
508 if (BltBufferSize > (UINT32) ~0) {
509 return EFI_INVALID_PARAMETER;
510 }
511
512 if ((BmpHeader->Size != BmpImageSize) ||
513 (BmpHeader->Size < BmpHeader->ImageOffset) ||
514 (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {
515 return EFI_INVALID_PARAMETER;
516 }
517
518 //
519 // Calculate Color Map offset in the image.
520 //
521 Image = BmpImage;
522 BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
523 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
524 return EFI_INVALID_PARAMETER;
525 }
526
527 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
528 switch (BmpHeader->BitPerPixel) {
529 case 1:
530 ColorMapNum = 2;
531 break;
532 case 4:
533 ColorMapNum = 16;
534 break;
535 case 8:
536 ColorMapNum = 256;
537 break;
538 default:
539 ColorMapNum = 0;
540 break;
541 }
542 //
543 // BMP file may has padding data between the bmp header section and the bmp data section.
544 //
545 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
546 return EFI_INVALID_PARAMETER;
547 }
548 }
549
550 //
551 // Calculate graphics image data address in the image
552 //
553 Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
554 ImageHeader = Image;
555
556 //
557 // Calculate the BltBuffer needed size.
558 //
559 BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
560 //
561 // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
562 //
563 if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
564 return EFI_UNSUPPORTED;
565 }
566 BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
567
568 IsAllocated = FALSE;
569 if (*GopBlt == NULL) {
570 //
571 // GopBlt is not allocated by caller.
572 //
573 *GopBltSize = (UINTN) BltBufferSize;
574 *GopBlt = AllocatePool (*GopBltSize);
575 IsAllocated = TRUE;
576 if (*GopBlt == NULL) {
577 return EFI_OUT_OF_RESOURCES;
578 }
579 } else {
580 //
581 // GopBlt has been allocated by caller.
582 //
583 if (*GopBltSize < (UINTN) BltBufferSize) {
584 *GopBltSize = (UINTN) BltBufferSize;
585 return EFI_BUFFER_TOO_SMALL;
586 }
587 }
588
589 *PixelWidth = BmpHeader->PixelWidth;
590 *PixelHeight = BmpHeader->PixelHeight;
591
592 //
593 // Convert image from BMP to Blt buffer format
594 //
595 BltBuffer = *GopBlt;
596 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
597 Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
598 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
599 switch (BmpHeader->BitPerPixel) {
600 case 1:
601 //
602 // Convert 1-bit (2 colors) BMP to 24-bit color
603 //
604 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
605 Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
606 Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
607 Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
608 Blt++;
609 Width++;
610 }
611
612 Blt--;
613 Width--;
614 break;
615
616 case 4:
617 //
618 // Convert 4-bit (16 colors) BMP Palette to 24-bit color
619 //
620 Index = (*Image) >> 4;
621 Blt->Red = BmpColorMap[Index].Red;
622 Blt->Green = BmpColorMap[Index].Green;
623 Blt->Blue = BmpColorMap[Index].Blue;
624 if (Width < (BmpHeader->PixelWidth - 1)) {
625 Blt++;
626 Width++;
627 Index = (*Image) & 0x0f;
628 Blt->Red = BmpColorMap[Index].Red;
629 Blt->Green = BmpColorMap[Index].Green;
630 Blt->Blue = BmpColorMap[Index].Blue;
631 }
632 break;
633
634 case 8:
635 //
636 // Convert 8-bit (256 colors) BMP Palette to 24-bit color
637 //
638 Blt->Red = BmpColorMap[*Image].Red;
639 Blt->Green = BmpColorMap[*Image].Green;
640 Blt->Blue = BmpColorMap[*Image].Blue;
641 break;
642
643 case 24:
644 //
645 // It is 24-bit BMP.
646 //
647 Blt->Blue = *Image++;
648 Blt->Green = *Image++;
649 Blt->Red = *Image;
650 break;
651
652 default:
653 //
654 // Other bit format BMP is not supported.
655 //
656 if (IsAllocated) {
657 FreePool (*GopBlt);
658 *GopBlt = NULL;
659 }
660 return EFI_UNSUPPORTED;
661 break;
662 };
663
664 }
665
666 ImageIndex = (UINTN) (Image - ImageHeader);
667 if ((ImageIndex % 4) != 0) {
668 //
669 // Bmp Image starts each row on a 32-bit boundary!
670 //
671 Image = Image + (4 - (ImageIndex % 4));
672 }
673 }
674
675 return EFI_SUCCESS;
676 }
677
678 /**
679 Use SystemTable Conout to stop video based Simple Text Out consoles from going
680 to the video device. Put up LogoFile on every video device that is a console.
681
682 @param[in] LogoFile File name of logo to display on the center of the screen.
683
684 @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
685 @retval EFI_UNSUPPORTED Logo not found
686
687 **/
688 EFI_STATUS
689 PlatformBootManagerEnableQuietBoot (
690 IN EFI_GUID *LogoFile
691 )
692 {
693 EFI_STATUS Status;
694 EFI_OEM_BADGING_PROTOCOL *Badging;
695 UINT32 SizeOfX;
696 UINT32 SizeOfY;
697 INTN DestX;
698 INTN DestY;
699 UINT8 *ImageData;
700 UINTN ImageSize;
701 UINTN BltSize;
702 UINT32 Instance;
703 EFI_BADGING_FORMAT Format;
704 EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
705 UINTN CoordinateX;
706 UINTN CoordinateY;
707 UINTN Height;
708 UINTN Width;
709 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
710 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
711 UINT32 ColorDepth;
712 UINT32 RefreshRate;
713 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
714 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
715 UINTN NumberOfLogos;
716 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
717 UINTN LogoDestX;
718 UINTN LogoDestY;
719 UINTN LogoHeight;
720 UINTN LogoWidth;
721 UINTN NewDestX;
722 UINTN NewDestY;
723 UINTN NewHeight;
724 UINTN NewWidth;
725 UINT64 BufferSize;
726
727 UgaDraw = NULL;
728 //
729 // Try to open GOP first
730 //
731 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
732 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
733 GraphicsOutput = NULL;
734 //
735 // Open GOP failed, try to open UGA
736 //
737 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
738 }
739 if (EFI_ERROR (Status)) {
740 return EFI_UNSUPPORTED;
741 }
742
743 //
744 // Try to open Boot Logo Protocol.
745 //
746 BootLogo = NULL;
747 gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
748
749 //
750 // Erase Cursor from screen
751 //
752 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
753
754 Badging = NULL;
755 Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
756
757 if (GraphicsOutput != NULL) {
758 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
759 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
760
761 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
762 Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
763 if (EFI_ERROR (Status)) {
764 return EFI_UNSUPPORTED;
765 }
766 } else {
767 return EFI_UNSUPPORTED;
768 }
769
770 Blt = NULL;
771 NumberOfLogos = 0;
772 LogoDestX = 0;
773 LogoDestY = 0;
774 LogoHeight = 0;
775 LogoWidth = 0;
776 NewDestX = 0;
777 NewDestY = 0;
778 NewHeight = 0;
779 NewWidth = 0;
780 Instance = 0;
781 while (1) {
782 ImageData = NULL;
783 ImageSize = 0;
784
785 if (Badging != NULL) {
786 //
787 // Get image from OEMBadging protocol.
788 //
789 Status = Badging->GetImage (
790 Badging,
791 &Instance,
792 &Format,
793 &ImageData,
794 &ImageSize,
795 &Attribute,
796 &CoordinateX,
797 &CoordinateY
798 );
799 if (EFI_ERROR (Status)) {
800 goto Done;
801 }
802
803 //
804 // Currently only support BMP format.
805 //
806 if (Format != EfiBadgingFormatBMP) {
807 if (ImageData != NULL) {
808 FreePool (ImageData);
809 }
810 continue;
811 }
812 } else {
813 //
814 // Get the specified image from FV.
815 //
816 Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
817 if (EFI_ERROR (Status)) {
818 return EFI_UNSUPPORTED;
819 }
820
821 CoordinateX = 0;
822 CoordinateY = 0;
823 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
824 Attribute = EfiBadgingDisplayAttributeCenter;
825 } else {
826 Attribute = EfiBadgingDisplayAttributeCustomized;
827 }
828 }
829
830 if (Blt != NULL) {
831 FreePool (Blt);
832 }
833 Blt = NULL;
834 Status = PlatformBootManagerConvertBmpToGopBlt (
835 ImageData,
836 ImageSize,
837 (VOID **) &Blt,
838 &BltSize,
839 &Height,
840 &Width
841 );
842 if (EFI_ERROR (Status)) {
843 FreePool (ImageData);
844
845 if (Badging == NULL) {
846 return Status;
847 } else {
848 continue;
849 }
850 }
851
852 //
853 // Calculate the display position according to Attribute.
854 //
855 switch (Attribute) {
856 case EfiBadgingDisplayAttributeLeftTop:
857 DestX = CoordinateX;
858 DestY = CoordinateY;
859 break;
860
861 case EfiBadgingDisplayAttributeCenterTop:
862 DestX = (SizeOfX - Width) / 2;
863 DestY = CoordinateY;
864 break;
865
866 case EfiBadgingDisplayAttributeRightTop:
867 DestX = (SizeOfX - Width - CoordinateX);
868 DestY = CoordinateY;;
869 break;
870
871 case EfiBadgingDisplayAttributeCenterRight:
872 DestX = (SizeOfX - Width - CoordinateX);
873 DestY = (SizeOfY - Height) / 2;
874 break;
875
876 case EfiBadgingDisplayAttributeRightBottom:
877 DestX = (SizeOfX - Width - CoordinateX);
878 DestY = (SizeOfY - Height - CoordinateY);
879 break;
880
881 case EfiBadgingDisplayAttributeCenterBottom:
882 DestX = (SizeOfX - Width) / 2;
883 DestY = (SizeOfY - Height - CoordinateY);
884 break;
885
886 case EfiBadgingDisplayAttributeLeftBottom:
887 DestX = CoordinateX;
888 DestY = (SizeOfY - Height - CoordinateY);
889 break;
890
891 case EfiBadgingDisplayAttributeCenterLeft:
892 DestX = CoordinateX;
893 DestY = (SizeOfY - Height) / 2;
894 break;
895
896 case EfiBadgingDisplayAttributeCenter:
897 DestX = (SizeOfX - Width) / 2;
898 DestY = (SizeOfY - Height) / 2;
899 break;
900
901 case EfiBadgingDisplayAttributeCustomized:
902 DestX = (SizeOfX - Width) / 2;
903 DestY = ((SizeOfY * 382) / 1000) - Height / 2;
904 break;
905
906 default:
907 DestX = CoordinateX;
908 DestY = CoordinateY;
909 break;
910 }
911
912 if ((DestX >= 0) && (DestY >= 0)) {
913 if (GraphicsOutput != NULL) {
914 Status = GraphicsOutput->Blt (
915 GraphicsOutput,
916 Blt,
917 EfiBltBufferToVideo,
918 0,
919 0,
920 (UINTN) DestX,
921 (UINTN) DestY,
922 Width,
923 Height,
924 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
925 );
926 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
927 Status = UgaDraw->Blt (
928 UgaDraw,
929 (EFI_UGA_PIXEL *) Blt,
930 EfiUgaBltBufferToVideo,
931 0,
932 0,
933 (UINTN) DestX,
934 (UINTN) DestY,
935 Width,
936 Height,
937 Width * sizeof (EFI_UGA_PIXEL)
938 );
939 } else {
940 Status = EFI_UNSUPPORTED;
941 }
942
943 //
944 // Report displayed Logo information.
945 //
946 if (!EFI_ERROR (Status)) {
947 NumberOfLogos++;
948
949 if (LogoWidth == 0) {
950 //
951 // The first Logo.
952 //
953 LogoDestX = (UINTN) DestX;
954 LogoDestY = (UINTN) DestY;
955 LogoWidth = Width;
956 LogoHeight = Height;
957 } else {
958 //
959 // Merge new logo with old one.
960 //
961 NewDestX = MIN ((UINTN) DestX, LogoDestX);
962 NewDestY = MIN ((UINTN) DestY, LogoDestY);
963 NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
964 NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
965
966 LogoDestX = NewDestX;
967 LogoDestY = NewDestY;
968 LogoWidth = NewWidth;
969 LogoHeight = NewHeight;
970 }
971 }
972 }
973
974 FreePool (ImageData);
975
976 if (Badging == NULL) {
977 break;
978 }
979 }
980
981 Done:
982 if (BootLogo == NULL || NumberOfLogos == 0) {
983 //
984 // No logo displayed.
985 //
986 if (Blt != NULL) {
987 FreePool (Blt);
988 }
989
990 return Status;
991 }
992
993 //
994 // Advertise displayed Logo information.
995 //
996 if (NumberOfLogos == 1) {
997 //
998 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
999 //
1000 LogoBlt = Blt;
1001 Status = EFI_SUCCESS;
1002 } else {
1003 //
1004 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
1005 //
1006 if (Blt != NULL) {
1007 FreePool (Blt);
1008 }
1009
1010 //
1011 // Ensure the LogoHeight * LogoWidth doesn't overflow
1012 //
1013 if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
1014 return EFI_UNSUPPORTED;
1015 }
1016 BufferSize = MultU64x64 (LogoWidth, LogoHeight);
1017
1018 //
1019 // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
1020 //
1021 if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
1022 return EFI_UNSUPPORTED;
1023 }
1024
1025 LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1026 if (LogoBlt == NULL) {
1027 return EFI_OUT_OF_RESOURCES;
1028 }
1029
1030 if (GraphicsOutput != NULL) {
1031 Status = GraphicsOutput->Blt (
1032 GraphicsOutput,
1033 LogoBlt,
1034 EfiBltVideoToBltBuffer,
1035 LogoDestX,
1036 LogoDestY,
1037 0,
1038 0,
1039 LogoWidth,
1040 LogoHeight,
1041 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1042 );
1043 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1044 Status = UgaDraw->Blt (
1045 UgaDraw,
1046 (EFI_UGA_PIXEL *) LogoBlt,
1047 EfiUgaVideoToBltBuffer,
1048 LogoDestX,
1049 LogoDestY,
1050 0,
1051 0,
1052 LogoWidth,
1053 LogoHeight,
1054 LogoWidth * sizeof (EFI_UGA_PIXEL)
1055 );
1056 } else {
1057 Status = EFI_UNSUPPORTED;
1058 }
1059 }
1060
1061 if (!EFI_ERROR (Status)) {
1062 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
1063 }
1064 FreePool (LogoBlt);
1065
1066 return Status;
1067 }
1068
1069 /**
1070 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
1071 Simple Text Out screens will now be synced up with all non video output devices
1072
1073 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
1074
1075 **/
1076 EFI_STATUS
1077 PlatformBootManagerDisableQuietBoot (
1078 VOID
1079 )
1080 {
1081 //
1082 // Enable Cursor on Screen
1083 //
1084 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1085 return EFI_SUCCESS;
1086 }