; vi:ft=nasm: bits 64 org 100000h start: 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 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 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 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 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: