💻
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
  • Glyph 기본 글꼴
  • 러시아어 글꼴에 대한 Glyph 데이터 가져오기
  1. UEFI 개발
  2. HII

52. Russian 글꼴 추가 - Part 1.

EFI_NARROW_GLYPH/EFI_WIDE_GLYPH 형식 조사 및 *.woff 글꼴 파일에서 GLYPH 배열 구성

Previous51. UEFI APP에 메뉴얼 추가하기(shell의 -?와 help 옵션)Next53. Russian 글꼴 추가 - Part 2.

Last updated 2 years ago

UNI 파일은 UEFI의 로컬화를 위한 것이다. 지금까지 우리는, UNI 파일에서 영어와 프랑스어만 출력해 보았다. 이 두 언어의 공통점은, 라틴어 문자 집합의 기호를 사용한다는 점에서 같다.

다른 문자 집합에서 문자열을 출력하려면 올바른 문장이 출력되지 않는다. 예를 들어, 간단하게 Hello를 러시아어로 출력하려면,

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

다음과 같이 출력된다.

nographic 모드에서는 다음과 같이 출력될 것이다.

FS0:\> HIIFont.efi
?@825B!

이 출력을 구현하는 것에는 신경쓰지 말자. 이는 다른 번역 레벨에서 발생하는 것이고, 이번 장에서는 UEFI Graphic(Native 또는 VNC)을 살펴보도록 하자.

어쨌건 출력으로 보이듯이, ! 하나만 출력된 것을 볼 수 있다. UEFI 시스템 자체에는 러시아어 글꼴이 없기 때문에 위와 같은 일이 발생한 것이다.

컴퓨터의 언어로 해석하자면, 러시아어 유니코드 기호 코드를 기호 이미지로 변환하는 방법을 UEFI 시스템은 모르기 때문이다.

글꼴 정보는 HII DB에 저장되므로, 문제를 해결하려면 러시아 코드가 있는 유니코드 기호에 대한 "그림"이 있는 글꼴 유형 패키지가 포함된 패키지 목록을 제공하기만 하면 된다.

UEFI는 작게는 8x19에 넓게는 16x19 글꼴은 사용한다. 코드에서 기호 데이터는 EFI_NARROW_GLYPH 및 EFI_WIDE_GLYPH(UefiInternalFormRepresentation.h) 구조로 인코딩된다.

$ cat MdePkg/Include/Uefi/UefiInternalFormRepresentation.h
---
#define EFI_GLYPH_HEIGHT                     19
#define EFI_GLYPH_WIDTH                      8
///@}

///
/// The EFI_NARROW_GLYPH has a preferred dimension (w x h) of 8 x 19 pixels.
///
typedef struct {
  ///
  /// The Unicode representation of the glyph. The term weight is the
  /// technical term for a character code.
  ///
  CHAR16                 UnicodeWeight;
  ///
  /// The data element containing the glyph definitions.
  ///
  UINT8                  Attributes;
  ///
  /// The column major glyph representation of the character. Bits
  /// with values of one indicate that the corresponding pixel is to be
  /// on when normally displayed; those with zero are off.
  ///
  UINT8                  GlyphCol1[EFI_GLYPH_HEIGHT];
} EFI_NARROW_GLYPH;

///
/// The EFI_WIDE_GLYPH has a preferred dimension (w x h) of 16 x 19 pixels, which is large enough
/// to accommodate logographic characters.
///
typedef struct {
  ///
  /// The Unicode representation of the glyph. The term weight is the
  /// technical term for a character code.
  ///
  CHAR16                 UnicodeWeight;
  ///
  /// The data element containing the glyph definitions.
  ///
  UINT8                  Attributes;
  ///
  /// The column major glyph representation of the character. Bits
  /// with values of one indicate that the corresponding pixel is to be
  /// on when normally displayed; those with zero are off.
  ///
  UINT8                  GlyphCol1[EFI_GLYPH_HEIGHT];
  ///
  /// The column major glyph representation of the character. Bits
  /// with values of one indicate that the corresponding pixel is to be
  /// on when normally displayed; those with zero are off.
  ///
  UINT8                  GlyphCol2[EFI_GLYPH_HEIGHT];
  ///
  /// Ensures that sizeof (EFI_WIDE_GLYPH) is twice the
  /// sizeof (EFI_NARROW_GLYPH). The contents of Pad must
  /// be zero.
  ///
  UINT8                  Pad[3];
} EFI_WIDE_GLYPH;

이유는 모르겠지만, mFontBin 구조의 String.c에서 일부 히브리어 문자에 대한 예를 찾아볼 수 있었다. 이 구조에서 유니코드 0x05d2가 있는 기호 하나를 살펴보도록 하겠다.

GlyphCol1 배열을 보고, 이진 시스템에서 배열 데이터를 인쇄해보자. X/-로도 표현해 보았다.

