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