|
@@ -22,25 +22,27 @@
|
22
|
22
|
enable data line
|
23
|
23
|
disable clock line */
|
24
|
24
|
|
|
25
|
+#define SCP_A 0x92 /* System Control Port A */
|
|
26
|
+
|
|
27
|
+#define A20_MAX_RETRIES 32
|
|
28
|
+
|
25
|
29
|
enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
|
26
|
30
|
Query_A20_Support = 0x2403 };
|
27
|
31
|
|
28
|
|
-#define CF ( 1 << 0 )
|
29
|
|
-
|
30
|
|
-#ifndef IBM_L40
|
|
32
|
+/**
|
|
33
|
+ * Drain keyboard controller
|
|
34
|
+ */
|
31
|
35
|
static void empty_8042 ( void ) {
|
32
|
36
|
unsigned long time;
|
33
|
37
|
|
34
|
38
|
time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
|
35
|
|
- while ( ( inb ( K_CMD ) & K_IBUF_FUL ) &&
|
|
39
|
+ while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
|
36
|
40
|
currticks() < time ) {
|
37
|
|
- /* Do nothing. In particular, do *not* read from
|
38
|
|
- * K_RDWR, because that will drain the keyboard buffer
|
39
|
|
- * and lose keypresses.
|
40
|
|
- */
|
|
41
|
+ SLOW_DOWN_IO;
|
|
42
|
+ ( void ) inb ( K_RDWR );
|
|
43
|
+ SLOW_DOWN_IO;
|
41
|
44
|
}
|
42
|
45
|
}
|
43
|
|
-#endif /* IBM_L40 */
|
44
|
46
|
|
45
|
47
|
/**
|
46
|
48
|
* Fast test to see if gate A20 is already set
|
|
@@ -82,6 +84,8 @@ static int gateA20_is_set ( void ) {
|
82
|
84
|
void gateA20_set ( void ) {
|
83
|
85
|
static char reentry_guard = 0;
|
84
|
86
|
unsigned int discard_a;
|
|
87
|
+ unsigned int scp_a;
|
|
88
|
+ int retries = 0;
|
85
|
89
|
|
86
|
90
|
/* Avoid potential infinite recursion */
|
87
|
91
|
if ( reentry_guard )
|
|
@@ -92,31 +96,49 @@ void gateA20_set ( void ) {
|
92
|
96
|
if ( gateA20_is_set() )
|
93
|
97
|
goto out;
|
94
|
98
|
|
95
|
|
- /* Try INT 15 method first */
|
96
|
|
- __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
|
97
|
|
- : "=a" ( discard_a )
|
98
|
|
- : "a" ( Enable_A20 ) );
|
99
|
|
- if ( gateA20_is_set() )
|
100
|
|
- goto out;
|
101
|
|
-
|
102
|
|
- /* INT 15 method failed, try alternatives */
|
103
|
|
-#ifdef IBM_L40
|
104
|
|
- outb(0x2, 0x92);
|
105
|
|
-#else /* IBM_L40 */
|
106
|
|
- empty_8042();
|
107
|
|
- outb(KC_CMD_WOUT, K_CMD);
|
108
|
|
- empty_8042();
|
109
|
|
- outb(KB_SET_A20, K_RDWR);
|
110
|
|
- empty_8042();
|
111
|
|
-#endif /* IBM_L40 */
|
112
|
|
- if ( gateA20_is_set() )
|
113
|
|
- goto out;
|
|
99
|
+ for ( ; retries < A20_MAX_RETRIES ; retries++ ) {
|
|
100
|
+
|
|
101
|
+ /* Try INT 15 method first */
|
|
102
|
+ __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
|
|
103
|
+ : "=a" ( discard_a )
|
|
104
|
+ : "a" ( Enable_A20 ) );
|
|
105
|
+ if ( gateA20_is_set() ) {
|
|
106
|
+ DBG ( "Enabled gate A20 using BIOS\n" );
|
|
107
|
+ goto out;
|
|
108
|
+ }
|
|
109
|
+
|
|
110
|
+ /* Try keyboard controller method */
|
|
111
|
+ empty_8042();
|
|
112
|
+ outb ( KC_CMD_WOUT, K_CMD );
|
|
113
|
+ empty_8042();
|
|
114
|
+ outb ( KB_SET_A20, K_RDWR );
|
|
115
|
+ empty_8042();
|
|
116
|
+ if ( gateA20_is_set() ) {
|
|
117
|
+ DBG ( "Enabled gate A20 using keyboard controller\n" );
|
|
118
|
+ goto out;
|
|
119
|
+ }
|
|
120
|
+
|
|
121
|
+ /* Try "Fast gate A20" method */
|
|
122
|
+ scp_a = inb ( SCP_A );
|
|
123
|
+ scp_a &= ~0x01; /* Avoid triggering a reset */
|
|
124
|
+ scp_a |= 0x02; /* Enable A20 */
|
|
125
|
+ SLOW_DOWN_IO;
|
|
126
|
+ outb ( scp_a, SCP_A );
|
|
127
|
+ SLOW_DOWN_IO;
|
|
128
|
+ if ( gateA20_is_set() ) {
|
|
129
|
+ DBG ( "Enabled gate A20 using Fast Gate A20\n" );
|
|
130
|
+ goto out;
|
|
131
|
+ }
|
|
132
|
+ }
|
114
|
133
|
|
115
|
134
|
/* Better to die now than corrupt memory later */
|
116
|
135
|
printf ( "FATAL: Gate A20 stuck\n" );
|
117
|
136
|
while ( 1 ) {}
|
118
|
137
|
|
119
|
138
|
out:
|
|
139
|
+ if ( retries )
|
|
140
|
+ DBG ( "%d attempts were required to enable A20\n",
|
|
141
|
+ ( retries + 1 ) );
|
120
|
142
|
reentry_guard = 0;
|
121
|
143
|
}
|
122
|
144
|
|