1!---------------------------------------------------------------------------
2!! This is a bootblock to load an execute a standalone program from an
3!! MSDOS filesystem on a floppy disk.
4!!
5!! The file loaded is called 'BOOTFILE.SYS' and is loaded at address $7C00.
6!---------------------------------------------------------------------------
7! The filename can be changed at install time by following the label
8! boot_name, because the file is loaded at address $7C00 it can be the
9! image of a boot block (eg LILO). It's also checked for the magic number
10! associated with a Linux-8086 standalone executable and this is used if
11! it's found.
12!
13! There are a number of assumptions made by the code concerning the layout
14! of the msdos files system:
15!
16! 1) All of the first 12 bit FAT must be on the first track.
17! 2) The FAT must be 12 bit or 16 bit. (known at install time)
18! 3) The value of the hidden sectors field must be zero
19!
20! All these are true for mtools created floppies on normal PC drives.
21!
22! In addition this now has a compile time option for FAT16 partitions.
23! TODO: Auto detect disk type
24!       FAT32
25!
26!---------------------------------------------------------------------------
27ORGADDR=$0500
28
29use16
30
31! Some configuration values
32LOADSEG=	$7C0
33export fatbits
34fatbits=12		! Set to 12 or 16 (16 for LS-120 disks)
35
36export heads
37heads=0			! This can be 0,1 or 2. 0 is dynamic.
38
39export harddisk
40 if fatbits=12
41harddisk=0
42 else
43harddisk=1		! Allow for hard disks, but will only work with
44 endif			! disks formatted >= MSDOS 4.0
45
46!---------------------------------------------------------------------------
47! Absolute position macro, fails if code before it is too big.
48macro locn
49  if *-start>?1
50   fail! *-start>?1
51  endif
52  .blkb	?1 + start-*
53mend
54
55org ORGADDR
56start:
57include sysboot16.s
58
59org dos_sysid
60   .ascii "DOSFS"	! System ID
61
62!---------------------------------------------------------------------------
63! Data into the temp area, 30 clear bytes
64org floppy_temp
65root_count:	.blkw	1
66
67!---------------------------------------------------------------------------
68  locn(codestart-start)
69
70  cld			! Assume _nothing_!
71  mov	bx,#$7C00	! Pointer to start of BB.
72  xor	ax,ax		! Segs all to zero
73  mov	ds,ax
74  mov	es,ax
75  mov	ss,ax
76  mov	sp,bx		! SP Just below BB
77  mov	cx,#$100	! Move 256 words
78  mov	si,bx		! From default BB
79  mov	di,#ORGADDR	! To the correct address.
80  rep
81   movsw
82  jmpi	cont,#0		! Set CS:IP correct.
83cont:
84  sti			! Let the interrupts back in.
85
86! DONT Need to fix BPB for fd0 to correct sectors (Like linux bootblock does)
87! as we only ever read one sector at a time.
88
89! For each sector in root dir
90! For each dir entry
91! If entry name is == boot_name
92! then load and run
93
94  ! First dir = dos_fatlen*dos_nfat+dos_resv
95  mov	ax,[dos_fatlen]
96  mov	dl,[dos_nfat]
97  xor	dh,dh
98  mul	dx
99  add	ax,[dos_resv]
100  mov	di,ax
101  ! DI is sector number of first root dir sector.
102
103  mov	ax,[dos_nroot]
104  mov	[root_count],ax
105  add	ax,#15
106  mov	cl,#4
107  shr	ax,cl
108  add	ax,di
109  mov	bp,ax		! bp is first data sector.
110
111nextsect:
112  call	linsect
113  mov	ax,#$0201
114  int	$13
115  jc	floppy_error
116
117! ... foreach dir entry
118  mov	si,bx
119nextentry:
120
121  ! TODO: Test attributes for !dir !label here ?
122
123! test entry name
124  push	si
125  push	di
126  mov	di,#boot_name
127  mov	cx,#11
128  rep
129   cmpsb
130  pop	di
131  pop	si
132  jne	bad_entry
133
134  mov	ax,[si+26]	! Cluster number of start of file
135  test	ax,ax		! Make sure we have a block.
136  jnz	load_system
137
138bad_entry:
139  add	si,#32		! skip to next entry
140  cmp	si,#512
141  jnz	nextentry
142
143  inc	di		! Load next sector
144  sub	[root_count],#16
145  jp	nextsect
146  jmp	no_system
147
148!---------------------------------------------------------------------------
149! Convert a cluster number in DI into a CHS in CX:DX
150linclust:
151  mov	ax,di
152  sub	ax,#2
153  mov	dl,[dos_clust]
154  xor	dh,dh
155  mul	dx
156  add	ax,bp		! Add sector number of first data sector.
157  adc   dx,#0
158  jmp	linsect2
159
160!
161! This function converts a linear sector number in DI
162! into a CHS representation in CX:DX
163!
164linsect:
165  mov	ax,di
166linsect1:
167  xor	dx,dx
168linsect2:
169  ! Add partition offset in.
170 if fatbits =16
171  add   ax,[dos_hidden]
172  adc   dx,[dos_hidden+2]
173 endif
174
175  div	[dos_spt]
176  inc	dx
177  mov	cl,dl		! Sector num
178  xor	dx,dx		! Drive 0
179 if heads =2
180  shr	ax,#1		! Assume dos_heads == 2
181  adc	dh,#0		! Head num
182 endif
183 if heads =0
184  div	[dos_heads]
185  xchg	dh,dl
186 endif
187  mov	ch,al		! Cylinder bits 0-7
188 if heads =0
189  sar   ax,#1		! Cylinder bits 8&9
190  sar   ax,#1
191  and   al,#$C0
192  or    cl,al
193 endif
194 if harddisk
195  mov	dl,[dos4_phy_drive]
196 endif
197  ret
198
199!---------------------------------------------------------------------------
200! Error processing.
201no_system:
202floppy_error:
203
204  mov	si,#error_msg
205no_boot:		! SI now has pointer to error message
206  lodsb
207  cmp	al,#0
208  jz	EOS
209  mov	bx,#7
210  mov	ah,#$E		! Can't use $13 cause that's AT+ only!
211  int	$10
212  jmp	no_boot
213EOS:
214  xor	ax,ax
215  int	$16
216  jmpi	$0,$FFFF	! Reboot.
217
218!---------------------------------------------------------------------------
219! This loads the boot program 1 sector at a time, funny thing is it actually
220! loads at exactly the same speed as loading a track at a time, at least on
221! my slow old 286/8Mhz. Oh well, we need the space so if you're worried just
222! tell superformat to give you an interleave of 2 (-i 2).
223!
224
225load_system:
226 if fatbits =12
227  push	ax		! Save cluster we're loading
228
229! 1) Load FAT
230  ! This assumes all of FAT1 is on the first track, this is normal
231  mov	ax,[dos_fatlen]
232  mov	ah,#2
233  mov	bx,#fat_table
234  mov	cx,[dos_resv]	! Fat starts past bootblock
235  inc	cx
236  xor	dx,dx		! Head zero
237  int	$13
238  jc	floppy_error
239  pop	di		! Cluster to start load.
240 else
241  mov	di,ax
242 endif
243
244  mov	ax,#LOADSEG
245  mov	es,ax
246
247  ! load whole cluster
248next_cluster:
249
250  mov	si,[dos_clust]	! How big is a cluster
251  and	si,#255
252  call	linclust	! Find it's physical address
253
254next:
255  mov	ax,#$0201
256  xor	bx,bx
257  int	$13		! Load 1 sector at a time
258  jc	floppy_error
259
260  mov	ax,es
261  add	ax,#512/16
262  mov	es,ax
263
264  cmp	cl,[dos_spt]	! Does cluster straddle tracks ?
265  jnz	sectok
266  mov	cl,#0
267 if heads=2
268  inc	dh
269  cmp	dh,#2		! Does cluster straddle cylinders ?
270  jnz	sectok
271  xor	dh,dh
272 endif
273 if heads=0
274  inc	dh
275  cmp	dh,[dos_heads]	! Nb low byte only.
276  jnz	sectok
277  xor	dh,dh
278 endif
279  inc	ch
280sectok:
281  inc	cl
282  dec	si
283  jnz	next
284
285  call	next_fat
286  jc	next_cluster
287  jmp	maincode
288
289next_fat:
290 if fatbits =12
291  mov	ax,di
292  shr	ax,#1
293  pushf			! Save if odd number
294  add	di,ax
295  mov	di,fat_table[di]
296  popf
297  jnc	noshift		! Odd in high nibbles.
298  mov	cl,#4
299  shr	di,cl
300noshift:
301  and	di,#$FFF
302  cmp	di,#$FF0	! FFF is EOF, clear carry flag.
303  			! FF0+ are badblocks etc.
304 endif
305
306 if fatbits =16
307  mov	ax,di
308  ! load fat sector AH (if it's not already loaded)
309
310  xchg	ah,al
311  xor	ah,ah
312  add	ax,[dos_resv]
313
314  cmp	ax,[fatsect]
315  jz	got_fsect
316  mov	[fatsect],ax
317
318  call	linsect1
319
320  push	es
321  mov	bx,#fat_table
322  xor	ax,ax
323  mov	es,ax
324  mov	ax,#$0201
325  int	$13
326  pop	es
327  jnc	got_fsect
328  br	floppy_error
329
330got_fsect:
331  ! Load di with cluster number in di
332  and	di,#$FF
333  shl	di,#1
334  mov	di,fat_table[di]
335  cmp	di,#$FFF0
336 endif
337
338  ret
339
340!---------------------------------------------------------------------------
341! File is now loaded, execute it.
342maincode:
343  mov	bx,#7
344  mov	ax,#$0E + ':
345  int	$10		! Marker printed to say bootblock succeeded.
346
347  xor	dx,dx		! DX=0 => floppy drive
348 if harddisk
349  mov	dl,[dos4_phy_drive]
350 endif
351  push	dx		! CX=0 => partition offset = 0
352  mov	si,[dos_spt]	! SI=Sectors per track
353
354  mov	bx,#LOADSEG
355  mov	ds,bx		! DS = loadaddress
356  xor	di,di		! Zero
357  mov	ax,[di]
358  cmp	ax,#0x0301	! Right magic ?
359  jnz	bad_magic	! Yuk ...
360  mov	ax,[di+2]
361  and	ax,#$20		! Is it split I/D ?
362  jz	impure		! No ...
363  mov	cl,#4
364  mov	ax,[di+8]
365  shr	ax,cl
366impure:
367  pop	cx		! Partition offset.
368  inc	bx
369  inc	bx		! bx = initial CS
370  add	ax,bx
371  mov	ss,ax
372  mov	sp,[di+24]	! Chmem value
373  mov	ds,ax
374
375  ! AX=ds, BX=cs, CX=X, DX=X, SI=X, DI=0, BP=X, ES=X, DS=*, SS=*, CS=*
376
377bad_magic:
378  push	bx		! jmpi	0,#LOADSEG+2
379  push	di
380  retf
381
382!---------------------------------------------------------------------------
383! initilised data
384
385fatsect:
386  .word	0
387
388error_msg:
389  .asciz "\r\nError during initial boot\r\nPress a key:"
390
391export boot_name
392boot_name:
393 .ascii "BOOTFILESYS"
394name_end:
395!        NNNNNNNNEEE
396
397locn(510)
398  .word $AA55	! This is a floppy so it should not need the magic _but_
399  		! the debian MBR requires the magic even on floppies
400
401fat_table:	! This is the location that the fat table is loaded.
402		! Note: The fat must be entirely on track zero if 12 bit.
403!---------------------------------------------------------------------------
404