Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * FAT Partition Boot Sector. Loaded at 0x7C00:
3
 *	8a pbslba.s; 8l -o pbslba -l -H3 -T0x7C00 pbslba.8
4
 * Will load the target at LOADSEG*16+LOADOFF, so the target
5
 * should be probably be loaded with LOADOFF added to the
6
 * -Taddress.
7
 * If LOADSEG is a multiple of 64KB and LOADOFF is 0 then
8
 * targets larger than 64KB can be loaded.
9
 *
10
 * This code is uses Enhanced BIOS Services for Disc Drives and
11
 * can be used with discs up to 137GB in capacity.
12
 *
13
 * It relies on the _volid field in the FAT header containing
14
 * the LBA of the root directory.
15
 */
16
#include "x16.h"
17
 
18
#define LOADSEG		(0x10000/16)	/* where to load code (64KB) */
19
#define LOADOFF		0
20
#define DIROFF		0x0200		/* where to read the root directory */
21
 
22
/*
23
 * FAT directory entry.
24
 */
25
#define Dname		0x00
26
#define Dnamesz	0x0B
27
#define Dext		0x08
28
#define Dattr		0x0B
29
#define Dtime		0x16
30
#define Ddate		0x18
31
#define Dstart		0x1A
32
#define Dlengthlo	0x1C
33
#define Dlengthhi	0x1E
34
 
35
#define Dirsz		0x20
36
 
37
/*
38
 * Data is kept on the stack, indexed by rBP.
39
 */
40
#define Xdap		0x00		/* disc address packet */
41
#define Xrootsz		0x10		/* file data area */
42
#define Xdrive		0x12		/* boot drive, passed by BIOS or MBR */
43
#define Xtotal		0x14		/* sum of allocated data above */
44
 
45
TEXT _magic(SB), $0
46
	BYTE $0xEB; BYTE $0x3C;		/* jmp .+ 0x3C  (_start0x3E) */
47
	BYTE $0x90			/* nop */
48
TEXT _version(SB), $0
49
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
50
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
51
TEXT _sectsize(SB), $0
52
	BYTE $0x00; BYTE $0x00
53
TEXT _clustsize(SB), $0
54
	BYTE $0x00
55
TEXT _nresrv(SB), $0
56
	BYTE $0x00; BYTE $0x00
57
TEXT _nfats(SB), $0
58
	BYTE $0x00
59
TEXT _rootsize(SB), $0
60
	BYTE $0x00; BYTE $0x00
61
TEXT _volsize(SB), $0
62
	BYTE $0x00; BYTE $0x00
63
TEXT _mediadesc(SB), $0
64
	BYTE $0x00
65
TEXT _fatsize(SB), $0
66
	BYTE $0x00; BYTE $0x00
67
TEXT _trksize(SB), $0
68
	BYTE $0x00; BYTE $0x00
69
TEXT _nheads(SB), $0
70
	BYTE $0x00; BYTE $0x00
71
TEXT _nhiddenlo(SB), $0
72
	BYTE $0x00; BYTE $0x00
73
TEXT _nhiddenhi(SB), $0
74
	BYTE $0x00; BYTE $0x00;
75
TEXT _bigvolsize(SB), $0
76
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
77
TEXT _driveno(SB), $0
78
	BYTE $0x00
79
TEXT _reserved0(SB), $0
80
	BYTE $0x00
81
TEXT _bootsig(SB), $0
82
	BYTE $0x00
83
TEXT _volid(SB), $0
84
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
85
TEXT _label(SB), $0
86
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
87
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
88
	BYTE $0x00; BYTE $0x00; BYTE $0x00
89
TEXT _type(SB), $0
90
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
91
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
92
 
93
_start0x3E:
94
	CLI
95
	CLR(rAX)
96
	MTSR(rAX, rSS)			/* 0000 -> rSS */
97
	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
98
	MTSR(rAX, rES)
99
	LWI(_magic-Xtotal(SB), rSP)
100
	MW(rSP, rBP)			/* set the indexed-data pointer */
101
 
102
	SBPB(rDL, Xdrive)		/* save the boot drive */
103
 
104
	/* booting from a CD starts us at 7C0:0.  Move to 0:7C00 */
105
	PUSHR(rAX)
106
	LWI(_nxt(SB), rAX)
107
	PUSHR(rAX)
108
	BYTE $0xCB	/* FAR RET */
109
 
110
TEXT _nxt(SB), $0
111
	STI
112
 
113
	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
114
	CALL16(BIOSputs(SB))
115
 
116
	LBI(0x41, rAH)			/* check extensions present */
117
	LWI(0x55AA, rBX)
118
	LXB(Xdrive, xBP, rDL)		/* drive */
119
	BIOSCALL(0x13)			/* CF set on failure */
120
	JCS _jmp01
