switched to 16bit mode, but int 10h hangs
[efitest3] / efitest.asm
index 2cc79a2..ae804dd 100644 (file)
@@ -1,55 +1,15 @@
 ; vi:ft=nasm:
        bits 64
-       org 100000h
-       default rel
+       org 1000h
 
-       ; EFI_SYSTEM_TABLE offsets
-SIMPLE_TEXT_OUTPUT     equ 64
-BOOT_SERVICES          equ 80
-
-       ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL function offsets
-TEXT_OUT_STRING                equ 8
-TEXT_SET_ATTR          equ 40
-TEXT_CLEAR_SCREEN      equ 48
-
-       ; 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 +18,209 @@ 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]
 
+       ; 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
+
+
 .hang: jmp .hang
 
 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
-       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
+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
+       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
 
-hexdig dw __utf16__ "0123456789abcdef"
-hexbuf: times 40 db 0
 
        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
+
+       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 code segment and jump to 16bit code
+       jmp 0x18:start16
+
+.hang: hlt
+       jmp .hang
+
+       
+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, [esi]
+       test al, al
+       jz .done
+       call ser_putchar
+       inc esi
+       jmp ser_putstr
+.done: ret
+
+
+       align 4
+       ; real mode IDTR pseudo-descriptor pointing to the IVT at addr 0
+       dw 0
+rmidt: dw 3ffh
+       dd 0
+
+       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
+
+       ; run 16bit video bios test
+       mov ax, 13h
+       ;int 10h
+
+       mov ax, 0a000h
+       mov es, ax
+       xor di, di
+       mov cx, 32000
+       mov ax, 6767h
+       rep stosw
+
+.hang: hlt
+       jmp .hang
+
+       align 4
+end: