fixed offset in notes
[efitest3] / efitest.asm
index 2cc79a2..3ca78d0 100644 (file)
@@ -1,55 +1,16 @@
-; vi:ft=nasm:
        bits 64
-       org 100000h
-       default rel
-
-       ; EFI_SYSTEM_TABLE offsets
-SIMPLE_TEXT_OUTPUT     equ 64
-BOOT_SERVICES          equ 80
+       org 1000h
 
-       ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL function offsets
-TEXT_OUT_STRING                equ 8
-TEXT_SET_ATTR          equ 40
-TEXT_CLEAR_SCREEN      equ 48
+%include "serial.inc"
 
-       ; EFI_BOOT_SERVICES function offsets
+BOOT_SERVICES          equ 96
 BOOT_GET_MEMORY_MAP    equ 56
 BOOT_EXIT_BOOT_SERVICES        equ 232
 
-
 start:
        mov [efihandle], rcx
        mov [systab], rdx
 
-       mov rax, [rdx + BOOT_SERVICES]
-       mov [bootsrv], rax
-       sub rsp, 32                     ; leave space for shadow area
-       and rsp, 0xfffffffffffffff0     ; make sure sp is 16-byte aligned
-
-       mov rcx, [rdx + SIMPLE_TEXT_OUTPUT]
-       mov rdx, 0x0c
-       call [rcx + TEXT_SET_ATTR]
-
-       mov rax, [systab]
-       mov rcx, [rax + SIMPLE_TEXT_OUTPUT]
-       call [rcx + TEXT_CLEAR_SCREEN]
-
-       mov rax, [systab]
-       mov rcx, [rax + SIMPLE_TEXT_OUTPUT]
-       lea rdx, [str_hello]
-       call [rcx + TEXT_OUT_STRING]
-
-       
-       mov rax, [systab]
-       mov rcx, [rax + SIMPLE_TEXT_OUTPUT]
-       mov rdx, 0x07
-       call [rcx + TEXT_SET_ATTR]
-
-       call get_rip
-       mov rdi, rax
-       call printhex64
-       call newline
-
        ; retrieve memory map
        ; args: RCX, RDX, R8, and R9.
        lea rcx, [mmap_size]
@@ -58,71 +19,333 @@ start:
        lea r9, [mmap_descsz]
        lea rax, [mmap_descver]
        push rax
-       push rax
+       sub rsp, 32
        mov rax, [systab]
        mov rbx, [rax + BOOT_SERVICES]
        call [rbx + BOOT_GET_MEMORY_MAP]
-       add rsp, 16
-
+       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]
 
-.hang: jmp .hang
+       ; move code to absolute 1000h
+       call get_rip
+.after_call:
+       sub rax, .after_call - start
+       mov rsi, rax    ; source address
+       mov rdi, start  ; destination
+       mov rcx, end - start
+       shr rcx, 2      ; dwords
+       cld
+       rep movsd       ; copy code to make it absolute
+
+       mov rax, .abs
+       jmp rax
+.abs:
+       call setup_serial
+
+       ; switch to 32-bit compatibility long mode
+       lgdt [gdtlim]
+       push word 8
+       push qword start32
+       retfq
 
 get_rip:
        mov rax, [rsp]
        ret
 
-       ; expects number in rdi
-printhex64:
-       mov rcx, 16
-       lea rbx, [hexbuf]
-.loop: rol rdi, 4
-       mov rax, rdi
-       and rax, 0xf
-       lea rdx, [hexdig]
-       shl rax, 1
-       add rdx, rax
-       mov ax, [rdx]
-       mov [rbx], ax
-       add rbx, 2
-       dec rcx
+       ; serial port setup
+setup_serial:
+       ; set clock divisor
+       mov al, LCTL_DLAB
+       mov dx, UART_LCTL
+       out dx, al
+       mov ax, DIV_9600
+       mov dx, UART_DIVLO
+       out dx, al
+       mov al, ah
+       mov dx, UART_DIVHI
+       out dx, al
+       ; set format 8n1
+       mov al, LCTL_8N1
+       mov dx, UART_LCTL
+       out dx, al
+       ; clear and enable fifo
+       mov al, FIFO_ENABLE_CLEAR
+       mov dx, UART_FIFO
+       out dx, al
+       ; assert RTS and DTR
+       mov al, MCTL_DTR_RTS_OUT2
+       mov dx, UART_MCTL
+       out dx, al
+       ret
+
+
+; ----------- 32bit code ----------
+
+       bits 32
+start32:
+       mov ax, 10h
+       mov ds, ax
+       mov ss, ax
+       mov es, ax
+       mov gs, ax
+       mov fs, ax
+
+       ; disable paging to deactivate long mode
+       mov eax, cr0
+       and eax, 7fffffffh
+       mov cr0, eax
+
+       ; disable long mode (EFER.LME = 0)
+       ; TODO: EFER is MSR c0000080, LME is bit 8
+       mov ecx, 0c0000080h
+       rdmsr
+       and eax, 0fffffeffh
+       wrmsr
+
+       ; 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
+
+       ; 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
-       mov word [rbx], 0
-       lea rdi, [hexbuf]
-
-       ; expects string in rdi
-printstr:
-       mov rcx, [systab]
-       mov rcx, [rcx + SIMPLE_TEXT_OUTPUT]
-       mov rdx, rdi
-       sub rsp, 32
-       call [rcx + TEXT_OUT_STRING]
-       add rsp, 32
        ret
 
-newline:
-       lea rdi, [str_hello + 18]
-       jmp printstr
+hexdig db '0123456789abcdef'
 
-hexdig dw __utf16__ "0123456789abcdef"
-hexbuf: times 40 db 0
+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
+       mov dx, UART_LSTAT
+.wait: in al, dx
+       and al, LST_TREG_EMPTY
+       jz .wait
+       mov dx, UART_DATA
+       mov al, ah
+       out dx, al
+       ret
+
+ser_putstr:
+       mov al, [si]
+       test al, al
+       jz .done
+       call ser_putchar
+       inc si
+       jmp ser_putstr
+.done: ret
+
+
+; ---------- data ------------
 
        align 8
 efihandle dq 0
 systab dq 0
-bootsrv dq 0
-str_hello dw __utf16__(`qurashee!\r\n`),0
-
-       align 8
 ; memory map data
-mmap_size dq 0
+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: