]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
280b1697b6421733dccbfa2ee502e4bd741ae47a
[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 This function will connect console device except ConIn base on the console
566 device variable ConOut and ErrOut.
567
568 @retval EFI_SUCCESS At least one of the ConOut device have
569 been connected success.
570 @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
571
572 **/
573 EFI_STATUS
574 EFIAPI
575 BdsLibConnectAllDefaultConsolesWithOutConIn (
576 VOID
577 )
578 {
579 EFI_STATUS Status;
580 BOOLEAN SystemTableUpdated;
581
582 //
583 // Connect all default console variables except ConIn
584 //
585
586 //
587 // It seems impossible not to have any ConOut device on platform,
588 // so we check the status here.
589 //
590 Status = BdsLibConnectConsoleVariable (L"ConOut");
591 if (EFI_ERROR (Status)) {
592 return Status;
593 }
594
595 //
596 // Insert the performance probe for Console Out
597 //
598 PERF_START (NULL, "ConOut", "BDS", 1);
599 PERF_END (NULL, "ConOut", "BDS", 0);
600
601 //
602 // The _ModuleEntryPoint err out var is legal.
603 //
604 BdsLibConnectConsoleVariable (L"ErrOut");
605
606 SystemTableUpdated = FALSE;
607 //
608 // Fill console handles in System Table if no console device assignd.
609 //
610 if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
611 SystemTableUpdated = TRUE;
612 }
613 if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
614 SystemTableUpdated = TRUE;
615 }
616
617 if (SystemTableUpdated) {
618 //
619 // Update the CRC32 in the EFI System Table header
620 //
621 gST->Hdr.CRC32 = 0;
622 gBS->CalculateCrc32 (
623 (UINT8 *) &gST->Hdr,
624 gST->Hdr.HeaderSize,
625 &gST->Hdr.CRC32
626 );
627 }
628
629 return EFI_SUCCESS;
630
631 }
632
633 /**
634 Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
635 is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
636 buffer is passed in it will be used if it is big enough.
637
638 @param BmpImage Pointer to BMP file
639 @param BmpImageSize Number of bytes in BmpImage
640 @param GopBlt Buffer containing GOP version of BmpImage.
641 @param GopBltSize Size of GopBlt in bytes.
642 @param PixelHeight Height of GopBlt/BmpImage in pixels
643 @param PixelWidth Width of GopBlt/BmpImage in pixels
644
645 @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
646 @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
647 @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
648 GopBltSize will contain the required size.
649 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
650
651 **/
652 EFI_STATUS
653 ConvertBmpToGopBlt (
654 IN VOID *BmpImage,
655 IN UINTN BmpImageSize,
656 IN OUT VOID **GopBlt,
657 IN OUT UINTN *GopBltSize,
658 OUT UINTN *PixelHeight,
659 OUT UINTN *PixelWidth
660 )
661 {
662 UINT8 *Image;
663 UINT8 *ImageHeader;
664 BMP_IMAGE_HEADER *BmpHeader;
665 BMP_COLOR_MAP *BmpColorMap;
666 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
667 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
668 UINT64 BltBufferSize;
669 UINTN Index;
670 UINTN Height;
671 UINTN Width;
672 UINTN ImageIndex;
673 UINT32 DataSizePerLine;
674 BOOLEAN IsAllocated;
675 UINT32 ColorMapNum;
676
677 if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
678 return EFI_INVALID_PARAMETER;
679 }
680
681 BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
682
683 if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
684 return EFI_UNSUPPORTED;
685 }
686
687 //
688 // Doesn't support compress.
689 //
690 if (BmpHeader->CompressionType != 0) {
691 return EFI_UNSUPPORTED;
692 }
693
694 //
695 // Only support BITMAPINFOHEADER format.
696 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
697 //
698 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
699 return EFI_UNSUPPORTED;
700 }
701
702 //
703 // The data size in each line must be 4 byte alignment.
704 //
705 DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
706 BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
707 if (BltBufferSize > (UINT32) ~0) {
708 return EFI_INVALID_PARAMETER;
709 }
710
711 if ((BmpHeader->Size != BmpImageSize) ||
712 (BmpHeader->Size < BmpHeader->ImageOffset) ||
713 (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {
714 return EFI_INVALID_PARAMETER;
715 }
716
717 //
718 // Calculate Color Map offset in the image.
719 //
720 Image = BmpImage;
721 BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
722 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
723 return EFI_INVALID_PARAMETER;
724 }
725
726 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
727 switch (BmpHeader->BitPerPixel) {
728 case 1:
729 ColorMapNum = 2;
730 break;
731 case 4:
732 ColorMapNum = 16;
733 break;
734 case 8:
735 ColorMapNum = 256;
736 break;
737 default:
738 ColorMapNum = 0;
739 break;
740 }
741 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) != sizeof (BMP_COLOR_MAP) * ColorMapNum) {
742 return EFI_INVALID_PARAMETER;
743 }
744 }
745
746 //
747 // Calculate graphics image data address in the image
748 //
749 Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
750 ImageHeader = Image;
751
752 //
753 // Calculate the BltBuffer needed size.
754 //
755 BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
756 //
757 // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
758 //
759 if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
760 return EFI_UNSUPPORTED;
761 }
762 BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
763
764 IsAllocated = FALSE;
765 if (*GopBlt == NULL) {
766 //
767 // GopBlt is not allocated by caller.
768 //
769 *GopBltSize = (UINTN) BltBufferSize;
770 *GopBlt = AllocatePool (*GopBltSize);
771 IsAllocated = TRUE;
772 if (*GopBlt == NULL) {
773 return EFI_OUT_OF_RESOURCES;
774 }
775 } else {
776 //
777 // GopBlt has been allocated by caller.
778 //
779 if (*GopBltSize < (UINTN) BltBufferSize) {
780 *GopBltSize = (UINTN) BltBufferSize;
781 return EFI_BUFFER_TOO_SMALL;
782 }
783 }
784
785 *PixelWidth = BmpHeader->PixelWidth;
786 *PixelHeight = BmpHeader->PixelHeight;
787
788 //
789 // Convert image from BMP to Blt buffer format
790 //
791 BltBuffer = *GopBlt;
792 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
793 Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
794 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
795 switch (BmpHeader->BitPerPixel) {
796 case 1:
797 //
798 // Convert 1-bit (2 colors) BMP to 24-bit color
799 //
800 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
801 Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
802 Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
803 Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
804 Blt++;
805 Width++;
806 }
807
808 Blt--;
809 Width--;
810 break;
811
812 case 4:
813 //
814 // Convert 4-bit (16 colors) BMP Palette to 24-bit color
815 //
816 Index = (*Image) >> 4;
817 Blt->Red = BmpColorMap[Index].Red;
818 Blt->Green = BmpColorMap[Index].Green;
819 Blt->Blue = BmpColorMap[Index].Blue;
820 if (Width < (BmpHeader->PixelWidth - 1)) {
821 Blt++;
822 Width++;
823 Index = (*Image) & 0x0f;
824 Blt->Red = BmpColorMap[Index].Red;
825 Blt->Green = BmpColorMap[Index].Green;
826 Blt->Blue = BmpColorMap[Index].Blue;
827 }
828 break;
829
830 case 8:
831 //
832 // Convert 8-bit (256 colors) BMP Palette to 24-bit color
833 //
834 Blt->Red = BmpColorMap[*Image].Red;
835 Blt->Green = BmpColorMap[*Image].Green;
836 Blt->Blue = BmpColorMap[*Image].Blue;
837 break;
838
839 case 24:
840 //
841 // It is 24-bit BMP.
842 //
843 Blt->Blue = *Image++;
844 Blt->Green = *Image++;
845 Blt->Red = *Image;
846 break;
847
848 default:
849 //
850 // Other bit format BMP is not supported.
851 //
852 if (IsAllocated) {
853 FreePool (*GopBlt);
854 *GopBlt = NULL;
855 }
856 return EFI_UNSUPPORTED;
857 break;
858 };
859
860 }
861
862 ImageIndex = (UINTN) (Image - ImageHeader);
863 if ((ImageIndex % 4) != 0) {
864 //
865 // Bmp Image starts each row on a 32-bit boundary!
866 //
867 Image = Image + (4 - (ImageIndex % 4));
868 }
869 }
870
871 return EFI_SUCCESS;
872 }
873
874 /**
875 Use SystemTable Conout to stop video based Simple Text Out consoles from going
876 to the video device. Put up LogoFile on every video device that is a console.
877
878 @param[in] LogoFile File name of logo to display on the center of the screen.
879
880 @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
881 @retval EFI_UNSUPPORTED Logo not found
882
883 **/
884 EFI_STATUS
885 EFIAPI
886 EnableQuietBoot (
887 IN EFI_GUID *LogoFile
888 )
889 {
890 EFI_STATUS Status;
891 EFI_OEM_BADGING_PROTOCOL *Badging;
892 UINT32 SizeOfX;
893 UINT32 SizeOfY;
894 INTN DestX;
895 INTN DestY;
896 UINT8 *ImageData;
897 UINTN ImageSize;
898 UINTN BltSize;
899 UINT32 Instance;
900 EFI_BADGING_FORMAT Format;
901 EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
902 UINTN CoordinateX;
903 UINTN CoordinateY;
904 UINTN Height;
905 UINTN Width;
906 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
907 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
908 UINT32 ColorDepth;
909 UINT32 RefreshRate;
910 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
911 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
912 UINTN NumberOfLogos;
913 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
914 UINTN LogoDestX;
915 UINTN LogoDestY;
916 UINTN LogoHeight;
917 UINTN LogoWidth;
918 UINTN NewDestX;
919 UINTN NewDestY;
920 UINTN NewHeight;
921 UINTN NewWidth;
922 UINT64 BufferSize;
923
924 UgaDraw = NULL;
925 //
926 // Try to open GOP first
927 //
928 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
929 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
930 GraphicsOutput = NULL;
931 //
932 // Open GOP failed, try to open UGA
933 //
934 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
935 }
936 if (EFI_ERROR (Status)) {
937 return EFI_UNSUPPORTED;
938 }
939
940 //
941 // Try to open Boot Logo Protocol.
942 //
943 BootLogo = NULL;
944 gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
945
946 //
947 // Erase Cursor from screen
948 //
949 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
950
951 Badging = NULL;
952 Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
953
954 if (GraphicsOutput != NULL) {
955 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
956 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
957
958 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
959 Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
960 if (EFI_ERROR (Status)) {
961 return EFI_UNSUPPORTED;
962 }
963 } else {
964 return EFI_UNSUPPORTED;
965 }
966
967 Blt = NULL;
968 NumberOfLogos = 0;
969 LogoDestX = 0;
970 LogoDestY = 0;
971 LogoHeight = 0;
972 LogoWidth = 0;
973 NewDestX = 0;
974 NewDestY = 0;
975 NewHeight = 0;
976 NewWidth = 0;
977 Instance = 0;
978 while (1) {
979 ImageData = NULL;
980 ImageSize = 0;
981
982 if (Badging != NULL) {
983 //
984 // Get image from OEMBadging protocol.
985 //
986 Status = Badging->GetImage (
987 Badging,
988 &Instance,
989 &Format,
990 &ImageData,
991 &ImageSize,
992 &Attribute,
993 &CoordinateX,
994 &CoordinateY
995 );
996 if (EFI_ERROR (Status)) {
997 goto Done;
998 }
999
1000 //
1001 // Currently only support BMP format.
1002 //
1003 if (Format != EfiBadgingFormatBMP) {
1004 if (ImageData != NULL) {
1005 FreePool (ImageData);
1006 }
1007 continue;
1008 }
1009 } else {
1010 //
1011 // Get the specified image from FV.
1012 //
1013 Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
1014 if (EFI_ERROR (Status)) {
1015 return EFI_UNSUPPORTED;
1016 }
1017
1018 CoordinateX = 0;
1019 CoordinateY = 0;
1020 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
1021 Attribute = EfiBadgingDisplayAttributeCenter;
1022 } else {
1023 Attribute = EfiBadgingDisplayAttributeCustomized;
1024 }
1025 }
1026
1027 if (Blt != NULL) {
1028 FreePool (Blt);
1029 }
1030 Blt = NULL;
1031 Status = ConvertBmpToGopBlt (
1032 ImageData,
1033 ImageSize,
1034 (VOID **) &Blt,
1035 &BltSize,
1036 &Height,
1037 &Width
1038 );
1039 if (EFI_ERROR (Status)) {
1040 FreePool (ImageData);
1041
1042 if (Badging == NULL) {
1043 return Status;
1044 } else {
1045 continue;
1046 }
1047 }
1048
1049 //
1050 // Calculate the display position according to Attribute.
1051 //
1052 switch (Attribute) {
1053 case EfiBadgingDisplayAttributeLeftTop:
1054 DestX = CoordinateX;
1055 DestY = CoordinateY;
1056 break;
1057
1058 case EfiBadgingDisplayAttributeCenterTop:
1059 DestX = (SizeOfX - Width) / 2;
1060 DestY = CoordinateY;
1061 break;
1062
1063 case EfiBadgingDisplayAttributeRightTop:
1064 DestX = (SizeOfX - Width - CoordinateX);
1065 DestY = CoordinateY;;
1066 break;
1067
1068 case EfiBadgingDisplayAttributeCenterRight:
1069 DestX = (SizeOfX - Width - CoordinateX);
1070 DestY = (SizeOfY - Height) / 2;
1071 break;
1072
1073 case EfiBadgingDisplayAttributeRightBottom:
1074 DestX = (SizeOfX - Width - CoordinateX);
1075 DestY = (SizeOfY - Height - CoordinateY);
1076 break;
1077
1078 case EfiBadgingDisplayAttributeCenterBottom:
1079 DestX = (SizeOfX - Width) / 2;
1080 DestY = (SizeOfY - Height - CoordinateY);
1081 break;
1082
1083 case EfiBadgingDisplayAttributeLeftBottom:
1084 DestX = CoordinateX;
1085 DestY = (SizeOfY - Height - CoordinateY);
1086 break;
1087
1088 case EfiBadgingDisplayAttributeCenterLeft:
1089 DestX = CoordinateX;
1090 DestY = (SizeOfY - Height) / 2;
1091 break;
1092
1093 case EfiBadgingDisplayAttributeCenter:
1094 DestX = (SizeOfX - Width) / 2;
1095 DestY = (SizeOfY - Height) / 2;
1096 break;
1097
1098 case EfiBadgingDisplayAttributeCustomized:
1099 DestX = (SizeOfX - Width) / 2;
1100 DestY = ((SizeOfY * 382) / 1000) - Height / 2;
1101 break;
1102
1103 default:
1104 DestX = CoordinateX;
1105 DestY = CoordinateY;
1106 break;
1107 }
1108
1109 if ((DestX >= 0) && (DestY >= 0)) {
1110 if (GraphicsOutput != NULL) {
1111 Status = GraphicsOutput->Blt (
1112 GraphicsOutput,
1113 Blt,
1114 EfiBltBufferToVideo,
1115 0,
1116 0,
1117 (UINTN) DestX,
1118 (UINTN) DestY,
1119 Width,
1120 Height,
1121 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1122 );
1123 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1124 Status = UgaDraw->Blt (
1125 UgaDraw,
1126 (EFI_UGA_PIXEL *) Blt,
1127 EfiUgaBltBufferToVideo,
1128 0,
1129 0,
1130 (UINTN) DestX,
1131 (UINTN) DestY,
1132 Width,
1133 Height,
1134 Width * sizeof (EFI_UGA_PIXEL)
1135 );
1136 } else {
1137 Status = EFI_UNSUPPORTED;
1138 }
1139
1140 //
1141 // Report displayed Logo information.
1142 //
1143 if (!EFI_ERROR (Status)) {
1144 NumberOfLogos++;
1145
1146 if (LogoWidth == 0) {
1147 //
1148 // The first Logo.
1149 //
1150 LogoDestX = (UINTN) DestX;
1151 LogoDestY = (UINTN) DestY;
1152 LogoWidth = Width;
1153 LogoHeight = Height;
1154 } else {
1155 //
1156 // Merge new logo with old one.
1157 //
1158 NewDestX = MIN ((UINTN) DestX, LogoDestX);
1159 NewDestY = MIN ((UINTN) DestY, LogoDestY);
1160 NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
1161 NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
1162
1163 LogoDestX = NewDestX;
1164 LogoDestY = NewDestY;
1165 LogoWidth = NewWidth;
1166 LogoHeight = NewHeight;
1167 }
1168 }
1169 }
1170
1171 FreePool (ImageData);
1172
1173 if (Badging == NULL) {
1174 break;
1175 }
1176 }
1177
1178 Done:
1179 if (BootLogo == NULL || NumberOfLogos == 0) {
1180 //
1181 // No logo displayed.
1182 //
1183 if (Blt != NULL) {
1184 FreePool (Blt);
1185 }
1186
1187 return Status;
1188 }
1189
1190 //
1191 // Advertise displayed Logo information.
1192 //
1193 if (NumberOfLogos == 1) {
1194 //
1195 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
1196 //
1197 LogoBlt = Blt;
1198 Status = EFI_SUCCESS;
1199 } else {
1200 //
1201 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
1202 //
1203 if (Blt != NULL) {
1204 FreePool (Blt);
1205 }
1206
1207 //
1208 // Ensure the LogoHeight * LogoWidth doesn't overflow
1209 //
1210 if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
1211 return EFI_UNSUPPORTED;
1212 }
1213 BufferSize = MultU64x64 (LogoWidth, LogoHeight);
1214
1215 //
1216 // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
1217 //
1218 if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
1219 return EFI_UNSUPPORTED;
1220 }
1221
1222 LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1223 if (LogoBlt == NULL) {
1224 return EFI_OUT_OF_RESOURCES;
1225 }
1226
1227 if (GraphicsOutput != NULL) {
1228 Status = GraphicsOutput->Blt (
1229 GraphicsOutput,
1230 LogoBlt,
1231 EfiBltVideoToBltBuffer,
1232 LogoDestX,
1233 LogoDestY,
1234 0,
1235 0,
1236 LogoWidth,
1237 LogoHeight,
1238 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1239 );
1240 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1241 Status = UgaDraw->Blt (
1242 UgaDraw,
1243 (EFI_UGA_PIXEL *) LogoBlt,
1244 EfiUgaVideoToBltBuffer,
1245 LogoDestX,
1246 LogoDestY,
1247 0,
1248 0,
1249 LogoWidth,
1250 LogoHeight,
1251 LogoWidth * sizeof (EFI_UGA_PIXEL)
1252 );
1253 } else {
1254 Status = EFI_UNSUPPORTED;
1255 }
1256 }
1257
1258 if (!EFI_ERROR (Status)) {
1259 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
1260 }
1261 FreePool (LogoBlt);
1262
1263 return Status;
1264 }
1265
1266 /**
1267 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
1268 Simple Text Out screens will now be synced up with all non video output devices
1269
1270 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
1271
1272 **/
1273 EFI_STATUS
1274 EFIAPI
1275 DisableQuietBoot (
1276 VOID
1277 )
1278 {
1279
1280 //
1281 // Enable Cursor on Screen
1282 //
1283 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1284 return EFI_SUCCESS;
1285 }
1286