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
24 #include "BootMaint.h"
26 EFI_DEVICE_PATH_PROTOCOL
*
27 DevicePathInstanceDup (
28 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
32 UpdateComAttributeFromVariable (
33 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
37 ChangeTerminalDevicePath (
38 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
39 BOOLEAN ChangeTerminal
42 EFI_DEVICE_PATH_PROTOCOL
*Node
;
43 EFI_DEVICE_PATH_PROTOCOL
*Node1
;
44 ACPI_HID_DEVICE_PATH
*Acpi
;
45 UART_DEVICE_PATH
*Uart
;
46 UART_DEVICE_PATH
*Uart1
;
49 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
50 BM_MENU_ENTRY
*NewMenuEntry
;
52 Match
= EISA_PNP_ID (0x0501);
54 Node
= NextDevicePathNode (Node
);
56 while (!IsDevicePathEnd (Node
)) {
57 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
58 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
59 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
60 CopyMem (&Com
, &Acpi
->UID
, sizeof (UINT32
));
64 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, Com
);
65 if (NULL
== NewMenuEntry
) {
69 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
70 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
71 Uart
= (UART_DEVICE_PATH
*) Node
;
74 &NewTerminalContext
->BaudRate
,
80 &NewTerminalContext
->DataBits
,
86 &NewTerminalContext
->Parity
,
92 &NewTerminalContext
->StopBits
,
96 // Change the device path in the ComPort
99 Node1
= NewTerminalContext
->DevicePath
;
100 Node1
= NextDevicePathNode (Node1
);
101 while (!IsDevicePathEnd (Node1
)) {
102 if ((DevicePathType (Node1
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node1
) == MSG_UART_DP
)) {
103 Uart1
= (UART_DEVICE_PATH
*) Node1
;
106 &NewTerminalContext
->BaudRate
,
112 &NewTerminalContext
->DataBits
,
118 &NewTerminalContext
->Parity
,
124 &NewTerminalContext
->StopBits
,
132 Node1
= NextDevicePathNode (Node1
);
141 Node
= NextDevicePathNode (Node
);
149 ChangeVariableDevicePath (
150 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
153 EFI_DEVICE_PATH_PROTOCOL
*Node
;
154 ACPI_HID_DEVICE_PATH
*Acpi
;
155 UART_DEVICE_PATH
*Uart
;
158 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
159 BM_MENU_ENTRY
*NewMenuEntry
;
161 Match
= EISA_PNP_ID (0x0501);
163 Node
= NextDevicePathNode (Node
);
165 while (!IsDevicePathEnd (Node
)) {
166 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
167 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
168 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
169 CopyMem (&Com
, &Acpi
->UID
, sizeof (UINT32
));
173 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
174 NewMenuEntry
= BOpt_GetMenuEntry (
178 ASSERT (NewMenuEntry
!= NULL
);
179 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
180 Uart
= (UART_DEVICE_PATH
*) Node
;
183 &NewTerminalContext
->BaudRate
,
189 &NewTerminalContext
->DataBits
,
195 &NewTerminalContext
->Parity
,
201 &NewTerminalContext
->StopBits
,
206 Node
= NextDevicePathNode (Node
);
213 IsTerminalDevicePath (
214 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
215 OUT TYPE_OF_TERMINAL
*Termi
,
226 Build a list containing all serial devices
240 ACPI_HID_DEVICE_PATH
*Acpi
;
241 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
243 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
244 EFI_DEVICE_PATH_PROTOCOL
*OutDevicePath
;
245 EFI_DEVICE_PATH_PROTOCOL
*InpDevicePath
;
246 EFI_DEVICE_PATH_PROTOCOL
*ErrDevicePath
;
247 BM_MENU_ENTRY
*NewMenuEntry
;
248 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
249 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
250 VENDOR_DEVICE_PATH Vendor
;
252 // Get all handles that have SerialIo protocol installed
254 InitializeListHead (&TerminalMenu
.Head
);
255 TerminalMenu
.MenuNumber
= 0;
256 Status
= gBS
->LocateHandleBuffer (
258 &gEfiSerialIoProtocolGuid
,
263 if (EFI_ERROR (Status
)) {
265 // No serial ports present
267 return EFI_UNSUPPORTED
;
270 for (Index
= 0; Index
< NoHandles
; Index
++) {
272 // Check to see whether the handle has DevicePath Protocol installed
274 gBS
->HandleProtocol (
276 &gEfiDevicePathProtocolGuid
,
279 Ptr
= (UINT8
*) DevicePath
;
280 while (*Ptr
!= END_DEVICE_PATH_TYPE
) {
284 Ptr
= Ptr
- sizeof (UART_DEVICE_PATH
) - sizeof (ACPI_HID_DEVICE_PATH
);
285 Acpi
= (ACPI_HID_DEVICE_PATH
*) Ptr
;
286 Match
= EISA_PNP_ID (0x0501);
288 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
289 NewMenuEntry
= BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT
);
291 return EFI_OUT_OF_RESOURCES
;
294 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
295 CopyMem (&NewMenuEntry
->OptionNumber
, &Acpi
->UID
, sizeof (UINT32
));
296 NewTerminalContext
->DevicePath
= DevicePathInstanceDup (DevicePath
);
298 // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
299 // coz' the misc data for each platform is not correct, actually it's the device path stored in
300 // datahub which is not completed, so a searching for end of device path will enter a
303 NewMenuEntry
->DisplayString
= EfiLibStrFromDatahub (DevicePath
);
304 if (NULL
== NewMenuEntry
->DisplayString
) {
305 NewMenuEntry
->DisplayString
= DevicePathToStr (DevicePath
);
308 NewMenuEntry
->HelpString
= NULL
;
310 gBS
->HandleProtocol (
312 &gEfiSerialIoProtocolGuid
,
317 &NewTerminalContext
->BaudRate
,
318 &SerialIo
->Mode
->BaudRate
,
323 &NewTerminalContext
->DataBits
,
324 &SerialIo
->Mode
->DataBits
,
329 &NewTerminalContext
->Parity
,
330 &SerialIo
->Mode
->Parity
,
335 &NewTerminalContext
->StopBits
,
336 &SerialIo
->Mode
->StopBits
,
339 InsertTailList (&TerminalMenu
.Head
, &NewMenuEntry
->Link
);
340 TerminalMenu
.MenuNumber
++;
344 // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
346 OutDevicePath
= EfiLibGetVariable (L
"ConOut", &gEfiGlobalVariableGuid
);
347 InpDevicePath
= EfiLibGetVariable (L
"ConIn", &gEfiGlobalVariableGuid
);
348 ErrDevicePath
= EfiLibGetVariable (L
"ErrOut", &gEfiGlobalVariableGuid
);
350 UpdateComAttributeFromVariable (OutDevicePath
);
354 UpdateComAttributeFromVariable (InpDevicePath
);
358 UpdateComAttributeFromVariable (ErrDevicePath
);
361 for (Index
= 0; Index
< TerminalMenu
.MenuNumber
; Index
++) {
362 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, Index
);
363 if (NULL
== NewMenuEntry
) {
364 return EFI_NOT_FOUND
;
367 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
369 NewTerminalContext
->TerminalType
= 0;
370 NewTerminalContext
->IsConIn
= FALSE
;
371 NewTerminalContext
->IsConOut
= FALSE
;
372 NewTerminalContext
->IsStdErr
= FALSE
;
374 Vendor
.Header
.Type
= MESSAGING_DEVICE_PATH
;
375 Vendor
.Header
.SubType
= MSG_VENDOR_DP
;
377 for (Index2
= 0; Index2
< 4; Index2
++) {
378 CopyMem (&Vendor
.Guid
, &Guid
[Index2
], sizeof (EFI_GUID
));
379 SetDevicePathNodeLength (&Vendor
.Header
, sizeof (VENDOR_DEVICE_PATH
));
380 NewDevicePath
= AppendDevicePathNode (
381 NewTerminalContext
->DevicePath
,
382 (EFI_DEVICE_PATH_PROTOCOL
*) &Vendor
384 SafeFreePool (NewMenuEntry
->HelpString
);
386 // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
387 // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
389 NewMenuEntry
->HelpString
= NULL
;
391 if (BdsLibMatchDevicePaths (OutDevicePath
, NewDevicePath
)) {
392 NewTerminalContext
->IsConOut
= TRUE
;
393 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
396 if (BdsLibMatchDevicePaths (InpDevicePath
, NewDevicePath
)) {
397 NewTerminalContext
->IsConIn
= TRUE
;
398 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
401 if (BdsLibMatchDevicePaths (ErrDevicePath
, NewDevicePath
)) {
402 NewTerminalContext
->IsStdErr
= TRUE
;
403 NewTerminalContext
->TerminalType
= (UINT8
) Index2
;
412 UpdateComAttributeFromVariable (
413 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
418 Update Com Ports attributes from DevicePath
421 DevicePath - DevicePath that contains Com ports
427 EFI_DEVICE_PATH_PROTOCOL
*Node
;
428 EFI_DEVICE_PATH_PROTOCOL
*SerialNode
;
429 ACPI_HID_DEVICE_PATH
*Acpi
;
430 UART_DEVICE_PATH
*Uart
;
431 UART_DEVICE_PATH
*Uart1
;
433 UINTN TerminalNumber
;
434 BM_MENU_ENTRY
*NewMenuEntry
;
435 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
438 Match
= EISA_PNP_ID (0x0501);
440 Node
= NextDevicePathNode (Node
);
442 for (Index
= 0; Index
< TerminalMenu
.MenuNumber
; Index
++) {
443 while (!IsDevicePathEnd (Node
)) {
444 if ((DevicePathType (Node
) == ACPI_DEVICE_PATH
) && (DevicePathSubType (Node
) == ACPI_DP
)) {
445 Acpi
= (ACPI_HID_DEVICE_PATH
*) Node
;
446 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
447 CopyMem (&TerminalNumber
, &Acpi
->UID
, sizeof (UINT32
));
451 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (Node
) == MSG_UART_DP
)) {
452 Uart
= (UART_DEVICE_PATH
*) Node
;
453 NewMenuEntry
= BOpt_GetMenuEntry (&TerminalMenu
, TerminalNumber
);
454 if (NULL
== NewMenuEntry
) {
455 return EFI_NOT_FOUND
;
458 NewTerminalContext
= (BM_TERMINAL_CONTEXT
*) NewMenuEntry
->VariableContext
;
460 &NewTerminalContext
->BaudRate
,
466 &NewTerminalContext
->DataBits
,
472 &NewTerminalContext
->Parity
,
478 &NewTerminalContext
->StopBits
,
483 SerialNode
= NewTerminalContext
->DevicePath
;
484 SerialNode
= NextDevicePathNode (SerialNode
);
485 while (!IsDevicePathEnd (SerialNode
)) {
486 if ((DevicePathType (SerialNode
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (SerialNode
) == MSG_UART_DP
)) {
488 // Update following device paths according to
489 // previous acquired uart attributes
491 Uart1
= (UART_DEVICE_PATH
*) SerialNode
;
494 &NewTerminalContext
->BaudRate
,
500 &NewTerminalContext
->DataBits
,
505 &NewTerminalContext
->Parity
,
510 &NewTerminalContext
->StopBits
,
517 SerialNode
= NextDevicePathNode (SerialNode
);
524 Node
= NextDevicePathNode (Node
);
534 EFI_DEVICE_PATH_PROTOCOL
*
535 DevicePathInstanceDup (
536 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
541 Function creates a device path data structure that identically matches the
542 device path passed in.
545 DevPath - A pointer to a device path data structure.
549 The new copy of DevPath is created to identically match the input.
550 Otherwise, NULL is returned.
554 EFI_DEVICE_PATH_PROTOCOL
*NewDevPath
;
555 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
556 EFI_DEVICE_PATH_PROTOCOL
*Temp
;
561 // get the size of an instance from the input
564 DevicePathInst
= GetNextDevicePathInstance (&Temp
, &Size
);
567 // Make a copy and set proper end type
571 NewDevPath
= AllocateZeroPool (Size
);
572 ASSERT (NewDevPath
!= NULL
);
576 CopyMem (NewDevPath
, DevicePathInst
, Size
);
577 Ptr
= (UINT8
*) NewDevPath
;
578 Ptr
+= Size
- sizeof (EFI_DEVICE_PATH_PROTOCOL
);
579 Temp
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
580 SetDevicePathEndNode (Temp
);
588 IN UINTN ConsoleMenuType
591 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
592 EFI_DEVICE_PATH_PROTOCOL
*AllDevicePath
;
593 EFI_DEVICE_PATH_PROTOCOL
*MultiDevicePath
;
594 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
599 BM_MENU_ENTRY
*NewMenuEntry
;
600 BM_CONSOLE_CONTEXT
*NewConsoleContext
;
601 BM_TERMINAL_CONTEXT
*NewTerminalContext
;
602 TYPE_OF_TERMINAL Terminal
;
603 BM_MENU_ENTRY
*NewTerminalMenuEntry
;
605 BM_MENU_OPTION
*ConsoleMenu
;
608 AllDevicePath
= NULL
;
610 switch (ConsoleMenuType
) {
611 case BM_CONSOLE_IN_CONTEXT_SELECT
:
612 ConsoleMenu
= &ConsoleInpMenu
;
613 DevicePath
= EfiLibGetVariable (
615 &gEfiGlobalVariableGuid
618 AllDevicePath
= EfiLibGetVariable (
620 &gEfiGlobalVariableGuid
624 case BM_CONSOLE_OUT_CONTEXT_SELECT
:
625 ConsoleMenu
= &ConsoleOutMenu
;
626 DevicePath
= EfiLibGetVariable (
628 &gEfiGlobalVariableGuid
631 AllDevicePath
= EfiLibGetVariable (
633 &gEfiGlobalVariableGuid
637 case BM_CONSOLE_ERR_CONTEXT_SELECT
:
638 ConsoleMenu
= &ConsoleErrMenu
;
639 DevicePath
= EfiLibGetVariable (
641 &gEfiGlobalVariableGuid
644 AllDevicePath
= EfiLibGetVariable (
646 &gEfiGlobalVariableGuid
651 return EFI_UNSUPPORTED
;
654 if (NULL
== AllDevicePath
) {
655 return EFI_NOT_FOUND
;
658 InitializeListHead (&ConsoleMenu
->Head
);
660 AllCount
= EfiDevicePathInstanceCount (AllDevicePath
);
661 ConsoleMenu
->MenuNumber
= 0;
663 // Following is menu building up for Console Out Devices
665 MultiDevicePath
= AllDevicePath
;
667 for (Index
= 0; Index
< AllCount
; Index
++) {
668 DevicePathInst
= GetNextDevicePathInstance (&MultiDevicePath
, &Size
);
670 NewMenuEntry
= BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT
);
671 if (NULL
== NewMenuEntry
) {
672 return EFI_OUT_OF_RESOURCES
;
675 NewConsoleContext
= (BM_CONSOLE_CONTEXT
*) NewMenuEntry
->VariableContext
;
676 NewMenuEntry
->OptionNumber
= Index2
;
678 NewConsoleContext
->DevicePath
= DevicePathInstanceDup (DevicePathInst
);
679 NewMenuEntry
->DisplayString
= EfiLibStrFromDatahub (NewConsoleContext
->DevicePath
);
680 if (NULL
== NewMenuEntry
->DisplayString
) {
681 NewMenuEntry
->DisplayString
= DevicePathToStr (NewConsoleContext
->DevicePath
);
684 NewConsoleContext
->IsTerminal
= IsTerminalDevicePath (
685 NewConsoleContext
->DevicePath
,
690 NewConsoleContext
->IsActive
= BdsLibMatchDevicePaths (
692 NewConsoleContext
->DevicePath
694 NewTerminalMenuEntry
= NULL
;
695 NewTerminalContext
= NULL
;
697 if (NewConsoleContext
->IsTerminal
) {
698 BOpt_DestroyMenuEntry (NewMenuEntry
);
701 ConsoleMenu
->MenuNumber
++;
702 InsertTailList (&ConsoleMenu
->Head
, &NewMenuEntry
->Link
);
716 Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
726 GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT
);
727 GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT
);
728 GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT
);
739 Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
749 BOpt_FreeMenu (&ConsoleOutMenu
);
750 BOpt_FreeMenu (&ConsoleInpMenu
);
751 BOpt_FreeMenu (&ConsoleErrMenu
);
752 BOpt_FreeMenu (&TerminalMenu
);
757 IsTerminalDevicePath (
758 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
759 OUT TYPE_OF_TERMINAL
*Termi
,
765 Test whether DevicePath is a valid Terminal
768 DevicePath - DevicePath to be checked
769 Termi - If is terminal, give its type
770 Com - If is Com Port, give its type
773 TRUE - If DevicePath point to a Terminal
780 VENDOR_DEVICE_PATH
*Vendor
;
781 ACPI_HID_DEVICE_PATH
*Acpi
;
788 // Parse the Device Path, should be change later!!!
790 Ptr
= (UINT8
*) DevicePath
;
791 while (*Ptr
!= END_DEVICE_PATH_TYPE
) {
795 Ptr
= Ptr
- sizeof (VENDOR_DEVICE_PATH
);
796 Vendor
= (VENDOR_DEVICE_PATH
*) Ptr
;
799 // There are four kinds of Terminal types
800 // check to see whether this devicepath
801 // is one of that type
803 CopyMem (&TempGuid
, &Vendor
->Guid
, sizeof (EFI_GUID
));
805 if (CompareGuid (&TempGuid
, &Guid
[0])) {
809 if (CompareGuid (&TempGuid
, &Guid
[1])) {
813 if (CompareGuid (&TempGuid
, &Guid
[2])) {
814 *Termi
= VT_100_PLUS
;
817 if (CompareGuid (&TempGuid
, &Guid
[3])) {
831 Ptr
= Ptr
- sizeof (UART_DEVICE_PATH
) - sizeof (ACPI_HID_DEVICE_PATH
);
832 Acpi
= (ACPI_HID_DEVICE_PATH
*) Ptr
;
833 Match
= EISA_PNP_ID (0x0501);
834 if (CompareMem (&Acpi
->HID
, &Match
, sizeof (UINT32
)) == 0) {
835 CopyMem (Com
, &Acpi
->UID
, sizeof (UINT32
));