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