121
	CMPI(0xAA55, rBX)
122
	JNE _jmp01
123
	ANDI(0x0001, rCX)
124
	JEQ _jmp01
125
 
126
					/* rCX contains 0x0001 */
127
	SBPWI(0x0010, Xdap+0)		/* reserved + packet size */
128
	SBPW(rCX, Xdap+2)		/* reserved + # of blocks to transfer */
129
 
130
	DEC(rCX)
131
	SBPW(rCX, Xdap+12)
132
	SBPW(rCX, Xdap+14)
133
 
134
	CALL16(dreset(SB))
135
 
136
_jmp00:
137
	LW(_volid(SB), rAX)		/* Xrootlo */
138
	LW(_volid+2(SB), rDX)		/* Xroothi */
139
 
140
	LWI(_magic+DIROFF(SB), rBX)
141
	CALL16(BIOSread(SB))		/* read the root directory */
142
 
143
	LWI((512/Dirsz), rBX)
144
 
145
	LWI(_magic+DIROFF(SB), rDI)	/* compare first directory entry */
146
 
147
_cmp00:
148
	PUSHR(rDI)			/* save for later if it matches */
149
	LWI(bootfile(SB), rSI)
150
	LWI(Dnamesz, rCX)
151
	REP
152
	CMPSB
153
	POPR(rDI)
154
	JEQ _jmp02
155
 
156
	DEC(rBX)
157
	JEQ _jmp01
158
 
159
	ADDI(Dirsz, rDI)
160
	JMP _cmp00
161
_jmp01:
162
	CALL16(buggery(SB))
163
 
164
_jmp02:
165
	CLR(rBX)			/* a handy value */
166
	LW(_rootsize(SB), rAX)		/* calculate and save Xrootsz */
167
	LWI(Dirsz, rCX)
168
	MUL(rCX)
169
	LW(_sectsize(SB), rCX)
170
	PUSHR(rCX)
171
	DEC(rCX)
172
	ADD(rCX, rAX)
173
	ADC(rBX, rDX)
174
	POPR(rCX)			/* _sectsize(SB) */
175
	DIV(rCX)
176
	PUSHR(rAX)			/* Xrootsz */
177
 
178
	/*
179
	 * rDI points to the matching directory entry.
180
	 */
181
	LXW(Dstart, xDI, rAX)		/* starting sector address */
182
	DEC(rAX)			/* that's just the way it is */
183
	DEC(rAX)
184
	LB(_clustsize(SB), rCL)
185
	CLRB(rCH)
186
	MUL(rCX)
187
	LW(_volid(SB), rCX)		/* Xrootlo */
188
	ADD(rCX, rAX)
189
	LW(_volid+2(SB), rCX)		/* Xroothi */
190
	ADC(rCX, rDX)
191
	POPR(rCX)			/* Xrootsz */
192
	ADD(rCX, rAX)
193
	ADC(rBX, rDX)
194
 
195
	PUSHR(rAX)			/* calculate how many sectors to read */
196
	PUSHR(rDX)
197
	LXW(Dlengthlo, xDI, rAX)
198
	LXW(Dlengthhi, xDI, rDX)
199
	LW(_sectsize(SB), rCX)
200
	PUSHR(rCX)
201
	DEC(rCX)
202
	ADD(rCX, rAX)
203
	ADC(rBX, rDX)
204
	POPR(rCX)			/* _sectsize(SB) */
205
	DIV(rCX)
206
	MW(rAX, rCX)
207
	POPR(rDX)
208
	POPR(rAX)
209
 
210
	LWI(LOADSEG, rBX)		/* address to load into (seg+offset) */
211
	MTSR(rBX, rES)			/*  seg */
212
	LWI(LOADOFF, rBX)		/*  offset */
213
 
214
_readboot:
215
	CALL16(BIOSread(SB))		/* read the sector */
216
 
217
	LW(_sectsize(SB), rDI)		/* bump addresses/counts */
218
	ADD(rDI, rBX)
219
	JCC _incsecno
220
 
221
	MFSR(rES, rDI)			/* next 64KB segment */
222
	ADDI(0x1000, rDI)
223
	MTSR(rDI, rES)
224
 
225
_incsecno:
226
	CLR(rDI)
227
	INC(rAX)
228
	ADC(rDI, rDX)
229
	LOOP _readboot
230
 
231
	LWI(LOADSEG, rDI)		/* set rDS for loaded code */
232
	MTSR(rDI, rDS)
233
	FARJUMP16(LOADSEG, LOADOFF)	/* no deposit, no return */
234
 
235
TEXT buggery(SB), $0
236
	LWI(error(SB), rSI)
237
	CALL16(BIOSputs(SB))
238
 
239
_wait:
240
	CLR(rAX)			/* wait for almost any key */
241
	BIOSCALL(0x16)
242
 