$ cat MdeModulePkg/Application/UiApp/String.c
---
        {
      0x05d2,
      0x00,
      {
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x78,      // 01111000 // -XXXX---
        0x7C,      // 01111100 // -XXXXX--
        0x0C,      // 00001100 // ----XX--
        0x0C,      // 00001100 // ----XX--
        0x0C,      // 00001100 // ----XX--
        0x0C,      // 00001100 // ----XX--
        0x0C,      // 00001100 // ----XX--
        0x0C,      // 00001100 // ----XX--
        0x1C,      // 00011100 // ---XXX--
        0x3E,      // 00111110 // --XXXXX-
        0x66,      // 01100110 // -XX--XX-
        0x66,      // 01100110 // -XX--XX-
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00       // 00000000 // --------
      }
    },

EDKII 코드베이스에 기호에 대한 에는 없지만, 간단하다. GlyphCol1은 기호 이미지의 왼쪽 절반을 인코딩하고, GlyphCol2는 남은 오른쪽 절반을 인코딩한다.

예를 들어, A는 다음과 같을 수있다.

    {
      0x05d2,
      0x00,
      {
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x01,      // 00000001 // -------X
        0x02,      // 00000010 // ------X-
        0x02,      // 00000010 // ------X-
        0x04,      // 00000100 // -----X--
        0x04,      // 00000100 // -----X--
        0x08,      // 00001000 // ----X---
        0x0F,      // 00001111 // ----XXXX
        0x10,      // 00010000 // ---X----
        0x10,      // 00010000 // ---X----
        0x20,      // 00100000 // --X-----
        0x20,      // 00100000 // --X-----
        0x70,      // 01110000 // -XXX----
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00       // 00000000 // --------
      },
      {
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x80,      // 10000000 // X-------
        0x80,      // 10000000 // X-------
        0x40,      // 01000000 // -X------
        0x40,      // 01000000 // -X------
        0x20,      // 00100000 // --X-----
        0xE0,      // 11100000 // XXX-----
        0x10,      // 00010000 // ---X----
        0x10,      // 00010000 // ---X----
        0x08,      // 00001000 // ----X---
        0x08,      // 00001000 // ----X---
        0x1C,      // 00011100 // ---XXX--
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00,      // 00000000 // --------
        0x00       // 00000000 // --------
      },
      {
        0x00,
        0x00,
        0x00
      }
    },

Glyph 기본 글꼴

기본 글꼴의 정의 위치가 궁금할 경우, LaffStd.c를 참조하는 것을 추천한다.

