man: --nbi, not --NBI
[wraplinux.git] / reloc / a20.S
1 /* -----------------------------------------------------------------------
2  *
3  *   Copyright 2008 rPath, Inc. - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * ----------------------------------------------------------------------- */
27
28 /*
29  * Code to enable A20.  Based on code in SYSLINUX.
30  */
31         .code16
32         .section ".text16","ax"
33
34         .type   enable_a20, @function
35         .globl  enable_a20
36 enable_a20:
37         pushal
38
39         /* Are we enabled already? */
40         call    a20_test
41         jnz     1f
42
43         /* Try the BIOS */
44 3:
45         movw    $0x2401, %ax
46         pushfl
47         int     $0x15
48         popfl
49         call    a20_test
50         jnz     1f
51
52         /* Try the keyboard controller */
53         movb    $1, %cl
54         call    empty_8042
55         jnz     1f              /* A20 live, no need for KBC */
56
57         xorw    %cx, %cx
58         movb    $0xd1, %al      /* Command write */
59         outb    %al, $0x64
60         call    empty_8042
61
62         movb    $0xdf, %al      /* Enable A20 */
63         outb    %al, $0x60
64         call    empty_8042
65
66         movb    $0xff, %al      /* Null command, required by UHCI spec */
67         outb    %al, $0x64
68         call    empty_8042
69
70         /* Loop until A20 is enabled, or for 2^16 loops */
71         /* %cx == 0 */
72 2:      call    a20_test
73         jnz     1f
74         loop    2b
75
76         /* Urk.  Try the "fast A20 gate" (config port A) */
77         inb     $0x92, %al
78         orb     $0x02, %al      /* Enable A20 */
79         andb    $0xfe, %al      /* Do not reset */
80         outb    %al, $0x92
81
82         /* Loop until A20 is enabled, or for 2^16 loops */
83         /* %cx == 0 */
84 2:      call    a20_test
85         jnz     1f
86         loop    2b
87
88         /* If we get here, we're in trouble.  Try again;
89            loop forever if need be. */
90         jmp     3b
91
92 1:
93         popal
94         ret
95         .size   enable_a20, .-enable_a20
96
97 /*
98  * Test to see if A20 already is enabled.
99  */
100         .type   a20_test, @function
101 a20_test:
102         pushw   %cx
103         pushw   %ax
104         pushw   %fs
105         pushw   %gs
106
107         xorw    %cx, %cx
108         movw    %cx, %fs
109         decw    %cx
110         movw    %cx, %gs
111
112         movw    $32, %cx        /* Loop count */
113         movw    %fs:0,%ax       /* Divide by zero vector, hope it's safe */
114         pushw   %ax
115 1:
116         incw    %ax
117         movw    %ax, %fs:0
118         call    io_delay
119         cmpw    %gs:0x10, %ax
120         loope   1b
121         popw    %fs:0           /* Restore previous value */
122         popw    %gs
123         popw    %fs
124         popw    %ax
125         popw    %cx
126         ret
127         .size   a20_test, .-a20_test
128
129
130 /*
131  * Routine to empty the 8042 KBC controller.  If %cx != 0 then we will
132  * test A20 in the loop and exit if A20 becomes enabled.
133  */
134         .type   empty_8042, @function
135 empty_8042:
136 4:
137         call    a20_test
138         jcxz    1f              /* If %cx == 0 continue regardless */
139         jnz     2f
140 1:
141         call    io_delay
142         inb     $0x64, %al      /* Status port */
143         testb   $0x01, %al
144         jz      3f              /* No input */
145         call    io_delay
146         inb     $0x60, %al      /* Read input */
147         jmp     4b
148 3:
149         testb   $0x02, %al
150         jnz     4b
151         call    io_delay
152 2:
153         ret
154         .size   empty_8042, .-empty_8042
155
156 /*
157  * I/O delay function
158  */
159 #define DELAY_PORT      0x80
160
161         .type   io_delay, @function
162 io_delay:
163         pushw   %ax
164         xorw    %ax, %ax
165         outb    %al, $DELAY_PORT
166         outb    %al, $DELAY_PORT
167         popw    %ax
168         ret
169         .size   io_delay, .-io_delay