• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 707
  • Last Modified:

Disk Parameter Code

I have some assembly used within Pascal to get the size of the hard disk as follows;

function GetGeometry(Drive: Byte; var cyls, heads, sects: Word): Integer;
var Regs: Registers;
 regs.ah := 8;
 regs.dl :=Drive or $80;
 Intr($13, regs);
 cyls := (((regs.cl shl 2) and $300) or regs.ch) + 1;
 heads := regs.dh + 1;
 sects := regs.cl and $3F;
 GetGeometry:=regs.ax and $FF00;
 if regs.flags and 1 <> 0 then

MB: (sect*heads*cyls)/2048

This unfortunatley only works upto 8gb, I've done some searching and found changing the interrupt 13
call to 48h should return me the information. I don't know how to access the informatin tho' as it is returned differently than above.

Can anyone post me some assembly/comment to help?

As It is quite urgent I am offering 500 points to a correct working solution.

  • 2
  • 2
  • 2
  • +5
6 Solutions
You didnt mention the operating system.
if it's Windows 95 or newer, you can use  the info below.

Note that most of those low-level calls you've been trying, like int $13, do not know about high-level disk constructs, like network drives, spanned volumes, comptressed volumes, and the like.  If you want the staright dope, use the high-level calls to Windows.



The GetDiskFreeSpaceEx function retrieves information about the amount of space available on a disk volume: the total amount of space, the total amount of free space, and the total amount of free space available to the user associated with the calling thread.

