|
|
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: !
9: ! bootsect.s (C) 1991 Linus Torvalds
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
227: undef_root:
228: jmp undef_root
229: root_defined:
230: seg cs
231: mov root_dev,ax
232:
233: ! after that (everyting loaded), we jump to
234: ! the setup-routine loaded directly after
235: ! the bootblock:
236:
237: jmpi 0,SETUPSEG
238:
239: ! This routine loads the system at address 0x10000, making sure
240: ! no 64kB boundaries are crossed. We try to load it as fast as
241: ! possible, loading whole tracks whenever we can.
242: !
243: ! in: es - starting address segment (normally 0x1000)
244: !
1.1.1.3 ! root 245: sread: .word 1+SETUPSECS ! sectors read of current track
1.1 root 246: head: .word 0 ! current head
247: track: .word 0 ! current track
248:
249: read_it:
250: mov ax,es
251: test ax,#0x0fff
252: die: jne die ! es must be at 64kB boundary
253: xor bx,bx ! bx is starting address within segment
254: rp_read:
255: mov ax,es
256: cmp ax,#ENDSEG ! have we loaded all yet?
257: jb ok1_read
258: ret
259: ok1_read:
260: seg cs
261: mov ax,sectors
262: sub ax,sread
263: mov cx,ax
264: shl cx,#9
265: add cx,bx
266: jnc ok2_read
267: je ok2_read
268: xor ax,ax
269: sub ax,bx
270: shr ax,#9
271: ok2_read:
272: call read_track
273: mov cx,ax
274: add ax,sread
275: seg cs
276: cmp ax,sectors
277: jne ok3_read
278: mov ax,#1
279: sub ax,head
280: jne ok4_read
281: inc track
282: ok4_read:
283: mov head,ax
284: xor ax,ax
285: ok3_read:
286: mov sread,ax
287: shl cx,#9
288: add bx,cx
289: jnc rp_read
290: mov ax,es
291: add ah,#0x10
292: mov es,ax
293: xor bx,bx
294: jmp rp_read
295:
296: read_track:
297: pusha
298: pusha
299: mov ax, #0xe2e ! loading... message 2e = .
300: mov bx, #7
301: int 0x10
302: popa
303:
1.1.1.3 ! root 304: mov dx,track
! 305: mov cx,sread
! 306: inc cx
! 307: mov ch,dl
! 308: mov dx,head
! 309: mov dh,dl
! 310: and dx,#0x0100
! 311: mov ah,#2
1.1 root 312:
313: push dx ! save for error dump
314: push cx
315: push bx
316: push ax
317:
1.1.1.3 ! root 318: int 0x13
! 319: jc bad_rt
! 320: add sp, #8
1.1 root 321: popa
322: ret
323:
324: bad_rt: push ax ! save error code
325: call print_all ! ah = error, al = read
326:
327:
328: xor ah,ah
329: xor dl,dl
330: int 0x13
331:
332:
333: add sp, #10
334: popa
335: jmp read_track
336:
337: /*
338: * print_all is for debugging purposes.
339: * It will print out all of the registers. The assumption is that this is
340: * called from a routine, with a stack frame like
341: * dx
342: * cx
343: * bx
344: * ax
345: * error
346: * ret <- sp
347: *
348: */
349:
350: print_all:
351: mov cx, #5 ! error code + 4 registers
352: mov bp, sp
353:
354: print_loop:
355: push cx ! save count left
356: call print_nl ! nl for readability
1.1.1.3 ! root 357:
! 358: cmp cl, 5
1.1 root 359: jae no_reg ! see if register name is needed
360:
1.1.1.3 ! root 361: mov ax, #0xe05 + 'A - 1
1.1 root 362: sub al, cl
363: int 0x10
364:
1.1.1.3 ! root 365: mov al, #'X
1.1 root 366: int 0x10
367:
1.1.1.3 ! root 368: mov al, #':
1.1 root 369: int 0x10
370:
371: no_reg:
372: add bp, #2 ! next register
373: call print_hex ! print it
374: pop cx
375: loop print_loop
376: ret
377:
378: print_nl:
379: mov ax, #0xe0d ! CR
380: int 0x10
381: mov al, #0xa ! LF
382: int 0x10
383: ret
384:
385: /*
386: * print_hex is for debugging purposes, and prints the word
387: * pointed to by ss:bp in hexadecmial.
388: */
389:
390: print_hex:
391: mov cx, #4 ! 4 hex digits
392: mov dx, (bp) ! load word into dx
393: print_digit:
394: rol dx, #4 ! rotate so that lowest 4 bits are used
395: mov ah, #0xe
396: mov al, dl ! mask off so we have only next nibble
397: and al, #0xf
1.1.1.3 ! root 398: add al, #'0 ! convert to 0-based digit
! 399: cmp al, #'9 ! check for overflow
1.1 root 400: jbe good_digit
1.1.1.3 ! root 401: add al, #'A - '0 - 10
1.1 root 402:
403: good_digit:
404: int 0x10
405: loop print_digit
406: ret
407:
408:
409: /*
410: * This procedure turns off the floppy drive motor, so
411: * that we enter the kernel in a known state, and
412: * don't have to worry about it later.
413: */
414: kill_motor:
415: push dx
416: mov dx,#0x3f2
417: xor al, al
418: outb
419: pop dx
420: ret
421:
422: sectors:
423: .word 0
424:
425: msg1:
426: .byte 13,10
427: .ascii "Loading"
428:
429: .org 506
430: swap_dev:
431: .word SWAP_DEV
432: root_dev:
433: .word ROOT_DEV
434: boot_flag:
435: .word 0xAA55
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.