503 lines
15 KiB
C
503 lines
15 KiB
C
/** @file
|
|
HII support functions for Unicode Collation
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 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.
|
|
;*
|
|
;******************************************************************************
|
|
|
|
*/
|
|
|
|
#include "UnicodeCollationEng.h"
|
|
#include "HiiSupport.h"
|
|
#include <Pi/PiFirmwareFile.h>
|
|
#include <Pi/PiFirmwareVolume.h>
|
|
#include <Protocol/FontDatabase.h>
|
|
#include <Protocol/FirmwareVolume2.h>
|
|
#include <Guid/H2OHiiFontFile.h>
|
|
|
|
#define ISO_639_2_ENTRY_SIZE 3
|
|
|
|
STATIC EFI_GUID mPackageListGuid = {0xf5f219d3, 0x7006, 0x4648, {0xac, 0x8d, 0xd6, 0x1d, 0xfb, 0x7b, 0xc6, 0xad}};
|
|
|
|
#pragma pack(1)
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH VendorDevicePath;
|
|
UINT32 Reserved;
|
|
UINT64 UniqueId;
|
|
} HII_VENDOR_DEVICE_PATH_NODE;
|
|
#pragma pack()
|
|
|
|
typedef struct {
|
|
HII_VENDOR_DEVICE_PATH_NODE Node;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} HII_TEMP_DEVICE_PATH;
|
|
|
|
#define EFI_IFR_TIANO_GUID \
|
|
{ 0xf0b1735, 0x87a0, 0x4193, 0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce }
|
|
|
|
//
|
|
// Hii vendor device path template
|
|
//
|
|
HII_TEMP_DEVICE_PATH mHiiVendorDevicePathTemplate = {
|
|
{
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
(UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),
|
|
(UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)
|
|
},
|
|
EFI_IFR_TIANO_GUID,
|
|
},
|
|
0,
|
|
0
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
END_DEVICE_PATH_LENGTH,
|
|
0
|
|
}
|
|
};
|
|
|
|
/**
|
|
The HII driver handle passed in for HiiDatabase.NewPackageList() requires
|
|
that there should be DevicePath Protocol installed on it.
|
|
This routine create a virtual Driver Handle by installing a vendor device
|
|
path on it, so as to use it to invoke HiiDatabase.NewPackageList().
|
|
|
|
@param[out] DriverHandle Handle to be returned
|
|
|
|
@retval EFI_SUCCESS Handle destroy success.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
CreateHiiDriverHandle (
|
|
OUT EFI_HANDLE *DriverHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
HII_VENDOR_DEVICE_PATH_NODE *VendorDevicePath;
|
|
|
|
VendorDevicePath = AllocateCopyPool (sizeof (HII_TEMP_DEVICE_PATH), &mHiiVendorDevicePathTemplate);
|
|
if (VendorDevicePath == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Use memory address as unique ID to distinguish from different device paths
|
|
//
|
|
VendorDevicePath->UniqueId = (UINT64) ((UINTN) VendorDevicePath);
|
|
|
|
*DriverHandle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
VendorDevicePath,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Collect Font database to install font.
|
|
|
|
@retval EFI_NOT_FOUND Doesn't found FontDatabase.
|
|
@retval EFI_LOAD_ERROR Handle gEfiFontDatabaseProtocolGuid protocol failed.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
SetSupportLanguageFonts (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HII_HANDLE HiiHandle;
|
|
UINTN NarrowFontSize;
|
|
EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimplifiedFont;
|
|
UINTN PackageLength;
|
|
UINT8 *Package;
|
|
UINT8 *Location;
|
|
EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
|
|
EFI_HANDLE DriverHandle;
|
|
UINTN TotalStringSize;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
EFI_FONT_DATABASE_PROTOCOL *Fonts;
|
|
UINTN Index1;
|
|
CHAR8 *LangBuffer;
|
|
|
|
LangBuffer = NULL;
|
|
Fonts = NULL;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFontDatabaseProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (EFI_ERROR (Status) || HandleCount == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiDatabaseProtocolGuid,
|
|
NULL,
|
|
(VOID **)&HiiDatabase
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
TotalStringSize = 0;
|
|
|
|
for (Index1 = 0; Index1 < HandleCount; Index1++) {
|
|
Status = gBS->HandleProtocol(
|
|
HandleBuffer[Index1],
|
|
&gEfiFontDatabaseProtocolGuid,
|
|
(VOID **)&Fonts
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
NarrowFontSize = (Fonts->NumOfNarrowGlyph * sizeof (EFI_NARROW_GLYPH)) + (Fonts->NumOfWideGlyph * sizeof (EFI_WIDE_GLYPH));
|
|
|
|
//
|
|
// Add 4 bytes to the header for entire length for PreparePackageList use only.
|
|
// Looks ugly. Might be updated when font tool is ready.
|
|
//
|
|
PackageLength = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + NarrowFontSize + 4;
|
|
Package = (UINT8 *)AllocateZeroPool (PackageLength);
|
|
if (Package == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (Package, &PackageLength, 4);
|
|
SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR*) (Package + 4);
|
|
SimplifiedFont->Header.Length = (UINT32) (PackageLength - 4);
|
|
SimplifiedFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
|
|
SimplifiedFont->NumberOfNarrowGlyphs = Fonts->NumOfNarrowGlyph;
|
|
SimplifiedFont->NumberOfWideGlyphs = Fonts->NumOfWideGlyph;
|
|
|
|
Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);
|
|
CopyMem(
|
|
Location,
|
|
Fonts->FontNarrowGlyph,
|
|
(Fonts->NumOfNarrowGlyph * sizeof (EFI_NARROW_GLYPH))
|
|
);
|
|
|
|
//
|
|
//Copy mChineseFontWideGlyphData[]
|
|
//
|
|
CopyMem(
|
|
Location + (Fonts->NumOfNarrowGlyph * sizeof (EFI_NARROW_GLYPH)),
|
|
Fonts->FontsWideGlyph,
|
|
(Fonts->NumOfWideGlyph * sizeof (EFI_WIDE_GLYPH))
|
|
);
|
|
//
|
|
// Add this simplified font package to a package list then install it.
|
|
//
|
|
|
|
CreateHiiDriverHandle (&DriverHandle);
|
|
HiiHandle = HiiAddPackages (&mPackageListGuid, DriverHandle, Package, NULL);
|
|
ASSERT(HiiHandle != NULL);
|
|
FreePool (Package);
|
|
TotalStringSize += AsciiStrSize ((CHAR8 *)Fonts->SupportedLanguages);
|
|
}
|
|
LangBuffer = (CHAR8 *)AllocateZeroPool (TotalStringSize);
|
|
ASSERT (LangBuffer != NULL);
|
|
if (LangBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
for (Index1 = 0; Index1 < HandleCount; Index1++) {
|
|
Status = gBS->HandleProtocol(
|
|
HandleBuffer[Index1],
|
|
&gEfiFontDatabaseProtocolGuid,
|
|
(VOID **)&Fonts
|
|
);
|
|
AsciiStrCatS (LangBuffer, TotalStringSize, (CHAR8 *)Fonts->SupportedLanguages);
|
|
if (Index1 != HandleCount - 1) {
|
|
AsciiStrCatS (LangBuffer, TotalStringSize, ";");
|
|
}
|
|
}
|
|
|
|
Status = CommonSetVariable (
|
|
L"PlatformLangCodes",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
TotalStringSize,
|
|
LangBuffer
|
|
);
|
|
|
|
FreePool (LangBuffer);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Initalize LangCodes from PCD
|
|
|
|
@param[in] LangCodesSettingRequired
|
|
**/
|
|
VOID
|
|
InitializeLanguage (
|
|
IN BOOLEAN LangCodesSettingRequired
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Size;
|
|
CHAR8 *Lang;
|
|
CHAR8 LangCode[ISO_639_2_ENTRY_SIZE + 1];
|
|
CHAR8 *LangCodes;
|
|
CHAR8 *PlatformLang;
|
|
CHAR8 *PlatformLangCodes;
|
|
UINTN Index;
|
|
BOOLEAN Invalid;
|
|
|
|
LangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes);
|
|
if (LangCodesSettingRequired) {
|
|
if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
|
|
//
|
|
// UEFI 2.1 depricated this variable so we support turning it off
|
|
//
|
|
Status = CommonSetVariable (
|
|
L"LangCodes",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
AsciiStrSize (LangCodes),
|
|
LangCodes
|
|
);
|
|
}
|
|
|
|
|
|
PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes);
|
|
Status = CommonSetVariable (
|
|
L"PlatformLangCodes",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
AsciiStrSize (PlatformLangCodes),
|
|
PlatformLangCodes
|
|
);
|
|
}
|
|
|
|
if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
|
|
//
|
|
// UEFI 2.1 depricated this variable so we support turning it off
|
|
//
|
|
//
|
|
// Find current LangCode from Lang NV Variable
|
|
//
|
|
Size = ISO_639_2_ENTRY_SIZE + 1;
|
|
Status =CommonGetVariable (
|
|
L"Lang",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&LangCode
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
for (Index = 0; LangCodes[Index] != 0; Index += ISO_639_2_ENTRY_SIZE) {
|
|
if (CompareMem (&LangCodes[Index], LangCode, ISO_639_2_ENTRY_SIZE) == 0) {
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we cannot get language code from Lang variable, or LangCode cannot be found from language table,
|
|
// set the mDefaultLangCode to Lang variable.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
Lang = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang);
|
|
Status = CommonSetVariable (
|
|
L"Lang",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
ISO_639_2_ENTRY_SIZE + 1,
|
|
Lang
|
|
);
|
|
}
|
|
}
|
|
|
|
Invalid = FALSE;
|
|
PlatformLang = CommonGetVariableData (L"PlatformLang", &gEfiGlobalVariableGuid);
|
|
if (PlatformLang != NULL) {
|
|
//
|
|
// Check Current PlatformLang value against PlatformLangCode.
|
|
// Need a library that is TBD Set Invalid based on state of PlatformLang.
|
|
//
|
|
FreePool (PlatformLang);
|
|
} else {
|
|
// No valid variable is set
|
|
Invalid = TRUE;
|
|
}
|
|
|
|
if (Invalid) {
|
|
PlatformLang = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang);
|
|
Status = CommonSetVariable (
|
|
L"PlatformLang",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
AsciiStrSize (PlatformLang),
|
|
PlatformLang
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Set support language font by pcd and install font from H2O_HII_FONT_FILE_GUID,
|
|
if H2O_HII_FONT is not found, then will collect Font database to install font.
|
|
|
|
@retval EFI_SUCCESS Install HII font success.
|
|
@retval EFI_NOT_FOUND Doesn't found H2O_HII_FONT or FontDatabase.
|
|
**/
|
|
EFI_STATUS
|
|
SetSupportLanguageFontsByPcd (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN FvProtocolCount;
|
|
EFI_HANDLE *FvHandles;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
|
|
UINTN Index;
|
|
UINT32 AuthenticationStatus;
|
|
UINTN ImageSize;
|
|
UINT8 *ImageData;
|
|
UINTN PackageLength;
|
|
UINT8 *Package;
|
|
EFI_HANDLE DriverHandle;
|
|
EFI_HII_HANDLE HiiHandle;
|
|
|
|
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&FvProtocolCount,
|
|
&FvHandles
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ImageData = NULL;
|
|
ImageSize = 0;
|
|
|
|
for (Index = 0; Index < FvProtocolCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
FvHandles[Index],
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "HandleProtocol(%r)\n", Status));
|
|
continue;
|
|
}
|
|
|
|
Status = Fv->ReadSection (
|
|
Fv,
|
|
&gH2OHiiFontFileGuid,
|
|
EFI_SECTION_RAW,
|
|
0,
|
|
(VOID **)&ImageData,
|
|
&ImageSize,
|
|
&AuthenticationStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return SetSupportLanguageFonts ();
|
|
}
|
|
|
|
InitializeLanguage (TRUE);
|
|
|
|
PackageLength = 4 + ImageSize;
|
|
Package = (UINT8 *)AllocateZeroPool (PackageLength);
|
|
if (Package == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (Package, &PackageLength, 4);
|
|
CopyMem (Package + 4, ImageData, ImageSize);
|
|
|
|
CreateHiiDriverHandle (&DriverHandle);
|
|
HiiHandle = HiiAddPackages (&mPackageListGuid, DriverHandle, Package, NULL);
|
|
ASSERT(HiiHandle != NULL);
|
|
|
|
FreePool (ImageData);
|
|
FreePool (Package);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
/**
|
|
Get all SupportedLanguages and append ";en" in the end of SupportedLanguages.
|
|
Then set back to SupportedLanguages.
|
|
|
|
@param UnicodeCollation2 A pointer to the EFI UNICODE COLLATION PROTOCOL.
|
|
|
|
@retval EFI_SUCCESS Update Unicode Collation 2 successfully.
|
|
@retval EFI_OUT_OF_RESOURCES AllocateZeroPool failed.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateUnicode2SupportedLanguages (
|
|
OUT EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation2
|
|
)
|
|
{
|
|
CHAR8 *PlatformLangCodes;
|
|
CHAR8 *AsciiStrBuffer;
|
|
UINTN AsciiStrBufferSize;
|
|
UINTN PaddingSize;
|
|
UINTN Index;
|
|
|
|
PlatformLangCodes = CommonGetVariableData (L"PlatformLangCodes", &gEfiGlobalVariableGuid);
|
|
ASSERT (PlatformLangCodes != NULL);
|
|
|
|
if (PlatformLangCodes != NULL) {
|
|
UnicodeCollation2->SupportedLanguages = PlatformLangCodes;
|
|
}
|
|
|
|
//
|
|
// Run SCT(edk2-test-stable201910) hang because SCT fails to find matched UnicodeCollation2 by searching "en" with null-terminated char.
|
|
// In order to workaround it, append ";en" in the end of SupportedLanguages and make sure string size is the multiples of 3.
|
|
//
|
|
AsciiStrBufferSize = AsciiStrLen (UnicodeCollation2->SupportedLanguages) + sizeof(";en");
|
|
PaddingSize = ((AsciiStrBufferSize % 3) == 0) ? 0 : (3 - (AsciiStrBufferSize % 3));
|
|
AsciiStrBufferSize += PaddingSize;
|
|
|
|
AsciiStrBuffer = AllocateZeroPool (AsciiStrBufferSize);
|
|
if (AsciiStrBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
AsciiStrCpyS (AsciiStrBuffer, AsciiStrBufferSize, UnicodeCollation2->SupportedLanguages);
|
|
for (Index = 0; Index < PaddingSize; Index++) {
|
|
AsciiStrCatS (AsciiStrBuffer, AsciiStrBufferSize, " ");
|
|
}
|
|
AsciiStrCatS (AsciiStrBuffer, AsciiStrBufferSize, ";en");
|
|
|
|
UnicodeCollation2->SupportedLanguages = AsciiStrBuffer;
|
|
if (PlatformLangCodes != NULL) {
|
|
FreePool (PlatformLangCodes);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} |