Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / transitions / liba20.S
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  */
20
21 FILE_LICENCE ( GPL2_OR_LATER )
22
23         .arch i386
24
25 /****************************************************************************
26  * test_a20_short, test_a20_long
27  *
28  * Check to see if A20 line is enabled
29  *
30  * Parameters:
31  *   none
32  * Returns:
33  *   CF set if A20 line is not enabled
34  * Corrupts:
35  *   none
36  ****************************************************************************
37  */
38 #define TEST_A20_SHORT_MAX_RETRIES 0x20
39 #define TEST_A20_LONG_MAX_RETRIES 0x200000
40         .section ".text16.early", "awx", @progbits
41         .code16
42 test_a20_short:
43         pushl   %ecx
44         movl    $TEST_A20_SHORT_MAX_RETRIES, %ecx
45         jmp     1f
46         .size   test_a20_short, . - test_a20_short
47 test_a20_long:
48         pushl   %ecx
49         movl    $TEST_A20_LONG_MAX_RETRIES, %ecx
50 1:      pushw   %ax
51         pushw   %ds
52         pushw   %es
53
54         /* Set up segment registers for access across the 1MB boundary */
55         xorw    %ax, %ax
56         movw    %ax, %ds
57         decw    %ax
58         movw    %ax, %es
59
60 2:      /* Modify and check test pattern; succeed if we see a difference */
61         pushfw
62         cli
63         xchgw   %ds:0, %cx
64         movw    %es:0x10, %ax
65         xchgw   %ds:0, %cx
66         popfw
67         cmpw    %ax, %cx
68         clc
69         jnz     99f
70
71         /* Delay and retry */
72         outb    %al, $0x80
73         addr32 loop 2b
74         stc
75
76 99:     /* Restore registers and return */
77         popw    %es
78         popw    %ds
79         popw    %ax
80         popl    %ecx
81         ret
82         .size   test_a20_long, . - test_a20_long
83
84 /****************************************************************************
85  * enable_a20_bios
86  *
87  * Try enabling A20 line via BIOS
88  *
89  * Parameters:
90  *   none
91  * Returns:
92  *   CF set if A20 line is not enabled
93  * Corrupts:
94  *   none
95  ****************************************************************************
96  */
97         .section ".text16.early", "awx", @progbits
98         .code16
99 enable_a20_bios:
100
101         /* Preserve registers.  Be very paranoid, since some BIOSes
102          * are reported to clobber %ebx
103          */
104         pushal
105
106         /* Attempt INT 15,2401 */
107         movw    $0x2401, %ax
108         int     $0x15
109         jc      99f
110
111         /* Check that success was really successful */
112         call    test_a20_short
113
114 99:     /* Restore registers and return */
115         popal
116         ret
117         .size   enable_a20_bios, . - enable_a20_bios
118
119 /****************************************************************************
120  * enable_a20_kbc
121  *
122  * Try enabling A20 line via keyboard controller
123  *
124  * Parameters:
125  *   none
126  * Returns:
127  *   CF set if A20 line is not enabled
128  * Corrupts:
129  *   none
130  ****************************************************************************
131  */
132 #define KC_RDWR         0x60
133 #define KC_RDWR_SET_A20         0xdf
134 #define KC_CMD          0x64
135 #define KC_CMD_WOUT             0xd1
136 #define KC_CMD_NULL             0xff
137 #define KC_STATUS       0x64
138 #define KC_STATUS_OBUF_FULL     0x01
139 #define KC_STATUS_IBUF_FULL     0x02
140 #define KC_MAX_RETRIES  100000
141         .section ".text16.early", "awx", @progbits
142         .code16
143 enable_a20_kbc:
144         /* Preserve registers */
145         pushw   %ax
146
147         /* Try keyboard controller */
148         call    empty_kbc
149         movb    $KC_CMD_WOUT, %al
150         outb    %al, $KC_CMD
151         call    empty_kbc
152         movb    $KC_RDWR_SET_A20, %al
153         outb    %al, $KC_RDWR
154         call    empty_kbc
155         movb    $KC_CMD_NULL, %al
156         outb    %al, $KC_CMD
157         call    empty_kbc
158
159         /* Check to see if it worked */
160         call    test_a20_long
161
162         /* Restore registers and return */
163         popw    %ax
164         ret
165         .size   enable_a20_kbc, . - enable_a20_kbc
166
167         .section ".text16.early", "awx", @progbits
168         .code16
169 empty_kbc:
170         /* Preserve registers */
171         pushl   %ecx
172         pushw   %ax
173
174         /* Wait for KBC to become empty */
175         movl    $KC_MAX_RETRIES, %ecx
176 1:      outb    %al, $0x80
177         inb     $KC_STATUS, %al
178         testb   $( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
179         jz      99f
180         testb   $KC_STATUS_OBUF_FULL, %al
181         jz      2f
182         outb    %al, $0x80
183         inb     $KC_RDWR, %al
184 2:      addr32 loop 1b
185
186 99:     /* Restore registers and return */
187         popw    %ax
188         popl    %ecx
189         ret
190         .size   empty_kbc, . - empty_kbc
191
192 /****************************************************************************
193  * enable_a20_fast
194  *
195  * Try enabling A20 line via "Fast Gate A20"
196  *
197  * Parameters:
198  *   none
199  * Returns:
200  *   CF set if A20 line is not enabled
201  * Corrupts:
202  *   none
203  ****************************************************************************
204  */
205 #define SCP_A 0x92
206         .section ".text16.early", "awx", @progbits
207         .code16
208 enable_a20_fast:
209         /* Preserve registers */
210         pushw   %ax
211
212         /* Try "Fast Gate A20" */
213         inb     $SCP_A, %al
214         orb     $0x02, %al
215         andb    $~0x01, %al
216         outb    %al, $SCP_A
217
218         /* Check to see if it worked */
219         call    test_a20_long
220
221         /* Restore registers and return */
222         popw    %ax
223         ret
224         .size   enable_a20_fast, . - enable_a20_fast
225
226 /****************************************************************************
227  * enable_a20
228  *
229  * Try enabling A20 line via any available method
230  *
231  * Parameters:
232  *   none
233  * Returns:
234  *   CF set if A20 line is not enabled
235  * Corrupts:
236  *   none
237  ****************************************************************************
238  */
239 #define ENABLE_A20_RETRIES 255
240         .section ".text16.early", "awx", @progbits
241         .code16
242         .globl  enable_a20
243 enable_a20:
244         /* Preserve registers */
245         pushl   %ecx
246         pushw   %ax
247
248         /* Check to see if A20 is already enabled */
249         call    test_a20_short
250         jnc     99f
251
252         /* Use known working method, if we have one */
253         movw    %cs:enable_a20_method, %ax
254         testw   %ax, %ax
255         jz      1f
256         call    *%ax
257         jmp     99f
258 1:
259         /* Try all methods in turn until one works */
260         movl    $ENABLE_A20_RETRIES, %ecx
261 2:      movw    $enable_a20_bios, %ax
262         movw    %ax, %cs:enable_a20_method
263         call    *%ax
264         jnc     99f
265         movw    $enable_a20_kbc, %ax
266         movw    %ax, %cs:enable_a20_method
267         call    *%ax
268         jnc     99f
269         movw    $enable_a20_fast, %ax
270         movw    %ax, %cs:enable_a20_method
271         call    *%ax
272         jnc     99f
273         addr32 loop 2b
274         /* Failure; exit with carry set */
275         movw    $0, %cs:enable_a20_method
276         stc
277
278 99:     /* Restore registers and return */
279         popw    %ax
280         popl    %ecx
281         ret
282
283         .section ".text16.early.data", "aw", @progbits
284         .align  2
285 enable_a20_method:
286         .word   0
287         .size   enable_a20_method, . - enable_a20_method
288
289 /****************************************************************************
290  * access_highmem (real mode far call)
291  *
292  * Open up access to high memory with A20 enabled
293  *
294  * Parameters:
295  *   none
296  * Returns:
297  *   CF set if high memory could not be accessed
298  * Corrupts:
299  *   none
300  ****************************************************************************
301  */
302         .section ".text16.early", "awx", @progbits
303         .code16
304         .globl  access_highmem
305 access_highmem:
306         /* Enable A20 line */
307         call    enable_a20
308         lret
309         .size   access_highmem, . - access_highmem