|  | @@ -1,176 +0,0 @@
 | 
		
	
		
			
			| 1 |  | -FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 2 |  | -
 | 
		
	
		
			
			| 3 |  | -#include <stdio.h>
 | 
		
	
		
			
			| 4 |  | -#include <realmode.h>
 | 
		
	
		
			
			| 5 |  | -#include <bios.h>
 | 
		
	
		
			
			| 6 |  | -#include <ipxe/io.h>
 | 
		
	
		
			
			| 7 |  | -#include <ipxe/timer.h>
 | 
		
	
		
			
			| 8 |  | -
 | 
		
	
		
			
			| 9 |  | -#define K_RDWR		0x60		/* keyboard data & cmds (read/write) */
 | 
		
	
		
			
			| 10 |  | -#define K_STATUS	0x64		/* keyboard status */
 | 
		
	
		
			
			| 11 |  | -#define K_CMD		0x64		/* keybd ctlr command (write-only) */
 | 
		
	
		
			
			| 12 |  | -
 | 
		
	
		
			
			| 13 |  | -#define K_OBUF_FUL	0x01		/* output buffer full */
 | 
		
	
		
			
			| 14 |  | -#define K_IBUF_FUL	0x02		/* input buffer full */
 | 
		
	
		
			
			| 15 |  | -
 | 
		
	
		
			
			| 16 |  | -#define KC_CMD_WIN	0xd0		/* read  output port */
 | 
		
	
		
			
			| 17 |  | -#define KC_CMD_WOUT	0xd1		/* write output port */
 | 
		
	
		
			
			| 18 |  | -#define KC_CMD_NULL	0xff		/* null command ("pulse nothing") */
 | 
		
	
		
			
			| 19 |  | -#define KB_SET_A20	0xdf		/* enable A20,
 | 
		
	
		
			
			| 20 |  | -					   enable output buffer full interrupt
 | 
		
	
		
			
			| 21 |  | -					   enable data line
 | 
		
	
		
			
			| 22 |  | -					   disable clock line */
 | 
		
	
		
			
			| 23 |  | -#define KB_UNSET_A20	0xdd		/* enable A20,
 | 
		
	
		
			
			| 24 |  | -					   enable output buffer full interrupt
 | 
		
	
		
			
			| 25 |  | -					   enable data line
 | 
		
	
		
			
			| 26 |  | -					   disable clock line */
 | 
		
	
		
			
			| 27 |  | -
 | 
		
	
		
			
			| 28 |  | -#define SCP_A		0x92		/* System Control Port A */
 | 
		
	
		
			
			| 29 |  | -
 | 
		
	
		
			
			| 30 |  | -enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
 | 
		
	
		
			
			| 31 |  | -	Query_A20_Support = 0x2403 };
 | 
		
	
		
			
			| 32 |  | -
 | 
		
	
		
			
			| 33 |  | -enum a20_methods {
 | 
		
	
		
			
			| 34 |  | -	A20_UNKNOWN = 0,
 | 
		
	
		
			
			| 35 |  | -	A20_INT15,
 | 
		
	
		
			
			| 36 |  | -	A20_KBC,
 | 
		
	
		
			
			| 37 |  | -	A20_SCPA,
 | 
		
	
		
			
			| 38 |  | -};
 | 
		
	
		
			
			| 39 |  | -
 | 
		
	
		
			
			| 40 |  | -#define A20_MAX_RETRIES		32
 | 
		
	
		
			
			| 41 |  | -#define A20_INT15_RETRIES	32
 | 
		
	
		
			
			| 42 |  | -#define A20_KBC_RETRIES		(2^21)
 | 
		
	
		
			
			| 43 |  | -#define A20_SCPA_RETRIES	(2^21)
 | 
		
	
		
			
			| 44 |  | -
 | 
		
	
		
			
			| 45 |  | -/**
 | 
		
	
		
			
			| 46 |  | - * Drain keyboard controller
 | 
		
	
		
			
			| 47 |  | - */
 | 
		
	
		
			
			| 48 |  | -static void empty_8042 ( void ) {
 | 
		
	
		
			
			| 49 |  | -	unsigned long time;
 | 
		
	
		
			
			| 50 |  | -
 | 
		
	
		
			
			| 51 |  | -	time = currticks() + TICKS_PER_SEC;	/* max wait of 1 second */
 | 
		
	
		
			
			| 52 |  | -	while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
 | 
		
	
		
			
			| 53 |  | -		currticks() < time ) {
 | 
		
	
		
			
			| 54 |  | -		iodelay();
 | 
		
	
		
			
			| 55 |  | -		( void ) inb_p ( K_RDWR );
 | 
		
	
		
			
			| 56 |  | -		iodelay();
 | 
		
	
		
			
			| 57 |  | -	}
 | 
		
	
		
			
			| 58 |  | -}
 | 
		
	
		
			
			| 59 |  | -
 | 
		
	
		
			
			| 60 |  | -/**
 | 
		
	
		
			
			| 61 |  | - * Fast test to see if gate A20 is already set
 | 
		
	
		
			
			| 62 |  | - *
 | 
		
	
		
			
			| 63 |  | - * @v retries		Number of times to retry before giving up
 | 
		
	
		
			
			| 64 |  | - * @ret set		Gate A20 is set
 | 
		
	
		
			
			| 65 |  | - */
 | 
		
	
		
			
			| 66 |  | -static int gateA20_is_set ( int retries ) {
 | 
		
	
		
			
			| 67 |  | -	static uint32_t test_pattern = 0xdeadbeef;
 | 
		
	
		
			
			| 68 |  | -	physaddr_t test_pattern_phys = virt_to_phys ( &test_pattern );
 | 
		
	
		
			
			| 69 |  | -	physaddr_t verify_pattern_phys = ( test_pattern_phys ^ 0x100000 );
 | 
		
	
		
			
			| 70 |  | -	userptr_t verify_pattern_user = phys_to_user ( verify_pattern_phys );
 | 
		
	
		
			
			| 71 |  | -	uint32_t verify_pattern;
 | 
		
	
		
			
			| 72 |  | -
 | 
		
	
		
			
			| 73 |  | -	do {
 | 
		
	
		
			
			| 74 |  | -		/* Check for difference */
 | 
		
	
		
			
			| 75 |  | -		copy_from_user ( &verify_pattern, verify_pattern_user, 0,
 | 
		
	
		
			
			| 76 |  | -				 sizeof ( verify_pattern ) );
 | 
		
	
		
			
			| 77 |  | -		if ( verify_pattern != test_pattern )
 | 
		
	
		
			
			| 78 |  | -			return 1;
 | 
		
	
		
			
			| 79 |  | -
 | 
		
	
		
			
			| 80 |  | -		/* Avoid false negatives */
 | 
		
	
		
			
			| 81 |  | -		test_pattern++;
 | 
		
	
		
			
			| 82 |  | -
 | 
		
	
		
			
			| 83 |  | -		iodelay();
 | 
		
	
		
			
			| 84 |  | -
 | 
		
	
		
			
			| 85 |  | -		/* Always retry at least once, to avoid false negatives */
 | 
		
	
		
			
			| 86 |  | -	} while ( retries-- >= 0 );
 | 
		
	
		
			
			| 87 |  | -
 | 
		
	
		
			
			| 88 |  | -	/* Pattern matched every time; gate A20 is not set */
 | 
		
	
		
			
			| 89 |  | -	return 0;
 | 
		
	
		
			
			| 90 |  | -}
 | 
		
	
		
			
			| 91 |  | -
 | 
		
	
		
			
			| 92 |  | -/*
 | 
		
	
		
			
			| 93 |  | - * Gate A20 for high memory
 | 
		
	
		
			
			| 94 |  | - *
 | 
		
	
		
			
			| 95 |  | - * Note that this function gets called as part of the return path from
 | 
		
	
		
			
			| 96 |  | - * librm's real_call, which is used to make the int15 call if librm is
 | 
		
	
		
			
			| 97 |  | - * being used.  To avoid an infinite recursion, we make gateA20_set
 | 
		
	
		
			
			| 98 |  | - * return immediately if it is already part of the call stack.
 | 
		
	
		
			
			| 99 |  | - */
 | 
		
	
		
			
			| 100 |  | -void gateA20_set ( void ) {
 | 
		
	
		
			
			| 101 |  | -	static char reentry_guard = 0;
 | 
		
	
		
			
			| 102 |  | -	static int a20_method = A20_UNKNOWN;
 | 
		
	
		
			
			| 103 |  | -	unsigned int discard_a;
 | 
		
	
		
			
			| 104 |  | -	unsigned int scp_a;
 | 
		
	
		
			
			| 105 |  | -	int retries = 0;
 | 
		
	
		
			
			| 106 |  | -
 | 
		
	
		
			
			| 107 |  | -	/* Avoid potential infinite recursion */
 | 
		
	
		
			
			| 108 |  | -	if ( reentry_guard )
 | 
		
	
		
			
			| 109 |  | -		return;
 | 
		
	
		
			
			| 110 |  | -	reentry_guard = 1;
 | 
		
	
		
			
			| 111 |  | -
 | 
		
	
		
			
			| 112 |  | -	/* Fast check to see if gate A20 is already enabled */
 | 
		
	
		
			
			| 113 |  | -	if ( gateA20_is_set ( 0 ) )
 | 
		
	
		
			
			| 114 |  | -		goto out;
 | 
		
	
		
			
			| 115 |  | -
 | 
		
	
		
			
			| 116 |  | -	for ( ; retries < A20_MAX_RETRIES ; retries++ ) {
 | 
		
	
		
			
			| 117 |  | -		switch ( a20_method ) {
 | 
		
	
		
			
			| 118 |  | -		case A20_UNKNOWN:
 | 
		
	
		
			
			| 119 |  | -		case A20_INT15:
 | 
		
	
		
			
			| 120 |  | -			/* Try INT 15 method */
 | 
		
	
		
			
			| 121 |  | -			__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
 | 
		
	
		
			
			| 122 |  | -					       : "=a" ( discard_a )
 | 
		
	
		
			
			| 123 |  | -					       : "a" ( Enable_A20 ) );
 | 
		
	
		
			
			| 124 |  | -			if ( gateA20_is_set ( A20_INT15_RETRIES ) ) {
 | 
		
	
		
			
			| 125 |  | -				DBG ( "Enabled gate A20 using BIOS\n" );
 | 
		
	
		
			
			| 126 |  | -				a20_method = A20_INT15;
 | 
		
	
		
			
			| 127 |  | -				goto out;
 | 
		
	
		
			
			| 128 |  | -			}
 | 
		
	
		
			
			| 129 |  | -			/* fall through */
 | 
		
	
		
			
			| 130 |  | -		case A20_KBC:
 | 
		
	
		
			
			| 131 |  | -			/* Try keyboard controller method */
 | 
		
	
		
			
			| 132 |  | -			empty_8042();
 | 
		
	
		
			
			| 133 |  | -			outb ( KC_CMD_WOUT, K_CMD );
 | 
		
	
		
			
			| 134 |  | -			empty_8042();
 | 
		
	
		
			
			| 135 |  | -			outb ( KB_SET_A20, K_RDWR );
 | 
		
	
		
			
			| 136 |  | -			empty_8042();
 | 
		
	
		
			
			| 137 |  | -			outb ( KC_CMD_NULL, K_CMD );
 | 
		
	
		
			
			| 138 |  | -			empty_8042();
 | 
		
	
		
			
			| 139 |  | -			if ( gateA20_is_set ( A20_KBC_RETRIES ) ) {
 | 
		
	
		
			
			| 140 |  | -				DBG ( "Enabled gate A20 using "
 | 
		
	
		
			
			| 141 |  | -				      "keyboard controller\n" );
 | 
		
	
		
			
			| 142 |  | -				a20_method = A20_KBC;
 | 
		
	
		
			
			| 143 |  | -				goto out;
 | 
		
	
		
			
			| 144 |  | -			}
 | 
		
	
		
			
			| 145 |  | -			/* fall through */
 | 
		
	
		
			
			| 146 |  | -		case A20_SCPA:
 | 
		
	
		
			
			| 147 |  | -			/* Try "Fast gate A20" method */
 | 
		
	
		
			
			| 148 |  | -			scp_a = inb ( SCP_A );
 | 
		
	
		
			
			| 149 |  | -			scp_a &= ~0x01; /* Avoid triggering a reset */
 | 
		
	
		
			
			| 150 |  | -			scp_a |= 0x02; /* Enable A20 */
 | 
		
	
		
			
			| 151 |  | -			iodelay();
 | 
		
	
		
			
			| 152 |  | -			outb ( scp_a, SCP_A );
 | 
		
	
		
			
			| 153 |  | -			iodelay();
 | 
		
	
		
			
			| 154 |  | -			if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
 | 
		
	
		
			
			| 155 |  | -				DBG ( "Enabled gate A20 using "
 | 
		
	
		
			
			| 156 |  | -				      "Fast Gate A20\n" );
 | 
		
	
		
			
			| 157 |  | -				a20_method = A20_SCPA;
 | 
		
	
		
			
			| 158 |  | -				goto out;
 | 
		
	
		
			
			| 159 |  | -			}
 | 
		
	
		
			
			| 160 |  | -		}
 | 
		
	
		
			
			| 161 |  | -	}
 | 
		
	
		
			
			| 162 |  | -
 | 
		
	
		
			
			| 163 |  | -	/* Better to die now than corrupt memory later */
 | 
		
	
		
			
			| 164 |  | -	printf ( "FATAL: Gate A20 stuck\n" );
 | 
		
	
		
			
			| 165 |  | -	while ( 1 ) {}
 | 
		
	
		
			
			| 166 |  | -
 | 
		
	
		
			
			| 167 |  | - out:
 | 
		
	
		
			
			| 168 |  | -	if ( retries )
 | 
		
	
		
			
			| 169 |  | -		DBG ( "%d attempts were required to enable A20\n",
 | 
		
	
		
			
			| 170 |  | -		      ( retries + 1 ) );
 | 
		
	
		
			
			| 171 |  | -	reentry_guard = 0;
 | 
		
	
		
			
			| 172 |  | -}
 | 
		
	
		
			
			| 173 |  | -
 | 
		
	
		
			
			| 174 |  | -void gateA20_unset ( void ) {
 | 
		
	
		
			
			| 175 |  | -	/* Not currently implemented */
 | 
		
	
		
			
			| 176 |  | -}
 |