root/mbr/gptmbr.S

Revision d0f275981c9289dc4b8df64e72cd9902bf85aebe, 7.0 KB (checked in by H. Peter Anvin <hpa@…>, 17 months ago)

mbr: Make sure the MBR code starts with the byte 0x33

Apparently some BIOSes (including some Acer Travelmate machines)
require an MBR to start with 0x33; apparently Micro$oft MBRs start
with 33 C0, an alternate coding of the "xorw %ax,%ax" instruction. As
such, follow suit to work on these braindead BIOSes.

Signed-off-by: H. Peter Anvin <hpa@…>

  • Property mode set to 100644
Line 
1/* -----------------------------------------------------------------------
2 *
3 *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 *
6 *   Permission is hereby granted, free of charge, to any person
7 *   obtaining a copy of this software and associated documentation
8 *   files (the "Software"), to deal in the Software without
9 *   restriction, including without limitation the rights to use,
10 *   copy, modify, merge, publish, distribute, sublicense, and/or
11 *   sell copies of the Software, and to permit persons to whom
12 *   the Software is furnished to do so, subject to the following
13 *   conditions:
14 *
15 *   The above copyright notice and this permission notice shall
16 *   be included in all copies or substantial portions of the Software.
17 *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 *   OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * ----------------------------------------------------------------------- */
28
29#include "adjust.h"
30
31        .code16
32        .text
33
34        .globl  bootsec
35stack           = 0x7c00
36
37/* Partition table header here */
38phdr            = stack         /* Above the stack, overwritten by bootsect */
39/* Partition table sector here */
40/* To handle > 32K we need to play segment tricks... */
41psec            = _phdr + 512
42
43/* Where we put DS:SI */
44dssi_out        = _start + 0x1be
45
46BIOS_kbdflags   = 0x417
47BIOS_page       = 0x462
48
49        /* gas/ld has issues with doing this as absolute addresses... */
50        .section ".bootsec", "a", @nobits
51        .globl  bootsec
52bootsec:
53        .space  512
54
55        .text
56        .globl  _start
57_start:
58        .byte   0x33, 0xc0      /* xorw %ax, %ax */
59        cli
60        movw    %ax, %ds
61        movw    %ax, %ss
62        movw    $stack, %sp
63        movw    %sp, %si
64        pushw   %es             /* 4(%bp) es:di -> $PnP header */
65        pushw   %di             /* 2(%bp) */
66        movw    %ax, %es
67        sti
68        cld
69
70        /* Copy down to 0:0x600 */
71        movw    $_start, %di
72        movw    $(512/2), %cx
73        rep; movsw
74
75        ljmpw   $0, $next
76next:
77
78        ADJUST_DRIVE
79        pushw   %dx             /* 0(%bp) = %dl -> drive number */
80
81        /* Check to see if we have EBIOS */
82        pushw   %dx             /* drive number */
83        movb    $0x41, %ah      /* %al == 0 already */
84        movw    $0x55aa, %bx
85        xorw    %cx, %cx
86        xorb    %dh, %dh
87        stc
88        int     $0x13
89        jc      1f
90        cmpw    $0xaa55, %bx
91        jne     1f
92        shrw    %cx             /* Bit 0 = fixed disk subset */
93        jnc     1f
94
95        /* We have EBIOS; patch in the following code at
96           read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
97        movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
98                (read_sector_cbios)
99
1001:
101        popw    %dx
102
103        /* Get (C)HS geometry */
104        movb    $0x08, %ah
105        int     $0x13
106        andw    $0x3f, %cx      /* Sector count */
107        movw    %sp, %bp        /* %bp -> frame pointer: LEAVE UNCHANGED */
108        pushw   %cx             /* -2(%bp) Save sectors on the stack */
109        movzbw  %dh, %ax        /* dh = max head */
110        incw    %ax             /* From 0-based max to count */
111        mulw    %cx             /* Heads*sectors -> sectors per cylinder */
112
113        /* Save sectors/cylinder on the stack */
114        pushw   %dx             /* -4(%bp) High word */
115        pushw   %ax             /* -6(%bp) Low word */
116
117        /* Load partition table header */
118        xorl    %eax,%eax
119        cltd
120        incw    %ax             /* %edx:%eax = 1 */
121        movw    $phdr, %bx
122        pushw   %bx             /* -8(%bp) phdr == bootsect */
123        call    read_sector
124
125        /* Number of partition sectors */
126        /* We assume the partition table is 32K or less, and that
127           the sector size is 512. */
128        /* Note: phdr == 6(%bp) */
129        movw    (80+6)(%bp),%cx         /* NumberOfPartitionEntries */
130        movw    (84+6)(%bp),%ax         /* SizeOfPartitionEntry */
131        pushw   %ax
132        pushw   %cx
133        mulw    %cx
134        shrw    $9,%ax
135        xchgw   %ax,%cx
136        incw    %cx
137
138        /* Starting LBA of partition array */
139        movl    (72+6)(%bp),%eax
140        movl    (76+6)(%bp),%edx
141
142        pushw   %bx
143get_ptab:
144        call    read_sector
145        call    inc64
146        loopw   get_ptab
147
148        /* Find the boot partition */
149        xorw    %si,%si                 /* Nothing found yet */
150        popw    %di                     /* Partition table in memory */
151        popw    %cx                     /* NumberOfPartitionEntries */
152        popw    %ax                     /* SizeOfPartitionEntry */
153
154find_part:
155        /* If the PartitionTypeGUID is all zero, it's an empty slot */
156        movl      (%di),%edx
157        orl      4(%di),%edx
158        orl      8(%di),%edx
159        orl     12(%di),%edx
160        jz      not_this
161        testb   $0x04,48(%di)
162        jz      not_this
163        andw    %si,%si
164        jnz     found_multiple
165        movw    %di,%si
166not_this:
167        addw    %ax,%di
168        loopw   find_part
169
170        andw    %si,%si
171        jnz     found_part
172
173missing_os:
174        call    error
175        .ascii  "Missing OS\r\n"
176
177found_multiple:
178        call    error
179        .ascii  "Multiple active partitions\r\n"
180
181found_part:
182        xchgw   %ax,%cx         /* Set up %cx for rep movsb further down */
183
184        movw    $dssi_out,%di
185        pushw   %di
186
187        /* 80 00 00 00 ee 00 00 00
188           - bootable partition, type EFI (EE), no CHS information */
189        xorl    %eax,%eax
190        movb    $0x80,%al
191        stosl
192        movb    $0xed,%al
193        stosl
194        movl    32(%si),%eax
195        movl    36(%si),%edx
196        call    saturate_stosl          /* Partition start */
197
198        movl    40(%si),%eax
199        movl    44(%si),%edx
200        subl    32(%si),%eax
201        sbbl    36(%si),%edx
202        call    inc64
203        call    saturate_stosl          /* Partition length */
204
205        movzwl  %cx,%eax                /* Length of GPT entry */
206        stosl
207       
208        rep; movsb                      /* GPT entry follows MBR entry */
209        popw    %si
210
211/*
212 * boot: invoke the actual bootstrap. %ds:%si points to the
213 * partition information in memory.  The top word on the stack
214 * is phdr == 0x7c00 == the address of the boot sector.
215 */
216boot:
217        movl    (32+20)(%si),%eax
218        movl    (36+20)(%si),%edx
219        popw    %bx
220        call    read_sector
221        cmpw    $0xaa55, -2(%bx)
222        jne     missing_os      /* Not a valid boot sector */
223        movw    %bp, %sp        /* driveno == bootsec-6 */
224        popw    %dx             /* dl -> drive number */
225        popw    %di             /* es:di -> $PnP vector */
226        popw    %es
227        movl    $0x54504721,%eax /* !GPT magic number */
228        cli
229        jmpw    *%sp            /* %sp == bootsec */
230
231/*
232 * Store the value in %eax to %di iff %edx == 0, otherwise store -1.
233 * Returns the value that was actually written in %eax.
234 */
235saturate_stosl:
236        andl    %edx,%edx
237        jz 1f
238        orl     $-1,%eax
2391:      stosl
240        ret
241
242/*
243 * Increment %edx:%eax
244 */
245inc64:
246        addl    $1,%eax
247        adcl    $0,%edx
248        ret
249
250/*
251 * read_sector: read a single sector pointed to by %edx:%eax to
252 * %es:%bx.  CF is set on error.  All registers saved.
253 */
254read_sector:
255        pushal
256        pushl   %edx    /* MSW of LBA */
257        pushl   %eax    /* LSW of LBA */
258        pushw   %es     /* Buffer segment */
259        pushw   %bx     /* Buffer offset */
260        pushw   $1      /* Sector count */
261        pushw   $16     /* Size of packet */
262        movw    %sp, %si
263
264        /* This chunk is skipped if we have ebios */
265        /* Do not clobber %es:%bx or %edx:%eax before this chunk! */
266read_sector_cbios:
267        divl    -6(%bp) /* secpercyl */
268        shlb    $6, %ah
269        movb    %ah, %cl
270        movb    %al, %ch
271        xchgw   %dx, %ax
272        divb    -2(%bp) /* sectors */
273        movb    %al, %dh
274        orb     %ah, %cl
275        incw    %cx     /* Sectors are 1-based */
276        movw    $0x0201, %ax
277
278read_common:
279        movb    (%bp), %dl /* driveno */
280        int     $0x13
281        leaw    16(%si), %sp    /* Drop DAPA */
282        popal
283        jc      disk_error
284        addb    $2, %bh         /* bx += 512: point to the next buffer */
285        ret
286
287disk_error:
288        call    error
289        .ascii  "Disk error on boot\r\n"
290
291/*
292 * Print error messages.  This is invoked with "call", with the
293 * error message at the return address.
294 */
295error:
296        popw    %si
2972:
298        lodsb
299        movb    $0x0e, %ah
300        movb    (BIOS_page), %bh
301        movb    $0x07, %bl
302        int     $0x10           /* May destroy %bp */
303        cmpb    $10, %al        /* Newline? */
304        jne     2b
305
306        int     $0x18           /* Boot failure */
307die:
308        hlt
309        jmp     die
Note: See TracBrowser for help on using the browser.