Browse Source

Use fast in-situ test for gate A20 being set, to cut down on the

number of (potentially very slow) gateA20_set operations.

Die with a fatal error if we are unable to set gate A20; if this fails
then we are bound to experience memory corruption at a later stage,
and I'd prefer to pick it up early.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
57b5e227ff
1 changed files with 55 additions and 19 deletions
  1. 55
    19
      src/arch/i386/firmware/pcbios/gateA20.c

+ 55
- 19
src/arch/i386/firmware/pcbios/gateA20.c View File

1
+#include <stdio.h>
1
 #include "realmode.h"
2
 #include "realmode.h"
2
 #include "timer.h"
3
 #include "timer.h"
3
 #include "latch.h"
4
 #include "latch.h"
41
 }
42
 }
42
 #endif	/* IBM_L40 */
43
 #endif	/* IBM_L40 */
43
 
44
 
45
+/**
46
+ * Fast test to see if gate A20 is already set
47
+ *
48
+ * @ret set		Gate A20 is set
49
+ */
50
+static int gateA20_is_set ( void ) {
51
+	static uint32_t test_pattern = 0xdeadbeef;
52
+	physaddr_t test_pattern_phys = virt_to_phys ( &test_pattern );
53
+	physaddr_t verify_pattern_phys = ( test_pattern_phys ^ 0x100000 );
54
+	userptr_t verify_pattern_user = phys_to_user ( verify_pattern_phys );
55
+	uint32_t verify_pattern;
56
+
57
+	/* Check for difference */
58
+	copy_from_user ( &verify_pattern, verify_pattern_user, 0,
59
+			 sizeof ( verify_pattern ) );
60
+	if ( verify_pattern != test_pattern )
61
+		return 1;
62
+
63
+	/* Invert pattern and retest, just to be sure */
64
+	test_pattern ^= 0xffffffff;
65
+	copy_from_user ( &verify_pattern, verify_pattern_user, 0,
66
+			 sizeof ( verify_pattern ) );
67
+	if ( verify_pattern != test_pattern )
68
+		return 1;
69
+
70
+	/* Pattern matched both times; gate A20 is not set */
71
+	return 0;
72
+}
73
+
44
 /*
74
 /*
45
  * Gate A20 for high memory
75
  * Gate A20 for high memory
46
  *
76
  *
52
 void gateA20_set ( void ) {
82
 void gateA20_set ( void ) {
53
 	static char reentry_guard = 0;
83
 	static char reentry_guard = 0;
54
 	unsigned int discard_a;
84
 	unsigned int discard_a;
55
-	unsigned int flags;
56
 
85
 
86
+	/* Avoid potential infinite recursion */
57
 	if ( reentry_guard )
87
 	if ( reentry_guard )
58
 		return;
88
 		return;
59
 	reentry_guard = 1;
89
 	reentry_guard = 1;
60
 
90
 
61
-	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
62
-					   "stc\n\t"
63
-					   "int $0x15\n\t"
64
-					   "pushfw\n\t"
65
-					   "popw %w0\n\t"
66
-					   "cli\n\t" )
67
-			       : "=r" ( flags ), "=a" ( discard_a )
68
-			       : "a" ( Enable_A20 ) );
69
-
91
+	/* Fast check to see if gate A20 is already enabled */
92
+	if ( gateA20_is_set() )
93
+		goto out;
70
 
94
 
71
-	if ( flags & CF ) {
72
-		/* INT 15 method failed, try alternatives */
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 */
73
 #ifdef	IBM_L40
103
 #ifdef	IBM_L40
74
-		outb(0x2, 0x92);
104
+	outb(0x2, 0x92);
75
 #else	/* IBM_L40 */
105
 #else	/* IBM_L40 */
76
-		empty_8042();
77
-		outb(KC_CMD_WOUT, K_CMD);
78
-		empty_8042();
79
-		outb(KB_SET_A20, K_RDWR);
80
-		empty_8042();
106
+	empty_8042();
107
+	outb(KC_CMD_WOUT, K_CMD);
108
+	empty_8042();
109
+	outb(KB_SET_A20, K_RDWR);
110
+	empty_8042();
81
 #endif	/* IBM_L40 */
111
 #endif	/* IBM_L40 */
82
-	}
112
+	if ( gateA20_is_set() )
113
+		goto out;
114
+
115
+	/* Better to die now than corrupt memory later */
116
+	printf ( "FATAL: Gate A20 stuck\n" );
117
+	while ( 1 ) {}
83
 
118
 
119
+ out:
84
 	reentry_guard = 0;
120
 	reentry_guard = 0;
85
 }
121
 }
86
 
122
 

Loading…
Cancel
Save