--- /dev/null
+/** @file\r
+ handles console redirection from boot manager\r
+\r
+Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BootMaint.h"\r
+\r
+/**\r
+ Update Com Ports attributes from DevicePath\r
+\r
+ @param DevicePath DevicePath that contains Com ports\r
+\r
+ @retval EFI_SUCCESS The update is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateComAttributeFromVariable (\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Update the multi-instance device path of Terminal Device based on\r
+ the global TerminalMenu. If ChangeTernimal is TRUE, the terminal \r
+ device path in the Terminal Device in TerminalMenu is also updated.\r
+\r
+ @param DevicePath The multi-instance device path.\r
+ @param ChangeTerminal TRUE, then device path in the Terminal Device \r
+ in TerminalMenu is also updated; FALSE, no update.\r
+\r
+ @return EFI_SUCCESS The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ChangeTerminalDevicePath (\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN BOOLEAN ChangeTerminal\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ EFI_DEVICE_PATH_PROTOCOL *Node1;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_DEVICE_PATH *Uart1;\r
+ UINTN Com;\r
+ UINT32 Match;\r
+ BM_TERMINAL_CONTEXT *NewTerminalContext;\r
+ BM_MENU_ENTRY *NewMenuEntry;\r
+\r
+ Match = EISA_PNP_ID (0x0501);\r
+ Node = DevicePath;\r
+ Node = NextDevicePathNode (Node);\r
+ Com = 0;\r
+ while (!IsDevicePathEnd (Node)) {\r
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));\r
+ }\r
+ }\r
+\r
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);\r
+\r
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
+ Uart = (UART_DEVICE_PATH *) Node;\r
+ CopyMem (\r
+ &Uart->BaudRate,\r
+ &NewTerminalContext->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->DataBits,\r
+ &NewTerminalContext->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->Parity,\r
+ &NewTerminalContext->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->StopBits,\r
+ &NewTerminalContext->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+ //\r
+ // Change the device path in the ComPort\r
+ //\r
+ if (ChangeTerminal) {\r
+ Node1 = NewTerminalContext->DevicePath;\r
+ Node1 = NextDevicePathNode (Node1);\r
+ while (!IsDevicePathEnd (Node1)) {\r
+ if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {\r
+ Uart1 = (UART_DEVICE_PATH *) Node1;\r
+ CopyMem (\r
+ &Uart1->BaudRate,\r
+ &NewTerminalContext->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart1->DataBits,\r
+ &NewTerminalContext->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart1->Parity,\r
+ &NewTerminalContext->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart1->StopBits,\r
+ &NewTerminalContext->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+ break;\r
+ }\r
+ //\r
+ // end if\r
+ //\r
+ Node1 = NextDevicePathNode (Node1);\r
+ }\r
+ //\r
+ // end while\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ Node = NextDevicePathNode (Node);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ Update the device path that describing a terminal device\r
+ based on the new BaudRate, Data Bits, parity and Stop Bits\r
+ set.\r
+\r
+ @param DevicePath terminal device's path\r
+\r
+**/\r
+VOID\r
+ChangeVariableDevicePath (\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ UART_DEVICE_PATH *Uart;\r
+ UINTN Com;\r
+ UINT32 Match;\r
+ BM_TERMINAL_CONTEXT *NewTerminalContext;\r
+ BM_MENU_ENTRY *NewMenuEntry;\r
+\r
+ Match = EISA_PNP_ID (0x0501);\r
+ Node = DevicePath;\r
+ Node = NextDevicePathNode (Node);\r
+ Com = 0;\r
+ while (!IsDevicePathEnd (Node)) {\r
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));\r
+ }\r
+ }\r
+\r
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
+ NewMenuEntry = BOpt_GetMenuEntry (\r
+ &TerminalMenu,\r
+ Com\r
+ );\r
+ ASSERT (NewMenuEntry != NULL);\r
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
+ Uart = (UART_DEVICE_PATH *) Node;\r
+ CopyMem (\r
+ &Uart->BaudRate,\r
+ &NewTerminalContext->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->DataBits,\r
+ &NewTerminalContext->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->Parity,\r
+ &NewTerminalContext->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart->StopBits,\r
+ &NewTerminalContext->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+ }\r
+\r
+ Node = NextDevicePathNode (Node);\r
+ }\r
+}\r
+\r
+/**\r
+ Retrieve ACPI UID of UART from device path\r
+\r
+ @param Handle The handle for the UART device.\r
+ @param AcpiUid The ACPI UID on output.\r
+\r
+ @retval TRUE Find valid UID from device path\r
+ @retval FALSE Can't find\r
+\r
+**/\r
+BOOLEAN\r
+RetrieveUartUid (\r
+ IN EFI_HANDLE Handle,\r
+ IN OUT UINT32 *AcpiUid\r
+ )\r
+{\r
+ UINT32 Match;\r
+ UINT8 *Ptr;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ gBS->HandleProtocol (\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+ Ptr = (UINT8 *) DevicePath;\r
+\r
+ while (*Ptr != END_DEVICE_PATH_TYPE) {\r
+ Ptr++;\r
+ }\r
+\r
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
+ Match = EISA_PNP_ID (0x0501);\r
+\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ if (AcpiUid != NULL) {\r
+ *AcpiUid = Acpi->UID;\r
+ }\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Sort Uart handles array with Acpi->UID from low to high.\r
+\r
+ @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer\r
+ @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count\r
+**/\r
+VOID\r
+SortedUartHandle (\r
+ IN EFI_HANDLE *Handles,\r
+ IN UINTN NoHandles\r
+ )\r
+{\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ UINTN Position;\r
+ UINT32 AcpiUid1;\r
+ UINT32 AcpiUid2;\r
+ UINT32 TempAcpiUid;\r
+ EFI_HANDLE TempHandle;\r
+\r
+ for (Index1 = 0; Index1 < NoHandles-1; Index1++) {\r
+ if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {\r
+ continue;\r
+ }\r
+ TempHandle = Handles[Index1];\r
+ Position = Index1;\r
+ TempAcpiUid = AcpiUid1;\r
+\r
+ for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {\r
+ if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {\r
+ continue;\r
+ }\r
+ if (AcpiUid2 < TempAcpiUid) {\r
+ TempAcpiUid = AcpiUid2;\r
+ TempHandle = Handles[Index2];\r
+ Position = Index2;\r
+ }\r
+ }\r
+ Handles[Position] = Handles[Index1];\r
+ Handles[Index1] = TempHandle;\r
+ }\r
+}\r
+\r
+/**\r
+ Test whether DevicePath is a valid Terminal\r
+\r
+\r
+ @param DevicePath DevicePath to be checked\r
+ @param Termi If DevicePath is valid Terminal, terminal type is returned.\r
+ @param Com If DevicePath is valid Terminal, Com Port type is returned.\r
+\r
+ @retval TRUE If DevicePath point to a Terminal.\r
+ @retval FALSE If DevicePath does not point to a Terminal.\r
+\r
+**/\r
+BOOLEAN\r
+IsTerminalDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT TYPE_OF_TERMINAL *Termi,\r
+ OUT UINTN *Com\r
+ );\r
+\r
+/**\r
+ Build a list containing all serial devices.\r
+\r
+\r
+ @retval EFI_SUCCESS The function complete successfully.\r
+ @retval EFI_UNSUPPORTED No serial ports present.\r
+\r
+**/\r
+EFI_STATUS\r
+LocateSerialIo (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 *Ptr;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *Handles;\r
+ EFI_STATUS Status;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINT32 Match;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;\r
+ BM_MENU_ENTRY *NewMenuEntry;\r
+ BM_TERMINAL_CONTEXT *NewTerminalContext;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ VENDOR_DEVICE_PATH Vendor;\r
+ //\r
+ // Get all handles that have SerialIo protocol installed\r
+ //\r
+ InitializeListHead (&TerminalMenu.Head);\r
+ TerminalMenu.MenuNumber = 0;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiSerialIoProtocolGuid,\r
+ NULL,\r
+ &NoHandles,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No serial ports present\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Sort Uart handles array with Acpi->UID from low to high\r
+ // then Terminal menu can be built from low Acpi->UID to high Acpi->UID\r
+ //\r
+ SortedUartHandle (Handles, NoHandles);\r
+\r
+ for (Index = 0; Index < NoHandles; Index++) {\r
+ //\r
+ // Check to see whether the handle has DevicePath Protocol installed\r
+ //\r
+ gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+ Ptr = (UINT8 *) DevicePath;\r
+ while (*Ptr != END_DEVICE_PATH_TYPE) {\r
+ Ptr++;\r
+ }\r
+\r
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
+ Match = EISA_PNP_ID (0x0501);\r
+\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);\r
+ if (NewMenuEntry == NULL) {\r
+ FreePool (Handles);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
+ CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));\r
+ NewTerminalContext->DevicePath = DuplicateDevicePath (DevicePath);\r
+ //\r
+ // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!\r
+ // coz' the misc data for each platform is not correct, actually it's the device path stored in\r
+ // datahub which is not completed, so a searching for end of device path will enter a\r
+ // dead-loop.\r
+ //\r
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);\r
+ if (NULL == NewMenuEntry->DisplayString) {\r
+ NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);\r
+ }\r
+\r
+ NewMenuEntry->HelpString = NULL;\r
+\r
+ gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->BaudRate,\r
+ &SerialIo->Mode->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->DataBits,\r
+ &SerialIo->Mode->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->Parity,\r
+ &SerialIo->Mode->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->StopBits,\r
+ &SerialIo->Mode->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+ InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);\r
+ TerminalMenu.MenuNumber++;\r
+ }\r
+ }\r
+ if (Handles != NULL) {\r
+ FreePool (Handles);\r
+ }\r
+\r
+ //\r
+ // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var\r
+ //\r
+ OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);\r
+ InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);\r
+ ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);\r
+ if (OutDevicePath != NULL) {\r
+ UpdateComAttributeFromVariable (OutDevicePath);\r
+ }\r
+\r
+ if (InpDevicePath != NULL) {\r
+ UpdateComAttributeFromVariable (InpDevicePath);\r
+ }\r
+\r
+ if (ErrDevicePath != NULL) {\r
+ UpdateComAttributeFromVariable (ErrDevicePath);\r
+ }\r
+\r
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {\r
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);\r
+ if (NULL == NewMenuEntry) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
+\r
+ NewTerminalContext->TerminalType = 0;\r
+ NewTerminalContext->IsConIn = FALSE;\r
+ NewTerminalContext->IsConOut = FALSE;\r
+ NewTerminalContext->IsStdErr = FALSE;\r
+\r
+ Vendor.Header.Type = MESSAGING_DEVICE_PATH;\r
+ Vendor.Header.SubType = MSG_VENDOR_DP;\r
+\r
+ for (Index2 = 0; Index2 < 4; Index2++) {\r
+ CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));\r
+ SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));\r
+ NewDevicePath = AppendDevicePathNode (\r
+ NewTerminalContext->DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &Vendor\r
+ );\r
+ if (NewMenuEntry->HelpString != NULL) {\r
+ FreePool (NewMenuEntry->HelpString);\r
+ }\r
+ //\r
+ // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);\r
+ // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;\r
+ //\r
+ NewMenuEntry->HelpString = NULL;\r
+\r
+ if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {\r
+ NewTerminalContext->IsConOut = TRUE;\r
+ NewTerminalContext->TerminalType = (UINT8) Index2;\r
+ }\r
+\r
+ if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {\r
+ NewTerminalContext->IsConIn = TRUE;\r
+ NewTerminalContext->TerminalType = (UINT8) Index2;\r
+ }\r
+\r
+ if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {\r
+ NewTerminalContext->IsStdErr = TRUE;\r
+ NewTerminalContext->TerminalType = (UINT8) Index2;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Update Com Ports attributes from DevicePath\r
+\r
+ @param DevicePath DevicePath that contains Com ports\r
+\r
+ @retval EFI_SUCCESS The update is successful.\r
+ @retval EFI_NOT_FOUND Can not find specific menu entry\r
+**/\r
+EFI_STATUS\r
+UpdateComAttributeFromVariable (\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ EFI_DEVICE_PATH_PROTOCOL *SerialNode;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_DEVICE_PATH *Uart1;\r
+ UINT32 Match;\r
+ UINTN TerminalNumber;\r
+ BM_MENU_ENTRY *NewMenuEntry;\r
+ BM_TERMINAL_CONTEXT *NewTerminalContext;\r
+ UINTN Index;\r
+\r
+ Match = EISA_PNP_ID (0x0501);\r
+ Node = DevicePath;\r
+ Node = NextDevicePathNode (Node);\r
+ TerminalNumber = 0;\r
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {\r
+ while (!IsDevicePathEnd (Node)) {\r
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));\r
+ }\r
+ }\r
+\r
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
+ Uart = (UART_DEVICE_PATH *) Node;\r
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);\r
+ if (NULL == NewMenuEntry) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
+ CopyMem (\r
+ &NewTerminalContext->BaudRate,\r
+ &Uart->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->DataBits,\r
+ &Uart->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->Parity,\r
+ &Uart->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ CopyMem (\r
+ &NewTerminalContext->StopBits,\r
+ &Uart->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ SerialNode = NewTerminalContext->DevicePath;\r
+ SerialNode = NextDevicePathNode (SerialNode);\r
+ while (!IsDevicePathEnd (SerialNode)) {\r
+ if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {\r
+ //\r
+ // Update following device paths according to\r
+ // previous acquired uart attributes\r
+ //\r
+ Uart1 = (UART_DEVICE_PATH *) SerialNode;\r
+ CopyMem (\r
+ &Uart1->BaudRate,\r
+ &NewTerminalContext->BaudRate,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ CopyMem (\r
+ &Uart1->DataBits,\r
+ &NewTerminalContext->DataBits,\r
+ sizeof (UINT8)\r
+ );\r
+ CopyMem (\r
+ &Uart1->Parity,\r
+ &NewTerminalContext->Parity,\r
+ sizeof (UINT8)\r
+ );\r
+ CopyMem (\r
+ &Uart1->StopBits,\r
+ &NewTerminalContext->StopBits,\r
+ sizeof (UINT8)\r
+ );\r
+\r
+ break;\r
+ }\r
+\r
+ SerialNode = NextDevicePathNode (SerialNode);\r
+ }\r
+ //\r
+ // end while\r
+ //\r
+ }\r
+\r
+ Node = NextDevicePathNode (Node);\r
+ }\r
+ //\r
+ // end while\r
+ //\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Build up Console Menu based on types passed in. The type can\r
+ be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT\r
+ and BM_CONSOLE_ERR_CONTEXT_SELECT.\r
+\r
+ @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT\r
+ and BM_CONSOLE_ERR_CONTEXT_SELECT.\r
+\r
+ @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.\r
+ @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev", \r
+ "ConInDev" or "ConErrDev" doesn't exists.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.\r
+ @retval EFI_SUCCESS Function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetConsoleMenu (\r
+ IN UINTN ConsoleMenuType\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
+ UINTN Size;\r
+ UINTN AllCount;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ BM_MENU_ENTRY *NewMenuEntry;\r
+ BM_CONSOLE_CONTEXT *NewConsoleContext;\r
+ TYPE_OF_TERMINAL Terminal;\r
+ UINTN Com;\r
+ BM_MENU_OPTION *ConsoleMenu;\r
+\r
+ DevicePath = NULL;\r
+ AllDevicePath = NULL;\r
+ AllCount = 0;\r
+ switch (ConsoleMenuType) {\r
+ case BM_CONSOLE_IN_CONTEXT_SELECT:\r
+ ConsoleMenu = &ConsoleInpMenu;\r
+ DevicePath = EfiLibGetVariable (\r
+ L"ConIn",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+\r
+ AllDevicePath = EfiLibGetVariable (\r
+ L"ConInDev",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+ break;\r
+\r
+ case BM_CONSOLE_OUT_CONTEXT_SELECT:\r
+ ConsoleMenu = &ConsoleOutMenu;\r
+ DevicePath = EfiLibGetVariable (\r
+ L"ConOut",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+\r
+ AllDevicePath = EfiLibGetVariable (\r
+ L"ConOutDev",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+ break;\r
+\r
+ case BM_CONSOLE_ERR_CONTEXT_SELECT:\r
+ ConsoleMenu = &ConsoleErrMenu;\r
+ DevicePath = EfiLibGetVariable (\r
+ L"ErrOut",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+\r
+ AllDevicePath = EfiLibGetVariable (\r
+ L"ErrOutDev",\r
+ &gEfiGlobalVariableGuid\r
+ );\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (NULL == AllDevicePath) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ InitializeListHead (&ConsoleMenu->Head);\r
+\r
+ AllCount = EfiDevicePathInstanceCount (AllDevicePath);\r
+ ConsoleMenu->MenuNumber = 0;\r
+ //\r
+ // Following is menu building up for Console Devices selected.\r
+ //\r
+ MultiDevicePath = AllDevicePath;\r
+ Index2 = 0;\r
+ for (Index = 0; Index < AllCount; Index++) {\r
+ DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);\r
+\r
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);\r
+ if (NULL == NewMenuEntry) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;\r
+ NewMenuEntry->OptionNumber = Index2;\r
+\r
+ NewConsoleContext->DevicePath = DuplicateDevicePath (DevicePathInst);\r
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);\r
+ if (NULL == NewMenuEntry->DisplayString) {\r
+ NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);\r
+ }\r
+\r
+ NewConsoleContext->IsTerminal = IsTerminalDevicePath (\r
+ NewConsoleContext->DevicePath,\r
+ &Terminal,\r
+ &Com\r
+ );\r
+\r
+ NewConsoleContext->IsActive = BdsLibMatchDevicePaths (\r
+ DevicePath,\r
+ NewConsoleContext->DevicePath\r
+ );\r
+\r
+ if (NewConsoleContext->IsTerminal) {\r
+ BOpt_DestroyMenuEntry (NewMenuEntry);\r
+ } else {\r
+ Index2++;\r
+ ConsoleMenu->MenuNumber++;\r
+ InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu\r
+\r
+ @retval EFI_SUCCESS The function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetAllConsoles (\r
+ VOID\r
+ )\r
+{\r
+ GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);\r
+ GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);\r
+ GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu\r
+\r
+ @retval EFI_SUCCESS The function always complete successfully.\r
+**/\r
+EFI_STATUS\r
+FreeAllConsoles (\r
+ VOID\r
+ )\r
+{\r
+ BOpt_FreeMenu (&ConsoleOutMenu);\r
+ BOpt_FreeMenu (&ConsoleInpMenu);\r
+ BOpt_FreeMenu (&ConsoleErrMenu);\r
+ BOpt_FreeMenu (&TerminalMenu);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Test whether DevicePath is a valid Terminal\r
+\r
+\r
+ @param DevicePath DevicePath to be checked\r
+ @param Termi If DevicePath is valid Terminal, terminal type is returned.\r
+ @param Com If DevicePath is valid Terminal, Com Port type is returned.\r
+\r
+ @retval TRUE If DevicePath point to a Terminal.\r
+ @retval FALSE If DevicePath does not point to a Terminal.\r
+\r
+**/\r
+BOOLEAN\r
+IsTerminalDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT TYPE_OF_TERMINAL *Termi,\r
+ OUT UINTN *Com\r
+ )\r
+{\r
+ UINT8 *Ptr;\r
+ BOOLEAN IsTerminal;\r
+ VENDOR_DEVICE_PATH *Vendor;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ UINT32 Match;\r
+ EFI_GUID TempGuid;\r
+\r
+ IsTerminal = FALSE;\r
+\r
+ //\r
+ // Parse the Device Path, should be change later!!!\r
+ //\r
+ Ptr = (UINT8 *) DevicePath;\r
+ while (*Ptr != END_DEVICE_PATH_TYPE) {\r
+ Ptr++;\r
+ }\r
+\r
+ Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH);\r
+ Vendor = (VENDOR_DEVICE_PATH *) Ptr;\r
+\r
+ //\r
+ // There are four kinds of Terminal types\r
+ // check to see whether this devicepath\r
+ // is one of that type\r
+ //\r
+ CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID));\r
+\r
+ if (CompareGuid (&TempGuid, &TerminalTypeGuid[0])) {\r
+ *Termi = PC_ANSI;\r
+ IsTerminal = TRUE;\r
+ } else {\r
+ if (CompareGuid (&TempGuid, &TerminalTypeGuid[1])) {\r
+ *Termi = VT_100;\r
+ IsTerminal = TRUE;\r
+ } else {\r
+ if (CompareGuid (&TempGuid, &TerminalTypeGuid[2])) {\r
+ *Termi = VT_100_PLUS;\r
+ IsTerminal = TRUE;\r
+ } else {\r
+ if (CompareGuid (&TempGuid, &TerminalTypeGuid[3])) {\r
+ *Termi = VT_UTF8;\r
+ IsTerminal = TRUE;\r
+ } else {\r
+ IsTerminal = FALSE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!IsTerminal) {\r
+ return FALSE;\r
+ }\r
+\r
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
+ Match = EISA_PNP_ID (0x0501);\r
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
+ CopyMem (Com, &Acpi->UID, sizeof (UINT32));\r
+ } else {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Get mode number according to column and row\r
+\r
+ @param CallbackData The BMM context data.\r
+**/\r
+VOID\r
+GetConsoleOutMode (\r
+ IN BMM_CALLBACK_DATA *CallbackData\r
+ )\r
+{\r
+ UINTN Col;\r
+ UINTN Row;\r
+ UINTN CurrentCol;\r
+ UINTN CurrentRow;\r
+ UINTN Mode;\r
+ UINTN MaxMode;\r
+ EFI_STATUS Status;\r
+ CONSOLE_OUT_MODE *ModeInfo;\r
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;\r
+\r
+ ConOut = gST->ConOut;\r
+ MaxMode = (UINTN) (ConOut->Mode->MaxMode);\r
+ ModeInfo = EfiLibGetVariable (VAR_CON_OUT_MODE, &gEfiGenericPlatformVariableGuid);\r
+\r
+ if (ModeInfo != NULL) {\r
+ CurrentCol = ModeInfo->Column;\r
+ CurrentRow = ModeInfo->Row;\r
+ for (Mode = 0; Mode < MaxMode; Mode++) {\r
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);\r
+ if (!EFI_ERROR(Status)) {\r
+ if (CurrentCol == Col && CurrentRow == Row) {\r
+ CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ FreePool (ModeInfo);\r
+ }\r
+}\r