Jump to content











Photo
- - - - -

get the disk capacity/size using grub4dos and the bios utility

grub4dos disk size

  • Please log in to reply
32 replies to this topic

#1 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 28 March 2015 - 07:56 PM

Here is a way to get the number of sectors on a disk and thus it's total capacity and last accessible sector.

It requires the bios grub4dos program from the grubutils pack.

echo xxxxxxxxxxxxxxxxxxxxxxxxx > (md)0x300+1
# set buffer to 0 in case bios call fails
write 0x60010 0
# get number of sectors from INT 13h AH=48 into memory at DS:SI+10h  - edx=80h is hard disk 0, 81h would be hard disk 1
/bios int=0x13 eax=0x4800 edx=0x80 ds=0x6000 esi=0x0 > nul
read 0x60010 > nul
set /A END=%@retval%-1 > nul
if %END%<=0 echo Drive too big! && exit

Note that END will be the last accessible sector (LBA number) - e.g. if the disk had only 1 sector then the last accessible sector would be LBA 0.

If the bios call fails, END will be -1.

If the drive is very large, then although read returns a 64-bit number, set /A only works with signed 32-bit numbers, so with large USB drives of over 7FFFFFFF sectors (=1TB), END will be negative! You need to be careful when doing any maths if that is the case - I just give up if the drive is over 1TB!

 

DS:EDI = 6000:0  which is 0x60000 in memory. This is equivalent to (md)0x300 and is a safe work area to use within grub4dos.

 

The BIOS call int13 AH=48h places various values into memory at this address, with the number of sectors at offset 10h.

 

[Edit: 1st line added as bios call fails without it]

[Edit2: Use write 0x60000 0x42 instead of the echo xxx line would be more correct as the buffer size needs to be specified before the call is made]


Edited by steve6375, 15 March 2016 - 09:53 AM.


#2 DavidB

DavidB

    Silver Member

  • Developer
  • 611 posts

Posted 29 March 2015 - 03:02 AM

That looks interesting.

 

Thank you.

 

 

Late edit: strange, it's returning "Drive too big!" even for a 58.6 GB disk. So, not even near to 1 TB.
It doesn't matter if I try on the real computer or on VirtualBox/Qemu, if I try with Grub4Dos 0.4.5c or 0.4.6a version or if I try with my real USB disk or with a virtual one.

 

USB Boot test.png

 

"END" is is 0xFFF...FFF.

Also the link to grubutils pack is actually to this thread. I had to use my bios utility (3704 B), hope it is the last version...



#3 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 09:00 AM

Actually, during testing of this, I found that I when I read the last sectors of a USB drive using VBox+VMUB, it returned the wrong sector data.

I still haven't figured out what is going wrong. It seems to be cacheing/buffering because sometimes if i access a sector well inside the USB drive and then access a sector near the end of the drive, it does return the correct sector data for the same last sector.

(I did have a screenshot showing this but I have lost it)

I looked at the vmdk file made by VMUB and the  CHS parameters for the drive geometry looked to be too small (the total sectors was correct).

However, even when I edited them, VBox still returned the wrong sector data.

I also can seem to read sectors past the physical end of the disk...

That is why I say to use are real system in my recent blog post concerning HitManPro.



#4 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 09:05 AM

That looks interesting.

 

Thank you.

 

 

Late edit: strange, it's returning "Drive too big!" even for a 58.6 GB disk. So, not even near to 1 TB.
It doesn't matter if I try on the real computer or on VirtualBox/Qemu, if I try with Grub4Dos 0.4.5c or 0.4.6a version or if I try with my real USB disk or with a virtual one.

 

attachicon.gifUSB Boot test.png

 

"END" is is 0xFFF...FFF.

Also the link to grubutils pack is actually to this thread. I had to use my bios utility (3704 B), hope it is the last version...

I fixed the link

 

The version of bios I used is in Easy2Boot  \_ISO\e2b\grub folder.

 

