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