alder_lake_bios/Insyde/InsydeModulePkg/Universal/BdsDxe/String.c

640 lines
19 KiB
C

/** @file
String support
;******************************************************************************
;* Copyright (c) 2012 - 2020, 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.
;*
;******************************************************************************
*/
/**
String support
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "String.h"
EFI_HII_HANDLE gStringPackHandle;
EFI_GUID mBdsStringPackGuid = {
0x7bac95d3, 0xddf, 0x42f3, {0x9e, 0x24, 0x7c, 0x64, 0x49, 0x40, 0x37, 0x9a}
};
/**
Initialize HII global accessor for string support.
**/
VOID
InitializeStringSupport (
VOID
)
{
gStringPackHandle = HiiAddPackages (
&mBdsStringPackGuid,
gImageHandle,
BdsDxeStrings,
NULL
);
ASSERT (gStringPackHandle != NULL);
}
/**
Get string by string id from HII Interface
@param Id String ID.
@retval CHAR16 * String from ID.
@retval NULL If error occurs.
**/
CHAR16 *
GetStringById (
IN EFI_STRING_ID Id
)
{
return HiiGetString (gStringPackHandle, Id, NULL);
}
/**
Update the content of STR_BOOT_DEVICE_ERROR_MESSAGE string to CSM16 for boot error message
if this string isn't an empty string.
@retval EFI_SUCCESS Update boot error message to CSM16 successfully.
@retval EFI_NOT_FOUND Cannot find default boot error message in CSM16.
@retval EFI_NOT_READY STR_BOOT_DEVICE_ERROR_MESSAGE token is empty string.
**/
EFI_STATUS
UpdateBootMessage (
VOID
)
{
EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
EFI_COMPATIBILITY16_TABLE *Table;
EFI_IA32_REGISTER_SET Regs;
EFI_STATUS Status;
UINT8 *Ptr;
BOOT_MESSAGE *BootMsg;
CHAR16 *NewString;
UINTN StringLen;
UINT8 *NewStringAddress;
//
// See if the Legacy Region Protocol is available
//
Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **)&LegacyRegion);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **)&LegacyBios);
if (EFI_ERROR (Status)) {
return Status;
}
BootMsg = NULL;
// CODE ANALYSIS (VS19.0.2) - Reports C6011. Added typecast to Ptr = Ptr + 0x10.
for (Ptr = (UINT8 *) ((UINTN) 0xF0000);
Ptr < (UINT8 *) ((UINTN) 0x100000);
Ptr = (UINT8 *) ((UINTN) Ptr + 0x10)) {
//
// "boot device error string (BDES)"
//
if (*(UINT32 *) Ptr == SIGNATURE_32 ('B', 'D', 'E', 'S')) {
BootMsg = (BOOT_MESSAGE *) Ptr;
break;
}
}
if (BootMsg == NULL) {
return EFI_NOT_FOUND;
}
NewString = GetStringById (STRING_TOKEN (STR_BOOT_DEVICE_ERROR_MESSAGE));
if (NewString == NULL) {
return EFI_NOT_READY;
}
StringLen = StrLen (NewString);
if (StringLen == 0) {
return EFI_NOT_READY;
}
if (StringLen <= BOOT_FAIL_STRING_LENTH) {
Status = LegacyRegion->UnLock (LegacyRegion, 0xF0000, 0x10000, NULL);
ZeroMem (&BootMsg->String, BOOT_FAIL_STRING_LENTH);
UnicodeStrToAsciiStrS (NewString, &BootMsg->String, BOOT_FAIL_STRING_LENTH);
Status = LegacyRegion->Lock (LegacyRegion, 0xF0000, 0x10000, NULL);
return EFI_SUCCESS;
}
Table = NULL;
// CODE ANALYSIS (VS19.0.2) - Reports C6011. Added typecast to Ptr = Ptr + 0x10.
for (Ptr = (UINT8 *) ((UINTN) 0xFE000);
Ptr < (UINT8 *) ((UINTN) 0x100000);
Ptr = (UINT8 *) ((UINTN) Ptr + 0x10)) {
if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;
break;
}
}
if (Table == NULL) {
return EFI_NOT_FOUND;
}
Status = LegacyRegion->UnLock (LegacyRegion, 0xE0000, 0x10000, NULL);
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16GetTableAddress;
Regs.X.BX = 0x0002;
Regs.X.CX = (UINT16)StringLen;
Regs.X.DX = 1;
LegacyBios->FarCall86 (
LegacyBios,
Table->Compatibility16CallSegment,
Table->Compatibility16CallOffset,
&Regs,
NULL,
0);
NewStringAddress = (UINT8 *)(UINTN)(Regs.X.DS*16 + Regs.X.BX);
BootMsg->StrSegment = (UINT16)(((UINTN)NewStringAddress >> 4) & 0xF000);
BootMsg->StrOffset = (UINT16)(UINTN)NewStringAddress;
ZeroMem (NewStringAddress, StringLen);
UnicodeStrToAsciiStrS (NewString, (CHAR8 *) NewStringAddress, StringLen);
Status = LegacyRegion->Lock (LegacyRegion, 0xE0000, 0x10000, NULL);
return EFI_SUCCESS;
}
/**
Check whether there is only one physical GOP on system.
@param[in] SinglePhyGop Pointer to GOP instance
@retval TRUE There is only one physical GOP on system
@retval FALSE There is zero or only one physical GOP on system
**/
STATIC
BOOLEAN
IsSinglePhysicalGop (
OUT EFI_HANDLE *SinglePhyGop
)
{
EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
UINTN NumberOfPhysicalGop;
NumberOfPhysicalGop = 0;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiGraphicsOutputProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return FALSE;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiDevicePathProtocolGuid,
(VOID*)&GopDevicePath
);
if (EFI_ERROR (Status)) {
continue;
}
*SinglePhyGop = HandleBuffer[Index];
NumberOfPhysicalGop++;
}
FreePool (HandleBuffer);
if (NumberOfPhysicalGop == 1) {
return TRUE;
} else {
return FALSE;
}
}
/**
Get the text mode number by input resolution.
@param[in] RequestedColumns Resolution column
@param[in] RequestedRows Resolution row
@param[out] TextModeNum Pointer to text mode number
@retval EFI_SUCCESS There is matched text mode number
@retval EFI_UNSUPPORTED There is no matched text mode number
**/
STATIC
EFI_STATUS
ChkTextModeNum (
IN UINTN RequestedColumns,
IN UINTN RequestedRows,
OUT UINTN *TextModeNum
)
{
UINTN ModeNum;
UINTN Columns;
UINTN Rows;
EFI_STATUS Status;
for (ModeNum = 0; ModeNum < (UINTN)(gST->ConOut->Mode->MaxMode); ModeNum++) {
gST->ConOut->QueryMode (gST->ConOut, ModeNum, &Columns, &Rows);
if ((RequestedColumns == Columns) && (RequestedRows == Rows)) {
*TextModeNum = ModeNum;
break;
}
}
if (ModeNum == (UINTN)(gST->ConOut->Mode->MaxMode)) {
*TextModeNum = ModeNum;
Status = EFI_UNSUPPORTED;
} else {
Status = EFI_SUCCESS;
}
return Status;
}
/**
Get the device path which contain all console output device path instances.
@retval The device path which contain all console output device path instances or NULL if not found.
**/
STATIC
VOID *
GetAllActiveConOutDevPath (
VOID
)
{
UINTN NoHandles;
EFI_HANDLE *HandleBuf;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
EFI_DEVICE_PATH_PROTOCOL *ConsoleDevPath;
EFI_DEVICE_PATH_PROTOCOL *TempDevPath;
UINT8 Index;
EFI_STATUS Status;
//
//init local
//
NoHandles = 0;
HandleBuf = NULL;
DevPath = NULL;
ConsoleDevPath = NULL;
TempDevPath = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiConsoleOutDeviceGuid,
NULL,
&NoHandles,
&HandleBuf
);
if (EFI_ERROR (Status)) {
return NULL;
}
for (Index = 0; Index < NoHandles; Index++) {
Status = gBS->HandleProtocol (
HandleBuf [Index],
&gEfiDevicePathProtocolGuid,
(VOID **)&DevPath
);
if (EFI_ERROR (Status) || (DevPath == NULL)) {
continue;
}
TempDevPath = ConsoleDevPath;
ConsoleDevPath = AppendDevicePathInstance (ConsoleDevPath, DevPath);
if (TempDevPath != NULL) {
FreePool (TempDevPath);
}
}
FreePool (HandleBuf);
return ConsoleDevPath;
}
/**
Check whether there is a text-based console output device on system.
@retval TRUE There is a text-based console output device on system.
@retval FALSE There is no text-based console output device on system.
**/
STATIC
BOOLEAN
FoundTextBasedConsole (
VOID
)
{
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *OrgRemainingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *NextDevPathInstance;
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
BOOLEAN FoundTextBasedCon;
UINTN Size;
EFI_DEVICE_PATH_PROTOCOL *ConOutDevPathInstance;
//
//init local
//
RemainingDevicePath = NULL;
Gop = NULL;
FoundTextBasedCon = FALSE;
NextDevPathInstance = NULL;
ConOutDevPathInstance = NULL;
RemainingDevicePath = GetAllActiveConOutDevPath ();
if (RemainingDevicePath == NULL) {
return FALSE;
}
OrgRemainingDevicePath = RemainingDevicePath;
do {
//
//find all output console handles
//
NextDevPathInstance = GetNextDevicePathInstance (&RemainingDevicePath, &Size);
if (NextDevPathInstance != NULL) {
ConOutDevPathInstance = NextDevPathInstance;
gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &ConOutDevPathInstance, &Handle);
Status = gBS->HandleProtocol (
Handle,
&gEfiGraphicsOutputProtocolGuid,
(VOID**)&Gop
);
if (EFI_ERROR (Status)) {
//
//found text-based console
//
FoundTextBasedCon = TRUE;
FreePool (NextDevPathInstance);
break;
}
FreePool (NextDevPathInstance);
}
} while (RemainingDevicePath != NULL);
FreePool (OrgRemainingDevicePath);
return FoundTextBasedCon;
}
/**
Get the optimal resolution.
@param[in] GraphicsOutput Pointer to GOP instance
@param[out] XResolution Pointer to resolution X
@param[out] YResoulution Pointer to resolution Y
**/
STATIC
VOID
GetComboVideoOptimalResolution (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
OUT UINT32 *XResolution,
OUT UINT32 *YResoulution
)
{
UINT32 ModeNumber;
EFI_STATUS Status;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINT32 MaxMode;
UINTN MaxResolution;
UINTN TempResolution;
Status = EFI_SUCCESS;
MaxMode = GraphicsOutput->Mode->MaxMode;
MaxResolution = 0;
TempResolution = 0;
for (ModeNumber = 0; ModeNumber < MaxMode; ModeNumber++) {
Status = GraphicsOutput->QueryMode (
GraphicsOutput,
ModeNumber,
&SizeOfInfo,
&Info
);
if (!EFI_ERROR (Status)) {
TempResolution = (UINTN) Info->HorizontalResolution * Info->VerticalResolution;
if (TempResolution > MaxResolution) {
MaxResolution = TempResolution;
*XResolution = Info->HorizontalResolution;
*YResoulution = Info->VerticalResolution;
}
FreePool (Info);
Info = NULL;
}
}
}
/**
Set console output device to optimal resolution.
**/
VOID
EnableOptimalTextMode (
VOID
)
{
EFI_STATUS Status;
OEM_LOGO_RESOLUTION_DEFINITION *OemLogoResolutionPtr;
OEM_LOGO_RESOLUTION_DEFINITION TempOemLogoResolution;
OEM_LOGO_RESOLUTION_DEFINITION LogoResolution;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
UINT32 SizeOfX;
UINT32 SizeOfY;
UINTN RequestedRows;
UINTN RequestedColumns;
UINTN TextModeNum;
UINT32 Index;
EFI_HANDLE SinglePhyGopHandle;
EFI_EDID_DISCOVERED_PROTOCOL *EdidDiscovered;
UINT32 NativeResolutionX;
UINT32 NativeResolutionY;
UINTN BestResolution;
UINTN SizeOfInfo;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINT32 GopModeNum;
UINTN ModeNum;
UINTN Columns;
UINTN Rows;
UINTN OptimalTxtMode;
EFI_DEVICE_PATH_PROTOCOL *ConOutDevicePath;
EFI_STATUS OemSvcStatus;
//
//init local vars
//
Index = 0;
SinglePhyGopHandle = NULL;
OemLogoResolutionPtr = NULL;
SizeOfInfo = 0;
Info = NULL;
BestResolution = 0;
RequestedColumns = 0;
RequestedRows = 0;
SizeOfX = 0;
SizeOfY = 0;
GraphicsOutput = NULL;
OptimalTxtMode = 0;
TextModeNum = gST->ConOut->Mode->MaxMode;
ConOutDevicePath = NULL;
ConOutDevicePath = GetAllActiveConOutDevPath ();
if (ConOutDevicePath == NULL) {
//
// no monitor is attached
//
return ;
}
FreePool (ConOutDevicePath);
if (FoundTextBasedConsole ()) {
//
//if any Console deveice is text-based display,
//based on text mode intersection, find optimal text mode
//
for (ModeNum = 0; ModeNum < (UINTN)(gST->ConOut->Mode->MaxMode); ModeNum++) {
Status = gST->ConOut->QueryMode (gST->ConOut, ModeNum, &Columns, &Rows);
if (!EFI_ERROR (Status)) {
if ((Columns * Rows) > OptimalTxtMode) {
OptimalTxtMode = Columns * Rows;
TextModeNum = (UINTN)ModeNum;
}
}
}
if (TextModeNum == (UINTN)(gST->ConOut->Mode->MaxMode)) {
Status = EFI_UNSUPPORTED;
} else {
Status = EFI_SUCCESS;
}
goto Done;
}
OemLogoResolutionPtr = (OEM_LOGO_RESOLUTION_DEFINITION *)PcdGetPtr (PcdDefaultLogoResolution);
CopyMem(&TempOemLogoResolution, OemLogoResolutionPtr, sizeof(OEM_LOGO_RESOLUTION_DEFINITION));
OemLogoResolutionPtr = &TempOemLogoResolution;
if (IsSinglePhysicalGop (&SinglePhyGopHandle)) {
gBS->HandleProtocol (
SinglePhyGopHandle,
&gEfiGraphicsOutputProtocolGuid,
(VOID**) &GraphicsOutput
);
Status = gBS->HandleProtocol (
SinglePhyGopHandle,
&gEfiEdidDiscoveredProtocolGuid,
(VOID **) &EdidDiscovered
);
if (!EFI_ERROR (Status)) {
Status = GetResolutionByEdid (EdidDiscovered, &NativeResolutionX, &NativeResolutionY);
if (!EFI_ERROR (Status)) {
LogoResolution.LogoResolutionX = NativeResolutionX;
LogoResolution.LogoResolutionY = NativeResolutionY;
Status = CheckModeSupported (
GraphicsOutput,
NativeResolutionX,
NativeResolutionY,
&GopModeNum
);
if (!EFI_ERROR (Status)) {
OemLogoResolutionPtr = &LogoResolution;
}
}
} else {
//
// find optimal resoltion from gop modes to set for possible combination of two video output devices
// attached to a gop device
//
GetComboVideoOptimalResolution (GraphicsOutput, &SizeOfX, &SizeOfY);
LogoResolution.LogoResolutionX = SizeOfX;
LogoResolution.LogoResolutionY = SizeOfY;
OemLogoResolutionPtr = &LogoResolution;
}
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcLogoResolution \n"));
OemSvcStatus = OemSvcLogoResolution (&OemLogoResolutionPtr);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcLogoResolution Status: %r\n", OemSvcStatus));
SizeOfX = OemLogoResolutionPtr->LogoResolutionX;
SizeOfY = OemLogoResolutionPtr->LogoResolutionY;
} else {
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID**)&GraphicsOutput);
if (!EFI_ERROR (Status)) {
for (Index = 0;Index < GraphicsOutput->Mode->MaxMode; Index++) {
//
//find best resolution from virtual gop
//
GraphicsOutput->QueryMode (GraphicsOutput, Index, &SizeOfInfo, &Info);
if (((UINTN) Info->HorizontalResolution * Info->VerticalResolution) > BestResolution) {
BestResolution = (UINTN) Info->HorizontalResolution * Info->VerticalResolution;
LogoResolution.LogoResolutionX = Info->HorizontalResolution;
LogoResolution.LogoResolutionY = Info->VerticalResolution;
OemLogoResolutionPtr = &LogoResolution;
}
FreePool (Info);
Info = NULL;
}
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcLogoResolution \n"));
OemSvcStatus = OemSvcLogoResolution (&OemLogoResolutionPtr);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcLogoResolution Status: %r\n", OemSvcStatus));
SizeOfX = OemLogoResolutionPtr->LogoResolutionX;
SizeOfY = OemLogoResolutionPtr->LogoResolutionY;
}
}
RequestedColumns = SizeOfX / EFI_GLYPH_WIDTH;
RequestedRows = SizeOfY / EFI_GLYPH_HEIGHT;
Status = ChkTextModeNum (RequestedColumns, RequestedRows, &TextModeNum);
Done:
if (!EFI_ERROR (Status)) {
if ((UINTN)(gST->ConOut->Mode->Mode) != TextModeNum) {
Status = gST->ConOut->SetMode (gST->ConOut, TextModeNum);
} else {
//
// make sure text dimension's conrresponding resolution is set.
//
if (GraphicsOutput != NULL) {
if ((SizeOfX != GraphicsOutput->Mode->Info->HorizontalResolution) ||
(SizeOfY != GraphicsOutput->Mode->Info->VerticalResolution)) {
CheckModeSupported (
GraphicsOutput,
SizeOfX,
SizeOfY,
&GopModeNum
);
GraphicsOutput->SetMode (GraphicsOutput, GopModeNum);
}
}
}
} else {
Status = gST->ConOut->SetMode (gST->ConOut, 0);
}
}