1 GAS LISTING /tmp/cc3TQNF4.s page 1
6 1 /* -----------------------------------------------------------------------
10 3 * Copyright 2007 H. Peter Anvin - All Rights Reserved
12 5 * Permission is hereby granted, free of charge, to any person
13 6 * obtaining a copy of this software and associated documentation
14 7 * files (the "Software"), to deal in the Software without
15 8 * restriction, including without limitation the rights to use,
16 9 * copy, modify, merge, publish, distribute, sublicense, and/or
17 10 * sell copies of the Software, and to permit persons to whom
18 11 * the Software is furnished to do so, subject to the following
21 14 * The above copyright notice and this permission notice shall
22 15 * be included in all copies or substantial portions of the Software.
24 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
28 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31 24 * OTHER DEALINGS IN THE SOFTWARE.
33 26 * ----------------------------------------------------------------------- */
40 33 driveno = (stack-6)
41 34 sectors = (stack-8)
42 35 secpercyl = (stack-12)
46 39 /* gas/ld has issues with doing this as absolute addresses... */
47 40 .section ".bootsec", "a", @nobits
50 43 0000 00000000 .space 512
60 49 0001 31C0 xorw %ax, %ax
61 \fGAS LISTING /tmp/cc3TQNF4.s page 2
64 50 0003 8ED8 movw %ax, %ds
65 51 0005 8ED0 movw %ax, %ss
66 52 0007 BC007C movw $stack, %sp
67 53 000a 89E6 movw %sp, %si
68 54 000c 06 pushw %es /* es:di -> $PnP header */
70 56 000e 52 pushw %dx /* dl -> drive number */
71 57 000f 8EC0 movw %ax, %es
75 61 /* Copy down to 0:0x600 */
76 62 0013 BF0000 movw $_start, %di
77 63 0016 B90001 movw $(512/2), %cx
78 64 0019 F3A5 rep; movsw
80 66 001b EA200000 ljmpw $0, $next
84 69 /* Check to see if we have EBIOS */
85 70 0020 52 pushw %dx /* drive number */
86 71 0021 B80041 movw $0x4100, %ax
87 72 0024 BBAA55 movw $0x55aa, %bx
88 73 0027 31C9 xorw %cx, %cx
89 74 0029 30F6 xorb %dh, %dh
91 76 002c CD13 int $0x13
93 78 0030 81FB55AA cmpw $0xaa55, %bx
95 80 0036 D1E9 shrw %cx /* Bit 0 = fixed disk subset */
98 83 /* We have EBIOS; patch in the following code at
99 84 read_sector_cbios: movb $0x42, %ah ; jmp read_common */
100 85 003a 66C7068F movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
103 86 (read_sector_cbios)
108 91 /* Get (C)HS geometry */
109 92 0044 B408 movb $0x08, %ah
110 93 0046 CD13 int $0x13
111 94 0048 83E13F andw $0x3f, %cx /* Sector count */
112 95 004b 51 pushw %cx /* Save sectors on the stack */
113 96 004c 0FB6C6 movzbw %dh, %ax /* dh = max head */
114 97 004f 40 incw %ax /* From 0-based max to count */
115 98 0050 F7E1 mulw %cx /* Heads*sectors -> sectors per cylinder */
117 100 /* Save sectors/cylinder on the stack */
118 101 0052 52 pushw %dx /* High word */
119 102 0053 50 pushw %ax /* Low word */
121 \fGAS LISTING /tmp/cc3TQNF4.s page 3
124 104 0054 6631C0 xorl %eax, %eax /* Base */
125 105 0057 6699 cdq /* Root (%edx <- 0) */
126 106 0059 E86700 call scan_partition_table
128 108 /* If we get here, we have no OS */
130 110 005c E82401 call error
131 111 005f 4D697373 .ascii "Missing operating system.\r\n"
139 115 * read_sector: read a single sector pointed to by %eax to 0x7c00.
140 116 * CF is set on error. All registers saved.
144 120 007d 6631D2 xorl %edx, %edx
145 121 0080 BB0000 movw $bootsec, %bx
146 122 0083 6652 pushl %edx /* MSW of LBA */
147 123 0085 6650 pushl %eax /* LSW of LBA */
148 124 0087 06 pushw %es /* Buffer segment */
149 125 0088 53 pushw %bx /* Buffer offset */
150 126 0089 6A01 pushw $1 /* Sector count */
151 127 008b 6A10 pushw $16 /* Size of packet */
152 128 008d 89E6 movw %sp, %si
154 130 /* This chunk is skipped if we have ebios */
155 131 /* Do not clobber %eax before this chunk! */
156 132 /* This also relies on %bx and %edx as set up above. */
157 133 read_sector_cbios:
158 134 008f 66F736F4 divl (secpercyl)
160 135 0094 C0E406 shlb $6, %ah
161 136 0097 88E1 movb %ah, %cl
162 137 0099 88C5 movb %al, %ch
163 138 009b 92 xchgw %dx, %ax
164 139 009c F636F87B divb (sectors)
165 140 00a0 88C6 movb %al, %dh
166 141 00a2 08E1 orb %ah, %cl
167 142 00a4 41 incw %cx /* Sectors are 1-based */
168 143 00a5 B80102 movw $0x0201, %ax
171 146 00a8 8A16FA7B movb (driveno), %dl
172 147 00ac CD13 int $0x13
173 148 00ae 83C410 addw $16, %sp /* Drop DAPA */
178 153 * read_partition_table:
179 154 * Read a partition table (pointed to by %eax), and copy
180 155 * the partition table into the ptab buffer.
181 \fGAS LISTING /tmp/cc3TQNF4.s page 4
185 157 * Clobbers %si, %di, and %cx, other registers preserved.
186 158 * %cx = 0 on exit.
188 160 * On error, CF is set and ptab is overwritten with junk.
190 162 ptab = _start+446
192 164 read_partition_table:
193 165 00b4 E8C4FF call read_sector
194 166 00b7 BEBE01 movw $bootsec+446, %si
195 167 00ba BFBE01 movw $ptab, %di
196 168 00bd B92000 movw $(16*4/2), %cx
197 169 00c0 F3A5 rep ; movsw
201 173 * scan_partition_table:
202 174 * Scan a partition table currently loaded in the partition table
203 175 * area. Preserve all registers.
206 178 * %eax - base (location of this partition table)
207 179 * %edx - root (offset from MBR, or 0 for MBR)
209 181 * These get pushed into stack slots:
210 182 * 28(%bp) - %eax - base
211 183 * 20(%bp) - %edx - root
214 186 scan_partition_table:
216 188 00c5 89E5 movw %sp, %bp
218 190 /* Search for active partitions */
219 191 00c7 BBBE01 movw $ptab, %bx
220 192 00ca B90400 movw $4, %cx
221 193 00cd 31C0 xorw %ax, %ax
225 197 00d1 F60780 testb $0x80, (%bx)
228 200 00d7 89DE movw %bx, %si
230 202 00d9 83C310 addw $16, %bx
231 203 00dc E2F3 loopw 5b
233 205 00de 48 decw %ax /* Number of active partitions found */
234 206 00df 745C jz boot
235 207 00e1 7939 jns too_many_active
237 209 /* No active partitions found, look for extended partitions */
238 210 00e3 5B popw %bx /* %bx <- ptab */
239 211 00e4 59 popw %cx /* %cx <- 4 */
241 \fGAS LISTING /tmp/cc3TQNF4.s page 5
244 213 00e5 8A4704 movb 4(%bx), %al
245 214 00e8 3C0F cmpb $0x0f, %al /* 0x0f = Win9x extended */
247 216 00ec 247F andb $~0x80, %al /* 0x85 = Linux extended */
248 217 00ee 3C05 cmpb $0x05, %al /* 0x05 = MS-DOS extended */
251 220 /* It is an extended partition. Read the extended partition and
252 221 try to scan it. If the scan returns, re-load the current
253 222 partition table and resume scan. */
255 224 00f2 668B4708 movl 8(%bx), %eax /* Partition table offset */
256 225 00f6 668B5614 movl 20(%bp), %edx /* "Root" */
257 226 00fa 6601D0 addl %edx, %eax /* Compute location of new ptab */
258 227 00fd 6621D2 andl %edx, %edx /* Is this the MBR? */
259 228 0100 7503 jnz 10f
260 229 0102 6689C2 movl %eax, %edx /* Offset -> root if this was MBR */
262 231 0105 E8ACFF call read_partition_table
264 233 010a E8B6FF call scan_partition_table
266 235 /* This returned, so we need to reload the current partition table */
267 236 010d 668B461C movl 28(%bp), %eax /* "Base" */
268 237 0111 E8A0FF call read_partition_table
270 239 /* fall through */
272 241 /* Not an extended partition */
273 242 0114 83C310 addw $16, %bx
274 243 0117 E2CC loopw 7b
276 245 /* Nothing found, return */
281 250 011c E86400 call error
282 251 011f 4D756C74 .ascii "Multiple active partitions.\r\n"
290 255 * boot: invoke the actual bootstrap. (%si) points to the partition
291 256 * table entry, and 28(%bp) has the partition table base.
294 259 013d 668B4408 movl 8(%si), %eax
295 260 0141 6603461C addl 28(%bp), %eax
296 261 0145 66894408 movl %eax, 8(%si) /* Adjust in-memory partition table entry */
297 262 0149 E82FFF call read_sector
298 263 014c 7213 jc disk_error
299 264 014e 813EFE01 cmpw $0xaa55, (bootsec+510)
301 \fGAS LISTING /tmp/cc3TQNF4.s page 6
304 265 0154 0F8504FF jne missing_os /* Not a valid boot sector */
305 266 0158 BCFA7B movw $driveno, %sp /* driveno == bootsec-6 */
306 267 015b 5A popw %dx /* dl -> drive number */
307 268 015c 5F popw %di /* es:di -> $PnP vector */
310 271 015f FFE4 jmpw *%sp /* %sp == bootsec */
313 274 0161 E81F00 call error
314 275 0164 4F706572 .ascii "Operating system load error.\r\n"
322 279 * Print error messages. This is invoked with "call", with the
323 280 * error message at the return address.
329 286 0185 20C0 andb %al, %al
331 288 0189 B40E movb $0x0e, %ah
332 289 018b 8A3E6204 movb (BIOS_page), %bh
333 290 018f B307 movb $0x07, %bl
334 291 0191 CD10 int $0x10
337 294 0195 CD18 int $0x18 /* Boot failure */
340 297 0198 EBFD jmp die
341 \fGAS LISTING /tmp/cc3TQNF4.s page 7
345 *ABS*:0000000000000000 mbr.S
346 mbr.S:42 .bootsec:0000000000000000 bootsec
347 mbr.S:32 *ABS*:0000000000007c00 stack
348 mbr.S:33 *ABS*:0000000000007bfa driveno
349 mbr.S:34 *ABS*:0000000000007bf8 sectors
350 mbr.S:35 *ABS*:0000000000007bf4 secpercyl
351 mbr.S:37 *ABS*:0000000000000462 BIOS_page
352 mbr.S:47 .text:0000000000000000 _start
353 mbr.S:68 .text:0000000000000020 next
354 mbr.S:145 .text:00000000000000a8 read_common
355 mbr.S:133 .text:000000000000008f read_sector_cbios
356 mbr.S:186 .text:00000000000000c3 scan_partition_table
357 mbr.S:109 .text:000000000000005c missing_os
358 mbr.S:282 .text:0000000000000183 error
359 mbr.S:118 .text:000000000000007b read_sector
360 mbr.S:47 .text:00000000000001be ptab
361 mbr.S:164 .text:00000000000000b4 read_partition_table
362 mbr.S:258 .text:000000000000013d boot
363 mbr.S:249 .text:000000000000011c too_many_active
364 mbr.S:273 .text:0000000000000161 disk_error
365 mbr.S:295 .text:0000000000000197 die