alder_lake_bios/Insyde/InsydeCrPkg/CrServiceDxe/CrServiceDxe.c

578 lines
15 KiB
C

/** @file
CrServiceDxe driver
;******************************************************************************
;* Copyright (c) 2012 - 2013, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "CrServiceDxe.h"
#include "CrVariableUpdate.h"
#include "CrLegacySupport.h"
BOOLEAN mCrEnable;
BOOLEAN mHeadless;
EFI_HANDLE mCrServiceImageHandle;
H2O_BDS_CP_HANDLE mCpConOutHandle;
CR_POLICY_VARIABLE mCrPolicy;
extern CR_DEVICES_SETTING_HEAD_NODE mCrVarDeviceHead;
extern UINT32 mCrBaudRateTable[];
EFI_STATUS
DummyQueryVgaScreenBuffer (
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
IN OUT UINTN *ScreenBuffer,
IN OUT UINTN *ScreenAttributes
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
DummyDisconnectCrsTerminal (
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
UINTN TerminalNumber
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
DummyconnectCrsTerminal (
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
UINTN TerminalNumber
)
{
return EFI_UNSUPPORTED;
}
/**
Query Consplitter screen buffer and attribute buffer
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
@param ScreenBuffer A pointer to current screen buffer.
@param ScreenAttributes A pointer to current attribute buffer.
@retval EFI_SUCCESS Get Screen Buffer Success
@retval EFI_UNSUPPORTED Get Screen Buffer fail
**/
EFI_STATUS
EFIAPI
QueryVgaScreenBuffer (
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
IN OUT UINTN *ScreenBuffer,
IN OUT UINTN *ScreenAttributes
)
{
UINTN ConsplitterScreenBuf;
UINTN ConsplitterAttrBuf;
ConsplitterScreenBuf = 0;
ConsplitterAttrBuf = 0;
ConsplitterScreenBuf = (UINTN)PcdGet64 (PcdDevNullScreenPtr);
ConsplitterAttrBuf = (UINTN)PcdGet64 (PcdDevNullAttributes);
if (ConsplitterScreenBuf == 0 || ConsplitterAttrBuf == 0) {
return EFI_UNSUPPORTED;
}
*ScreenBuffer = ConsplitterScreenBuf;
*ScreenAttributes = ConsplitterAttrBuf;
return EFI_SUCCESS;
}
/**
Disconnect Console Redirection Terminal controller.
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
@param TerminalNumber Specify the terminal index that will be disconnect. The first index number is 0.
@retval EFI_SUCCESS Disconnect success
@retval EFI_INVALID_PARAMETER The Terminal number is invalid
@retval others Disconnect fail
**/
EFI_STATUS
EFIAPI
DisconnectCrTerminal (
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
IN UINTN TerminalNumber
)
{
EFI_STATUS Status;
EFI_CONSOLE_REDIRECTION_INFO *CrInfo;
EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath;
EFI_HANDLE ChildHandle;
EFI_HANDLE ParentHandle;
CrInfo = This->CRInfo;
if (TerminalNumber >= CrInfo->DeviceCount) {
return EFI_INVALID_PARAMETER;
}
ChildDevicePath = CrInfo->CRDevice[TerminalNumber].DevicePath;
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid , &ChildDevicePath, &ChildHandle);
if (!EFI_ERROR (Status) && IsDevicePathEnd (ChildDevicePath)) {
Status = GetParentHandle (ChildHandle, &ParentHandle);
if (!EFI_ERROR(Status)) {
Status = gBS->DisconnectController (ParentHandle, NULL, NULL);
}
}
return Status;
}
/**
Connect Console Redirection Terminal controller.
@param This A pointer to the EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL instance.
@param TerminalNumber Specify the terminal index that will be Connect. The first index number is 0.
@retval EFI_SUCCESS Connect success
@retval EFI_INVALID_PARAMETER The Terminal number is invalid
@retval EFI_ABORTED Can't duplicate device path.
@retval others Connect fail
**/
EFI_STATUS
EFIAPI
ConnectCrTerminal (
IN EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *This,
IN UINTN TerminalNumber
)
{
EFI_STATUS Status;
EFI_CONSOLE_REDIRECTION_INFO *CrInfo;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_PROTOCOL *OriginalDevicePath;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_HANDLE ParentHandle;
CrInfo = This->CRInfo;
if (TerminalNumber >= CrInfo->DeviceCount) {
return EFI_INVALID_PARAMETER;
}
OriginalDevicePath = DuplicateDevicePath (CrInfo->CRDevice[TerminalNumber].DevicePath);
if (OriginalDevicePath == NULL) {
return EFI_ABORTED;
}
RemainingDevicePath = CrInfo->CRDevice[TerminalNumber].DevicePath;
DevicePath = OriginalDevicePath;
TruncateLastNode (DevicePath);
PointToLastNode (&RemainingDevicePath);
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid , &DevicePath, &ParentHandle);
if (!EFI_ERROR (Status) && IsDevicePathEnd (DevicePath)) {
Status = gBS->ConnectController (ParentHandle, NULL, RemainingDevicePath, TRUE);
}
gBS->FreePool (OriginalDevicePath);
return Status;
}
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL mDummyCRService = {
NULL,
DummyQueryVgaScreenBuffer,
DummyDisconnectCrsTerminal,
DummyconnectCrsTerminal
};
EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL mCrService = {
NULL,
QueryVgaScreenBuffer,
DisconnectCrTerminal,
ConnectCrTerminal
};
/**
@param
@retval
**/
BOOLEAN
IsHeadlessPlatform (
VOID
)
{
EFI_STATUS Status;
UINTN NumHandles;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 PciConfig;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&NumHandles,
&HandleBuffer
);
if (EFI_ERROR(Status)) {
return TRUE;
}
for (Index = 0; Index < NumHandles; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo
);
if (EFI_ERROR(Status)) {
continue;
}
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
0,
sizeof(PCI_TYPE00),
&PciConfig
);
if (EFI_ERROR(Status)) {
continue;
}
if (PciConfig.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) {
return FALSE;
}
}
CrSafeFreePool (HandleBuffer);
return TRUE;
}
/**
@param
@retval
**/
VOID
UpdateCrStatus (
VOID
)
{
CR_POLICY_VARIABLE *Tmp;
Tmp = NULL;
Tmp = (CR_POLICY_VARIABLE*) CommonGetVariableData (CR_POLICY_NAME, &gH2OCrConfigurationGuid);
if (Tmp == NULL) {
mCrEnable = FALSE;
DEBUG ((EFI_D_INFO, "\nCr << %a >> C.R. Disable\n", __FUNCTION__));
return;
}
CopyMem (&mCrPolicy, Tmp, sizeof(CR_POLICY_VARIABLE));
mCrEnable = TRUE;
if (IsHeadlessPlatform()) {
mHeadless = TRUE;
mCrEnable = TRUE;
} else {
mHeadless = FALSE;
}
DEBUG ((EFI_D_INFO, "\nCr << %a >> C.R. Enable, Headless:%d\n", __FUNCTION__, mHeadless));
FreePool (Tmp);
}
UINTN
GetNumberOfActiveCrDevice (
VOID
)
{
LIST_ENTRY *Link;
CR_DEVICES_SETTING_NODE *CrDevNode;
UINTN Count;
Count = 0;
Link = GetFirstNode (&mCrVarDeviceHead.Link);
while (!IsNull (&mCrVarDeviceHead.Link, Link)) {
CrDevNode = CR_DEVICE_SETTING_FROM_THIS (Link);
if (CrDevNode->AddIntoConVar == FALSE) {
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
continue;
}
Count++;
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
}
return Count;
}
EFI_CONSOLE_REDIRECTION_INFO *
BuildCrInfo (
VOID
)
{
UINTN DeviceCount;
UINTN DeviceIndex;
UINTN BufferSize;
EFI_CONSOLE_REDIRECTION_INFO *CRInfo;
LIST_ENTRY *Link;
CR_DEVICES_SETTING_NODE *CrDevNode;
EFI_DEVICE_PATH *RemainDevPath;
EFI_DEVICE_PATH_PROTOCOL *DevPathProtocol;
EFI_STATUS Status;
H2O_UART_16550_ACCESS_PROTOCOL *Uart16550Protocol;
UART_16550_DEVICE_INFO *DeviceInfo;
CRInfo = NULL;
DeviceIndex = 0;
DeviceCount = GetNumberOfActiveCrDevice ();
if (DeviceCount == 0) {
return NULL;
}
BufferSize = sizeof(EFI_CONSOLE_REDIRECTION_INFO) + (DeviceCount * sizeof (EFI_CONSOLE_REDIRECTION_DEVICE));
CRInfo = AllocateZeroPool (BufferSize);
if (CRInfo == NULL) {
return CRInfo;
}
CRInfo->Headless = mHeadless;
Link = GetFirstNode (&mCrVarDeviceHead.Link);
while (!IsNull (&mCrVarDeviceHead.Link, Link)) {
CrDevNode = CR_DEVICE_SETTING_FROM_THIS (Link);
if (CrDevNode->AddIntoConVar == FALSE) {
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
continue;
}
RemainDevPath = GetDevicePathFromCrDevSetting(CrDevNode->CrSetting);
Status = GetProtocolWithLocateDevicePath (&gH2OCrUart16550AccessProtocolGuid, &RemainDevPath, &Uart16550Protocol);
if (EFI_ERROR (Status)) {
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
continue;
}
DeviceInfo = Uart16550Protocol->DeviceInfo;
CRInfo->CRDevice[DeviceIndex].Uart16550protocol = Uart16550Protocol;
CRInfo->CRDevice[DeviceIndex].Type = DeviceInfo->DeviceType;
CRInfo->CRDevice[DeviceIndex].BaudRateDivisor = (UINT8)(DeviceInfo->SerialClockFreq / DeviceInfo->SampleRate / mCrBaudRateTable[CrDevNode->CrSetting->Attribute.BaudRate]);
RemainDevPath = GetDevicePathFromCrDevSetting(CrDevNode->CrSetting);
Status = GetProtocolWithLocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainDevPath, &DevPathProtocol);
if (!EFI_ERROR (Status)) {
CRInfo->CRDevice[DeviceIndex].DevicePath = DevPathProtocol;
}
Link = GetNextNode (&mCrVarDeviceHead.Link, Link);
DeviceIndex ++;
}
CRInfo->DeviceCount = (UINT8)DeviceIndex;
return CRInfo;
}
/**
Before connect console device, CRservice need to add CR devices path into ConIn/ConOut variable.
@param
@retval
**/
VOID
BeforeConnectConsoleCallback (
IN EFI_EVENT Event,
IN H2O_BDS_CP_HANDLE Handle
)
{
static BOOLEAN IsDone = FALSE;
if (IsDone == TRUE) {
return;
}
IsDone = TRUE;
//
// If SCU set CrEnable or headless then set CrEnable.
//
UpdateCrStatus ();
//
// Create a temp device list for access current Cr Device Variable.
//
CreateCrDeviceVarList ();
//
// Update CR device setting value from H2OSerialConfigLib
//
UpdateCrDeviceSetting ();
//
// Add Enable CR devices to ConIn/ConOut Variable
//
UpdateConInConOutVarFromActiveDevicePath ();
}
VOID
AfterConnectConOutCallBack (
IN EFI_EVENT Event,
IN H2O_BDS_CP_HANDLE Handle
)
{
EFI_STATUS Status;
if (mCrEnable) {
//
// Check the select Cr devices still in Con Variable?
// If CR device connect fail then set exist = false.
//
CheckAndSaveConnectResult (mConOutVarName, mConVarGuid);
CreateNewActiveCrDevice ();
//
// Prepare CrInfo and reinstall protocol
//
mCrService.CRInfo = BuildCrInfo ();
gBS->ReinstallProtocolInterface (
mCrServiceImageHandle,
&gH2OConsoleRedirectionServiceProtocolGuid,
&mDummyCRService,
&mCrService
);
//
// If there have Cr device, prepare option rom
//
if (mCrService.CRInfo != NULL) {
Status = CrOpRomSupport ( mCrService.CRInfo);
DEBUG ((DEBUG_INFO, "\nCr << CrOpRomSupport >> %r\n", Status));
}
} else {
//
// CrHookDxe driver entry always install CRService protocol for avoid headless platform
// no CouOut device. please reference ForceActiveVga function.
//
gBS->UninstallProtocolInterface (
mCrServiceImageHandle,
&gH2OConsoleRedirectionServiceProtocolGuid,
&mDummyCRService
);
}
BdsCpUnregisterHandler (mCpConOutHandle);
}
VOID
AfterConnectAllCallBack (
IN EFI_EVENT Event,
IN H2O_BDS_CP_HANDLE Handle
)
{
if (mCrEnable) {
//
// Update device's exist-status that are non-exist before,
// or now disappear device.
//
UpdateDevicesExistStatus ();
//
// Check * device exist? if true create new variable
//
FindAsteriskDevicePath ();
//
// Free Temp Cr device variable list
//
FreeCrDevicesVarList ();
}
}
/**
The driver entry point.
@param ImageHandle A handle for the image that is initializing this driver
@param SystemTable A pointer to the EFI system table
@retval EFI_SUCCESS: Driver initialized successfully
@retval others Driver initialized unsuccessfully
**/
EFI_STATUS
EFIAPI
CrServiceEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
H2O_BDS_CP_HANDLE CpHandle;
mCrServiceImageHandle = ImageHandle;
InitializeCrDeviceList ();
Status = gBS->InstallProtocolInterface (
&ImageHandle,
&gH2OConsoleRedirectionServiceProtocolGuid,
EFI_NATIVE_INTERFACE,
&mDummyCRService
);
//
// Register Callback function
//
Status = BdsCpRegisterHandler (
&gH2OBdsCpConInConnectBeforeProtocolGuid,
BeforeConnectConsoleCallback,
H2O_BDS_CP_HIGH,
&CpHandle
);
Status = BdsCpRegisterHandler (
&gH2OBdsCpConOutConnectBeforeProtocolGuid,
BeforeConnectConsoleCallback,
H2O_BDS_CP_HIGH,
&CpHandle
);
Status = BdsCpRegisterHandler (
&gH2OBdsCpConOutConnectAfterProtocolGuid,
AfterConnectConOutCallBack,
H2O_BDS_CP_MEDIUM,
&mCpConOutHandle
);
Status = BdsCpRegisterHandler (
&gH2OBdsCpConnectAllAfterProtocolGuid,
AfterConnectAllCallBack,
H2O_BDS_CP_MEDIUM,
&CpHandle
);
return Status;
}