Martin Str|mberg
2017-Mar-24 18:55 UTC
[syslinux] "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
On Fri, Mar 24, 2017 at 05:38:31PM +0100, Thomas Schmitt via Syslinux wrote:> isohdpfc pushes the CX value to the stack which it gets from INT 13 AH 41. > Quite surely bit 0 of that CX is not set. But bit 2 "Enhanced Disk Drive" > could be set. > https://en.wikipedia.org/wiki/INT_13H > > I understand on David's BIOS after > > andw $1,%cx /* Bit 0 = fixed disk subset */ > jz 1f > > jz jumps because CX is 0. This gets pushed to the stack. > (So the code around the int 13 assumes that either int 13 fails and returns > CX == 0, or the reply is good enough to reach "andw 1,%cx". Ewww ...)Well... I'm not quite following you. If it reaches andw 1,%cx then CX will indicate if wanted EBIOS calls are supported or not as the and will mask away all but the interesting bit. The code: /* Check to see if we have EBIOS */ pushw %dx /* drive number */ movb $0x41, %ah /* %al == 0 already */ movw $0x55aa, %bx xorw %cx, %cx xorb %dh, %dh stc int $0x13 jc 1f cmpw $0xaa55, %bx jne 1f andw $1,%cx /* Bit 0 = fixed disk subset */ jz 1f /* We have EBIOS; patch in the following code at read_sector_cbios: movb $0x42, %ah ; jmp read_common */ movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ (read_sector_cbios) jmp 1f 1: This is my interpretation: David's machine's BIOS returns no carry indicating maybe support. However it doesn't set BX to the correct value, so isohdpfx.S jumps to 1f with some flags in CX set. Or David's machine's BIOS returns carry but corrupts CX. My versions of isohdpfc just replaced the first "jc 1f" above with "jnc 1f" or with "jmp 1f", thus in the end possibly indicating EBIOS support to isolinux (assuming weird return status on the EBIOS check). Then I interpret the code in isolinux that when EBIOS calls doesn't work it will fall back to old not extended calls (CBIOS?). That's why it worked after a delay. Your findings in isohdpfx.S made clear it confused/is wrong with regard to order of number of heads and sectors on the stack. Either the declared offsets were wrong or the order of pushes. At that time I choose the order of pushes as the correct way. Good work digging in the code again (isolinux.asm). Yes, it's Intel syntax, or more specifically nasm syntax (in case it matters). Now given your findings in isolinux.asm it seems that previous choice was wrong and the declared offsets were correct. Thus a new patch that corrects the order of pushes (instead of offsets) _and_ setting CX to zero if EBIOS detection fails. Apply it to orginal syslinux code. diff --git a/mbr/isohdpfx.S b/mbr/isohdpfx.S index 17e1efe..14eca14 100644 --- a/mbr/isohdpfx.S +++ b/mbr/isohdpfx.S @@ -151,7 +151,7 @@ next: /* Check to see if we have EBIOS */ pushw %dx /* drive number */ - movb $0x41, %ah /* %al == 0 already */ + movb $0x41, %ah movw $0x55aa, %bx xorw %cx, %cx xorb %dh, %dh @@ -167,20 +167,22 @@ next: read_sector_cbios: movb $0x42, %ah ; jmp read_common */ movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ (read_sector_cbios) - jmp 1f + jmp 2f 1: + xor %cx, %cx /* Clear EBIOS flag. */ +2: popw %dx pushw %cx /* EBIOS flag */ /* Get (C)HS geometry */ movb $0x08, %ah int $0x13 - andw $0x3f, %cx /* Sector count */ popw %bx /* EBIOS flag */ - pushw %cx /* -16: Save sectors on the stack */ movzbw %dh, %ax /* dh = max head */ incw %ax /* From 0-based max to count */ - pushw %ax /* -18: Save heads on the stack */ + pushw %ax /* -16: Save heads on the stack */ + andw $0x3f, %cx /* Sector count */ + pushw %cx /* -18: Save sectors on the stack */ mulw %cx /* Heads*sectors -> sectors per cylinder */ pushw %bx /* -20: EBIOS flag */ I suppose you'd want a .bin as well: <http://www.ludd.ltu.se/~ams/tmp/isohdpfx.bin.170324> -- MartinS
Thomas Schmitt
2017-Mar-24 20:46 UTC
[syslinux] "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
Hi, MartinS wrote:> Well... I'm not quite following you.We only differ whether CX is illfully non-zero and some other register content caused the CBIOS decision, or whether CX was returned rightfully non-zero by David's INT 13 AH 41 with a bit other than bit 0 being set. In my theory, the forcing of pseudo-CBIOS pushed this non-zero CX, which "andw 1,%cx" converts to 0 in the non-forced case before it gets pushed. Whatever, we can see that the first successful test of David was with EBIOS assumption in isolinux.bin, by the texts "CHDD" and "EHDD" of the isolinux.bin messages which David reported in his mail Date: Thu, 23 Mar 2017 17:23:51 -0700 Message-ID: <f7735ce8-c912-fdfc-504e-b1de2f6d86c0 at holgerdanske.com> Failure was with unforced CBIOS in MBR (to my theory with andw reached), popped CX = 0, thus C/H/S addressing: ISOLINUX 6.03 20150819 CHDDisolinux: Image checksum error, sorry... Success was with forced CBIOS in MBR, popped CX != 0, thus LBA addressing: ISOLINUX 6.03 20150819 EHDD Copyright (C) 1994-2014 H. Peter Anvin et al As stated, it is stunning that David's BIOS does LBA addressing fine, but does not advertise it properly in bit 0 of CX by INT 13 AH 41 without possibly other confusing register contents. ------------------------------------------------------------------------> Thus a new patch that corrects the order of pushes (instead of > offsets) _and_ setting CX to zero if EBIOS detection fails. Apply it > to orginal syslinux code.Let's cross fingers that this is without unexpected new side effects. It is appealing, of course, to do all changes in the MBR. It has the same block address 0 in all ISOs. Thus a description how to repair them by a better MBR will be about as complicated as how to copy them onto an USB stick.> <http://www.ludd.ltu.se/~ams/tmp/isohdpfx.bin.170324>May it solve all known C/H/S problems !!! (I downloaded it and am ready to rename it to "isohdpfx_chs_fix.bin" as soon as its success is confirmed.)> <http://www.ludd.ltu.se/~ams/tmp/isodavid.tgz> > It won't boot anything, but it will: > * CXI place my bet on CX value 4. :)) (Or will it say by value 2 that it can eject the stick ?) Have a nice day :) Thomas
Gene Cumm
2017-Mar-26 11:33 UTC
[syslinux] "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
On Fri, Mar 24, 2017 at 2:55 PM, Martin Str|mberg via Syslinux <syslinux at zytor.com> wrote:> On Fri, Mar 24, 2017 at 05:38:31PM +0100, Thomas Schmitt via Syslinux wrote: >> isohdpfc pushes the CX value to the stack which it gets from INT 13 AH 41. >> Quite surely bit 0 of that CX is not set. But bit 2 "Enhanced Disk Drive" >> could be set. >> https://en.wikipedia.org/wiki/INT_13H >> >> I understand on David's BIOS after >> >> andw $1,%cx /* Bit 0 = fixed disk subset */ >> jz 1f >> >> jz jumps because CX is 0. This gets pushed to the stack. >> (So the code around the int 13 assumes that either int 13 fails and returns >> CX == 0, or the reply is good enough to reach "andw 1,%cx". Ewww ...) > > Well... I'm not quite following you. > If it reaches andw 1,%cx then CX will indicate if wanted EBIOS calls > are supported or not as the and will mask away all but the interesting > bit. > > > The code: > /* Check to see if we have EBIOS */ > pushw %dx /* drive number */ > movb $0x41, %ah /* %al == 0 already */ > movw $0x55aa, %bx > xorw %cx, %cx > xorb %dh, %dh > stc > int $0x13 > jc 1f > cmpw $0xaa55, %bx > jne 1f > andw $1,%cx > /* Bit 0 = fixed disk subset */ > jz 1f > > /* We have EBIOS; patch in the following code at > read_sector_cbios: movb $0x42, %ah ; jmp read_common */ > movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ > (read_sector_cbios) > jmp 1f > 1: > > > This is my interpretation: > > David's machine's BIOS returns no carry indicating maybe > support. However it doesn't set BX to the correct value, so isohdpfx.S > jumps to 1f with some flags in CX set. > > Or David's machine's BIOS returns carry but corrupts CX. > > My versions of isohdpfc just replaced the first "jc 1f" above with > "jnc 1f" or with "jmp 1f", thus in the end possibly indicating EBIOS > support to isolinux (assuming weird return status on the EBIOS check). > > Then I interpret the code in isolinux that when EBIOS calls doesn't > work it will fall back to old not extended calls (CBIOS?). That's why > it worked after a delay. > > > Your findings in isohdpfx.S made clear it confused/is wrong with > regard to order of number of heads and sectors on the stack. Either > the declared offsets were wrong or the order of pushes. At that time I > choose the order of pushes as the correct way. > > Good work digging in the code again (isolinux.asm). Yes, it's Intel > syntax, or more specifically nasm syntax (in case it matters). > > Now given your findings in isolinux.asm it seems that previous choice > was wrong and the declared offsets were correct. > > Thus a new patch that corrects the order of pushes (instead of > offsets) _and_ setting CX to zero if EBIOS detection fails. Apply it > to orginal syslinux code. > > diff --git a/mbr/isohdpfx.S b/mbr/isohdpfx.S > index 17e1efe..14eca14 100644 > --- a/mbr/isohdpfx.S > +++ b/mbr/isohdpfx.S > @@ -151,7 +151,7 @@ next: > > /* Check to see if we have EBIOS */ > pushw %dx /* drive number */ > - movb $0x41, %ah /* %al == 0 already */ > + movb $0x41, %ah > movw $0x55aa, %bx > xorw %cx, %cx > xorb %dh, %dh > @@ -167,20 +167,22 @@ next: > read_sector_cbios: movb $0x42, %ah ; jmp read_common */ > movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ > (read_sector_cbios) > - jmp 1f > + jmp 2f > 1: > + xor %cx, %cx /* Clear EBIOS flag. */ > +2: > popw %dx > pushw %cx /* EBIOS flag */ > > /* Get (C)HS geometry */ > movb $0x08, %ah > int $0x13 > - andw $0x3f, %cx /* Sector count */ > popw %bx /* EBIOS flag */ > - pushw %cx /* -16: Save sectors on the stack */ > movzbw %dh, %ax /* dh = max head */ > incw %ax /* From 0-based max to count */ > - pushw %ax /* -18: Save heads on the stack */ > + pushw %ax /* -16: Save heads on the stack */ > + andw $0x3f, %cx /* Sector count */ > + pushw %cx /* -18: Save sectors on the stack */ > mulw %cx /* Heads*sectors -> sectors per cylinder */ > > pushw %bx /* -20: EBIOS flag */Martin/Thomas: Thank you for your troubleshooting efforts. Looks like I jumped a little too soon. I started doing git blame on core/isolinux.asm and mbr/isohdpfx.S and it seems the stack format got set, changed, then mostly reverted back, with this code being the last piece missing from 2009. I started second-guessing if there was yet another but it appears fine. I just want to run some tests. David, thank you for working with them to diagnose your computer. As you're probably aware, diagnosing system-specific bugs are always challenging and finding representative hardware to reproduce an issue isn't always easy (or sometimes even feasible). Finding a system that doesn't seem to properly support LBA/EBIOS reads is increasingly difficult due to age. -- -Gene
Thomas Schmitt
2017-Mar-26 14:45 UTC
[syslinux] "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
Hi, Gene Cumm wrote:> it seems the stack format got > set, changed, then mostly reverted back, with this code being the last > piece missing from 2009.The commit to isohdpfx.S of 2009-05-31 looks incomplete. The sequence of the stack pointers was swapped, but the sequence of stack pushes was not. https://git.kernel.org/pub/scm/boot/syslinux/syslinux.git/commit/mbr/isohdpfx.S?id=2f92affcce5ffef4da90fe44bcac5a4db45df25f> Finding a system that > doesn't seem to properly support LBA/EBIOS reads is increasingly > difficult due to age.It is now easier to force C/H/S for both MBR and isolinux.bin because of the "Clear EBIOS flag" code piece. A isohdpfc with "jmp" instead of "jc" after INT 13 AH 41, derived from the new code would instruct isolinux.bin to use C/H/S addressing, too. I just tested this replacement by locating the "jc" instruction by its neighbor "cmpw $0xaa55, %bx" at byte 88 and changing it to "jmp": echo -n $'\xeb' | dd conv=notrunc bs=1 seek=88 count=1 of="$iso" It still boots in qemu to the first graphical Debian menu. The "ISOLINUX 6.03 ..." messages vanishes too fast for my eyes. So i damage the ISO to prevent booting the Debian payload. For that purpose i obtain the 2048-block address of isolinux.cfg xorriso -indev "$iso" -find /isolinux/isolinux.cfg -exec report_lba -- This reports: Report layout: xt , Startlba , Blocks , Filesize , ISO image path File data lba: 0 , 303939 , 1 , 157 , '/isolinux/isolinux.cfg' I flatten its content block to zero: dd if=/dev/zero conv=notrunc bs=2048 count=1 seek=303939 of="$iso" Now booting by qemu says ISOLINUX 6.03 20150819 CHDD Copyright ...and.so.on... No DEFAULT or UI configuration directive found! boot: "CHDD" confirms that the slightly modified MBR really told isolinux.bin to use C/H/S addressing although SeaBIOS advertises LBA. Our previous qemu experiments with the old MBR code did not bring isolinux.bin to C/H/S so that Martin and i did not see the stack interface problem on the first hand. Have a nice day :) Thomas