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 * ----------------------------------------------------------------------- */ 28 29 /* 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 */ 36 37 #include "adjust.h" 38 39 .code16 40 .text 41 42 HYBRID_MAGIC = 0x7078c0fb 43 isolinux_hybrid_signature = 0x7c00+64 44 isolinux_start_hybrid = 0x7c00+64+4 45 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) 55 56 BIOS_kbdflags = 0x417 57 BIOS_page = 0x462 58 59 /* gas/ld has issues with doing this as absolute addresses... */ 60 .section ".bootsec", "a", @nobits 61 .globl bootsec 62 bootsec: 63 .space 512 64 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 105 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 125 126 /* We have non-GPT partition information */ 127 2: 128 movl 8(%si), %ecx 129 #endif 130 1: 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 */ 136 137 movw %bp, %ds 138 movw %bp, %es 139 140 ADJUST_DRIVE 141 pushw %dx /* -14: dl -> drive number */ 142 143 /* Copy down to 0:0x600 */ 144 movw $0x7c00, %si 145 movw $_start, %di 146 movw $(512/2), %cx 147 rep; movsw 148 149 ljmpw $0, $next 150 next: 151 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 165 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 171 1: 172 popw %dx 173 pushw %cx /* EBIOS flag */ 174 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 */ 185 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 */ 191 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 199 200 2: 201 call read_sector 202 jc disk_error 203 incl %eax 204 addb $(512 >> 8), %bh 205 loopw 2b 206 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 213 214 cli 215 movw $ebios_flag, %sp 216 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 224 225 bad_signature: 226 call error 227 .ascii "isolinux.bin missing or corrupt.\r\n" 228 229 /* 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 245 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 260 261 read_common: 262 movb (driveno), %dl 263 int $0x13 264 leaw 16(%si), %sp /* Drop DAPA */ 265 popal 266 ret 267 268 disk_error: 269 call error 270 .ascii "Operating system load error.\r\n" 271 272 /* 273 * Print error messages. This is invoked with "call", with the 274 * error message at the return address. 275 */ 276 error: 277 popw %si 278 2: 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 286 287 int $0x18 /* Boot failure */ 288 die: 289 hlt 290 jmp die 291 292 /* Address of pointer to isolinux.bin */ 293 lba_offset = _start+432 294