💻
UEFI 프로젝트
  • 🧑‍🏫프로젝트 개요
  • 📖UEFI 개념
    • 1. BIOS의 과거
    • 2. UEFI 개념
    • 3. BIOS vs UEFI
    • 4. UEFI 부팅 단계
  • 🖥️UEFI 개발
    • UEFI 개발 시작하기
      • 0. EDK II 빌드 환경 구성
      • 1. 간단한 EFI application 만들기
      • 2. 간단한 Pkg 만들기
      • 3. Hello World 출력하기
      • 4. 라이브러리와 Hello World
      • 5. Conf를 통한 Build 단순화
    • 핸들 및 프로토콜
      • 6. 핸들/프로토콜 데이터 베이스 구조 - Part 1
      • 7. 핸들/프로토콜 데이터 베이스 구조 - Part 2
      • 8. HandleProtocol API 함수 & ImageHandle 프로토콜을 통한 정보
      • 9. ProtocolsPerHandle API를 통한 ImageHandle 프로토콜 가져오기
      • 10. EFI_STATUS 타입 과 EFI_ERROR 매크로
    • 메모리 맵
      • 11. EFI 메모리 맵 정보 얻기
      • 12. EFI 메모리 맵을 리눅스 커널 스타일로 바꾸기
    • 명령줄 인수를 받는 간단한 앱 만들기
      • 13.ShellAppMain Entry point
      • 14.gRT->GetNextVariableName API를 사용하여 모든 변수 이름 및 GUID 가져오기
    • 부팅 옵션
      • 15. gRT->GetVariable API를 사용하여 부팅 변수 가져오기 및 구문 분석
      • 16. OVMF 이미지 내에 부팅 옵션 추가
      • 17. 부팅 옵션에 WaitForEvent 함수 추가
      • 18. ReadKeyStroke 함수로 사용자 입력 처리
      • 19. bcfg 명령어를 사용한 부팅 옵션 수정
    • PCD
      • 20. PCD 소개
      • 21. PCD 변수에 대한 Overriding
      • 22. Feature Flag PCD와 BOOLEAN FixedAtBuild PCD의 비교
      • 23. PatchableInModule PCD 및 GenPatchPcdTable/PatchPcdValue 유틸리티를 통해 PCD를 변경하는 방법
      • 24. Dynamic/DynamiEx PCDs
      • 25. PCD 더 알아보기
    • 테이블
      • 26. EFI_CONFIGURATION_TABLE에서 참조되는 테이블
      • 27. dmem/EFI_SMBIOS_PROTOCOL/smbiosview를 통해서 SMBIOS 정보 가져오기
      • 28. EFI_SHELL_PROTOCOL을 통하여 ACPI 테이블을 파일에 저장하기
      • 29. EFI_ACPI_SDT_PROTOCOL 및 ShellLib를 사용하여 ACPI BGRT 테이블에서 BMP 이미지 저장하기
    • PCI
      • 30. PCI 루트 브리지 찾은 후 시스템의 모든 PCI 기능 가져오기
      • 31. ShellLib/PrintLib 함수를 사용해 PCI Vendor/Device 정보 가져오기
      • 32. EFI_PCI_IO_PROTOCOL을 사용해 PCI Option ROM 이미지 표시
      • 33. EfiRom 유틸리티를 사용한 PCI Option ROM 이미지 파싱 및 생성
    • 드라이버 및 라이브러리
      • 34. 간단한 UEFI 드라이버 생성
      • 35. 애플리케이션에서 사용할 간단한 라이브러리 생성
      • 36. Library의 constructor와 destructor, NULL Library
      • 37. Shell에 acpiview 명령을 추가하는 방법 조사
      • 38. 사용자 지정 프로토콜을 만들고 사용하기
      • 39. RegisterKeyNotify / UnrigisterKeyNotify 함수를 사용해 단축키 기능을 추가하는 드라이버 만들기
      • 40. Key #### NVRAM 변수
    • 디버그
      • 41. DEBUG 출력문 내부 구조와 DEBUG 문 제어를 위한 PCD 분석, 그리고 OVMF 부트 로그 가져오기
      • 42. GDB를 이용한 Driver/Application 및 OVMF Debug
    • HII
      • 43. HII 데이터베이스 개념 및 출력
      • 44. HII 데이터베이스 내부
      • 45. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 문자열 목록 게시
      • 46. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 HII 패키지 목록 게시
      • 47. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 HII 패키지 목록 게시
      • 48. UNI 파일 및 HiiLib를 사용하여 HII String 패키지 게시 및 작업하기
      • 49.MODULE_UNI_FILE/PACKAGE_UNI_FILE/[UserExtensions.TianoCore."ExtraFiles"]의 도움으로 UNI 파일 선언하기
      • 50.UEFI_HII_RESOURCE_SECTION을 사용하여 문자열 패키지와 함께 HII 패키지 목록 게시하기
      • 51. UEFI APP에 메뉴얼 추가하기(shell의 -?와 help 옵션)
      • 52. Russian 글꼴 추가 - Part 1.
      • 53. Russian 글꼴 추가 - Part 2.
      • 54. EFI_HII_STRING_PROTOCOL의 NewString 및 SetString 함수를 사용하여 다른 언어에 대한 문자열 패키지를 동적으로 추가
      • 55. PlatformLangCodes EFI 변수 수정 및 다른 언어를 동적 추가하기
      • 56. 코드에서 FILE_GUID 및 BASE_NAME을 가져오기
    • VFR
      • 57. VFR을 사용해 간단한 폼 생성 및 EFI_FORM_BROWSER2_PROTOCOL.SendForm()를 통해 화면에 폼 표시하기
      • 58. VFR 요소 : subtitle 및 text
      • 59. 간단한 폼 애플리케이션을 UEFI 드라이버 Form으로 변환하기
      • 60. gRT->SetVariable() 함수를 사용한 UEFI 변수 생성, 변경 및 삭제
      • 61.dmpstore 명령을 사용하여 변수를 파일에 저장/로드하기
      • 62. UEFI Device path의 구조
      • 63. checkbox를 가진 HII 폼 만들기
      • 64. checkbox를 가진 HII폼 만들기
      • 65. VFR 추가 입력 요소 Part 1: number
      • 66. VFR 추가 입력 요소 Part 2: string
      • 67. VFR 추가 입력 요소 Part 3: date & time
      • 68. VFR 추가 입력 요소 Part 3: oneof & orderedlist
      • 69. VFR의 조건부 키워드
      • 70. VFR의 상수 및 연산자가 내장된 기본 조건문
      • 71. 기본 VFR 내장 문자열용 함수
      • 72. label 키워드를 이용하여 HII 양식에 동적 요소 추가하기
      • 73. VFR question 기본값 설정
  • 🔐UEFI 보안
    • 1. 개요
    • 2. 공격 벡터
    • 3. mitigation
    • 4. 정적 분석 방법
    • 5. 동적 분석 방법