try removing the > nul bits to see what is going on



#5 DavidB

DavidB

    Silver Member

  • Developer
  • 611 posts

Posted 29 March 2015 - 09:30 AM

It doesn't matter if I try on the real computer

 

Internal HDD 500 GB.jpg

 

USB disk 58.6 GB.jpg

 

Looks like the Bios calls fails...



#6 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 09:31 AM

I found the problem!

Rather strange - the code I presented was a fraction of the whole code I used for HitManPro.

 

If you start with the line

echo xxxxxxxxxxxxxxxxxxxxxxxxx > (md)0x300+1

then it works!  I am not sure why at this point...



#7 DavidB

DavidB

    Silver Member

  • Developer
  • 611 posts

Posted 29 March 2015 - 09:34 AM

ok, I'll reboot to test.

 

LE: BTW, I added this line at the end "echo HDD size is %END% && pause" and removed the previous exit.

 

LLE: Yes, with your late fix seems to work now. For my 500 GB internal HDD returned 0x3A38602F sectors = 976773167 sectors. Multiplied with 512 B /s = 500107861504 B = 465.76 GB (correct value).

 

Well done, thank you :)



#8 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 09:52 AM

The returned value from the bios call is the total number of sectors

I subtract 1 to get the LBA of the last sector on the disk.

So END is the last sector on the disk not the size (which will be 1 sector more).

 

It seems that the buffer area needs to have non-zero values in bytes 1 and 2 of the buffer area...

I don't think this is anything to do with the BIOS call, it may be a problem with  the 'bios' code or grub4dos???

Disabling auto-decompression using write 0x82a4 1  does not fix it, so not sure why it needs the buffer area to be preset???



#9 DavidB

DavidB

    Silver Member

  • Developer
  • 611 posts

Posted 29 March 2015 - 10:04 AM

Maybe that area it's used by some grub4dos/bios code, try with a much higher memory area, like 0x19000 and above.

I use 0x19000 to load all my menu and  batch files in RAM (as a single file) and I've never had problems on dozens of computer configurations.

 

LE: I was talking about the "(md)0x300+1" from the fix...



#10 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 11:08 AM

this BIOS call only works below 1MB as in real mode.

I get same issue using a different memory area e.g. 8000:0

I  have reported it as an Issue - lets see if chenall, et al. can figure it out...



#11 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 29 March 2015 - 12:03 PM

Nice! :thumbsup:

 

Do I get it right that if one issues something *like*:

cat --hex --length=8 --skip=16 (md)0x300+1

 

The whole 64 bit value is displayed?

 

:duff:

Wonko



#12 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 12:05 PM

read returns a whole 64-bit value 32-bit value, the problem is that any calculation uses signed 32-bit arithmetic.


Edited by steve6375, 30 March 2015 - 11:51 AM.


#13 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 12:06 PM

Even neater...

!BAT
# Get Drive Bus and Drive Type from BIOS
set DRIVE=0
call :gettype
set DRIVE=1
call :gettype
set DRIVE=2
call :gettype
exit
:gettype
# OLD CODE 
#echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > (md)0x300+1
# BETTER CODE
write 0x60000 0x42
/%grub%/bios int=0x13 eax=0x4800 edx=0x8%DRIVE% ds=0x6000 edi=0x0 > nul
read 0x60010 > nul
#24h  4 BYTEs   ASCIZ name of host bus ("ISA" or "PCI")
#28h  8 BYTEs   ASCIZ name of interface type
#"ATA"
#"ATAPI"
#"SCSI"
#"USB"
#"1394" IEEE 1394 (FireWire)
#"FIBRE" Fibre Channel
set BUS= && set DTYPE=
cat --locate=PCI --skip=0x24 --length=4 (md)0x300+1 > nul && set BUS=PCI
cat --locate=ISA --skip=0x24 --length=4 (md)0x300+1 > nul && set BUS=ISA
cat --locate=USB --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=USB
cat --locate="ATA  " --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=ATA
cat --locate=ATAPI --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=ATAPI
cat --locate=USB --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=USB
cat --locate=SCSI --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=SCSI
cat --locate=1394 --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=IEEE_1394
cat --locate=FIBRE --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=FIBRE_CHANNEL
echo Drive %DRIVE% = %BUS% %DTYPE%
goto :eof

