Adding upstream version 4.00~pre55+dfsg.
[syslinux-debian/hramrach.git] / mbr / gptmbr.S
blobd25d27c83293ceb3c457bdfc3413cd4a884a2c7f
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         cli
59         xorw    %ax, %ax
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         testb   $0x04,48(%di)
156         jz      not_this
157         andw    %si,%si
158         jnz     found_multiple
159         movw    %di,%si
160 not_this:
161         addw    %ax,%di
162         loopw   find_part
164         andw    %si,%si
165         jnz     found_part
167 missing_os:
168         call    error
169         .ascii  "Missing OS\r\n"
171 found_multiple:
172         call    error
173         .ascii  "Multiple active partitions\r\n"
175 found_part:
176         xchgw   %ax,%cx         /* Set up %cx for rep movsb further down */
178         movw    $dssi_out,%di
179         pushw   %di
181         /* 80 00 00 00 ee 00 00 00
182            - bootable partition, type EFI (EE), no CHS information */
183         xorl    %eax,%eax
184         movb    $0x80,%al
185         stosl
186         movb    $0xed,%al
187         stosl
188         movl    32(%si),%eax
189         movl    36(%si),%edx
190         call    saturate_stosl          /* Partition start */
192         movl    40(%si),%eax
193         movl    44(%si),%edx
194         subl    32(%si),%eax
195         sbbl    36(%si),%edx
196         call    inc64
197         call    saturate_stosl          /* Partition length */
199         movzwl  %cx,%eax                /* Length of GPT entry */
200         stosl
201         
202         rep; movsb                      /* GPT entry follows MBR entry */
203         popw    %si
206  * boot: invoke the actual bootstrap. %ds:%si points to the
207  * partition information in memory.  The top word on the stack
208  * is phdr == 0x7c00 == the address of the boot sector.
209  */
210 boot:
211         movl    (32+20)(%si),%eax
212         movl    (36+20)(%si),%edx
213         popw    %bx
214         call    read_sector
215         cmpw    $0xaa55, -2(%bx)
216         jne     missing_os      /* Not a valid boot sector */
217         movw    %bp, %sp        /* driveno == bootsec-6 */
218         popw    %dx             /* dl -> drive number */
219         popw    %di             /* es:di -> $PnP vector */
220         popw    %es
221         movl    $0x54504721,%eax /* !GPT magic number */
222         cli
223         jmpw    *%sp            /* %sp == bootsec */
226  * Store the value in %eax to %di iff %edx == 0, otherwise store -1.
227  * Returns the value that was actually written in %eax.
228  */
229 saturate_stosl:
230         andl    %edx,%edx
231         jz 1f
232         orl     $-1,%eax
233 1:      stosl
234         ret
237  * Increment %edx:%eax
238  */
239 inc64:
240         addl    $1,%eax
241         adcl    $0,%edx
242         ret
245  * read_sector: read a single sector pointed to by %edx:%eax to
246  * %es:%bx.  CF is set on error.  All registers saved.
247  */
248 read_sector:
249         pushal
250         pushl   %edx    /* MSW of LBA */
251         pushl   %eax    /* LSW of LBA */
252         pushw   %es     /* Buffer segment */
253         pushw   %bx     /* Buffer offset */
254         pushw   $1      /* Sector count */
255         pushw   $16     /* Size of packet */
256         movw    %sp, %si
258         /* This chunk is skipped if we have ebios */
259         /* Do not clobber %es:%bx or %edx:%eax before this chunk! */
260 read_sector_cbios:
261         divl    -6(%bp) /* secpercyl */
262         shlb    $6, %ah
263         movb    %ah, %cl
264         movb    %al, %ch
265         xchgw   %dx, %ax
266         divb    -2(%bp) /* sectors */
267         movb    %al, %dh
268         orb     %ah, %cl
269         incw    %cx     /* Sectors are 1-based */
270         movw    $0x0201, %ax
272 read_common:
273         movb    (%bp), %dl /* driveno */
274         int     $0x13
275         leaw    16(%si), %sp    /* Drop DAPA */
276         popal
277         jc      disk_error
278         addb    $2, %bh         /* bx += 512: point to the next buffer */
279         ret
281 disk_error:
282         call    error
283         .ascii  "Disk error on boot\r\n"
286  * Print error messages.  This is invoked with "call", with the
287  * error message at the return address.
288  */
289 error:
290         popw    %si
292         lodsb
293         movb    $0x0e, %ah
294         movb    (BIOS_page), %bh
295         movb    $0x07, %bl
296         int     $0x10           /* May destroy %bp */
297         cmpb    $10, %al        /* Newline? */
298         jne     2b
300         int     $0x18           /* Boot failure */
301 die:
302         hlt
303         jmp     die