xref: /plan9-contrib/sys/src/boot/pc/pbsraw.s (revision b94bb474148e9d24a82a427863d9c9eb4c20f4ae)
1/*
2 *  Partition Boot Sector. Loaded at 0x7C00:
3 *	8a pbsraw.s; 8l -o pbsraw -l -H3 -T0x7C00 pbsraw.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 _startlba,  _filesz and _sectsz containing the start lba of
14 * the loader and filesz to contain the size of the file and the sector size.
15 * The sector size can be probably detected by the bios.
16 */
17#include "x16.h"
18
19#define LOADSEG		(0x10000/16)	/* where to load code (64KB) */
20#define LOADOFF		0
21
22/*
23 * Data is kept on the stack, indexed by rBP.
24 */
25#define Xdap		0x00		/* disc address packet */
26#define Xrootsz		0x10		/* file data area */
27#define Xdrive		0x12		/* boot drive, passed by BIOS or MBR */
28#define Xtotal		0x14		/* sum of allocated data above */
29
30TEXT _magic(SB), $0
31	BYTE $0xEB; BYTE $0x3C;		/* jmp .+ 0x3C  (_start0x3E) */
32	BYTE $0x90			/* nop */
33TEXT _startlba(SB), $0
34	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
35TEXT _filesz(SB), $0
36	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
37TEXT _sectsz(SB), $0
38	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
39TEXT _pad(SB), $0
40	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
41	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
42	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
43	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
44	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
45	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
46	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
47	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
48	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
49	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
50	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
51	BYTE $0x00; BYTE $0x00; BYTE $0x00
52
53_start0x3E:
54	CLI
55	CLR(rAX)
56	MTSR(rAX, rSS)			/* 0000 -> rSS */
57	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
58	MTSR(rAX, rES)
59	LWI(_magic-Xtotal(SB), rSP)
60	MW(rSP, rBP)			/* set the indexed-data pointer */
61
62	SBPB(rDL, Xdrive)		/* save the boot drive */
63
64	/* booting from a CD starts us at 7C0:0.  Move to 0:7C00 */
65	PUSHR(rAX)
66	LWI(_nxt(SB), rAX)
67	PUSHR(rAX)
68	BYTE $0xCB			/* FAR RET */
69
70TEXT _nxt(SB), $0
71	STI
72
73	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
74	CALL16(BIOSputs(SB))
75
76	LBI(0x41, rAH)			/* check extensions present */
77	LWI(0x55AA, rBX)
78	LXB(Xdrive, xBP, rDL)		/* drive */
79	BIOSCALL(0x13)			/* CF set on failure */
80	JCS _jmp00
81	CMPI(0xAA55, rBX)
82	JNE _jmp00
83	ANDI(0x0001, rCX)
84	JNE _jmp01
85
86_jmp00:
87	CALL16(buggery(SB))
88
89_jmp01:
90	SBPWI(0x0010, Xdap+0)		/* reserved + packet size */
91	SBPW(rCX, Xdap+2)		/* reserved + # of blocks to transfer */
92
93	DEC(rCX)
94	SBPW(rCX, Xdap+12)
95	SBPW(rCX, Xdap+14)
96
97	CALL16(dreset(SB))
98
99_jmp02:
100	CLR(rBX)			/* a handy value */
101
102	LW(_startlba(SB), rAX)
103	LW(_startlba+2(SB), rDX)
104	CALL16(printDXAX(SB))
105	PUSHR(rAX)
106	PUSHR(rDX)
107	LW(_filesz(SB), rAX)
108	LW(_filesz+2(SB), rDX)
109	CALL16(printDXAX(SB))
110
111	MW(rAX, rCX)
112	POPR(rDX)
113	POPR(rAX)
114
115	LWI(LOADSEG, rBX)		/* address to load into (seg+offset) */
116	MTSR(rBX, rES)			/*  seg */
117	LWI(LOADOFF, rBX)		/*  offset */
118
119_readboot:
120	CALL16(BIOSread(SB))		/* read the sector */
121
122	LW(_sectsz(SB), rDI)		/* bump addresses/counts */
123	ADD(rDI, rBX)
124	JCC _incsecno
125
126	MFSR(rES, rDI)			/* next 64KB segment */
127	ADDI(0x1000, rDI)
128	MTSR(rDI, rES)
129
130_incsecno:
131	CLR(rDI)
132	INC(rAX)
133	ADC(rDI, rDX)
134	LOOP _readboot
135
136	LWI(LOADSEG, rDI)		/* set rDS for loaded code */
137	MTSR(rDI, rDS)
138	FARJUMP16(LOADSEG, LOADOFF)	/* no deposit, no return */
139
140TEXT buggery(SB), $0
141	LWI(error(SB), rSI)
142	CALL16(BIOSputs(SB))
143
144_wait:
145	CLR(rAX)			/* wait for almost any key */
146	BIOSCALL(0x16)
147
148_reset:
149	CLR(rBX)			/* set ES segment for BIOS area */
150	MTSR(rBX, rES)
151
152	LWI(0x0472, rBX)		/* warm-start code address */
153	LWI(0x1234, rAX)		/* warm-start code */
154	POKEW				/* MOVW	AX, ES:[BX] */
155
156	FARJUMP16(0xFFFF, 0x0000)	/* reset */
157
158/*
159 * Read a sector from a disc. On entry:
160 *   rDX:rAX	sector number
161 *   rES:rBX	buffer address
162 */
163TEXT BIOSread(SB), $0
164	LWI(5, rDI)			/* retry count (ATAPI ZIPs suck) */
165_retry:
166	PUSHA				/* may be trashed by BIOSCALL */
167
168	SBPW(rBX, Xdap+4)		/* transfer buffer :offset */
169	MFSR(rES, rDI)			/* transfer buffer seg: */
170	SBPW(rDI, Xdap+6)
171	SBPW(rAX, Xdap+8)		/* LBA (64-bits) */
172	SBPW(rDX, Xdap+10)
173
174	MW(rBP, rSI)			/* disk address packet */
175	LBI(0x42, rAH)			/* extended read */
176	LBPB(Xdrive, rDL)		/* form drive */
177	BIOSCALL(0x13)			/* CF set on failure */
178	JCC _BIOSreadret
179
180	POPA
181	DEC(rDI)			/* too many retries? */
182	JEQ _ioerror
183
184	CALL16(dreset(SB))
185	JMP _retry
186
187_ioerror:
188	LWI(ioerror(SB), rSI)
189	CALL16(BIOSputs(SB))
190	JMP _wait
191
192_BIOSreadret:
193	POPA
194	RET
195
196TEXT dreset(SB), $0
197	PUSHA
198	CLR(rAX)			/* rAH == 0 == reset disc system */
199	LBPB(Xdrive, rDL)
200	BIOSCALL(0x13)
201	ORB(rAH, rAH)			/* status (0 == success) */
202	POPA
203	JNE _ioerror
204	RET
205
206TEXT printsharp(SB), $0
207	LWI(sharp(SB), rSI)
208_doprint:
209	CALL16(BIOSputs(SB))
210	RET
211
212TEXT printspace(SB), $0
213	LWI(space(SB), rSI)
214	JMP _doprint
215
216TEXT printnl(SB), $0
217	LWI(nl(SB), rSI)
218	JMP _doprint
219
220/*
221 * Output a string to the display.
222 * String argument is in rSI.
223 */
224TEXT BIOSputs(SB), $0
225	PUSHA
226	CLR(rBX)
227_BIOSputs:
228	LODSB
229	ORB(rAL, rAL)
230	JEQ _BIOSputsret
231
232	LBI(0x0E, rAH)
233	BIOSCALL(0x10)
234	JMP _BIOSputs
235
236_BIOSputsret:
237	POPA
238	RET
239
240/*
241 * Output a register to the display.
242 */
243TEXT printAX(SB), $0
244	PUSHR(rAX)
245	PUSHR(rBX)
246	PUSHR(rCX)
247	PUSHR(rDI)
248
249	LWI(4, rCX)
250	LWI(numbuf+4(SB), rSI)
251
252_nextchar:
253	DEC(rSI)
254	MW(rAX, rBX)
255	ANDI(0x000F, rBX)
256	ADDI(0x30, rBX)	/* 0x30 = '0' */
257	CMPI(0x39, rBX)	/* 0x39 = '9' */
258	JLE _dowrite
259	ADDI(0x07, rBX)	/* 0x07 = 'A'-(1+'9')*/
260
261_dowrite:
262	SXB(rBL, 0, xSI)
263	SHRI(4, rAX)
264
265	DEC(rCX)
266	JNE _nextchar
267
268	LWI(numbuf(SB), rSI)
269	CALL16(BIOSputs(SB))
270
271	POPR(rDI)
272	POPR(rCX)
273	POPR(rBX)
274	POPR(rAX)
275
276	CALL16(printspace(SB))
277	RET
278
279TEXT printDXAX(SB), $0
280	PUSHR(rAX)
281	MW(rDX, rAX)
282	CALL16(printAX(SB))
283	POPR(rAX)
284	CALL16(printAX(SB))
285	RET
286
287TEXT printBX(SB), $0
288	PUSHR(rAX)
289	MW(rBX, rAX)
290	CALL16(printAX(SB))
291	POPR(rAX)
292	RET
293
294TEXT error(SB), $0
295	BYTE $'E';
296
297TEXT ioerror(SB), $0
298	BYTE $'I';
299
300TEXT nl(SB), $0
301	BYTE $'\r';
302	BYTE $'\n';
303	BYTE $'\z';
304
305TEXT numbuf(SB), $0
306	BYTE $'X'; BYTE $'X'; BYTE $'X'; BYTE $'X';
307	BYTE $'\z';
308
309TEXT space(SB), $0
310	BYTE $' ';
311	BYTE $'\z';
312
313TEXT sharp(SB), $0
314	BYTE $'#'; BYTE $'\z';
315
316/* "PBSR..." */
317TEXT confidence(SB), $0
318	BYTE $'P'; BYTE $'B'; BYTE $'S'; BYTE $'R';
319	BYTE $'.'; BYTE $'.'; BYTE $'.';
320	BYTE $'\z';
321