$ cat MdeModulePkg/Universal/Console/GraphicsConsoleDxe/LaffStd.c
---
EFI_NARROW_GLYPH  gUsStdNarrowGlyphData[] = {
  { 0x0020, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
  { 0x0021, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}},
  { 0x0022, 0x00, {0x00,0x00,0x00,0x6C,0x6C,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
  ...
  { 0x0000, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} //EOL
};

// Get available Unicode glyphs narrow fonts(8*19 pixels) size.
UINT32 mNarrowFontSize =  sizeof (gUsStdNarrowGlyphData);

이 gUsStdNarrowGlyphData 배열은 글꼴 패키지를 생성하고, HII 데이터베이스에 등록하는 데 사용된다. 실제 코드는 MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c 파일의 RegisterFontPackage 함수를 참조하도록 하자.

HII 데이터베이스에 패키지 목록을 조사했을 때, 이것이 이 글꼴을 담당했다.

PackageList[10]: GUID=F5F219D3-7006-4648-AC8D-D61DFB7BC6AD; size=0x14EC  // mFontPackageListGuid
        Package[0]: type=SIMPLE_FONTS; size=0x14D4
        Package[1]: type=END; size=0x4

러시아어 글꼴에 대한 Glyph 데이터 가져오기

Glyph 데이터를 얻어오는 것은 글꼴을 추가하는 작업에 있어서 가장 어려운 것이다.

HTML canvas의 글꼴에서 각 기호를 하나씩 인쇄한다. 각 기호에 대해 이미지 비트맵을 가져오고 해당 데이터를 사용하여 UEFI 환경에서 사용할 수 있는 Glyph 배열을 구성한다. 결국 Glyph 배열을 화면에 출력한다.

이는 자바스크립트와 관련된 장장이 아니지만, 스크립트에 대한 설명이 필요하다고 생각한다. 먼저 글꼴을 로드하고 canvas와 스크립트 코드를 선언하는 HTML 부분이다.

<html>
  <head>
    <style>
      @font-face {
        font-family: "AST";
        src: url(web_ast_premiumexec.woff) format('woff');
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" width="32" height="32"></canvas>
    <script type="text/javascript">
      ...
    </script>
  </body>
</html>

우리의 코드는 핵심, 다음과 같다.

const unicode_start_code = 0x0400;
const unicode_end_code = 0x045F;
var f = new FontFace('AST', 'url(web_ast_premiumexec.woff)');
f.load().then(function() {
  document.write(UnicodeToGlyphs(unicode_start_code, unicode_end_code));
})

글꼴이 로드되면, canvas에 U+0400에서 U+045F까지의 유니코드 기호를 인쇄하고, 데이터를 조사하고 화면의 UEFI에 대한 최종 C 배열을 출력하는 사용자 지정 함수 UnicodeToGlyphs를 실행한다.

그리고 여기에 나머지 자바스크립트코드가 있다. 이는 매우 간단하므로, 이해하기 어렵지 않을 것이라 생각한다.

function decimalToHex(d, padding) {
  var hex = Number(d).toString(16);
  padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;

  while (hex.length < padding) {
    hex = "0" + hex;
  }

  return hex;
}

function UnicodeToGlyphs(unicode_start_code, unicode_end_code) {
  const threshold = 100;                // `A` threshold to count data as a black pixel
  const FW = 16;
  const FH = 19;
  const left_glyph_start_column = 0;
  const left_glyph_end_column = FW/2 - 1;
  const right_glyph_start_column = FW/2;
  const right_glyph_end_column = FW - 1;

  const canvas = document.getElementById('canvas');
  canvas.width *= window.devicePixelRatio
  canvas.height *= window.devicePixelRatio
  canvas.style.width = 32
  canvas.style.height = 32
  const ctx = canvas.getContext('2d');
  ctx.strokeRect(0, 0, FW, FH);
  ctx.font = "19px AST"
  ctx.fillstyle='#00f';

  var wide_glyphs_str="EFI_WIDE_GLYPH  gSimpleFontWideGlyphData[] = {<BR>";
  var narrow_glyphs_str="EFI_NARROW_GLYPH  gSimpleFontNarrowGlyphData[] = {<BR>";
  for(i=unicode_start_code; i<=unicode_end_code; i++){
    wide_glyph = false;
    ctx.clearRect(0, 0, FW, FH);
    ctx.fillText(String.fromCharCode(i), 0, 0 + FW-1);
    var bitmapimg = ctx.getImageData(0, 0, FW, FH);
    var bitmap = bitmapimg.data;
    var left_glyph = " ";
    var right_glyph = " ";
    for (row=0; row<FH; row++){
      left_row = 0;
      for (col=left_glyph_start_column; col<=left_glyph_end_column; col++){
        left_row <<= 1
        if (bitmap[row*FW*4 + col*4 + 3] > threshold)
          left_row |= 1;
      }
      left_glyph += "0x" + decimalToHex(left_row);

      right_row = 0;
      for (col=right_glyph_start_column; col<=right_glyph_end_column; col++){
        right_row <<= 1
        if(bitmap[row*FW*4 + col*4 + 3] > threshold) {
          wide_glyph = true;
          right_row |= 1;
        }
      }
      right_glyph += "0x" + decimalToHex(right_row);

      if (row < (FH-1)) {
        left_glyph += ",";
        right_glyph += ",";
      }
    }
    if (wide_glyph)
      wide_glyphs_str += "{ 0x" + decimalToHex(i) + ", 0x00, " + "{" +  left_glyph + "}, {" + right_glyph + "}, {0x00,0x00,0x00}}," + "<BR>";
    else
      narrow_glyphs_str += "{ 0x" + decimalToHex(i) + ", 0x00, " + "{" +  left_glyph + "}},"+ "<BR>";
  }
  narrow_glyphs_str += "};<BR>"
  narrow_glyphs_str += "UINT32 gSimpleFontNarrowBytes = sizeof(gSimpleFontNarrowGlyphData);<BR>"
  wide_glyphs_str += "{ 0x00, 0x00, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}" + "<BR>"
  wide_glyphs_str += "};<BR>"
  wide_glyphs_str += "UINT32 gSimpleFontWideBytes = sizeof(gSimpleFontWideGlyphData);<BR>"
  return wide_glyphs_str + "<BR>" + narrow_glyphs_str;
}

create_font_data.html과 web_ast_premiumexec.woff를 두고 create_font_data.html을 연다. 이 작업을 위해 Chrome(version 95.0.4638.69)을 사용했다. 페이지는 다음과 같이 출력되어야 한다.

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}},
 ...
{ 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);

우리가 가져온 글꼴은 고정된 크기인 8x19 문자만 포함하므로, gSimpleFontNarrowGlyphData 배열만 데이터로 채워진다. 이제 UEFI 애플리케이션을 구성하고, 글꼴을 HII 데이터베이스에 추가할 때이다.

이는 실제 히브리어 문자인 gimel &#0x05D2(U+05D2)로 보인다.

우선 크기가 8x19/16x19인 픽셀 글꼴을 찾아야 하는데, 이는 이미 어려운 작업일 수 있다. 에서 키릴 문자가 포함된 AST PremiumExec 글꼴을 찾았다. 이 글꼴에는 대부분의 키릴 유니코드 블록(U+0400 - U+04FF)의 심볼들을 포함하고 있다.

하지만 이 글꼴은 *.woff 형식으로 인코딩되어 있으므로, Glyph 데이터로 변환해야 한다. 수동으로 변환해주기에는 어려움이 있기에, 서 이 작업에 HTML canvas를 사용해보자는 아이디어를 차용했다.

🖥️
https://unicodemap.org/details/0x05D2/index.html
https://int10h.org/oldschool-pc-fonts/fontlist/font?ast_premiumexec
https://github.com/zhenghuadai/uefi-programming/tree/master/book/GUIbasics/font