aboutsummaryrefslogtreecommitdiffstats
path: root/src/boot/boot.stage2.a20.asm
blob: 8fa3d37d979ca6fd2432bc87845e99b071ebb7b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    ;;  boot.stage2.a20.asm
    
_enable_a20:    
    call _check_a20
    test ax, ax
    jnz .end

    call _enable_a20_bios
    call _check_a20
    test ax, ax
    jnz .end
    
    call _enable_a20_keyb
    call _check_a20
    test ax, ax
    jnz .end

    call _enable_a20_io92
    call _check_a20
    test ax, ax
    jnz .end

    .halt: hlt
    jmp .halt
    .end:
    ret

_check_a20:     
    pushf
    push ds
    push es
    push di
    push si
    cli                         ; Clear Interrupts
    
    xor ax, ax
    mov es, ax
    not ax
    mov ds, ax
    ;; 0500 and 0510 are guaranteed to be free
    mov di, 0x0500
    mov si, 0x0510
    
    ;; Save the original values
    mov dl, byte [es:di]
    push dx
    mov dl, byte [ds:si]
    push dx

    mov byte [es:di], 0x00
    mov byte [ds:si], 0xFF
    cmp byte [es:di], 0xFF

    mov ax, 0                   ; The A20 is disabled
    je .a20_disabled
    mov ax, 1                   ; The A20 is enabled
    .a20_disabled:
    pop dx
    mov byte [ds:si], dl
    pop dx
    mov byte [es:di], dl
    
    pop si
    pop di
    pop es
    pop ds
    popf
    sti                         ; Enable interrupts again
    ret

_enable_a20_bios:   
    mov ax, 0x2401
    int 0x15
    jc .fast_gate
    test ah, ah
    jnz .failed
    call _check_a20
    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 _check_a20
    test ax, ax
    jnz .done

    .done:
    mov ax, 1
    ret

    .failed:
    mov ax, 0
    ret

_enable_a20_keyb:   
    cli 
    call .wait_io1
    mov al, 0xad
    out 0x64, al

    call .wait_io1
    mov al, 0x0d0
    out 0x64, al

    call .wait_io2
    in al, 0x60
    push eax

    call .wait_io1
    mov al, 0xd1
    out 0x64, al

    call .wait_io1
    mov al, 0xae
    out 0x64, al
    
    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

_enable_a20_io92:   
    in al, 0x92                 ; Read from port 0x92
    test al, 2                  ; Check if bit 1
    jnz .end
    or al, 2
    and al, 0xfe
    out 0x92, al
    .end:
    ret