1. gBS란?
UEFI 환경이 제공하는 부트 서비스 테이블(EFI_BOOT_SERVICES)을 가리키는 전역 포인터이다. 시스템 전체 관점에서는 DXE 코어 단계에서 테이블이 생성되며, 전역 포인터 gBS 자체는 각 모듈(드라이버/애플리케이션)의 진입점(Entry Point)이 호출될 때 UefiBootServicesTableLib에 의해 해당 모듈 내에서 자동으로 초기화된다. OS 로더가 메모리와 제어권을 완전히 넘겨받기 위해 ExitBootServices() 함수를 호출하기 전까지만 유효하다.
운영체제가 부팅되기 전 단계인 프리부트 환경에서 미니 운영체제(kernel)와 같은 역할을 수행하며 메모리 할당/해제, 프로토콜 설치/검색, 이벤트 및 타이머 생성, 이미지 로드/실행 등 펌웨어 레벨에서 필요한 모든 핵심 시스템 콜을 제공한다.
2. EFI_BOOT_SERVICES 주요 카테고리
EFI_BOOT_SERVICES 구조체 내에는 수십 개의 함수 포인터가 포함되어 있으며, 크게 6가지 영역으로 나눌 수 있다.
- Task Priority Services: 인터럽트 우선순위(TPL)를 조절하여 임계 영역을 보호하거나 비동기 작업의 우선순위를 결정
- Memory Services: AllocatePool, AllocatePages 등을 통해 메모리를 할당하고, 시스템 메모리 맵(GetMemoryMap)을 관리
- Event & Timer Services: 단일 스레드 환경인 UEFI에서 비동기 콜백이나 주기적인 작업을 수행하기 위한 이벤트 및 타이머를 생성
- Protocol Services: UEFI 아키텍처의 핵심인 프로토콜(Interface)을 설치하거나 검색(LocateProtocol, OpenProtocol)하여 드라이버 간 통신을 가능하게 함 (최신 스펙에서는 레거시인 HandleProtocol 대신 OpenProtocol 사용을 강력히 권장)
- Image Services: PE/COFF 포맷의 UEFI 드라이버나 애플리케이션을 메모리에 로드(LoadImage)하고 실행(StartImage)한다.
- Miscellaneous Services: 딜레이(Stall), 메모리 제어(CopyMem, SetMem) 및 시스템 설정 테이블(ACPI, SMBIOS 등) 관리를 위한 부가 기능 제공
3. 구조체 정의 분석(축약)
// MdePkg/Include/Uefi/UefiSpec.h
typedef struct {
EFI_TABLE_HEADER Hdr;
// 1. Task Priority (인터럽트 레벨 제어)
EFI_RAISE_TPL RaiseTPL;
EFI_RESTORE_TPL RestoreTPL;
// 2. Memory Services (메모리 할당/해제)
EFI_ALLOCATE_PAGES AllocatePages;
EFI_FREE_PAGES FreePages;
EFI_GET_MEMORY_MAP GetMemoryMap;
EFI_ALLOCATE_POOL AllocatePool;
EFI_FREE_POOL FreePool;
// 3. Event & Timer Services (이벤트 및 타이머)
EFI_CREATE_EVENT CreateEvent;
EFI_SET_TIMER SetTimer;
EFI_WAIT_FOR_EVENT WaitForEvent;
// 4. Protocol Management (프로토콜 설치/검색)
EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface;
EFI_OPEN_PROTOCOL OpenProtocol; // HandleProtocol 대체 권장
EFI_CLOSE_PROTOCOL CloseProtocol;
EFI_LOCATE_PROTOCOL LocateProtocol;
// 5. Image Services (이미지 로드/실행)
EFI_IMAGE_LOAD LoadImage;
EFI_IMAGE_START StartImage;
EFI_EXIT_BOOT_SERVICES ExitBootServices; // 부트 서비스 종료!
// 6. Miscellaneous Services (기타 유틸리티)
EFI_STALL Stall;
EFI_COPY_MEM CopyMem;
EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable;
// (이외 다수의 함수 포인터 존재)
} EFI_BOOT_SERVICES;
EDK2 소스코드 내에서는 gBS는 전역 포인터로 선언되어 있으며, 실제 가리키는 EFI_BOOT_SERVICES 구조체는 수십 개의 함수 포인터를 담고 있는 거대한 테이블이다.
4. 자주 쓰는 패턴
4.1. 프로토콜 검색: gBS->LocateProtocol
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/GraphicsOutput.h>
EFI_STATUS GetGop() {
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
// 시스템에 등록된 첫 번째 GOP 인스턴스를 검색
Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
return Status;
}
특정 하드웨어나 기능을 제어하기 위해 해당 프로토콜의 인스턴스를 찾을 때 사용한다. 단 LocateProtocol은 시스템에 등록된 첫 번째 인스턴스만 반환하므로 주의가 필요하다.
디스플레이나 네트워크 카드 등 동일한 장치가 여러 개일 수 있는 환경에서 특정 인스턴스를 정확히 제어하려면, gBS->LocateHandleBuffer를 통해 전체 핸들 목록을 가져온 뒤 탐색하는 패턴을 함께 사용하는 것이 좋다.
4.2. 메모리 할당: gBS->AllocatePool
EFI_STATUS Status;
VOID *Buffer = NULL;
// 1024바이트 할당 (OS 부팅 시 해제되는 타입)
Status = gBS->AllocatePool(EfiBootServicesData, 1024, (VOID **)&Buffer);
// 할당 성공 여부를 Status로 명확히 검증 후 해제 (Memory Leak 방지)
if (!EFI_ERROR(Status)) {
gBS->FreePool(Buffer);
}
OS의 malloc과 동일한 역할을 수행한다. 할당 시 메모리 타입을 지정하여 OS 부팅 후 해당 데이터를 유지할지 결정한다. 포인터의 NULL 여부로 할당 성공을 판단하기보다는, EDK2 코딩 스탠다드에 맞춰 반환된 EFI_STATUS 값을 검증(EFI_ERROR 매크로 사용)하는 것이 가장 안전하다.
'CS > Graduation project' 카테고리의 다른 글
| [UEFI] Ghidra에서 edk2 함수 P-code로 확인해 보기 (0) | 2026.02.26 |
|---|---|
| [UEFI] gRT(Runtime Services)란? (0) | 2026.02.24 |
| [UEFI] SMM/MM Communication Protocol이란? (0) | 2026.02.24 |
| [UEFI] CommBuffer 검증 우회 (Ring -2) (0) | 2026.02.24 |
| [UEFI] BRLY-2022-016 분석 및 재현 (CommBuffer) (0) | 2026.02.23 |