# --- T2-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # T2 SDE: package/.../grub/usb-cd.patch # Copyright (C) 2011 The T2 SDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- T2-COPYRIGHT-NOTE-END --- Some Phoenix / Award BIOS does corrupt itself, if the disk system reset or version query is called when booting from an USB CD-ROM. Strangely, however, those Phoenix/Award BIOS did work fine booting from an internal IDE CD. Whatever. Avoid said calls and additionally incorporated another Award BIOS fix, searching for an instruction sequence and extracting the call address, as well as hardened reading (retry including decreased sizes, also inspired by isolinux) and check the carry flag to pro- actively further help potentially broken BIOSes, as there are so many of those, ... - Rene Rebe diff -ur grub-0.97/stage2/asm.S grub-0.97-fixed/stage2/asm.S --- grub-0.97/stage2/asm.S 2004-06-19 18:55:22.000000000 +0200 +++ grub-0.97-fixed/stage2/asm.S 2007-09-30 15:35:34.000000000 +0200 @@ -139,7 +139,7 @@ ADDR32 movb %dl, EXT_C(boot_drive) /* reset disk system (%ah = 0) */ - int $0x13 + /* int $0x13 */ /* appears to confuse Phoenix/Award BIOS with USB CDs -ReneR */ #endif /* transition to protected mode */ @@ -971,7 +1060,10 @@ movw %bx, %ax movw %cx, %ds int $0x13 /* do the operation */ - movb %ah, %dl /* save return value */ + jc 1f /* carry flag indicates error -ReneR */ + xor %ah, %ah /* no error: clearn ah just in case, ... */ +1: movb %ah, %dl /* save return value */ + /* clear the data segment */ xorw %ax, %ax movw %ax, %ds diff -ur grub-0.97/stage2/bios.c grub-0.97-fixed/stage2/bios.c --- grub-0.97/stage2/bios.c 2004-03-27 17:34:04.000000000 +0100 +++ grub-0.97-fixed/stage2/bios.c 2007-09-30 15:40:29.000000000 +0200 @@ -61,27 +61,54 @@ unsigned long buffer; unsigned long long block; } __attribute__ ((packed)) dap; + + int retry_count = 4; + + while (nsec > 0 && retry_count > 0) { - /* XXX: Don't check the geometry by default, because some buggy - BIOSes don't return the number of total sectors correctly, - even if they have working LBA support. Hell. */ + /* XXX: Don't check the geometry by default, because some buggy + BIOSes don't return the number of total sectors correctly, + even if they have working LBA support. Hell. */ #ifdef NO_BUGGY_BIOS_IN_THE_WORLD - if (sector >= geometry->total_sectors) - return BIOSDISK_ERROR_GEOMETRY; + if (sector >= geometry->total_sectors) + return BIOSDISK_ERROR_GEOMETRY; #endif /* NO_BUGGY_BIOS_IN_THE_WORLD */ - - /* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler - can't add any padding. */ - dap.length = sizeof (dap); - dap.block = sector; - dap.blocks = nsec; - dap.reserved = 0; - /* This is undocumented part. The address is formated in - SEGMENT:ADDRESS. */ - dap.buffer = segment << 16; + + + /* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler + can't add any padding. */ + dap.length = sizeof (dap); + dap.block = sector; + switch (retry_count) { + case 1: + dap.blocks = 1; break; + case 2: + dap.blocks = nsec / 2; break; + default: + dap.blocks = nsec; + } + dap.reserved = 0; + /* This is undocumented part. The address is formated in + SEGMENT:ADDRESS. */ + dap.buffer = segment << 16; + + err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap); + + if (err && ! geometry->flags & BIOSDISK_FLAG_CDROM) + break; /* only retry for CD-ROMs */ + if (err) { + printf ("biosdisk: err: %x\n", (int) err); + --retry_count; + } + + if (!err) { + sector += dap.blocks; + nsec -= dap.blocks; + segment += geometry->sector_size / 16; /* 16 bytes per segment */ + retry_count = 3; /* refresh on success */ + } + } - err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap); - /* #undef NO_INT13_FALLBACK */ #ifndef NO_INT13_FALLBACK if (err) @@ -142,11 +168,42 @@ unsigned char heads; unsigned char dummy[16]; - } __attribute__ ((packed)) cdrp; + } __attribute__ ((packed)) cdrp __attribute__ ((aligned(8))); grub_memset (&cdrp, 0, sizeof (cdrp)); cdrp.size = sizeof (cdrp) - sizeof (cdrp.dummy); err = biosdisk_int13_extensions (0x4B01, drive, &cdrp); + + /* On error try to find a broken Award BIOS, idea and signature from isolinux. + -ReneR */ +#if !defined(NO_BUGGY_BIOS_IN_THE_WORLD) && defined(FSYS_ISO9660) + if (err || cdrp.drive_no != drive) + { + const char award_string [] = { 0xb8,1,2,0xbb,0,0x7c,0xb9,6,0,0xba,0x80,1,0x9c,0x9a }; + char* bios_addr; + + /* printf ("get_cdinfo: failed. Searching for broken Award BIOS signature ...\n"); */ + for (bios_addr = (char*)0xf0000; bios_addr < (char*) 0xfffff; ++bios_addr) + if (grub_memcmp (bios_addr, award_string, sizeof (award_string)) == 0) + break; + + if (bios_addr != (void*)0xfffff) + { + void** int13_vector = (void**) (0x13 * 4); + void** call_addr = (void**)(bios_addr + 0x0e); + + /* printf ("get_cdinfo: found Award signature @ %x\n", bios_addr); */ + if (*int13_vector != *call_addr) { + printf ("get_cdinfo: patching INT13 old: %x new: %x\n", *int13_vector, *call_addr); + + *int13_vector = *call_addr; + err = biosdisk_int13_extensions (0x4B01, drive, &cdrp); + } + /* else + printf ("get_cdinfo: INT13 already pointing to same entry.\n"); */ + } + } +#endif if (! err && cdrp.drive_no == drive) { if ((cdrp.media_type & 0x0F) == 0)