LSA Disk Sector Read - using int 13h ah 42 (extended read)

  • Follow


I'm just messing around here trying to learn how some of this low level
stuff works, and to my surprise I can not find a working example any
where...

Can someone please help. I'm about to pull my hair out!
I'm using visual studio 1.52 to compile my 16 bit code. I'm doing C
with inline ASM.
Note: I called check_extensions and extension are on my computer.

When i compile and run the following code bError prints out "0" so that
is no error i think? Yet when i print out my buffer the buffer is all
0's which i know is wrong because i have another functions that read
the MBR in with CHS format call and then it prints out the mbr just
fine. Any ideas?


struct disk_packet    //needed for int13 42h
{
	BYTE size_pack;		//size of packet must be 16 or 16+
	BYTE reserved1;		//reserved
	BYTE no_of_blocks;                   //no:of blocks for transfer
	BYTE reserved2;                        //reserved
	WORD offset;		//offset address
	WORD segment;                       //segment address
	DWORD lba1;
	DWORD lba2;
} disk_pack;

void LBASectorRead(void *buffer, unsigned long lba )
{
	unsigned char bError = 0;
	disk_pack.size_pack=16;            //set size to 16
	disk_pack.no_of_blocks=1;         //1 block  ie read one sector
	disk_pack.reserved1=0;              //reserved word
	disk_pack.reserved2=0;              //reserved word
	disk_pack.segment=FP_SEG(buffer); //segment of buffer
	disk_pack.offset=FP_OFF(buffer);     //offset of buffer
	disk_pack.lba1=0;                     //lba  first 32 bits
	disk_pack.lba2=0;                     //last 32 bit address

	_asm
	{
		mov dl, 80h;
		mov [disk_pack.segment], ds;
		mov si, disk_pack;
		mov ah, 42h;
		int 13h
		jc		NoError	;   //No error, ignore error code
		mov		bError, ah	;   // Error, get the error code
		NoError:
	}

	printf( "%d", bError);

}

int  main(void)
{
        static unsigned char  currentMBR[SECTOR_SIZE] = {0};
        printf("\n\n");
        LBASectorRead(currentMBR );
        PrintSector(currentMBR);   //function to print buffer in hex
}

0
Reply spamtrap2 (1628) 10/5/2006 6:56:05 PM

On 5 Oct 2006 11:56:05 -0700, "jay"  <spamtrap@crayne.org> wrote:

>I'm just messing around here trying to learn how some of this low level
>stuff works, and to my surprise I can not find a working example any
>where...
>
>Can someone please help. I'm about to pull my hair out!
>I'm using visual studio 1.52 to compile my 16 bit code. I'm doing C
>with inline ASM.
>Note: I called check_extensions and extension are on my computer.
>
>When i compile and run the following code bError prints out "0" so that
>is no error i think? Yet when i print out my buffer the buffer is all
>0's which i know is wrong because i have another functions that read
>the MBR in with CHS format call and then it prints out the mbr just
>fine. Any ideas?
>
>
>struct disk_packet    //needed for int13 42h
>{
>	BYTE size_pack;		//size of packet must be 16 or 16+
>	BYTE reserved1;		//reserved
>	BYTE no_of_blocks;                   //no:of blocks for transfer
>	BYTE reserved2;                        //reserved

>	WORD offset;		//offset address
>	WORD segment;                       //segment address

>	DWORD lba1;
>	DWORD lba2;
>} disk_pack;
>
>void LBASectorRead(void *buffer, unsigned long lba )
>{
>	unsigned char bError = 0;
>	disk_pack.size_pack=16;            //set size to 16
>	disk_pack.no_of_blocks=1;         //1 block  ie read one sector
>	disk_pack.reserved1=0;              //reserved word
>	disk_pack.reserved2=0;              //reserved word

>	disk_pack.segment=FP_SEG(buffer); //segment of buffer
>	disk_pack.offset=FP_OFF(buffer);     //offset of buffer

>	disk_pack.lba1=0;                     //lba  first 32 bits
>	disk_pack.lba2=0;                     //last 32 bit address
>
>	_asm
>	{
>		mov dl, 80h;
>		mov [disk_pack.segment], ds;

		mov ds, [disk_pack.segment];  // I think
though wouldn't this use the same FP_??? as in the packet?


>		mov si, disk_pack;
>		mov ah, 42h;
>		int 13h
>		jc		NoError	;   //No error, ignore error code
>		mov		bError, ah	;   // Error, get the error code
>		NoError:
>	}
>
>	printf( "%d", bError);
>
>}
>
>int  main(void)
>{
>        static unsigned char  currentMBR[SECTOR_SIZE] = {0};
>        printf("\n\n");
>        LBASectorRead(currentMBR );
>        PrintSector(currentMBR);   //function to print buffer in hex
>}

