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