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