BOOL GetDiskFreeSpaceEx(
  LPCTSTR lpDirectoryName,
  PULARGE_INTEGER lpFreeBytesAvailable,
  PULARGE_INTEGER lpTotalNumberOfBytes,
  PULARGE_INTEGER lpTotalNumberOfFreeBytes

[in] Pointer to a null-terminated string that specifies a directory on the disk of interest. If this parameter is NULL, the function uses the root of the current disk. If this parameter is a UNC name, it must include a trailing backslash (for example, \\MyServer\MyShare\).
Note that this parameter does not have to specify the root directory on a disk. The function accepts any directory on the disk.

[out] Pointer to a variable that receives the total number of free bytes on the disk that are available to the user associated with the calling thread. This parameter can be NULL.
If per-user quotas are in use, this value may be less than the total number of free bytes on the disk.

[out] Pointer to a variable that receives the total number of bytes on the disk that are available to the user associated with the calling thread. This parameter can be NULL.
If per-user quotas are in use, this value may be less than the total number of bytes on the disk.

[out] Pointer to a variable that receives the total number of free bytes on the disk. This parameter can be NULL.
Return Values
If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Note that the values obtained by this function are of type ULARGE_INTEGER. Be careful not to truncate these values to 32 bits.

Windows 95 OSR2 and later:  The GetDiskFreeSpaceEx function is available beginning with Windows 95 OEM Service Release 2 (OSR2). To determine whether GetDiskFreeSpaceEx is available, call GetModuleHandle to get the handle to Kernel32.dll. Then you can call GetProcAddress.

The following code fragment shows one way to do this:

pGetDiskFreeSpaceEx = GetProcAddress( GetModuleHandle("kernel32.dll"),

if (pGetDiskFreeSpaceEx)
   fResult = pGetDiskFreeSpaceEx (pszDrive,

// Process GetDiskFreeSpaceEx results.

   fResult = GetDiskFreeSpace (pszDrive,

// Process GetDiskFreeSpace results.


It is not necessary to call LoadLibrary on Kernel32.dll because it is already loaded into every process address space.

Windows NT Server 3.51 and earlier, Windows 95:  Include an additional header file called NewAPIs.h to make GetDiskFreeSpaceEx available on these operating systems. The function is not implemented natively, but by a wrapper that utilizes other native functions on these systems. See the header file for details of the use of preprocessor directives that make the function available. If you do not have this header file, it can be obtained by downloading the most recent Windows SDK from the SDK Update Site.

Windows Me/98/95 OSR2:  GetDiskFreeSpaceExW is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems.

Client: Included in Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0, Windows Me, Windows 98, and Windows 95 OSR2 and later.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server 4.0.
Unicode: Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

MConnorAuthor Commented:
Dos Boot Floppy, can be any version currently dos 6.22, I am using int13 as the disk might not be partitioned hence the calls to hardware directly.

You need to use INT 13h function 48h.
Take a look at:
And here is example how to call extended INT 13h functions:
Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Check out this code.


Regards,  P1
MConnorAuthor Commented:
Thanks Dimitry, I had seen both links hence I know I need int13 ah=48h. The code I posted origonally uses int13 ah=8 and this works fine for disks <7.8gb this returns nice easy register entries for me to read.

ah=48h returns something else which I don't understand.

This essentially is my question, how do I read/interpret what int13h ah=48h returns?

If I can get an answer to that the points are yours (I don't hold points back like your last posted link).

See http://www.delorie.com/djgpp/doc/rbinter/it/73/2.html


      AH = 48h
      DL = drive (80h-FFh)
      DS:SI -> buffer for drive parameters (see #00273)
Return: CF clear if successful
          AH = 00h
          DS:SI buffer filled
      CF set on error
          AH = error code (see #00234)
BUGS:      several different Compaq BIOSes incorrectly report high-numbered
        drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
        same geometry as drive 80h; as a workaround, scan through disk
        numbers, stopping as soon as the number of valid drives encountered
        equals the value in 0040h:0075h
      Dell machines using PhoenixBIOS 4.0 Release 6.0 fail to correctly
        handle this function if the flag word at DS:[SI+2] is not 0000h
        on entry
SeeAlso: AH=08h,AH=41h,AH=49h,MEM 0040h:0075h


Format of IBM/MS INT 13 Extensions drive parameters:
Offset      Size      Description      )
 00h      WORD      (call) size of buffer
                (001Ah for v1.x, 001Eh for v2.x, 42h for v3.0)
            (ret) size of returned data
 02h      WORD      information flags (see #00274)
 04h      DWORD      number of physical cylinders on drive
 08h      DWORD      number of physical heads on drive
 0Ch      DWORD      number of physical sectors per track
 10h      QWORD      total number of sectors on drive
 18h      WORD      bytes per sector
---v2.0+ ---
 1Ah      DWORD      -> EDD configuration parameters (see #00278)
            FFFFh:FFFFh if not available
---v3.0 ---
 1Eh      WORD      signature BEDDh to indicate presence of Device Path info
 20h      BYTE      length of Device Path information, including signature and this
              byte (24h for v3.0)
 21h  3 BYTEs      reserved (0)
 24h  4 BYTEs      ASCIZ name of host bus ("ISA" or "PCI")
 28h  8 BYTEs      ASCIZ name of interface type
            "1394" IEEE 1394 (FireWire)
            "FIBRE" Fibre Channel
 30h  8 BYTEs      Interface Path (see #00275)
 38h  8 BYTEs      Device Path (see #00276)
 40h      BYTE      reserved (0)
 41h      BYTE      checksum of bytes 1Eh-40h (two's complement of sum, which makes
              the 8-bit sum of bytes 1Eh-41h equal 00h)
Note:      if the size is less than 30 on call, the final DWORD will not be
        returned by a v2.x implementation; similarly for the Device Path info

Bitfields for IBM/MS INT 13 Extensions information flags:
Bit(s)      Description      )
 0      DMA boundary errors handled transparently
 1      cylinder/head/sectors-per-track information is valid
 2      removable drive
 3      write with verify supported
 4      drive has change-line support (required if drive >= 80h is removable)
 5      drive can be locked (required if drive >= 80h is removable)
 6      CHS information set to maximum supported values, not current media
 15-7      reserved (0)
Note:      bits 4-6 are only valid if bit 2 is set


Format of Phoenix Enhanced Disk Drive Spec Fixed Disk Parameter Table:
Offset      Size      Description      )
 00h      WORD      physical I/O port base address
 02h      WORD      disk-drive control port address
 04h      BYTE      drive flags (see #00279)
 05h      BYTE      proprietary information
            bits 7-4 reserved (0)
            bits 3-0: Phoenix proprietary (used by BIOS)
 06h      BYTE      IRQ for drive (bits 3-0; bits 7-4 reserved and must be 0)
 07h      BYTE      sector count for multi-sector transfers
 08h      BYTE      DMA control
            bits 7-4: DMA type (0-2) as per ATA-2 specification
            bits 3-0: DMA channel
 09h      BYTE      programmed I/O control
            bits 7-4: reserved (0)
            bits 3-0: PIO type (1-4) as per ATA-2 specification
 0Ah      WORD      drive options (see #00280)
 0Ch  2 BYTEs      reserved (0)
 0Eh      BYTE      extension revision level (high nybble=major, low nybble=minor)
            (currently 10h for v1.0 and 11h for v1.1-3.0)
 0Fh      BYTE      2's complement checksum of bytes 00h-0Eh
            8-bit sum of all bytes 00h-0Fh should equal 00h
Note:      this structure is also called the Device Paramter Table Extension

Format of EDD v3.0 Interface Path:
Offset      Size      Description      )
 00h      WORD      16-bit base address
 02h  6 BYTEs      reserved (0)
 00h      BYTE      PCI bus number
 01h      BYTE      PCI device number
 02h      BYTE      PCI function number
 03h  5 BYTEs      reserved (0)


Format of EDD v3.0 Device Path:
Offset      Size      Description      )
 00h      BYTE      flag: 00h = master, 01h = slave
 01h  7 BYTEs      reserved (0)
 00h      BYTE      flag: 00h = master, 01h = slave
 01h      BYTE      logical unit number
 02h  6 BYTEs      reserved (0)
 00h      BYTE      logical unit number
 01h  7 BYTEs      reserved (0)
 00h      BYTE      to be determined
 01h  7 BYTEs      reserved (0)
 00h      QWORD      64-bit FireWire General Unique Identifier (GUID)
 00h      QWORD      Word Wide Number (WWN)
Unfortunately I can't now write in Pascal, but the code C below shows how to use INT 13h, function 48h. It works properly for my computer, but I suspect that for different BIOSes it may work not properly. If you can't compile it, give me your e-mail, I'll send you executable.

#include <stdio.h>
#include <dos.h>
#define DISK       0x13
#define CF         1
typedef unsigned char  BYTE;
typedef unsigned short WORD;
typedef unsigned long  DWORD;
typedef struct {
  DWORD lowSecNum;
  DWORD highSecNum;

typedef struct {
  WORD  bufSize;     /* (001Ah for v1.x, 001Eh for v2.x, 42h for v3.0) */
  WORD  infoFlags;   /* (see #00274) */
  DWORD cylNum;      /* number of physical cylinders on drive */
  DWORD headNum;     /* number of physical heads on drive */
  DWORD secPerTrack; /* number of physical sectors per track */
  QWORD secNum;      /* total number of sectors on drive */
  WORD  bytesPerSec; /* bytes per sector */
/*---v2.0+ ---*/
  DWORD confParam;   /* -> EDD configuration parameters (see #00278) */
/*---v3.0 ---*/
  WORD  sign;
  BYTE  length;
  BYTE  reserved0[3];
  BYTE  nameBus[4];  /* ASCIZ name of host bus ("ISA" or "PCI") */
  BYTE  nameType[8]; /* ASCIZ name of interface type */
  BYTE  intPath[8];
  BYTE  devPath[8];
  BYTE  reserved1;
  BYTE  checksum;
} DevParam48;

DevParam48 devParam;
int getDriveParam( unsigned short driveNo, void far *buf )
{ /* Send get Drive Parameters command to INT 13 */
  struct REGPACK sreg;

  sreg.r_ax = 0x4800;                    /* Get Drive Parameters */
  sreg.r_dx = driveNo;                   /* Drive: 0x80 */
  sreg.r_si = FP_OFF( buf );
  sreg.r_ds = FP_SEG( buf );
  intr(DISK, &sreg);
  if( sreg.r_flags & CF )
    return( 1 );
  return( 0 );
int main()
  DWORD numOfMeg = 0L;

  devParam.bufSize = 0x1A;
  if( getDriveParam( 0x80, (void far *)&devParam ) != 0 ) {
    printf("Error Get Drive Parameters\n");
    return( 1 );
  printf("Get Drive Parameters:\n");
  numOfMeg = devParam.secNum.lowSecNum / 2048;
  printf("  HD size = %ld Mb\n", numOfMeg);
  return( 0 );

Lets try this in assembly.

Thr first thing to remember about the new interface is that
it is a packet passing convention instead of a register
passing convention like the legacy interface.

old :  AH=function   (08h)
       DL=Drive      (80h)
       int 13h
       returns info in registers.

new :  AH=Function   (48h) - same style
       DL=Drive      (80h) - Same style
       DS:SI=Buffer pointer- NEW
       Returns info in memory bufer.

In the new scheme you have to tell the bios where
you want the inforamtion placed. It is an indirect
type of interface designed to be extendable.

So in order to use it the first thing you do is declare
a block of memory like this.

BlkSz     dw  01Ah ; This is the size of the block.
Flags     dw  00h  ; Interface flags.
Cyls      dw  00h  ; Default cylinders.
Hds       dw  00h  ; Defauly heads.
Secs      dw  00h  ; Defaults sectors Per Track (03Fh-63)
TotSecs   dq  00h  ; Total sectors.
(TotSecs can be considered to be a pair of DD's because
it is really a 64-Bit number. TotSec_Hi,TotSec_Lo ).
BytsPSec  dw  00h  ; Bytes per sector.
EOB       dw  00h  ;

this defines a 26 byte block for the bios to fill in.
You tell the bios where your block is and it fills it in
with the requested information.

So you can use the following bit of code inline in your
program to get the information you want.


asm ;

jmp newbegin;

BlkSz     dw  01Ah ; This is the size of the block.
Flags     dw  00h  ; Interface flags.
Cyls      dw  00h  ; Default cylinders.
Hds       dw  00h  ; Defauly heads.
Secs      dw  00h  ; Defaults sectors Per Track (03Fh-63)
TotSec_Hi dd  00h  ; Total Sectors High.
TotSec_Lo dd  00h  ; Total sectors Low.
BytsPSec  dw  00h  ; Bytes per sector.
EOB       dw  00h  ;
push ds
push cs
pop  ds
mov  si,offset(BlkSz)
mov  dl,080h
mov  ah,048h
int  013h
pop  ds


Then you just go ahead and print the TotSec_Lo though
on some systems it will be in TotSec_Hi.

You packet is actually the memory in the BlkSz structure.
Hopefully this will tell you all you need to know.

If you need anything further please visit my site
and look in the ideinfo section.

HopeFully this will show you how to use the new style
of interface.

Hey whats wrong or are you absent?
Tell more details and show the complete code!
What's wrong with Borlands DriveSize?
It's really good assembly!
Try to throw an eye with a Debugger on it!

Make it Like this :

Uses {win}Dos;


Writeln('Size of actual Drive:',DiskSize(0):16);

recommend -- split to all participanting Experts

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

  • 2
  • 2
  • 2
  • +5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now