summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/prefix/libprefix.S21
-rw-r--r--src/arch/i386/transitions/libflat.S283
2 files changed, 296 insertions, 8 deletions
diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S
index df71a9d7b..6a23a96cc 100644
--- a/src/arch/i386/prefix/libprefix.S
+++ b/src/arch/i386/prefix/libprefix.S
@@ -512,13 +512,24 @@ install_prealloc:
/* Open up access to payload */
#ifndef KEEP_IT_REAL
- /* Flatten real mode */
+ /* Access high memory */
pushw %cs
pushw $1f
pushw %ax
- pushw $flatten_real_mode
+ pushw $access_highmem
lret
-1:
+1: /* Die if we could not access high memory */
+ jnc 3f
+ movw $a20_death_message, %si
+ xorw %di, %di
+ call print_message
+2: jmp 2b
+ .section ".prefix.data", "aw", @progbits
+a20_death_message:
+ .asciz "Gate A20 stuck - cannot continue\n"
+ .size a20_death_message, . - a20_death_message
+ .previous
+3:
#endif
/* Calculate physical address of payload (i.e. first source) */
@@ -570,13 +581,13 @@ install_prealloc:
popl %edx /* discard */
/* Copy code to new location */
+ pushl %edi
xorw %ax, %ax
movw %ax, %es
- movl %ebp, %edi
es rep addr32 movsb
+ popl %edi
/* Initialise librm at new location */
- movl %ebp, %edi
lcall *init_librm_vector
#endif
diff --git a/src/arch/i386/transitions/libflat.S b/src/arch/i386/transitions/libflat.S
index 9cb4c8af3..9062b74fa 100644
--- a/src/arch/i386/transitions/libflat.S
+++ b/src/arch/i386/transitions/libflat.S
@@ -24,7 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
#define CR0_PE 1
/****************************************************************************
- * flatten_real_mode (real-mode far call)
+ * flatten_real_mode
*
* Set up 4GB segment limits
*
@@ -63,7 +63,6 @@ flatten_saved_gdt:
.section ".text16.early", "awx", @progbits
.code16
- .globl flatten_real_mode
flatten_real_mode:
/* Preserve registers and flags */
pushfl
@@ -126,7 +125,7 @@ flatten_real_mode:
popw %si
popl %eax
popfl
- lret
+ ret
.size flatten_real_mode, . - flatten_real_mode
.section ".text16.early", "awx", @progbits
@@ -139,3 +138,281 @@ set_seg_base:
andb $0x0f, 4(%si)
ret
.size set_seg_base, . - set_seg_base
+
+/****************************************************************************
+ * test_a20_short, test_a20_long
+ *
+ * Check to see if A20 line is enabled
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if A20 line is not enabled
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+#define TEST_A20_SHORT_MAX_RETRIES 0x20
+#define TEST_A20_LONG_MAX_RETRIES 0x200000
+ .section ".text16.early", "awx", @progbits
+ .code16
+test_a20_short:
+ pushl %ecx
+ movl $TEST_A20_SHORT_MAX_RETRIES, %ecx
+ jmp 1f
+ .size test_a20_short, . - test_a20_short
+test_a20_long:
+ pushl %ecx
+ movl $TEST_A20_LONG_MAX_RETRIES, %ecx
+1: pushw %ax
+
+ /* Flatten real mode so we can access the test pattern's 1MB offset */
+ call flatten_real_mode
+
+2: /* Modify and check test pattern; succeed if we see a difference */
+ incw %cs:test_a20_data
+ addr32 movw %cs:(test_a20_data + 0x100000 ), %ax
+ cmpw %cs:test_a20_data, %ax
+ clc
+ jnz 99f
+
+ /* Delay and retry */
+ outb %al, $0x80
+ addr32 loop 2b
+ stc
+
+99: /* Restore registers and return */
+ popw %ax
+ popl %ecx
+ ret
+ .size test_a20_long, . - test_a20_long
+
+ .section ".text16.early.data", "aw", @progbits
+ .align 2
+test_a20_data:
+ .word 0xdead
+ .size test_a20_data, . - test_a20_data
+
+/****************************************************************************
+ * enable_a20_bios
+ *
+ * Try enabling A20 line via BIOS
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if A20 line is not enabled
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16.early", "awx", @progbits
+ .code16
+enable_a20_bios:
+ /* Preserve registers */
+ pushw %ax
+
+ /* Attempt INT 15,2401 */
+ movw $0x2401, %ax
+ int $0x15
+ jc 99f
+
+ /* Check that success was really successful */
+ call test_a20_short
+
+99: /* Restore registers and return */
+ popw %ax
+ ret
+ .size enable_a20_bios, . - enable_a20_bios
+
+/****************************************************************************
+ * enable_a20_kbc
+ *
+ * Try enabling A20 line via keyboard controller
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if A20 line is not enabled
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+#define KC_RDWR 0x60
+#define KC_RDWR_SET_A20 0xdf
+#define KC_CMD 0x64
+#define KC_CMD_WOUT 0xd1
+#define KC_CMD_NULL 0xff
+#define KC_STATUS 0x64
+#define KC_STATUS_OBUF_FULL 0x01
+#define KC_STATUS_IBUF_FULL 0x02
+#define KC_MAX_RETRIES 100000
+ .section ".text16.early", "awx", @progbits
+ .code16
+enable_a20_kbc:
+ /* Preserve registers */
+ pushw %ax
+
+ /* Try keyboard controller */
+ call empty_kbc
+ movb $KC_CMD_WOUT, %al
+ outb %al, $KC_CMD
+ call empty_kbc
+ movb $KC_RDWR_SET_A20, %al
+ outb %al, $KC_RDWR
+ call empty_kbc
+ movb $KC_CMD_NULL, %al
+ outb %al, $KC_CMD
+ call empty_kbc
+
+ /* Check to see if it worked */
+ call test_a20_long
+
+ /* Restore registers and return */
+ popw %ax
+ ret
+ .size enable_a20_kbc, . - enable_a20_kbc
+
+ .section ".text16.early", "awx", @progbits
+ .code16
+empty_kbc:
+ /* Preserve registers */
+ pushl %ecx
+ pushw %ax
+
+ /* Wait for KBC to become empty */
+ movl $KC_MAX_RETRIES, %ecx
+1: outb %al, $0x80
+ inb $KC_STATUS, %al
+ testb $( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
+ jz 99f
+ testb $KC_STATUS_OBUF_FULL, %al
+ jz 2f
+ outb %al, $0x80
+ inb $KC_RDWR, %al
+2: addr32 loop 1b
+
+99: /* Restore registers and return */
+ popw %ax
+ popl %ecx
+ ret
+ .size empty_kbc, . - empty_kbc
+
+/****************************************************************************
+ * enable_a20_fast
+ *
+ * Try enabling A20 line via "Fast Gate A20"
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if A20 line is not enabled
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+#define SCP_A 0x92
+ .section ".text16.early", "awx", @progbits
+ .code16
+enable_a20_fast:
+ /* Preserve registers */
+ pushw %ax
+
+ /* Try "Fast Gate A20" */
+ inb $SCP_A, %al
+ orb $0x02, %al
+ andb $~0x01, %al
+ outb %al, $SCP_A
+
+ /* Check to see if it worked */
+ call test_a20_long
+
+ /* Restore registers and return */
+ popw %ax
+ ret
+ .size enable_a20_fast, . - enable_a20_fast
+
+/****************************************************************************
+ * enable_a20
+ *
+ * Try enabling A20 line via any available method
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if A20 line is not enabled
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+#define ENABLE_A20_RETRIES 255
+ .section ".text16.early", "awx", @progbits
+ .code16
+enable_a20:
+ /* Preserve registers */
+ pushl %ecx
+ pushw %ax
+
+ /* Check to see if A20 is already enabled */
+ call test_a20_short
+ jnc 99f
+
+ /* Use known working method, if we have one */
+ movw %cs:enable_a20_method, %ax
+ testw %ax, %ax
+ jz 1f
+ call *%ax
+ jmp 99f
+1:
+ /* Try all methods in turn until one works */
+ movl $ENABLE_A20_RETRIES, %ecx
+2: movw $enable_a20_bios, %ax
+ movw %ax, %cs:enable_a20_method
+ call *%ax
+ jnc 99f
+ movw $enable_a20_kbc, %ax
+ movw %ax, %cs:enable_a20_method
+ call *%ax
+ jnc 99f
+ movw $enable_a20_fast, %ax
+ movw %ax, %cs:enable_a20_method
+ call *%ax
+ jnc 99f
+ addr32 loop 2b
+ /* Failure; exit with carry set */
+ movw $0, %cs:enable_a20_method
+ stc
+
+99: /* Restore registers and return */
+ popw %ax
+ popl %ecx
+ ret
+
+ .section ".text16.early.data", "aw", @progbits
+ .align 2
+enable_a20_method:
+ .word 0
+ .size enable_a20_method, . - enable_a20_method
+
+/****************************************************************************
+ * access_highmem (real mode far call)
+ *
+ * Open up access to high memory in flat real mode with A20 enabled
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * CF set if high memory could not be accessed
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16.early", "awx", @progbits
+ .code16
+ .globl access_highmem
+access_highmem:
+ /* Enable A20 line */
+ call enable_a20
+ /* CPU will be in flat real mode as a result of this call */
+ lret
+ .size access_highmem, . - access_highmem