summaryrefslogtreecommitdiff
path: root/src/boot/stage2_a20.asm
blob: c0951ad855eca09e21c8ee5da2b21b0defcdd6f8 (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
148
149
150
151
152
153
154
155
156
157
; functions to handle A20 address line status and switching

; returns 0 if not A20_ENABLED, 1 if A20_ENABLED in AX
check_A20_enabled:
	pushf
	push ds
	push es
	push di
	push si
	
	cli
	
	xor ax, ax
	mov es, ax
	mov di, 0x0500			; es:di = 0000:0500
	
	mov ax, 0xffff
	mov ds, ax
	mov si, 0x0510			; ds:si = ffff:0510
	
	mov al, byte [es:di]		; preserve values in memory
	push ax				; on stack
	mov al, byte [ds:si]
	push ax
	
	mov byte [es:di], 0x00		; now the test: write 0x00 to 0000:0500
	mov byte [ds:si], 0xFF		; write 0xff to ffff:0510
	
	cmp byte [es:di], 0xFF		; memory wrap? A20 notA20_ENABLED
	
	pop ax				; restore original memory contents
	mov byte [ds:si], al
	pop ax
	mov byte [es:di], al
	
	je .enabled
	jmp .disabled
	
.enabled:
	mov al, '+'
	call print_char
	mov ax, 1			; not wrapped around
	jmp .exit

.disabled:
	mov al, '-'
	call print_char
	mov ax, 0			; wrapped around (last cmp)
	jmp .exit
	
.exit:
	pop si
	pop di
	pop es
	pop ds
	popf

	ret

check_and_enable_A20:
	call check_A20_enabled
	cmp ax, 1
	je A20_ENABLED

A20_ENABLE_KBD_PORT:
	mov al, 'K'
	call print_char
	mov al, 0xdd
	out 0x64, al

	call check_A20_enabled
	cmp ax, 1
	je A20_ENABLED

A20_ENABLE_KBD_OUT:

	mov al, 'k'
	call print_char

	cli			; disable interrupts, we talk directly to the keyboard ports

        call    .wait_input
        mov     al,0xAD
        out     0x64,al		; disable keyboard
        call    .wait_input

        mov     al,0xD0
        out     0x64,al		; tell controller to read output port
        call    .wait_output

        in      al,0x60
        push    eax		; get output port data and store it
        call    .wait_input

        mov     al,0xD1
        out     0x64,al		; tell controller to write output port
        call    .wait_input

        pop     eax
        or      al,2		; set bit 1 (enable a20)
        out     0x60,al		; write out data back to the output port

        call    .wait_input
        mov     al,0xAE		; enable keyboard
        out     0x64,al

        call    .wait_input

        sti

        jmp .retest

; wait for input buffer to be clear
.wait_input:
        in      al,0x64
        test    al,2
        jnz     .wait_input
        ret

; wait for output buffer to be clear
.wait_output:
        in      al,0x64
        test    al,1
        jz      .wait_output
        ret

.retest:
	call check_A20_enabled
	cmp ax, 1
	je A20_ENABLED

A20_FAST_SPECIAL_PORT:

	mov al, 'F'
	call print_char

	in al, 0x92
	or al, 2
	out 0x92, al

	call check_A20_enabled
	cmp ax, 1
	je A20_ENABLED
	ret

A20_ENABLE_VIA_BIOS:
	mov al, 'B'
	call print_char
	mov ax, 0x2401
	int 0x15

	call check_A20_enabled
	cmp ax, 1
	je A20_ENABLED
  	
A20_ENABLED:
	ret