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