diff options
Diffstat (limited to 'MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c')
| -rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c | 1544 |
1 files changed, 772 insertions, 772 deletions
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c index 60e7b1099a..6d4e938481 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c @@ -1,772 +1,772 @@ -/** @file
- Library functions which contain all the code to connect console device.
-
-Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "InternalBm.h"
-
-CHAR16 *mConVarName[] = {
- L"ConIn",
- L"ConOut",
- L"ErrOut",
- L"ConInDev",
- L"ConOutDev",
- L"ErrOutDev"
-};
-
-/**
- Search out the video controller.
-
- @return PCI device path of the video controller.
-**/
-EFI_HANDLE
-BmGetVideoController (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN RootBridgeHandleCount;
- EFI_HANDLE *RootBridgeHandleBuffer;
- UINTN HandleCount;
- EFI_HANDLE *HandleBuffer;
- UINTN RootBridgeIndex;
- UINTN Index;
- EFI_HANDLE VideoController;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
-
- //
- // Make all the PCI_IO protocols show up
- //
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiPciRootBridgeIoProtocolGuid,
- NULL,
- &RootBridgeHandleCount,
- &RootBridgeHandleBuffer
- );
- if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {
- return NULL;
- }
-
- VideoController = NULL;
- for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
- gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
-
- //
- // Start to check all the pci io to find the first video controller
- //
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiPciIoProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- for (Index = 0; Index < HandleCount; Index++) {
- Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
- if (!EFI_ERROR (Status)) {
- //
- // Check for all video controller
- //
- Status = PciIo->Pci.Read (
- PciIo,
- EfiPciIoWidthUint32,
- 0,
- sizeof (Pci) / sizeof (UINT32),
- &Pci
- );
- if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {
- // TODO: use IS_PCI_DISPLAY??
- VideoController = HandleBuffer[Index];
- break;
- }
- }
- }
-
- FreePool (HandleBuffer);
-
- if (VideoController != NULL) {
- break;
- }
- }
-
- FreePool (RootBridgeHandleBuffer);
-
- return VideoController;
-}
-
-/**
- Query all the children of VideoController and return the device paths of all the
- children that support GraphicsOutput protocol.
-
- @param VideoController PCI handle of video controller.
-
- @return Device paths of all the children that support GraphicsOutput protocol.
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-EFIAPI
-EfiBootManagerGetGopDevicePath (
- IN EFI_HANDLE VideoController
- )
-{
- UINTN Index;
- EFI_STATUS Status;
- EFI_GUID **ProtocolBuffer;
- UINTN ProtocolBufferCount;
- UINTN ProtocolIndex;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
- UINTN EntryCount;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_DEVICE_PATH_PROTOCOL *Next;
- EFI_DEVICE_PATH_PROTOCOL *Previous;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *GopPool;
- EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath;
-
- Status = gBS->ProtocolsPerHandle (
- VideoController,
- &ProtocolBuffer,
- &ProtocolBufferCount
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- GopPool = NULL;
-
- for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
- Status = gBS->OpenProtocolInformation (
- VideoController,
- ProtocolBuffer[ProtocolIndex],
- &OpenInfoBuffer,
- &EntryCount
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- for (Index = 0; Index < EntryCount; Index++) {
- //
- // Query all the children
- //
- if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
- Status = gBS->OpenProtocol (
- OpenInfoBuffer[Index].ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&DevicePath,
- NULL,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Previous = NULL;
- for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
- Previous = Next;
- }
-
- ASSERT (Previous != NULL);
-
- if ((DevicePathType (Previous) == ACPI_DEVICE_PATH) && (DevicePathSubType (Previous) == ACPI_ADR_DP)) {
- Status = gBS->OpenProtocol (
- OpenInfoBuffer[Index].ControllerHandle,
- &gEfiGraphicsOutputProtocolGuid,
- NULL,
- NULL,
- NULL,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- //
- // Append the device path to GOP pool when there is GOP protocol installed.
- //
- TempDevicePath = GopPool;
- GopPool = AppendDevicePathInstance (GopPool, DevicePath);
- gBS->FreePool (TempDevicePath);
- }
- }
-
- if ((DevicePathType (Previous) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (Previous) == HW_CONTROLLER_DP)) {
- //
- // Recursively look for GOP child in this frame buffer handle
- //
- DEBUG ((DEBUG_INFO, "[Bds] Looking for GOP child deeper ... \n"));
- TempDevicePath = GopPool;
- ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
- GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
- gBS->FreePool (ReturnDevicePath);
- gBS->FreePool (TempDevicePath);
- }
- }
- }
-
- FreePool (OpenInfoBuffer);
- }
-
- FreePool (ProtocolBuffer);
-
- return GopPool;
-}
-
-/**
- Connect the platform active active video controller.
-
- @param VideoController PCI handle of video controller.
-
- @retval EFI_NOT_FOUND There is no active video controller.
- @retval EFI_SUCCESS The video controller is connected.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectVideoController (
- EFI_HANDLE VideoController OPTIONAL
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *Gop;
-
- if (VideoController == NULL) {
- //
- // Get the platform vga device
- //
- VideoController = BmGetVideoController ();
- }
-
- if (VideoController == NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Try to connect the PCI device path, so that GOP driver could start on this
- // device and create child handles with GraphicsOutput Protocol installed
- // on them, then we get device paths of these child handles and select
- // them as possible console device.
- //
- gBS->ConnectController (VideoController, NULL, NULL, FALSE);
-
- Gop = EfiBootManagerGetGopDevicePath (VideoController);
- if (Gop == NULL) {
- return EFI_NOT_FOUND;
- }
-
- EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);
- FreePool (Gop);
-
- //
- // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.
- //
- return gBS->ConnectController (VideoController, NULL, NULL, TRUE);
-}
-
-/**
- Fill console handle in System Table if there are no valid console handle in.
-
- Firstly, check the validation of console handle in System Table. If it is invalid,
- update it by the first console device handle from EFI console variable.
-
- @param VarName The name of the EFI console variable.
- @param ConsoleGuid Specified Console protocol GUID.
- @param ConsoleHandle On IN, console handle in System Table to be checked.
- On OUT, new console handle in system table.
- @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
- On OUT, new console protocol on new console handle in system table.
-
- @retval TRUE System Table has been updated.
- @retval FALSE System Table hasn't been updated.
-
-**/
-BOOLEAN
-BmUpdateSystemTableConsole (
- IN CHAR16 *VarName,
- IN EFI_GUID *ConsoleGuid,
- IN OUT EFI_HANDLE *ConsoleHandle,
- IN OUT VOID **ProtocolInterface
- )
-{
- EFI_STATUS Status;
- UINTN DevicePathSize;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *VarConsole;
- EFI_DEVICE_PATH_PROTOCOL *Instance;
- EFI_DEVICE_PATH_PROTOCOL *FullInstance;
- VOID *Interface;
- EFI_HANDLE NewHandle;
- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
-
- ASSERT (VarName != NULL);
- ASSERT (ConsoleHandle != NULL);
- ASSERT (ConsoleGuid != NULL);
- ASSERT (ProtocolInterface != NULL);
-
- if (*ConsoleHandle != NULL) {
- Status = gBS->HandleProtocol (
- *ConsoleHandle,
- ConsoleGuid,
- &Interface
- );
- if ((Status == EFI_SUCCESS) && (Interface == *ProtocolInterface)) {
- //
- // If ConsoleHandle is valid and console protocol on this handle also
- // also matched, just return.
- //
- return FALSE;
- }
- }
-
- //
- // Get all possible consoles device path from EFI variable
- //
- GetEfiGlobalVariable2 (VarName, (VOID **)&VarConsole, NULL);
- if (VarConsole == NULL) {
- //
- // If there is no any console device, just return.
- //
- return FALSE;
- }
-
- FullDevicePath = VarConsole;
-
- do {
- //
- // Check every instance of the console variable
- //
- Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
- if (Instance == NULL) {
- DEBUG ((DEBUG_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
- // We should not ASSERT when all the console devices are removed.
- // ASSERT_EFI_ERROR (EFI_NOT_FOUND);
- FreePool (FullDevicePath);
- return FALSE;
- }
-
- //
- // Find console device handle by device path instance
- //
- FullInstance = Instance;
- Status = gBS->LocateDevicePath (
- ConsoleGuid,
- &Instance,
- &NewHandle
- );
- FreePool (FullInstance);
- if (!EFI_ERROR (Status)) {
- //
- // Get the console protocol on this console device handle
- //
- Status = gBS->HandleProtocol (
- NewHandle,
- ConsoleGuid,
- &Interface
- );
- if (!EFI_ERROR (Status)) {
- //
- // Update new console handle in System Table.
- //
- *ConsoleHandle = NewHandle;
- *ProtocolInterface = Interface;
- if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
- //
- // If it is console out device, set console mode 80x25 if current mode is invalid.
- //
- TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Interface;
- if (TextOut->Mode->Mode == -1) {
- TextOut->SetMode (TextOut, 0);
- }
- }
-
- FreePool (FullDevicePath);
- return TRUE;
- }
- }
- } while (Instance != NULL);
-
- //
- // No any available console devcie found.
- //
- FreePool (FullDevicePath);
- return FALSE;
-}
-
-/**
- This function updates the console variable based on ConVarName. It can
- add or remove one specific console device path from the variable
-
- @param ConsoleType ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
- @param CustomizedConDevicePath The console device path to be added to
- the console variable. Cannot be multi-instance.
- @param ExclusiveDevicePath The console device path to be removed
- from the console variable. Cannot be multi-instance.
-
- @retval EFI_UNSUPPORTED The added device path is the same as a removed one.
- @retval EFI_SUCCESS Successfully added or removed the device path from the
- console variable.
- @retval others Return status of RT->SetVariable().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerUpdateConsoleVariable (
- IN CONSOLE_TYPE ConsoleType,
- IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
- IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *VarConsole;
- EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
-
- if (ConsoleType >= ARRAY_SIZE (mConVarName)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Notes: check the device path point, here should check
- // with compare memory
- //
- if (CustomizedConDevicePath == ExclusiveDevicePath) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Delete the ExclusiveDevicePath from current default console
- //
- GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **)&VarConsole, NULL);
- //
- // Initialize NewDevicePath
- //
- NewDevicePath = VarConsole;
-
- //
- // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
- // In the end, NewDevicePath is the final device path.
- //
- if ((ExclusiveDevicePath != NULL) && (VarConsole != NULL)) {
- NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
- }
-
- //
- // Try to append customized device path to NewDevicePath.
- //
- if (CustomizedConDevicePath != NULL) {
- if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
- //
- // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
- //
- NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
- //
- // In the first check, the default console variable will be _ModuleEntryPoint,
- // just append current customized device path
- //
- TempNewDevicePath = NewDevicePath;
- NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
- if (TempNewDevicePath != NULL) {
- FreePool (TempNewDevicePath);
- }
- }
- }
-
- //
- // Finally, Update the variable of the default console by NewDevicePath
- //
- Status = gRT->SetVariable (
- mConVarName[ConsoleType],
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
- | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),
- GetDevicePathSize (NewDevicePath),
- NewDevicePath
- );
-
- if (VarConsole == NewDevicePath) {
- if (VarConsole != NULL) {
- FreePool (VarConsole);
- }
- } else {
- if (VarConsole != NULL) {
- FreePool (VarConsole);
- }
-
- if (NewDevicePath != NULL) {
- FreePool (NewDevicePath);
- }
- }
-
- return Status;
-}
-
-/**
- Connect the console device base on the variable ConsoleType.
-
- @param ConsoleType ConIn, ConOut or ErrOut.
-
- @retval EFI_NOT_FOUND There is not any console devices connected
- success
- @retval EFI_SUCCESS Success connect any one instance of the console
- device path base on the variable ConVarName.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectConsoleVariable (
- IN CONSOLE_TYPE ConsoleType
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *Instance;
- EFI_DEVICE_PATH_PROTOCOL *Next;
- EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
- UINTN Size;
- BOOLEAN DeviceExist;
- EFI_HANDLE Handle;
-
- if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = EFI_SUCCESS;
- DeviceExist = FALSE;
- Handle = NULL;
-
- //
- // Check if the console variable exist
- //
- GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **)&StartDevicePath, NULL);
- if (StartDevicePath == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- CopyOfDevicePath = StartDevicePath;
- do {
- //
- // Check every instance of the console variable
- //
- Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
- if (Instance == NULL) {
- FreePool (StartDevicePath);
- return EFI_UNSUPPORTED;
- }
-
- Next = Instance;
- while (!IsDevicePathEndType (Next)) {
- Next = NextDevicePathNode (Next);
- }
-
- SetDevicePathEndNode (Next);
- //
- // Connect the USB console
- // USB console device path is a short-form device path that
- // starts with the first element being a USB WWID
- // or a USB Class device path
- //
- if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP))
- )
- {
- Status = BmConnectUsbShortFormDevicePath (Instance);
- if (!EFI_ERROR (Status)) {
- DeviceExist = TRUE;
- }
- } else {
- for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
- if ((DevicePathType (Next) == ACPI_DEVICE_PATH) && (DevicePathSubType (Next) == ACPI_ADR_DP)) {
- break;
- } else if ((DevicePathType (Next) == HARDWARE_DEVICE_PATH) &&
- (DevicePathSubType (Next) == HW_CONTROLLER_DP) &&
- (DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH) &&
- (DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP)
- )
- {
- break;
- }
- }
-
- if (!IsDevicePathEnd (Next)) {
- //
- // For GOP device path, start the video driver with NULL remaining device path
- //
- SetDevicePathEndNode (Next);
- Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
- if (!EFI_ERROR (Status)) {
- gBS->ConnectController (Handle, NULL, NULL, TRUE);
- }
- } else {
- Status = EfiBootManagerConnectDevicePath (Instance, NULL);
- }
-
- if (EFI_ERROR (Status)) {
- //
- // Delete the instance from the console varialbe
- //
- EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);
- } else {
- DeviceExist = TRUE;
- }
- }
-
- FreePool (Instance);
- } while (CopyOfDevicePath != NULL);
-
- FreePool (StartDevicePath);
-
- if (!DeviceExist) {
- return EFI_NOT_FOUND;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This function will search every input/output device in current system,
- and make every input/output device as potential console device.
-**/
-VOID
-EFIAPI
-EfiBootManagerConnectAllConsoles (
- VOID
- )
-{
- UINTN Index;
- EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
- UINTN HandleCount;
- EFI_HANDLE *HandleBuffer;
-
- Index = 0;
- HandleCount = 0;
- HandleBuffer = NULL;
- ConDevicePath = NULL;
-
- //
- // Update all the console variables
- //
- gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiSimpleTextInProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
-
- for (Index = 0; Index < HandleCount; Index++) {
- gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- (VOID **)&ConDevicePath
- );
- EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL);
- }
-
- if (HandleBuffer != NULL) {
- FreePool (HandleBuffer);
- HandleBuffer = NULL;
- }
-
- gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiSimpleTextOutProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- for (Index = 0; Index < HandleCount; Index++) {
- gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- (VOID **)&ConDevicePath
- );
- EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);
- EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);
- }
-
- if (HandleBuffer != NULL) {
- FreePool (HandleBuffer);
- }
-
- //
- // Connect all console variables
- //
- EfiBootManagerConnectAllDefaultConsoles ();
-}
-
-/**
- This function will connect all the console devices base on the console
- device variable ConIn, ConOut and ErrOut.
-
- @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
- @retval EFI_SUCCESS Success connect any one instance of the console
- device path base on the variable ConVarName.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectAllDefaultConsoles (
- VOID
- )
-{
- EFI_STATUS Status;
- BOOLEAN OneConnected;
- BOOLEAN SystemTableUpdated;
-
- OneConnected = FALSE;
-
- Status = EfiBootManagerConnectConsoleVariable (ConOut);
- if (!EFI_ERROR (Status)) {
- OneConnected = TRUE;
- }
-
- PERF_EVENT ("ConOutReady");
-
- Status = EfiBootManagerConnectConsoleVariable (ConIn);
- if (!EFI_ERROR (Status)) {
- OneConnected = TRUE;
- }
-
- PERF_EVENT ("ConInReady");
-
- Status = EfiBootManagerConnectConsoleVariable (ErrOut);
- if (!EFI_ERROR (Status)) {
- OneConnected = TRUE;
- }
-
- PERF_EVENT ("ErrOutReady");
-
- SystemTableUpdated = FALSE;
- //
- // Fill console handles in System Table if no console device assignd.
- //
- if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn)) {
- SystemTableUpdated = TRUE;
- }
-
- if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut)) {
- SystemTableUpdated = TRUE;
- }
-
- if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr)) {
- SystemTableUpdated = TRUE;
- }
-
- if (SystemTableUpdated) {
- //
- // Update the CRC32 in the EFI System Table header
- //
- gST->Hdr.CRC32 = 0;
- gBS->CalculateCrc32 (
- (UINT8 *)&gST->Hdr,
- gST->Hdr.HeaderSize,
- &gST->Hdr.CRC32
- );
- }
-
- return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
-}
+/** @file + Library functions which contain all the code to connect console device. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalBm.h" + +CHAR16 *mConVarName[] = { + L"ConIn", + L"ConOut", + L"ErrOut", + L"ConInDev", + L"ConOutDev", + L"ErrOutDev" +}; + +/** + Search out the video controller. + + @return PCI device path of the video controller. +**/ +EFI_HANDLE +BmGetVideoController ( + VOID + ) +{ + EFI_STATUS Status; + UINTN RootBridgeHandleCount; + EFI_HANDLE *RootBridgeHandleBuffer; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN RootBridgeIndex; + UINTN Index; + EFI_HANDLE VideoController; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Make all the PCI_IO protocols show up + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &RootBridgeHandleCount, + &RootBridgeHandleBuffer + ); + if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) { + return NULL; + } + + VideoController = NULL; + for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) { + gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE); + + // + // Start to check all the pci io to find the first video controller + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&PciIo); + if (!EFI_ERROR (Status)) { + // + // Check for all video controller + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) { + // TODO: use IS_PCI_DISPLAY?? + VideoController = HandleBuffer[Index]; + break; + } + } + } + + FreePool (HandleBuffer); + + if (VideoController != NULL) { + break; + } + } + + FreePool (RootBridgeHandleBuffer); + + return VideoController; +} + +/** + Query all the children of VideoController and return the device paths of all the + children that support GraphicsOutput protocol. + + @param VideoController PCI handle of video controller. + + @return Device paths of all the children that support GraphicsOutput protocol. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiBootManagerGetGopDevicePath ( + IN EFI_HANDLE VideoController + ) +{ + UINTN Index; + EFI_STATUS Status; + EFI_GUID **ProtocolBuffer; + UINTN ProtocolBufferCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *Next; + EFI_DEVICE_PATH_PROTOCOL *Previous; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *GopPool; + EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath; + + Status = gBS->ProtocolsPerHandle ( + VideoController, + &ProtocolBuffer, + &ProtocolBufferCount + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + GopPool = NULL; + + for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) { + Status = gBS->OpenProtocolInformation ( + VideoController, + ProtocolBuffer[ProtocolIndex], + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (Index = 0; Index < EntryCount; Index++) { + // + // Query all the children + // + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&DevicePath, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + Previous = NULL; + for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) { + Previous = Next; + } + + ASSERT (Previous != NULL); + + if ((DevicePathType (Previous) == ACPI_DEVICE_PATH) && (DevicePathSubType (Previous) == ACPI_ADR_DP)) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiGraphicsOutputProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Append the device path to GOP pool when there is GOP protocol installed. + // + TempDevicePath = GopPool; + GopPool = AppendDevicePathInstance (GopPool, DevicePath); + gBS->FreePool (TempDevicePath); + } + } + + if ((DevicePathType (Previous) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (Previous) == HW_CONTROLLER_DP)) { + // + // Recursively look for GOP child in this frame buffer handle + // + DEBUG ((DEBUG_INFO, "[Bds] Looking for GOP child deeper ... \n")); + TempDevicePath = GopPool; + ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle); + GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath); + gBS->FreePool (ReturnDevicePath); + gBS->FreePool (TempDevicePath); + } + } + } + + FreePool (OpenInfoBuffer); + } + + FreePool (ProtocolBuffer); + + return GopPool; +} + +/** + Connect the platform active active video controller. + + @param VideoController PCI handle of video controller. + + @retval EFI_NOT_FOUND There is no active video controller. + @retval EFI_SUCCESS The video controller is connected. +**/ +EFI_STATUS +EFIAPI +EfiBootManagerConnectVideoController ( + EFI_HANDLE VideoController OPTIONAL + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Gop; + + if (VideoController == NULL) { + // + // Get the platform vga device + // + VideoController = BmGetVideoController (); + } + + if (VideoController == NULL) { + return EFI_NOT_FOUND; + } + + // + // Try to connect the PCI device path, so that GOP driver could start on this + // device and create child handles with GraphicsOutput Protocol installed + // on them, then we get device paths of these child handles and select + // them as possible console device. + // + gBS->ConnectController (VideoController, NULL, NULL, FALSE); + + Gop = EfiBootManagerGetGopDevicePath (VideoController); + if (Gop == NULL) { + return EFI_NOT_FOUND; + } + + EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL); + FreePool (Gop); + + // + // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated. + // + return gBS->ConnectController (VideoController, NULL, NULL, TRUE); +} + +/** + Fill console handle in System Table if there are no valid console handle in. + + Firstly, check the validation of console handle in System Table. If it is invalid, + update it by the first console device handle from EFI console variable. + + @param VarName The name of the EFI console variable. + @param ConsoleGuid Specified Console protocol GUID. + @param ConsoleHandle On IN, console handle in System Table to be checked. + On OUT, new console handle in system table. + @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked. + On OUT, new console protocol on new console handle in system table. + + @retval TRUE System Table has been updated. + @retval FALSE System Table hasn't been updated. + +**/ +BOOLEAN +BmUpdateSystemTableConsole ( + IN CHAR16 *VarName, + IN EFI_GUID *ConsoleGuid, + IN OUT EFI_HANDLE *ConsoleHandle, + IN OUT VOID **ProtocolInterface + ) +{ + EFI_STATUS Status; + UINTN DevicePathSize; + EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; + EFI_DEVICE_PATH_PROTOCOL *VarConsole; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *FullInstance; + VOID *Interface; + EFI_HANDLE NewHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; + + ASSERT (VarName != NULL); + ASSERT (ConsoleHandle != NULL); + ASSERT (ConsoleGuid != NULL); + ASSERT (ProtocolInterface != NULL); + + if (*ConsoleHandle != NULL) { + Status = gBS->HandleProtocol ( + *ConsoleHandle, + ConsoleGuid, + &Interface + ); + if ((Status == EFI_SUCCESS) && (Interface == *ProtocolInterface)) { + // + // If ConsoleHandle is valid and console protocol on this handle also + // also matched, just return. + // + return FALSE; + } + } + + // + // Get all possible consoles device path from EFI variable + // + GetEfiGlobalVariable2 (VarName, (VOID **)&VarConsole, NULL); + if (VarConsole == NULL) { + // + // If there is no any console device, just return. + // + return FALSE; + } + + FullDevicePath = VarConsole; + + do { + // + // Check every instance of the console variable + // + Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize); + if (Instance == NULL) { + DEBUG ((DEBUG_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName)); + // We should not ASSERT when all the console devices are removed. + // ASSERT_EFI_ERROR (EFI_NOT_FOUND); + FreePool (FullDevicePath); + return FALSE; + } + + // + // Find console device handle by device path instance + // + FullInstance = Instance; + Status = gBS->LocateDevicePath ( + ConsoleGuid, + &Instance, + &NewHandle + ); + FreePool (FullInstance); + if (!EFI_ERROR (Status)) { + // + // Get the console protocol on this console device handle + // + Status = gBS->HandleProtocol ( + NewHandle, + ConsoleGuid, + &Interface + ); + if (!EFI_ERROR (Status)) { + // + // Update new console handle in System Table. + // + *ConsoleHandle = NewHandle; + *ProtocolInterface = Interface; + if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) { + // + // If it is console out device, set console mode 80x25 if current mode is invalid. + // + TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Interface; + if (TextOut->Mode->Mode == -1) { + TextOut->SetMode (TextOut, 0); + } + } + + FreePool (FullDevicePath); + return TRUE; + } + } + } while (Instance != NULL); + + // + // No any available console devcie found. + // + FreePool (FullDevicePath); + return FALSE; +} + +/** + This function updates the console variable based on ConVarName. It can + add or remove one specific console device path from the variable + + @param ConsoleType ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev. + @param CustomizedConDevicePath The console device path to be added to + the console variable. Cannot be multi-instance. + @param ExclusiveDevicePath The console device path to be removed + from the console variable. Cannot be multi-instance. + + @retval EFI_UNSUPPORTED The added device path is the same as a removed one. + @retval EFI_SUCCESS Successfully added or removed the device path from the + console variable. + @retval others Return status of RT->SetVariable(). + +**/ +EFI_STATUS +EFIAPI +EfiBootManagerUpdateConsoleVariable ( + IN CONSOLE_TYPE ConsoleType, + IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *VarConsole; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; + + if (ConsoleType >= ARRAY_SIZE (mConVarName)) { + return EFI_INVALID_PARAMETER; + } + + // + // Notes: check the device path point, here should check + // with compare memory + // + if (CustomizedConDevicePath == ExclusiveDevicePath) { + return EFI_UNSUPPORTED; + } + + // + // Delete the ExclusiveDevicePath from current default console + // + GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **)&VarConsole, NULL); + // + // Initialize NewDevicePath + // + NewDevicePath = VarConsole; + + // + // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it. + // In the end, NewDevicePath is the final device path. + // + if ((ExclusiveDevicePath != NULL) && (VarConsole != NULL)) { + NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath); + } + + // + // Try to append customized device path to NewDevicePath. + // + if (CustomizedConDevicePath != NULL) { + if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) { + // + // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it. + // + NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath); + // + // In the first check, the default console variable will be _ModuleEntryPoint, + // just append current customized device path + // + TempNewDevicePath = NewDevicePath; + NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath); + if (TempNewDevicePath != NULL) { + FreePool (TempNewDevicePath); + } + } + } + + // + // Finally, Update the variable of the default console by NewDevicePath + // + Status = gRT->SetVariable ( + mConVarName[ConsoleType], + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0), + GetDevicePathSize (NewDevicePath), + NewDevicePath + ); + + if (VarConsole == NewDevicePath) { + if (VarConsole != NULL) { + FreePool (VarConsole); + } + } else { + if (VarConsole != NULL) { + FreePool (VarConsole); + } + + if (NewDevicePath != NULL) { + FreePool (NewDevicePath); + } + } + + return Status; +} + +/** + Connect the console device base on the variable ConsoleType. + + @param ConsoleType ConIn, ConOut or ErrOut. + + @retval EFI_NOT_FOUND There is not any console devices connected + success + @retval EFI_SUCCESS Success connect any one instance of the console + device path base on the variable ConVarName. + +**/ +EFI_STATUS +EFIAPI +EfiBootManagerConnectConsoleVariable ( + IN CONSOLE_TYPE ConsoleType + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *StartDevicePath; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *Next; + EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; + UINTN Size; + BOOLEAN DeviceExist; + EFI_HANDLE Handle; + + if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + DeviceExist = FALSE; + Handle = NULL; + + // + // Check if the console variable exist + // + GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **)&StartDevicePath, NULL); + if (StartDevicePath == NULL) { + return EFI_UNSUPPORTED; + } + + CopyOfDevicePath = StartDevicePath; + do { + // + // Check every instance of the console variable + // + Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size); + if (Instance == NULL) { + FreePool (StartDevicePath); + return EFI_UNSUPPORTED; + } + + Next = Instance; + while (!IsDevicePathEndType (Next)) { + Next = NextDevicePathNode (Next); + } + + SetDevicePathEndNode (Next); + // + // Connect the USB console + // USB console device path is a short-form device path that + // starts with the first element being a USB WWID + // or a USB Class device path + // + if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)) + ) + { + Status = BmConnectUsbShortFormDevicePath (Instance); + if (!EFI_ERROR (Status)) { + DeviceExist = TRUE; + } + } else { + for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) { + if ((DevicePathType (Next) == ACPI_DEVICE_PATH) && (DevicePathSubType (Next) == ACPI_ADR_DP)) { + break; + } else if ((DevicePathType (Next) == HARDWARE_DEVICE_PATH) && + (DevicePathSubType (Next) == HW_CONTROLLER_DP) && + (DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH) && + (DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP) + ) + { + break; + } + } + + if (!IsDevicePathEnd (Next)) { + // + // For GOP device path, start the video driver with NULL remaining device path + // + SetDevicePathEndNode (Next); + Status = EfiBootManagerConnectDevicePath (Instance, &Handle); + if (!EFI_ERROR (Status)) { + gBS->ConnectController (Handle, NULL, NULL, TRUE); + } + } else { + Status = EfiBootManagerConnectDevicePath (Instance, NULL); + } + + if (EFI_ERROR (Status)) { + // + // Delete the instance from the console varialbe + // + EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance); + } else { + DeviceExist = TRUE; + } + } + + FreePool (Instance); + } while (CopyOfDevicePath != NULL); + + FreePool (StartDevicePath); + + if (!DeviceExist) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + This function will search every input/output device in current system, + and make every input/output device as potential console device. +**/ +VOID +EFIAPI +EfiBootManagerConnectAllConsoles ( + VOID + ) +{ + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ConDevicePath; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + + Index = 0; + HandleCount = 0; + HandleBuffer = NULL; + ConDevicePath = NULL; + + // + // Update all the console variables + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextInProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + for (Index = 0; Index < HandleCount; Index++) { + gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&ConDevicePath + ); + EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextOutProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + for (Index = 0; Index < HandleCount; Index++) { + gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&ConDevicePath + ); + EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL); + EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + // + // Connect all console variables + // + EfiBootManagerConnectAllDefaultConsoles (); +} + +/** + This function will connect all the console devices base on the console + device variable ConIn, ConOut and ErrOut. + + @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error. + @retval EFI_SUCCESS Success connect any one instance of the console + device path base on the variable ConVarName. +**/ +EFI_STATUS +EFIAPI +EfiBootManagerConnectAllDefaultConsoles ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN OneConnected; + BOOLEAN SystemTableUpdated; + + OneConnected = FALSE; + + Status = EfiBootManagerConnectConsoleVariable (ConOut); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } + + PERF_EVENT ("ConOutReady"); + + Status = EfiBootManagerConnectConsoleVariable (ConIn); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } + + PERF_EVENT ("ConInReady"); + + Status = EfiBootManagerConnectConsoleVariable (ErrOut); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } + + PERF_EVENT ("ErrOutReady"); + + SystemTableUpdated = FALSE; + // + // Fill console handles in System Table if no console device assignd. + // + if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn)) { + SystemTableUpdated = TRUE; + } + + if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut)) { + SystemTableUpdated = TRUE; + } + + if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr)) { + SystemTableUpdated = TRUE; + } + + if (SystemTableUpdated) { + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + } + + return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR; +} |
