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 -#include -#include -#include -#include - -#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 #include #include -#include #include #include #include @@ -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.