+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, 64 << 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
+ 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
+; 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
+
+