组装 - 如何在 UEFI 中设置图形模式(无 VGA,无 BIOS,无弃用)

Assembly - How to set graphics mode in UEFI (No VGA, No BIOS, Nothing deprecated)

我正在使用的工具:nasm、qemu-system-x86_64。

我使用的操作系统:Windows10.

所以我在 https://wiki.osdev.org/Real_Mode_OS_Warning

查看了 "Real Mode OS Warning"

这篇文章似乎暗示的是,一切都可以在不使用 BIOS 中断的情况下完成。我知道如何加载长模式,所以我已经这样做了,但现在我卡住了,因为直到现在我只知道 BIOS 中断。我想做一些事情,比如将图形模​​式设置为全内存访问模式(如果您已经看过 int 10h / AX = 4F02h / BX = 81FFh,可能听起来很熟悉),但由于我不想使用已弃用的东西 (BIOS),我一直无法在网上搜索如何设置图形模式,然后仅在长模式下访问单个像素。

希望最终可以在 Whosebug 上回答这个问题。我非常相信 "it's too complicated" 不会作为答案出现,尤其是因为 OSDev 刚刚告诉我不要使用已弃用的东西。告诉某人这太难了,假设他们知道什么,甚至不知道自己是谁,也能学到什么。我只需要一个起点来了解如何做到这一点。

澄清一下,对我不起作用的事情:

Enter graphics mode without interrupts in assembly

这对我不起作用,因为答案为 VGA 提供了 link,这是我不想要的。

这对我不起作用,因为这个问题不是关于长模式,而是关于实模式下的 VGA 图形。

这对我不起作用,因为答案基本上是 "it's too complicated, use the deprecated stuff",这与我正在尝试做的相反,并且与我刚刚在 OSDev 上被告知的完全矛盾。

Drawing directly by graphics card on Intel 8086

这对我不起作用,因为答案与设置图形模式无关。

A few x86 Assembly language questions

这对我不起作用,因为答案没有说明如何在 UEFI 中设置图形模式。他们只谈论过时的东西。

下面是使用 UEFI 获取和打印第一个图形设备上的可用图形模式并可选择设置模式的示例代码。

我使用了这个参考:http://wiki.phoenix.com/wiki/index.php/EFI_GRAPHICS_OUTPUT_PROTOCOL

实现注意事项:

  • 调用LocateProtocol获取图形输出协议。我尝试使用 LocateHandle 获取所有支持图形输出协议的句柄。它返回了两个句柄,但 OpenProtocol 失败了。我还没有机会使用 LocateHandle 调试版本。这个使用 LocateProtocol 的版本有效。
  • 它打印可用模式的数量、当前模式以及每个模式的特性。
  • 函数的参数是要设置的模式。如果为-1,则模式不变。否则它必须介于 0 和 N - 1 之间,其中 N 是支持的图形模式数。此函数不检查参数,但 SetMode 函数检查它。
  • 它使用 Sys V x86-64 函数调用约定,但对 UEFI 函数的调用除外,后者使用 UEFI 约定。
  • 它使用一个名为 efi_printf 的函数,它的工作方式与 printf 类似,并使用 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
  • 写入 ConOut
  • 它依赖于启动代码在名为 efi_boot_services.
  • 的全局变量中存储指向 EFI 引导服务 Table 的指针
  • 它是为 gas 而写的,而不是 nasm。

这是示例输出:

max mode: 5
mode 1: size 36, ver 0, hor res 800, ver res 600, pixel format 1
frame buffer: b1000000, frame buffer size: 1d4c00
mode 0: size 36, ver 0, hor res 640, ver res 480, pixel format 1
mode 1: size 36, ver 0, hor res 800, ver res 600, pixel format 1
mode 2: size 36, ver 0, hor res 1024, ver res 768, pixel format 1
mode 3: size 36, ver 0, hor res 1280, ver res 1024, pixel format 1
mode 4: size 36, ver 0, hor res 1600, ver res 1200, pixel format 1

我假设你熟悉 UEFI,所以我没有解释一切是如何工作的,所以如果你需要更多解释,请告诉我。

            .intel_syntax noprefix

            .section .text
            .align  16
            .globl  gfxmode
    gfxmode:
            push    rbx
            push    rbp
            push    r14
            push    r15
            sub     rsp, 0x38

            mov     ebp, edi                // desired mode

            lea     rcx, EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID[rip]
            xor     edx, edx                // arg 2: unused
            lea     r8, 0x20[rsp]           // arg 3: address of protocol
            mov     rax, efi_boot_services[rip]
            call    0x140[rax]              // locate protocol
            test    rax, rax
            js      2f

            mov     r15, 0x20[rsp]          // graphics output protocol
            mov     r14, 0x18[r15]          // mode

            lea     rdi, trace1[rip]
            mov     esi, [r14]              // max mode
            call    efi_printf

            mov     rdi, 8[r14]             // current mode info
            mov     esi, 4[r14]             // current mode number
            mov     edx, 16[r14]            // current mode info size
            call    print_mode

            lea     rdi, trace3[rip]
            mov     rsi, 24[r14]            // frame buffer addr
            mov     rdx, 32[r14]            // frame buffer size
            call    efi_printf

            xor     ebx, ebx
    1:
            mov     rcx, r15                // arg 1: graphics output protocol
            mov     edx, ebx                // arg 2: mode number
            lea     r8, 0x30[rsp]           // arg 3: &info size
            lea     r9, 0x28[rsp]           // arg 4: &info
            call    0x00[rcx]               // query mode
            test    rax, rax
            js      2f

            mov     rdi, 0x28[rsp]          // mode info
            mov     esi, ebx                // mode number
            mov     edx, 0x30[rsp]          // mode info size
            call    print_mode

            mov     rax, efi_boot_services[rip]
            mov     rcx, 0x28[rsp]          // mode info
            call    0x48[rax]               // free pool

            inc     ebx
            cmp     ebx, [r14]              // max mode
            jb      1b

            xor     eax, eax
            test    ebp, ebp                // new mode
            js      2f
            mov     rcx, r15                // arg 1: graphics output protocol
            mov     edx, ebp                // arg 2: mode number
            call    0x08[rcx]               // set mode

    2:
            add     rsp, 0x38
            pop     r15
            pop     r14
            pop     rbp
            pop     rbx
            ret

            .align  16
    print_mode:
            // rdi: mode info
            // esi: mode number
            // edx: mode size
            mov     ecx, [rdi]              // mode version
            mov     r8d, 4[rdi]             // hor res
            mov     r9d, 8[rdi]             // ver res
            mov     eax, 12[rdi]            // pixel format
            push    rax
            lea     rdi, trace2[rip]
            call    efi_printf
            add     rsp, 8
            ret

    trace1: .asciz  "max mode: %d\n"
    trace2: .asciz  "mode %d: size %d, ver %d, hor res %d, ver res %d, pixel format %d\n"
    trace3: .asciz  "frame buffer: %p, frame buffer size: %llx\n"

            .align  16
    EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID:
            .byte   0xde,0xa9,0x42,0x90,0xdc,0x23,0x38,0x4a
            .byte   0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a