2 * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 FILE_LICENCE ( GPL2_OR_LATER )
26 /****************************************************************************
29 * Set up 4GB segment limits
37 ****************************************************************************
39 /* GDT for protected-mode calls */
40 .section ".text16.early.data", "aw", @progbits
43 flatten_gdt_limit: .word flatten_gdt_length - 1
44 flatten_gdt_base: .long 0
46 flatten_cs: /* 16-bit protected-mode flat code segment */
47 .equ FLAT_CS, flatten_cs - flatten_gdt
49 .byte 0, 0x9b, 0x8f, 0
50 flatten_ss: /* 16-bit protected-mode flat stack segment */
51 .equ FLAT_SS, flatten_ss - flatten_gdt
53 .byte 0, 0x93, 0x8f, 0
55 .equ flatten_gdt_length, . - flatten_gdt
56 .size flatten_gdt, . - flatten_gdt
58 .section ".text16.early.data", "aw", @progbits
62 .size flatten_saved_gdt, . - flatten_saved_gdt
64 .section ".text16.early", "awx", @progbits
67 /* Preserve registers and flags */
77 /* Set %ds for access to .text16.early.data variables */
81 /* Preserve original GDT */
82 sgdt flatten_saved_gdt
84 /* Set up GDT bases */
88 addl $flatten_gdt, %eax
89 movl %eax, flatten_gdt_base
97 /* Switch temporarily to protected mode and set segment registers */
101 data32 lgdt flatten_gdt
106 1: movw $FLAT_SS, %ax
116 2: /* lret will ljmp to here */
118 /* Restore GDT, registers and flags */
119 data32 lgdt flatten_saved_gdt
129 .size flatten_real_mode, . - flatten_real_mode
131 .section ".text16.early", "awx", @progbits
140 .size set_seg_base, . - set_seg_base
142 /****************************************************************************
143 * test_a20_short, test_a20_long
145 * Check to see if A20 line is enabled
150 * CF set if A20 line is not enabled
153 ****************************************************************************
155 #define TEST_A20_SHORT_MAX_RETRIES 0x20
156 #define TEST_A20_LONG_MAX_RETRIES 0x200000
157 .section ".text16.early", "awx", @progbits
161 movl $TEST_A20_SHORT_MAX_RETRIES, %ecx
163 .size test_a20_short, . - test_a20_short
166 movl $TEST_A20_LONG_MAX_RETRIES, %ecx
169 /* Flatten real mode so we can access the test pattern's 1MB offset */
170 call flatten_real_mode
172 2: /* Modify and check test pattern; succeed if we see a difference */
173 incw %cs:test_a20_data
174 addr32 movw %cs:(test_a20_data + 0x100000 ), %ax
175 cmpw %cs:test_a20_data, %ax
179 /* Delay and retry */
184 99: /* Restore registers and return */
188 .size test_a20_long, . - test_a20_long
190 .section ".text16.early.data", "aw", @progbits
194 .size test_a20_data, . - test_a20_data
196 /****************************************************************************
199 * Try enabling A20 line via BIOS
204 * CF set if A20 line is not enabled
207 ****************************************************************************
209 .section ".text16.early", "awx", @progbits
212 /* Preserve registers */
215 /* Attempt INT 15,2401 */
220 /* Check that success was really successful */
223 99: /* Restore registers and return */
226 .size enable_a20_bios, . - enable_a20_bios
228 /****************************************************************************
231 * Try enabling A20 line via keyboard controller
236 * CF set if A20 line is not enabled
239 ****************************************************************************
242 #define KC_RDWR_SET_A20 0xdf
244 #define KC_CMD_WOUT 0xd1
245 #define KC_CMD_NULL 0xff
246 #define KC_STATUS 0x64
247 #define KC_STATUS_OBUF_FULL 0x01
248 #define KC_STATUS_IBUF_FULL 0x02
249 #define KC_MAX_RETRIES 100000
250 .section ".text16.early", "awx", @progbits
253 /* Preserve registers */
256 /* Try keyboard controller */
258 movb $KC_CMD_WOUT, %al
261 movb $KC_RDWR_SET_A20, %al
264 movb $KC_CMD_NULL, %al
268 /* Check to see if it worked */
271 /* Restore registers and return */
274 .size enable_a20_kbc, . - enable_a20_kbc
276 .section ".text16.early", "awx", @progbits
279 /* Preserve registers */
283 /* Wait for KBC to become empty */
284 movl $KC_MAX_RETRIES, %ecx
287 testb $( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
289 testb $KC_STATUS_OBUF_FULL, %al
295 99: /* Restore registers and return */
299 .size empty_kbc, . - empty_kbc
301 /****************************************************************************
304 * Try enabling A20 line via "Fast Gate A20"
309 * CF set if A20 line is not enabled
312 ****************************************************************************
315 .section ".text16.early", "awx", @progbits
318 /* Preserve registers */
321 /* Try "Fast Gate A20" */
327 /* Check to see if it worked */
330 /* Restore registers and return */
333 .size enable_a20_fast, . - enable_a20_fast
335 /****************************************************************************
338 * Try enabling A20 line via any available method
343 * CF set if A20 line is not enabled
346 ****************************************************************************
348 #define ENABLE_A20_RETRIES 255
349 .section ".text16.early", "awx", @progbits
353 /* Preserve registers */
357 /* Check to see if A20 is already enabled */
361 /* Use known working method, if we have one */
362 movw %cs:enable_a20_method, %ax
368 /* Try all methods in turn until one works */
369 movl $ENABLE_A20_RETRIES, %ecx
370 2: movw $enable_a20_bios, %ax
371 movw %ax, %cs:enable_a20_method
374 movw $enable_a20_kbc, %ax
375 movw %ax, %cs:enable_a20_method
378 movw $enable_a20_fast, %ax
379 movw %ax, %cs:enable_a20_method
383 /* Failure; exit with carry set */
384 movw $0, %cs:enable_a20_method
387 99: /* Restore registers and return */
392 .section ".text16.early.data", "aw", @progbits
396 .size enable_a20_method, . - enable_a20_method
398 /****************************************************************************
399 * access_highmem (real mode far call)
401 * Open up access to high memory in flat real mode with A20 enabled
406 * CF set if high memory could not be accessed
409 ****************************************************************************
411 .section ".text16.early", "awx", @progbits
413 .globl access_highmem
415 /* Enable A20 line */
417 /* CPU will be in flat real mode as a result of this call */
419 .size access_highmem, . - access_highmem