summaryrefslogtreecommitdiff
path: root/bootblocks/boot_fpy.s
blob: ef1f21a0cbf8e4b5e61b6ea17f756ebe63083d1e (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
! 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
!
! Warning: Disk errors currently cause a hang.
!          The boot sector does not end with $AA55 this is not a problem
!          with the BIOS but many boot managers will not boot it.

ORGADDR=0x0600
EXEADDR=0x06E0
LOADSEG=0x0080		! Must be 512b aligned for DMA		

.org EXEADDR-1
.byte 0xFF	! Marker

.org ORGADDR
entry start
public start
start:
  mov	ax,#$07C0	! Relocate to ORGADDR
  mov	ds,ax
  xor	ax,ax
  mov	es,ax
  mov	cx,#256
  mov	si,ax
  mov	di,#ORGADDR
  cld
  rep
  movsw
  jmpi	go,#0
go:
  mov	ds,ax		! Setup SP & S-regs
  mov	ss,ax
  mov	sp,#ORGADDR
  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: There are some versions of superformat that incorrectly 
  ! calculate the inter-sector gaps and end up squeezing the sectors 
  ! to the start of the track. This means that only a full track read
  ! is fast enough.

  			! 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:

  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:
  ! TODO Error.
  j	sect_error

maxsect:
  .word	0

! 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