fixed offset in notes
[efitest3] / efitest.asm
index 26d29d1..3ca78d0 100644 (file)
@@ -1,8 +1,37 @@
-; vi:ft=nasm:
        bits 64
-       org 100000h
+       org 1000h
+
+%include "serial.inc"
+
+BOOT_SERVICES          equ 96
+BOOT_GET_MEMORY_MAP    equ 56
+BOOT_EXIT_BOOT_SERVICES        equ 232
 
 start:
+       mov [efihandle], rcx
+       mov [systab], rdx
+
+       ; retrieve memory map
+       ; args: RCX, RDX, R8, and R9.
+       lea rcx, [mmap_size]
+       lea rdx, [mmapbuf]
+       lea r8, [mmap_key]
+       lea r9, [mmap_descsz]
+       lea rax, [mmap_descver]
+       push rax
+       sub rsp, 32
+       mov rax, [systab]
+       mov rbx, [rax + BOOT_SERVICES]
+       call [rbx + BOOT_GET_MEMORY_MAP]
+       add rsp, 40
+       ; exit boot services
+       mov rcx, [efihandle]
+       mov rdx, [mmap_key]
+       mov rax, [systab]
+       mov rbx, [rax + BOOT_SERVICES]
+       call [rbx + BOOT_EXIT_BOOT_SERVICES]
+
+       ; move code to absolute 1000h
        call get_rip
 .after_call:
        sub rax, .after_call - start
@@ -24,28 +53,10 @@ start:
        push qword start32
        retfq
 
-
-.hang: jmp .hang
-
 get_rip:
        mov rax, [rsp]
        ret
 
-
-UART_DATA              equ 0x3f8
-UART_DIVLO             equ 0x3f8
-UART_DIVHI             equ 0x3f9
-UART_FIFO              equ 0x3fa
-UART_LCTL              equ 0x3fb
-UART_MCTL              equ 0x3fc
-UART_LSTAT             equ 0x3fd
-DIV_9600               equ 115200 / 9600
-LCTL_8N1               equ 0x03
-LCTL_DLAB              equ 0x80
-FIFO_ENABLE_CLEAR      equ 0x07
-MCTL_DTR_RTS_OUT2      equ 0x0b
-LST_TREG_EMPTY         equ 0x20
-
        ; serial port setup
 setup_serial:
        ; set clock divisor
@@ -72,22 +83,8 @@ setup_serial:
        out dx, al
        ret
 
-str_hello db 'hello!',13,10,0
-
-       align 4
-gdtlim dw 23
-gdtbase        dq gdt
-
-       align 8
-gdt:   ; 0: null segment
-       dd 0, 0
-       ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
-       dd 0x0000ffff
-       dd 0x00cf9a00
-       ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
-       dd 0x0000ffff
-       dd 0x00cf9200
 
+; ----------- 32bit code ----------
 
        bits 32
 start32:
@@ -110,13 +107,182 @@ start32:
        and eax, 0fffffeffh
        wrmsr
 
-       mov esi, str_hello
+       ; load 16bit IVT descriptor
+       cli     ; just to make sure
+       lidt [rmidt]
+
+       ; load 16bit code segment and jump to 16bit code
+       jmp 0x18:start16
+
+; ---------- 16bit real mode code ----------
+
+       bits 16
+start16:
+       ; disable protection
+       mov eax, cr0
+       and eax, 0fffffffeh
+       mov cr0, eax
+       ; load cs <- 0
+       jmp 0:.loadcs0
+.loadcs0:
+       ; zero data segments
+       xor ax, ax
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       ; move stack to the top of 640k
+       mov ax, 9000h
+       mov ss, ax
+       xor sp, sp
+
+       call print_ivt
+
+detect_vbios:
+       ; make sure we have video bios vector installed in 10h
+       mov ax, [10h * 4 + 2]
+       test ax, ax
+       jnz .notnull
+       call init_vbios
+       jnc vbios_present
+       jmp halt
+.notnull: ; beyond being non-zero, the video bios should really be at c0000h
+       cmp ax, 0c000h
+       jz vbios_present
+       ; unexpected address, make sure it starts with 0aa55h
+       mov es, ax
+       xor bx, bx
+       mov ax, [es:bx]
+       cmp ax, 0aa55h
+       call init_vbios ; seems like garbage, try init
+       jc halt
+
+vbios_present:
+       mov si, msg_vbios_test
        call ser_putstr
 
