组装 - 如何在 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
我正在使用的工具: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