[prefix] Add A20-enabling code in libflat
[people/meteger/gpxe.git] / src / arch / i386 / transitions / libflat.S
index 9cb4c8a..9062b74 100644 (file)
@@ -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