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