dmi: check both the AC and ID flags at the same time
[syslinux.git] / mbr / isohdpfx.S
blob4b107e4b529fb09fb3df415c97df36e8a74d1234
1 /* -----------------------------------------------------------------------
2  *
3  *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2009 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  * ----------------------------------------------------------------------- */
30  * Modified MBR code used on an ISO image in hybrid mode.
31  *
32  * This doesn't follow the El Torito spec at all -- it is just a stub
33  * loader of a hard-coded offset, but that's good enough to load
34  * ISOLINUX.
35  */
37 #include "adjust.h"
39         .code16
40         .text
42 HYBRID_MAGIC                    = 0x7078c0fb
43 isolinux_hybrid_signature       = 0x7c00+64
44 isolinux_start_hybrid           = 0x7c00+64+4
46         .globl  bootsec
47 /* Important: the top 6 words on the stack are passed to isolinux.bin */
48 stack           = 0x7c00
49 partoffset      = (stack-8)
50 driveno         = (stack-14)
51 heads           = (stack-16)
52 sectors         = (stack-18)
53 ebios_flag      = (stack-20)
54 secpercyl       = (stack-24)
56 BIOS_kbdflags   = 0x417
57 BIOS_page       = 0x462
59         /* gas/ld has issues with doing this as absolute addresses... */
60         .section ".bootsec", "a", @nobits
61         .globl  bootsec
62 bootsec:
63         .space  512
65         .text
66         .globl  _start
67 _start:
68         .byte   0x33, 0xed      /* xorw %bp, %bp */
69         nop
70         nop
71         nop
72         nop
73         nop
74         nop
75         nop
76         nop
77         nop
78         nop
79         nop
80         nop
81         nop
82         nop
83         nop
84         nop
85         nop
86         nop
87         nop
88         nop
89         nop
90         nop
91         nop
92         nop
93         nop
94         nop
95         nop
96         nop
97         nop
98         nop
99         .byte   0x33, 0xed      /* xorw %bp, %bp */
100         cli
101         movw    %bp, %ss
102         movw    $stack, %sp
103         sti
104         cld
106         /* Check to see if we have a partition table entry */
107         xorl    %ebx, %ebx
108         xorl    %ecx, %ecx
109 #ifdef PARTITION_SUPPORT
110         andw    %si, %si                /* %si == 0 -> no partition data */
111         jz      1f
112         testb   $0x7f, (%si)            /* Invalid active flag field? */
113         jnz     1f
114         cmpb    %cl, 4(%si)             /* Partition type zero == invalid? */
115         je      1f
116         cmpl    $0x58504721, %eax       /* !GPT signature in EAX? */
117         jne     2f
118         cmpb    $0xed, 4(%si)           /* EFI partition type? */
119         jne     2f
120         
121         /* We have GPT partition information */
122         movl    (32+20)(%si), %ecx
123         movl    (36+20)(%si), %ebx
124         jmp     1f
126         /* We have non-GPT partition information */
128         movl    8(%si), %ecx
129 #endif
131         /* We have no partition information */
132         pushl   %ebx                    /*  -4: partoffset_hi */
133         pushl   %ecx                    /*  -8: partoffset_lo */
134         pushw   %es                     /* -10: es:di -> $PnP header */
135         pushw   %di                     /* -12: es:di -> $PnP header */
137         movw    %bp, %ds
138         movw    %bp, %es
139         
140         ADJUST_DRIVE
141         pushw   %dx                     /* -14: dl -> drive number */
143         /* Copy down to 0:0x600 */
144         movw    $0x7c00, %si
145         movw    $_start, %di
146         movw    $(512/2), %cx
147         rep; movsw
149         ljmpw   $0, $next
150 next:
152         /* Check to see if we have EBIOS */
153         pushw   %dx             /* drive number */
154         movb    $0x41, %ah      /* %al == 0 already */
155         movw    $0x55aa, %bx
156         xorw    %cx, %cx
157         xorb    %dh, %dh
158         stc
159         int     $0x13
160         jc      1f
161         cmpw    $0xaa55, %bx
162         jne     1f
163         andw    $1,%cx          /* Bit 0 = fixed disk subset */
164         jz      1f
166         /* We have EBIOS; patch in the following code at
167            read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
168         movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
169                 (read_sector_cbios)
170         jmp     2f
172         xor     %cx, %cx        /* Clear EBIOS flag. */
174         popw    %dx
175         pushw   %cx             /* EBIOS flag */
177         /* Get (C)HS geometry */
178         movb    $0x08, %ah
179         int     $0x13
180         popw    %bx             /* EBIOS flag */
181         movzbw  %dh, %ax        /* dh = max head */
182         incw    %ax             /* From 0-based max to count */
183         pushw   %ax             /* -16: Save heads on the stack */
184         andw    $0x3f, %cx      /* Sector count */
185         pushw   %cx             /* -18: Save sectors on the stack */
186         mulw    %cx             /* Heads*sectors -> sectors per cylinder */
188         pushw   %bx             /* -20: EBIOS flag */
189         
190         /* Save sectors/cylinder on the stack */
191         pushw   %dx             /* -22: High word */
192         pushw   %ax             /* -24: Low word */
194         /*
195          * Load sectors.  We do this one at a time mostly to avoid
196          * pitfalls and to share code with the stock MBR code.
197          */
198         movw    $0x7c00, %bx
199         movw    $4, %cx         /* Sector count */
200         movl    (lba_offset), %eax
203         call    read_sector
204         jc      disk_error
205         incl    %eax
206         addb    $(512 >> 8), %bh
207         loopw   2b
209         /*
210          * Okay, that actually worked... update the stack pointer
211          * and jump into isolinux.bin...
212          */
213         cmpl    $HYBRID_MAGIC,(isolinux_hybrid_signature)
214         jne     bad_signature
216         cli
217         movw    $ebios_flag, %sp
219         /*
220          * Use a ljmpw here to work around a bug in some unknown version
221          * of gas or ld when it comes to jumping to an absolute symbol...
222          *
223          * Look more closely into it if we ever are short on space.
224          */
225         ljmpw   $0, $isolinux_start_hybrid
227 bad_signature:
228         call    error
229         .ascii  "isolinux.bin missing or corrupt.\r\n"
232  * read_sector: read a single sector pointed to by %eax to %es:%bx.
233  * CF is set on error.  All registers saved.
234  */
235 read_sector:
236         pushal
237         xorl    %edx, %edx
238         addl    (partoffset), %eax
239         adcl    (partoffset+4), %edx
240         pushl   %edx    /* MSW of LBA */
241         pushl   %eax    /* LSW of LBA */
242         pushw   %es     /* Buffer segment */
243         pushw   %bx     /* Buffer offset */
244         pushw   $1      /* Sector count */
245         pushw   $16     /* Size of packet */
246         movw    %sp, %si
248         /* This chunk is skipped if we have ebios */
249         /* Do not clobber %eax before this chunk! */
250         /* This also relies on %bx and %edx as set up above. */
251 read_sector_cbios:
252         divl    (secpercyl)
253         shlb    $6, %ah
254         movb    %ah, %cl
255         movb    %al, %ch
256         xchgw   %dx, %ax
257         divb    (sectors)
258         movb    %al, %dh
259         orb     %ah, %cl
260         incw    %cx     /* Sectors are 1-based */
261         movw    $0x0201, %ax
263 read_common:
264         movb    (driveno), %dl
265         int     $0x13
266         leaw    16(%si), %sp    /* Drop DAPA */
267         popal
268         ret
270 disk_error:
271         call    error
272         .ascii  "Operating system load error.\r\n"
275  * Print error messages.  This is invoked with "call", with the
276  * error message at the return address.
277  */
278 error:
279         popw    %si
281         lodsb
282         movb    $0x0e, %ah
283         movb    (BIOS_page), %bh
284         movb    $0x07, %bl
285         int     $0x10           /* May destroy %bp */
286         cmpb    $10, %al        /* Newline? */
287         jne     2b
289         int     $0x18           /* Boot failure */
290 die:
291         hlt
292         jmp     die
294         /* Address of pointer to isolinux.bin */
295 lba_offset = _start+432