; vi:ft=nasm:
bits 64
org 100000h
- default rel
-
- ; 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_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]
- lea rdx, [mmapbuf]
- lea r8, [mmap_key]
- lea r9, [mmap_descsz]
- lea rax, [mmap_descver]
- push rax
- push rax
- mov rax, [systab]
- mov rbx, [rax + BOOT_SERVICES]
- call [rbx + BOOT_GET_MEMORY_MAP]
- add rsp, 16
-
- mov rcx, [efihandle]
- mov rdx, [mmap_key]
- mov rax, [systab]
- mov rbx, [rax + BOOT_SERVICES]
- call [rbx + BOOT_EXIT_BOOT_SERVICES]
+.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
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
+
+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
-newline:
- lea rdi, [str_hello + 18]
- jmp printstr
+str_hello db 'hello!',13,10,0
-hexdig dw __utf16__ "0123456789abcdef"
-hexbuf: times 40 db 0
+ align 4
+gdtlim dw 23
+gdtbase dq gdt
align 8
-efihandle dq 0
-systab dq 0
-bootsrv dq 0
-str_hello dw __utf16__(`qurashee!\r\n`),0
+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
+
+
+ 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
+
+ mov esi, str_hello
+ call ser_putstr
+
+.hang: hlt
+ jmp .hang
- align 8
-; memory map data
-mmap_size dq 0
-mmap_key dq 0
-mmap_descsz dq 0
-mmap_descver dq 0
-
- align 4096
-mmapbuf: times 4096 db 0
+
+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
+
+
+end: