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