summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2010-04-20 20:20:26 +0200
committerMichael Brown2010-04-20 22:00:49 +0200
commit38cd2035ff56307284676d3d10cb77821ae3386a (patch)
tree1b39266a7bf7bc3161f0c6736d7e4c95d6615329 /src
parent[prefix] Add A20-enabling code in libflat (diff)
downloadipxe-38cd2035ff56307284676d3d10cb77821ae3386a.tar.gz
ipxe-38cd2035ff56307284676d3d10cb77821ae3386a.tar.xz
ipxe-38cd2035ff56307284676d3d10cb77821ae3386a.zip
[librm] Use libflat to enable A20 line on each real-to-protected transition
Use the shared code in libflat to perform the A20 transitions automatically on each transition from real to protected mode. This allows us to remove all explicit calls to gateA20_set(). The old warnings about avoiding automatically enabling A20 are essentially redundant; they date back to the time when we would always start hammering the keyboard controller without first checking to see if gate A20 was already enabled (which it almost always is). Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r--src/arch/i386/drivers/net/undiload.c10
-rw-r--r--src/arch/i386/firmware/pcbios/gateA20.c176
-rw-r--r--src/arch/i386/image/nbi.c7
-rw-r--r--src/arch/i386/include/gateA20.h7
-rw-r--r--src/arch/i386/include/librm.h5
-rw-r--r--src/arch/i386/interface/pxeparent/pxeparent.c10
-rw-r--r--src/arch/i386/transitions/libflat.S1
-rw-r--r--src/arch/i386/transitions/librm.S23
8 files changed, 12 insertions, 227 deletions
diff --git a/src/arch/i386/drivers/net/undiload.c b/src/arch/i386/drivers/net/undiload.c
index 67ef00dd..c278db79 100644
--- a/src/arch/i386/drivers/net/undiload.c
+++ b/src/arch/i386/drivers/net/undiload.c
@@ -104,16 +104,6 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
: "a" ( __from_data16 ( &undi_loader ) )
: "ebx", "ecx", "edx", "esi", "edi", "ebp" );
- /* UNDI API calls may rudely change the status of A20 and not
- * bother to restore it afterwards. Intel is known to be
- * guilty of this.
- *
- * Note that we will return to this point even if A20 gets
- * screwed up by the UNDI driver, because Etherboot always
- * resides in an even megabyte of RAM.
- */
- gateA20_set();
-
if ( exit != PXENV_EXIT_SUCCESS ) {
/* Clear entry point */
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
diff --git a/src/arch/i386/firmware/pcbios/gateA20.c b/src/arch/i386/firmware/pcbios/gateA20.c
deleted file mode 100644
index 55f72936..00000000
--- a/src/arch/i386/firmware/pcbios/gateA20.c
+++ /dev/null
@@ -1,176 +0,0 @@
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stdio.h>
-#include <realmode.h>
-#include <bios.h>
-#include <ipxe/io.h>
-#include <ipxe/timer.h>
-
-#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
-#define K_STATUS 0x64 /* keyboard status */
-#define K_CMD 0x64 /* keybd ctlr command (write-only) */
-
-#define K_OBUF_FUL 0x01 /* output buffer full */
-#define K_IBUF_FUL 0x02 /* input buffer full */
-
-#define KC_CMD_WIN 0xd0 /* read output port */
-#define KC_CMD_WOUT 0xd1 /* write output port */
-#define KC_CMD_NULL 0xff /* null command ("pulse nothing") */
-#define KB_SET_A20 0xdf /* enable A20,
- enable output buffer full interrupt
- enable data line
- disable clock line */
-#define KB_UNSET_A20 0xdd /* enable A20,
- enable output buffer full interrupt
- enable data line
- disable clock line */
-
-#define SCP_A 0x92 /* System Control Port A */
-
-enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
- Query_A20_Support = 0x2403 };
-
-enum a20_methods {
- A20_UNKNOWN = 0,
- A20_INT15,
- A20_KBC,
- A20_SCPA,
-};
-
-#define A20_MAX_RETRIES 32
-#define A20_INT15_RETRIES 32
-#define A20_KBC_RETRIES (2^21)
-#define A20_SCPA_RETRIES (2^21)
-
-/**
- * Drain keyboard controller
- */
-static void empty_8042 ( void ) {
- unsigned long time;
-
- time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
- while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
- currticks() < time ) {
- iodelay();
- ( void ) inb_p ( K_RDWR );
- iodelay();
- }
-}
-
-/**
- * Fast test to see if gate A20 is already set
- *
- * @v retries Number of times to retry before giving up
- * @ret set Gate A20 is set
- */
-static int gateA20_is_set ( int retries ) {
- static uint32_t test_pattern = 0xdeadbeef;
- physaddr_t test_pattern_phys = virt_to_phys ( &test_pattern );
- physaddr_t verify_pattern_phys = ( test_pattern_phys ^ 0x100000 );
- userptr_t verify_pattern_user = phys_to_user ( verify_pattern_phys );
- uint32_t verify_pattern;
-
- do {
- /* Check for difference */
- copy_from_user ( &verify_pattern, verify_pattern_user, 0,
- sizeof ( verify_pattern ) );
- if ( verify_pattern != test_pattern )
- return 1;
-
- /* Avoid false negatives */
- test_pattern++;
-
- iodelay();
-
- /* Always retry at least once, to avoid false negatives */
- } while ( retries-- >= 0 );
-
- /* Pattern matched every time; gate A20 is not set */
- return 0;
-}
-
-/*
- * Gate A20 for high memory
- *
- * Note that this function gets called as part of the return path from
- * librm's real_call, which is used to make the int15 call if librm is
- * being used. To avoid an infinite recursion, we make gateA20_set
- * return immediately if it is already part of the call stack.
- */
-void gateA20_set ( void ) {
- static char reentry_guard = 0;
- static int a20_method = A20_UNKNOWN;
- unsigned int discard_a;
- unsigned int scp_a;
- int retries = 0;
-
- /* Avoid potential infinite recursion */
- if ( reentry_guard )
- return;
- reentry_guard = 1;
-
- /* Fast check to see if gate A20 is already enabled */
- if ( gateA20_is_set ( 0 ) )
- goto out;
-
- for ( ; retries < A20_MAX_RETRIES ; retries++ ) {
- switch ( a20_method ) {
- case A20_UNKNOWN:
- case A20_INT15:
- /* Try INT 15 method */
- __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
- : "=a" ( discard_a )
- : "a" ( Enable_A20 ) );
- if ( gateA20_is_set ( A20_INT15_RETRIES ) ) {
- DBG ( "Enabled gate A20 using BIOS\n" );
- a20_method = A20_INT15;
- goto out;
- }
- /* fall through */
- case A20_KBC:
- /* Try keyboard controller method */
- empty_8042();
- outb ( KC_CMD_WOUT, K_CMD );
- empty_8042();
- outb ( KB_SET_A20, K_RDWR );
- empty_8042();
- outb ( KC_CMD_NULL, K_CMD );
- empty_8042();
- if ( gateA20_is_set ( A20_KBC_RETRIES ) ) {
- DBG ( "Enabled gate A20 using "
- "keyboard controller\n" );
- a20_method = A20_KBC;
- goto out;
- }
- /* fall through */
- case A20_SCPA:
- /* Try "Fast gate A20" method */
- scp_a = inb ( SCP_A );
- scp_a &= ~0x01; /* Avoid triggering a reset */
- scp_a |= 0x02; /* Enable A20 */
- iodelay();
- outb ( scp_a, SCP_A );
- iodelay();
- if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
- DBG ( "Enabled gate A20 using "
- "Fast Gate A20\n" );
- a20_method = A20_SCPA;
- goto out;
- }
- }
- }
-
- /* Better to die now than corrupt memory later */
- printf ( "FATAL: Gate A20 stuck\n" );
- while ( 1 ) {}
-
- out:
- if ( retries )
- DBG ( "%d attempts were required to enable A20\n",
- ( retries + 1 ) );
- reentry_guard = 0;
-}
-
-void gateA20_unset ( void ) {
- /* Not currently implemented */
-}
diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c
index 68497365..67f0d511 100644
--- a/src/arch/i386/image/nbi.c
+++ b/src/arch/i386/image/nbi.c
@@ -1,7 +1,6 @@
#include <errno.h>
#include <assert.h>
#include <realmode.h>
-#include <gateA20.h>
#include <memsizes.h>
#include <basemem_packet.h>
#include <ipxe/uaccess.h>
@@ -306,8 +305,6 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
imgheader->execaddr.segoff.segment,
imgheader->execaddr.segoff.offset );
- gateA20_unset();
-
__asm__ __volatile__ (
REAL_CODE ( "pushw %%ds\n\t" /* far pointer to bootp data */
"pushw %%bx\n\t"
@@ -327,8 +324,6 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
"b" ( __from_data16 ( basemem_packet ) )
: "ecx", "edx", "ebp" );
- gateA20_set();
-
return rc;
}
@@ -345,8 +340,6 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
image, imgheader->execaddr.linear );
- /* no gateA20_unset for PM call */
-
/* Jump to OS with flat physical addressing */
__asm__ __volatile__ (
PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
diff --git a/src/arch/i386/include/gateA20.h b/src/arch/i386/include/gateA20.h
deleted file mode 100644
index 297ad6f2..00000000
--- a/src/arch/i386/include/gateA20.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef GATEA20_H
-#define GATEA20_H
-
-extern void gateA20_set ( void );
-extern void gateA20_unset ( void );
-
-#endif /* GATEA20_H */
diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h
index f193f5e3..c6992f64 100644
--- a/src/arch/i386/include/librm.h
+++ b/src/arch/i386/include/librm.h
@@ -157,11 +157,6 @@ extern uint16_t __data16 ( rm_cs );
extern uint16_t __text16 ( rm_ds );
#define rm_ds __use_text16 ( rm_ds )
-/* Functions that librm expects to be able to link to. Included here
- * so that the compiler will catch prototype mismatches.
- */
-extern void gateA20_set ( void );
-
/**
* Convert segment:offset address to user buffer
*
diff --git a/src/arch/i386/interface/pxeparent/pxeparent.c b/src/arch/i386/interface/pxeparent/pxeparent.c
index dd0bbc5c..e9330744 100644
--- a/src/arch/i386/interface/pxeparent/pxeparent.c
+++ b/src/arch/i386/interface/pxeparent/pxeparent.c
@@ -147,16 +147,6 @@ int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
"D" ( __from_data16 ( &pxeparent_params ) )
: "ecx", "edx", "esi", "ebp" );
- /* PXE API calls may rudely change the status of A20 and not
- * bother to restore it afterwards. Intel is known to be
- * guilty of this.
- *
- * Note that we will return to this point even if A20 gets
- * screwed up by the parent PXE stack, because Etherboot always
- * resides in an even megabyte of RAM.
- */
- gateA20_set();
-
/* Determine return status code based on PXENV_EXIT and
* PXENV_STATUS
*/
diff --git a/src/arch/i386/transitions/libflat.S b/src/arch/i386/transitions/libflat.S
index 9062b74f..5e5f7b99 100644
--- a/src/arch/i386/transitions/libflat.S
+++ b/src/arch/i386/transitions/libflat.S
@@ -348,6 +348,7 @@ enable_a20_fast:
#define ENABLE_A20_RETRIES 255
.section ".text16.early", "awx", @progbits
.code16
+ .globl enable_a20
enable_a20:
/* Preserve registers */
pushl %ecx
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S
index a07ffc50..5eb82b44 100644
--- a/src/arch/i386/transitions/librm.S
+++ b/src/arch/i386/transitions/librm.S
@@ -170,10 +170,18 @@ idt_init: /* Reuse the return opcode here */
.section ".text16", "ax", @progbits
.code16
real_to_prot:
+ /* Enable A20 line */
+ call enable_a20
+ /* A failure at this point is fatal, and there's nothing we
+ * can do about it other than lock the machine to make the
+ * problem immediately visible.
+ */
+1: jc 1b
+
/* Make sure we have our data segment available */
movw %cs:rm_ds, %ax
movw %ax, %ds
-
+
/* Add _virt_offset, _text16 and _data16 to stack to be
* copied, and also copy the return address.
*/
@@ -181,7 +189,7 @@ real_to_prot:
pushl _text16
pushl _data16
addw $16, %cx /* %ecx must be less than 64kB anyway */
-
+
/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
xorl %ebp, %ebp
movw %ss, %bp
@@ -396,9 +404,6 @@ prot_call:
.section ".text", "ax", @progbits
.code32
1:
- /* Set up environment expected by C code */
- call gateA20_set
-
/* Call function */
leal PC_OFFSET_IX86(%esp), %eax
pushl %eax
@@ -442,13 +447,7 @@ prot_call:
* function will be passed back to the protected-mode caller. A
* result of this is that this routine cannot be called directly from
* C code, since it clobbers registers that the C ABI expects the
- * callee to preserve. Gate A20 will *not* be automatically
- * re-enabled. Since we always run from an even megabyte of memory,
- * we are guaranteed to return successfully to the protected-mode
- * code, which should then call gateA20_set() if it suspects that gate
- * A20 may have been disabled. Note that enabling gate A20 is a
- * potentially slow operation that may also cause keyboard input to be
- * lost; this is why it is not done automatically.
+ * callee to preserve.
*
* librm.h defines a convenient macro REAL_CODE() for using real_call.
* See librm.h and realmode.h for details and examples.