英文:
Enabling the VGA 13h video mode on a modern PC in UEFI via a UEFI bootloader, written in assembly
问题
I have translated the code as requested. Here's the translated code:
[BITS 64]
[DEFAULT ABS]
[ORG 0x00100000]
%include "jd9999_hdr_macro.inc"
jd9999_hdr_macro textsize, datasize, 0x00100000, textsize+datasize+1024
section .text follows=.header
start:
sub rsp, 6*8+8 ; Copied from Charles AP's implementation, fix stack alignment issue (Thanks Charles AP!)
mov qword [EFI_HANDLE], rcx
mov qword [EFI_SYSTEM_TABLE], rdx
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+96]
mov rax, qword [rax+56]
mov qword [get_mmap_boot_srvc], rax
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+64]
mov rax, qword [rax+8]
mov qword [efi_print], rax
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+96]
mov rax, qword [rax+232]
mov qword [exit_boot_services], rax
mov rcx, mmap_sz
mov rdx, MMap
mov r8, mmkey
mov r9, mmdsz
mov r10, mmdsv ; get_mmap
sub rsp, 32
call qword [get_mmap_boot_srvc]
add rsp, 32
mov rcx, qword [EFI_SYSTEM_TABLE]
mov rcx, qword [rcx+64]
mov rdx, tststr ; print
sub rsp, 32
call qword [efi_print]
add rsp, 32
mov rcx, qword [EFI_HANDLE] ; EBS
mov rdx, qword [mmkey]
xor r8, r8
sub rsp, 32
call qword [exit_boot_services]
add rsp, 32
mov rcx, qword [EFI_SYSTEM_TABLE]
mov rcx, qword [rcx+64]
mov rdx, tststr ; print
sub rsp, 32
call qword [efi_print]
add rsp, 32
mov rsi, VGA13h
call set_regs
mov rsi, palette256
call set_palette256
cld
mov rcx, 64000
mov rdi, 0xA0000
mov al, 0
rep stosb
mov byte [0xA23F8], 60
cli
hlt
set_regs:
cli
cld
mov rdx, 0x3C2
outsb
mov rdx, 0x3DA
outsb
xor rcx, rcx
mov rdx, 0x3C4
._loop_CRTC:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 4
jbe ._loop_CRTC
mov rdx, 0x3D4
mov rax, 0x0000000000000E11
out dx, ax
xor rcx, rcx
mov rdx, 0x3D4
._loop_CRTC_2:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 0x18
jbe ._loop_CRTC_2
xor rcx, rcx
mov rdx, 0x3CE
._loop_GC_:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 8
jbe ._loop_GC_
mov rdx, 0x3DA
in al, dx
xor rcx, rcx
mov dx, 0x3C0
.l4:
in ax, dx
mov al, cl
out dx, al
outsb
inc cx
cmp cl, 0x14
jbe .l4
mov al, 0x20
out dx, al
sti
ret
set_palette256:
xor rax, rax
cld
.loop:
mov rdx, 0x038C8
out dx, al
inc dx
mov rcx, 3
rep outsb
inc rax
<details>
<summary>英文:</summary>
I have been writing some x86_16 assembly code for BIOS real mode as a hobby for quiet a while now. Recently I decided to move to writing 64-bit bootloaders for UEFI. First thing, that I came up with was entering the 13h VGA graphics mode(256 colors, 320x200) in a UEFI program. Obviously, I cannot simply call the 0x10 interrupt, as I did in BIOS. Luckily, a while ago, I wrote a program, that enters the VGA 13h mode without interrupts(manipulating the VGA registers, mapped at ports 0x03B0-0x03DF by default)(Confirmed to work both in qemu and on the real hardware). I successfully adopted a PE header implementation for NASM, made by JD9999. Next I successfully implemented calls to `EFI_GET_MEMORY_MAP` and `EFI_EXIT_BOOT_SERVICES`, needed for UEFI to hand over all of the PC resources to my program. After that I ported my 16-bit assembly code, that manipulates VGA registers to 64-bit and called it in my UEFI bootloader.
After calling it nothing happened. my attempts to write to `0xA000:0x0000-0xA000:0xFA00`(or, in my case, using linear addressing `0xA0000-0xAFA00`) did not display anything on the screen both in qemu and on real hardware. Though, when setting -vga cirrus in qemu, it gave me a ton of gtk widget errors in terminal, upon every write attempt to the VGA frame buffer.
By the, way, both the integrated and the discrete video cards are called VGA compatible by various PCI configuration space-reading software.
Why does all of that happen? What do I miss in my program?
My guesses are: I could miss some series of actions, needed for the video card to enter the VGA compatibility mode(if so, what are those actions?), I/O ports for VGA compatibility could differ from the I/O ports, used by real VGA(if so, what are they?).
My code(jd9999_hdr_macro.inc is just a PE header implementation in nasm):
[BITS 64]
[DEFAULT ABS]
[ORG 0x00100000]
%include "jd9999_hdr_macro.inc"
jd9999_hdr_macro textsize, datasize, 0x00100000, textsize+datasize+1024
section .text follows=.header
start:
sub rsp, 6*8+8 ; Copied from Charles AP's implementation, fix stack alignment issue (Thanks Charles AP!)
mov qword [EFI_HANDLE], rcx
mov qword [EFI_SYSTEM_TABLE], rdx
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+96]
mov rax, qword [rax+56]
mov qword [get_mmap_boot_srvc], rax
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+64]
mov rax, qword [rax+8]
mov qword [efi_print], rax
mov rax, qword [EFI_SYSTEM_TABLE]
mov rax, qword [rax+96]
mov rax, qword [rax+232]
mov qword [exit_boot_services], rax
mov rcx, mmap_sz
mov rdx, MMap
mov r8, mmkey
mov r9, mmdsz
mov r10, mmdsv ; get_mmap
sub rsp, 32
call qword [get_mmap_boot_srvc]
add rsp, 32
mov rcx, qword [EFI_SYSTEM_TABLE]
mov rcx, qword [rcx+64]
mov rdx, tststr ; print
sub rsp, 32
call qword [efi_print]
add rsp, 32
mov rcx, qword [EFI_HANDLE] ; EBS
mov rdx, qword [mmkey]
xor r8, r8
sub rsp, 32
call qword [exit_boot_services]
add rsp, 32
mov rcx, qword [EFI_SYSTEM_TABLE]
mov rcx, qword [rcx+64]
mov rdx, tststr ; print
sub rsp, 32
call qword [efi_print]
add rsp, 32
mov rsi, VGA13h
call set_regs
mov rsi, palette256
call set_palette256
cld
mov rcx, 64000
mov rdi, 0xA0000
mov al, 0
rep stosb
mov byte [0xA23F8], 60
cli
hlt
set_regs:
cli
cld
mov rdx, 0x3C2
outsb
mov rdx, 0x3DA
outsb
xor rcx, rcx
mov rdx, 0x3C4
._loop_CRTC:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 4
jbe ._loop_CRTC
mov rdx, 0x3D4
mov rax, 0x0000000000000E11
out dx, ax
xor rcx, rcx
mov rdx, 0x3D4
._loop_CRTC_2:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 0x18
jbe ._loop_CRTC_2
xor rcx, rcx
mov rdx, 0x3CE
.loop_GC:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc rcx
cmp cl, 8
jbe .loop_GC
mov rdx, 0x3DA
in al, dx
xor rcx, rcx
mov dx, 0x3C0
.l4:
in ax, dx
mov al, cl
out dx, al
outsb
inc cx
cmp cl, 0x14
jbe .l4
mov al, 0x20
out dx, al
sti
ret
set_palette256:
xor rax, rax
cld
._loop:
mov rdx, 0x038C8
out dx, al
inc dx
mov rcx, 3
rep outsb
inc rax
cmp rax, 256
jl ._loop
ret
times 1024 - ($-$$) db 0 ;alignment
textsize equ $-$$
section .data follows=.text
dataStart:
tststr db utf16 test_\0
;Handover variables
EFI_HANDLE dq 0
EFI_SYSTEM_TABLE dq 0
get_mmap_boot_srvc dq 0
efi_print dq 0
exit_boot_services dq 0
memmap_UEFI:
type dd 0
phys_addr dq 0
virt_addr dq 0
num_pafes dq 0
attribute dq 0
mmap_sz dq 4096
mmdsz dq 48
mmkey dq 0
mmdsv dq 0
VGA13h db 0x63, 0x00, 0x03, 0x01, 0x0F, 0x00, 0x0E, 0x5F, 0x4F
db 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x0E, 0x8F, 0x28
db 0x40, 0x96, 0xB9, 0xA3, 0xFF, 0x00, 0x00, 0x00, 0x00
db 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x01, 0x02, 0x03
db 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
db 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00
palette256 db 00, 00, 00, 00, 10, 41, 12, 28, 18, 02, 43, 22, 35
db 19, 09, 58, 00, 00, 57, 35, 12, 43, 43, 47, 24, 24
db 28, 20, 24, 60, 10, 60, 15, 31, 47, 63, 62, 56, 20
db 60, 56, 22, 63, 61, 36, 63, 63, 63, 00, 00, 00, 05
db 05, 05, 08, 08, 08, 11, 11, 11, 14, 14, 14, 17, 17
db 17, 20, 20, 20, 24, 24, 24, 28, 28, 28, 32, 32, 32
db 36, 36, 36, 40, 40, 40, 45, 45, 45, 50, 50, 50, 56
db 56, 56, 63, 63, 63, 13, 12, 15, 15, 16, 22, 17, 20
db 29, 19, 24, 36, 21, 28, 43, 23, 31, 50, 25, 34, 57
db 26, 42, 63, 00, 15, 02, 01, 22, 04, 02, 29, 06, 03
db 36, 08, 04, 43, 10, 05, 50, 12, 06, 57, 14, 20, 63
db 40, 18, 06, 07, 25, 12, 11, 33, 17, 14, 40, 23, 18
db 48, 28, 21, 55, 34, 25, 62, 39, 27, 63, 48, 36, 15
db 03, 02, 22, 06, 04, 29, 09, 06, 36, 12, 08, 43, 15
db 10, 50, 18, 12, 57, 21, 14, 63, 28, 20, 15, 00, 00
db 22, 07, 00, 29, 15, 00, 36, 23, 00, 43, 31, 00, 50
db 39, 00, 57, 47, 00, 63, 55, 00, 15, 05, 03, 22, 11
db 07, 29, 17, 11, 36, 23, 15, 43, 29, 19, 50, 35, 23
db 57, 41, 27, 63, 53, 34, 28, 14, 12, 33, 20, 14, 38
db 26, 16, 43, 32, 18, 48, 38, 20, 53, 44, 22, 58, 50
db 24, 63, 56, 30, 05, 05, 06, 10, 10, 13, 15, 15, 20
db 20, 20, 27, 25, 25, 34, 30, 30, 41, 35, 35, 48, 44
db 44, 63, 03, 06, 05, 05, 11, 09, 07, 16, 13, 09, 21
db 17, 11, 26, 21, 13, 31, 25, 15, 36, 29, 20, 48, 38
db 06, 06, 07, 13, 13, 15, 20, 20, 23, 27, 27, 31, 34
db 34, 39, 41, 41, 47, 48, 48, 55, 57, 57, 63, 06, 15
db 04, 12, 22, 08, 18, 29, 12, 24, 36, 16, 30, 43, 20
db 36, 50, 24, 42, 57, 28, 54, 63, 35, 15, 10, 10, 22
db 16, 16, 29, 21, 21, 36, 27, 27, 43, 32, 32, 50, 38
db 38, 57, 43, 43, 63, 54, 54, 15, 15, 06, 22, 22, 12
db 29, 29, 18, 36, 36, 24, 43, 43, 30, 50, 50, 36, 57
db 57, 42, 63, 63, 54, 02, 04, 14, 06, 12, 21, 10, 20
db 28, 14, 28, 35, 18, 36, 42, 22, 44, 49, 26, 52, 56
db 36, 63, 63, 18, 04, 14, 24, 08, 21, 31, 12, 28, 37
db 16, 35, 44, 20, 42, 50, 24, 49, 57, 28, 56, 63, 38
db 63, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 53, 44, 22, 09
db 08, 12, 16, 14, 16, 22, 21, 20, 29, 27, 24, 35, 34
db 28, 42, 40, 32, 48, 47, 36, 57, 56, 43, 08, 12, 16
db 14, 16, 22, 21, 20, 29, 27, 24, 35, 34, 28, 42, 40
db 32, 48, 47, 36, 57, 56, 43, 63, 13, 09, 11, 21, 16
db 15, 27, 22, 18, 36, 29, 22, 42, 35, 25, 51, 42, 29
db 57, 48, 32, 63, 56, 39, 06, 14, 09, 12, 21, 14, 18
db 27, 22, 24, 33, 28, 30, 39, 36, 36, 46, 42, 42, 52
db 47, 50, 59, 53, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00
times 1024 - ($-$$) db 0 ;alignment
MMap:
times 4096 db 0
datasize equ $-$$
My 16-bit code for setting the VGA mode 13h(confirmed to work both in qemu and on the real hardware):
[BITS 16]
[ORG 0X7C00]
mov ax, 0
mov es, ax
mov sp, 0xffff
mov ah, 0x02
mov al, 4 ; 512 * al to read
mov ch, 0
mov dh, 0
mov cl, 2
mov bx, stage2
int 0x13
jmp 0x7e00
times 510 - ($-$$) db 0
dw 0xAA55
stage2:
mov si, VGA13h
call set_regs
mov si, palette256
call set_palette256
mov ax, 0xa000
mov es, ax
mov si, 0
mov al, 0
mov cx, 64000
rep stosb
;mov ax, 0xa000
;mov es, ax
mov byte [es:9208], 60
cli
hlt
set_regs:
cli
cld
mov dx, 0x3C2
outsb
mov dx, 0x3DA
outsb
xor cx, cx
mov dx, 0x3C4
.loop_CRTC_:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc cx
cmp cl, 4
jbe .loop_CRTC_
mov dx, 0x3D4
mov ax, 0x0E11
out dx, ax
xor cx, cx
mov dx, 0x3D4
.loop_CRTC_2:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc cx
cmp cl, 0x18
jbe .loop_CRTC_2
xor cx, cx
mov dx, 0x3CE
.loop_GC_:
lodsb
xchg al, ah
mov al, cl
out dx, ax
inc cx
cmp cl, 8
jbe .loop_GC_
mov dx, 0x3DA
in al, dx
xor cx, cx
mov dx, 0x3C0
.l4:
in ax, dx
mov al, cl
out dx, al
outsb
inc cx
cmp cl, 0x14
jbe .l4
mov al, 0x20
out dx, al
sti
ret
set_palette256:
xor ax, ax
cld
.loop_:
mov dx, 0x03C8
out dx, al ; output index
inc dx ; port 0x3C9
mov cx, 3
rep outsb
;outsb ; red
;outsb ; blue
;outsb ; green
inc ax
cmp ax, 256
jl .loop_
ret
VGA13h db 0x63, 0x00, 0x03, 0x01, 0x0F, 0x00, 0x0E, 0x5F, 0x4F
db 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x0E, 0x8F, 0x28
db 0x40, 0x96, 0xB9, 0xA3, 0xFF, 0x00, 0x00, 0x00, 0x00
db 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x01, 0x02, 0x03
db 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
db 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00
palette256 db 00, 00, 00, 00, 10, 41, 12, 28, 18, 02, 43, 22, 35
db 19, 09, 58, 00, 00, 57, 35, 12, 43, 43, 47, 24, 24
db 28, 20, 24, 60, 10, 60, 15, 31, 47, 63, 62, 56, 20
db 60, 56, 22, 63, 61, 36, 63, 63, 63, 00, 00, 00, 05
db 05, 05, 08, 08, 08, 11, 11, 11, 14, 14, 14, 17, 17
db 17, 20, 20, 20, 24, 24, 24, 28, 28, 28, 32, 32, 32
db 36, 36, 36, 40, 40, 40, 45, 45, 45, 50, 50, 50, 56
db 56, 56, 63, 63, 63, 13, 12, 15, 15, 16, 22, 17, 20
db 29, 19, 24, 36, 21, 28, 43, 23, 31, 50, 25, 34, 57
db 26, 42, 63, 00, 15, 02, 01, 22, 04, 02, 29, 06, 03
db 36, 08, 04, 43, 10, 05, 50, 12, 06, 57, 14, 20, 63
db 40, 18, 06, 07, 25, 12, 11, 33, 17, 14, 40, 23, 18
db 48, 28, 21, 55, 34, 25, 62, 39, 27, 63, 48, 36, 15
db 03, 02, 22, 06, 04, 29, 09, 06, 36, 12, 08, 43, 15
db 10, 50, 18, 12, 57, 21, 14, 63, 28, 20, 15, 00, 00
db 22, 07, 00, 29, 15, 00, 36, 23, 00, 43, 31, 00, 50
db 39, 00, 57, 47, 00, 63, 55, 00, 15, 05, 03, 22, 11
db 07, 29, 17, 11, 36, 23, 15, 43, 29, 19, 50, 35, 23
db 57, 41, 27, 63, 53, 34, 28, 14, 12, 33, 20, 14, 38
db 26, 16, 43, 32, 18, 48, 38, 20, 53, 44, 22, 58, 50
db 24, 63, 56, 30, 05, 05, 06, 10, 10, 13, 15, 15, 20
db 20, 20, 27, 25, 25, 34, 30, 30, 41, 35, 35, 48, 44
db 44, 63, 03, 06, 05, 05, 11, 09, 07, 16, 13, 09, 21
db 17, 11, 26, 21, 13, 31, 25, 15, 36, 29, 20, 48, 38
db 06, 06, 07, 13, 13, 15, 20, 20, 23, 27, 27, 31, 34
db 34, 39, 41, 41, 47, 48, 48, 55, 57, 57, 63, 06, 15
db 04, 12, 22, 08, 18, 29, 12, 24, 36, 16, 30, 43, 20
db 36, 50, 24, 42, 57, 28, 54, 63, 35, 15, 10, 10, 22
db 16, 16, 29, 21, 21, 36, 27, 27, 43, 32, 32, 50, 38
db 38, 57, 43, 43, 63, 54, 54, 15, 15, 06, 22, 22, 12
db 29, 29, 18, 36, 36, 24, 43, 43, 30, 50, 50, 36, 57
db 57, 42, 63, 63, 54, 02, 04, 14, 06, 12, 21, 10, 20
db 28, 14, 28, 35, 18, 36, 42, 22, 44, 49, 26, 52, 56
db 36, 63, 63, 18, 04, 14, 24, 08, 21, 31, 12, 28, 37
db 16, 35, 44, 20, 42, 50, 24, 49, 57, 28, 56, 63, 38
db 63, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 53, 44, 22, 09
db 08, 12, 16, 14, 16, 22, 21, 20, 29, 27, 24, 35, 34
db 28, 42, 40, 32, 48, 47, 36, 57, 56, 43, 08, 12, 16
db 14, 16, 22, 21, 20, 29, 27, 24, 35, 34, 28, 42, 40
db 32, 48, 47, 36, 57, 56, 43, 63, 13, 09, 11, 21, 16
db 15, 27, 22, 18, 36, 29, 22, 42, 35, 25, 51, 42, 29
db 57, 48, 32, 63, 56, 39, 06, 14, 09, 12, 21, 14, 18
db 27, 22, 24, 33, 28, 30, 39, 36, 36, 46, 42, 42, 52
db 47, 50, 59, 53, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
db 00
times ((0x1000) - ($ - $$)) db 0x00
</details>
# 答案1
**得分**: 1
> 为什么会发生这一切?
**简短答案:** 这不起作用,因为你正在做的相当于在你的马已经死了35年之后,往一辆现代电动汽车的前部塞草。
**更长的答案:**
很久以前(1987年),IBM发布了VGA。它是一个系列的一部分(CGA,EGA等),在同一年被SVGA卡取代。出于毫无理由的原因,VGA成为了一种向后兼容的东西 - 它可以让你在安装不可接受的视频驱动程序时看到你在做什么。
大约在它已经被取代了10年之后(大约在没有人再想再次看到320x200之后的9年),一些人开始想要多显示器。这导致了一个问题,因为两个显卡不能使用相同的IO端口,所以整个世界都转向了PCI。在这一点上,VGA仍然是一个更糟糕的向后兼容性的东西(只支持一个显示器而不支持其他显示器),但每个真正的操作系统(带有本机视频驱动程序)大多只是将显卡切换到其本机模式(由PCI配置的内存映射IO),这样它们可以访问不丑陋的视频模式,而不需要编写2个不同的驱动程序(一个用于显卡使用VGA IO端口时,一个用于显卡表现得像PCI设备应该时)。
再过了大约10年,UEFI被引入了。其主要目的是摆脱所有过时的东西(例如VGA)。其想法是显卡将表现得像PCI设备,没有人会再费心慢速的IO端口的混乱(不支持多个显示器,不支持更高分辨率的视频模式,不支持垂直刷新IRQ,不支持GPU等),因此UEFI(就像大多数操作系统一样)不需要为每个显卡编写2个不同的驱动程序。不幸的是,临时过渡期(其中包括一个临时的“混合BIOS + UEFI”阶段)持续时间太长,但幸运的是,现在已经没有了。
当然,还发生了许多其他事情(VBE,支持多个显示器的显卡,因此您不需要多个显卡,从9引脚VGA连接器切换到现代的替代品,如HDMI,“无”的增强型“固定功能加速器”等)。
> 我可能会错过一些进入VGA兼容模式所需的操作系列(如果是这样,那么是什么操作?
现在我们(几乎完全)完成了“临时的混合BIOS + UEFI”阶段,不能保证视频卡支持VGA。像VGA IO端口、字体/文本模式、调色板、使低分辨率工作的各种技巧(发送每个像素两次,每行两次,以便显示器认为它是640x400)、奇怪的“读模式”和“写模式”、使其与64 KiB的银行一起工作的技巧(因为8086的物理地址空间受到限制),等等,都不需要存在。实际上(因为显卡制造商不是从头开始设计,而是演变了已经具有VGA功能的旧设计),目前在大多数显卡上可能仍然存在大部分内容;但它们是“遗传的”,不能保证(尤其是对于将来的硬件)。
如果您真的想要尝试唤醒VGA的腐烂尸体,步骤可能如下:
* 启动所有CPU并重新编程它们的MTRR,以便“0xA0000到0xBFFFF”区域(可能以前是RAM)不使用写回缓存。请注意,这是一个谨慎的顺序(必须仔细确定结果应该是什么;然后确保所有缓存都已禁用并清空/刷新,然后再更改MTRR)。
* 编写特定于芯片组的代码,以重新配置芯片组(内存控制器等),以便VGA IO端口和“0xA0000到0xBFFFF”区域的访问被转发到显卡。不要忘记,这个区域可能以前是RAM(或其他东西),并且可能被您的代码或UEFI的固件使用,因此这可能是不可能的。
* 编写一个本机视频驱动程序,了解如何将您的特定显卡从其正常/本机模式切换回古老的模式。这可能是不可能的。
> 用于VGA兼容性的I/O端口可能与真正的VGA使用的I/O端口不同(如果是这样,它们是什么?
它们是内存映射IO,但对于每个视频卡来说都不同,没有理由期望它们中的任何一个与VGA相似。
UEFI唯一有用的标准(应该与任何视频卡兼容的标准)就是UEFI本身。具体来说是“图形输出协议”(Graphics Output Protocol,GOP),它允许您为每个监视器设置视频模式,并提供您所需的信息(帧缓冲物理地址、行间字节、分辨
<details>
<summary>英文:</summary>
> Why does all of that happen?
**Short answer:** It doesn't work because you're doing the equivalent of shoving hay into the front of a modern electric car about 35 years after your horse died.
**Longer answer**
Once upon a time (1987) IBM released VGA. It was part of a series (CGA, EGA, ..) and was superseded by SVGA cards in the same year. For no sane reason whatsoever, VGA became a backward compatibility thing - something that lets you see what you're doing while installing a video driver that isn't awful.
About 10 years after it was already superseded (and about 9 years after nobody wanted to ever see 320x200 ever again) some people started wanting multiple monitors. This caused a problem because 2 video cards can't use the same IO ports; so the entire world switched to PCI. At this point VGA remained as an even worse backward compatibility thing (for one monitor and none others); but every real OS (with native video drivers) mostly just switched the video card into its native mode (with memory mapped IO configured by PCI) so they could access video modes that aren't ugly without writing 2 different drivers (one for when the video card is using VGA IO ports and one when the video card is behaving like a PCI device should).
About 10 years after that UEFI got introduced. The entire point was to get rid of all the obsolete trash (e.g. VGA). The idea was that the video card would just behave like a PCI device and nobody would bother with the broken mess of slow IO ports (that didn't support multiple monitors and didn't support higher resolution video modes, didn't support vertical refresh IRQ, didn't support GPUs, ...), so that UEFI (like most operating systems) wouldn't need 2 different video drivers for each video card. Sadly the temporary transition period (which involved a temporary "hybrid BIOS + UEFI" phase) lasted way too long, but fortunately it's all gone now.
Of course many other things also happened (VBE, video cards that support multiple monitors so you don't need multiple video cards, the switch from the 9-pin VGA connector to modern alternatives like HDMI, "nothing" being augmented by "fixed function accelerators", ...).
> I could miss some series of actions, needed for the video card to enter the VGA compatibility mode(if so, what are those actions?)
Now that we've (almost completely) finished the "temporary hybrid BIOS + UEFI" phase there's no guarantee a video card supports VGA. Things like the VGA IO ports, fonts/text mode, the palette, the hacks to make low resolution work (sending each pixel twice and each line twice so that the monitor thinks it's 640x400), the weird "read modes" and "write modes", the "make it work with 64 KiB banks because an 8086 is limited to 1 MiB of physical address space", ... - none of that needs to exist. In practice (because video card manufacturers don't redesign from scratch and are evolving old pre-existing designs that already had the VGA stuff) it's currently possibly still likely most of it still exists on most video cards; but it's "vestigial" and there's no guarantee (especially for future hardware).
If you really want to try to raise the rotting corpse of VGA, the steps would be something like :
* start all CPUs and reprogram their MTRRs so that the "0xA0000 to 0xBFFFF" area (which may have previously been RAM) isn't using write-back caching. Note that this is a careful sequence (must carefully determine what the result should be; then make sure all caches are disabled and empty/flushed before you change MTRRs).
* write chipset specific code to reconfigure the chipset (memory controllers, etc) so that accesses done by VGA IO ports and the "0xA0000 to 0xBFFFF" area is forwarded to the video card. Don't forget that this area might have been RAM (or something else) and might be being used by your code or UEFI's firmware; so this might not be possible.
* write a native video driver that understands how to switch your specific video card from its normal/native mode back into Ye Olden Days. This may be impossible.
> I/O ports for VGA compatibility could differ from the I/O ports, used by real VGA(if so, what are they?
They're memory mapped IO; but it's different for each video card with no reason to expect any of it is similar to VGA.
The only useful standard for UEFI (that is supposed to work with any video card) is UEFI. Specifically the "Graphics Output Protocol" (GOP) that lets you set up a video mode for each monitor and gives you the information you need (framebuffer physical address, bytes between lines, resolution, pixel format) to draw pixels into it. There was also an older "UGA" in the original EFI specs (from before the UEFI consortium was created and EFI was renamed to UEFI) that was used on old Apple machines; but it's not worth the hassle of supporting UGA now.
For reference; the correct sequence (for each monitor) is to use GOP to discover video modes, then choose one that your software decides it likes the most and use GOP to set that video mode, then (if it worked and after you've done all monitors) you can use EFI_EXIT_BOOT_SERVICES and the previously set up video modes continue to work after. Note that you can't assume any specific video mode is supported (e.g. if you want "1024x768 with 32-bit RGB colors" then you might not be able to get it), which means you need code that adapts to whatever is supported (e.g. uses variables and not constants for things like horizontal and vertical resolution, and is able to work with a range of pixel formats).
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论