# 3. Hello World 출력하기

앞서 생성한 패키지 내부에 `HelloWorld` 애플리케이션을 포함하도록 한다.

```
$ mkdir UefiLessonsPkg/HelloWorld
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.inf
-----
[Defines]
  INF_VERSION                    = 1.25
  BASE_NAME                      = HelloWorld
  FILE_GUID                      = 2e55fa38-f148-42d3-af90-1be247323e30
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

[Sources]
  HelloWorld.c

[Packages]
  MdePkg/MdePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
-----
[Components]
  UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
```

`HelloWorld.c`의 소스 코드는 아래와 같이 작성한다.

```
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
  return EFI_SUCCESS;
}
```

위와 같이 작성한 이유는 다음과 같다.

문자열을 출력하기 위해서는 애플리케이션의 Entry Point에 전달되는`EFI_SYSTEM_TABLE` 서비스를 이용해야 한다.\
`EFI_SYSTEM_TABLE`은 다음과 같이 구성되어 있으며 공식 UEFI 스펙에서 자세히 기술하고 있다.[(https://uefi.org/sites/default/files/resources/UEFI\_Spec\_2\_8\_final.pdf)](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf\))

```
typedef struct {
 EFI_TABLE_HEADER Hdr;
 CHAR16 *FirmwareVendor;
 UINT32 FirmwareRevision;
 EFI_HANDLE ConsoleInHandle;
 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
 EFI_HANDLE ConsoleOutHandle;
 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
 EFI_HANDLE StandardErrorHandle;
 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
 EFI_RUNTIME_SERVICES *RuntimeServices;
 EFI_BOOT_SERVICES *BootServices;
 UINTN NumberOfTableEntries;
 EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
```

그 중에서 `*ConOut`은 'Console Output'의 약자로 `ConsoleOutHandle`과 연결된 `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` 인터페이스에 대한 포인터이다.

`EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` 인터페이스에 대한 정보는 다음과 같다.

```
typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
 EFI_TEXT_RESET Reset;
 EFI_TEXT_STRING OutputString;
 EFI_TEXT_TEST_STRING TestString;
 EFI_TEXT_QUERY_MODE QueryMode;
 EFI_TEXT_SET_MODE SetMode;
 EFI_TEXT_SET_ATTRIBUTE SetAttribute;
 EFI_TEXT_CLEAR_SCREEN ClearScreen;
 EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
 EFI_TEXT_ENABLE_CURSOR EnableCursor;
 SIMPLE_TEXT_OUTPUT_MODE *Mode;
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
```

출력 기능을 담당하는 `OutputString`의 구현은 다음과 같이 정의되어 있다.\
[(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/SimpleTextOut.h)](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/SimpleTextOut.h)

<pre><code><strong>EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString()
</strong>
Summary
Writes a string to the output device.

Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_TEXT_STRING) (
 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
 IN CHAR16 *String
 );

Parameters
This    A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
String  The Null-terminated string to be displayed on the output device(s).
</code></pre>

또한 `L""` 은 `CHAR16` 을 의미하며 다른 프로세서 아키텍처에서 다른 유형 구현을 위한 프록시이다.\
이 때문에 아키텍처별 다른 `ProcessorBind.h` 헤더 정보를 지정하여 빌드한다.

예로 X64경우에는 다음과 같든 헤더 정보를 이용한다[(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/X64/ProcessorBind.h)](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/X64/ProcessorBind.h:)

이제 빌드를 통해 정상적인 출력이 진행되는지 확인해보자

```
$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/HelloWorld.efi ~/UEFI_disk/
$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
                     -drive format=raw,file=fat:rw:~/UEFI_disk \
                     -nographic \
                     -net none
```

아래와 같은 결과를 얻을 수 있다.

```
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
      FS0: Alias(s):HD0a1:;BLK1:
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Press ESC in 4 seconds to skip startup.nsh or any other key to continue.
Shell> fs0:
FS0:\> HelloWorld.efi
Hello World!
FS0:\>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bob-mcd-team.gitbook.io/uefi/uefi-development/uefi-start/3.print-hello-world.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
