Enabling the VGA 13h video mode on a modern PC in UEFI via a UEFI bootloader, written in assembly

634 Views Asked by At

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

1

There are 1 best solutions below

0
Brendan On

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).