243
_reset:
244
	CLR(rBX)			/* set ES segment for BIOS area */
245
	MTSR(rBX, rES)
246
 
247
	LWI(0x0472, rBX)		/* warm-start code address */
248
	LWI(0x1234, rAX)		/* warm-start code */
249
	POKEW				/* MOVW	AX, ES:[BX] */
250
 
251
	FARJUMP16(0xFFFF, 0x0000)	/* reset */
252
 
253
 
254
/*
255
 * Read a sector from a disc. On entry:
256
 *   rDX:rAX	sector number
257
 *   rES:rBX	buffer address
258
 */
259
TEXT BIOSread(SB), $0
260
	LWI(5, rDI)			/* retry count (ATAPI ZIPs suck) */
261
_retry:
262
	PUSHA				/* may be trashed by BIOSCALL */
263
 
264
	SBPW(rBX, Xdap+4)		/* transfer buffer :offset */
265
	MFSR(rES, rDI)			/* transfer buffer seg: */
266
	SBPW(rDI, Xdap+6)
267
	SBPW(rAX, Xdap+8)		/* LBA (64-bits) */
268
	SBPW(rDX, Xdap+10)
269
 
270
	MW(rBP, rSI)			/* disk address packet */
271
	LBI(0x42, rAH)			/* extended read */
272
	LBPB(Xdrive, rDL)		/* form drive */
273
	BIOSCALL(0x13)			/* CF set on failure */
274
	JCC _BIOSreadret
275
 
276
	POPA
277
	DEC(rDI)			/* too many retries? */
278
	JEQ _ioerror
279
 
280
	CALL16(dreset(SB))
281
	JMP _retry
282
 
283
_ioerror:
284
	LWI(ioerror(SB), rSI)
285
	CALL16(BIOSputs(SB))
286
	JMP _wait
287
 
288
_BIOSreadret:
289
	POPA
290
	RET
291
 
292
TEXT dreset(SB), $0
293
	PUSHA
294
	CLR(rAX)			/* rAH == 0 == reset disc system */
295
	LBPB(Xdrive, rDL)
296
	BIOSCALL(0x13)
297
	ORB(rAH, rAH)			/* status (0 == success) */
298
	POPA
299
	JNE _ioerror
300
	RET
301
 
302
/*
303
 * Output a string to the display.
304
 * String argument is in rSI.
305
 */
306
TEXT BIOSputs(SB), $0
307
	PUSHA
308
	CLR(rBX)
309
_BIOSputs:
310
	LODSB
311
	ORB(rAL, rAL)
312
	JEQ _BIOSputsret
313
 
314
	LBI(0x0E, rAH)
315
	BIOSCALL(0x10)
316
	JMP _BIOSputs
317
 
318
_BIOSputsret:
319
	POPA
320
	RET
321
 
322
/* "Bad format or I/O error\r\nPress almost any key to reboot..." */
323
TEXT error(SB), $0
324
	BYTE $'B'; BYTE $'a'; BYTE $'d'; BYTE $' ';
325
	BYTE $'f'; BYTE $'o'; BYTE $'r'; BYTE $'m';
326
	BYTE $'a'; BYTE $'t'; BYTE $' '; BYTE $'o';
327
	BYTE $'r'; BYTE $' ';
328
/* "I/O error\r\nPress almost any key to reboot..." */
329
TEXT ioerror(SB), $0
330
	BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
331
	BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
332
	BYTE $'r'; BYTE $'\r';BYTE $'\n';
333
	BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
334
	BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $' ';
335
	BYTE $'k'; BYTE $'e'; BYTE $'y';
336
	BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
337
	BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
338
	BYTE $'o'; BYTE $'t';
339
	BYTE $'.'; BYTE $'.'; BYTE $'.';
340
	BYTE $'\z';
341
 
342
#ifdef USEBCOM
343
/* "B       COM" */
344
TEXT bootfile(SB), $0
345
	BYTE $'B'; BYTE $' '; BYTE $' '; BYTE $' ';
346
	BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' ';
347
	BYTE $'C'; BYTE $'O'; BYTE $'M';
348
	BYTE $'\z';
349
#else
350
/* "9LOAD      " */
351
TEXT bootfile(SB), $0
352
	BYTE $'9'; BYTE $'L'; BYTE $'O'; BYTE $'A';
353
	BYTE $'D'; BYTE $' '; BYTE $' '; BYTE $' ';
354
	BYTE $' '; BYTE $' '; BYTE $' ';
355
	BYTE $'\z';
356
#endif /* USEBCOM */
357
 
358
/* "PBS..." */
359
TEXT confidence(SB), $0
360
	BYTE $'P'; BYTE $'B'; BYTE $'S'; BYTE $'2';
361
	BYTE $'.'; BYTE $'.'; BYTE $'.';
362
	BYTE $'\z';