2019-09-03 11:58:42 +02:00
|
|
|
/** @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
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status) || (RootBridgeHandleCount == 0)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
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
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Check for all video controller
|
|
|
|
//
|
|
|
|
Status = PciIo->Pci.Read (
|
|
|
|
PciIo,
|
|
|
|
EfiPciIoWidthUint32,
|
|
|
|
0,
|
|
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
|
|
&Pci
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status) && IS_PCI_VGA (&Pci)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
// TODO: use IS_PCI_DISPLAY??
|
|
|
|
VideoController = HandleBuffer[Index];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(HandleBuffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
if (VideoController != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(RootBridgeHandleBuffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
GopPool = NULL;
|
|
|
|
|
|
|
|
for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
|
|
|
|
Status = gBS->OpenProtocolInformation (
|
|
|
|
VideoController,
|
|
|
|
ProtocolBuffer[ProtocolIndex],
|
|
|
|
&OpenInfoBuffer,
|
|
|
|
&EntryCount
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
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
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
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
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Append the device path to GOP pool when there is GOP protocol installed.
|
|
|
|
//
|
|
|
|
TempDevicePath = GopPool;
|
|
|
|
GopPool = AppendDevicePathInstance (GopPool, DevicePath);
|
2020-04-23 11:08:10 +02:00
|
|
|
gBS->FreePool(TempDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {
|
|
|
|
//
|
|
|
|
// Recursively look for GOP child in this frame buffer handle
|
|
|
|
//
|
|
|
|
DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));
|
|
|
|
TempDevicePath = GopPool;
|
|
|
|
ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
|
|
|
|
GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
|
2020-04-23 11:08:10 +02:00
|
|
|
gBS->FreePool(ReturnDevicePath);
|
|
|
|
gBS->FreePool(TempDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(OpenInfoBuffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(ProtocolBuffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(Gop);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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 ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
|
|
|
|
// We should not ASSERT when all the console devices are removed.
|
2020-04-23 11:08:10 +02:00
|
|
|
// ASSERT_EFI_ERROR(EFI_NOT_FOUND);
|
|
|
|
FreePool(FullDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Find console device handle by device path instance
|
|
|
|
//
|
|
|
|
FullInstance = Instance;
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
|
|
ConsoleGuid,
|
|
|
|
&Instance,
|
|
|
|
&NewHandle
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(FullInstance);
|
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Get the console protocol on this console device handle
|
|
|
|
//
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
NewHandle,
|
|
|
|
ConsoleGuid,
|
|
|
|
&Interface
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(FullDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (Instance != NULL);
|
|
|
|
|
|
|
|
//
|
|
|
|
// No any available console devcie found.
|
|
|
|
//
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(FullDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
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) {
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StartDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
gBS->ConnectController (Handle, NULL, NULL, TRUE);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Status = EfiBootManagerConnectDevicePath (Instance, NULL);
|
|
|
|
}
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Delete the instance from the console varialbe
|
|
|
|
//
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);
|
|
|
|
} else {
|
|
|
|
DeviceExist = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FreePool(Instance);
|
|
|
|
} while (CopyOfDevicePath != NULL);
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StartDevicePath);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
OneConnected = TRUE;
|
|
|
|
}
|
|
|
|
PERF_EVENT ("ConOutReady");
|
|
|
|
|
|
|
|
|
|
|
|
Status = EfiBootManagerConnectConsoleVariable (ConIn);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
OneConnected = TRUE;
|
|
|
|
}
|
|
|
|
PERF_EVENT ("ConInReady");
|
|
|
|
|
|
|
|
Status = EfiBootManagerConnectConsoleVariable (ErrOut);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
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;
|
|
|
|
}
|