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