-- 
Doors - Dont look at the future in a window.
        Walk to a door - Open it, and go there.

http://www.freedoors.org

doorsremove@mefreedoors.org
mailto:doorsremove@mefreedoors.org

0
Reply Doors 10/6/2006 6:54:08 AM


I tried messing around with the line of code that you suggested but now
the programs just hangs.

Can anyone help me fix up this code. I really need to find a working
example of LBA_Read_Sector or I would prefer even more to just make
this block of code work correctly. I'm not really an assembley expert.

Jay

0
Reply jay 10/11/2006 3:41:47 PM

jay wrote:
> I'm just messing around here trying to learn how some of this low level
> stuff works, and to my surprise I can not find a working example any
> where...
> 
> Can someone please help. I'm about to pull my hair out!
> I'm using visual studio 1.52 to compile my 16 bit code. I'm doing C
> with inline ASM.
> Note: I called check_extensions and extension are on my computer.
> 
> When i compile and run the following code bError prints out "0" so that
> is no error i think? Yet when i print out my buffer the buffer is all
> 0's which i know is wrong because i have another functions that read
> the MBR in with CHS format call and then it prints out the mbr just
> fine. Any ideas?
> 
> 
> struct disk_packet    //needed for int13 42h
> {
> 	BYTE size_pack;		//size of packet must be 16 or 16+
> 	BYTE reserved1;		//reserved
> 	BYTE no_of_blocks;                   //no:of blocks for transfer
> 	BYTE reserved2;                        //reserved
> 	WORD offset;		//offset address
> 	WORD segment;                       //segment address
> 	DWORD lba1;
> 	DWORD lba2;
> } disk_pack;
> 
> void LBASectorRead(void *buffer, unsigned long lba )
> {
> 	unsigned char bError = 0;
> 	disk_pack.size_pack=16;            //set size to 16
> 	disk_pack.no_of_blocks=1;         //1 block  ie read one sector
> 	disk_pack.reserved1=0;              //reserved word
> 	disk_pack.reserved2=0;              //reserved word
> 	disk_pack.segment=FP_SEG(buffer); //segment of buffer
> 	disk_pack.offset=FP_OFF(buffer);     //offset of buffer
> 	disk_pack.lba1=0;                     //lba  first 32 bits
> 	disk_pack.lba2=0;                     //last 32 bit address
> 
> 	_asm
> 	{
> 		mov dl, 80h;
> 		mov [disk_pack.segment], ds;
> 		mov si, disk_pack;

I'm not familiar with the syntax you're using... Should this be "offset 
disk_pack"?

Best,
Frank

0
Reply Frank 10/11/2006 7:18:37 PM

I have no idea about the format. I'm not sure what offset I want. I
copied this code from another posting in google groups from someone who
"Claimed" this code worked to do a read sector with an LBA address.
Only when I compile and run the code and display (ie print out ) my
read sector it is all 00's so I know it didnt work.

0
Reply jay 10/11/2006 8:09:35 PM

jay wrote:
> I tried messing around with the line of code that you suggested but now
> the programs just hangs.
> 
> Can anyone help me fix up this code. I really need to find a working
> example of LBA_Read_Sector or I would prefer even more to just make
> this block of code work correctly. I'm not really an assembley expert.

I just happened to update an old disk erasure program yesterday, it is 
written in Turbo Pascal with inline asm for all the lowlevel stuff.

If you send me an email, I'll send you the source code.

OK?

Terje

-- 
- <Terje.Mathisen@hda.hydro.com>
"almost all programming can be viewed as an exercise in caching"

0
Reply Terje 10/11/2006 8:40:47 PM

"jay" <spamtrap@crayne.org> wrote in message
news:1160074565.866424.132440@m7g2000cwm.googlegroups.com...
> I'm just messing around here trying to learn how some of this low level
> stuff works, and to my surprise I can not find a working example any
> where...
>
<snip>
(on comp.lang.asm.x86 and a similar post on alt.os.development "Read Sector
(LBA mode)")


You could look at LFN tools by Ortwin "Odi" Glueck.  In addition to working
for Real Mode DOS, they implement Windows drive locking, and should work for
Protected Mode "DOS-boxes" and DOS emulators under older Windows OS:
Win95/98/98SE/ME etc.  I don't know whether the drive locking will work
under Protected Mode "DOS-boxes" and DOS emulators for 2k/NT/XP.  The source
code is for Microsoft Visual C++ 1.51.
http://lfntools.sourceforge.net/
http://www.odi.ch/prog/lfn/index.php


Also, Chris Giese wrote a LBA routine originally for DJGPP:
http://my.execpc.com/CE/AC/geezer/software/djgpplba.c

I ported it to OpenWatcom.  This link has it in html form with useful
comments.
http://www.openwatcom.org/index.php/Accessing_the_Harddisk_using_LBA_under_DPMI

These links have "my" complete ported source without html.
http://groups.google.com/group/openwatcom.users.c_cpp/msg/91921e7bfb09bcbc?hl=en
http://groups.google.com/group/openwatcom.users.c_cpp/msg/dd21a94062d38ad8?hl=en

Chris also ported it at a later date to OpenWatcom using a slightly
different technique:
http://my.execpc.com/CE/AC/geezer/temp/djdisk.c

<snip, problems...>
> Any ideas?
>

Let me take a look...

> struct disk_packet    //needed for int13 42h
> {
> BYTE size_pack; //size of packet must be 16 or 16+
> BYTE reserved1; //reserved
> BYTE no_of_blocks;                   //no:of blocks for transfer
> BYTE reserved2;                        //reserved
> WORD offset; //offset address
> WORD segment;                       //segment address
> DWORD lba1;
> DWORD lba2;
> } disk_pack;
>

The first problem is that it appears that your struct isn't packed.  This
means that additional bytes, which are used to align the structure, might be
inserted by the compiler.  Of course, DOS doesn't recognized those inserted
bytes...  You'll need to look for a compiler specific option, something like
"#pragma pack","__attribute__((packed))","_Packed", etc.

(Since I'm experiencing major "Deja Vu," after reading the rest of this
post, you might view this similar thread w/Ernesto a while back on
alt.os.development)
http://groups.google.com/group/alt.os.development/browse_frm/thread/c80d83d660e2b760/86d328a4777de8ef?&hl=en#86d328a4777de8ef

Second, I don't think this is an issue, but it might be. You are using two
32-bit lba fields instead of one 64-bit field.

Third, you've also obfuscated the "BYTE", "WORD", "DWORD", etc.  BYTE should
be an unsigned 8-bit quantity.  The others should also be unsigned of the
exact bit size.  You probably have some defines like so:

#define BYTE unsigned char
#define WORD unsigned shor
#define DWORD unsigned long
#define QWORD unsigned long long

You might try using "uint8_t", "uint16_t", "uint32_t", and "uint64_t" if
your compiler has C99's stdint.h.

> void LBASectorRead(void *buffer, unsigned long lba )
> {
> unsigned char bError = 0;
> disk_pack.size_pack=16;            //set size to 16
> disk_pack.no_of_blocks=1;         //1 block  ie read one sector
> disk_pack.reserved1=0;              //reserved word
> disk_pack.reserved2=0;              //reserved word
> disk_pack.segment=FP_SEG(buffer); //segment of buffer
> disk_pack.offset=FP_OFF(buffer);     //offset of buffer
> disk_pack.lba1=0;                     //lba  first 32 bits
> disk_pack.lba2=0;                     //last 32 bit address
>
> _asm
> {
> mov dl, 80h;
> mov [disk_pack.segment], ds;
> mov si, disk_pack;
> mov ah, 42h;
> int 13h
> jc NoError ;   //No error, ignore error code
> mov bError, ah ;   // Error, get the error code
> NoError:
> }
>

First, it appears that this line is reversed.  I think you should be setting
ds instead of saving it:

> mov [disk_pack.segment], ds;
mov ds,[disk_pack.segment]

Second, IIRC, LBA block numbering starts at 1 (one), but it appears that
both lba1 and lba2 are zero.

Third, you first need to check if the BIOS supports ah=42h by calling
ah=41h,bx=55AA.  I suggest you obtain a copy of Ralph Brown's interrupt list
if you don't have it.

Fourth, since you didn't pack your struct, "disk_pack.size_pack" might not
be 16, although it should be.
> disk_pack.size_pack=16;
disk_pack.size_pack=sizeof(disk_pack);  /* this should be 16, if correctly
packed */

Fourth, it won't work under Windows since there is no drive locking.

Five, if you're compiling for DPMI or a Dos Extender (both PM 32-bit), your
"buffer" variable and "disk_packet" struct may be above 1Mb.  Both will need
to be copied from a virtual address above 1Mb to a physical Real Mode
address below 1Mb to be accessed by DOS and BIOS.  Of course, the reverse
must be done upon completion.

Sixth, your compiler may have C structures which map to the registers.  It
might be easier to use them.



Rod Pemberton

0
Reply Rod 10/13/2006 8:03:38 AM

updated my code and tried several different thing but still nothing
works. I have a functions that checks for extensions and my machine has
the extensions. It is a fairly new dell inspiron 8500. Using visual
studio to make a DOS exe program. I did NOT select P-mode DOS so I
guess that means i'm working in real mode. I know the PrintSector
function works fine because if try a not extended (ie read int 13 ah=2)
then the whole thing works fine (but of course i want to have an
extended read function)

here is the code:


typedef unsigned char  BYTE;
typedef unsigned short WORD;
typedef unsigned long  DWORD;

typedef struct {
  unsigned long low;
  unsigned long high;
} QDWORD;

void PrintSector ( void * );
void LBASectorRead(void *, double );
int check_ext_present();

QDWORD double2qd( double x )
{
	QDWORD qdw;
	qdw.high = (unsigned long)(x/4294967296.0);
	qdw.low = (unsigned long) x;
	return qdw;
}

#pragma pack(1)
typedef struct disk_packet
{
	BYTE size_pack;       //size of packet must be 16 or 16+
	BYTE reserved1;        //reserved
	BYTE no_of_blocks;   //no:of blocks for transfer
	BYTE reserved2;        //reserved
	DWORD TransAddr;   //address in seg:off format
	QDWORD lba;           //quad word sector to read
};
struct disk_packet disk_pack;

void LBASectorRead(void *buffer, double lba )
{
       union REGS uRegs;
       struct SREGS sSeg;

       disk_pack.TransAddr = 0;
       disk_pack.size_pack=sizeof(disk_pack);        //set size to 16
       disk_pack.no_of_blocks=1;                           //1 block
       disk_pack.reserved1=0x0;
       disk_pack.reserved2=0x0;
       disk_pack.TransAddr = (unsigned long) MK_FP( FP_SEG(buffer),
FP_OFF(buffer));
       disk_pack.lba=double2qd( lba );

       sSeg.ds = FP_SEG( disk_pack );
       uRegs.x.si = FP_OFF( disk_pack );

       uRegs.h.dl = 0x80;
       uRegs.h.ah = 0x42;

       int86x( 0x13, &uRegs, &uRegs, &sSeg);

       printf("\n\nError: %x", uRegs.x.cx );
}


void Main ( void )
{
       static unsigned char  currentMBR[512] = {0};

       LBASectorRead(currentMBR, 1 );
       PrintSector ( currentMBR );
}

0
Reply jay 10/26/2006 5:39:35 PM

"jay" <spamtrap@crayne.org> wrote in message
news:1161884374.929492.285360@k70g2000cwa.googlegroups.com...
> updated my code and tried several different thing but still nothing
> works. I have a functions that checks for extensions and my machine has
> the extensions. It is a fairly new dell inspiron 8500. Using visual
> studio to make a DOS exe program. I did NOT select P-mode DOS so I
> guess that means i'm working in real mode. I know the PrintSector
> function works fine because if try a not extended (ie read int 13 ah=2)
> then the whole thing works fine (but of course i want to have an
> extended read function)
>
> here is the code:
>

The MSVC 1.52 code looked similar to OpenWatcom.  So, I decided to try it.
The code runs with a few minor changes for OW.  Sorry, it appears that I was
the culprit behind one of them being incorrect.  I also found a few
additional issues.  First, here's the code changes:

> typedef unsigned char  BYTE;
> typedef unsigned short WORD;
> typedef unsigned long  DWORD;
>
> typedef struct {
>   unsigned long low;
>   unsigned long high;
> } QDWORD;
>
> void PrintSector ( void * );
> void LBASectorRead(void *, double );
> int check_ext_present();
>
> QDWORD double2qd( double x )
> {
> QDWORD qdw;
> qdw.high = (unsigned long)(x/4294967296.0);
> qdw.low = (unsigned long) x;
> return qdw;
> }
>
> #pragma pack(1)
> typedef struct disk_packet
> {
> BYTE size_pack;       //size of packet must be 16 or 16+
> BYTE reserved1;        //reserved
> BYTE no_of_blocks;   //no:of blocks for transfer
> BYTE reserved2;        //reserved
> DWORD TransAddr;   //address in seg:off format
> QDWORD lba;           //quad word sector to read
> };
> struct disk_packet disk_pack;
>
> void LBASectorRead(void *buffer, double lba )
> {
>        union REGS uRegs;
>        struct SREGS sSeg;
>
>        disk_pack.TransAddr = 0;
>        disk_pack.size_pack=sizeof(disk_pack);        //set size to 16
>        disk_pack.no_of_blocks=1;                           //1 block
>        disk_pack.reserved1=0x0;
>        disk_pack.reserved2=0x0;
>        disk_pack.TransAddr = (unsigned long) MK_FP( FP_SEG(buffer),
> FP_OFF(buffer));
>        disk_pack.lba=double2qd( lba );
>
>        sSeg.ds = FP_SEG( disk_pack );
>        uRegs.x.si = FP_OFF( disk_pack );

sSeg.ds = FP_SEG( &disk_pack );
uRegs.x.si = FP_OFF( &disk_pack );

>
>        uRegs.h.dl = 0x80;
>        uRegs.h.ah = 0x42;
>
>        int86x( 0x13, &uRegs, &uRegs, &sSeg);
>
>        printf("\n\nError: %x", uRegs.x.cx );

printf("CF: %x", uRegs.x.cflag );
printf("AX: %x\n", uRegs.x.ax );

> }
>
>
> void Main ( void )

int main(void)

( Lowercase!  This was a "nice" error.  It totally hosed 16-bit OW. )
> {
>        static unsigned char  currentMBR[512] = {0};
>
>        LBASectorRead(currentMBR, 1 );
        LBASectorRead(currentMBR, 0 );

LBA sector numbers start at 1, but the appears that int 0x13 interface uses
LBA-1.  Again, sorry.  I'm not sure where this is documented.  I didn't see
in Ralph Brown's interrupt list.  It might be in the ATAPI specs or the
ancient Phoenix EDD specs somewhere.

>        PrintSector ( currentMBR );
> }
>

After making those changes (and adding my own PrintSector, and
check_ext_present), it compiled for OW and loaded the correct track (under
RM DOS).  In addition to stdio.h and stdlib.h, I included OW's i86.h, but I
believe MSVC uses dos.h or bios.h.

The first issue is that although you typedef'd BYTE, WORD, etc.  You didn't
use them throughout the code.  Take a look at your QDWORD struct and your
(unsigned long) casts.

Second, OW represents 16-bit addresses in segment:offset form.  This may
also be the case for MSVC 1.52.  In which case, the following change will
work:
> disk_pack.TransAddr=(unsigned long)MK_FP(FP_SEG(buffer),FP_OFF(buffer));
disk_pack.TransAddr=(unsigned long)buffer;

Third, the disk_packet struct is defined differently in Chris Giese's code
versus Ralph Brown's interrupt list.  I didn't notice this previously.  CG
defines it like so (in his code, those are typedef's like yours, not C99
stdint.h):

uint8_t  packet_len;
uint8_t  reserved1;
uint8_t  nsects;
uint8_t  reserved2;
uint16_t buf_offset;
uint16_t buf_segment;
uint64_t lba;

But, Ralph Brown's interrupt had it like this (with an optional QWORD, for
EDD 3.0):

 00h BYTE size of packet (10h or 18h)
 01h BYTE reserved (0)
 02h WORD number of blocks to transfer (max 007Fh for Phoenix EDD)
 04h DWORD -> transfer buffer
 08h QWORD starting absolute block number
 10h QWORD (EDD-3.0, optional) 64-bit flat address of transfer buffer; used
if DWORD at 04h is FFFFh:FFFFh

RB's would make your no_of_blocks a WORD and eliminate reserved2.  RB
indicates the reserved2 would always be 0 for Phoenix EDD, but the
no_of_blocks was obviously defined with room for a larger value.

>I did NOT select P-mode DOS so I
> guess that means i'm working in real mode.

Sorry, no.  It means you created a real mode DOS application, but you could
be attempting to run it in a protected mode emulator or the x86 CPU's V86
mode, usually called a DOS-box.  If you're running the code from Windows
3.1/98/98SE/98ME/NT/2k/XP, Linux, Bochs, VMWare, QEMU, DOSBox, DOSEMU, etc.,
don't expect the code to work.  Windows3.1/98/98SE/98ME were built on top of
MS-DOS, so it is possible to boot directly into RM DOS instead of Windows
with those OS's.  Win98ME requires a patch to boot RM DOS.  If you're
running from Windows, you'll need to add additional file/drive locking code
to work under Windows.


Rod Pemberton

0
Reply Rod 10/27/2006 4:04:53 AM

> >        sSeg.ds = FP_SEG( disk_pack );
> >        uRegs.x.si = FP_OFF( disk_pack );
>
> sSeg.ds = FP_SEG( &disk_pack );
> uRegs.x.si = FP_OFF( &disk_pack );

I have tried it both ways. Everything I have been seeing indicates that
i should have the & present but visual studio give me an error " '&'
requires l-value " and the only way to get ride of the error is to
remove the & from the code?? any ideas on this?

> > disk_pack.TransAddr=(unsigned long)MK_FP(FP_SEG(buffer),FP_OFF(buffer));
> disk_pack.TransAddr=(unsigned long)buffer;

I made this change and that make sense. That seems okee.


I changed my structure to match this

>  00h BYTE size of packet (10h or 18h)
>  01h BYTE reserved (0)
>  02h WORD number of blocks to transfer (max 007Fh for Phoenix EDD)
>  04h DWORD -> transfer buffer
>  08h QWORD starting absolute block number
>  10h QWORD (EDD-3.0, optional) 64-bit flat address of transfer buffer; used
> if DWORD at 04h is FFFFh:FFFFh



> Sorry, no.  It means you created a real mode DOS application, but you could
> be attempting to run it in a protected mode emulator or the x86 CPU's V86
> mode, usually called a DOS-box.  If you're running the code from Windows
> 3.1/98/98SE/98ME/NT/2k/XP, Linux, Bochs, VMWare, QEMU, DOSBox, DOSEMU, etc.,
> don't expect the code to work.  Windows3.1/98/98SE/98ME were built on top of
> MS-DOS, so it is possible to boot directly into RM DOS instead of Windows
> with those OS's.  Win98ME requires a patch to boot RM DOS.  If you're
> running from Windows, you'll need to add additional file/drive locking code
> to work under Windows.
>

I'm compiling the code and coping to a bootable DOS floopy disk and
then restarting my computer. This makes testing a HUGE pain so needless
to say I would like to resolve this soon.

Thanks again.
jay

0
Reply jay 10/30/2006 5:38:36 PM

On Tue, 31 Oct 2006 04:38:36 +1100, jay <spamtrap@crayne.org> wrote:

>> >        sSeg.ds = FP_SEG( disk_pack );
>> >        uRegs.x.si = FP_OFF( disk_pack );
>>
>> sSeg.ds = FP_SEG( &disk_pack );
>> uRegs.x.si = FP_OFF( &disk_pack );
>
> I have tried it both ways. Everything I have been seeing indicates that
> i should have the & present but visual studio give me an error " '&'
> requires l-value " and the only way to get ride of the error is to
> remove the & from the code?? any ideas on this?

Well there's nothing wrong your software development technique. Just keep  
changing the code at random until it seems to work :-)

Nah, but seriously, though... in Microsoft C up to v7 and Visual C++ up to  
v1.5 (for real-mode) FP_OFF and FP_SEG require that you pass a pointer to  
them. Passing an address won't cut the mustard, even though on the face of  
it it's the same thing. The reason is that these macros dereference the  
pointer - something that can't be done to an address. Check out the  
ancient MSDN article Q47497, dated 1997, if you can find it.

The solution/workaround (I'm not really sure how to characterize it) is to  
define a pointer variable that points to disk_pack and then pass that to  
the macros:

   struct disk_packet *p = &disk_pack;
   blah = FP_SEG(p);

I haven't taken the time to make sure I've got it exactly right, and I  
haven't been paying attention to what the code is really trying to do, but  
that should be enough to get you on the right track.


Cheers,
Ciaran

-- 
Ciaran Keating
Amad�n Technologies Pty Ltd

0
Reply Ciaran 10/31/2006 12:55:21 AM

"Ciaran Keating" <spamtrap@crayne.org> wrote in message
news:op.th9gv6pblndgv1@elmo...
> On Tue, 31 Oct 2006 04:38:36 +1100, jay <spamtrap@crayne.org> wrote:
>
> >> >        sSeg.ds = FP_SEG( disk_pack );
> >> >        uRegs.x.si = FP_OFF( disk_pack );
> >>
> >> sSeg.ds = FP_SEG( &disk_pack );
> >> uRegs.x.si = FP_OFF( &disk_pack );
> >
> > I have tried it both ways. Everything I have been seeing indicates that
> > i should have the & present but visual studio give me an error " '&'
> > requires l-value " and the only way to get ride of the error is to
> > remove the & from the code?? any ideas on this?
>
> Well there's nothing wrong your software development technique. Just keep
> changing the code at random until it seems to work :-)
>
> Nah, but seriously, though... in Microsoft C up to v7 and Visual C++ up to
> v1.5 (for real-mode) FP_OFF and FP_SEG require that you pass a pointer to
> them. Passing an address won't cut the mustard, even though on the face of
> it it's the same thing. The reason is that these macros dereference the
> pointer - something that can't be done to an address. Check out the
> ancient MSDN article Q47497, dated 1997, if you can find it.
>
> The solution/workaround (I'm not really sure how to characterize it) is to
> define a pointer variable that points to disk_pack and then pass that to
> the macros:
>
>    struct disk_packet *p = &disk_pack;
>    blah = FP_SEG(p);

Although your solution seems fine, if that still doesn't work, he might try:

    unsigned __far *p;
    p = (unsigned __far *)&disk_pack;
    blah = FP_SEG(p);

Also, you stated:
> The reason is that these macros dereference the
> pointer - something that can't be done to an address.

I think that part of your explanation is inaccurate.  I believe this is from
the same compiler he's using:

>From "errata":
"_FP_OFF, _FP_SEG
Add the following note to the Remarks section.

The argument to _FP_OFF and _FP_SEG must be a far pointer variable. It
cannot be an array name, or a near pointer cast to a far pointer."

It appears, from _FP_SEG/OFF in dos.h, that their use of the address
operator within the macro definitions is the primary cause of the problem:

#define _FP_SEG(fp) (*((unsigned __far *)&(fp)+1))
#define _FP_OFF(fp) (*((unsigned __far *)&(fp)))

A secondary issue is their assumption of a "far pointer" format or perhaps
they have casting conversion failure.  I'd presume, without knowing as fact,
that the address operator, &, returns a "near pointer" for VC which is
probably the reason why taking the address of the struct in the OP's
original code might not or didn't work.


Rod Pemberton

0
Reply Rod 11/1/2006 12:57:16 AM

Hi Rod,


On Wed, 01 Nov 2006 11:57:16 +1100, Rod Pemberton <spamtrap@crayne.org>  
wrote:

>>    struct disk_packet *p = &disk_pack;
>>    blah = FP_SEG(p);
>
> Although your solution seems fine, if that still doesn't work, he might  
> try:
>
>     unsigned __far *p;
>     p = (unsigned __far *)&disk_pack;
>     blah = FP_SEG(p);

Not trying to pick a fight here, but this looks like more of jay's hopeful  
bit-fiddling. I can't see how this is any different - all you've done is  
changed the target type of the pointer, you haven't changed any of the  
qualities of the pointer itself. Particularly in C, with its type-unsafety  
(is that a word?) this is a no-op. Even in C++ (although the code smacks  
of C) this casting might affect syntax, but not semantics.


> I think that part of your explanation is inaccurate.  I believe this is  
> from
> the same compiler he's using:

Perhaps. My information came from a very old MSDN disk, although it did  
say explicitly that it applied to the following products:

- Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, and 6.0ax
- Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a
- Microsoft C/C++ for MS-DOS, version 7.0
- Microsoft Visual C++ for Windows, versions 1.0 and 1.5

And this article explicitly says that passing the address of something,  
rather than an actual pointer to it, will give the error that jay  
encountered.


> The argument to _FP_OFF and _FP_SEG must be a far pointer variable. It
> cannot be an array name, or a near pointer cast to a far pointer."

I imagine the reason it can't be a near pointer cast to a far pointer is  
not because of some shortcoming in the implementation of FP_SEG/FP_OFF.  
(Not sure why your documentation gives a leading underscore...?) The  
reason you can't just cast a short pointer to a long pointer is that the  
result will simply be incorrect - the cast can't synthesize the segment  
information, but just sign-extends the short part. Or something like that.  
And I could be wrong, of course.


> It appears, from _FP_SEG/OFF in dos.h, that their use of the address
> operator within the macro definitions is the primary cause of the  
> problem:
>
> #define _FP_SEG(fp) (*((unsigned __far *)&(fp)+1))
> #define _FP_OFF(fp) (*((unsigned __far *)&(fp)))

Don't know what you see wrong here, and I'm too hungry right now to worry  
about it :-)


> A secondary issue is their assumption of a "far pointer" format or  
> perhaps
> they have casting conversion failure.  I'd presume, without knowing as  
> fact,
> that the address operator, &, returns a "near pointer" for VC which is
> probably the reason why taking the address of the struct in the OP's
> original code might not or didn't work.

Hmm... it's a hundred years since I did any real-mode programming, but if  
you select the correct memory model then surely &blah will yield the  
correct size of pointer?


Anyway, jay, if you're still here then let us know how you get on.


Cheers,
Ciaran

-- 
Ciaran Keating
Amad�n Technologies Pty Ltd

0
Reply Ciaran 11/1/2006 3:47:09 AM

If you are so totally lost, I have some source for a disk wiper
utility that uses MSC 1.52c.  It uses standard INT 13h and the
extended functions when supported.  It was written before the extended
functions and updated when they appeared.  Provide me with an email
address, such as: delta alpha victor echo at yankee oscar sierra hotel
india mike uniform nancy india dot charlie oscar mike, which is mine.

On 30 Oct 2006 09:38:36 -0800, "jay"  <spamtrap@crayne.org> wrote:

>> >        sSeg.ds = FP_SEG( disk_pack );
>> >        uRegs.x.si = FP_OFF( disk_pack );
>>
>> sSeg.ds = FP_SEG( &disk_pack );
>> uRegs.x.si = FP_OFF( &disk_pack );
>
>I have tried it both ways. Everything I have been seeing indicates that
>i should have the & present but visual studio give me an error " '&'
>requires l-value " and the only way to get ride of the error is to
>remove the & from the code?? any ideas on this?
>
>> > disk_pack.TransAddr=(unsigned long)MK_FP(FP_SEG(buffer),FP_OFF(buffer));
>> disk_pack.TransAddr=(unsigned long)buffer;
>
>I made this change and that make sense. That seems okee.
>
>
>I changed my structure to match this
>
>>  00h BYTE size of packet (10h or 18h)
>>  01h BYTE reserved (0)
>>  02h WORD number of blocks to transfer (max 007Fh for Phoenix EDD)
>>  04h DWORD -> transfer buffer
>>  08h QWORD starting absolute block number
>>  10h QWORD (EDD-3.0, optional) 64-bit flat address of transfer buffer; used
>> if DWORD at 04h is FFFFh:FFFFh
>
>
>
>> Sorry, no.  It means you created a real mode DOS application, but you could
>> be attempting to run it in a protected mode emulator or the x86 CPU's V86
>> mode, usually called a DOS-box.  If you're running the code from Windows
>> 3.1/98/98SE/98ME/NT/2k/XP, Linux, Bochs, VMWare, QEMU, DOSBox, DOSEMU, etc.,
>> don't expect the code to work.  Windows3.1/98/98SE/98ME were built on top of
>> MS-DOS, so it is possible to boot directly into RM DOS instead of Windows
>> with those OS's.  Win98ME requires a patch to boot RM DOS.  If you're
>> running from Windows, you'll need to add additional file/drive locking code
>> to work under Windows.
>>
>
>I'm compiling the code and coping to a bootable DOS floopy disk and
>then restarting my computer. This makes testing a HUGE pain so needless
>to say I would like to resolve this soon.
>
>Thanks again.
>jay

0
Reply spamtrap 11/1/2006 4:14:41 AM

13 Replies
574 Views

(page loaded in 0.139 seconds)

Similiar Articles:


















7/22/2012 1:21:24 PM


Reply: