I am trying to write a code sequence, that will switch my intel graphics card into the legacy VGA mode after a call to Exitbootservices() in my uefi nasm bootloader. In order to do that I am to change some values in my graphics card's registers. My graphics card supports two ways of accessing its registers - through MMIO and through I/O space via a pair of I/O registers called MMIO_ADDRESS and MMIO_DATA. Base address for the MMIO and base port for the I/O access are obtained through the PCI configuration space registers. I successfully got both of the values from the PCI configuration space. Weirdly, trying to read any register value through the MMIO(MMIO_BAR + reg_offset) or through the pair of I/O registers always returns zero. Trying to write to any of the device's registers with bot ways, listed above, also results in nothing. I would like to know, what I miss, because clearly I am missing something. My guess is that, the graphics card register access may be locked by some graphics card feature. By the way, my intel graphics card is operated by the linux i915 driver. I validated MMIO BAR and I/O port base multiple times by: using lspci -vvv in Linux, by calling the pci util in the UEFI shell and by simply reading the values from the pci configuration space with my bootloader.
This is the code I have so far. I call get_mmap(), then I call exitbootservices(). After that I change the caching policy for the VGA framebuffer by changing values in the fixed-range MTRRs. After that I put some pixels on the screen(I chechked the buffer address via GOP in another bootloader) to see that PC is not stalled after a call to exitbootservices(). After that I call a function, that should disable all current display modes of my intel graphics card. Then I put more pixels on the screen to see that computer is not stalled, though, pixels should not be visible and the first sequence of pixels, I printed earlier, is expected to disappear after I alter the graphics card's register values. After that I call a sequence of functions, that put a VGA compatible graphics card into the VGA 13h mode(256 colors, 320x200)(confirmed to work on real hardware in 16-bit real-mode bootloader). My code(jd9999_hdr_macro is an implementation of the UEFI PE header):
[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_HANDLE] ; EBS
mov rdx, qword [mmkey]
xor r8, r8
sub rsp, 32
call qword [exit_boot_services]
add rsp, 32
mov rdi, 0x00000000a0000000
mov eax, 0x22822837 ; First sequence of pixels
mov rcx, 0x2223
cld
rep stosd
mov eax, 00000001000000010000000100000001b
mov edx, 00000001000000010000000100000001b ; Reprogram MTRRs
mov ecx, 0x00000259
wrmsr
mov rdi, 0x00000000c2000000;
call disable_all_display_modes ; Here I pass the MMIO BAR in rdi and put some stuff into registers through it. After this call the screen should become blank and any further attempts to print any pixels to it should not display anything.
mov rdi, 0x00000000a0000000 + 0x2223*4 ; Second sequence of pixels(should not be displayed)
mov eax, 0x33722818
mov rcx, 0x2223
cld
rep stosd
mov rsi, VGA13h
call set_regs
; VGA 13h sequence
mov rsi, palette256
call set_palette256
cld
mov rcx, 64000
mov rdi, 0xA0000
mov al, 60 ; Fill the screen in VGA 13h mode
rep stosb
cli
hlt
; rdi - MMIO BAR
align 8
disable_all_display_modes: ; A function that disables all current video modes through MMIO
mov eax, dword [rdi+0x61140]
and eax, 11011111111111111111111111111111b
mov dword [rdi+0x61140], eax ; Disable sDVO ports stall
mov eax, dword [rdi+0x61160]
and eax, 11011111111111111111111111111111b
mov dword [rdi+0x61160], eax
mov eax, dword [rdi+0x70080]
and eax, 11111111111111111111111111011000b ; CURACNTR - cursor A disable
mov dword [rdi+0x70080], eax
mov eax, dword [rdi+0x700c0]
and eax, 11111111111111111111111111011000b ; CURBCNTR - cursor B disable
mov dword [rdi+0x700c0], eax
mov eax, dword [rdi+0x70180]
and eax, 01111111111111111111111111111111b ; DSPACNTR - Plane A disable
mov dword [rdi+0x70180], eax
mov eax, dword [rdi+0x71180]
and eax, 01111111111111111111111111111111b ; DSPBCNTR - Plane B disable
mov dword [rdi+0x71180], eax
mov eax, dword [rdi+0x70008]
or eax, 00000000000011000000000000000000b ; PIPEACONF - Disable all planes and cursors
mov dword [rdi+0x70008], eax
mov eax, dword [rdi+0x70008]
;test eax, 10000000000000000000000000000000b
;jz ._PIPEA_skip_wait
and eax, 01111111111111111111111111111111b ; PIPEACONF - Disable PIPE
mov dword [rdi+0x70008], eax
;lea eax, [edi+0x70008]
;monitor ; this is probably the proper way of waiting for the pipes to disable
;mwait
;._PIPEA_skip_wait:
mov eax, dword [rdi+0x71008]
or eax, 00000000000011000000000000000000b ; PIPEBCONF - Disable all planes and cursors
mov dword [rdi+0x71008], eax
mov eax, dword [rdi+0x71008]
;test eax, 10000000000000000000000000000000b
;jz ._PIPEB_skip_wait
and eax, 01111111111111111111111111111111b ; PIPEBCONF - Disable PIPE
mov dword [rdi+0x71008], eax
;lea eax, [edi+0x71008]
;monitor ; this is probably the proper way of waiting for the pipes to disable
;mwait
;._PIPEB_skip_wait:
mov eax, dword [rdi+0x71400]
and eax, 01111111111111111111111111111111b ; Disable VGA display
mov dword [rdi+0x71400], eax
mov eax, dword [rdi+0x68000]
and eax, 11111111111111111111011111111111b ; Disable panel fitter
mov dword [rdi+0x68000], eax
mov eax, dword [rdi+0x6014]
and eax, 01101111111111111111111111111111b ; DPLLA_CTRL - DPLL VCO = 0(disabled), VGA mode = 0 (enabled)
mov dword [rdi+0x6014], eax
mov eax, dword [rdi+0x6018]
and eax, 01101111111111111111111111111111b ; DPLLB_CTRL - DPLL VCO = 0(disabled), VGA mode = 0 (enabled)
mov dword [rdi+0x6018], eax
ret
align 8
; dx - IOBAR
disable_all_display_modes_IO: ; A function that disables all current video modes through I/O
mov eax, 0x61140
out dx, eax
add dx, 4
in eax, dx
and eax, 11011111111111111111111111111111b
out dx, eax
sub dx, 4
mov eax, 0x61160
out dx, eax ; Disable sDVO ports stall
add dx, 4
in eax, dx
and eax, 11011111111111111111111111111111b
out dx, eax
sub dx, 4
mov eax, 0x70080
out dx, eax
add dx, 4 ; CURACNTR - cursor A disable
in eax, dx
and eax, 11111111111111111111111111011000b
out dx, eax
sub dx, 4
mov eax, 0x700c0
out dx, eax
add dx, 4 ; CURBCNTR - cursor B disable
in eax, dx
and eax, 11111111111111111111111111011000b
out dx, eax
sub dx, 4
mov eax, 0x70180
out dx, eax
add dx, 4 ; DSPACNTR - Plane A disable
in eax, dx
and eax, 01111111111111111111111111111111b
out dx, eax
sub dx, 4
mov eax, 0x71180
out dx, eax
add dx, 4 ; DSPBCNTR - Plane B disable
in eax, dx
and eax, 01111111111111111111111111111111b
out dx, eax
sub dx, 4
mov eax, 0x70008
out dx, eax
add dx, 4
in eax, dx
or eax, 00000000000011000000000000000000b ; PIPEACONF - Disable all planes and cursors
out dx, eax
sub dx, 4
mov eax, 0x71008
out dx, eax
add dx, 4
in eax, dx
or eax, 00000000000011000000000000000000b ; PIPEBCONF - Disable all planes and cursors
out dx, eax
sub dx, 4
mov eax, 0x71400
out dx, eax
add dx, 4
in eax, dx
and eax, 01111111111111111111111111111111b ; Disable VGA display
out dx, eax
sub dx, 4
mov eax, 0x68000
out dx, eax
add dx, 4
in eax, dx
and eax, 11111111111111111111011111111111b ; Disable panel fitter
out dx, eax
sub dx, 4
mov eax, 0x6014
out dx, eax
add dx, 4
in eax, dx
and eax, 01101111111111111111111111111111b ; DPLLA_CTRL - DPLL VCO = 0(disabled), VGA mode = 0 (enabled)
out dx, eax
sub dx, 4
mov eax, 0x6018
out dx, eax
add dx, 4
in eax, dx
and eax, 01101111111111111111111111111111b ; DPLLB_CTRL - DPLL VCO = 0(disabled), VGA mode = 0 (enabled)
out dx, eax
sub dx, 4
ret
align 8
set_regs: ; Set VGA registers for the 13h mode
xor rdx, rdx
xor rax, rax
xor rcx, rcx
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
align 8
set_palette256: ; Set Vga palette
xor rdx, rdx
xor rax, rax
xor rcx, rcx
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
times 2048 - ($-$$) db 0 ;alignment
textsize equ $-$$
section .data follows=.text
dataStart:
tststr dw __utf16__(`test_\0`)
numretstr dw __utf16__(`0x0000000000000000\n\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 $-$$
Photos of the computer screen after the program finished(from afar and a closeup with explanation):
As you can see, VGA 13h draws some weird stuff on the screen because previous graphics mode was not disabled. So, why does my code does not disable the current video mode of my intel graphics card(considering that the Base address of MMIO is alright)?.
Your reads from MMIO space return 0 because you are reading from the render and media section from the MMIO, which is not even powered on. But you don't want to read from the render and media section. You want to read from the display engine section. I just made exactly the same error.
Here is an example from your code:
mov eax, 0x70080
out dx, eax
add dx, 4 ; CURACNTR - cursor A disable
in eax, dx
Let's translate this to pseudocode:
out("address channel", 0x70080)
eax = in("data channel")
The documentation says the following about the 2 example registers "CURACNTR" and "GTLC wake control":
CURACNTR is at memory offset address 7 00 80h
GTLC wake control is at MMIO address offset 13 00 90h
What you need is the offset from the beginning of the MMIO space. The offset from the beginning of the MMIO space for the 2 example registers "CURACNTR" and "GTLC wake control" is:
This additional offset (18 00 00h) was taken from the Valleyview/Baytrail-documentation. With your graphics circuit you might have a different offset.