]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
Add more check for the bmp file to avoid access violation.
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsConsole.c
1 /** @file
2 BDS Lib functions which contain all the code to connect console device
3
4 Copyright (c) 2004 - 2012, 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 "InternalBdsLib.h"
16 #include <IndustryStandard/Bmp.h>
17
18
19 /**
20 Check if we need to save the EFI variable with "ConVarName" as name
21 as NV type
22 If ConVarName is NULL, then ASSERT().
23
24 @param ConVarName The name of the EFI variable.
25
26 @retval TRUE Set the EFI variable as NV type.
27 @retval FALSE EFI variable as NV type can be set NonNV.
28 **/
29 BOOLEAN
30 IsNvNeed (
31 IN CHAR16 *ConVarName
32 )
33 {
34 CHAR16 *Ptr;
35
36 ASSERT (ConVarName != NULL);
37
38 Ptr = ConVarName;
39
40 //
41 // If the variable includes "Dev" at last, we consider
42 // it does not support NV attribute.
43 //
44 while (*Ptr != L'\0') {
45 Ptr++;
46 }
47
48 if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
49 return TRUE;
50 }
51
52 if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
53 return FALSE;
54 } else {
55 return TRUE;
56 }
57 }
58
59 /**
60 Fill console handle in System Table if there are no valid console handle in.
61
62 Firstly, check the validation of console handle in System Table. If it is invalid,
63 update it by the first console device handle from EFI console variable.
64
65 @param VarName The name of the EFI console variable.
66 @param ConsoleGuid Specified Console protocol GUID.
67 @param ConsoleHandle On IN, console handle in System Table to be checked.
68 On OUT, new console hanlde in system table.
69 @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
70 On OUT, new console protocol on new console hanlde in system table.
71
72 @retval TRUE System Table has been updated.
73 @retval FALSE System Table hasn't been updated.
74
75 **/
76 BOOLEAN
77 UpdateSystemTableConsole (
78 IN CHAR16 *VarName,
79 IN EFI_GUID *ConsoleGuid,
80 IN OUT EFI_HANDLE *ConsoleHandle,
81 IN OUT VOID **ProtocolInterface
82 )
83 {
84 EFI_STATUS Status;
85 UINTN DevicePathSize;
86 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
87 EFI_DEVICE_PATH_PROTOCOL *VarConsole;
88 EFI_DEVICE_PATH_PROTOCOL *Instance;
89 VOID *Interface;
90 EFI_HANDLE NewHandle;
91
92 ASSERT (VarName != NULL);
93 ASSERT (ConsoleHandle != NULL);
94 ASSERT (ConsoleGuid != NULL);
95 ASSERT (ProtocolInterface != NULL);
96
97 if (*ConsoleHandle != NULL) {
98 Status = gBS->HandleProtocol (
99 *ConsoleHandle,
100 ConsoleGuid,
101 &Interface
102 );
103 if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
104 //
105 // If ConsoleHandle is valid and console protocol on this handle also
106 // also matched, just return.
107 //
108 return FALSE;
109 }
110 }
111
112 //
113 // Get all possible consoles device path from EFI variable
114 //
115 VarConsole = BdsLibGetVariableAndSize (
116 VarName,
117 &gEfiGlobalVariableGuid,
118 &DevicePathSize
119 );
120 if (VarConsole == NULL) {
121 //
122 // If there is no any console device, just return.
123 //
124 return FALSE;
125 }
126
127 FullDevicePath = VarConsole;
128
129 do {
130 //
131 // Check every instance of the console variable
132 //
133 Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
134 if (Instance == NULL) {
135 FreePool (FullDevicePath);
136 ASSERT (FALSE);
137 }
138
139 //
140 // Find console device handle by device path instance
141 //
142 Status = gBS->LocateDevicePath (
143 ConsoleGuid,
144 &Instance,
145 &NewHandle
146 );
147 if (!EFI_ERROR (Status)) {
148 //
149 // Get the console protocol on this console device handle
150 //
151 Status = gBS->HandleProtocol (
152 NewHandle,
153 ConsoleGuid,
154 &Interface
155 );
156 if (!EFI_ERROR (Status)) {
157 //
158 // Update new console handle in System Table.
159 //
160 *ConsoleHandle = NewHandle;
161 *ProtocolInterface = Interface;
162 return TRUE;
163 }
164 }
165
166 } while (Instance != NULL);
167
168 //
169 // No any available console devcie found.
170 //
171 return FALSE;
172 }
173
174 /**
175 This function update console variable based on ConVarName, it can
176 add or remove one specific console device path from the variable
177
178 @param ConVarName Console related variable name, ConIn, ConOut,
179 ErrOut.
180 @param CustomizedConDevicePath The console device path which will be added to
181 the console variable ConVarName, this parameter
182 can not be multi-instance.
183 @param ExclusiveDevicePath The console device path which will be removed
184 from the console variable ConVarName, this
185 parameter can not be multi-instance.
186
187 @retval EFI_UNSUPPORTED The added device path is same to the removed one.
188 @retval EFI_SUCCESS Success add or remove the device path from the
189 console variable.
190
191 **/
192 EFI_STATUS
193 EFIAPI
194 BdsLibUpdateConsoleVariable (
195 IN CHAR16 *ConVarName,
196 IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
197 IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
198 )
199 {
200 EFI_STATUS Status;
201 EFI_DEVICE_PATH_PROTOCOL *VarConsole;
202 UINTN DevicePathSize;
203 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
204 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
205 UINT32 Attributes;
206
207 VarConsole = NULL;
208 DevicePathSize = 0;
209
210 //
211 // Notes: check the device path point, here should check
212 // with compare memory
213 //
214 if (CustomizedConDevicePath == ExclusiveDevicePath) {
215 return EFI_UNSUPPORTED;
216 }
217 //
218 // Delete the ExclusiveDevicePath from current default console
219 //
220 VarConsole = BdsLibGetVariableAndSize (
221 ConVarName,
222 &gEfiGlobalVariableGuid,
223 &DevicePathSize
224 );
225
226 //
227 // Initialize NewDevicePath
228 //
229 NewDevicePath = VarConsole;
230
231 //
232 // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
233 // In the end, NewDevicePath is the final device path.
234 //
235 if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
236 NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
237 }
238 //
239 // Try to append customized device path to NewDevicePath.
240 //
241 if (CustomizedConDevicePath != NULL) {
242 if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
243 //
244 // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
245 //
246 NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
247 //
248 // In the first check, the default console variable will be _ModuleEntryPoint,
249 // just append current customized device path
250 //
251 TempNewDevicePath = NewDevicePath;
252 NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
253 if (TempNewDevicePath != NULL) {
254 FreePool(TempNewDevicePath);
255 }
256 }
257 }
258
259 //
260 // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
261 //
262 if (IsNvNeed(ConVarName)) {
263 //
264 // ConVarName has NV attribute.
265 //
266 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
267 } else {
268 //
269 // ConVarName does not have NV attribute.
270 //
271 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
272 }
273
274 //
275 // Finally, Update the variable of the default console by NewDevicePath
276 //
277 DevicePathSize = GetDevicePathSize (NewDevicePath);
278 Status = gRT->SetVariable (
279 ConVarName,
280 &gEfiGlobalVariableGuid,
281 Attributes,
282 DevicePathSize,
283 NewDevicePath
284 );
285 if ((DevicePathSize == 0) && (Status == EFI_NOT_FOUND)) {
286 Status = EFI_SUCCESS;
287 }
288 ASSERT_EFI_ERROR (Status);
289
290 if (VarConsole == NewDevicePath) {
291 if (VarConsole != NULL) {
292 FreePool(VarConsole);
293 }
294 } else {
295 if (VarConsole != NULL) {
296 FreePool(VarConsole);
297 }
298 if (NewDevicePath != NULL) {
299 FreePool(NewDevicePath);
300 }
301 }
302
303 return Status;
304
305 }
306
307
308 /**
309 Connect the console device base on the variable ConVarName, if
310 device path of the ConVarName is multi-instance device path, if
311 anyone of the instances is connected success, then this function
312 will return success.
313
314 @param ConVarName Console related variable name, ConIn, ConOut,
315 ErrOut.
316
317 @retval EFI_NOT_FOUND There is not any console devices connected
318 success
319 @retval EFI_SUCCESS Success connect any one instance of the console
320 device path base on the variable ConVarName.
321
322 **/
323 EFI_STATUS
324 EFIAPI
325 BdsLibConnectConsoleVariable (
326 IN CHAR16 *ConVarName
327 )
328 {
329 EFI_STATUS Status;
330 EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
331 UINTN VariableSize;
332 EFI_DEVICE_PATH_PROTOCOL *Instance;
333 EFI_DEVICE_PATH_PROTOCOL *Next;
334 EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
335 UINTN Size;
336 BOOLEAN DeviceExist;
337
338 Status = EFI_SUCCESS;
339 DeviceExist = FALSE;
340
341 //
342 // Check if the console variable exist
343 //
344 StartDevicePath = BdsLibGetVariableAndSize (
345 ConVarName,
346 &gEfiGlobalVariableGuid,
347 &VariableSize
348 );
349 if (StartDevicePath == NULL) {
350 return EFI_UNSUPPORTED;
351 }
352
353 CopyOfDevicePath = StartDevicePath;
354 do {
355 //
356 // Check every instance of the console variable
357 //
358 Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
359 if (Instance == NULL) {
360 FreePool (StartDevicePath);
361 return EFI_UNSUPPORTED;
362 }
363
364 Next = Instance;
365 while (!IsDevicePathEndType (Next)) {
366 Next = NextDevicePathNode (Next);
367 }
368
369 SetDevicePathEndNode (Next);
370 //
371 // Connect the USB console
372 // USB console device path is a short-form device path that
373 // starts with the first element being a USB WWID
374 // or a USB Class device path
375 //
376 if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
377 ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
378 || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
379 )) {
380 Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance);
381 if (!EFI_ERROR (Status)) {
382 DeviceExist = TRUE;
383 }
384 } else {
385 //
386 // Connect the instance device path
387 //
388 Status = BdsLibConnectDevicePath (Instance);
389 if (EFI_ERROR (Status)) {
390 //
391 // Delete the instance from the console varialbe
392 //
393 BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
394 } else {
395 DeviceExist = TRUE;
396 }
397 }
398 FreePool(Instance);
399 } while (CopyOfDevicePath != NULL);
400
401 FreePool (StartDevicePath);
402
403 if (!DeviceExist) {
404 return EFI_NOT_FOUND;
405 }
406
407 return EFI_SUCCESS;
408 }
409
410
411 /**
412 This function will search every simpletext device in current system,
413 and make every simpletext device as pertantial console device.
414
415 **/
416 VOID
417 EFIAPI
418 BdsLibConnectAllConsoles (
419 VOID
420 )
421 {
422 UINTN Index;
423 EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
424 UINTN HandleCount;
425 EFI_HANDLE *HandleBuffer;
426
427 Index = 0;
428 HandleCount = 0;
429 HandleBuffer = NULL;
430 ConDevicePath = NULL;
431
432 //
433 // Update all the console variables
434 //
435 gBS->LocateHandleBuffer (
436 ByProtocol,
437 &gEfiSimpleTextInProtocolGuid,
438 NULL,
439 &HandleCount,
440 &HandleBuffer
441 );
442
443 for (Index = 0; Index < HandleCount; Index++) {
444 gBS->HandleProtocol (
445 HandleBuffer[Index],
446 &gEfiDevicePathProtocolGuid,
447 (VOID **) &ConDevicePath
448 );
449 BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
450 }
451
452 if (HandleBuffer != NULL) {
453 FreePool(HandleBuffer);
454 HandleBuffer = NULL;
455 }
456
457 gBS->LocateHandleBuffer (
458 ByProtocol,
459 &gEfiSimpleTextOutProtocolGuid,
460 NULL,
461 &HandleCount,
462 &HandleBuffer
463 );
464 for (Index = 0; Index < HandleCount; Index++) {
465 gBS->HandleProtocol (
466 HandleBuffer[Index],
467 &gEfiDevicePathProtocolGuid,
468 (VOID **) &ConDevicePath
469 );
470 BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
471 BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
472 }
473
474 if (HandleBuffer != NULL) {
475 FreePool(HandleBuffer);
476 }
477
478 //
479 // Connect all console variables
480 //
481 BdsLibConnectAllDefaultConsoles ();
482
483 }
484
485 /**
486 This function will connect console device base on the console
487 device variable ConIn, ConOut and ErrOut.
488
489 @retval EFI_SUCCESS At least one of the ConIn and ConOut device have
490 been connected success.
491 @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
492
493 **/
494 EFI_STATUS
495 EFIAPI
496 BdsLibConnectAllDefaultConsoles (
497 VOID
498 )
499 {
500 EFI_STATUS Status;
501 BOOLEAN SystemTableUpdated;
502
503 //
504 // Connect all default console variables
505 //
506
507 //
508 // It seems impossible not to have any ConOut device on platform,
509 // so we check the status here.
510 //
511 Status = BdsLibConnectConsoleVariable (L"ConOut");
512 if (EFI_ERROR (Status)) {
513 return Status;
514 }
515
516 //
517 // Insert the performance probe for Console Out
518 //
519 PERF_START (NULL, "ConOut", "BDS", 1);
520 PERF_END (NULL, "ConOut", "BDS", 0);
521
522 //
523 // Because possibly the platform is legacy free, in such case,
524 // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
525 // so we need not check the status.
526 //
527 BdsLibConnectConsoleVariable (L"ConIn");
528
529 //
530 // The _ModuleEntryPoint err out var is legal.
531 //
532 BdsLibConnectConsoleVariable (L"ErrOut");
533
534 SystemTableUpdated = FALSE;
535 //
536 // Fill console handles in System Table if no console device assignd.
537 //
538 if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
539 SystemTableUpdated = TRUE;
540 }
541 if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
542 SystemTableUpdated = TRUE;
543 }
544 if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
545 SystemTableUpdated = TRUE;
546 }
547
548 if (SystemTableUpdated) {
549 //
550 // Update the CRC32 in the EFI System Table header
551 //
552 gST->Hdr.CRC32 = 0;
553 gBS->CalculateCrc32 (
554 (UINT8 *) &gST->Hdr,
555 gST->Hdr.HeaderSize,
556 &gST->Hdr.CRC32
557 );
558 }
559
560 return EFI_SUCCESS;
561
562 }
563
564 /**
565 Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
566 is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
567 buffer is passed in it will be used if it is big enough.
568
569 @param BmpImage Pointer to BMP file
570 @param BmpImageSize Number of bytes in BmpImage
571 @param GopBlt Buffer containing GOP version of BmpImage.
572 @param GopBltSize Size of GopBlt in bytes.
573 @param PixelHeight Height of GopBlt/BmpImage in pixels
574 @param PixelWidth Width of GopBlt/BmpImage in pixels
575
576 @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
577 @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
578 @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
579 GopBltSize will contain the required size.
580 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
581
582 **/
583 EFI_STATUS
584 ConvertBmpToGopBlt (
585 IN VOID *BmpImage,
586 IN UINTN BmpImageSize,
587 IN OUT VOID **GopBlt,
588 IN OUT UINTN *GopBltSize,
589 OUT UINTN *PixelHeight,
590 OUT UINTN *PixelWidth
591 )
592 {
593 UINT8 *Image;
594 UINT8 *ImageHeader;
595 BMP_IMAGE_HEADER *BmpHeader;
596 BMP_COLOR_MAP *BmpColorMap;
597 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
598 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
599 UINT64 BltBufferSize;
600 UINTN Index;
601 UINTN Height;
602 UINTN Width;
603 UINTN ImageIndex;
604 UINT32 DataSizePerLine;
605 BOOLEAN IsAllocated;
606 UINT32 ColorMapNum;
607
608 if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
609 return EFI_INVALID_PARAMETER;
610 }
611
612 BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
613
614 if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
615 return EFI_UNSUPPORTED;
616 }
617
618 //
619 // Doesn't support compress.
620 //
621 if (BmpHeader->CompressionType != 0) {
622 return EFI_UNSUPPORTED;
623 }
624
625 //
626 // Only support BITMAPINFOHEADER format.
627 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
628 //
629 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
630 return EFI_UNSUPPORTED;
631 }
632
633 //
634 // The data size in each line must be 4 byte alignment.
635 //
636 DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
637 BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
638 if (BltBufferSize > (UINT32) ~0) {
639 return EFI_INVALID_PARAMETER;
640 }
641
642 if ((BmpHeader->Size != BmpImageSize) ||
643 (BmpHeader->Size < BmpHeader->ImageOffset) ||
644 (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {
645 return EFI_INVALID_PARAMETER;
646 }
647
648 //
649 // Calculate Color Map offset in the image.
650 //
651 Image = BmpImage;
652 BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
653 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
654 return EFI_INVALID_PARAMETER;
655 }
656
657 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
658 switch (BmpHeader->BitPerPixel) {
659 case 1:
660 ColorMapNum = 2;
661 break;
662 case 4:
663 ColorMapNum = 16;
664 break;
665 case 8:
666 ColorMapNum = 256;
667 break;
668 default:
669 ColorMapNum = 0;
670 break;
671 }
672 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) != sizeof (BMP_COLOR_MAP) * ColorMapNum) {
673 return EFI_INVALID_PARAMETER;
674 }
675 }
676
677 //
678 // Calculate graphics image data address in the image
679 //
680 Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
681 ImageHeader = Image;
682
683 //
684 // Calculate the BltBuffer needed size.
685 //
686 BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
687 //
688 // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
689 //
690 if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
691 return EFI_UNSUPPORTED;
692 }
693 BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
694
695 IsAllocated = FALSE;
696 if (*GopBlt == NULL) {
697 //
698 // GopBlt is not allocated by caller.
699 //
700 *GopBltSize = (UINTN) BltBufferSize;
701 *GopBlt = AllocatePool (*GopBltSize);
702 IsAllocated = TRUE;
703 if (*GopBlt == NULL) {
704 return EFI_OUT_OF_RESOURCES;
705 }
706 } else {
707 //
708 // GopBlt has been allocated by caller.
709 //
710 if (*GopBltSize < (UINTN) BltBufferSize) {
711 *GopBltSize = (UINTN) BltBufferSize;
712 return EFI_BUFFER_TOO_SMALL;
713 }
714 }
715
716 *PixelWidth = BmpHeader->PixelWidth;
717 *PixelHeight = BmpHeader->PixelHeight;
718
719 //
720 // Convert image from BMP to Blt buffer format
721 //
722 BltBuffer = *GopBlt;
723 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
724 Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
725 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
726 switch (BmpHeader->BitPerPixel) {
727 case 1:
728 //
729 // Convert 1-bit (2 colors) BMP to 24-bit color
730 //
731 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
732 Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
733 Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
734 Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
735 Blt++;
736 Width++;
737 }
738
739 Blt--;
740 Width--;
741 break;
742
743 case 4:
744 //
745 // Convert 4-bit (16 colors) BMP Palette to 24-bit color
746 //
747 Index = (*Image) >> 4;
748 Blt->Red = BmpColorMap[Index].Red;
749 Blt->Green = BmpColorMap[Index].Green;
750 Blt->Blue = BmpColorMap[Index].Blue;
751 if (Width < (BmpHeader->PixelWidth - 1)) {
752 Blt++;
753 Width++;
754 Index = (*Image) & 0x0f;
755 Blt->Red = BmpColorMap[Index].Red;
756 Blt->Green = BmpColorMap[Index].Green;
757 Blt->Blue = BmpColorMap[Index].Blue;
758 }
759 break;
760
761 case 8:
762 //
763 // Convert 8-bit (256 colors) BMP Palette to 24-bit color
764 //
765 Blt->Red = BmpColorMap[*Image].Red;
766 Blt->Green = BmpColorMap[*Image].Green;
767 Blt->Blue = BmpColorMap[*Image].Blue;
768 break;
769
770 case 24:
771 //
772 // It is 24-bit BMP.
773 //
774 Blt->Blue = *Image++;
775 Blt->Green = *Image++;
776 Blt->Red = *Image;
777 break;
778
779 default:
780 //
781 // Other bit format BMP is not supported.
782 //
783 if (IsAllocated) {
784 FreePool (*GopBlt);
785 *GopBlt = NULL;
786 }
787 return EFI_UNSUPPORTED;
788 break;
789 };
790
791 }
792
793 ImageIndex = (UINTN) (Image - ImageHeader);
794 if ((ImageIndex % 4) != 0) {
795 //
796 // Bmp Image starts each row on a 32-bit boundary!
797 //
798 Image = Image + (4 - (ImageIndex % 4));
799 }
800 }
801
802 return EFI_SUCCESS;
803 }
804
805 /**
806 Use SystemTable Conout to stop video based Simple Text Out consoles from going
807 to the video device. Put up LogoFile on every video device that is a console.
808
809 @param[in] LogoFile File name of logo to display on the center of the screen.
810
811 @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
812 @retval EFI_UNSUPPORTED Logo not found
813
814 **/
815 EFI_STATUS
816 EFIAPI
817 EnableQuietBoot (
818 IN EFI_GUID *LogoFile
819 )
820 {
821 EFI_STATUS Status;
822 EFI_OEM_BADGING_PROTOCOL *Badging;
823 UINT32 SizeOfX;
824 UINT32 SizeOfY;
825 INTN DestX;
826 INTN DestY;
827 UINT8 *ImageData;
828 UINTN ImageSize;
829 UINTN BltSize;
830 UINT32 Instance;
831 EFI_BADGING_FORMAT Format;
832 EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
833 UINTN CoordinateX;
834 UINTN CoordinateY;
835 UINTN Height;
836 UINTN Width;
837 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
838 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
839 UINT32 ColorDepth;
840 UINT32 RefreshRate;
841 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
842 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
843 UINTN NumberOfLogos;
844 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
845 UINTN LogoDestX;
846 UINTN LogoDestY;
847 UINTN LogoHeight;
848 UINTN LogoWidth;
849 UINTN NewDestX;
850 UINTN NewDestY;
851 UINTN NewHeight;
852 UINTN NewWidth;
853 UINT64 BufferSize;
854
855 UgaDraw = NULL;
856 //
857 // Try to open GOP first
858 //
859 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
860 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
861 GraphicsOutput = NULL;
862 //
863 // Open GOP failed, try to open UGA
864 //
865 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
866 }
867 if (EFI_ERROR (Status)) {
868 return EFI_UNSUPPORTED;
869 }
870
871 //
872 // Try to open Boot Logo Protocol.
873 //
874 BootLogo = NULL;
875 gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
876
877 //
878 // Erase Cursor from screen
879 //
880 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
881
882 Badging = NULL;
883 Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
884
885 if (GraphicsOutput != NULL) {
886 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
887 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
888
889 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
890 Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
891 if (EFI_ERROR (Status)) {
892 return EFI_UNSUPPORTED;
893 }
894 } else {
895 return EFI_UNSUPPORTED;
896 }
897
898 Blt = NULL;
899 NumberOfLogos = 0;
900 LogoDestX = 0;
901 LogoDestY = 0;
902 LogoHeight = 0;
903 LogoWidth = 0;
904 NewDestX = 0;
905 NewDestY = 0;
906 NewHeight = 0;
907 NewWidth = 0;
908 Instance = 0;
909 while (1) {
910 ImageData = NULL;
911 ImageSize = 0;
912
913 if (Badging != NULL) {
914 //
915 // Get image from OEMBadging protocol.
916 //
917 Status = Badging->GetImage (
918 Badging,
919 &Instance,
920 &Format,
921 &ImageData,
922 &ImageSize,
923 &Attribute,
924 &CoordinateX,
925 &CoordinateY
926 );
927 if (EFI_ERROR (Status)) {
928 goto Done;
929 }
930
931 //
932 // Currently only support BMP format.
933 //
934 if (Format != EfiBadgingFormatBMP) {
935 if (ImageData != NULL) {
936 FreePool (ImageData);
937 }
938 continue;
939 }
940 } else {
941 //
942 // Get the specified image from FV.
943 //
944 Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
945 if (EFI_ERROR (Status)) {
946 return EFI_UNSUPPORTED;
947 }
948
949 CoordinateX = 0;
950 CoordinateY = 0;
951 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
952 Attribute = EfiBadgingDisplayAttributeCenter;
953 } else {
954 Attribute = EfiBadgingDisplayAttributeCustomized;
955 }
956 }
957
958 if (Blt != NULL) {
959 FreePool (Blt);
960 }
961 Blt = NULL;
962 Status = ConvertBmpToGopBlt (
963 ImageData,
964 ImageSize,
965 (VOID **) &Blt,
966 &BltSize,
967 &Height,
968 &Width
969 );
970 if (EFI_ERROR (Status)) {
971 FreePool (ImageData);
972
973 if (Badging == NULL) {
974 return Status;
975 } else {
976 continue;
977 }
978 }
979
980 //
981 // Calculate the display position according to Attribute.
982 //
983 switch (Attribute) {
984 case EfiBadgingDisplayAttributeLeftTop:
985 DestX = CoordinateX;
986 DestY = CoordinateY;
987 break;
988
989 case EfiBadgingDisplayAttributeCenterTop:
990 DestX = (SizeOfX - Width) / 2;
991 DestY = CoordinateY;
992 break;
993
994 case EfiBadgingDisplayAttributeRightTop:
995 DestX = (SizeOfX - Width - CoordinateX);
996 DestY = CoordinateY;;
997 break;
998
999 case EfiBadgingDisplayAttributeCenterRight:
1000 DestX = (SizeOfX - Width - CoordinateX);
1001 DestY = (SizeOfY - Height) / 2;
1002 break;
1003
1004 case EfiBadgingDisplayAttributeRightBottom:
1005 DestX = (SizeOfX - Width - CoordinateX);
1006 DestY = (SizeOfY - Height - CoordinateY);
1007 break;
1008
1009 case EfiBadgingDisplayAttributeCenterBottom:
1010 DestX = (SizeOfX - Width) / 2;
1011 DestY = (SizeOfY - Height - CoordinateY);
1012 break;
1013
1014 case EfiBadgingDisplayAttributeLeftBottom:
1015 DestX = CoordinateX;
1016 DestY = (SizeOfY - Height - CoordinateY);
1017 break;
1018
1019 case EfiBadgingDisplayAttributeCenterLeft:
1020 DestX = CoordinateX;
1021 DestY = (SizeOfY - Height) / 2;
1022 break;
1023
1024 case EfiBadgingDisplayAttributeCenter:
1025 DestX = (SizeOfX - Width) / 2;
1026 DestY = (SizeOfY - Height) / 2;
1027 break;
1028
1029 case EfiBadgingDisplayAttributeCustomized:
1030 DestX = (SizeOfX - Width) / 2;
1031 DestY = ((SizeOfY * 382) / 1000) - Height / 2;
1032 break;
1033
1034 default:
1035 DestX = CoordinateX;
1036 DestY = CoordinateY;
1037 break;
1038 }
1039
1040 if ((DestX >= 0) && (DestY >= 0)) {
1041 if (GraphicsOutput != NULL) {
1042 Status = GraphicsOutput->Blt (
1043 GraphicsOutput,
1044 Blt,
1045 EfiBltBufferToVideo,
1046 0,
1047 0,
1048 (UINTN) DestX,
1049 (UINTN) DestY,
1050 Width,
1051 Height,
1052 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1053 );
1054 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1055 Status = UgaDraw->Blt (
1056 UgaDraw,
1057 (EFI_UGA_PIXEL *) Blt,
1058 EfiUgaBltBufferToVideo,
1059 0,
1060 0,
1061 (UINTN) DestX,
1062 (UINTN) DestY,
1063 Width,
1064 Height,
1065 Width * sizeof (EFI_UGA_PIXEL)
1066 );
1067 } else {
1068 Status = EFI_UNSUPPORTED;
1069 }
1070
1071 //
1072 // Report displayed Logo information.
1073 //
1074 if (!EFI_ERROR (Status)) {
1075 NumberOfLogos++;
1076
1077 if (LogoWidth == 0) {
1078 //
1079 // The first Logo.
1080 //
1081 LogoDestX = (UINTN) DestX;
1082 LogoDestY = (UINTN) DestY;
1083 LogoWidth = Width;
1084 LogoHeight = Height;
1085 } else {
1086 //
1087 // Merge new logo with old one.
1088 //
1089 NewDestX = MIN ((UINTN) DestX, LogoDestX);
1090 NewDestY = MIN ((UINTN) DestY, LogoDestY);
1091 NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
1092 NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
1093
1094 LogoDestX = NewDestX;
1095 LogoDestY = NewDestY;
1096 LogoWidth = NewWidth;
1097 LogoHeight = NewHeight;
1098 }
1099 }
1100 }
1101
1102 FreePool (ImageData);
1103
1104 if (Badging == NULL) {
1105 break;
1106 }
1107 }
1108
1109 Done:
1110 if (BootLogo == NULL || NumberOfLogos == 0) {
1111 //
1112 // No logo displayed.
1113 //
1114 if (Blt != NULL) {
1115 FreePool (Blt);
1116 }
1117
1118 return Status;
1119 }
1120
1121 //
1122 // Advertise displayed Logo information.
1123 //
1124 if (NumberOfLogos == 1) {
1125 //
1126 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
1127 //
1128 LogoBlt = Blt;
1129 Status = EFI_SUCCESS;
1130 } else {
1131 //
1132 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
1133 //
1134 if (Blt != NULL) {
1135 FreePool (Blt);
1136 }
1137
1138 //
1139 // Ensure the LogoHeight * LogoWidth doesn't overflow
1140 //
1141 if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
1142 return EFI_UNSUPPORTED;
1143 }
1144 BufferSize = MultU64x64 (LogoWidth, LogoHeight);
1145
1146 //
1147 // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
1148 //
1149 if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
1150 return EFI_UNSUPPORTED;
1151 }
1152
1153 LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1154 if (LogoBlt == NULL) {
1155 return EFI_OUT_OF_RESOURCES;
1156 }
1157
1158 if (GraphicsOutput != NULL) {
1159 Status = GraphicsOutput->Blt (
1160 GraphicsOutput,
1161 LogoBlt,
1162 EfiBltVideoToBltBuffer,
1163 LogoDestX,
1164 LogoDestY,
1165 0,
1166 0,
1167 LogoWidth,
1168 LogoHeight,
1169 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1170 );
1171 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1172 Status = UgaDraw->Blt (
1173 UgaDraw,
1174 (EFI_UGA_PIXEL *) LogoBlt,
1175 EfiUgaVideoToBltBuffer,
1176 LogoDestX,
1177 LogoDestY,
1178 0,
1179 0,
1180 LogoWidth,
1181 LogoHeight,
1182 LogoWidth * sizeof (EFI_UGA_PIXEL)
1183 );
1184 } else {
1185 Status = EFI_UNSUPPORTED;
1186 }
1187 }
1188
1189 if (!EFI_ERROR (Status)) {
1190 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
1191 }
1192 FreePool (LogoBlt);
1193
1194 return Status;
1195 }
1196
1197 /**
1198 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
1199 Simple Text Out screens will now be synced up with all non video output devices
1200
1201 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
1202
1203 **/
1204 EFI_STATUS
1205 EFIAPI
1206 DisableQuietBoot (
1207 VOID
1208 )
1209 {
1210
1211 //
1212 // Enable Cursor on Screen
1213 //
1214 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1215 return EFI_SUCCESS;
1216 }
1217