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