2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 handles console redirection from boot manager
25 // Include common header file for this module.
27 #include "CommonHeader.h"
29 #include "BootMaint.h"
31 EFI_DEVICE_PATH_PROTOCOL
*
32 DevicePathInstanceDup (
33 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
37 UpdateComAttributeFromVariable (
38 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
42 ChangeTerminalDevicePath (
43 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
44 BOOLEAN ChangeTerminal
47 EFI_DEVICE_PATH_PROTOCOL
*Node
;
48 EFI_DEVICE_PATH_PROTOCOL
*Node1
;
49 ACPI_HID_DEVICE_PATH
*Acpi
;
50 UART_DEVICE_PATH
*Uart
;
51 UART_DEVICE_PATH
*Uart1
;
54 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
55 BM_MENU_ENTRY
*NewMenuEntry
;
57 Match
= EISA_PNP_ID (0x0501);
59 Node
= NextDevicePathNode (Node
);
61 while (!IsDevicePathEnd (Node
)) {
62 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
63 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
64 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
65 CopyMem (&Com
, &Acpi
->UID
, sizeof (UINT32
));
69 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, Com
);
70 if (NULL
== NewMenuEntry
) {
74 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
75 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
76 Uart
= (UART_DEVICE_PATH
*) Node
;
79 &NewTerminalContext
->BaudRate
,
85 &NewTerminalContext
->DataBits
,
91 &NewTerminalContext
->Parity
,
97 &NewTerminalContext
->StopBits
,
101 // Change the device path in the ComPort
103 if (ChangeTerminal
) {
104 Node1
= NewTerminalContext
->DevicePath
;
105 Node1
= NextDevicePathNode (Node1
);
106 while (!IsDevicePathEnd (Node1
)) {
107 if ((DevicePathType (Node1
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node1
) == MSG_UART_DP
)) {
108 Uart1
= (UART_DEVICE_PATH
*) Node1
;
111 &NewTerminalContext
->BaudRate
,
117 &NewTerminalContext
->DataBits
,
123 &NewTerminalContext
->Parity
,
129 &NewTerminalContext
->StopBits
,
137 Node1
= NextDevicePathNode (Node1
);
146 Node
= NextDevicePathNode (Node
);
154 ChangeVariableDevicePath (
155 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
158 EFI_DEVICE_PATH_PROTOCOL
*Node
;
159 ACPI_HID_DEVICE_PATH
*Acpi
;
160 UART_DEVICE_PATH
*Uart
;
163 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
164 BM_MENU_ENTRY
*NewMenuEntry
;
166 Match
= EISA_PNP_ID (0x0501);
168 Node
= NextDevicePathNode (Node
);
170 while (!IsDevicePathEnd (Node
)) {
171 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
172 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
173 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
174 CopyMem (&Com
, &Acpi
->UID
, sizeof (UINT32
));
178 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
179 NewMenuEntry
= BOpt_GetMenuEntry (
183 ASSERT (NewMenuEntry
!= NULL
);
184 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
185 Uart
= (UART_DEVICE_PATH
*) Node
;
188 &NewTerminalContext
->BaudRate
,
194 &NewTerminalContext
->DataBits
,
200 &NewTerminalContext
->Parity
,
206 &NewTerminalContext
->StopBits
,
211 Node
= NextDevicePathNode (Node
);
218 IsTerminalDevicePath (
219 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
220 OUT TYPE_OF_TERMINAL
*Termi
,
231 Build a list containing all serial devices
245 ACPI_HID_DEVICE_PATH
*Acpi
;
246 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
248 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
249 EFI_DEVICE_PATH_PROTOCOL
*OutDevicePath
;
250 EFI_DEVICE_PATH_PROTOCOL
*InpDevicePath
;
251 EFI_DEVICE_PATH_PROTOCOL
*ErrDevicePath
;
252 BM_MENU_ENTRY
*NewMenuEntry
;
253 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
254 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
255 VENDOR_DEVICE_PATH Vendor
;
257 // Get all handles that have SerialIo protocol installed
259 InitializeListHead (&TerminalMenu
.Head
);
260 TerminalMenu
.MenuNumber
= 0;
261 Status
= gBS
->LocateHandleBuffer (
263 &gEfiSerialIoProtocolGuid
,
268 if (EFI_ERROR (Status
)) {
270 // No serial ports present
272 return EFI_UNSUPPORTED
;
275 for (Index
= 0; Index
< NoHandles
; Index
++) {
277 // Check to see whether the handle has DevicePath Protocol installed
279 gBS
->HandleProtocol (
281 &gEfiDevicePathProtocolGuid
,
284 Ptr
= (UINT8
*) DevicePath
;
285 while (*Ptr
!= END_DEVICE_PATH_TYPE
) {
289 Ptr
= Ptr
- sizeof (UART_DEVICE_PATH
) - sizeof (ACPI_HID_DEVICE_PATH
);
290 Acpi
= (ACPI_HID_DEVICE_PATH
*) Ptr
;
291 Match
= EISA_PNP_ID (0x0501);
293 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
294 NewMenuEntry
= BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT
);
296 return EFI_OUT_OF_RESOURCES
;
299 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
300 CopyMem (&NewMenuEntry
->OptionNumber
, &Acpi
->UID
, sizeof (UINT32
));
301 NewTerminalContext
->DevicePath
= DevicePathInstanceDup (DevicePath
);
303 // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
304 // coz' the misc data for each platform is not correct, actually it's the device path stored in
305 // datahub which is not completed, so a searching for end of device path will enter a
308 NewMenuEntry
->DisplayString
= EfiLibStrFromDatahub (DevicePath
);
309 if (NULL
== NewMenuEntry
->DisplayString
) {
310 NewMenuEntry
->DisplayString
= DevicePathToStr (DevicePath
);
313 NewMenuEntry
->HelpString
= NULL
;
315 gBS
->HandleProtocol (
317 &gEfiSerialIoProtocolGuid
,
322 &NewTerminalContext
->BaudRate
,
323 &SerialIo
->Mode
->BaudRate
,
328 &NewTerminalContext
->DataBits
,
329 &SerialIo
->Mode
->DataBits
,
334 &NewTerminalContext
->Parity
,
335 &SerialIo
->Mode
->Parity
,
340 &NewTerminalContext
->StopBits
,
341 &SerialIo
->Mode
->StopBits
,
344 InsertTailList (&TerminalMenu
.Head
, &NewMenuEntry
->Link
);
345 TerminalMenu
.MenuNumber
++;
349 // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
351 OutDevicePath
= EfiLibGetVariable (L
"ConOut", &gEfiGlobalVariableGuid
);
352 InpDevicePath
= EfiLibGetVariable (L
"ConIn", &gEfiGlobalVariableGuid
);
353 ErrDevicePath
= EfiLibGetVariable (L
"ErrOut", &gEfiGlobalVariableGuid
);
355 UpdateComAttributeFromVariable (OutDevicePath
);
359 UpdateComAttributeFromVariable (InpDevicePath
);
363 UpdateComAttributeFromVariable (ErrDevicePath
);
366 for (Index
= 0; Index
< TerminalMenu
.MenuNumber
; Index
++) {
367 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, Index
);
368 if (NULL
== NewMenuEntry
) {
369 return EFI_NOT_FOUND
;
372 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
374 NewTerminalContext
->TerminalType
= 0;
375 NewTerminalContext
->IsConIn
= FALSE
;
376 NewTerminalContext
->IsConOut
= FALSE
;
377 NewTerminalContext
->IsStdErr
= FALSE
;
379 Vendor
.Header
.Type
= MESSAGING_DEVICE_PATH
;
380 Vendor
.Header
.SubType
= MSG_VENDOR_DP
;
382 for (Index2
= 0; Index2
< 4; Index2
++) {
383 CopyMem (&Vendor
.Guid
, &Guid
[Index2
], sizeof (EFI_GUID
));
384 SetDevicePathNodeLength (&Vendor
.Header
, sizeof (VENDOR_DEVICE_PATH
));
385 NewDevicePath
= AppendDevicePathNode (
386 NewTerminalContext
->DevicePath
,
387 (EFI_DEVICE_PATH_PROTOCOL
*) &Vendor
389 SafeFreePool (NewMenuEntry
->HelpString
);
391 // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
392 // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
394 NewMenuEntry
->HelpString
= NULL
;
396 if (BdsLibMatchDevicePaths (OutDevicePath
, NewDevicePath
)) {
397 NewTerminalContext
->IsConOut
= TRUE
;
398 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
401 if (BdsLibMatchDevicePaths (InpDevicePath
, NewDevicePath
)) {
402 NewTerminalContext
->IsConIn
= TRUE
;
403 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
406 if (BdsLibMatchDevicePaths (ErrDevicePath
, NewDevicePath
)) {
407 NewTerminalContext
->IsStdErr
= TRUE
;
408 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
417 UpdateComAttributeFromVariable (
418 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
423 Update Com Ports attributes from DevicePath
426 DevicePath - DevicePath that contains Com ports
432 EFI_DEVICE_PATH_PROTOCOL
*Node
;
433 EFI_DEVICE_PATH_PROTOCOL
*SerialNode
;
434 ACPI_HID_DEVICE_PATH
*Acpi
;
435 UART_DEVICE_PATH
*Uart
;
436 UART_DEVICE_PATH
*Uart1
;
438 UINTN TerminalNumber
;
439 BM_MENU_ENTRY
*NewMenuEntry
;
440 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
443 Match
= EISA_PNP_ID (0x0501);
445 Node
= NextDevicePathNode (Node
);
447 for (Index
= 0; Index
< TerminalMenu
.MenuNumber
; Index
++) {
448 while (!IsDevicePathEnd (Node
)) {
449 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
450 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
451 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
452 CopyMem (&TerminalNumber
, &Acpi
->UID
, sizeof (UINT32
));
456 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
457 Uart
= (UART_DEVICE_PATH
*) Node
;
458 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, TerminalNumber
);
459 if (NULL
== NewMenuEntry
) {
460 return EFI_NOT_FOUND
;
463 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
465 &NewTerminalContext
->BaudRate
,
471 &NewTerminalContext
->DataBits
,
477 &NewTerminalContext
->Parity
,
483 &NewTerminalContext
->StopBits
,
488 SerialNode
= NewTerminalContext
->DevicePath
;
489 SerialNode
= NextDevicePathNode (SerialNode
);
490 while (!IsDevicePathEnd (SerialNode
)) {
491 if ((DevicePathType (SerialNode
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (SerialNode
) == MSG_UART_DP
)) {
493 // Update following device paths according to
494 // previous acquired uart attributes
496 Uart1
= (UART_DEVICE_PATH
*) SerialNode
;
499 &NewTerminalContext
->BaudRate
,
505 &NewTerminalContext
->DataBits
,
510 &NewTerminalContext
->Parity
,
515 &NewTerminalContext
->StopBits
,
522 SerialNode
= NextDevicePathNode (SerialNode
);
529 Node
= NextDevicePathNode (Node
);
539 EFI_DEVICE_PATH_PROTOCOL
*
540 DevicePathInstanceDup (
541 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
546 Function creates a device path data structure that identically matches the
547 device path passed in.
550 DevPath - A pointer to a device path data structure.
554 The new copy of DevPath is created to identically match the input.
555 Otherwise, NULL is returned.
559 EFI_DEVICE_PATH_PROTOCOL
*NewDevPath
;
560 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
561 EFI_DEVICE_PATH_PROTOCOL
*Temp
;
566 // get the size of an instance from the input
569 DevicePathInst
= GetNextDevicePathInstance (&Temp
, &Size
);
572 // Make a copy and set proper end type
576 NewDevPath
= AllocateZeroPool (Size
);
577 ASSERT (NewDevPath
!= NULL
);
581 CopyMem (NewDevPath
, DevicePathInst
, Size
);
582 Ptr
= (UINT8
*) NewDevPath
;
583 Ptr
+= Size
- sizeof (EFI_DEVICE_PATH_PROTOCOL
);
584 Temp
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
585 SetDevicePathEndNode (Temp
);
593 IN UINTN ConsoleMenuType
596 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
597 EFI_DEVICE_PATH_PROTOCOL
*AllDevicePath
;
598 EFI_DEVICE_PATH_PROTOCOL
*MultiDevicePath
;
599 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
604 BM_MENU_ENTRY
*NewMenuEntry
;
605 BM_CONSOLE_CONTEXT
*NewConsoleContext
;
606 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
607 TYPE_OF_TERMINAL Terminal
;
608 BM_MENU_ENTRY
*NewTerminalMenuEntry
;
610 BM_MENU_OPTION
*ConsoleMenu
;
613 AllDevicePath
= NULL
;
615 switch (ConsoleMenuType
) {
616 case BM_CONSOLE_IN_CONTEXT_SELECT
:
617 ConsoleMenu
= &ConsoleInpMenu
;
618 DevicePath
= EfiLibGetVariable (
620 &gEfiGlobalVariableGuid
623 AllDevicePath
= EfiLibGetVariable (
625 &gEfiGlobalVariableGuid
629 case BM_CONSOLE_OUT_CONTEXT_SELECT
:
630 ConsoleMenu
= &ConsoleOutMenu
;
631 DevicePath
= EfiLibGetVariable (
633 &gEfiGlobalVariableGuid
636 AllDevicePath
= EfiLibGetVariable (
638 &gEfiGlobalVariableGuid
642 case BM_CONSOLE_ERR_CONTEXT_SELECT
:
643 ConsoleMenu
= &ConsoleErrMenu
;
644 DevicePath
= EfiLibGetVariable (
646 &gEfiGlobalVariableGuid
649 AllDevicePath
= EfiLibGetVariable (
651 &gEfiGlobalVariableGuid
656 return EFI_UNSUPPORTED
;
659 if (NULL
== AllDevicePath
) {
660 return EFI_NOT_FOUND
;
663 InitializeListHead (&ConsoleMenu
->Head
);
665 AllCount
= EfiDevicePathInstanceCount (AllDevicePath
);
666 ConsoleMenu
->MenuNumber
= 0;
668 // Following is menu building up for Console Out Devices
670 MultiDevicePath
= AllDevicePath
;
672 for (Index
= 0; Index
< AllCount
; Index
++) {
673 DevicePathInst
= GetNextDevicePathInstance (&MultiDevicePath
, &Size
);
675 NewMenuEntry
= BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT
);
676 if (NULL
== NewMenuEntry
) {
677 return EFI_OUT_OF_RESOURCES
;
680 NewConsoleContext
= (BM_CONSOLE_CONTEXT
*) NewMenuEntry
->VariableContext
;
681 NewMenuEntry
->OptionNumber
= Index2
;
683 NewConsoleContext
->DevicePath
= DevicePathInstanceDup (DevicePathInst
);
684 NewMenuEntry
->DisplayString
= EfiLibStrFromDatahub (NewConsoleContext
->DevicePath
);
685 if (NULL
== NewMenuEntry
->DisplayString
) {
686 NewMenuEntry
->DisplayString
= DevicePathToStr (NewConsoleContext
->DevicePath
);
689 NewConsoleContext
->IsTerminal
= IsTerminalDevicePath (
690 NewConsoleContext
->DevicePath
,
695 NewConsoleContext
->IsActive
= BdsLibMatchDevicePaths (
697 NewConsoleContext
->DevicePath
699 NewTerminalMenuEntry
= NULL
;
700 NewTerminalContext
= NULL
;
702 if (NewConsoleContext
->IsTerminal
) {
703 BOpt_DestroyMenuEntry (NewMenuEntry
);
706 ConsoleMenu
->MenuNumber
++;
707 InsertTailList (&ConsoleMenu
->Head
, &NewMenuEntry
->Link
);
721 Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
731 GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT
);
732 GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT
);
733 GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT
);
744 Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
754 BOpt_FreeMenu (&ConsoleOutMenu
);
755 BOpt_FreeMenu (&ConsoleInpMenu
);
756 BOpt_FreeMenu (&ConsoleErrMenu
);
757 BOpt_FreeMenu (&TerminalMenu
);
762 IsTerminalDevicePath (
763 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
764 OUT TYPE_OF_TERMINAL
*Termi
,
770 Test whether DevicePath is a valid Terminal
773 DevicePath - DevicePath to be checked
774 Termi - If is terminal, give its type
775 Com - If is Com Port, give its type
778 TRUE - If DevicePath point to a Terminal
785 VENDOR_DEVICE_PATH
*Vendor
;
786 ACPI_HID_DEVICE_PATH
*Acpi
;
793 // Parse the Device Path, should be change later!!!
795 Ptr
= (UINT8
*) DevicePath
;
796 while (*Ptr
!= END_DEVICE_PATH_TYPE
) {
800 Ptr
= Ptr
- sizeof (VENDOR_DEVICE_PATH
);
801 Vendor
= (VENDOR_DEVICE_PATH
*) Ptr
;
804 // There are four kinds of Terminal types
805 // check to see whether this devicepath
806 // is one of that type
808 CopyMem (&TempGuid
, &Vendor
->Guid
, sizeof (EFI_GUID
));
810 if (CompareGuid (&TempGuid
, &Guid
[0])) {
814 if (CompareGuid (&TempGuid
, &Guid
[1])) {
818 if (CompareGuid (&TempGuid
, &Guid
[2])) {
819 *Termi
= VT_100_PLUS
;
822 if (CompareGuid (&TempGuid
, &Guid
[3])) {
836 Ptr
= Ptr
- sizeof (UART_DEVICE_PATH
) - sizeof (ACPI_HID_DEVICE_PATH
);
837 Acpi
= (ACPI_HID_DEVICE_PATH
*) Ptr
;
838 Match
= EISA_PNP_ID (0x0501);
839 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
840 CopyMem (Com
, &Acpi
->UID
, sizeof (UINT32
));