/** @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; | |
} |