P.S. Only works for BIOS controlled drives, so does not report anything for USB drives if using the Plop! or grub4dos USB driver because they don't implement the BIOS call fully.


Edited by steve6375, 30 March 2015 - 11:52 AM.


#14 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 29 March 2015 - 01:08 PM

read returns a whole 64-bit value, the problem is that any calculation uses signed 32-bit arithmetic.

I understand, but if the data is there then maybe it can be manipulated by a specially written batch.

Ultimately, if I get this right, the problem is that of converting a 64 bit hex number into a decimal value, so that the size of the device is displayed in a more human friendly way.

Or may be it would be time to start writing some "real" grub4dos program.  :unsure:

 

:duff:

Wonko



#15 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 01:41 PM

!BAT
# Get disk capacity (up to 2TB only)
echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > (md)0x300+1
write 0x60010 0 > nul
# get size of disk from INT 13h AH=48 into memory at DS:DI+10h  - edx=80h is hard disk 0, 81h would be hard disk 1
/%grub%/bios int=0x13 eax=0x4800 edx=0x80 ds=0x6000 edi=0x0 > nul
read 0x60014  > nul
if not %@retval%==0 echo Sorry - Drive is over 2TB! && exit
read 0x60010  > nul
set /A SIZE= %@retval% > nul
set /A SIGN=%SIZE% & 0x80000000 > nul
set /A SIZE=%SIZE% & 0x7fffffff > nul
set /a CAP=%SIZE% / 2048 > nul
if not %SIGN%==0 set /a CAP=%CAP% + 0x100000 > nul
echo CAPACITY=%CAP%MiB

works for my WD Passport 2TB USB drive and returns  

CAPACITY=1907697MiB

 

There is probably a better way of doing it...



#16 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 01:56 PM

!BAT
# Get disk capacity (up to 2048TB only)
write 0x60000 0x42
write 0x60010 0 > nul
write 0x60014 0 > nul
# get size of disk from INT 13h AH=48 into memory at DS:DI+10h  - edx=80h is hard disk 0, 81h would be hard disk 1
/%grub%/bios int=0x13 eax=0x4800 edx=0x80 ds=0x6000 edi=0x0 > nul
read 0x60014  > nul
set MSSIZE=%@retval%
read 0x60010  > nul
set /A SIZE= %@retval% > nul
set /A SIGN=%SIZE% & 0x80000000 > nul
set /A SIZE=%SIZE% & 0x7fffffff > nul
set /a CAP=%SIZE% / 2048 > nul
if not %SIGN%==0 set /a CAP=%CAP% + 0x100000 > nul
if %MSSIZE%==0 echo CAPACITY=%CAP%MB && exit
# should work up to 2048TB
#now look at MSSIZE
set /A EXTRA=%MSSIZE% * 0x800 > nul
set /A CAP=%CAP% / 1024 > nul
set /a CAP=%CAP% + %EXTRA% > nul
echo CAPACITY=%CAP%GB

A bit messy but should work...

Displays capacity in MB if under 2TB or in GB if under 2048TB.


Edited by steve6375, 30 March 2015 - 11:53 AM.

  • DavidB likes this

#17 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 29 March 2015 - 03:08 PM

 

A bit messy but should work...

Displays capacity in MB if under 2TB or in GB if under 2048TB.

 

Yep, but what's the use of an approximated value in Mb, Gb or Tb?

 

And how accurate does it needs to be?

 

I mean, if you have a 32 bit hex number like:

0xFFFFFFFF

Which equates to 4294967295 (sectors), i.e. 4294967295*512 bytes=2199023255040 bytes and you want to express it in Mbytes (real Mbytes or Mib), you

2199023255040/1048576=2097151,99951171875 i.e. if you round it 2097152 and if you truncate it 2097151.

But, to simplify, let's say that you have:

0xFFFFF000

which corresponds to 4294963200*512/1048576=2097150 or 4294963200*512/1024/1024

you can have the same result if you strip last three chars and multiply by two (or add to self), i.e.

0xFFFFF=1048575*2=1048575+1048575=2097150

 

If you go for a 64 bit number, say ;)

0x000003FFFFFFF000

i.e. 4398046507008 you can have 4398046507008*512/1048576=2,147,483,646 Mb i.e. up to 2147 Tb (which should cover for the next few years the size of hard disks)

which can be obtained as:

0x3FFFFFFF=0x3FFFFFFF*0x2=0x7FFFFFFF=1073741823*2=1073741823+1073741823=2,147,483,646

 

For Gbytes, (real Gbytes, i.e. Gib) you can have:

0xFFFFF000

which corresponds to 4294963200*512/1073741824=2047.998046875

you can have the same result if you strip last five chars and divide by two, i.e.

0xFFF=4095/2=2047.5

 

Wouldn't this be easier (and "good enough" for a few years)?

 

:duff:

Wonko



#18 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 29 March 2015 - 05:18 PM

!BAT
# DISK can be 0-9, A-F only
# Returns: CAP = Capacity of disk displayed in GB
set DISK=0
# Get disk capacity
write 0x60000 0x42
write 0x60010 0 > nul
# get size of disk from INT 13h AH=48 into memory at DS:DI+10h  - edx=80h is hard disk 0, 81h would be hard disk 1
/%grub%/bios int=0x13 eax=0x4800 edx=0x8%DISK% ds=0x6000 edi=0x0 > nul
read 0x60010 > nul
set /A A=%@retval% & 0xffffffff > nul
set /a CAP=%A%>>21&0xffffffff > nul
# Get most significant dword
read 0x60014  > nul
set /A B=%@retval% & 0x1ffff > nul
set /a CAP=%B% * 0x800 + %CAP% > nul
echo DISK %DISK% = %CAP%GiB (LS_DWORD=%A% MS_DWORD=%B%, TOTAL SECTORS=%B%%%A:~2,999%)
set A=
set B=

Should be OK for very large disks now.

Attached Thumbnails

  • CaptureDiskCap.JPG


#19 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 29 March 2015 - 06:54 PM

I was thinking more of something *like*:





!BAT
# DISK can be 0-9, A-F only
# Returns: CAP = Capacity of disk displayed in GB
set DISK=0
# Get disk capacity
echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > (md)0x300+1
write 0x60010 0 > nul
# get size of disk from INT 13h AH=48 into memory at DS:DI+10h - edx=80h is hard disk 0, 81h would be hard disk 1
/bios int=0x13 eax=0x4800 edx=0x8%DISK% ds=0x6000 edi=0x0 > nul

cat --hex --skip=16 --length=8 (md)0x300+1 | set C=
set lword=%C:~32,2%%%C:~29,2%%%C:~26,2%%%C:~23,2%%%C:~19,2%%%C:~16,2%%%C:~13,2%%%C:~10,2%
set /a Mib=0x%lword:~5,8% > nul
echo Mib
set /a Mib=%Mib% * 2

set /a Gib=0x%lword:~3,8% > nul
echo Gib
set /a Gib=%Gib% / 2
echo TOTAL SECTORS 0x%lword%

but it should behave the same. :thumbup:

 

:duff:

Wonko



#20 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 30 March 2015 - 12:27 AM

Check to see if a drive is removable by the user.

Note: This does NOT report the RMB bit (unfortunately)!

