summaryrefslogtreecommitdiff
path: root/bootblocks/boot_fpy.s
blob: ced54c7795db768bec6678d1d333cddcaf5c360b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
! This binary is for loading a dev86 a.out file from a floppy without
! a filesystem; to make a bootable disk just do:
!
!  cat boot_fpy.bin monitor.out > /dev/fd0
!

ORGADDR=0x0600
EXEADDR=0x0800		! This must be up to 0x7E0 or 0x0800
LOADSEG=0x0080		! Must be 512b aligned for DMA		

! Padding so you can join with 'cat'.
.org EXEADDR-1
.byte 0

! This marker is needed by many boot managers (and bochs) but the BIOS does
! NOT require it on a floppy.
if EXEADDR=0x0800
.org ORGADDR+0x1FE
.word 0xAA55
endif

.org ORGADDR
entry start
public start
start:
  xor	ax,ax
  mov	si,#$7C00
  mov	di,#ORGADDR

  mov	ss,ax
  mov	sp,di		! Or si or ax

  push	ax
  pop	ds
  push	ax
  pop	es

  mov	cx,#256
  cld
  rep
   movsw
  jmpi	go,#0
go:

! Grrr, have to load sector 1 in by hand.
if EXEADDR=0x0800
Loopi:
  mov	ax,#$0201	! Read 1 sector
  mov	bx,#EXEADDR	! Into EXEADDR
  mov	cx,#$0002	! From sector 2
  xor	dx,dx		! Of the floppy drive head zero
  int	$13
  jc	Loopi
endif

  mov	si,#Boot_message
  call	puts

  mov	ax,[a_text]	! How many sectors to load
  mov	cl,#4
  shr	ax,cl
  mov	bx,ax
  mov	ax,[a_data]
  mov	cl,#4
  shr	ax,cl
  add	ax,bx
  add	ax,#$1F
  mov	cl,#5
  shr	ax,cl		! ax = sectors to read

  ! This routine starts by loading one sector at a time, with most
  ! modern PCs the processor is fast enough to keep up with single
  ! sector reads, in reality an 8Mhz 286 can keep up!
  ! But occasionally some older machines have really poor BIOSes
  ! (Some modern ones too) so once we know how many sectors to read
  ! we switch to reading a track at a time. But we only try it once
  ! for each track. Normally, as long as the load address is sector
  ! aligned, this will work every time but with some BIOSes we can't
  ! read a track without messing with the BPB so if the track read
  ! fails it's one try we fall back to sector reads.
  !
  ! Overall this usually gives good performance, and with a BIOS that
  ! isn't completely broken and correctly formatted floppies will run
  ! at about 2.5 rotations per cylinder (1.25 per track). If you find
  ! your BIOS is one of the bad ones you'll have to format your disks
  ! to a 2:1 interleave.
  !
  ! BTW: It's very easy to make superformat incorrectly calculate the 
  ! inter-sector gaps so it ends up squeezing the sectors to the start 
  ! of the track. This means that only a full track read is fast enough.
  ! I suggest you use fdformat as it always uses 'safe' parameters for 
  ! a 1440k floppy.

  			! AX = count of sectors
  mov	cx,#2		! CX = First sector
  mov	bx,#LOADSEG	! ES:BX = Where to load
  mov	es,bx
  xor	bx,bx		! Initial offset

  xor	dx,dx		! DX = Drive 0

  ! ax=cnt, dl=drv, ch=*, dh=*, cl=sec, es:bx=buffer.

read_data:
  mov	si,ax		! Save big count.
  xor	ch,ch	
  xor	dh,dh

  mov	maxsect,cl	! Save first sector.

load_loop:
  mov	di,#5		! Error retry.

sect_retry:
  mov	ax,#$0201
  ! ah=2, al=1, dl=drv, ch=cyl, dh=head, cl=sec, es:bx=buffer.
  int	$13
  jnc	next_sect

  dec	di		! Retry counter
  jz	sect_error

  cmp	cl,maxsect	! If this is first sector or previously ok sector
  jle	sect_retry	! number then retry.

  mov	maxsect,cl
  j	inc_trk

next_sect:
  mov	ax,es		! Inc load address.
  add	ax,#32
  mov	es,ax

  dec	si		! Had enough ?
  jz	all_loaded

inc_sect:
  inc	cl
  cmp	cl,maxsect
  jnz	load_loop
inc_trk:		! Reached end of track, seek to next.
  mov	cl,#1
  xor	dh,cl
  jnz	load_track
  inc	ch
load_track:
  cmp	si,maxsect	! Is the whole track needed ?
  jb	load_loop	! no, goto load_loop for 1 by 1
  
  ! Try to load the track _once_ only, if it fails go 1 by 1 again.

  mov	ax,maxsect
  dec	ax
  mov	ah,#$02
  ! ah=2, al=*, dl=drv, ch=cyl, dh=head, cl=sec, es:bx=buffer.
  int	$13
  jc	load_loop

  mov	ax,maxsect	! Ok that worked, update the pointers
  dec	ax
  mov	cl,#5
  shl	ax,cl
  mov	di,es
  add	ax,di
  mov	es,ax

  inc	si
  sub	si,maxsect
  jnz	inc_trk

all_loaded:
  ! Now it's loaded turn off the floppy motor.
  mov dx,#0x3f2
  xor al, al
  outb

  ! And start up the program.

  xor	dx,dx		! DX=0 => floppy drive
  push	dx		! CX=0 => partition offset = 0
  mov	si,dx		! Sect/track = 0

  mov	bx,#EXEADDR>>4
  mov	ds,bx		! DS = loadaddress
  xor	di,di		! Zero
  mov	ax,[di+2]
  and	ax,#$20		! Is it split I/D ?
  jz	impure		! No ...
  mov	cl,#4
  mov	ax,[di+8]
  shr	ax,cl
impure:
  pop	cx		! Partition offset.
  inc	bx
  inc	bx		! bx = initial CS
  add	ax,bx
  mov	ss,ax
  mov	sp,[di+24]	! Chmem value
  mov	ds,ax

  ! AX=ds, BX=cs, CX=X, DX=X, SI=X, DI=0, BP=X, ES=X, DS=*, SS=*, CS=*

bad_magic:
  push	bx		! jmpi	0,#LOADSEG+2
  push	di
  retf

sect_error:
  ! Disk error, wait then reboot.

  mov	si,#reboot_msg
  call	puts

  xor   ax,ax		! Wait for the user.
  int   $16
  jmpi  $0,$FFFF

puts:
  lodsb
  cmp   al,#0
  jz    EOS
  push  bx
  mov   bx,#7
  mov   ah,#$E                  ! Can't use $13 cause that's AT+ only!
  int   $10
  pop   bx
  jmp   puts
EOS:
  ret

maxsect:
  .word	0

reboot_msg:
  .asciz	"Disk error, press a key to reboot:"

Boot_message:
  .asciz	"Boot sector loaded.\r\n"

! Check for overlap
end_of_code:
  if end_of_code>hitme
     fail! Overlap at end_of_code
  endif

.org EXEADDR
hitme:

magic:		.space 2	! A.out header
btype:		.space 2
headerlen:	.space 4
a_text:		.space 4
a_data:		.space 4
a_bss:		.space 4
a_entry:	.space 4
a_total:	.space 4
a_syms:		.space 4