-.hang: hlt
-       jmp .hang
+       ; run 16bit video bios test
+       mov ax, 13h
+       int 10h
+
+       ; setup palette
+       mov dx, 3c8h
+       xor al, al
+       out dx, al
+       inc dx
+       xor cl, cl
+.pal:  mov al, cl
+       out dx, al
+       xor al, al
+       out dx, al
+       mov al, cl
+       not al
+       out dx, al
+       inc cl
+       jnz .pal
+
+       ; fill framebuffer with xor pattern
+       mov ax, 0a000h
+       mov es, ax
+       xor di, di
+       xor cx, cx
+.yloop:        xor dx, dx
+.xloop:        mov ax, dx
+       xor ax, cx
+       stosb
+       inc dx
+       cmp dx, 320
+       jnz .xloop
+       inc cx
+       cmp cx, 200
+       jnz .yloop
+
+       ; halt for ever
+halt:  hlt
+       jmp halt
+
+init_vbios:
+       mov ax, 0c000h
+       mov es, ax
+       xor bx, bx
+       cmp word [es:bx], 0aa55h
+       jz .foundsig
+       mov si, err_vbios_notfound
+       call ser_putstr
+       mov ax, [es:bx]
+       call printhex16
+       mov al, 13
+       call ser_putchar
+       mov al, 10
+       call ser_putchar
+       stc
+       ret
+.foundsig:
+       mov si, msg_vbios_init
+       call ser_putstr
+       ; don't bother with CRC, just call it
+       push es
+       push word 4
+       mov bp, sp
+       call far [bp]
+       add sp, 4
+       clc
+       ret
+
+msg_vbios_test db 'running video BIOS test',13,10,0
+msg_vbios_init db 'attempting to initialize video BIOS',13,10,0
+err_vbios_notfound db 'failed to initialize video BIOS, sig not found at c0000h: ',0
+
+print_ivt:
+       xor bx, bx
+.loop: mov ax, bx
+       shr ax, 2
+       call printhex8
+       mov al, ' '
+       call ser_putchar
+       mov ax, [bx + 2]        ; segment
+       call printhex16
+       mov al, ':'
+       call ser_putchar
+       mov ax, [bx]            ; offset
+       call printhex16
+       mov al, 13
+       call ser_putchar
+       mov al, 10
+       call ser_putchar
+       add bx, 4
+
+       cmp bx, 33 << 2
+       jnz .loop
+       ret
+
+hexdig db '0123456789abcdef'
+
+printhex8:
+       push bx
+       rol al, 4
+       mov bx, ax
+       and bx, 0fh
+       mov cx, ax
+       mov al, [bx + hexdig]
+       call ser_putchar
+       mov ax, cx
+       rol al, 4
+       mov bx, ax
+       and bx, 0fh
+       mov al, [bx + hexdig]
+       call ser_putchar
+       pop bx
+       ret
+
+printhex16:
+       push ax
+       mov al, ah
+       call printhex8
+       pop ax
+       call printhex8
+       ret
 
-       
 ser_putchar:
        mov ah, al
        ; wait until transmit register is empty
@@ -130,13 +296,56 @@ ser_putchar:
        ret
 
 ser_putstr:
-       mov al, [esi]
+       mov al, [si]
        test al, al
        jz .done
        call ser_putchar
-       inc esi
+       inc si
        jmp ser_putstr
 .done: ret
 
 
+; ---------- data ------------
+
+       align 8
+efihandle dq 0
+systab dq 0
+; memory map data
+mmap_size dq 4096
+mmap_key dq 0
+mmap_descsz dq 0
+mmap_descver dq 0
+
+       align 4096
+mmapbuf: times 4096 db 0
+
+str_hello db 'hello!',13,10,0
+
+       align 4
+gdtlim dw 31
+gdtbase        dq gdt
+
+       align 8
+gdt:   ; 0: null segment
+       dd 0, 0
+       ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
+       dd 0x0000ffff
+       dd 0x00cf9a00
+       ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
+       dd 0x0000ffff
+       dd 0x00cf9200
+       ; 3: code16
+       dd 0x0000ffff
+       dd 0x00009a00
+
+
+       align 4
+       ; real mode IDTR pseudo-descriptor pointing to the IVT at addr 0
+       dw 0
+rmidt: dw 3ffh
+       dd 0
+
+
+       align 4
 end:
+; vi:ft=nasm: