-; 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
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
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:
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
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: