Makefile: make the handling of firmware selection a little saner
[syslinux.git] / mbr / isohdpfx.S
blob17e1efe1b1ece01d716b8f28de76c2a19e7927d7
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     1f
172         popw    %dx
173         pushw   %cx             /* EBIOS flag */
175         /* Get (C)HS geometry */
176         movb    $0x08, %ah
177         int     $0x13
178         andw    $0x3f, %cx      /* Sector count */
179         popw    %bx             /* EBIOS flag */
180         pushw   %cx             /* -16: Save sectors on the stack */
181         movzbw  %dh, %ax        /* dh = max head */
182         incw    %ax             /* From 0-based max to count */
183         pushw   %ax             /* -18: Save heads on the stack */
184         mulw    %cx             /* Heads*sectors -> sectors per cylinder */
186         pushw   %bx             /* -20: EBIOS flag */
187         
188         /* Save sectors/cylinder on the stack */
189         pushw   %dx             /* -22: High word */
190         pushw   %ax             /* -24: Low word */
192         /*
193          * Load sectors.  We do this one at a time mostly to avoid
194          * pitfalls and to share code with the stock MBR code.
195          */
196         movw    $0x7c00, %bx
197         movw    $4, %cx         /* Sector count */
198         movl    (lba_offset), %eax
201         call    read_sector
202         jc      disk_error
203         incl    %eax
204         addb    $(512 >> 8), %bh
205         loopw   2b
207         /*
208          * Okay, that actually worked... update the stack pointer
209          * and jump into isolinux.bin...
210          */
211         cmpl    $HYBRID_MAGIC,(isolinux_hybrid_signature)
212         jne     bad_signature
214         cli
215         movw    $ebios_flag, %sp
217         /*
218          * Use a ljmpw here to work around a bug in some unknown version
219          * of gas or ld when it comes to jumping to an absolute symbol...
220          *
221          * Look more closely into it if we ever are short on space.
222          */
223         ljmpw   $0, $isolinux_start_hybrid
225 bad_signature:
226         call    error
227         .ascii  "isolinux.bin missing or corrupt.\r\n"
230  * read_sector: read a single sector pointed to by %eax to %es:%bx.
231  * CF is set on error.  All registers saved.
232  */
233 read_sector:
234         pushal
235         xorl    %edx, %edx
236         addl    (partoffset), %eax
237         adcl    (partoffset+4), %edx
238         pushl   %edx    /* MSW of LBA */
239         pushl   %eax    /* LSW of LBA */
240         pushw   %es     /* Buffer segment */
241         pushw   %bx     /* Buffer offset */
242         pushw   $1      /* Sector count */
243         pushw   $16     /* Size of packet */
244         movw    %sp, %si
246         /* This chunk is skipped if we have ebios */
247         /* Do not clobber %eax before this chunk! */
248         /* This also relies on %bx and %edx as set up above. */
249 read_sector_cbios:
250         divl    (secpercyl)
251         shlb    $6, %ah
252         movb    %ah, %cl
253         movb    %al, %ch
254         xchgw   %dx, %ax
255         divb    (sectors)
256         movb    %al, %dh
257         orb     %ah, %cl
258         incw    %cx     /* Sectors are 1-based */
259         movw    $0x0201, %ax
261 read_common:
262         movb    (driveno), %dl
263         int     $0x13
264         leaw    16(%si), %sp    /* Drop DAPA */
265         popal
266         ret
268 disk_error:
269         call    error
270         .ascii  "Operating system load error.\r\n"
273  * Print error messages.  This is invoked with "call", with the
274  * error message at the return address.
275  */
276 error:
277         popw    %si
279         lodsb
280         movb    $0x0e, %ah
281         movb    (BIOS_page), %bh
282         movb    $0x07, %bl
283         int     $0x10           /* May destroy %bp */
284         cmpb    $10, %al        /* Newline? */
285         jne     2b
287         int     $0x18           /* Boot failure */
288 die:
289         hlt
290         jmp     die
292         /* Address of pointer to isolinux.bin */
293 lba_offset = _start+432