[syslinux] "isolinux.bin missing or corrupt" when booting USB flash drive in old PC

Gene Cumm
Sun, 26 Mar 2017 11:33:39 -0000

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