2006-02-24 19:14:49

by Andrey Borzenkov

[permalink] [raw]
Subject: "Ghost" devices in /sys/firmware/edd

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I have single drive hda; still EDD shows valid and the _same_ MBR signature
for all possible 16 drives:

{pts/0}% cat /sys/firmware/edd/*/mbr_*
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a
0x7fca3a0a

other attributes are correctly present for the drive 0x80 only.

Not being expert in x86 assembly, but comparing main loops for signature and
other info:

signature:
int $0x13
sti # work around buggy BIOSes
popw %dx
popw %es
popw %bx
jc edd_mbr_sig_done # on failure, we're done.

extended EDD info:

edd_check_ext:
movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
movw $EDDMAGIC1, %bx # magic
int $0x13 # make the call
jc edd_done # no more BIOS devices

Is it possible that carry flag is cleared between return from int 0x13 and
querying for it in the former case? This would perfectly explain that EDD
does not notice failure of reading sector and simply copies the same
signature from the very first drive.

- -andrey
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (GNU/Linux)

iD8DBQFD/1smR6LMutpd94wRAncjAJ0b9wLmKK9V2bc93ghAIUa7dY5VWQCfZ8BP
aiT8y5TX3DE05ZN8wfnfg7E=
=uB1I
-----END PGP SIGNATURE-----


2006-02-25 05:07:51

by Matt Domsch

[permalink] [raw]
Subject: Re: "Ghost" devices in /sys/firmware/edd

On Fri, Feb 24, 2006 at 10:14:34PM +0300, Andrey Borzenkov wrote:
> I have single drive hda; still EDD shows valid and the _same_ MBR signature
> for all possible 16 drives:
>
> {pts/0}% cat /sys/firmware/edd/*/mbr_*
> 0x7fca3a0a
> 0x7fca3a0a
> 0x7fca3a0a
[snip]
>
> other attributes are correctly present for the drive 0x80 only.
>
> Not being expert in x86 assembly, but comparing main loops for signature and
> other info:
>
> signature:
> int $0x13
> sti # work around buggy BIOSes
> popw %dx
> popw %es
> popw %bx
> jc edd_mbr_sig_done # on failure, we're done.

The code here is fine. Immediately before the int13 is an stc
instruction, so the carry flag is set. sti and popw don't change CF.
What this means is that your BIOS cleared CF in the int13 to a
nonexistant disk, rather than setting CF (or leaving it unchanged).
CF being clear means the command succeeded. In your case, the BIOS
cleared it, but shouldn't have.

Care to share your system type / BIOS version, and if it's at all
recent, file an bug with their support department?


> extended EDD info:
>
> edd_check_ext:
> movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
> movw $EDDMAGIC1, %bx # magic
> int $0x13 # make the call
> jc edd_done # no more BIOS devices
>

Yet, it does properly set CF on int13 AH=41h to a nonexistant disk.
How annoying.


> Is it possible that carry flag is cleared between return from int 0x13 and
> querying for it in the former case? This would perfectly explain that EDD
> does not notice failure of reading sector and simply copies the same
> signature from the very first drive.

I'll look more next week, but what isn't ever happening is an int13
AH=15h GET DISK TYPE probe to see if the disk is there. The edd.S
code just issue a READ SECTORS and expects that to fail (to set CF) if
it's not there. This has been working fine for most people. In your
case, it's not reporting a failure (CF is cleared by the int13). Now,
there's no guarantee your BIOS would respond properly to the GET DISK
TYPE command either. There are also notes that BIOS should set
0040h:0075h to the number of drives present, and the code isn't
reading that value now either. Either of these tests, if the BIOS
isn't buggy for them, could result in reporting the right number of
disks.

Thanks much for the report and for digging to find where the mistake
could be.

Thanks,
Matt

--
Matt Domsch
Software Architect
Dell Linux Solutions linux.dell.com & http://www.dell.com/linux
Linux on Dell mailing lists @ http://lists.us.dell.com

2006-02-25 14:26:29

by Andrey Borzenkov

[permalink] [raw]
Subject: Re: "Ghost" devices in /sys/firmware/edd

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Saturday 25 February 2006 08:07, Matt Domsch wrote:
[...]
> The code here is fine. Immediately before the int13 is an stc
> instruction, so the carry flag is set. sti and popw don't change CF.
> What this means is that your BIOS cleared CF in the int13 to a
> nonexistant disk, rather than setting CF (or leaving it unchanged).
> CF being clear means the command succeeded. In your case, the BIOS
> cleared it, but shouldn't have.
>
> Care to share your system type / BIOS version, and if it's at all
> recent, file an bug with their support department?
>

This is Toshiba Portege 4000, BIOS 2.10 dated 15 Dec 2003. I'll try to find
how to submit a bug report but I do not hold my breath.

[...]
>
> I'll look more next week, but what isn't ever happening is an int13
> AH=15h GET DISK TYPE probe to see if the disk is there. The edd.S
> code just issue a READ SECTORS and expects that to fail (to set CF) if
> it's not there. This has been working fine for most people. In your
> case, it's not reporting a failure (CF is cleared by the int13). Now,
> there's no guarantee your BIOS would respond properly to the GET DISK
> TYPE command either. There are also notes that BIOS should set
> 0040h:0075h to the number of drives present, and the code isn't
> reading that value now either. Either of these tests, if the BIOS
> isn't buggy for them, could result in reporting the right number of
> disks.
>

More simple solution may be the patch below. I am not sure if INT13 succeeded
is always the same as status == 0; there appears to be at least one corner
case 11h == "data ECC corrected".

The patch fixed the issue here.

regards

- -andrey

Subject: [PATCH] Fix EDD to properly ignore signature of non-existing drives

From: Andrey Borzenkov <[email protected]>

Some BIOSes do not always set CF on error before return from int13.
The patch adds additional check for status being zero (AH == 0).

Signed-off-by: Andrey Borzenkov <[email protected]>

- ---

arch/i386/boot/edd.S | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
index d8d69f2..4b84ea2 100644
- --- a/arch/i386/boot/edd.S
+++ b/arch/i386/boot/edd.S
@@ -76,6 +76,8 @@ edd_mbr_sig_read:
popw %es
popw %bx
jc edd_mbr_sig_done # on failure, we're done.
+ cmpb $0, %ah # some BIOSes do not set CF
+ jne edd_mbr_sig_done # on failure, we're done.
movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
movl %eax, (%bx) # store success
incb (EDD_MBR_SIG_NR_BUF) # note that we stored something
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (GNU/Linux)

iD8DBQFEAGkPR6LMutpd94wRAocYAJ4mRhgW0UOoK2+0bfQsh0+s1nUyIgCdGRrF
UCJpkIEPVEuUE2Gnfe7mG/Q=
=ij5i
-----END PGP SIGNATURE-----