浏览代码

On advice of hpa: be more patient with the KBC and SCPA methods; retry

in a long loop before giving up on them.  Record method which worked
and default to that method on next attempt.
tags/v0.9.3
Michael Brown 17 年前
父节点
当前提交
26473105cd
共有 1 个文件被更改,包括 71 次插入47 次删除
  1. 71
    47
      src/arch/i386/firmware/pcbios/gateA20.c

+ 71
- 47
src/arch/i386/firmware/pcbios/gateA20.c 查看文件

@@ -24,11 +24,21 @@
24 24
 
25 25
 #define SCP_A		0x92		/* System Control Port A */
26 26
 
27
-#define A20_MAX_RETRIES	32
28
-
29 27
 enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
30 28
 	Query_A20_Support = 0x2403 };
31 29
 
30
+enum a20_methods {
31
+	A20_UNKNOWN = 0,
32
+	A20_INT15,
33
+	A20_KBC,
34
+	A20_SCPA,
35
+};
36
+
37
+#define A20_MAX_RETRIES		32
38
+#define A20_INT15_RETRIES	32
39
+#define A20_KBC_RETRIES		(2^21)
40
+#define A20_SCPA_RETRIES	(2^21)
41
+
32 42
 /**
33 43
  * Drain keyboard controller
34 44
  */
@@ -47,29 +57,32 @@ static void empty_8042 ( void ) {
47 57
 /**
48 58
  * Fast test to see if gate A20 is already set
49 59
  *
60
+ * @v retries		Number of times to retry before giving up
50 61
  * @ret set		Gate A20 is set
51 62
  */
52
-static int gateA20_is_set ( void ) {
63
+static int gateA20_is_set ( int retries ) {
53 64
 	static uint32_t test_pattern = 0xdeadbeef;
54 65
 	physaddr_t test_pattern_phys = virt_to_phys ( &test_pattern );
55 66
 	physaddr_t verify_pattern_phys = ( test_pattern_phys ^ 0x100000 );
56 67
 	userptr_t verify_pattern_user = phys_to_user ( verify_pattern_phys );
57 68
 	uint32_t verify_pattern;
58 69
 
59
-	/* Check for difference */
60
-	copy_from_user ( &verify_pattern, verify_pattern_user, 0,
61
-			 sizeof ( verify_pattern ) );
62
-	if ( verify_pattern != test_pattern )
63
-		return 1;
70
+	do {
71
+		/* Check for difference */
72
+		copy_from_user ( &verify_pattern, verify_pattern_user, 0,
73
+				 sizeof ( verify_pattern ) );
74
+		if ( verify_pattern != test_pattern )
75
+			return 1;
64 76
 
65
-	/* Invert pattern and retest, just to be sure */
66
-	test_pattern ^= 0xffffffff;
67
-	copy_from_user ( &verify_pattern, verify_pattern_user, 0,
68
-			 sizeof ( verify_pattern ) );
69
-	if ( verify_pattern != test_pattern )
70
-		return 1;
77
+		/* Avoid false negatives */
78
+		test_pattern++;
71 79
 
72
-	/* Pattern matched both times; gate A20 is not set */
80
+		SLOW_DOWN_IO;
81
+
82
+		/* Always retry at least once, to avoid false negatives */
83
+	} while ( retries-- >= 0 );
84
+
85
+	/* Pattern matched every time; gate A20 is not set */
73 86
 	return 0;
74 87
 }
75 88
 
@@ -83,6 +96,7 @@ static int gateA20_is_set ( void ) {
83 96
  */
84 97
 void gateA20_set ( void ) {
85 98
 	static char reentry_guard = 0;
99
+	static int a20_method = A20_UNKNOWN;
86 100
 	unsigned int discard_a;
87 101
 	unsigned int scp_a;
88 102
 	int retries = 0;
@@ -93,41 +107,51 @@ void gateA20_set ( void ) {
93 107
 	reentry_guard = 1;
94 108
 
95 109
 	/* Fast check to see if gate A20 is already enabled */
96
-	if ( gateA20_is_set() )
110
+	if ( gateA20_is_set ( 0 ) )
97 111
 		goto out;
98 112
 
99 113
 	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;
114
+		switch ( a20_method ) {
115
+		case A20_UNKNOWN:
116
+		case A20_INT15:
117
+			/* Try INT 15 method */
118
+			__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
119
+					       : "=a" ( discard_a )
120
+					       : "a" ( Enable_A20 ) );
121
+			if ( gateA20_is_set ( A20_INT15_RETRIES ) ) {
122
+				DBG ( "Enabled gate A20 using BIOS\n" );
123
+				a20_method = A20_INT15;
124
+				goto out;
125
+			}
126
+			/* fall through */
127
+		case A20_KBC:
128
+			/* Try keyboard controller method */
129
+			empty_8042();
130
+			outb ( KC_CMD_WOUT, K_CMD );
131
+			empty_8042();
132
+			outb ( KB_SET_A20, K_RDWR );
133
+			empty_8042();
134
+			if ( gateA20_is_set ( A20_KBC_RETRIES ) ) {
135
+				DBG ( "Enabled gate A20 using "
136
+				      "keyboard controller\n" );
137
+				a20_method = A20_KBC;
138
+				goto out;
139
+			}
140
+			/* fall through */
141
+		case A20_SCPA:
142
+			/* Try "Fast gate A20" method */
143
+			scp_a = inb ( SCP_A );
144
+			scp_a &= ~0x01; /* Avoid triggering a reset */
145
+			scp_a |= 0x02; /* Enable A20 */
146
+			SLOW_DOWN_IO;
147
+			outb ( scp_a, SCP_A );
148
+			SLOW_DOWN_IO;
149
+			if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
150
+				DBG ( "Enabled gate A20 using "
151
+				      "Fast Gate A20\n" );
152
+				a20_method = A20_SCPA;
153
+				goto out;
154
+			}
131 155
 		}
132 156
 	}
133 157
 

正在加载...
取消
保存