1 /* 2 * GRUB -- GRand Unified Bootloader 3 * Copyright (C) 1994-2002 H. Peter Anvin 4 * Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * 20 */ 21 22 /* 23 Most of this file was originally "isolinux.asm" from SYSLINUX package. 24 It has been very heavily modified. 25 */ 26 27 #define ASM_FILE 28 #include "stage1.h" 29 #include "shared.h" 30 #include "iso9660.h" 31 32 #ifndef STAGE1_5 33 #include "stage2_size.h" 34 #endif 35 36 37 /* Absolute addresses 38 This makes the assembler generate the address without support 39 from the linker. (ELF can't relocate 16-bit addresses!) */ 40 #define ABS(x) (x-_start+BOOTSEC_LOCATION) 41 42 #ifdef STAGE1_5 43 # define STAGE_ADDR 0x2000 44 #else 45 # define STAGE_ADDR 0x8000 46 #endif /* STAGE1_5 */ 47 48 /* Print message string */ 49 #define MSG(x) mov $ABS(x), %si; call message; 50 51 .file "start_eltorito.S" 52 53 .text 54 55 /* Tell GAS to generate 16-bit instructions so that this code works 56 in real mode. */ 57 .code16 58 59 .globl start, _start 60 61 /* 62 * Primary entry point. Because BIOSes are buggy, we only load the first 63 * CD-ROM sector (2K) of the file, so the number one priority is actually 64 * loading the rest. 65 */ 66 start: 67 _start: 68 cli 69 ljmp $0, $ABS(real_start) 70 71 . = _start + 8 /* Pad to file offset 8 */ 72 73 /* This table gets filled in by mkisofs using the 74 -boot-info-table option */ 75 bi_pvd: .long 0xDEADBEEF /* LBA of primary volume descript */ 76 bi_file: .long 0xDEADBEEF /* LBA of boot file */ 77 bi_length: .long 0xDEADBEEF /* Length of boot file */ 78 bi_csum: .long 0xDEADBEEF /* Checksum of boot file */ 79 bi_reserved: .space (10*4) /* Reserved */ 80 81 real_start: 82 xor %ax, %ax 83 mov %ax, %ss 84 mov %ax, %ds 85 mov %ax, %es 86 mov %ax, %fs 87 mov %ax, %gs 88 mov $STAGE1_STACKSEG, %sp /* set up the REAL stack */ 89 sti 90 cld 91 92 /* save drive reference first thing! */ 93 mov %dl, ABS(BootDrive) 94 95 /* print a notification message on the screen */ 96 MSG(notification_string) 97 98 load_image: 99 /* Set up boot file sector, size, load address */ 100 mov ABS(bi_length), %eax 101 add $(ISO_SECTOR_SIZE-1), %eax 102 shr $ISO_SECTOR_BITS, %eax /* dwords->sectors */ 103 mov %ax, %bp /* boot file sectors */ 104 mov $(STAGE_ADDR >> 4), %bx 105 mov %bx, %es 106 xor %bx, %bx 107 mov ABS(bi_file), %eax 108 call getlinsec 109 mov %ds, %ax 110 mov %ax, %es 111 112 MSG(notification_done) 113 bootit: 114 /* save the sector number of the second sector in %ebp */ 115 mov $ABS(firstlist - BOOTSEC_LISTSIZE), %si 116 mov (%si), %ebp 117 mov ABS(BootDrive), %dl /* this makes sure %dl is our "boot" drive */ 118 ljmp $0, $(STAGE_ADDR+SECTOR_SIZE) /* jump to main() in asm.S */ 119 120 /* go here when you need to stop the machine hard after an error condition */ 121 stop: jmp stop 122 123 124 /* 125 * Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. 126 * 127 * Note that we can't always do this as a single request, because at least 128 * Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick 129 * to 16 sectors (32K) per request. 130 * 131 * Input: 132 * EAX - Linear sector number 133 * ES:BX - Target buffer 134 * BP - Sector count 135 */ 136 getlinsec: 137 mov $ABS(dapa), %si /* Load up the DAPA */ 138 mov %bx, 4(%si) 139 mov %es, %bx 140 mov %bx, 6(%si) 141 mov %eax, 8(%si) 142 1: 143 push %bp 144 push %si 145 cmp ABS(MaxTransfer), %bp 146 jbe 2f 147 mov ABS(MaxTransfer), %bp 148 2: 149 mov %bp, 2(%si) 150 mov ABS(BootDrive), %dl 151 mov $0x42, %ah /* Extended Read */ 152 call xint13 153 pop %si 154 pop %bp 155 movzwl 2(%si), %eax /* Sectors we read */ 156 add %eax, 8(%si) /* Advance sector pointer */ 157 sub %ax, %bp /* Sectors left */ 158 shl $(ISO_SECTOR_BITS-4), %ax /* 2048-byte sectors -> segment */ 159 add %ax, 6(%si) /* Advance buffer pointer */ 160 161 pushal 162 MSG(notification_step) 163 popal 164 cmp $0, %bp 165 ja 1b 166 mov 8(%si), %eax /* Return next sector */ 167 ret 168 169 /* 170 * INT 13h with retry 171 */ 172 xint13: 173 movb $6, ABS(RetryCount) 174 pushal 175 .try: 176 int $0x13 177 jc 1f 178 add $(8*4), %sp /* Clean up stack */ 179 ret 180 1: 181 mov %ah, %dl /* Save error code */ 182 decb ABS(RetryCount) 183 jz .real_error 184 mov ABS(RetryCount), %al 185 mov ABS(dapa+2), %ah /* Sector transfer count */ 186 cmp $2, %al /* Only 2 attempts left */ 187 ja 2f 188 mov $1, %ah /* Drop transfer size to 1 */ 189 jmp .setmaxtr 190 2: 191 cmp $3, %al 192 ja 3f /* First time, just try again */ 193 shr $1, %ah /* Otherwise, try to reduce */ 194 adc $0, %ah /* the max transfer size, but not */ 195 .setmaxtr: 196 mov %ah, ABS(MaxTransfer) 197 mov %ah, ABS(dapa+2) 198 3: 199 popal 200 jmp .try 201 202 .real_error: 203 MSG(read_error_string) 204 mov %dl, %al 205 call printhex2 206 popal 207 jmp stop 208 209 210 211 /* 212 * message: write the string pointed to by %si 213 * 214 * WARNING: trashes %si, %ax, and %bx 215 */ 216 217 /* 218 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode 219 * %ah = 0xe %al = character 220 * %bh = page %bl = foreground color (graphics modes) 221 */ 222 1: 223 mov $0x0001, %bx 224 mov $0x0E, %ah 225 int $0x10 /* display a byte */ 226 227 message: 228 lodsb 229 or %al, %al 230 jne 1b /* if not end of string, jmp to display */ 231 ret 232 233 /* 234 * printhex[248]: Write a hex number in (AL, AX, EAX) to the console 235 */ 236 printhex2: 237 pushal 238 rol $24, %eax 239 mov $2, %cx 240 jmp 1f 241 printhex4: 242 pushal 243 rol $16, %eax 244 mov $4, %cx 245 jmp 1f 246 printhex8: 247 pushal 248 mov $8, %cx 249 1: 250 rol $4, %eax 251 push %eax 252 and $0x0F, %al 253 cmp $10, %al 254 jae .high 255 .low: add $('0'), %al 256 jmp 2f 257 .high: add $('A'-10), %al 258 2: 259 mov $0x0001, %bx 260 mov $0x0E, %ah 261 int $0x10 /* display a char */ 262 pop %eax 263 loop 1b 264 popal 265 ret 266 267 /**************************************************************************/ 268 #ifdef STAGE1_5 269 notification_string: .string "Loading stage1.5 " 270 #else 271 notification_string: .string "Loading stage2 " 272 #endif 273 274 notification_step: .string "." 275 notification_done: .string "\r\n" 276 277 read_error_string: .string "Read error 0x" 278 279 /* 280 * EBIOS disk address packet 281 */ 282 .align 8 283 dapa: .byte 16 /* Packet size */ 284 .byte 0 /* reserved */ 285 .word 0 /* +2 Block count */ 286 .word 0 /* +4 Offset of buffer */ 287 .word 0 /* +6 Segment of buffer */ 288 .long 0 /* +8 LBA (LSW) */ 289 .long 0 /* +C LBA (MSW) */ 290 291 VARIABLE(BootDrive) 292 .byte 0xFF 293 VARIABLE(MaxTransfer) 294 .word 16 /* Max sectors per transfer (32Kb) */ 295 VARIABLE(RetryCount) 296 .byte 0 297 298 299 /* 300 * This area is an empty space between the main body of code below which 301 * grows up (fixed after compilation, but between releases it may change 302 * in size easily), and the lists of sectors to read, which grows down 303 * from a fixed top location. 304 */ 305 306 .word 0 307 .word 0 308 309 . = _start + SECTOR_SIZE - BOOTSEC_LISTSIZE 310 311 /* fill the first data listing with the default */ 312 blocklist_default_start:/* this is the sector start parameter, in logical 313 sectors from the start of the disk, sector 0 */ 314 .long 0 315 316 blocklist_default_len: /* this is the number of sectors to read */ 317 #ifdef STAGE1_5 318 .word 0 319 #else 320 .word (STAGE2_SIZE + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_BITS 321 #endif 322 blocklist_default_seg: /* this is the segment of the starting address 323 to load the data into */ 324 .word (STAGE_ADDR + SECTOR_SIZE) >> 4 325 326 firstlist: /* this label has to be after the list data!!! */ 327