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