| /** @file | |
| handles console redirection from boot manager | |
| Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "BootMaintenanceManager.h" | |
| /** | |
| Function compares a device path data structure to that of all the nodes of a | |
| second device path instance. | |
| @param Multi A pointer to a multi-instance device path data | |
| structure. | |
| @param Single A pointer to a single-instance device path data | |
| structure. | |
| @retval TRUE If the Single device path is contained within Multi device path. | |
| @retval FALSE The Single device path is not match within Multi device path. | |
| **/ | |
| BOOLEAN | |
| MatchDevicePaths ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *Multi, | |
| IN EFI_DEVICE_PATH_PROTOCOL *Single | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; | |
| UINTN Size; | |
| if (Multi == NULL || Single == NULL) { | |
| return FALSE; | |
| } | |
| DevicePath = Multi; | |
| DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); | |
| // | |
| // Search for the match of 'Single' in 'Multi' | |
| // | |
| while (DevicePathInst != NULL) { | |
| // | |
| // If the single device path is found in multiple device paths, | |
| // return success | |
| // | |
| if (CompareMem (Single, DevicePathInst, Size) == 0) { | |
| FreePool (DevicePathInst); | |
| return TRUE; | |
| } | |
| FreePool (DevicePathInst); | |
| DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Check whether the device path node is ISA Serial Node. | |
| @param Acpi Device path node to be checked | |
| @retval TRUE It's ISA Serial Node. | |
| @retval FALSE It's NOT ISA Serial Node. | |
| **/ | |
| BOOLEAN | |
| IsIsaSerialNode ( | |
| IN ACPI_HID_DEVICE_PATH *Acpi | |
| ) | |
| { | |
| return (BOOLEAN) ( | |
| (DevicePathType (Acpi) == ACPI_DEVICE_PATH) && | |
| (DevicePathSubType (Acpi) == ACPI_DP) && | |
| (ReadUnaligned32 (&Acpi->HID) == EISA_PNP_ID (0x0501)) | |
| ); | |
| } | |
| /** | |
| Update Com Ports attributes from DevicePath | |
| @param DevicePath DevicePath that contains Com ports | |
| @retval EFI_SUCCESS The update is successful. | |
| **/ | |
| EFI_STATUS | |
| UpdateComAttributeFromVariable ( | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ); | |
| /** | |
| Update the multi-instance device path of Terminal Device based on | |
| the global TerminalMenu. If ChangeTernimal is TRUE, the terminal | |
| device path in the Terminal Device in TerminalMenu is also updated. | |
| @param DevicePath The multi-instance device path. | |
| @param ChangeTerminal TRUE, then device path in the Terminal Device | |
| in TerminalMenu is also updated; FALSE, no update. | |
| @return EFI_SUCCESS The function completes successfully. | |
| **/ | |
| EFI_STATUS | |
| ChangeTerminalDevicePath ( | |
| IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN BOOLEAN ChangeTerminal | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *Node; | |
| EFI_DEVICE_PATH_PROTOCOL *Node1; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| UART_DEVICE_PATH *Uart; | |
| UART_DEVICE_PATH *Uart1; | |
| UINTN Com; | |
| BM_TERMINAL_CONTEXT *NewTerminalContext; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| Node = DevicePath; | |
| Node = NextDevicePathNode (Node); | |
| Com = 0; | |
| while (!IsDevicePathEnd (Node)) { | |
| Acpi = (ACPI_HID_DEVICE_PATH *) Node; | |
| if (IsIsaSerialNode (Acpi)) { | |
| CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); | |
| } | |
| NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com); | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { | |
| Uart = (UART_DEVICE_PATH *) Node; | |
| CopyMem ( | |
| &Uart->BaudRate, | |
| &NewTerminalContext->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &Uart->DataBits, | |
| &NewTerminalContext->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart->Parity, | |
| &NewTerminalContext->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart->StopBits, | |
| &NewTerminalContext->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| // | |
| // Change the device path in the ComPort | |
| // | |
| if (ChangeTerminal) { | |
| Node1 = NewTerminalContext->DevicePath; | |
| Node1 = NextDevicePathNode (Node1); | |
| while (!IsDevicePathEnd (Node1)) { | |
| if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) { | |
| Uart1 = (UART_DEVICE_PATH *) Node1; | |
| CopyMem ( | |
| &Uart1->BaudRate, | |
| &NewTerminalContext->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &Uart1->DataBits, | |
| &NewTerminalContext->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart1->Parity, | |
| &NewTerminalContext->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart1->StopBits, | |
| &NewTerminalContext->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| break; | |
| } | |
| // | |
| // end if | |
| // | |
| Node1 = NextDevicePathNode (Node1); | |
| } | |
| // | |
| // end while | |
| // | |
| break; | |
| } | |
| } | |
| Node = NextDevicePathNode (Node); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Update the device path that describing a terminal device | |
| based on the new BaudRate, Data Bits, parity and Stop Bits | |
| set. | |
| @param DevicePath terminal device's path | |
| **/ | |
| VOID | |
| ChangeVariableDevicePath ( | |
| IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *Node; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| UART_DEVICE_PATH *Uart; | |
| UINTN Com; | |
| BM_TERMINAL_CONTEXT *NewTerminalContext; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| Node = DevicePath; | |
| Node = NextDevicePathNode (Node); | |
| Com = 0; | |
| while (!IsDevicePathEnd (Node)) { | |
| Acpi = (ACPI_HID_DEVICE_PATH *) Node; | |
| if (IsIsaSerialNode (Acpi)) { | |
| CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); | |
| } | |
| if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { | |
| NewMenuEntry = BOpt_GetMenuEntry ( | |
| &TerminalMenu, | |
| Com | |
| ); | |
| ASSERT (NewMenuEntry != NULL); | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| Uart = (UART_DEVICE_PATH *) Node; | |
| CopyMem ( | |
| &Uart->BaudRate, | |
| &NewTerminalContext->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &Uart->DataBits, | |
| &NewTerminalContext->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart->Parity, | |
| &NewTerminalContext->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart->StopBits, | |
| &NewTerminalContext->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| } | |
| Node = NextDevicePathNode (Node); | |
| } | |
| } | |
| /** | |
| Retrieve ACPI UID of UART from device path | |
| @param Handle The handle for the UART device. | |
| @param AcpiUid The ACPI UID on output. | |
| @retval TRUE Find valid UID from device path | |
| @retval FALSE Can't find | |
| **/ | |
| BOOLEAN | |
| RetrieveUartUid ( | |
| IN EFI_HANDLE Handle, | |
| IN OUT UINT32 *AcpiUid | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return FALSE; | |
| } | |
| Acpi = NULL; | |
| for (; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) { | |
| if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MSG_UART_DP)) { | |
| break; | |
| } | |
| // | |
| // Acpi points to the node before the Uart node | |
| // | |
| Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; | |
| } | |
| if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { | |
| if (AcpiUid != NULL) { | |
| CopyMem (AcpiUid, &Acpi->UID, sizeof (UINT32)); | |
| } | |
| return TRUE; | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Sort Uart handles array with Acpi->UID from low to high. | |
| @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer | |
| @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count | |
| **/ | |
| VOID | |
| SortedUartHandle ( | |
| IN EFI_HANDLE *Handles, | |
| IN UINTN NoHandles | |
| ) | |
| { | |
| UINTN Index1; | |
| UINTN Index2; | |
| UINTN Position; | |
| UINT32 AcpiUid1; | |
| UINT32 AcpiUid2; | |
| UINT32 TempAcpiUid; | |
| EFI_HANDLE TempHandle; | |
| for (Index1 = 0; Index1 < NoHandles-1; Index1++) { | |
| if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) { | |
| continue; | |
| } | |
| TempHandle = Handles[Index1]; | |
| Position = Index1; | |
| TempAcpiUid = AcpiUid1; | |
| for (Index2 = Index1+1; Index2 < NoHandles; Index2++) { | |
| if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) { | |
| continue; | |
| } | |
| if (AcpiUid2 < TempAcpiUid) { | |
| TempAcpiUid = AcpiUid2; | |
| TempHandle = Handles[Index2]; | |
| Position = Index2; | |
| } | |
| } | |
| Handles[Position] = Handles[Index1]; | |
| Handles[Index1] = TempHandle; | |
| } | |
| } | |
| /** | |
| Test whether DevicePath is a valid Terminal | |
| @param DevicePath DevicePath to be checked | |
| @param Termi If DevicePath is valid Terminal, terminal type is returned. | |
| @param Com If DevicePath is valid Terminal, Com Port type is returned. | |
| @retval TRUE If DevicePath point to a Terminal. | |
| @retval FALSE If DevicePath does not point to a Terminal. | |
| **/ | |
| BOOLEAN | |
| IsTerminalDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| OUT TYPE_OF_TERMINAL *Termi, | |
| OUT UINTN *Com | |
| ); | |
| /** | |
| Build a list containing all serial devices. | |
| @retval EFI_SUCCESS The function complete successfully. | |
| @retval EFI_UNSUPPORTED No serial ports present. | |
| **/ | |
| EFI_STATUS | |
| LocateSerialIo ( | |
| VOID | |
| ) | |
| { | |
| UINTN Index; | |
| UINTN Index2; | |
| UINTN NoHandles; | |
| EFI_HANDLE *Handles; | |
| EFI_STATUS Status; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_SERIAL_IO_PROTOCOL *SerialIo; | |
| EFI_DEVICE_PATH_PROTOCOL *Node; | |
| EFI_DEVICE_PATH_PROTOCOL *OutDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *InpDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| BM_TERMINAL_CONTEXT *NewTerminalContext; | |
| EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
| VENDOR_DEVICE_PATH Vendor; | |
| // | |
| // Get all handles that have SerialIo protocol installed | |
| // | |
| InitializeListHead (&TerminalMenu.Head); | |
| TerminalMenu.MenuNumber = 0; | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiSerialIoProtocolGuid, | |
| NULL, | |
| &NoHandles, | |
| &Handles | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // No serial ports present | |
| // | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Sort Uart handles array with Acpi->UID from low to high | |
| // then Terminal menu can be built from low Acpi->UID to high Acpi->UID | |
| // | |
| SortedUartHandle (Handles, NoHandles); | |
| for (Index = 0; Index < NoHandles; Index++) { | |
| // | |
| // Check to see whether the handle has DevicePath Protocol installed | |
| // | |
| gBS->HandleProtocol ( | |
| Handles[Index], | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &DevicePath | |
| ); | |
| Acpi = NULL; | |
| for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { | |
| if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { | |
| break; | |
| } | |
| // | |
| // Acpi points to the node before Uart node | |
| // | |
| Acpi = (ACPI_HID_DEVICE_PATH *) Node; | |
| } | |
| if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { | |
| NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT); | |
| if (NewMenuEntry == NULL) { | |
| FreePool (Handles); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32)); | |
| NewTerminalContext->DevicePath = DuplicateDevicePath (DevicePath); | |
| // | |
| // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system! | |
| // coz' the misc data for each platform is not correct, actually it's the device path stored in | |
| // datahub which is not completed, so a searching for end of device path will enter a | |
| // dead-loop. | |
| // | |
| NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath); | |
| if (NULL == NewMenuEntry->DisplayString) { | |
| NewMenuEntry->DisplayString = UiDevicePathToStr (DevicePath); | |
| } | |
| NewMenuEntry->HelpString = NULL; | |
| NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL); | |
| NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; | |
| gBS->HandleProtocol ( | |
| Handles[Index], | |
| &gEfiSerialIoProtocolGuid, | |
| (VOID **) &SerialIo | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->BaudRate, | |
| &SerialIo->Mode->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->DataBits, | |
| &SerialIo->Mode->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->Parity, | |
| &SerialIo->Mode->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->StopBits, | |
| &SerialIo->Mode->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link); | |
| TerminalMenu.MenuNumber++; | |
| } | |
| } | |
| if (Handles != NULL) { | |
| FreePool (Handles); | |
| } | |
| // | |
| // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var | |
| // | |
| GetEfiGlobalVariable2 (L"ConOut", (VOID**)&OutDevicePath, NULL); | |
| GetEfiGlobalVariable2 (L"ConIn", (VOID**)&InpDevicePath, NULL); | |
| GetEfiGlobalVariable2 (L"ErrOut", (VOID**)&ErrDevicePath, NULL); | |
| if (OutDevicePath != NULL) { | |
| UpdateComAttributeFromVariable (OutDevicePath); | |
| } | |
| if (InpDevicePath != NULL) { | |
| UpdateComAttributeFromVariable (InpDevicePath); | |
| } | |
| if (ErrDevicePath != NULL) { | |
| UpdateComAttributeFromVariable (ErrDevicePath); | |
| } | |
| for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { | |
| NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); | |
| if (NULL == NewMenuEntry) { | |
| return EFI_NOT_FOUND; | |
| } | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| NewTerminalContext->TerminalType = 0; | |
| NewTerminalContext->IsConIn = FALSE; | |
| NewTerminalContext->IsConOut = FALSE; | |
| NewTerminalContext->IsStdErr = FALSE; | |
| Vendor.Header.Type = MESSAGING_DEVICE_PATH; | |
| Vendor.Header.SubType = MSG_VENDOR_DP; | |
| for (Index2 = 0; Index2 < (sizeof (TerminalTypeGuid) / sizeof (TerminalTypeGuid[0])); Index2++) { | |
| CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID)); | |
| SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH)); | |
| NewDevicePath = AppendDevicePathNode ( | |
| NewTerminalContext->DevicePath, | |
| (EFI_DEVICE_PATH_PROTOCOL *) &Vendor | |
| ); | |
| if (NewMenuEntry->HelpString != NULL) { | |
| FreePool (NewMenuEntry->HelpString); | |
| } | |
| // | |
| // NewMenuEntry->HelpString = UiDevicePathToStr (NewDevicePath); | |
| // NewMenuEntry->DisplayString = NewMenuEntry->HelpString; | |
| // | |
| NewMenuEntry->HelpString = NULL; | |
| NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL); | |
| NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; | |
| if (MatchDevicePaths (OutDevicePath, NewDevicePath)) { | |
| NewTerminalContext->IsConOut = TRUE; | |
| NewTerminalContext->TerminalType = (UINT8) Index2; | |
| } | |
| if (MatchDevicePaths (InpDevicePath, NewDevicePath)) { | |
| NewTerminalContext->IsConIn = TRUE; | |
| NewTerminalContext->TerminalType = (UINT8) Index2; | |
| } | |
| if (MatchDevicePaths (ErrDevicePath, NewDevicePath)) { | |
| NewTerminalContext->IsStdErr = TRUE; | |
| NewTerminalContext->TerminalType = (UINT8) Index2; | |
| } | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Update Com Ports attributes from DevicePath | |
| @param DevicePath DevicePath that contains Com ports | |
| @retval EFI_SUCCESS The update is successful. | |
| @retval EFI_NOT_FOUND Can not find specific menu entry | |
| **/ | |
| EFI_STATUS | |
| UpdateComAttributeFromVariable ( | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *Node; | |
| EFI_DEVICE_PATH_PROTOCOL *SerialNode; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| UART_DEVICE_PATH *Uart; | |
| UART_DEVICE_PATH *Uart1; | |
| UINTN TerminalNumber; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| BM_TERMINAL_CONTEXT *NewTerminalContext; | |
| UINTN Index; | |
| Node = DevicePath; | |
| Node = NextDevicePathNode (Node); | |
| TerminalNumber = 0; | |
| for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { | |
| while (!IsDevicePathEnd (Node)) { | |
| Acpi = (ACPI_HID_DEVICE_PATH *) Node; | |
| if (IsIsaSerialNode (Acpi)) { | |
| CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32)); | |
| } | |
| if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { | |
| Uart = (UART_DEVICE_PATH *) Node; | |
| NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber); | |
| if (NULL == NewMenuEntry) { | |
| return EFI_NOT_FOUND; | |
| } | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| CopyMem ( | |
| &NewTerminalContext->BaudRate, | |
| &Uart->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->DataBits, | |
| &Uart->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->Parity, | |
| &Uart->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &NewTerminalContext->StopBits, | |
| &Uart->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| SerialNode = NewTerminalContext->DevicePath; | |
| SerialNode = NextDevicePathNode (SerialNode); | |
| while (!IsDevicePathEnd (SerialNode)) { | |
| if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) { | |
| // | |
| // Update following device paths according to | |
| // previous acquired uart attributes | |
| // | |
| Uart1 = (UART_DEVICE_PATH *) SerialNode; | |
| CopyMem ( | |
| &Uart1->BaudRate, | |
| &NewTerminalContext->BaudRate, | |
| sizeof (UINT64) | |
| ); | |
| CopyMem ( | |
| &Uart1->DataBits, | |
| &NewTerminalContext->DataBits, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart1->Parity, | |
| &NewTerminalContext->Parity, | |
| sizeof (UINT8) | |
| ); | |
| CopyMem ( | |
| &Uart1->StopBits, | |
| &NewTerminalContext->StopBits, | |
| sizeof (UINT8) | |
| ); | |
| break; | |
| } | |
| SerialNode = NextDevicePathNode (SerialNode); | |
| } | |
| // | |
| // end while | |
| // | |
| } | |
| Node = NextDevicePathNode (Node); | |
| } | |
| // | |
| // end while | |
| // | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Build up Console Menu based on types passed in. The type can | |
| be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT | |
| and BM_CONSOLE_ERR_CONTEXT_SELECT. | |
| @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT | |
| and BM_CONSOLE_ERR_CONTEXT_SELECT. | |
| @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined. | |
| @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev", | |
| "ConInDev" or "ConErrDev" doesn't exists. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations. | |
| @retval EFI_SUCCESS Function completes successfully. | |
| **/ | |
| EFI_STATUS | |
| GetConsoleMenu ( | |
| IN UINTN ConsoleMenuType | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *AllDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; | |
| UINTN Size; | |
| UINTN AllCount; | |
| UINTN Index; | |
| UINTN Index2; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| BM_CONSOLE_CONTEXT *NewConsoleContext; | |
| TYPE_OF_TERMINAL Terminal; | |
| UINTN Com; | |
| BM_MENU_OPTION *ConsoleMenu; | |
| DevicePath = NULL; | |
| AllDevicePath = NULL; | |
| AllCount = 0; | |
| switch (ConsoleMenuType) { | |
| case BM_CONSOLE_IN_CONTEXT_SELECT: | |
| ConsoleMenu = &ConsoleInpMenu; | |
| GetEfiGlobalVariable2 (L"ConIn", (VOID**)&DevicePath, NULL); | |
| GetEfiGlobalVariable2 (L"ConInDev", (VOID**)&AllDevicePath, NULL); | |
| break; | |
| case BM_CONSOLE_OUT_CONTEXT_SELECT: | |
| ConsoleMenu = &ConsoleOutMenu; | |
| GetEfiGlobalVariable2 (L"ConOut", (VOID**)&DevicePath, NULL); | |
| GetEfiGlobalVariable2 (L"ConOutDev", (VOID**)&AllDevicePath, NULL); | |
| break; | |
| case BM_CONSOLE_ERR_CONTEXT_SELECT: | |
| ConsoleMenu = &ConsoleErrMenu; | |
| GetEfiGlobalVariable2 (L"ErrOut", (VOID**)&DevicePath, NULL); | |
| GetEfiGlobalVariable2 (L"ErrOutDev", (VOID**)&AllDevicePath, NULL); | |
| break; | |
| default: | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (NULL == AllDevicePath) { | |
| return EFI_NOT_FOUND; | |
| } | |
| InitializeListHead (&ConsoleMenu->Head); | |
| AllCount = EfiDevicePathInstanceCount (AllDevicePath); | |
| ConsoleMenu->MenuNumber = 0; | |
| // | |
| // Following is menu building up for Console Devices selected. | |
| // | |
| MultiDevicePath = AllDevicePath; | |
| Index2 = 0; | |
| for (Index = 0; Index < AllCount; Index++) { | |
| DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size); | |
| NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT); | |
| if (NULL == NewMenuEntry) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; | |
| NewMenuEntry->OptionNumber = Index2; | |
| NewConsoleContext->DevicePath = DuplicateDevicePath (DevicePathInst); | |
| ASSERT (NewConsoleContext->DevicePath != NULL); | |
| NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath); | |
| if (NULL == NewMenuEntry->DisplayString) { | |
| NewMenuEntry->DisplayString = UiDevicePathToStr (NewConsoleContext->DevicePath); | |
| } | |
| NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL); | |
| if (NULL == NewMenuEntry->HelpString) { | |
| NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; | |
| } else { | |
| NewMenuEntry->HelpStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL); | |
| } | |
| NewConsoleContext->IsTerminal = IsTerminalDevicePath ( | |
| NewConsoleContext->DevicePath, | |
| &Terminal, | |
| &Com | |
| ); | |
| NewConsoleContext->IsActive = MatchDevicePaths ( | |
| DevicePath, | |
| NewConsoleContext->DevicePath | |
| ); | |
| if (NewConsoleContext->IsTerminal) { | |
| BOpt_DestroyMenuEntry (NewMenuEntry); | |
| } else { | |
| Index2++; | |
| ConsoleMenu->MenuNumber++; | |
| InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu | |
| @retval EFI_SUCCESS The function always complete successfully. | |
| **/ | |
| EFI_STATUS | |
| GetAllConsoles ( | |
| VOID | |
| ) | |
| { | |
| GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT); | |
| GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT); | |
| GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu | |
| @retval EFI_SUCCESS The function always complete successfully. | |
| **/ | |
| EFI_STATUS | |
| FreeAllConsoles ( | |
| VOID | |
| ) | |
| { | |
| BOpt_FreeMenu (&ConsoleOutMenu); | |
| BOpt_FreeMenu (&ConsoleInpMenu); | |
| BOpt_FreeMenu (&ConsoleErrMenu); | |
| BOpt_FreeMenu (&TerminalMenu); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Test whether DevicePath is a valid Terminal | |
| @param DevicePath DevicePath to be checked | |
| @param Termi If DevicePath is valid Terminal, terminal type is returned. | |
| @param Com If DevicePath is valid Terminal, Com Port type is returned. | |
| @retval TRUE If DevicePath point to a Terminal. | |
| @retval FALSE If DevicePath does not point to a Terminal. | |
| **/ | |
| BOOLEAN | |
| IsTerminalDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| OUT TYPE_OF_TERMINAL *Termi, | |
| OUT UINTN *Com | |
| ) | |
| { | |
| BOOLEAN IsTerminal; | |
| EFI_DEVICE_PATH_PROTOCOL *Node; | |
| VENDOR_DEVICE_PATH *Vendor; | |
| UART_DEVICE_PATH *Uart; | |
| ACPI_HID_DEVICE_PATH *Acpi; | |
| IsTerminal = FALSE; | |
| Uart = NULL; | |
| Vendor = NULL; | |
| Acpi = NULL; | |
| for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { | |
| // | |
| // Vendor points to the node before the End node | |
| // | |
| Vendor = (VENDOR_DEVICE_PATH *) Node; | |
| if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { | |
| Uart = (UART_DEVICE_PATH *) Node; | |
| } | |
| if (Uart == NULL) { | |
| // | |
| // Acpi points to the node before the UART node | |
| // | |
| Acpi = (ACPI_HID_DEVICE_PATH *) Node; | |
| } | |
| } | |
| if (Vendor == NULL || | |
| DevicePathType (Vendor) != MESSAGING_DEVICE_PATH || | |
| DevicePathSubType (Vendor) != MSG_VENDOR_DP || | |
| Uart == NULL) { | |
| return FALSE; | |
| } | |
| // | |
| // There are four kinds of Terminal types | |
| // check to see whether this devicepath | |
| // is one of that type | |
| // | |
| if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[0])) { | |
| *Termi = TerminalTypePcAnsi; | |
| IsTerminal = TRUE; | |
| } else { | |
| if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[1])) { | |
| *Termi = TerminalTypeVt100; | |
| IsTerminal = TRUE; | |
| } else { | |
| if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[2])) { | |
| *Termi = TerminalTypeVt100Plus; | |
| IsTerminal = TRUE; | |
| } else { | |
| if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[3])) { | |
| *Termi = TerminalTypeVtUtf8; | |
| IsTerminal = TRUE; | |
| } else { | |
| if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[4])) { | |
| *Termi = TerminalTypeTtyTerm; | |
| IsTerminal = TRUE; | |
| } else { | |
| IsTerminal = FALSE; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if (!IsTerminal) { | |
| return FALSE; | |
| } | |
| if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { | |
| CopyMem (Com, &Acpi->UID, sizeof (UINT32)); | |
| } else { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| Get mode number according to column and row | |
| @param CallbackData The BMM context data. | |
| **/ | |
| VOID | |
| GetConsoleOutMode ( | |
| IN BMM_CALLBACK_DATA *CallbackData | |
| ) | |
| { | |
| UINTN Col; | |
| UINTN Row; | |
| UINTN CurrentCol; | |
| UINTN CurrentRow; | |
| UINTN Mode; | |
| UINTN MaxMode; | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; | |
| ConOut = gST->ConOut; | |
| MaxMode = (UINTN) (ConOut->Mode->MaxMode); | |
| CurrentCol = PcdGet32 (PcdSetupConOutColumn); | |
| CurrentRow = PcdGet32 (PcdSetupConOutRow); | |
| for (Mode = 0; Mode < MaxMode; Mode++) { | |
| Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row); | |
| if (!EFI_ERROR(Status)) { | |
| if (CurrentCol == Col && CurrentRow == Row) { | |
| CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| Initialize console input device check box to ConsoleInCheck[MAX_MENU_NUMBER] | |
| in BMM_FAKE_NV_DATA structure. | |
| @param CallbackData The BMM context data. | |
| **/ | |
| VOID | |
| GetConsoleInCheck ( | |
| IN BMM_CALLBACK_DATA *CallbackData | |
| ) | |
| { | |
| UINT16 Index; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| UINT8 *ConInCheck; | |
| BM_CONSOLE_CONTEXT *NewConsoleContext; | |
| ASSERT (CallbackData != NULL); | |
| ConInCheck = &CallbackData->BmmFakeNvData.ConsoleInCheck[0]; | |
| for (Index = 0; ((Index < ConsoleInpMenu.MenuNumber) && \ | |
| (Index < MAX_MENU_NUMBER)) ; Index++) { | |
| NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index); | |
| NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; | |
| ConInCheck[Index] = NewConsoleContext->IsActive; | |
| } | |
| } | |
| /** | |
| Initialize console output device check box to ConsoleOutCheck[MAX_MENU_NUMBER] | |
| in BMM_FAKE_NV_DATA structure. | |
| @param CallbackData The BMM context data. | |
| **/ | |
| VOID | |
| GetConsoleOutCheck ( | |
| IN BMM_CALLBACK_DATA *CallbackData | |
| ) | |
| { | |
| UINT16 Index; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| UINT8 *ConOutCheck; | |
| BM_CONSOLE_CONTEXT *NewConsoleContext; | |
| ASSERT (CallbackData != NULL); | |
| ConOutCheck = &CallbackData->BmmFakeNvData.ConsoleOutCheck[0]; | |
| for (Index = 0; ((Index < ConsoleOutMenu.MenuNumber) && \ | |
| (Index < MAX_MENU_NUMBER)) ; Index++) { | |
| NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index); | |
| NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; | |
| ConOutCheck[Index] = NewConsoleContext->IsActive; | |
| } | |
| } | |
| /** | |
| Initialize standard error output device check box to ConsoleErrCheck[MAX_MENU_NUMBER] | |
| in BMM_FAKE_NV_DATA structure. | |
| @param CallbackData The BMM context data. | |
| **/ | |
| VOID | |
| GetConsoleErrCheck ( | |
| IN BMM_CALLBACK_DATA *CallbackData | |
| ) | |
| { | |
| UINT16 Index; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| UINT8 *ConErrCheck; | |
| BM_CONSOLE_CONTEXT *NewConsoleContext; | |
| ASSERT (CallbackData != NULL); | |
| ConErrCheck = &CallbackData->BmmFakeNvData.ConsoleErrCheck[0]; | |
| for (Index = 0; ((Index < ConsoleErrMenu.MenuNumber) && \ | |
| (Index < MAX_MENU_NUMBER)) ; Index++) { | |
| NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index); | |
| NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; | |
| ConErrCheck[Index] = NewConsoleContext->IsActive; | |
| } | |
| } | |
| /** | |
| Initialize terminal attributes (baudrate, data rate, stop bits, parity and terminal type) | |
| to BMM_FAKE_NV_DATA structure. | |
| @param CallbackData The BMM context data. | |
| **/ | |
| VOID | |
| GetTerminalAttribute ( | |
| IN BMM_CALLBACK_DATA *CallbackData | |
| ) | |
| { | |
| BMM_FAKE_NV_DATA *CurrentFakeNVMap; | |
| BM_MENU_ENTRY *NewMenuEntry; | |
| BM_TERMINAL_CONTEXT *NewTerminalContext; | |
| UINT16 TerminalIndex; | |
| UINT8 AttributeIndex; | |
| ASSERT (CallbackData != NULL); | |
| CurrentFakeNVMap = &CallbackData->BmmFakeNvData; | |
| for (TerminalIndex = 0; ((TerminalIndex < TerminalMenu.MenuNumber) && \ | |
| (TerminalIndex < MAX_MENU_NUMBER)); TerminalIndex++) { | |
| NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalIndex); | |
| NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; | |
| for (AttributeIndex = 0; AttributeIndex < sizeof (BaudRateList) / sizeof (BaudRateList [0]); AttributeIndex++) { | |
| if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[AttributeIndex].Value)) { | |
| NewTerminalContext->BaudRateIndex = AttributeIndex; | |
| break; | |
| } | |
| } | |
| for (AttributeIndex = 0; AttributeIndex < sizeof (DataBitsList) / sizeof (DataBitsList[0]); AttributeIndex++) { | |
| if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) { | |
| NewTerminalContext->DataBitsIndex = AttributeIndex; | |
| break; | |
| } | |
| } | |
| for (AttributeIndex = 0; AttributeIndex < sizeof (ParityList) / sizeof (ParityList[0]); AttributeIndex++) { | |
| if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) { | |
| NewTerminalContext->ParityIndex = AttributeIndex; | |
| break; | |
| } | |
| } | |
| for (AttributeIndex = 0; AttributeIndex < sizeof (StopBitsList) / sizeof (StopBitsList[0]); AttributeIndex++) { | |
| if (NewTerminalContext->StopBits == (UINT64) (StopBitsList[AttributeIndex].Value)) { | |
| NewTerminalContext->StopBitsIndex = AttributeIndex; | |
| break; | |
| } | |
| } | |
| CurrentFakeNVMap->COMBaudRate[TerminalIndex] = NewTerminalContext->BaudRateIndex; | |
| CurrentFakeNVMap->COMDataRate[TerminalIndex] = NewTerminalContext->DataBitsIndex; | |
| CurrentFakeNVMap->COMStopBits[TerminalIndex] = NewTerminalContext->StopBitsIndex; | |
| CurrentFakeNVMap->COMParity[TerminalIndex] = NewTerminalContext->ParityIndex; | |
| CurrentFakeNVMap->COMTerminalType[TerminalIndex] = NewTerminalContext->TerminalType; | |
| CurrentFakeNVMap->COMFlowControl[TerminalIndex] = NewTerminalContext->FlowControl; | |
| } | |
| } | |