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