Linux/boot/setup.S
1 !
2 ! setup.S Copyright (C) 1991, 1992 Linus Torvalds
3 !
4 ! setup.s is responsible for getting the system data from the BIOS,
5 ! and putting them into the appropriate places in system memory.
6 ! both setup.s and system has been loaded by the bootblock.
7 !
8 ! This code asks the bios for memory/disk/other parameters, and
9 ! puts them in a "safe" place: 0x90000-0x901FF, ie where the
10 ! boot-block used to be. It is then up to the protected mode
11 ! system to read them from there before the area is overwritten
12 ! for buffer-blocks.
13 !
14 ! Move PS/2 aux init code to psaux.c
15 ! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
16 !
17 ! some changes and additional features by Christoph Niemann, March 1993
18 ! (niemann@rubdv15.ETDV.Ruhr-Uni-Bochum.De)
19 !
20
21 ! NOTE! These had better be the same as in bootsect.s!
22 #include <linux/config.h>
23 #include <linux/segment.h>
24
25 #ifndef SVGA_MODE
26 #define SVGA_MODE ASK_VGA
27 #endif
28
29 INITSEG = DEF_INITSEG ! we move boot here - out of the way
30 SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
31 SETUPSEG = DEF_SETUPSEG ! this is the current segment
32
33 .globl begtext, begdata, begbss, endtext, enddata, endbss
34 .text
35 begtext:
36 .data
37 begdata:
38 .bss
39 begbss:
40 .text
41
42 entry start
43 start:
44
45 ! ok, the read went well so we get current cursor position and save it for
46 ! posterity.
47
48 mov ax,#INITSEG ! this is done in bootsect already, but...
49 mov ds,ax
50
51 ! Get memory size (extended mem, kB)
52
53 mov ah,#0x88
54 int 0x15
55 mov [2],ax
56
57 ! set the keyboard repeat rate to the max
58
59 mov ax,#0x0305
60 xor bx,bx ! clear bx
61 int 0x16
62
63 ! check for EGA/VGA and some config parameters
64
65 mov ah,#0x12
66 mov bl,#0x10
67 int 0x10
68 mov [8],ax
69 mov [10],bx
70 mov [12],cx
71 mov ax,#0x5019
72 cmp bl,#0x10
73 je novga
74 mov ax,#0x1a00 ! Added check for EGA/VGA discrimination
75 int 0x10
76 mov bx,ax
77 mov ax,#0x5019
78 cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower
79 jne novga
80 call chsvga
81 novga: mov [14],ax
82 mov ah,#0x03 ! read cursor pos
83 xor bh,bh ! clear bh
84 int 0x10 ! save it in known place, con_init fetches
85 mov [0],dx ! it from 0x90000.
86
87 ! Get video-card data:
88
89 mov ah,#0x0f
90 int 0x10
91 mov [4],bx ! bh = display page
92 mov [6],ax ! al = video mode, ah = window width
93
94 ! Get hd0 data
95
96 xor ax,ax ! clear ax
97 mov ds,ax
98 lds si,[4*0x41]
99 mov ax,#INITSEG
100 mov es,ax
101 mov di,#0x0080
102 mov cx,#0x10
103 cld
104 rep
105 movsb
106
107 ! Get hd1 data
108
109 xor ax,ax ! clear ax
110 mov ds,ax
111 lds si,[4*0x46]
112 mov ax,#INITSEG
113 mov es,ax
114 mov di,#0x0090
115 mov cx,#0x10
116 cld
117 rep
118 movsb
119
120 ! Check that there IS a hd1
121
122 mov ax,#0x01500
123 mov dl,#0x81
124 int 0x13
125 jc no_disk1
126 cmp ah,#3
127 je is_disk1
128 no_disk1:
129 mov ax,#INITSEG
130 mov es,ax
131 mov di,#0x0090
132 mov cx,#0x10
133 xor ax,ax ! clear ax
134 cld
135 rep
136 stosb
137 is_disk1:
138
139 ! check for PS/2 pointing device
140
141 mov ax,#INITSEG
142 mov ds,ax
143 mov [0x1ff],#0 ! default is no pointing device
144 int 0x11 ! int 0x11: equipment determination
145 test al,#0x04 ! check if pointing device installed
146 jz no_psmouse
147 mov [0x1ff],#0xaa ! device present
148 no_psmouse:
149 ! now we want to move to protected mode ...
150
151 cli ! no interrupts allowed !
152 mov al,#0x80 ! disable NMI for the bootup sequence
153 out #0x70,al
154
155 ! first we move the system to its rightful place
156
157 mov ax,#0x100 ! start of destination segment
158 mov bx,#0x1000 ! start of source segment
159 cld ! 'direction'=0, movs moves forward
160 do_move:
161 mov es,ax ! destination segment
162 add ax,#0x100
163 cmp ax,#0x9000
164 jz end_move
165 mov ds,bx ! source segment
166 add bx,#0x100
167 sub di,di
168 sub si,si
169 mov cx,#0x800
170 rep
171 movsw
172 jmp do_move
173
174 ! then we load the segment descriptors
175
176 end_move:
177 mov ax,#SETUPSEG ! right, forgot this at first. didn't work
178 mov ds,ax
179 lidt idt_48 ! load idt with 0,0
180 lgdt gdt_48 ! load gdt with whatever appropriate
181
182 ! that was painless, now we enable A20
183
184 call empty_8042
185 mov al,#0xD1 ! command write
186 out #0x64,al
187 call empty_8042
188 mov al,#0xDF ! A20 on
189 out #0x60,al
190 call empty_8042
191
192 ! make sure any possible coprocessor is properly reset..
193
194 xor ax,ax
195 out #0xf0,al
196 call delay
197 out #0xf1,al
198 call delay
199
200 ! well, that went ok, I hope. Now we have to reprogram the interrupts
201 ! we put them right after the intel-reserved hardware interrupts, at
202 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
203 ! messed this up with the original PC, and they haven't been able to
204 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
205 ! which is used for the internal hardware interrupts as well. We just
206 ! have to reprogram the 8259's, and it isn't fun.
207
208 mov al,#0x11 ! initialization sequence
209 out #0x20,al ! send it to 8259A-1
210 call delay
211 out #0xA0,al ! and to 8259A-2
212 call delay
213 mov al,#0x20 ! start of hardware int's (0x20)
214 out #0x21,al
215 call delay
216 mov al,#0x28 ! start of hardware int's 2 (0x28)
217 out #0xA1,al
218 call delay
219 mov al,#0x04 ! 8259-1 is master
220 out #0x21,al
221 call delay
222 mov al,#0x02 ! 8259-2 is slave
223 out #0xA1,al
224 call delay
225 mov al,#0x01 ! 8086 mode for both
226 out #0x21,al
227 call delay
228 out #0xA1,al
229 call delay
230 mov al,#0xFF ! mask off all interrupts for now
231 out #0xA1,al
232 call delay
233 mov al,#0xFB ! mask all irq's but irq2 which
234 out #0x21,al ! is cascaded
235
236 ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
237 ! need no steenking BIOS anyway (except for the initial loading :-).
238 ! The BIOS-routine wants lots of unnecessary data, and it's less
239 ! "interesting" anyway. This is how REAL programmers do it.
240 !
241 ! Well, now's the time to actually move into protected mode. To make
242 ! things as simple as possible, we do no register set-up or anything,
243 ! we let the gnu-compiled 32-bit programs do that. We just jump to
244 ! absolute address 0x00000, in 32-bit protected mode.
245 !
246 ! Note that the short jump isn't strictly needed, althought there are
247 ! reasons why it might be a good idea. It won't hurt in any case.
248 !
249 mov ax,#0x0001 ! protected mode (PE) bit
250 lmsw ax ! This is it!
251 jmp flush_instr
252 flush_instr:
253 jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs)
254
255 ! This routine checks that the keyboard command queue is empty
256 ! (after emptying the output buffers)
257 !
258 ! No timeout is used - if this hangs there is something wrong with
259 ! the machine, and we probably couldn't proceed anyway.
260 empty_8042:
261 call delay
262 in al,#0x64 ! 8042 status port
263 test al,#1 ! output buffer?
264 jz no_output
265 call delay
266 in al,#0x60 ! read it
267 jmp empty_8042
268 no_output:
269 test al,#2 ! is input buffer full?
270 jnz empty_8042 ! yes - loop
271 ret
272 !
273 ! Read a key and return the (US-)ascii code in al, scan code in ah
274 !
275 getkey:
276 xor ah,ah
277 int 0x16
278 ret
279
280 !
281 ! Read a key with a timeout of 30 seconds. The cmos clock is used to get
282 ! the time.
283 !
284 getkt:
285 call gettime
286 add al,#30 ! wait 30 seconds
287 cmp al,#60
288 jl lminute
289 sub al,#60
290 lminute:
291 mov cl,al
292 again: mov ah,#0x01
293 int 0x16
294 jnz getkey ! key pressed, so get it
295 call gettime
296 cmp al,cl
297 jne again
298 mov al,#0x20 ! timeout, return default char `space'
299 ret
300
301 !
302 ! Flush the keyboard buffer
303 !
304 flush: mov ah,#0x01
305 int 0x16
306 jz empty
307 xor ah,ah
308 int 0x16
309 jmp flush
310 empty: ret
311
312 !
313 ! Read the cmos clock. Return the seconds in al
314 !
315 gettime:
316 push cx
317 mov ah,#0x02
318 int 0x1a
319 mov al,dh ! dh contains the seconds
320 and al,#0x0f
321 mov ah,dh
322 mov cl,#0x04
323 shr ah,cl
324 aad
325