xref: /plan9/sys/src/boot/pc/mbr.s (revision 452adaa48b6720b6b8891a967f6776a8078487da)
1/*
2 * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600:
3 *	8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8
4 */
5#include "x16.h"
6
7/*#define FLOPPY	1		/* test on a floppy */
8#define TRACE(C)	PUSHA;\
9			CLR(rBX);\
10			MOVB $C, AL;\
11			LBI(0x0E, rAH);\
12			BIOSCALL(0x10);\
13			POPA
14
15/*
16 * We keep data on the stack, indexed by BP.
17 */
18#define Xdap		0x00		/* disc address packet */
19#define Xtable		0x10		/* partition table entry */
20#define Xdrive		0x12		/* starting disc */
21#define Xtotal		0x14		/* sum of allocated data above */
22
23/*
24 * Start: loaded at 0000:7C00, relocate to 0000:0600.
25 * Boot drive is in rDL.
26 */
27TEXT _start(SB), $0
28	CLI
29	CLR(rAX)
30	MTSR(rAX, rSS)			/* 0000 -> rSS */
31	LWI((0x7C00-Xtotal), rSP)	/* 7Bxx -> rSP */
32	MW(rSP, rBP)			/* set the indexed-data pointer */
33
34	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
35	LWI(0x7C00, rSI)		/* 7C00 -> rSI, source offset */
36	MTSR(rAX, rES)			/* 0000 -> rES, destination segment */
37	LWI(0x600, rDI)			/* 0600 -> rDI, destination offset */
38	LWI(0x100, rCX)			/* 0100 -> rCX, loop count (words) */
39
40	CLD
41	REP; MOVSL			/* MOV DS:[(E)SI] -> ES:[(E)DI] */
42
43	FARJUMP16(0x0000, _start0600(SB))
44
45TEXT _start0600(SB), $0
46#ifdef FLOPPY
47	LBI(0x80, rDL)
48#else
49	CLRB(rAL)			/* some systems pass 0 */
50	CMPBR(rAL, rDL)
51	JNE _save
52	LBI(0x80, rDL)
53#endif /* FLOPPY */
54_save:
55	SXB(rDL, Xdrive, xBP)		/* save disc */
56
57	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
58	CALL16(BIOSputs(SB))
59
60	LWI(_start+0x01BE(SB), rSI)	/* address of partition table */
61	LWI(0x04, rCX)			/* 4 entries in table */
62	LBI(0x80, rAH)			/* active entry value */
63	CLRB(rAL)			/* inactive entry value */
64
65_activeloop0:
66	LXB(0x00, xSI, rBL)		/* get active entry from table */
67	CMPBR(rBL, rAH)			/* is this an active entry? */
68	JEQ _active
69
70	CMPBR(rBL, rAL)			/* if not active it should be 0 */
71	JNE _invalidMBR
72
73	ADDI(0x10, rSI)			/* next table entry */
74	DEC(rCX)
75	JNE _activeloop0
76
77	LWI(noentry(SB), rSI)
78	CALL16(buggery(SB))
79
80_active:
81	MW(rSI, rDI)			/* save table address */
82
83_activeloop1:
84	ADDI(0x10, rSI)			/* next table entry */
85	DEC(rCX)
86	JEQ _readsector
87
88	LXB(0x00, xSI, rBL)		/* get active entry from table */
89	CMPBR(rBL, rAH)			/* is this an active entry? */
90	JNE _activeloop1		/* should only be one active */
91
92_invalidMBR:
93	LWI(invalidMBR(SB), rSI)
94	CALL16(buggery(SB))
95
96_readsector:
97	LBI(0x41, rAH)			/* check extensions present */
98	LWI(0x55AA, rBX)
99	LXB(Xdrive, xBP, rDL)		/* drive */
100	BIOSCALL(0x13)			/* CF set on failure */
101	JCS _readsector2
102	CMPI(0xAA55, rBX)
103	JNE _readsector2
104	ANDI(0x0001, rCX)
105	JEQ _readsector2
106
107_readsector42:
108	SBPBI(0x10, Xdap+0)		/* packet size */
109	SBPBI(0x00, Xdap+1)		/* reserved */
110	SBPBI(0x01, Xdap+2)		/* number of blocks to transfer */
111	SBPBI(0x00, Xdap+3)		/* reserved */
112	SBPWI(0x7C00, Xdap+4)		/* transfer buffer :offset */
113	SBPWI(0x0000, Xdap+6)		/* transfer buffer seg: */
114	LXW(0x08, xDI, rAX)		/* LBA (64-bits) */
115	SBPW(rAX, Xdap+8)
116	LXW(0x0A, xDI, rAX)
117	SBPW(rAX, Xdap+10)
118	SBPWI(0x0000, Xdap+12)
119	SBPWI(0x0000, Xdap+14)
120
121	MW(rBP, rSI)			/* disk address packet */
122	LBI(0x42, rAH)			/* extended read */
123	BIOSCALL(0x13)			/* CF set on failure */
124	JCC _readsectorok
125
126	LWI(ioerror(SB), rSI)
127	CALL16(buggery(SB))
128
129/*
130 * Read a sector from a disc using the traditional BIOS call.
131 * For BIOSCALL(0x13/AH=0x02):
132 *   rAH	0x02
133 *   rAL	number of sectors to read (1)
134 *   rCH	low 8 bits of cylinder
135 *   rCL	high 2 bits of cylinder (7-6), sector (5-0)
136 *   rDH	head
137 *   rDL	drive
138 *   rES:rBX	buffer address
139 */
140_readsector2:
141	LXB(0x01, xDI, rDH)		/* head */
142	LXW(0x02, xDI, rCX)		/* save active cylinder/sector */
143
144	LWI(0x0201, rAX)		/* read one sector */
145	LXB(Xdrive, xBP, rDL)		/* drive */
146	LWI(0x7C00, rBX)		/* buffer address (rES already OK) */
147	BIOSCALL(0x13)			/* CF set on failure */
148	JCC _readsectorok
149
150	LWI(ioerror(SB), rSI)
151	CALL16(buggery(SB))
152
153_readsectorok:
154	LWI(0x7C00, rBX)		/* buffer address (rES already OK) */
155	LXW(0x1FE, xBX, rAX)
156	CMPI(0xAA55, rAX)
157	JNE _bbnotok
158
159	/*
160	 * Jump to the loaded PBS.
161	 * rDL and rSI should still contain the drive
162	 * and partition table pointer respectively.
163	 */
164	MW(rDI, rSI)
165	FARJUMP16(0x0000, 0x7C00)
166
167_bbnotok:
168	LWI(invalidPBS(SB), rSI)
169
170TEXT buggery(SB), $0
171	CALL16(BIOSputs(SB))
172	LWI(reboot(SB), rSI)
173	CALL16(BIOSputs(SB))
174
175_wait:
176	CLR(rAX)			/* wait for any key */
177	BIOSCALL(0x16)
178
179_reset:
180	CLR(rBX)			/* set ES segment for BIOS area */
181	MTSR(rBX, rES)
182
183	LWI(0x0472, rBX)		/* warm-start code address */
184	LWI(0x1234, rAX)		/* warm-start code */
185	POKEW				/* MOVW	AX, ES:[BX] */
186
187	FARJUMP16(0xFFFF, 0x0000)	/* reset */
188
189/*
190 * Output a string to the display.
191 * String argument is in rSI.
192 */
193TEXT BIOSputs(SB), $0
194	PUSHA
195	CLR(rBX)
196_BIOSputs:
197	LODSB
198	ORB(rAL, rAL)
199	JEQ _BIOSputsret
200
201	LBI(0x0E, rAH)
202	BIOSCALL(0x10)
203	JMP _BIOSputs
204
205_BIOSputsret:
206	POPA
207	RET
208
209/* "No active entry in MBR" */
210TEXT noentry(SB), $0
211	BYTE $'N'; BYTE $'o'; BYTE $' '; BYTE $'a';
212	BYTE $'c'; BYTE $'t'; BYTE $'i'; BYTE $'v';
213	BYTE $'e'; BYTE $' '; BYTE $'e'; BYTE $'n';
214	BYTE $'t'; BYTE $'r'; BYTE $'y'; BYTE $' ';
215	BYTE $'i'; BYTE $'n'; BYTE $' '; BYTE $'M';
216	BYTE $'B'; BYTE $'R';
217	BYTE $'\z';
218
219/* "Invalid MBR" */
220TEXT invalidMBR(SB), $0
221	BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
222	BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
223	BYTE $'M'; BYTE $'B'; BYTE $'R';
224	BYTE $'\z';
225
226/* "I/O error" */
227TEXT ioerror(SB), $0
228	BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
229	BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
230	BYTE $'r';
231	BYTE $'\z';
232
233/* "Invalid PBS" */
234TEXT invalidPBS(SB), $0
235	BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
236	BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
237	BYTE $'P'; BYTE $'B'; BYTE $'S';
238	BYTE $'\z';
239
240/* "\r\nPress almost any key to reboot..." */
241TEXT reboot(SB), $0
242	BYTE $'\r';BYTE $'\n';
243	BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
244	BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $'l';
245	BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t';
246	BYTE $' '; BYTE $'a'; BYTE $'n'; BYTE $'y';
247	BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y';
248	BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
249	BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
250	BYTE $'o'; BYTE $'t'; BYTE $'.'; BYTE $'.';
251	BYTE $'.';
252	BYTE $'\z';
253
254/* "MBR..." */
255TEXT confidence(SB), $0
256	BYTE $'M'; BYTE $'B'; BYTE $'R'; BYTE $'.';
257	BYTE $'.'; BYTE $'.';
258	BYTE $'\z';
259