29. EFI_ACPI_SDT_PROTOCOL 및 ShellLib를 사용하여 ACPI BGRT 테이블에서 BMP 이미지 저장하기
지난 장에서 시스템에 BGRT ACPI 테이블이 있음을 확인했다.
ACPI 스펙에 따르면:
BGRT(Boot Graphics Resource Table)는 다음을 나타내는 메커니즘을 제공하는 선택적 테이블입니다.
부팅하는 동안 화면에 이미지가 그려지고 이미지에 대한 일부 정보가 표시됩니다.
이미지가 화면에 그려지면 테이블이 작성됩니다.
이 작업은 펌웨어 구성 요소가 화면에 기록될 것으로 예상되고 이미지만 화면에 표시된 후 수행해야 합니다.
부팅 경로가 중단된 경우(예시: 키 누름), 현재 이미지가 무효화되었음을 OS에 나타내려면
Status 필드를 0으로 변경해야 합니다.
////// Boot Graphics Resource Table definition.///typedefstruct { EFI_ACPI_DESCRIPTION_HEADER Header; /// /// 2-bytes (16 bit) version ID. This value must be 1. /// UINT16 Version; /// /// 1-byte status field indicating current status about the table. /// Bits[7:1] = Reserved (must be zero) /// Bit [0] = Valid. A one indicates the boot image graphic is valid. /// UINT8 Status; /// /// 1-byte enumerated type field indicating format of the image. /// 0 = Bitmap /// 1 - 255 Reserved (for future use) /// UINT8 ImageType; /// /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy /// of the image bitmap. /// UINT64 ImageAddress; /// /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. /// (X, Y) display offset of the top left corner of the boot image. /// The top left corner of the display is at offset (0, 0). /// UINT32 ImageOffsetX; /// /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. /// (X, Y) display offset of the top left corner of the boot image. /// The top left corner of the display is at offset (0, 0). /// UINT32 ImageOffsetY;} EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE;
EFI_ACPI_SDT_PROTOCOL.GetAcpiTable()
Summary:
Returns a requested ACPI table.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_ACPI_GET_ACPI_TABLE) (
IN UINTN Index,
OUT EFI_ACPI_SDT_HEADER **Table,
OUT EFI_ACPI_TABLE_VERSION *Version,
OUT UINTN *TableKey
);
Parameters:
Index The zero-based index of the table to retrieve.
Table Pointer for returning the table buffer.
Version On return, updated with the ACPI versions to which this table belongs.
TableKey On return, points to the table key for the specified ACPI system definition table.
Description:
The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated with the Index that was input. The following structures are not considered elements in the list of ACPI tables:
- Root System Description Pointer (RSD_PTR)
- Root System Description Table (RSDT)
- Extended System Description Table (XSDT)
모든 테이블을 가져오기 위해서는 0부터 시작하여 인덱스 값을 증가시키는 GetAcpiTable을 호출해야 하며 함수는 EFI_SUCCESS를 반환해야 한다.
모든 성공 호출을 하면 ACPI 테이블의 공통 헤더에 대한 포인터를 얻을 수 있다.
이미지가 BMP인 것이 확인되면 서명(BM)을 확인하고 크기를 파싱 후 실제로 데이터를 파일에 쓰기가 가능하다. 여기서는 EFI_STATUS WriteFile(CHAR16* FileName, VOID* Data, UINTN* Size) 함수를 통해서 파일에 데이터를 쓰며 이에 대한 정의는 이후에 언급하겠다.
/**
This function will open a file or directory referenced by filename.
If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
otherwise, the Filehandle is NULL. Attributes is valid only for
EFI_FILE_MODE_CREATE.
@param[in] FileName The pointer to file name.
@param[out] FileHandle The pointer to the file handle.
@param[in] OpenMode The mode to open the file with.
@param[in] Attributes The file's file attributes.
...
**/
EFI_STATUS
EFIAPI
ShellOpenFileByName(
IN CONST CHAR16 *FileName,
OUT SHELL_FILE_HANDLE *FileHandle,
IN UINT64 OpenMode,
IN UINT64 Attributes
);
/**
Write data to a file.
This function writes the specified number of bytes to the file at the current
file position. The current file position is advanced the actual number of bytes
written, which is returned in BufferSize. Partial writes only occur when there
has been a data error during the write attempt (such as "volume space full").
The file is automatically grown to hold the data if required. Direct writes to
opened directories are not supported.
@param[in] FileHandle The opened file for writing.
@param[in, out] BufferSize On input the number of bytes in Buffer. On output
the number of bytes written.
@param[in] Buffer The buffer containing data to write is stored.
...
**/
EFI_STATUS
EFIAPI
ShellWriteFile(
IN SHELL_FILE_HANDLE FileHandle,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
);
/**
Close an open file handle.
This function closes a specified file handle. All "dirty" cached file data is
flushed to the device, and the file is closed. In all cases the handle is
closed.
@param[in] FileHandle The file handle to close.
**/
EFI_STATUS
EFIAPI
ShellCloseFile (
IN SHELL_FILE_HANDLE *FileHandle
);
ShellLib 사용으로써 얻는 점은 EFI_SHELL_PROTOCOL을 찾아서 수동으로 작업할 필요가 없다는 것이다.
WriteFile 함수는 아래와 같다.
EFI_STATUS WriteFile(CHAR16* FileName, VOID* Data, UINTN* Size){ SHELL_FILE_HANDLE FileHandle; EFI_STATUS Status =ShellOpenFileByName( FileName,&FileHandle, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ,0 );if (!EFI_ERROR(Status)) {Print(L"Save it to %s\n", FileName); UINTN ToWrite =*Size; Status =ShellWriteFile( FileHandle,Size, Data );if (EFI_ERROR(Status)) {Print(L"Can't write file: %r\n", Status); }if (*Size!= ToWrite) {Print(L"Error! Not all data was written\n"); } Status =ShellCloseFile(&FileHandle );if (EFI_ERROR(Status)) {Print(L"Can't close file: %r\n", Status); } } else {Print(L"Can't open file: %r\n", Status); } ret
ShellLib를 사용하기 위해서 헤더 파일을 추가하고 [Packages], [LibraryClasses]에도 ShellLib를 추가해야 한다.
BGRT 드라이버는 플래시 이미지를 사용하지 않고 실제로 부팅 화면을 가져와 BMP 이미지로 변환하기 때문에 파일 자체는 동일하지 않는다. BGRT가 플래시 이미지를 사용하는 대신 화면을 잡는 것이 이상하다고 생각되면 ACPI 스펙에서 BGRT가 정의된 방식을 다시 생각하는 것이 좋다.
BGRT(Boot Graphics Resource Table)는 부팅 중에 이미지가 화면에 그려졌음을 나타내는 메커니즘을 제공하는 선택적 테이블입니다.