我正在使用的工具:nasm,qemu-system-x86_64。
我正在使用的操作系统:视窗 10。
所以我在 https://wiki.osdev.org/Real_Mode_OS_Warning 查看了"实模式操作系统警告">
这篇文章似乎暗示的是,一切都可以在不使用BIOS中断的情况下完成。我知道如何加载长模式,所以我已经这样做了,但现在我被困住了,因为到目前为止我只知道 BIOS 中断。我想做一些事情,比如将图形模式设置为全内存访问模式(如果您看过int 10h / AX = 4F02h / BX = 81FFh
,听起来可能很熟悉(,但由于我不想使用已弃用的东西 (BIOS(,我一直在搜索网络上如何设置图形模式,然后仅在长模式下访问单个像素。
希望事实证明可以在StackOverflow上回答这个问题。我非常相信"它太复杂了"不会作为答案出现,特别是因为 OSDev 刚刚告诉我不要使用已弃用的东西。告诉某人这太难了,假设他们知道什么,以及他们能够学到什么,甚至不知道他们是谁。我只需要一个起点来了解如何做到这一点。
澄清一下,对我不起作用的事情:
进入图形模式,无需中断装配
这对我不起作用,因为答案给出了我不想要的 VGA 链接。
装配体 8086 中的图形模式
这对我不起作用,因为这个问题不是关于长模式,而是关于真实模式下的 VGA 图形。
如何在不使用 BIOS 的情况下将数据写入显卡?
这对我不起作用,因为答案本质上是"它太复杂了,使用已弃用的东西",这与我试图做的事情相反,并且与我刚刚在 OSDev 上被告知的内容非常矛盾。
通过英特尔 8086 上的图形卡直接绘图
这对我不起作用,因为答案与设置图形模式无关。
一些 x86 汇编语言问题
这对我不起作用,因为答案没有说明如何在 UEFI 中设置图形模式。他们只谈论已弃用的东西。
下面是使用 UEFI 获取和打印第一个图形设备上的可用图形模式并选择性地设置模式的示例代码。
我使用了这个参考:http://wiki.phoenix.com/wiki/index.php/EFI_GRAPHICS_OUTPUT_PROTOCOL。
实施注意事项:
- 它调用定位协议来获取图形输出协议。我尝试使用 LocateHandle 获取支持图形输出协议的所有句柄。它返回了两个句柄,但OpenProtocol失败了。我没有机会使用 LocateHandle 调试版本。此版本使用定位协议有效。
- 它打印可用模式的数量、当前模式以及每种模式的特性。
- 函数的参数是要设置的模式。如果为 -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 引导服务表的指针。
- 它是为气体而不是 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: %dn"
trace2: .asciz "mode %d: size %d, ver %d, hor res %d, ver res %d, pixel format %dn"
trace3: .asciz "frame buffer: %p, frame buffer size: %llxn"
.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