module: Fix incorrect list_entry() use
[syslinux.git] / mbr / gptmbr.S
blobae0549f050b60faba1b35d1b864f1b3264ad68df
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  * ----------------------------------------------------------------------- */
29 #include "adjust.h"
31         .code16
32         .text
34         .globl  bootsec
35 stack           = 0x7c00
37 /* Partition table header here */
38 phdr            = stack         /* Above the stack, overwritten by bootsect */
39 /* Partition table sector here */
40 /* To handle > 32K we need to play segment tricks... */
41 psec            = _phdr + 512
43 /* Where we put DS:SI */
44 dssi_out        = _start + 0x1be
46 BIOS_kbdflags   = 0x417
47 BIOS_page       = 0x462
49         /* gas/ld has issues with doing this as absolute addresses... */
50         .section ".bootsec", "a", @nobits
51         .globl  bootsec
52 bootsec:
53         .space  512
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
70         /* Copy down to 0:0x600 */
71         movw    $_start, %di
72         movw    $(512/2), %cx
73         rep; movsw
75         ljmpw   $0, $next
76 next:
78         ADJUST_DRIVE
79         pushw   %dx             /* 0(%bp) = %dl -> drive number */
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
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)
101         popw    %dx
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 */
113         /* Save sectors/cylinder on the stack */
114         pushw   %dx             /* -4(%bp) High word */
115         pushw   %ax             /* -6(%bp) Low word */
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
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
138         /* Starting LBA of partition array */
139         movl    (72+6)(%bp),%eax
140         movl    (76+6)(%bp),%edx
142         pushw   %bx
143 get_ptab:
144         call    read_sector
145         call    inc64
146         loopw   get_ptab
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 */
154 find_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
166 not_this:
167         addw    %ax,%di
168         loopw   find_part
170         andw    %si,%si
171         jnz     found_part
173 missing_os:
174         call    error
175         .ascii  "Missing OS\r\n"
177 found_multiple:
178         call    error
179         .ascii  "Multiple active partitions\r\n"
181 found_part:
182         xchgw   %ax,%cx         /* Set up %cx for rep movsb further down */
184         movw    $dssi_out,%di
185         pushw   %di
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 */
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 */
205         movzwl  %cx,%eax                /* Length of GPT entry */
206         stosl
207         
208         rep; movsb                      /* GPT entry follows MBR entry */
209         popw    %si
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  */
216 boot:
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 */
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  */
235 saturate_stosl:
236         andl    %edx,%edx
237         jz 1f
238         orl     $-1,%eax
239 1:      stosl
240         ret
243  * Increment %edx:%eax
244  */
245 inc64:
246         addl    $1,%eax
247         adcl    $0,%edx
248         ret
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  */
254 read_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
264         /* This chunk is skipped if we have ebios */
265         /* Do not clobber %es:%bx or %edx:%eax before this chunk! */
266 read_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
278 read_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
287 disk_error:
288         call    error
289         .ascii  "Disk error on boot\r\n"
292  * Print error messages.  This is invoked with "call", with the
293  * error message at the return address.
294  */
295 error:
296         popw    %si
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
306         int     $0x18           /* Boot failure */
307 die:
308         hlt
309         jmp     die