Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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