summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
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 67ef00ddc..c278db795 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 55f729364..000000000
--- 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 684973658..67f0d5111 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 297ad6f21..000000000
--- 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 f193f5e37..c6992f643 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 dd0bbc5c5..e93307443 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 9062b74fa..5e5f7b995 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 a07ffc502..5eb82b44b 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.