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