Powered by GitBook
On this page
  • String.uni file
  • RussianFont.c
  • HIIAddRussianFont.c
  1. UEFI 개발
  2. HII

53. Russian 글꼴 추가 - Part 2.

EFI_HII_SIMPLE_FONT_PACKAGE 구성 및 HII 데이터베이스에 채우기

이제 우리 글꼴을 HII 데이터베이스에 추가할 시점이다.

새로운 애플리케이션을 초기화한다.

./createNewApp.sh HIIAddRussianFont

패키지 DSC 파일(UefiLessonsPkg.dsc)에 추가한다.

$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
---
[Components]
  UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf

애플리케이션에서는 HII 데이터베이스에 패키지 목록을 채울 것이므로, UefiLessonsPkg.dec에서 이 패키지 목록에 대한 GUID를 선언해야 한다.

$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[Guids]
  ...
  gHIIAddRussianFontGuid = { 0x9fe2f616, 0x323c, 0x45a7, { 0x87, 0xa2, 0xdf, 0xef, 0xf5, 0x17, 0xcc, 0x66 }}

그리고 애플리케이션을 이용하기 위해서 INF 파일을 선언한다.

$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Packages]
  ...
  UefiLessonsPkg/UefiLessonsPkg.dec

[Guids]
  gHIIAddRussianFontGuid

또한 HII 서비스(ex. HiiAddPackages 함수)용 라이브러리를 사용하므로 처음부터 포함시키도록 하자.

[Packages]
  ...
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  ...
  HiiLib

String.uni file

애플리케이션 소스(HIIAddRussianFont.inf)에 문자열 UNI 파일을 추가한다.

$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
  ...
  Strings.uni

그 다음 아래의 문자열을 사용하여 이 Strings.uni 파일을 만든다.

  • "Hello!"

  • "Bye!"

  • 대문자 알파벳

  • 소문자 알파벳

#langdef en-US "English"
#langdef fr-FR "Francais"
#langdef ru-RU "Russian"

#string STR_HELLO               #language en-US  "Hello!"
                                #language fr-FR  "Bonjour!"
                                #language ru-RU  "Привет!"

