1 !
2 ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
3 ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
4 ! versions of linux
5 !
6 #include <linux/config.h>
7 SYSSIZE = DEF_SYSSIZE
8 !
9 ! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
10 ! modified by Drew Eckhardt
11 ! modified by Bruce Evans (bde)
12 !
13 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
14 ! itself out of the way to address 0x90000, and jumps there.
15 !
16 ! bde - should not jump blindly, there may be systems with only 512K low
17 ! memory. Use int 0x12 to get the top of memory, etc.
18 !
19 ! It then loads 'setup' directly after itself (0x90200), and the system
20 ! at 0x10000, using BIOS interrupts.
21 !
22 ! NOTE! currently system is at most 8*65536 bytes long. This should be no
23 ! problem, even in the future. I want to keep it simple. This 512 kB
24 ! kernel size should be enough, especially as this doesn't contain the
25 ! buffer cache as in minix
26 !
27 ! The loader has been made as simple as possible, and continuos
28 ! read errors will result in a unbreakable loop. Reboot by hand. It
29 ! loads pretty fast by getting whole tracks at a time whenever possible.
30
31 .text
32
33 SETUPSECS = 4 ! nr of setup-sectors
34 BOOTSEG = 0x07C0 ! original address of boot-sector
35 INITSEG = DEF_INITSEG ! we move boot here - out of the way
36 SETUPSEG = DEF_SETUPSEG ! setup starts here
37 SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
38
39 ! ROOT_DEV & SWAP_DEV are now written by "build".
40 ROOT_DEV = 0
41 SWAP_DEV = 0
42 #ifndefSVGA_MODE 43 #defineSVGA_MODE ASK_VGA
44 #endif 45 #ifndefRAMDISK 46 #defineRAMDISK 0
47 #endif 48
49 ! ld86 requires an entry symbol. This may as well be the usual one.
50 .globl _main
51 _main:
52 #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ 53 int 3
54 #endif 55 mov ax,#BOOTSEG
56 mov ds,ax
57 mov ax,#INITSEG
58 mov es,ax
59 mov cx,#256
60 sub si,si
61 sub di,di
62 cld
63 rep
64 movsw
65 jmpi go,INITSEG
66
67 go: mov ax,cs
68 mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of
69 ! bootsect + length of setup + room for stack
70 ! 12 is disk parm size
71
72 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
73 ! wouldn't have to worry about this if we checked the top of memory. Also
74 ! my BIOS can be configured to put the wini drive tables in high memory
75 ! instead of in the vector table. The old stack might have clobbered the
76 ! drive table.
77
78 mov ds,ax
79 mov es,ax
80 mov ss,ax ! put stack at INITSEG:0x4000-12.
81 mov sp,dx
82 /* 83 * Many BIOS's default disk parameter tables will not 84 * recognize multi-sector reads beyond the maximum sector number 85 * specified in the default diskette parameter tables - this may 86 * mean 7 sectors in some cases. 87 * 88 * Since single sector reads are slow and out of the question, 89 * we must take care of this by creating new parameter tables 90 * (for the first disk) in RAM. We will set the maximum sector 91 * count to 18 - the most we will encounter on an HD 1.44. 92 * 93 * High doesn't hurt. Low does. 94 * 95 * Segments are as follows: ds=es=ss=cs - INITSEG, 96 * fs = 0, gs = parameter table segment 97 */ 98
99 push #0
100 pop fs
101 mov bx,#0x78 ! fs:bx is parameter table address
102 seg fs
103 lgs si,(bx) ! gs:si is source
104
105 mov di,dx ! es:di is destination
106 mov cx,#6 ! copy 12 bytes
107 cld
108
109 rep
110 seg gs
111 movsw
112
113 mov di,dx
114 movb 4(di),*18 ! patch sector count
115
116 seg fs
117 mov (bx),di
118 seg fs
119 mov 2(bx),es
120
121 mov ax,cs
122 mov fs,ax
123 mov gs,ax
124
125 xor ah,ah ! reset FDC
126 xor dl,dl
127 int 0x13
128
129 ! load the setup-sectors directly after the bootblock.
130 ! Note that 'es' is already set up.
131
132 load_setup:
133 xor dx, dx ! drive 0, head 0
134 mov cx,#0x0002 ! sector 2, track 0
135 mov bx,#0x0200 ! address = 512, in INITSEG
136 mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors
137 ! (assume all on head 0, track 0)
138 int 0x13 ! read it
139 jnc ok_load_setup ! ok - continue
140
141 push ax ! dump error code
142 call print_nl
143 mov bp, sp
144 call print_hex
145 pop ax
146
147 xor dl, dl ! reset FDC
148 xor ah, ah
149 int 0x13
150 jmp load_setup
151
152 ok_load_setup:
153
154 ! Get disk drive parameters, specifically nr of sectors/track
155
156 #if 0
157
158 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
159 ! disks. It doesn't work for one of my BIOS's (1987 Award). It was
160 ! fatal not to check the error code.
161
162 xor dl,dl
163 mov ah,#0x08 ! AH=8 is get drive parameters
164 int 0x13
165 xor ch,ch
166 #else 167
168 ! It seems that there is no BIOS call to get the number of sectors. Guess
169 ! 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
170 ! Otherwise guess 9.
171
172 xor dx, dx ! drive 0, head 0
173 mov cx,#0x0012 ! sector 18, track 0
174 mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs)
175 mov ax,#0x0201 ! service 2, 1 sector
176 int 0x13
177 jnc got_sectors
178 mov cl,#0x0f ! sector 15
179 mov ax,#0x0201 ! service 2, 1 sector
180 int 0x13
181 jnc got_sectors
182 mov cl,#0x09
183
184 #endif 185
186 got_sectors:
187 seg cs
188 mov sectors,cx
189 mov ax,#INITSEG
190 mov es,ax
191
192 ! Print some inane message
193
194 mov ah,#0x03 ! read cursor pos
195 xor bh,bh
196 int 0x10
197
198 mov cx,#9
199 mov bx,#0x0007 ! page 0, attribute 7 (normal)
200 mov bp,#msg1
201 mov ax,#0x1301 ! write string, move cursor
202 int 0x10
203
204 ! ok, we've written the message, now
205 ! we want to load the system (at 0x10000)
206
207 mov ax,#SYSSEG
208 mov es,ax ! segment of 0x010000
209 call read_it
210 call kill_motor
211 call print_nl
212
213 ! After that we check which root-device to use. If the device is
214 ! defined (!= 0), nothing is done and the given device is used.
215 ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
216 ! on the number of sectors that the BIOS reports currently.
217
218 seg cs
219 mov ax,root_dev
220 or ax,ax
221 jne root_defined
222 seg cs
223 mov bx,sectors
224 mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
225 cmp bx,#15
226 je root_defined
227 mov ax,#0x021c ! /dev/PS0 - 1.44Mb
228 cmp bx,#18
229 je root_defined
230 mov ax,#0x0200 ! /dev/fd0 - autodetect
231 root_defined:
232 seg cs
233 mov root_dev,ax
234
235 ! after that (everyting loaded), we jump to
236 ! the setup-routine loaded directly after
237 ! the bootblock:
238
239 jmpi 0,SETUPSEG
240
241 ! This routine loads the system at address 0x10000, making sure
242 ! no 64kB boundaries are crossed. We try to load it as fast as
243 ! possible, loading whole tracks whenever we can.
244 !
245 ! in: es - starting address segment (normally 0x1000)
246 !
247 sread: .word 1+SETUPSECS ! sectors read of current track
248 head: .word 0 ! current head
249 track: .word 0 ! current track
250
251 read_it:
252 mov ax,es
253 test ax,#0x0fff
254 die: jne die ! es must be at 64kB boundary
255 xor bx,bx ! bx is starting address within segment
256 rp_read:
257 mov ax,es
258 sub ax,#SYSSEG
259 cmp ax,syssize ! have we loaded all yet?
260 jbe ok1_read
261 ret
262 ok1_read:
263 seg cs
264 mov ax,sectors
265 sub ax,sread
266 mov cx,ax
267 shl cx,#9
268 add cx,bx
269 jnc ok2_read
270 je ok2_read
271 xor ax,ax
272 sub ax,bx
273 shr ax,#9
274 ok2_read:
275 call read_track
276 mov cx,ax
277 add ax,sread
278 seg cs
279 cmp ax,sectors
280 jne ok3_read
281 mov ax,#1
282 sub ax,head
283 jne ok4_read
284 inc track
285 ok4_read:
286 mov head,ax
287 xor ax,ax
288 ok3_read:
289 mov sread,ax
290 shl cx,#9
291 add bx,cx
292 jnc rp_read
293 mov ax,es
294 add ah,#0x10
295 mov es,ax
296 xor bx,bx
297 jmp rp_read
298
299 read_track:
300 pusha
301 pusha
302 mov ax, #0xe2e ! loading... message 2e = .
303 mov bx, #7
304 int 0x10
305 popa
306
307 mov dx,track
308 mov cx,sread
309 inc cx
310 mov ch,dl
311 mov dx,head
312 mov dh,dl
313 and dx,#0x0100
314 mov ah,#2
315
316 push dx ! save for error dump
317 push cx
318 push bx
319 push ax
320
321 int 0x13
322 jc bad_rt
323 add sp, #8
324 popa
325 ret
326
327 bad_rt: push ax ! save error code
328 call print_all ! ah = error, al = read
329
330
331 xor ah,ah
332 xor dl,dl
333 int 0x13
334
335
336 add sp, #10
337 popa
338 jmp read_track
339
340 /* 341 * print_all is for debugging purposes. 342 * It will print out all of the registers. The assumption is that this is 343 * called from a routine, with a stack frame like 344 * dx 345 * cx 346 * bx 347 * ax 348 * error 349 * ret <- sp 350 * 351 */ 352
353 print_all:
354 mov cx, #5 ! error code + 4 registers
355 mov bp, sp
356
357 print_loop:
358 push cx ! save count left
359 call print_nl ! nl for readability
360
361 cmp cl, 5
362 jae no_reg ! see if register name is needed
363
364 mov ax, #0xe05 + 'A - 1
365 sub al, cl
366 int 0x10
367
368 mov al, #'X
369 int 0x10
370
371 mov al, #':
372 int 0x10
373
374 no_reg:
375 add bp, #2 ! next register
376 call print_hex ! print it
377 pop cx
378 loop print_loop
379 ret
380
381 print_nl:
382 mov ax, #0xe0d ! CR
383 int 0x10
384 mov al, #0xa ! LF
385 int 0x10
386 ret
387
388 /* 389 * print_hex is for debugging purposes, and prints the word 390 * pointed to by ss:bp in hexadecmial. 391 */ 392
393 print_hex:
394 mov cx, #4 ! 4 hex digits
395 mov dx, (bp) ! load word into dx
396 print_digit:
397 rol dx, #4 ! rotate so that lowest 4 bits are used
398 mov ah, #0xe
399 mov al, dl ! mask off so we have only next nibble
400 and al, #0xf
401 add al, #'0 ! convert to 0-based digit
402 cmp al, #'9 ! check for overflow
403 jbe good_digit
404 add al, #'A - '0 - 10
405
406 good_digit:
407 int 0x10
408 loop print_digit
409 ret
410
411
412 /* 413 * This procedure turns off the floppy drive motor, so 414 * that we enter the kernel in a known state, and 415 * don't have to worry about it later. 416 */ 417 kill_motor:
418 push dx
419 mov dx,#0x3f2
420 xor al, al
421 outb
422 pop dx
423 ret
424
425 sectors:
426 .word 0
427
428 msg1:
429 .byte 13,10
430 .ascii "Loading"
431
432 .org 500
433 syssize:
434 .word SYSSIZE
435 swap_dev:
436 .word SWAP_DEV
437 ram_size:
438 .word RAMDISK
439 vid_mode:
440 .word SVGA_MODE
441 root_dev:
442 .word ROOT_DEV
443 boot_flag:
444 .word 0xAA55