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