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