section .realmode

int_08_ticks_counter: dd 0
int_08_callback:      dd 0

int_08_isr:
    bits 16
    pushf
    inc dword [cs:int_08_ticks_counter]
    popf
    jmp far [cs:int_08_callback]
    bits 32

extern getchar_internal

global _pit_sleep_and_quit_on_keypress
_pit_sleep_and_quit_on_keypress:
    ; Hook int 0x08
    mov edx, dword [0x08*4]
    mov dword [int_08_callback], edx
    mov dword [0x08*4], int_08_isr

    ; pit_ticks in edx
    mov edx, dword [esp+4]

    mov dword [int_08_ticks_counter], 0

    ; Save GDT in case BIOS overwrites it
    sgdt [.gdt]

    ; Save IDT
    sidt [.idt]

    ; Load BIOS IVT
    lidt [.rm_idt]

    ; Save non-scratch GPRs
    push ebx
    push esi
    push edi
    push ebp

    ; Jump to real mode
    jmp 0x08:.bits16
  .bits16:
    bits 16
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov eax, cr0
    and al, 0xfe
    mov cr0, eax
    jmp 0x00:.cszero
  .cszero:
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    sti

    mov byte [.mods], 0
    mov byte [.ascii], 0
    mov byte [.scan], 0

  .loop:
    cmp dword [int_08_ticks_counter], edx
    je .done

    push ecx
    push edx
    mov ah, 0x01
    xor al, al
    int 0x16
    pop edx
    pop ecx

    jz .loop

    ; on keypress
    xor ax, ax
    int 0x16
    mov byte [.ascii], al
    mov byte [.scan], ah

    mov ax, 0x0200
    int 0x16
    test al, 0x04
    jz .done

    ; ctrl handling
    mov byte [.mods], 0x04
    add byte [.ascii], 0x60

  .done:
    cli

    ; Restore GDT
    o32 lgdt [ss:.gdt]

    ; Restore IDT
    o32 lidt [ss:.idt]

    ; Jump back to pmode
    mov ebx, cr0
    or bl, 1
    mov cr0, ebx
    jmp 0x18:.bits32
  .bits32:
    bits 32
    mov bx, 0x20
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx
    mov ss, bx

    ; Restore non-scratch GPRs
    pop ebp
    pop edi
    pop esi
    pop ebx

    ; Dehook int 0x08
    mov edx, dword [int_08_callback]
    mov dword [0x08*4], edx

    cmp byte [.scan], 0
    je .fail

    push dword [.mods]
    push dword [.ascii]
    push dword [.scan]
    call getchar_internal
    add esp, 3*4

    ret

  .fail:
    xor eax, eax
    ret

  .gdt:      dq 0
  .idt:      dq 0
  .rm_idt:   dw 0x3ff
             dd 0

  .mods:  dd 0
  .ascii: dd 0
  .scan:  dd 0

section .note.GNU-stack noalloc noexec nowrite progbits
