Assembly 汇编-如何在UEFI中设置图形模式(没有VGA,没有BIOS,没有不推荐的)

Assembly 汇编-如何在UEFI中设置图形模式(没有VGA,没有BIOS,没有不推荐的),assembly,graphics,64-bit,uefi,Assembly,Graphics,64 Bit,Uefi,我正在使用的工具:nasm、qemu-system-x86_64 我使用的操作系统:Windows10 所以我在 这篇文章似乎暗示的是,任何事情都可以在不使用BIOS中断的情况下完成。我知道如何加载长模式,所以我已经这样做了,但现在我被卡住了,因为BIOS中断是我现在所知道的全部。我想做一些类似于将图形模式设置为完全内存访问模式的事情(如果您看过int10h/AX=4F02h/BX=81FFh,听起来可能会很熟悉),但因为我不想使用不推荐使用的东西(BIOS),我在网上搜索如何设置图形模式,然后

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

我使用的操作系统:Windows10

所以我在

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

希望能在StackOverflow上回答这个问题。我非常相信“它太复杂了”不会作为答案出现,特别是因为OSDev刚刚告诉我不要使用不推荐的东西。告诉别人这太难了,假设他们知道什么,他们能学到什么,甚至不知道他们是谁。我只需要一个起点来找出如何做到这一点

要澄清的是,对我不起作用的事情:

这对我不起作用,因为答案给出了指向VGA的链接,我不想要

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

这对我来说不起作用,因为答案基本上是“太复杂了,使用不推荐的东西”,这与我试图做的相反,也与我刚刚在OSDev上听到的相反

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


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

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

我使用了以下引用:

关于执行情况的说明:

  • 它调用LocateProtocol以获取图形输出协议。我尝试使用LocatHandle获取所有支持图形输出协议的句柄。它返回了两个句柄,但OpenProtocol失败。我还没有机会用LocateHandle调试这个版本。此版本使用LocateProtocol工作
  • 它打印可用模式的数量、当前模式以及每个模式的特征
  • 该功能的参数是要设置的模式。如果为-1,则模式不变。否则它必须介于0和N-1之间,其中N是支持的图形模式数。此函数不检查参数,但SetMode函数检查它
  • 它使用Sys V x86-64函数调用约定,但对UEFI函数的调用除外,该函数使用UEFI约定
  • 它使用一个名为efi_printf的函数,该函数的工作原理与printf类似,并使用efi_SIMPLE_TEXT_OUTPUT_协议写入ConOut
  • 它依赖于在名为EFI_Boot_Services的全局变量中存储指向EFI Boot Services表的指针的启动代码
  • 它是为气体而不是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

如果您只需要切换一次图形模式,则使用UEFI的图形输出协议在UEFI引导加载程序中切换视频模式如果您需要在操作系统启动后切换图形模式,则需要为您想要支持的每种视频卡编写视频驱动程序。与BIOS服务不同,UEFI服务在操作系统加载后不工作。这“因为答案基本上是”太复杂了,请使用不推荐使用的东西“其实包含了相当详细的答案,从哪里开始。。。不确定您还希望得到什么,复制~5000行文档以使堆栈溢出没有多大意义,您可以自己阅读(英特尔集成卡手册,其他供应商通常更难获得文件,或者对于个人来说完全不可能)我主要在寻找一个具体的源代码示例,它展示了一种使用UEFI设置视频模式的方法,然后我就可以进行反向工程。这是我学习新东西的最好方法之一。尝试Linux源代码,但它不使用UEFI设置视频模式,因为正如我所解释的,它不能。你可以看看GRUB GOP驱动程序,我想:哦,我对UEFI一无所知,我到目前为止只使用过BIOS,这就是我发布这篇文章的原因。你知道除了UEFI(一个用于各种事情的内存地址列表,或者一个协议列表,而不是一个中断列表),我在哪里可以找到与拉尔夫·布朗(Ralph Brown)相同的中断列表比拉尔夫·布朗的中断列表要好得多,因为它是一个实际的规范,而不仅仅是随着时间的推移而演变的软件接口的积累。