mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-28 17:08:18 +01:00
762 lines
23 KiB
C
762 lines
23 KiB
C
|
/** @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 ((EFI_D_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 ((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.
|
||
|
// 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;
|
||
|
}
|