51. UEFI APP에 메뉴얼 추가하기(shell의 -?와 help 옵션)

- EFI_SHELL_PROTOCOL의 EFI_SHELL_GET_HELP_TEXT 함수

UEFI shell의 모든 명령어를 보면, -? 옵션을 추가하면, 도움말 메시지를 출력할 수 있다. 예를 들어,

Shell> reset -?
Resets the system.

RESET [-w [string]]
RESET [-s [string]]
RESET [-c [string]]

  -s     - Performs a shutdown.
  -w     - Performs a warm boot.
  -c     - Performs a cold boot.
  string - Describes a reason for the reset.

NOTES:
  1. This command resets the system.
  2. The default is to perform a cold reset unless the -w parameter is
     specified.
  3. If a reset string is specified, it is passed into the Reset()
     function, and the system records the reason for the system reset.

이번 장에서는 help/man 기능을 애플리케이션에 추가하는 방법을 알아볼 것이다.

man finding 및 파싱을 담당하는 Shell 모듈은 ShellManParser이다.

ProcessManFile 함수를 자세히 보면, 다음과 같은 기능들이 있다.

  • gEfiHiiPackageListProtocolGuid에 의한 개방형 이미지 프로토콜

  • 이를 찾아내면, 받은 패키지 목록을 gHiiDatabase -> NewPackageList에 등록한다.

  • HiiGetString의 도움으로 가능한 모든 문자열 ID를 검토한다.

  • ManFileFindTitleSection 함수가 일부 문자열에 대해 true를 반환하면, ManFileFindSections를 실행한다.

ManFileFineTitleSection은 기본적으로 특별한 man 형식의 문자열을 검색한다.

UEFI shell 규격에서 이 형식에 대해 자세히 알아볼 수 있다. https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf

최소한의 manual로 앱 만들기

manual이 있는 애플리케이션을 만들어 보자.

shell 스크립트를 사용하여, 템플릿을 통해 애플리케이션 만들기

새로 만든 애플리케이션을 UefiLessonsPkg.dsc에 추가한다.

기억할 것이라 생각하지만, ShellManParsergEfiHiiPackageListProtocolGuid 프로토콜 데이터에서 maunal 문자열을 검색했다. 따라서 manual 문자열을 이미지 리소스 Section(HIIStringsMan.inf)에 직접 포함해야 한다.

다음은 문자열 파일에 최소화된 내용만을 담은 코드이다.

애플리케이션을 빌드하고, 실행하려고 하면 더 이상 아무런 도움이 되지 않는다는 것을 볼 수 있다.

이는 프로그램이 문자열 토큰을 참조하지 않고, 빌드 프로세스(HIIStringsManStrDefs.h)에서 최적화되었기 때문이다.

이를 수정하려면, 다음 코드를 HIIStringsMan.c에 추가하면 된다.

현재 문자열이 최적화되지 않았음을 빌드 이후에 확인할 수 있다.

애플리케이션을 실행하고 나면, 다음과 같은 결과를 확인할 수 있다.

우리의 Manual을 확장하기

manual에 들어갈 수 있는 모든 섹션을 추가해보자.

여기까지 빌드하고, 실행하면 다음 내용이 출력되는 것을 확인할 수 있다.

보다시피, 넣어준 모든 섹션에 대한 print가 되지 않았다는 것을 알 수 있다. 그 이유에 대해 알아보자.

먼저 명령어에 -? 옵션을 추가해주면, 어떤 일이 일어나는지 알아보도록 하자. shell의 소스코드를 보면 shell이 -?를 명령 인수 중 하나로, command 및 나머지 모든 인수를 Shell.c의 도움말 명령으로 리다이렉트한다.

프로그램에 직접 help 명령을 사용하면, 결과가 동일하게 출력되는지 확인할 수 있다.

이제 도움말 명령 소스 코드(Help.c)를 살펴보자.

여기에서 help를 넣어줄 인수를 파싱하는 방법을 찾아볼 수 있다.

  • 기본적으로 NAME, SYNOPSIS, OPTIONS, DESCRIPTION, EXAMPLES 섹션이 프린트된다.

  • -section <SECTION NAME> 인수를 사용해 특정 섹션을 출력할 수 있다.

  • -verbose 혹은 -v 인수를 사용해 모든 섹션들을 출력할 수 있다.

Shell에서 이 내용을 직접 확인해 볼 수 있다.

-? 옵션도 마찬가지다.

ShellManParser가 호출되는 방식

ShellManParser가 애플리케이션 문자열을 파싱한 것이라는 가정으로, 이번 장을 시작했었다. 도움말 프로그램이 이 모듈을 사용하여, 어떻게 끝나는 지 조사해보자.

모든 걸 따져보면, ShellCommandRunHelpShellPrintHelp 함수(Help.c)를 호출한다.

이 ShellPrintHelp 함수는 UefiShellLib.c에 정의되어 있다. 주로 EFI_SHELL_PROTOCOL에서 GetHelpText 함수를 호출한다.

다음은 UEFI Shell 규격에서의 위 함수에 대한 설명이다.

EDKII의 EFI_SHELL_PROTOCOL structure에 대한 프로토타입은 Shell.h에 나와있다.

이 프로토콜에 대한 초기화는 ShellProtocol.c에 있다.

이 함수는 위의 동일한 파일에 정의되어 있으며, 정의를 읽어보면 ProcessManFile 모듈에서 함수를 호출하고 있음을 알 수 있다.

Last updated