!BAT
if not exist DRIVE set DRIVE=0
write 0x60000 0x42
write 0x60010 0
# get size of disk from INT 13h AH=48 into memory at DS:sI+10h  - edx=80h is hard disk 0, 81h would be hard disk 1
/bios int=0x13 eax=0x4800 edx=0x8%DRIVE% ds=0x6000 esi=0x0 > nul
read 0x60002 > nul
set R=%@retval%&0xFFFF > nul
set /A bRMB=%R%&0x04 > nul
if %bRMB%>=1 echo DRIVE %DRIVE% IS A USER-REMOVABLE DRIVE

Edited by steve6375, 30 March 2015 - 11:54 AM.


#21 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 30 March 2015 - 10:00 AM

It seems to me like this may possibly create confusion. :dubbio:

 

What does the actual value represent?

 

I mean, is it connected to the BUS to which the device is attached?

Examples:

  1. External eSATA hard disk <- it is "external" (and "fixed" alright) but I don't think there is *anything* in a BIOS call that can tell you that it is different from an internal SATA
  2. External SCSI hard disk <- same as above
  3. External USB stick <- external, and usually "removable"
  4. External USB 3.0 "fast" stick <- external, and usually "fixed"
  5. External USB hard disk <- external and "fixed"
  6. SD Card reader <- internal, USB connected and (usually) "removable"
  7. SD in (say) a eeePC <- internal, USB connected and (cannot remember if "removable" or "fixed")

 

:duff:

Wonko



#22 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 30 March 2015 - 10:05 AM

The BIOS 'knows' which buses are internal and which are external because it knows what mainboard it is on.

I have seem some OEM Intel BIOSes where you can use the BIOS Setup menu to declare a SATA port as either Internal or External - this is so that manufacturers can connect an internal SATA header on the mainboard to a PCI Card bracket and have rear external SATA interface(s) at the back of the PC which use the onboard headers.

 

So this is not the RMB bit of the device, it is what the BIOS has been configured to report (e.g. via DMI).

 

P.S. Windows needs to know if the drive is removable (i.e. external and can be disconnected by the user) as it uses a safer (not delayed write-cache) algorithm.


Edited by steve6375, 30 March 2015 - 10:11 AM.


#23 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 30 March 2015 - 11:05 AM

I know, what I was trying to say is that either this "IS AN EXTERNAL REMOVABLE DRIVE" is accurate (always) or it is not (or not always so) and the way the message is worded may create confusion/convey a false message to the user.

 

As an example, a message like "BIOS sees Disk #8x as connected to an external bus" would not create the same possible confusion with "removable".

 

And we are still around the same possible confusion between disk, drive and disk drive. :frusty:

 

:duff:

Wonko



#24 steve6375

steve6375

    Platinum Member

  • Developer
  • 6557 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films,guitars
  •  
    United Kingdom

Posted 30 March 2015 - 11:16 AM

I see - well, yes, the bit that is being tested is called 'Removable' and it means that the drive is capable of being removed whilst the system is 'up' (i.e. the drive is not permanently attached). It does not necessarily mean the drive is external - e.g. it could be in a caddy in the front panel of a system.

I just didn't want people to confuse it with the RMB bit  by just saying 'Removable' which is not the same thing.

I have edited the code now. :cheers:

 



#25 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 13480 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 30 March 2015 - 11:35 AM

I see that I am again failing at it. :(

 

If you use the word "drive" (two times :frusty:) you insist on the possible confusion between disk and drive, if you use the word "removable" you insist on the possible confusion with the "removable" bit (which many people at least know about of that have read/heard) and "user-removable" (that only a few people may know).

 

Last attempt:

DRIVE %DRIVE% IS A USER-REMOVABLE DRIVE

 

seems to me more confusing than (say):

Disk %DRIVE% is connected to a bus that supports hot-swapping.

 

or:

Disk %drive% is a hot-swappable device.

 

 

 

:duff:

Wonko







Also tagged with one or more of these keywords: grub4dos, disk size

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users