ISOLINUX: support for hybrid mode (CD-ROM/USB key)
[syslinux.git] / mbr / isohdpfx.S
blobf2bc7dc6b87c61444d07459438776f0d419d5d16
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  * ----------------------------------------------------------------------- */
29  * Modified MBR code used on an ISO image in hybrid mode.
30  *
31  * This doesn't follow the El Torito spec at all -- it is just a stub
32  * loader of a hard-coded offset, but that's good enough to load
33  * ISOLINUX.
34  */
35         
36         .code16
37         .text
39 HYBRID_MAGIC                    = 0x7078c0fb
40 isolinux_hybrid_signature       = 0x7c00+64
41 isolinux_start_hybrid           = 0x7c00+64+4
43         .globl  bootsec
44 /* Important: the top 6 words on the stack are passed to isolinux.bin */
45 stack           = 0x7c00
46 driveno         = (stack-6)
47 sectors         = (stack-8)
48 heads           = (stack-10)
49 secpercyl       = (stack-14)
51 BIOS_page = 0x462
53         /* gas/ld has issues with doing this as absolute addresses... */
54         .section ".bootsec", "a", @nobits
55         .globl  bootsec
56 bootsec:
57         .space  512
59         .text
60         .globl  _start
61 _start:
63         cli
64         xorw    %ax, %ax
65         movw    %ax, %ds
66         movw    %ax, %ss
67         movw    $stack, %sp
68         movw    %sp, %si
69         pushw   %es             /* es:di -> $PnP header */
70         pushw   %di
71         pushw   %dx             /* dl -> drive number */
72         movw    %ax, %es
73         sti
74         cld
76         /* Copy down to 0:0x600 */
77         movw    $_start, %di
78         movw    $(512/2), %cx
79         rep; movsw
81         ljmpw   $0, $next
83 next:
84         /* Check to see if we have EBIOS */
85         pushw   %dx             /* drive number */
86         movb    $0x41, %ah      /* %al == 0 already */
87         movw    $0x55aa, %bx
88         xorw    %cx, %cx
89         xorb    %dh, %dh
90         stc
91         int     $0x13
92         jc      1f
93         cmpw    $0xaa55, %bx
94         jne     1f
95         shrw    %cx             /* Bit 0 = fixed disk subset */
96         jnc     1f
98         /* We have EBIOS; patch in the following code at
99            read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
100         movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
101                 (read_sector_cbios)
104         popw    %dx
106         /* Get (C)HS geometry */
107         movb    $0x08, %ah
108         int     $0x13
109         andw    $0x3f, %cx      /* Sector count */
110         pushw   %cx             /* Save sectors on the stack */
111         movzbw  %dh, %ax        /* dh = max head */
112         incw    %ax             /* From 0-based max to count */
113         pushw   %ax             /* Save heads on the stack */
114         mulw    %cx             /* Heads*sectors -> sectors per cylinder */
116         /* Save sectors/cylinder on the stack */
117         pushw   %dx             /* High word */
118         pushw   %ax             /* Low word */
120         /*
121          * Load sectors.  We do this one at a time mostly to avoid
122          * pitfalls and to share code with the stock MBR code.
123          */
124         movw    $0x7c00, %bx
125         movw    $4, %cx         /* Sector count */
126         movl    (lba_offset), %eax
129         call    read_sector
130         jc      disk_error
131         incl    %eax
132         addw    $512, %bx
133         loopw   2b
135         /*
136          * Okay, that actually worked... update the stack pointer
137          * and jump into isolinux.bin...
138          */
139         cmpl    $HYBRID_MAGIC,(isolinux_hybrid_signature)
140         jne     bad_signature
141         
142         cli
143         movw    $heads, %sp
144         jmp     isolinux_start_hybrid
146 bad_signature:
147         call    error
148         .ascii  "isolinux.bin missing or corrupt.\r\n"
151  * read_sector: read a single sector pointed to by %eax to %es:%bx.
152  * CF is set on error.  All registers saved.
153  */
154 read_sector:
155         pushal
156         xorl    %edx, %edx
157         pushl   %edx    /* MSW of LBA */
158         pushl   %eax    /* LSW of LBA */
159         pushw   %es     /* Buffer segment */
160         pushw   %bx     /* Buffer offset */
161         pushw   $1      /* Sector count */
162         pushw   $16     /* Size of packet */
163         movw    %sp, %si
165         /* This chunk is skipped if we have ebios */
166         /* Do not clobber %eax before this chunk! */
167         /* This also relies on %bx and %edx as set up above. */
168 read_sector_cbios:
169         divl    (secpercyl)
170         shlb    $6, %ah
171         movb    %ah, %cl
172         movb    %al, %ch
173         xchgw   %dx, %ax
174         divb    (sectors)
175         movb    %al, %dh
176         orb     %ah, %cl
177         incw    %cx     /* Sectors are 1-based */
178         movw    $0x0201, %ax
180 read_common:
181         movb    (driveno), %dl
182         int     $0x13
183         addw    $16, %sp        /* Drop DAPA */
184         popal
185         ret
187 disk_error:
188         call    error
189         .ascii  "Operating system load error.\r\n"
192  * Print error messages.  This is invoked with "call", with the
193  * error message at the return address.
194  */
195 error:
196         popw    %si
198         lodsb
199         movb    $0x0e, %ah
200         movb    (BIOS_page), %bh
201         movb    $0x07, %bl
202         int     $0x10           /* May destroy %bp */
203         cmpb    $10, %al        /* Newline? */
204         jne     2b
206         int     $0x18           /* Boot failure */
207 die:
208         hlt
209         jmp     die
211         /* Address of pointer to isolinux.bin */
212 lba_offset = _start+432