#string STR_BYE                 #language en-US  "Bye!"
                                #language fr-FR  "Au revoir!"
                                #language ru-RU  "До свидания!"

#string STR_ALPHABET_UPPERCASE  #language en-US  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                #language fr-FR  "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÈÙÉÂÊÎÔÛËÏÜŸÆŒÇ"
                                #language ru-RU  "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЭЮЯ"

#string STR_ALPHABET_LOWERCASE  #language en-US  "abcdefghijklmnopqrstuvwxyz"
                                #language fr-FR  "abcdefghijklmnopqrstuvwxyzàèùéâêîôûëïüÿæœç"
                                #language ru-RU  "абвгдеёжзийклмнопрстуфхцчшщьъэюя"

알파벳 문자열은 해당 언어의 모든 문자가 올바르게 출력되었는지 확인하는 데 도움이 된다.

RussianFont.c

이전 장에서 받은 러시아어 글꼴 Glyph가 포함된 파일을 HIIAddRussianFont.inf에 추가한다.

$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
  ...
  RussianFont.c

다음 내용이 포함된 파일일 경우를 대비하여

EFI_WIDE_GLYPH gSimpleFontWideGlyphData[] = {
{ 0x00, 0x00, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
};
UINT32 gSimpleFontWideBytes = sizeof(gSimpleFontWideGlyphData);

EFI_NARROW_GLYPH gSimpleFontNarrowGlyphData[] = {
{ 0x400, 0x00, { 0x60,0x30,0x00,0xfe,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00}},
{ 0x401, 0x00, { 0x66,0x66,0x00,0xfe,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00}},
{ 0x402, 0x00, { 0x00,0x00,0x00,0xfc,0x64,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0x66,0xe6,0x0c,0x00,0x00,0x00}},
{ 0x403, 0x00, { 0x0c,0x18,0x00,0xfe,0x66,0x62,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00}},
{ 0x404, 0x00, { 0x00,0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc8,0xf8,0xc8,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00}},
...
{ 0x45c, 0x00, { 0x00,0x00,0x00,0x0c,0x18,0x30,0x00,0xe6,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00}},
{ 0x45d, 0x00, { 0x00,0x00,0x00,0x60,0x30,0x18,0x00,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x00,0x00,0x00,0x00}},
{ 0x45e, 0x00, { 0x00,0x00,0x00,0x00,0x6c,0x38,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x0c,0xf8,0x00}},
{ 0x45f, 0x00, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfe,0x10,0x10,0x00,0x00}},
};
UINT32 gSimpleFontNarrowBytes = sizeof(gSimpleFontNarrowGlyphData);

HIIAddRussianFont.c

이제 기본 코드를 작성할 차례이다.

#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/HiiLib.h>
#include <Library/MemoryAllocationLib.h>

extern EFI_WIDE_GLYPH gSimpleFontWideGlyphData[];
extern UINT32 gSimpleFontWideBytes;
extern EFI_NARROW_GLYPH gSimpleFontNarrowGlyphData[];
extern UINT32 gSimpleFontNarrowBytes;


EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  UINT8* FontPackage = CreateSimpleFontPkg(gSimpleFontWideGlyphData,
                                          gSimpleFontWideBytes,
                                          gSimpleFontNarrowGlyphData,
                                          gSimpleFontNarrowBytes);

  EFI_HII_HANDLE Handle = HiiAddPackages(&gHIIAddRussianFontGuid,
                                         NULL,
                                         FontPackage,
                                         HIIAddRussianFontStrings,
                                         NULL);

  FreePool(FontPackage);

  if (Handle == NULL)
  {
    Print(L"Error! Can't perform HiiAddPackages\n");
    return EFI_INVALID_PARAMETER;
  }

  Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
  Print(L"en-US ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "en-US"));
  Print(L"en-US ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "en-US"));
  Print(L"en-US ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "en-US"));
  Print(L"en-US ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "en-US"));
  Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
  Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "fr-FR"));
  Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "fr-FR"));
  Print(L"fr-FR ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "fr-FR"));
  Print(L"fr-FR ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "fr-FR"));
  Print(L"ru-RU ID=1: %s\n", HiiGetString(Handle, 1, "ru-RU"));
  Print(L"ru-RU ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "ru-RU"));
  Print(L"ru-RU ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "ru-RU"));
  Print(L"ru-RU ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "ru-RU"));
  Print(L"ru-RU ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "ru-RU"));

  return EFI_SUCCESS;
}

여기서 우리는,

  • RussianFont.c 파일의 Glyph 배열에서 글꼴 패키지 데이터를 구성한다. 이 다음에 CreateSimpleFontPkg 함수를 정의한다.

  • 패키지를 추가하면, 더 이상 FontPackage가 필요하지 않으므로 FreePool 기능으로 해제하는 것을 잊지 않도록 하자.

  • 모든 것이 정상이라면, HiiGetString을 사용하여 모든 언어의 모든 문자열을 출력한다.

///
/// A simplified font package consists of a font header
/// followed by a series of glyph structures.
///
typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
  EFI_HII_PACKAGE_HEADER Header;
  UINT16                 NumberOfNarrowGlyphs;
  UINT16                 NumberOfWideGlyphs;
  // EFI_NARROW_GLYPH       NarrowGlyphs[];
  // EFI_WIDE_GLYPH         WideGlyphs[];
} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;

///
/// The header found at the start of each package.
///
typedef struct {
  UINT32  Length:24;
  UINT32  Type:8;
  // UINT8  Data[...];
} EFI_HII_PACKAGE_HEADER;


//
// Value of HII package type
//
...
#define EFI_HII_PACKAGE_SIMPLE_FONTS         0x07
...

함수에서 글꼴 패키지에 필요한 배열을 할당해야 한다. 패키지 자체를 위한 공간을 할당하는 것 외에도 모든 데이터 앞에 추가할 패키지 크기에 대해 4바이트를 추가해야 한다. 알다시피 이것은 HiiAddPackages 함수에 필요한 데이터 형식이다.

UINT8* CreateSimpleFontPkg(EFI_WIDE_GLYPH* WideGlyph,
                           UINT32 WideGlyphSizeInBytes,
                           EFI_NARROW_GLYPH* NarrowGlyph,
                           UINT32 NarrowGlyphSizeInBytes)
{
  UINT32 PackageLen = sizeof(EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + WideGlyphSizeInBytes + NarrowGlyphSizeInBytes + 4;
  UINT8* FontPackage = (UINT8*)AllocateZeroPool (PackageLen);

  *(UINT32*)FontPackage = PackageLen;

  ...

  return FontPackage;
}

이제 패키지 데이터를 채우자. 먼저 헤더를 채운다.

EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimpleFont;
SimpleFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR*)(FontPackage + 4);
SimpleFont->Header.Length = (UINT32)(PackageLen - 4);
SimpleFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
SimpleFont->NumberOfNarrowGlyphs = (UINT16)(NarrowGlyphSizeInBytes / sizeof(EFI_NARROW_GLYPH));
SimpleFont->NumberOfWideGlyphs = (UINT16)(WideGlyphSizeInBytes / sizeof(EFI_WIDE_GLYPH));

그런 다음 Glyphs 데이터를 복사한다(CopyMem 함수의 경우, <Library/BaseMemoryLib.h> 헤더를 포함한다.).

UINT8* Location = (UINT8*)(&SimpleFont->NumberOfWideGlyphs + 1);
CopyMem(Location, NarrowGlyph, NarrowGlyphSizeInBytes);
CopyMem(Location + NarrowGlyphSizeInBytes, WideGlyph, WideGlyphSizeInBytes);

애플리케이션을 빌드하고 실행하면, 러시아어 문자열이 올바르게 출력되는 것을 볼 수 있다.

애플리케이션의 시작 부분과 끝 부분에 러시아어로 일부 문자열을 출력해보겠다.

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"Привет!\n");

  ...

  Print(L"Привет!\n");

  return EFI_SUCCESS;
}

첫 번째 출력내용은 !만 출력한다. 러시아어 유니코드 기호 Glyph를 표시하는 방법에 대한 정보가 시스템에 없기 때문이다. 그러나 마지막에 글꼴 패키지를 추가한 후의 내용에는 예상된 결과를 출력한다.

Previous52. Russian 글꼴 추가 - Part 1.Next54. EFI_HII_STRING_PROTOCOL의 NewString 및 SetString 함수를 사용하여 다른 언어에 대한 문자열 패키지를 동적으로 추가

Last updated 2 years ago

HiiAddPackages를 사용하여 글꼴 패키지와 애플리케이션 문자열 패키지를 모두 추가한다. (이 함수는 가변적이며, 다양한 수의 패키지를 사용하여 모두 push하여 새 패키지 목록을 만들 수 있다. )

이제 CreateSimpleFontPkg 함수를 정의한다. 먼저, 글꼴 패키지 생성에 필요한 정의 및 유형이다.

🖥️
https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h