组装 - 如何在 UEFI 中设置图形模式(无 VGA、无 BIOS、没有弃用) [英] Assembly - How to set graphics mode in UEFI (No VGA, No BIOS, Nothing deprecated)
问题描述
我使用的工具:nasm、qemu-system-x86_64.
Tools I'm using: nasm, qemu-system-x86_64.
我使用的操作系统:Windows 10.
Operating System I'm on: Windows 10.
所以我在 https://wiki.osdev.org/Real_Mode_OS_Warning 查看了实模式操作系统警告"
这篇文章似乎暗示着一切都可以在不使用 BIOS 中断的情况下完成.我知道如何加载长模式,所以我已经这样做了,但现在我被卡住了,因为直到现在我只知道 BIOS 中断.我想做一些事情,比如将图形模式设置为全内存访问模式(如果你看过 int 10h/AX = 4F02h/BX = 81FFh
,可能听起来很熟悉),但因为我不不想使用已弃用的东西 (BIOS),我一直在网上搜索如何设置图形模式,然后仅在长模式下访问单个像素时遇到问题.
What the article seems to imply is that everything can be done without using BIOS interrupts whatsoever. I know how to load Long Mode, and so I've done this, but now I am stuck because BIOS interrupts were all I knew until now. I want to do something like set the graphics mode to full-memory-access-mode (might sound familiar if you've seen int 10h / AX = 4F02h / BX = 81FFh
), but since I don't want to use something that's deprecated (BIOS), I have been having trouble searching the web for how to set the graphics mode and then access individual pixels in Long Mode only.
希望可以在 StackOverflow 上回答这个问题.我非常相信它太复杂了"不会作为答案出现,尤其是因为 OSDev 刚刚告诉我不要使用已弃用的东西.告诉某人太难了,假设他们知道什么以及他们能够学习什么,甚至不知道他们是谁.我只需要一个起点来找出如何做到这一点.
Hopefully it turns out to be possible to answer this question on StackOverflow. I have much faith that "it's too complicated" won't show up as an answer, especially since I was just told by OSDev NOT to use deprecated things. Telling someone it's too difficult assumes what they know and what they're able to learn without even knowing who they are. I just need a starting point to find out how to do this.
澄清一下,对我不起作用的事情:
To give clarification, things that didn't work for me:
这对我不起作用,因为答案提供了我不想要的 VGA 链接.
This didn't work for me because the answer gives a link to VGA, which I don't want.
这对我不起作用,因为问题不是关于长模式,而是关于实模式下的 VGA 图形.
This didn't work for me because the question does not ask about Long Mode, but rather about VGA graphics in Real Mode.
这对我不起作用,因为答案本质上是它太复杂了,使用已弃用的东西",这与我正在尝试做的相反,并且与我刚刚在 OSDev 上被告知的内容完全矛盾.
This didn't work for me because the answer was essentially "it's too complicated, use the deprecated stuff", which is the opposite of what i'm trying to do and quite contradictory to what I was just told on OSDev.
这对我不起作用,因为答案与设置图形模式无关.
This didn't work for me because the answer has nothing to do with setting the graphics mode.
这对我不起作用,因为答案没有说明如何在 UEFI 中设置图形模式.他们只谈论过时的东西.
This didn't work for me because the answers do not say how to set the graphics mode in UEFI. They only talk about deprecated things.
推荐答案
这是使用 UEFI 获取和打印第一个图形设备上可用的图形模式并可选择设置模式的示例代码.
Here is sample code that uses UEFI to get and print the available graphics modes on the first graphics device and optionally sets the mode.
我使用了这个参考: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 引导服务表的指针存储在名为 efi_boot_services 的全局变量中的启动代码.
- 它是为 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,所以我没有解释一切是如何工作的,如果您需要更多解释,请告诉我.
I assume you are familiar with UEFI, so I haven't explained how everything works, so let me know if you need more explanation.
.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
"
trace2: .asciz "mode %d: size %d, ver %d, hor res %d, ver res %d, pixel format %d
"
trace3: .asciz "frame buffer: %p, frame buffer size: %llx
"
.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 中设置图形模式(无 VGA、无 BIOS、没有弃用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!