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