55. PlatformLangCodes EFI 변수 수정 및 다른 언어를 동적 추가하기

우리는 새 언어에 대한 글꼴을 추가해주는 방법을 학습했으며, 시스템의 일부 기존 언어에 대한 문자열을 동적으로 채우는 방법을 알게 되었다. 이번 장에서는 다른 언어를 동적으로 생성할 수 있는지 살펴보겠다.

Select Language 메뉴는 PlatformLangCodes EFI 변수 값에서 가능한 모든 언어 옵션을 가져온다. 그리고 현재 언어 옵션은 PlatformLang EFI 옵션에 반영된다.

이러한 옵션의 값은 https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec서 PCD의 도움으로 설정된다.

  ## Default platform supported RFC 4646 languages: (American) English & French.
  # @Prompt Default Value of PlatformLangCodes Variable.
  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes|"en;fr;en-US;fr-FR"|VOID*|0x0000001e

  ## Default current RFC 4646 language: (American) English.
  # @Prompt Default Value of PlatformLang Variable.
  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang|"en-US"|VOID*|0x0000001f

https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c 에서 UiCreateLanguageMenu 함수의 실제 코드를 볼 수 있다.

PlatformLangCodes를 수정하고, 다른 언어를 추가할 수 있는지 살펴보자.

먼저 PlatformLangCodes 옵션의 값을 출력하는 애플리케이션을 만든다.

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

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS Status;

  CHAR8* LanguageString;
  Status = GetEfiGlobalVariable2(L"PlatformLangCodes", (VOID**)&LanguageString, NULL);
  if (EFI_ERROR(Status)) {
    Print(L"Error! Can't perform GetEfiGlobalVariable2, status=%r\n", Status);
    return Status;
  }
  Print(L"Current value of the 'PlatformLangCodes' variable is '%a'\n", LanguageString);

  return EFI_SUCCESS;
}

이전에 이미 gRT->GetVariable 프로토콜 함수를 직접 사용한 적이 있으므로, 여기서는 GetEfiGlobalVariable2 라이브러리 함수를 사용하여 코드를 단순화한다. 이 함수는 https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiLib/UefiLib.c 정의되어 있다.

애플리케이션을 빌드하고 실행하면, PCD에서 값을 얻을 수 있다.

이제 변수 끝에 ;ru-RU를 추가하고 다시 작성해보자.

먼저 새 문자열을 구성하고 필요한 데이터로 채운다.

ASCII 문자열 함수가 https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/String.c 정의된 경우에 대비. 또한 AllocatePool 함수에 대한 Library/MemoryAllocationLib.h 헤더와 CopyMem 함수에 대한 Library/BaseMemoryLib.h 헤더를 포함하는 것을 잊지 않도록 하자.

이제 SetVariable 호출을 사용하여 변수를 업데이트한다.

SetVariable은 Runtime 서비스이며, UEFI 스펙에서 해당 정의를 찾을 수 있다.

gRTUefiRuntimeServicesTableLib 라이브러리의 SystemTable->RuntimeServices에 대한 바로가기이다. 따라서 라이브러리 헤더 <Library/UefiRuntimeServicesTableLib.h>를 포함하는 것을 잊지 않도록 하자.

애플리케이션을 빌드하고 실행하면, 다음과 같은 결과를 얻을 수 있다.

안타깝게도, 'PlatformLangCodes' EFI 변수가 쓰기 금지되어 있으므로 Runtime 시, 새 언어를 추가할 수 없다. 따라서 Runtime에 다른 로컬화 언어를 추가할 수 없다.

UEFI 스펙을 보면 다음과 같이 표시된다.

EDKII_VARIABLE_POLICY_PROTOCOL

PlatformLangCodesgEdkiiVariablePolicyProtocolGuid 프로토콜의 도움으로 수정할 수 있도록 잠겨 있다. 이는 변수에 대해 다른 정책을 설정하기 위한 사용자 정의 EDKII 프로토콜이다.

https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md 보면, UEFI 변수 정책 프로토콜에 대한 자세한 내용을 알 수 있다.

https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Protocol/VariablePolicy.h 아래에 헤더파일이 존재한다.

PlatformLangCodes EFI 변수에 대한 정책은 몇가지 다른 변수와 함께 https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/BdsDxe/BdsEntry.c 설정된다.

Try to execute DisableVariablePolicy()

DisableVariablePolicy()를 수행하여, VariablePolicyProtocol을 비활성화할 수 있다.

하지만, 이 호출에 에러가 발생한다.

이는 DXE UEFI 단계의 변수 정책이 VariableDxe.c에서 잠겨있기 때문에 발생하는 것이다.

Locking(잠금)은 더 이상 변수에 대한 정책을 변경하거나, 비활성화할 수 없음을 의미한다. 따라서 Runtime에 PlatformLangCodes를 변경할 방법이 없다.

Last updated