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