获取支持的文本显示模式

到目前为止,我们的控制台输出所用的都是UEFI默认的文本显示模式(Text mode)。通过切换到其它设备支持的文本显示模式,我们可以改变屏幕显示的行数和列数。本节将讲述如何获取设备支持的文本显示模式。

本节示例代码的目录为query-text-mode (日文版为012_simple_text_output_query_mode)。

利用QueryMode()函数可以通过某个文本显示模式的ID来获取它对应的行数和列数,图2.8展示了它的定义。

struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
    ...
    unsigned long long (*QueryMode)(
        struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
        unsigned long long ModeNumber,  /* 要查询的文本显示模式ID */
        unsigned long long *Columns,    /* 指向存放返回的列数的变量的指针 */
        unsigned long long *Rows        /* 指向存放返回的行数的变量的指针 */
        );
    ...
};

图2.8: QueryMode()的定义(位于efi.h中)

QueryMode()的第二个参数ModeNumber的值在所支持的文本显示模式的范围外时,将会返回EFI_UNSUPPORTED(0x80000000 00000003)

要获取设备支持的文本显示模式的范围,需要用到EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL->Mode->MaxMode这个值,所有支持的文本显示模式的都在[0, MaxMode - 1]这个区间内。而EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL->Mode是一个SIMPLE_TEXT_OUTPUT_MODE的结构体,它的定义如图2.9所示。

#define EFI_SUCCESS      0
#define EFI_ERROR        0x8000000000000000
#define EFI_UNSUPPORTED  (EFI_ERROR | 3)

struct SIMPLE_TEXT_OUTPUT_MODE {
    int MaxMode;                  /* 所支持的文本显示模式的ID上限 */
    int Mode;                     /* 当前的文本显示模式ID */
    int Attribute;                /* 当前设置的文字颜色和背景色 */
    int CursorColumn;             /* 当前光标所在列 */
    int CursorRow;                /* 当前光标所在行 */
    unsigned char CursorVisible;  /* 当前是否显示光标 */
};

图2.9: SIMPLE_TEXT_OUTPUT_MODE结构体的定义(位于efi.h中)

在上面的基础上,使用QueryMode()的一个例子如图2.10所示

#include "efi.h"
#include "common.h"

void efi_main(void *ImageHandle __attribute__ ((unused)),
          struct EFI_SYSTEM_TABLE *SystemTable)
{
    int mode;
    unsigned long long status;
    unsigned long long col, row;

    efi_init(SystemTable);
    ST->ConOut->ClearScreen(ST->ConOut);

    for (mode = 0; mode < ST->ConOut->Mode->MaxMode; mode++) {
        status = ST->ConOut->QueryMode(ST->ConOut, mode, &col, &row);
        switch (status) {
        case EFI_SUCCESS:
            puth(mode, 2);
            puts(L": ");
            puth(col, 4);
            puts(L" x ");
            puth(row, 4);
            puts(L"\r\n");
            break;

        case EFI_UNSUPPORTED:
            puth(mode, 2);
            puts(L": unsupported\r\n");
            break;

        default:
            assert(status, L"QueryMode");
            break;
        }
    }

    while (TRUE);
}

图2.10: 使用QueryMode()的例子

这个例子列出所有[0, MaxMode - 1]区间内受支持的文本显示模式的行数和列数的16进制值,如图2.11所示。

运行图2.10的程序的情况

图2.11: 运行图2.10的程序的情况