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 */ 66start: 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 */ 75bi_pvd: .long 0xDEADBEEF /* LBA of primary volume descript */ 76bi_file: .long 0xDEADBEEF /* LBA of boot file */ 77bi_length: .long 0xDEADBEEF /* Length of boot file */ 78bi_csum: .long 0xDEADBEEF /* Checksum of boot file */ 79bi_reserved: .space (10*4) /* Reserved */ 80 81real_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 98load_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) 113bootit: 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 */ 121stop: 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 */ 136getlinsec: 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) 1421: 143 push %bp 144 push %si 145 cmp ABS(MaxTransfer), %bp 146 jbe 2f 147 mov ABS(MaxTransfer), %bp 1482: 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 */ 172xint13: 173 movb $6, ABS(RetryCount) 174.try: 175 pushal 176 int $0x13 177 jc 1f 178 add $(8*4), %sp /* Clean up stack */ 179 ret 1801: 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 1902: 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) 1983: 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 */ 2221: 223 mov $0x0001, %bx 224 mov $0x0E, %ah 225 int $0x10 /* display a byte */ 226 227message: 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 */ 236printhex2: 237 pushal 238 rol $24, %eax 239 mov $2, %cx 240 jmp 1f 241printhex4: 242 pushal 243 rol $16, %eax 244 mov $4, %cx 245 jmp 1f 246printhex8: 247 pushal 248 mov $8, %cx 2491: 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 2582: 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 269notification_string: .string "Loading stage1.5 " 270#else 271notification_string: .string "Loading stage2 " 272#endif 273 274notification_step: .string "." 275notification_done: .string "\r\n" 276 277read_error_string: .string "Read error 0x" 278 279/* 280 * EBIOS disk address packet 281 */ 282 .align 8 283dapa: .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 291VARIABLE(BootDrive) 292 .byte 0xFF 293VARIABLE(MaxTransfer) 294 .word 16 /* Max sectors per transfer (32Kb) */ 295VARIABLE(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 */ 312blocklist_default_start:/* this is the sector start parameter, in logical 313 sectors from the start of the disk, sector 0 */ 314 .long 0 315 316blocklist_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 322blocklist_default_seg: /* this is the segment of the starting address 323 to load the data into */ 324 .word (STAGE_ADDR + SECTOR_SIZE) >> 4 325 326firstlist: /* this label has to be after the list data!!! */ 327