;; File: a20.inc
	;; copy/pasted from https://wiki.osdev.org/A20_Line
    ;; .... sorry I was lazy :x

	;; Function: a20_get_state
a20_get_state:
        pushf
        push si
        push di
        push ds
        push es

        cli

        xor ax, ax
        mov ds, ax
        mov si, 0x500

        not ax
        mov es, ax
        mov di, 0x0510

        mov al, [ds:si]  ; save old values
        mov byte [.BufferBelowMB], al
        mov al, [es:di]
        mov byte [.BufferOverMB], al
 
        mov ah, 1 ; check byte [0x00100500] == byte [0x0500]
        mov byte [ds:si], 0
        mov byte [es:di], 1
        mov al, [ds:si]
        cmp al, [es:di]
        jne .exit
        dec ah
.exit:
        mov al, [.BufferBelowMB]
        mov [ds:si], al
        mov al, [.BufferOverMB]
        mov [es:di], al
        shr ax, 8
        sti
        pop es
        pop ds
        pop di
        pop si
        popf
        ret
 
.BufferBelowMB: db 0
.BufferOverMB   db 0

	;; Function: a20_query_support
a20_query_support:
        push bx
        clc
 
        mov ax, 0x2403
        int 0x15
        jc .error
 
        test ah, ah
        jnz .error
 
        mov ax, bx
        pop bx
        ret
.error:
        stc
        pop bx
        ret
 
	;; Function: a20_enable_keyboard_controller
a20_enable_keyboard_controller:
        cli
 
        call .wait_io1
        mov al, 0xad
        out 0x64, al
 
        call .wait_io1
        mov al, 0xd0
        out 0x64, al
 
        call .wait_io2
        in al, 0x60
        push eax
 
        call .wait_io1
        mov al, 0xd1
        out 0x64, al
 
        call .wait_io1
        pop eax
        or al, 2
        out 0x60, al
 
        call .wait_io1
        mov al, 0xae
        out 0x64, al
 
        call .wait_io1
        sti
        ret
.wait_io1:
        in al, 0x64
        test al, 2
        jnz .wait_io1
        ret
.wait_io2:
        in al, 0x64
        test al, 1
        jz .wait_io2
        ret
 
	;; Function: a20_enable
	;; 
    ;; Out:
    ;;     CF - set on error
	;;
a20_enable:
        clc                                                                     ;       clear cf
        pusha
        mov bh, 0                                                       ;       clear bh
 
        call a20_get_state
        jc .fast_gate
 
        test ax, ax
        jnz .done
 
        call a20_query_support
        mov bl, al
        test bl, 1                                                      ;       enable A20 using keyboard controller
        jnz .keybord_controller
 
        test bl, 2                                                      ;       enable A20 using fast A20 gate
        jnz .fast_gate
.bios_int:
        mov ax, 0x2401
        int 0x15
        jc .fast_gate
        test ah, ah
        jnz .failed
        call a20_get_state
        test ax, ax
        jnz .done
.fast_gate:
        in al, 0x92
        test al, 2
        jnz .done
 
        or al, 2
        and al, 0xfe
        out 0x92, al
 
        call a20_get_state
        test ax, ax
        jnz .done
 
        test bh, bh                                                     ;       test if there was an attempt using the keyboard controller
        jnz .failed
.keybord_controller:
        call a20_enable_keyboard_controller
        call a20_get_state
        test ax, ax
        jnz .done
 
        mov bh, 1                                                       ;       flag enable attempt with keyboard controller
 
        test bl, 2
        jnz .fast_gate
        jmp .failed
.failed:
        stc
.done:
        popa
        ret