Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using DPMI to simulate interrupt

191 views
Skip to first unread message

Vinayak Belamkar

unread,
Jul 18, 2005, 11:42:01 PM7/18/05
to
Hi,
I have created a 32-bit exe using Watcom 11.0c;
Used DPMI to simulate interrupt 13h and read physical boot sectors, get the
read data into my buffer - works well and good.
I tried to simulate interrupt 25h, but am not successful.
The function that I am using is given below:
********************************************************************

#pragma pack(1)
// real mode structure.
typedef struct tagRMInfo
{
unsigned long EDI;
unsigned long ESI;
unsigned long EBP;
unsigned long reserved_by_system;
unsigned long EBX;
unsigned long EDX;
unsigned long ECX;
unsigned long EAX;
unsigned short flags;
unsigned short ES,DS,FS,GS,IP,CS,SP,SS;
} REALMODEINFO;
#pragma pack()


// Cmd = 0 to read,
// 1 to write;
// Drive number,
// ....
int AbsAccess(int Cmd, int Drive, long SectorNo, unsigned char *Buffer)
{
#pragma pack(1)
struct LargeDiskIO
{
long StartingSector ;
unsigned SectorCount ;
unsigned BufferOffset ;
unsigned BufferSegment ;
} Block ;
#pragma pack()

union REGS inregs, outregs ;
struct SREGS segs ;
int Command;
REALMODEINFO MY_RMI;
unsigned int selector = 0;
unsigned int mysegment = 0;
unsigned int block_selector = 0;
unsigned int block_mysegment = 0;
char far *buf_boot = NULL;
char *pChar = NULL;
int iVal = 0;
unsigned long lVal = 0L;
int offset = 0;


// allocate DOS memory;
memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));
inregs.w.ax = 0x0100;
inregs.w.bx = 0x200;
int386x (0x31, &inregs, &outregs, &segs);
mysegment = outregs.w.ax;
selector = outregs.w.dx;


#define RD 0

if(Cmd == RD)
Command = 0x25 ;
else
Command = 0x26 ;


// simulate the read interrupt;
memset (&MY_RMI, 0, sizeof(MY_RMI));

lVal = 0L;
lVal = MAKEWORD(Drive, 0); // (AL, AH)
MY_RMI.EAX = lVal;

MY_RMI.ECX = 1;

MY_RMI.EBX = 0;
MY_RMI.DS = mysegment;

lVal = 0L;
lVal = MAKEWORD(SectorNo, 0); // (DL, DH)
MY_RMI.EDX = lVal;


memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

/* use DPMI call 300h to issue DOS interrupt */
inregs.w.ax = 0x0300;
inregs.h.bl = Command; // interrupt number
inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);


if (MY_RMI.flags)
{
printf ("After 1st try, Error value, (0x%x)\n", (unsigned
long)(MY_RMI.EAX));

memset (&MY_RMI, 0, sizeof(MY_RMI));
memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&Block, 0, sizeof(Block));

// allocate more DOS memory for Block;
memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));
inregs.w.ax = 0x0100;

inregs.w.bx = sizeof(Block);
int386x (0x31, &inregs, &outregs, &segs);
block_mysegment = outregs.w.ax;
block_selector = outregs.w.dx;

MY_RMI.ECX = 0xFFFF;

memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

Block.StartingSector = SectorNo ;
Block.SectorCount = 1 ;

Block.BufferOffset = 0;
Block.BufferSegment = mysegment;

// copy the block to allocated DOS memory;
buf_boot = (unsigned char far *)MK_FP(block_selector,0);
pChar = (char*)&Block;
for(offset = 0; offset<(sizeof(Block)); offset++)
buf_boot[offset] = pChar[offset];
MY_RMI.EBX = 0;
MY_RMI.DS = block_mysegment;


memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

/* use DPMI call 300h to issue DOS interrupt */
inregs.w.ax = 0x0300;
inregs.h.bl = Command; // interrupt number
inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);

printf ("After using Block, Error value, (0x%x)\n", (unsigned
long)(MY_RMI.EAX));

buf_boot=(unsigned char far *)MK_FP(selector,0);

for(offset = 0; offset<1 * 512; offset++)
Buffer[offset] = buf_boot[offset];


// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = block_selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);
}

// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);


for (int i = 0 ;i < 512; i++)
{
if (i % 16 == 0)
printf ("\n");
printf ("%02x ", Buffer[i]);
}

return 1;
}

********************************************************************

The error I am getting is "Bad Address Mark".
Where am I going wrong?

Regards,
Vinayak


japheth

unread,
Jul 18, 2005, 11:42:01 PM7/18/05
to

For FAT32 drives, you will have to use int 21h, ax=7105h instead of int
25h/26h. See RBIL for more details

Rod Pemberton

unread,
Jul 19, 2005, 7:38:15 AM7/19/05
to
I have no code for int 0x25, but I have working code for int 0x13 (like you)
and a ported code for int int 0x13, ah=0x4_ ( int 0x13 lba extensions).
I'll attempt to get your code working for OW 1.3 as my time permits.

Rod Pemberton

Here is a port of Chris Giese's lba biosdisk routines (int 0x13 extensions):
----

/***************************************************************************
**
LBA version of biosdisk() for DJGPP and WATCOM
WATCOM porting and DJGPP restructuring by Rod Pemberton
Changes: Feb 19, 2005
The changes are also public domain (no copyright).

LBA version of biosdisk() for DJGPP
Chris Giese <gee...@execpc.com> http://my.execpc.com/~geezer
Release date: Jan 2, 2004
This code is public domain (no copyright).
You can do whatever you want with it.

DJGPP: gcc -O2 -o djgpplba.exe djgpplba.c
WATCOM: wcl386/l=dos4g djgpplba.c
or wcl/l=dos djgpplba.c

****************************************************************************
*/
#include <stdio.h> /* printf() */
#include <string.h> /* memset() */
#include <bios.h> /* _DISK_... */

#ifdef __DJGPP__
#include <dpmi.h> /* __dpmi_regs, __dpmi_int() */
#include <go32.h> /* _go32_info_block, __tb, dosmemget(), dosmemput() */
__dpmi_regs r;
#define HANDLE_PRAGMA_PACK_PUSH_POP 1
#endif
/* end __DJGPP__ */

#ifdef __WATCOMC__
#include <i86.h> /* regs, sregs, int86x() int386x() */
#include <stdlib.h> /* atexit */
union REGS r;
struct SREGS s;
struct {
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;
/* tb used to setup transfer buffer below 1st megabyte (DJGPP __tb) */
/* DOS can only access the first 1Mb of memory */
/* tb used to save return information from DOS calls */
void *tb;
unsigned short sel; /* sel needed to free allocated memory, don't use */
#endif
/* end __WATCOMC__ */

#define BPS 512 /* bytes per sector for disk */

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef unsigned long long uint64_t;

#pragma pack(push,1)
typedef struct
{
uint8_t packet_len;
uint8_t reserved1;
uint8_t nsects;
uint8_t reserved2;
uint16_t buf_offset;
uint16_t buf_segment;
uint64_t lba;
} lba_command_packet;
#pragma pack(pop)
/***************************************************************************
**
****************************************************************************
*/
#ifdef __WATCOMC__
#define WAT_TB 0x4000
/* setup tb - transfer buffer for dos calls in memory below 1Mb */
void free_dos_mem(void)
{
#ifdef __386__
r.w.ax=0x0101; /* free dos memory */
r.w.dx=sel;
int386(0x31,&r,&r);
#else
free (tb);
#endif
}

void get_dos_mem(void)
{
#ifdef __386__
r.w.ax=0x0100; /* allocate dos memory, no __tb in WATCOM */
r.w.bx=WAT_TB>>4; /* 0400h is 04000h (16384 bytes) in paragraphs (16
bytes) */
int386(0x31,&r,&r);
sel = r.w.dx;
tb = (void *)(r.w.ax<<4);
#else
tb = malloc (16384);
if (tb==NULL)
{
printf("RM malloc failed.");
exit(1);
}
#endif
}
#endif
/***************************************************************************
**
****************************************************************************
*/
int lba_biosdisk(unsigned int13_drive_num, int cmd, unsigned long lba,
unsigned nsects, void *buf)
{

/* RP - this function is large and there were so many #ifdef's that I */
/* decided to just separate this function into three sections: */
/* DJGPP, WATCOM PM, WATCOM RM */
/* It really needs to be broken down into smaller functions... */

#ifdef __DJGPP__
/* DJGPP section */
lba_command_packet lba_cmd_pkt;

/* INT 13h AH=42h/AH=43h command packet: */
unsigned tries, err = 0;

if(cmd != _DISK_READ && cmd != _DISK_WRITE)
return 0x100;
/* make sure the DJGPP or WATCOM transfer buffer
(in conventional memory) is big enough */
if(BPS * nsects + sizeof(lba_command_packet) >
_go32_info_block.size_of_transfer_buffer)
return 0x100;
/* make sure drive and BIOS support LBA. Note that Win95 DOS box
emulates INT 13h AH=4x if they are not present in the BIOS. */
r.x.bx = 0x55AA;
r.h.dl = int13_drive_num;
r.h.ah = 0x41;
__dpmi_int(0x13, &r);
if(r.x.flags & 0x0001) /* carry bit (CY) is set */
return 0x100;
/* fill in the INT 13h AH=4xh command packet */
memset(&lba_cmd_pkt, 0, sizeof(lba_command_packet));
lba_cmd_pkt.packet_len = sizeof(lba_command_packet);
lba_cmd_pkt.nsects = nsects;
/* use start of transfer buffer
for data transferred by BIOS disk I/O... */
lba_cmd_pkt.buf_offset = 0;
lba_cmd_pkt.buf_segment = __tb >> 4;
lba_cmd_pkt.lba = lba;
/* ...use end of transfer buffer for the command packet itself */
dosmemput(&lba_cmd_pkt, sizeof(lba_command_packet), __tb + BPS *
nsects);
/* fill in registers for INT 13h AH=4xh */
r.x.ds = (__tb + BPS * nsects) >> 4;
r.x.si = (__tb + BPS * nsects) & 0x0F;
r.h.dl = int13_drive_num;
/* if writing, copy the data to conventional memory now */
if(cmd == _DISK_WRITE)
dosmemput(buf, BPS * nsects, __tb);
/* make 3 attempts */
for(tries = 3; tries != 0; tries--)
{
r.h.ah = (cmd == _DISK_READ) ? 0x42 : 0x43;
__dpmi_int(0x13, &r);
err = r.h.ah;
if((r.x.flags & 0x0001) == 0)
{
/* if reading, copy the data from conventional memory now */
if(cmd == _DISK_READ)
dosmemget(__tb, BPS * nsects, buf);
return 0;
}
/* reset disk */
r.h.ah = 0;
__dpmi_int(0x13, &r);
}
return err;
#endif
/* end DJGPP section */

#ifdef __WATCOMC__
#ifdef __386__
/* WATCOM PM section */
lba_command_packet lba_cmd_pkt;

/* INT 13h AH=42h/AH=43h command packet: */
unsigned tries, err = 0;

if(cmd != _DISK_READ && cmd != _DISK_WRITE)
return 0x100;
/* make sure the DJGPP or WATCOM transfer buffer
(in conventional memory) is big enough */
if(BPS * nsects + sizeof(lba_command_packet) >
WAT_TB) /* 04000h (16384) bytes for WATCOM above */
return 0x100;
/* make sure drive and BIOS support LBA. Note that Win95 DOS box
emulates INT 13h AH=4x if they are not present in the BIOS. */
RMI.EBX = 0x55AA;
RMI.EDX = int13_drive_num;
RMI.EAX = (0x41<<8);
r.w.ax=0x0300; /* simulate real mode interrupt */
r.h.bl=0x13; /* int 0x13 */
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31, &r, &r, &s);
if (RMI.flags & 0x0001) /* carry bit (CY) is set */
return 0x100;
/* fill in the INT 13h AH=4xh command packet */
memset(&lba_cmd_pkt, 0, sizeof(lba_command_packet));
lba_cmd_pkt.packet_len = sizeof(lba_command_packet);
lba_cmd_pkt.nsects = nsects;
/* use start of transfer buffer
for data transferred by BIOS disk I/O... */
lba_cmd_pkt.buf_offset = (unsigned long)tb & 0x0F;
lba_cmd_pkt.buf_segment = (unsigned long)tb >> 4;
lba_cmd_pkt.lba = lba;
/* ...use end of transfer buffer for the command packet itself */
memcpy((char *)tb + BPS * nsects, &lba_cmd_pkt,
sizeof(lba_command_packet));
/* fill in registers for INT 13h AH=4xh */
RMI.DS = ((unsigned long)tb + BPS * nsects) >> 4;
RMI.ESI = ((unsigned long)tb + BPS * nsects) & 0x0F;
RMI.EDX = int13_drive_num;
/* if writing, copy the data to conventional memory now */
if(cmd == _DISK_WRITE)
memcpy(tb, buf, BPS * nsects);
/* make 3 attempts */
for(tries = 3; tries != 0; tries--)
{
RMI.EAX = (((cmd == _DISK_READ) ? 0x42 : 0x43)<<8);
r.w.ax=0x0300; /* simulate real mode interrupt */
r.h.bl=0x13; /* int 0x13 */
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31, &r, &r, &s);
err = (RMI.EAX >> 8) & 0x0F;
if((RMI.flags & 0x0001) == 0)
{
/* if reading, copy the data from conventional memory now */
if(cmd == _DISK_READ)
memcpy(buf, tb, BPS * nsects);
return 0;
}
/* reset disk */
RMI.EAX = 0;
r.w.ax=0x0300; /* simulate real mode interrupt */
r.h.bl=0x13; /* int 0x13 */
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31, &r, &r, &s);
}
return err;
/* end WATCOM PM section */
#else
/* WATCOM RM section */
lba_command_packet lba_cmd_pkt;

/* INT 13h AH=42h/AH=43h command packet: */
unsigned tries, err = 0;

if(cmd != _DISK_READ && cmd != _DISK_WRITE)
return 0x100;
/* make sure the DJGPP or WATCOM transfer buffer
(in conventional memory) is big enough */
if(BPS * nsects + sizeof(lba_command_packet) >
WAT_TB) /* 04000h (16384) bytes for WATCOM above */
return 0x100;
/* make sure drive and BIOS support LBA. Note that Win95 DOS box
emulates INT 13h AH=4x if they are not present in the BIOS. */
r.w.bx = 0x55AA;
r.h.dl = int13_drive_num;
r.h.ah = 0x41;
int86(0x13, &r, &r);
if (r.w.cflag & 0x0001) /* carry bit (CY) is set */
return 0x100;
/* fill in the INT 13h AH=4xh command packet */
memset(&lba_cmd_pkt, 0, sizeof(lba_command_packet));
lba_cmd_pkt.packet_len = sizeof(lba_command_packet);
lba_cmd_pkt.nsects = nsects;
/* use start of transfer buffer
for data transferred by BIOS disk I/O... */
lba_cmd_pkt.buf_offset = FP_OFF(tb);
lba_cmd_pkt.buf_segment = FP_SEG(tb);
lba_cmd_pkt.lba = lba;
/* ...use end of transfer buffer for the command packet itself */
movedata(FP_SEG(&lba_cmd_pkt), FP_OFF(&lba_cmd_pkt), FP_SEG((char
*)tb + BPS * nsects), FP_OFF((char *)tb + BPS * nsects),
sizeof(lba_command_packet));
/* fill in registers for INT 13h AH=4xh */
s.ds = FP_SEG((char *)tb + BPS * nsects);
r.w.si = FP_OFF((char *)tb + BPS * nsects);
r.h.dl = int13_drive_num;
/* if writing, copy the data to conventional memory now */
if(cmd == _DISK_WRITE)
movedata(FP_SEG(buf), FP_OFF(buf), FP_SEG(tb), FP_OFF(tb),
BPS * nsects);
/* make 3 attempts */
for(tries = 3; tries != 0; tries--)
{
r.h.ah = (cmd == _DISK_READ) ? 0x42 : 0x43;
int86x(0x13, &r, &r, &s);
err = r.h.ah;
if((r.w.cflag & 0x0001) == 0)
{
/* if reading, copy the data from conventional memory now */
if(cmd == _DISK_READ)
movedata(FP_SEG(tb), FP_OFF(tb),
FP_SEG(buf), FP_OFF(buf), BPS * nsects);
return 0;
}
/* reset disk */
r.h.ah = 0;
int86(0x13, &r, &r);
}
return err;
/* end WATCOM RM section */
#endif
#endif
}
/***************************************************************************
**
demo routines
****************************************************************************
*/
#define BPERL 16 /* byte/line for dump */

void dump(void *data_p, unsigned count)
{
unsigned char *data = (unsigned char *)data_p;
unsigned byte1, byte2;

while(count != 0)
{
for(byte1 = 0; byte1 < BPERL; byte1++)
{
if(count == 0)
break;
printf("%02X ", data[byte1]);
count--;
}
printf("\t");
for(byte2 = 0; byte2 < byte1; byte2++)
{
if(data[byte2] < ' ')
printf(".");
else
printf("%c", data[byte2]);
}
printf("\n");
data += BPERL;
}
}
/***************************************************************************
**
****************************************************************************
*/
int main(void)
{
char boot[BPS], mbr[BPS], *pte; /* partition table entry */
unsigned i, drive = 0x80;
unsigned long j;

#ifdef __WATCOMC__
atexit(free_dos_mem);
get_dos_mem();
#endif

/* read sector 0 of drive (the partition table; or MBR)
int13_drive_num = 0x80 for drive C: */
if(lba_biosdisk(drive, _DISK_READ, 0, 1, mbr))
{
printf("Error reading partition table on drive 0x%02X\n",
drive);
return 1;
}
printf("Dump of partition table on drive 0x%02X:\n", drive);
dump(mbr + 446, 64);
for(i = 0; i < 4; i++)
{
pte = mbr + 446 + 16 * i;
/* skip partition if size == 0 */
j = *(uint32_t *)(pte + 12);
if(j == 0)
continue;
/* read sector 0 of partition (the boot sector) */
j = *(uint32_t *)(pte + 8);
if(lba_biosdisk(drive, _DISK_READ, j, 1, boot))
{
printf("Error reading bootsector of drive 0x%02X, "
"partition %u\n", drive, i);
continue;
}
printf("Dump of bootsector for drive 0x%02X, "
"partition %u:\n", drive, i);
dump(boot, 64);
}
return 0;
}


"Vinayak Belamkar" <belamkar...@hotmail.com> wrote in message
news:dbg2lk$tsq$1...@www1.scitechsoft.com...

Vinayak Belamkar

unread,
Jul 19, 2005, 7:38:15 AM7/19/05
to
Thanks a lot for this, but I have already simulated int 13h and it is not a
problem.
Reading the PTEs and getting the values for physically reading the
bootsector is okay, but int 25h is the one I may require further.

- Vinayak

"Rod Pemberton" <dont...@noreply.bit> wrote in message
news:dbi8hn$3vk$1...@www1.scitechsoft.com...


> I have no code for int 0x25, but I have working code for int 0x13 (like
you)
> and a ported code for int int 0x13, ah=0x4_ ( int 0x13 lba extensions).
> I'll attempt to get your code working for OW 1.3 as my time permits.
>
> Rod Pemberton
>
> Here is a port of Chris Giese's lba biosdisk routines (int 0x13
extensions):

<snip>
...


Vinayak Belamkar

unread,
Jul 19, 2005, 7:38:15 AM7/19/05
to
On referring RBIL, did you mean int 21h/ax=7305h?
I am trying to use it, getting some minor problems; but I will post here
when I get the code going or any problems.
This was an invaluable suggestion,
Thank you.

- Vinayak

"japheth" <ma...@japheth.de> wrote in message
news:dbg7ln$vrj$1...@www1.scitechsoft.com...

Rod Pemberton

unread,
Jul 19, 2005, 11:39:06 PM7/19/05
to
Okay,

I'm using wcl386/l=dos4g OW1.3 on Win98SE.
Firstly, things I suspect are incorrect in your code:

RMI is not packed
Block is incorrect
no need for 'far' keyword in PM code
MK_FP not used in PM code
didn't reset value for MY_RMI.EAX
didn't copy returned Block at buf_boot from int386x() back to Block

It appears you are mixing RM and PM code features. (e.g., int386 is PM and
MK_FP is RM)

Secondly, see if the modified version of your code (below) works for you. I
think it works for FAT12 and FAT16. FAT32 needs int 0x21 ax=0x7305...

Rod Pemberton

----

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bios.h>
#include <dos.h>
#include <i86.h>

#define RD 0
#define WR 1
#define MAKEWORD(a,b) (((b)<<8)|(a))

typedef struct tagRMInfo
{
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} REALMODEINFO;


// Cmd = 0 to read,
// 1 to write;
// Drive number,
// ....

int AbsAccess(int Cmd, int Drive, unsigned long SectorNo, unsigned char
*Buffer)
{
#pragma pack(push,1)
struct LargeDiskIO
{
unsigned long StartingSector ;
unsigned short SectorCount ;
unsigned long BufferAddress;
} Block ;
#pragma pack(pop)

union REGS inregs, outregs ;
struct SREGS segs ;

int Command=0x25;


REALMODEINFO MY_RMI;
unsigned int selector = 0;
unsigned int mysegment = 0;
unsigned int block_selector = 0;
unsigned int block_mysegment = 0;

unsigned char *buf_boot = NULL;
unsigned char *pChar = NULL;


int iVal = 0;
unsigned long lVal = 0L;

int offset = 0, i, status;

memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

// allocate DOS memory;


inregs.w.ax = 0x0100;
inregs.w.bx = 0x200;
int386x (0x31, &inregs, &outregs, &segs);
mysegment = outregs.w.ax;
selector = outregs.w.dx;

if(Cmd == RD)


Command = 0x25 ;
else
Command = 0x26 ;

// simulate the read interrupt;
memset (&MY_RMI, 0, sizeof(MY_RMI));

lVal = 0L;
lVal = MAKEWORD(Drive, 0); // (AL, AH)
MY_RMI.EAX = lVal;
MY_RMI.ECX = 1;

MY_RMI.EDX = SectorNo;


MY_RMI.EBX = 0;
MY_RMI.DS = mysegment;

memset (&inregs, 0, sizeof(inregs));


memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

/* use DPMI call 300h to issue DOS interrupt */
inregs.w.ax = 0x0300;
inregs.h.bl = Command; // interrupt number
inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);

status=MY_RMI.flags&INTR_CF;
if (status)
{
printf ("After 1st try, Carry Flag value, (0x%08x), Error value,
(0x%08x)\n",(unsigned long)(status), (unsigned long)(MY_RMI.EAX));

memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

memset (&MY_RMI, 0, sizeof(MY_RMI));
memset (&Block, 0, sizeof(Block));

// allocate more DOS memory for Block;

inregs.w.ax = 0x0100;
inregs.w.bx = sizeof(Block);
int386x (0x31, &inregs, &outregs, &segs);
block_mysegment = outregs.w.ax;
block_selector = outregs.w.dx;

lVal = 0L;


lVal = MAKEWORD(Drive, 0); // (AL, AH)
MY_RMI.EAX = lVal;

MY_RMI.ECX = 0xFFFF;
MY_RMI.DS = block_mysegment;
MY_RMI.EBX = 0;

Block.StartingSector = SectorNo ;
Block.SectorCount = 1 ;

Block.BufferAddress = mysegment<<4;

// copy Block to allocated DOS memory
buf_boot = (unsigned char *)(block_mysegment<<4);
pChar = (unsigned char *)&Block;
memcpy(buf_boot,pChar,sizeof(Block));

memset (&inregs, 0, sizeof(inregs));
memset (&outregs, 0, sizeof(outregs));
memset (&segs, 0, sizeof(segs));

/* use DPMI call 300h to issue DOS interrupt */
inregs.w.ax = 0x0300;
inregs.h.bl = Command; // interrupt number
inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);

memcpy(pChar,buf_boot,sizeof(Block));

status=MY_RMI.flags&INTR_CF;
if (status)
{
printf ("After using Block, Carry Flag value, (0x%08x), Error value,
(0x%08x)\n",(unsigned long)(status), (unsigned long)(MY_RMI.EAX));
/* EAX will be 0x207 for FAT32 under DOS, but will be 0x1 for FAT32 under
Win98 SE */
/* int 0x21/ax=0x7305 code here */
}
else if (Command==0x25) /* no error & RD */
{
buf_boot=(unsigned char *)(Block.BufferAddress);
memcpy(Buffer,buf_boot,512);
}

// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = block_selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);
}

// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);


if(!status)
{
printf("Passed\n");
#if 0
for (i = 0 ;i < 512; i++)
{
if (i % 32 == 0)


printf ("\n");
printf ("%02x", Buffer[i]);
}

printf ("\n");
#endif
}

return(0);
}

int main(void)
{
unsigned char *bufr;

bufr=malloc(4096);
printf("1:");
AbsAccess(RD,0,0,bufr); /* read, A:, sector0, buf*/
printf("2:");
AbsAccess(RD,2,0,bufr); /* read, C:, sector0, buf*/
printf("3:");
AbsAccess(RD,3,0,bufr); /* read, D:, sector0, buf*/
printf("4:");
AbsAccess(RD,3,130,bufr); /* read, D:, sector0, buf*/
printf("5:");
AbsAccess(RD,3,0x192ff6c,bufr); /* read, D:, sector0, buf*/

return(0);
}

"Vinayak Belamkar" <belamkar...@hotmail.com> wrote in message

news:dbihem$7fj$1...@www1.scitechsoft.com...

Vinayak Belamkar

unread,
Jul 20, 2005, 7:36:14 AM7/20/05
to
Thank you again for the code and the guidelines. :-)
I used int 0x21 ax=0x7305, and it is working fine.

> Firstly, things I suspect are incorrect in your code:
>
> RMI is not packed

--- It is packed in my original code, I forgot to mention it in the code
posted in the newsgroup.
> Block is incorrect
--- As you have mentioned further, I mixed up some RM / PM code features,
hence the Block was interpreted incorrectly.


> no need for 'far' keyword in PM code
> MK_FP not used in PM code
> didn't reset value for MY_RMI.EAX
> didn't copy returned Block at buf_boot from int386x() back to Block
>
> It appears you are mixing RM and PM code features. (e.g., int386 is PM and
> MK_FP is RM)

--- I realized the mistakes I was making and seem to be getting a bit where
I was going wrong in my original code.

> Secondly, see if the modified version of your code (below) works for you.
I
> think it works for FAT12 and FAT16. FAT32 needs int 0x21 ax=0x7305...

--- It works

Maybe I will need some more guidance for coding using DPMI, and I could find
very less information/samples apart from the DPMI docs.

Thanks a lot,
Vinayak


Rod Pemberton

unread,
Jul 20, 2005, 7:36:14 AM7/20/05
to
> > Secondly, see if the modified version of your code (below) works for
you.
> I
> > think it works for FAT12 and FAT16. FAT32 needs int 0x21 ax=0x7305...
> --- It works

Good. I couldn't completely confirm the sector data being read was actually
the same data in the buffer...

>
> Maybe I will need some more guidance for coding using DPMI, and I could
find
> very less information/samples apart from the DPMI docs.

I've posted two good samples of DPMI usage:
1) lba_biosdisk.c, in my post on 7/18/05 3:02AM in "Using DPMI to simulate
interrupt by Vinayak Belamkar 7/18/05 7:11AM"
2) boot.c, in my post on 5/9/05 4:40AM in "Reboot using C and DOS4GW by
Greg Engle 4/28/05 11:25AM"

Feel free to ask about DPMI. I've many personal DOS programs for DJGPP and
OpenWatcom.


Rod Pemberton

FreeDOSfan

unread,
Jul 20, 2005, 4:13:29 PM7/20/05
to
Thanks. Could be useful for me too.

Michal Necasek

unread,
Jul 20, 2005, 11:38:22 PM7/20/05
to
Vinayak Belamkar wrote:

> --- How do I download the older posts from the newsgroup? I am using MS
> Outlook, and even though I try to redownload the posts from the newsgroup,
> only the latest few (approx 300) are made available.
> Is there some URL where the archives are being maintained or some other
> newsreader should be used ?
>
Google Groups.


Michal

Vinayak Belamkar

unread,
Jul 20, 2005, 11:38:18 PM7/20/05
to
Some more problems:


> Good. I couldn't completely confirm the sector data being read was
actually
> the same data in the buffer...

--- There are several utilities available for disk editing/viewing.


> >
> > Maybe I will need some more guidance for coding using DPMI, and I could
> find
> > very less information/samples apart from the DPMI docs.
>
> I've posted two good samples of DPMI usage:
> 1) lba_biosdisk.c, in my post on 7/18/05 3:02AM in "Using DPMI to simulate
> interrupt by Vinayak Belamkar 7/18/05 7:11AM"
> 2) boot.c, in my post on 5/9/05 4:40AM in "Reboot using C and DOS4GW by
> Greg Engle 4/28/05 11:25AM"

--- How do I download the older posts from the newsgroup? I am using MS
Outlook, and even though I try to redownload the posts from the newsgroup,
only the latest few (approx 300) are made available.
Is there some URL where the archives are being maintained or some other
newsreader should be used ?

> Feel free to ask about DPMI. I've many personal DOS programs for DJGPP
and
> OpenWatcom.
---- Thanks a lot.


One small problem regarding your earlier code is that, it is not able to
logical read sectors under DOS622 - FAT16, 2 GB HDD.
EAX has value 0x207, and the data is garbage.

Thank you,
Vinayak


Rod Pemberton

unread,
Jul 21, 2005, 7:38:11 AM7/21/05
to
> --- How do I download the older posts from the newsgroup? I am using MS
> Outlook, and even though I try to redownload the posts from the newsgroup,
> only the latest few (approx 300) are made available.
> Is there some URL where the archives are being maintained or some other
> newsreader should be used ?
>

I think it goes like so...
1) select openwatcom.users.c_cpp, File->Properties->LocalFile->Reset
2) Tools->Read->News-> x Get 1000 headers at a time (check and set value)
3) select new.openwatcom.org, Tools->SynchronizeAccount

> One small problem regarding your earlier code is that, it is not able to
> logical read sectors under DOS622 - FAT16, 2 GB HDD.
> EAX has value 0x207, and the data is garbage.

I noticed you are not checking EAX for the carry flag (INTR_CF) only. Is
that the problem?

If not, which EAX? The first or second?
The first EAX (FAT12)? EAX=0x207 means the partition size is too large to
read. It tries the second read because your partition is not a FAT12
partition. The second EAX (FAT16)? EAX=0x207 indicates it is a FAT32
partition not a FAT16 partition.

Under MS-DOS 7.10 (Win98SE), I've tried FAT12, Extended Partition FAT16,
Primary FAT16, Primary FAT32.
I'd have to find a copy of 6.22 to check things out. As I said, I can't
confirm the reading or copying of the data is correct.

int 0x25 is only for FAT12 ( <32M partition)
int 0x25/cx=0xFFFF is only for FAT16 (32M-4096M partition, if fdisked as
FAT16, no large disk support)
int 0x21/ax=7305 is only for FAT32 ( 32M-2T partition, if fdisked as FAT32,
yes large disk support)

May I ask why are you trying to use DOS routines instead of BIOS routines?
Using int 0x13 and in0x13/ax=0x41-49,4E you should be able to read the
entire disk. MS-DOS's routines are built upon the BIOS functions (except
0x21,ax=7305). If your BIOS doesn't support those, MS-DOS doesn't either.

I've reattached boot.c.

Rod Pemberton

----

/* boot.c reboot the PC */
/* Rod Pemberton 2000-2004 */
/* this program is released to PUBLIC DOMAIN */
/* */
/* DJGPP gcc -o boot.exe boot.c */
/* WATCOM wcl/l=dos boot.c */
/* or wcl386/l=dos4g boot.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __DJGPP__
#include <go32.h>
#include <dpmi.h>
#include <sys/farptr.h>
__dpmi_regs r;
#endif

#ifdef __WATCOMC__
#include <i86.h>
#include <dos.h>


union REGS r;
struct SREGS s;
struct {
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;

#endif


int main(int argc,char **argv)
{
#ifdef __WATCOMC__
unsigned short *ptr;
#ifndef __386__
void ( __far *reset)();
#endif
#endif

memset(&r,0,sizeof(r));
if (argc == 1 || argc > 2 || argv[1][0]!='-')
/* no valid flags, print usage & exit */
{
printf( "A program to reboot your computer.\n"
"Usage: Boot <param>\n"
"-c cold \n"
"-w warm \n"
/* "-s soft (Int 19) \n" */
);
exit(1);
}

switch(argv[1][1]) /* fill option controls with arg position */
{
case 'c': /* cold reset */
#ifdef __DJGPP__
/* DJGPP PM */
_farpokew(_dos_ds,0x472,0x0);
r.x.cs = 0xFFFF;
r.x.ip = 0x0000;
__dpmi_simulate_real_mode_procedure_retf(&r);
#endif
#ifdef __WATCOMC__

ptr = (unsigned short *)0x472;
*ptr = 0x0;

#ifdef __386__
/* WATCOM PM, use DPMI */
/* DOS/4G (non-professional) doesn't support */
/* DPMI 0x301 "Call Real Mode Procedure With Far Return Frame" */
/* so we simulate it by setting an interrupt to the BIOS RESET JUMP */
/* and then calling the interrupt using: */
/* DPMI 0x201 "Set Real Mode Interrupt Vector" */
/* DPMI 0x300 "Simulate Real Mode Interrupt" */

r.w.ax=0x0201; /* set real mode interrupt */
r.h.bl=0x60; /* user interrupt */
r.w.cx=0xFFFF;
r.w.dx=0x0000;
int386(0x31,&r,&r);


r.w.ax=0x0300; /* simulate real mode interrupt */

r.h.bl=0x60;
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31,&r,&r,&s);
#else
/* WATCOM RM */
reset=MK_FP(0xFFFF,0x0000);
(*reset)(); /* call the function */

#if 0
/* Another possible WATCOM RM coding option: */

void (__interrupt __far *handler)(); /* declaration */

handler=MK_FP(0xFFFF,0x0000);
_dos_setvect(0x60,handler);
int86(0x60,&r,&r);

#endif
#endif
#endif
break;
case 'w': /* warm reset */
#ifdef __DJGPP__
/* DJGPP PM */
_farpokew(_dos_ds,0x472,0x1234);
r.x.cs = 0xFFFF;
r.x.ip = 0x0000;
__dpmi_simulate_real_mode_procedure_retf(&r);
#endif
#ifdef __WATCOMC__
ptr = (unsigned short *)0x472;
*ptr = 0x1234;

#ifdef __386__
/* WATCOM PM, use DPMI */
r.w.ax=0x0201; /* set real mode interrupt */
r.h.bl=0x60; /* user interrupt */
r.w.cx=0xFFFF;
r.w.dx=0x0000;
int386(0x31,&r,&r);


r.w.ax=0x0300; /* simulate real mode interrupt */

r.h.bl=0x60;
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31,&r,&r,&s);
#else
/* WATCOM RM */
reset=MK_FP(0xFFFF,0x0000);
(*reset)(); /* call the function */
#endif
#endif
break;
/* Int 0x19 works if HIMEM is not loaded by CONFIG.SYS or Windows9x */
/* i.e., "Safe mode command prompt only" for Windows9x */
/* WATCOM works for both RM & PM */
/* DJGPP fails */
case 's': /* soft reset */
#ifdef __DJGPP__
/* No working method found. */
#endif
#ifdef __WATCOMC__
#ifdef __386__
/* WATCOM PM, use DPMI */


r.w.ax=0x0300; /* simulate real mode interrupt */

r.h.bl=0x19;
r.h.bh=0;
r.w.cx=0;
s.es=FP_SEG(&RMI);
r.x.edi=FP_OFF(&RMI);
int386x(0x31,&r,&r,&s);
#else
/* WATCOM RM */
int86(0x19,&r,&r);
#endif
#endif
break;
default: break;
}

return(0);
}

Rod Pemberton

unread,
Jul 21, 2005, 11:39:07 PM7/21/05
to

Okay,
I made at least two mistakes in the code I posted.
1) the address in block is offset/segment as you had
2) there needs to be another memcpy for the first read
Could you try out the following code?

Rod Pemberton
----


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ctype.h>


#include <bios.h>
#include <dos.h>
#include <i86.h>

#define RD 0
#define WR 1

#define BLOCKSIZE 1024
#define dotch(i) (isprint(i)?(i):'.')

union REGS r;
struct SREGS s;
struct {
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;

// Cmd = 0 to read,


// 1 to write;
// Drive number,
// ....
int AbsAccess(int Cmd, int Drive, unsigned long SectorNo, unsigned char
*Buffer)
{

struct {
unsigned long SectorNumber;
unsigned short ReadSectors;
unsigned long TransferAddress;
} Block;

int Command=0x25;
unsigned int selector,mysegment,block_selector,block_mysegment;


int offset = 0, i, status;

// allocate DOS memory;
r.w.ax = 0x0100;
r.w.bx = BLOCKSIZE>>4; /* paragraph = 16 bytes */
int386x (0x31, &r, &r, &s);
if (r.w.cflag!=0)
{
printf("alloc failed\n");
exit(1);
}
mysegment = r.w.ax;
selector = r.w.dx;

if(Cmd == RD)
Command = 0x25;
else
Command = 0x26;

RMI.EAX = Drive;
RMI.ECX = 1;
RMI.EDX = SectorNo;
RMI.DS = mysegment;
RMI.EBX = 0;

/* use DPMI call 300h to issue DOS interrupt */

r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);
memcpy(Buffer,(unsigned char*)(mysegment<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;


if (status)
{
printf ("After 1st try, Carry Flag value, (0x%08x), Error value,

(0x%08x)\n",(unsigned long)(status), (unsigned long)(RMI.EAX));

// allocate more DOS memory for Block;

r.w.ax = 0x0100;
r.w.bx = sizeof(Block);
int386x (0x31, &r, &r, &s);
if (r.w.cflag!=0)
{
printf("alloc failed\n");
exit(1);
}
block_mysegment = r.w.ax;
block_selector = r.w.dx;

Block.SectorNumber = SectorNo;
Block.ReadSectors = 1;
Block.TransferAddress = mysegment;
printf("%x\n",Block.TransferAddress);

// copy Block to allocated DOS memory

memcpy((unsigned char*)(block_mysegment<<4),(unsigned
char*)&Block,sizeof(Block));

RMI.EAX = Drive;
RMI.ECX = 0xFFFF;
RMI.DS = block_mysegment;
RMI.EBX = 0;

/* use DPMI call 300h to issue DOS interrupt */

r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);
memcpy((unsigned char*)&Block,(unsigned
char*)(block_mysegment<<4),sizeof(Block));
memcpy(Buffer,(unsigned char*)(Block.TransferAddress<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;


if (status)
{
printf ("After using Block, Carry Flag value, (0x%08x), Error value,

(0x%08x)\n",(unsigned long)(status), (unsigned long)(RMI.EAX));


/* EAX will be 0x207 for FAT32 under DOS, but will be 0x1 for FAT32 under
Win98 SE */
/* int 0x21/ax=0x7305 code here */
}

// Free Dos Memory Block
r.w.ax = 0x101;
r.w.dx = block_selector;
r.w.cflag = 0x000;
int386x (0x31, &r, &r, &s);
}

// Free Dos Memory Block

r.w.ax = 0x101;
r.w.dx = selector;
r.w.cflag = 0x000;
int386x (0x31, &r, &r, &s);

if(!status)
{
printf ("\n");
for (i = 0;i < 512; i+=16)


{
if (i % 32 == 0)
printf

("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
" %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",

Buffer[i+0],Buffer[i+1],Buffer[i+2],Buffer[i+3],Buffer[i+4],Buffer[i+5],Buff
er[i+6],Buffer[i+7],

Buffer[i+8],Buffer[i+9],Buffer[i+10],Buffer[i+11],Buffer[i+12],Buffer[i+13],
Buffer[i+14],Buffer[i+15],

dotch(Buffer[i+0]),dotch(Buffer[i+1]),dotch(Buffer[i+2]),dotch(Buffer[i+3]),
dotch(Buffer[i+4]),dotch(Buffer[i+5]),dotch(Buffer[i+6]),dotch(Buffer[i+7]),

dotch(Buffer[i+8]),dotch(Buffer[i+9]),dotch(Buffer[i+10]),dotch(Buffer[i+11]
),dotch(Buffer[i+12]),dotch(Buffer[i+13]),dotch(Buffer[i+14]),dotch(Buffer[i
+15]));
}
}

return(0);
}

int main(void)
{
unsigned char *bufr;

bufr=malloc(BLOCKSIZE);

printf("1:");
AbsAccess(RD,0,0,bufr); /* read, A:, sector0, buf*/

#if 0


printf("2:");
AbsAccess(RD,2,0,bufr); /* read, C:, sector0, buf*/

#endif

#if 1


printf("3:");
AbsAccess(RD,3,0,bufr); /* read, D:, sector0, buf*/

#endif

#if 0


printf("4:");
AbsAccess(RD,3,130,bufr); /* read, D:, sector0, buf*/

#endif

#if 0


printf("5:");
AbsAccess(RD,3,0x192ff6c,bufr); /* read, D:, sector0, buf*/

#endif

return(0);
}

Vinayak Belamkar

unread,
Jul 21, 2005, 11:39:06 PM7/21/05
to
Hi,

> I think it goes like so...
> 1) select openwatcom.users.c_cpp, File->Properties->LocalFile->Reset
> 2) Tools->Read->News-> x Get 1000 headers at a time (check and set value)
> 3) select new.openwatcom.org, Tools->SynchronizeAccount

--- I started using the Google groups...has a better UI :-)

> I'd have to find a copy of 6.22 to check things out. As I said, I can't
> confirm the reading or copying of the data is correct.

--- I found an image of bootable disk of MSDOS 622 on www.allbootdisks.com
--- more than sufficient utils of DOS are available there to install MSDOS
622

> int 0x25 is only for FAT12 ( <32M partition)
> int 0x25/cx=0xFFFF is only for FAT16 (32M-4096M partition, if fdisked as
> FAT16, no large disk support)
> int 0x21/ax=7305 is only for FAT32 ( 32M-2T partition, if fdisked as
FAT32,
> yes large disk support)

--- I have attached my code herewith, OW 1.2
OK: Executes fine with MSDOS 7 in Win98, windowed mode.
FAILS:
- when executed in Command Prompt mode of Win98, (pressing F8 at boot time).
- with MSDOS 622;

I needed to modify very little of the code you provided, its execution
routine is:
Step 1: Tries the normal int 0x25 routine; (the FAT 12 code)
Step 2: When the above fails (carry & INTR_CF)......the int 0x25/cx=0xFFFF
routine is executed; (the FAT 16 code)
Step 3: When the above fails.....the int 0x21/ax=0x7305 routine is
executed; (the FAT 32 code)
Step 4: When everything fails, everything fails !

Output and result: On my MSDOS 622 setup, the Step 1 fails; then the int
0x25/cx=0xFFFF routine is executed and successful; BUT the complete
partition is no more available. I mean that dir listing shows "File not
found", no contents are displayed. Everything is fine after reboot.

Under Win98 Command Prompt mode, the partition is not available, message
"General Failure reading Drive C, Abort, Retry or Fail?".
I think you could try this on your Win98 too.


> May I ask why are you trying to use DOS routines instead of BIOS routines?
> Using int 0x13 and in0x13/ax=0x41-49,4E you should be able to read the
> entire disk. MS-DOS's routines are built upon the BIOS functions (except
> 0x21,ax=7305). If your BIOS doesn't support those, MS-DOS doesn't either.

--- int 0x13 gives me physical disk access, i.e. I will provide CHS and it
will give me data at that location,
but my requirements are for accessing logical sectors on volumes.

> I've reattached boot.c.
--- Thank you, I found it when I searched it on google groups.


Thank you,
Vinayak

CODE:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <bios.h>
#include <dos.h>
#include <i86.h>


#include <io.h>
#include <sys/stat.h>
#include <fcntl.h>


#define RD 0
#define WR 1
#define MAKEWORD(a,b) (((b)<<8)|(a))

int ResetDisk(int nDrive);
void WriteBufToBin (const char *pszFilename, const char *pszBuf, int iLen);
int AbsAccess16(int Cmd, int Drive, unsigned long SectorNo, unsigned char
*Buffer);

#pragma pack(1)


typedef struct tagRMInfo
{
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} REALMODEINFO;

#pragma pack()


// Cmd = 0 to read,
// 1 to write;
// Drive number,
// ....

int AbsAccess16(int Cmd, int Drive, unsigned long SectorNo, unsigned char


*Buffer)
{
#pragma pack(push,1)
struct LargeDiskIO
{
unsigned long StartingSector ;
unsigned short SectorCount ;
unsigned long BufferAddress;
} Block ;
#pragma pack(pop)

union REGS inregs, outregs ;
struct SREGS segs ;
int Command=0x25;
REALMODEINFO MY_RMI;
unsigned int selector = 0;
unsigned int mysegment = 0;
unsigned int block_selector = 0;
unsigned int block_mysegment = 0;
unsigned char *buf_boot = NULL;
unsigned char *pChar = NULL;
int iVal = 0;
unsigned long lVal = 0L;
int offset = 0, i, status;

char szFilename[256];

// Now to use int 0x25/cx=0xFFFF;

inregs.h.bl = Command; // interrupt number, ... = 0x25


inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);
memcpy(pChar,buf_boot,sizeof(Block));

status=MY_RMI.flags&INTR_CF;
if (status)
{
printf ("After using int 0x25/cx=0xFFFF, Carry Flag value, (0x%08x),


Error value, (0x%08x)\n",

(unsigned long)(status), (unsigned long)(MY_RMI.EAX));
/*
EAX will be 0x207 for FAT32 under DOS,
but will be 0x1 for FAT32 under Win98 SE
*/
/* int 0x21/ax=0x7305 code here */

memset (&MY_RMI, 0, sizeof(MY_RMI));

MY_RMI.EAX = 0x7305;


MY_RMI.ECX = 0xFFFF;
MY_RMI.DS = block_mysegment;
MY_RMI.EBX = 0;

MY_RMI.EDX = MAKEWORD(Drive, 0); // (DL, DH); drive: 0x1H = A, ...
MY_RMI.ESI = 0L;
Command = 0x21;

Block.StartingSector = SectorNo ;
Block.SectorCount = 1 ;
Block.BufferAddress = mysegment<<4;

// copy Block to allocated DOS memory
buf_boot = (unsigned char *)(block_mysegment<<4);
pChar = (unsigned char *)&Block;
memcpy(buf_boot,pChar,sizeof(Block));

/* use DPMI call 300h to issue DOS interrupt */


inregs.w.ax = 0x0300;
inregs.h.bl = Command; // interrupt number
inregs.h.bh = 0;
inregs.w.cx = 0; // dont push anything on the stack
segs.es = FP_SEG(&MY_RMI);
inregs.x.edi = FP_OFF(&MY_RMI);
inregs.w.cflag = 0;
int386x(0x31, &inregs, &outregs, &segs);
memcpy(pChar,buf_boot,sizeof(Block));

status=MY_RMI.flags&INTR_CF;
if (status)
{
printf (

"After using Block, int 0x21/ax=7305h, Carry Flag value, (0x%08x),


Error value, (0x%08x)\n",
(unsigned long)(status), (unsigned long)(MY_RMI.EAX));
}

else
{
buf_boot=(unsigned char *)(Block.BufferAddress);
memcpy(Buffer,buf_boot,512);
}
}
else
{
buf_boot=(unsigned char *)(Block.BufferAddress);
memcpy(Buffer,buf_boot,512);
}

// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = block_selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);
}

// Free Dos Memory Block
inregs.w.ax = 0x101;
inregs.w.dx = selector;
inregs.w.cflag = 0x000;
int386x (0x31, &inregs, &outregs, &segs);


if(!status)
{
printf("Passed\n");
#if 0

sprintf (szFilename, "c:\\16a%u.%u", SectorNo, Drive);
WriteBufToBin (szFilename, Buffer, 512);

for (i = 0 ;i < 512; i++)
{
if (i % 32 == 0)
printf ("\n");
printf ("%02x", Buffer[i]);
}
printf ("\n");
#endif

return(1);
}

return(0);
}

int ResetDisk(int nDrive)
{
union REGS regs;
struct SREGS sregs;


REALMODEINFO MY_RMI;
unsigned int selector = 0;
unsigned int mysegment = 0;

unsigned long lVal = 0L;

// allocate DOS memory;
memset (&regs, 0, sizeof(regs));
memset (&sregs, 0, sizeof(sregs));
regs.w.ax = 0x0100;
regs.w.bx = 0x0040;
int386x (0x31, &regs, &regs, &sregs);
mysegment = regs.w.ax;
selector = regs.w.dx;

// simulate the reset disk;
memset (&regs, 0, sizeof(regs));
memset (&sregs, 0, sizeof(sregs));


memset (&MY_RMI, 0, sizeof(MY_RMI));
lVal = 0L;

lVal = MAKEWORD(nDrive,0); // (DL, DH)
MY_RMI.EDX = lVal;

/* use DPMI call 300h to issue DOS interrupt */
regs.w.ax = 0x0300;
regs.h.bl = 0x13; // interrupt number
regs.h.bh = 0;


regs.w.cx = 0; // dont push anything on the stack

sregs.es = FP_SEG(&MY_RMI);
regs.x.edi = FP_OFF(&MY_RMI);
regs.w.cflag = 0;
int386x(0x31, &regs, &regs, &sregs);

// Free Dos Memory Block

regs.w.ax = 0x101;
regs.w.dx = selector;
regs.w.cflag = 0x0000;
int386x (0x31, &regs, &regs, &sregs);

return 1;
}


int main(void)
{
int iRet = 0;
unsigned char *bufr;

bufr=malloc(4096);

ResetDisk (0x00); // reset physical disk;
printf("1: for drive A, drive 0");
iRet = AbsAccess16(RD,0,0,bufr); /* read, A:, sector0, buf*/

ResetDisk (0x01); // reset physical disk;
printf("2: for drive C, drive 2");
iRet = AbsAccess16(RD,2,0,bufr); /* read, C:, sector0, buf*/

ResetDisk (0x80); // reset physical disk, assuming a single phy disk;
printf("3: for drive D, drive 3");
iRet = AbsAccess16(RD,3,0,bufr); /* read, D:, sector0, buf*/

ResetDisk (0x80); // reset physical disk, assuming a single phy disk;
printf("4: for drive D, drive 3 sector 130");
iRet = AbsAccess16(RD,3,130,bufr); /* read, D:, sector0, buf*/

ResetDisk (0x80); // reset physical disk, assuming a single phy disk;
printf("5: for drive D, drive 3 sector 0x192ff6c");
iRet = AbsAccess16(RD,3,0x192ff6c,bufr); /* read, D:, sector0, buf*/

return(0);
}


void WriteBufToBin (const char *pszFilename, const char *pszBuf, int iLen)
{
int nhFile = -1;
int iRet = 0;
nhFile = _open (pszFilename, O_CREAT | O_BINARY | O_RDWR, S_IREAD |
S_IWRITE);
if (-1 == nhFile)
{
return;
}
iRet = write (nhFile, pszBuf, iLen);
if (iRet != iLen)
{
// maybe give some error message;
}

_close (nhFile);
nhFile = -1;
}


Vinayak Belamkar

unread,
Jul 21, 2005, 11:39:07 PM7/21/05
to
First of all, the code WORKS FINE everywhere :D

> 1) the address in block is offset/segment as you had

--- as I had ??? do u mean the "TransferAddress" member in the Block
structure in this code ?


> 2) there needs to be another memcpy for the first read

--- ok, got it, I thought maybe since the address have been stored in th
Block, the memcpy after invoking the interrupt is not required. never done
something like this.


> Could you try out the following code?

--- tried the code, works fine, will try the int 0x21/ax=0x7305 code and let
you know.

Thanks,
Vinayak


Vinayak Belamkar

unread,
Jul 21, 2005, 11:39:07 PM7/21/05
to
Here is Rod Pemberton's code that I modified a bit to include int
21h/ax=7305h;
Works fine now with DOS622 also, as well as Win98's DOS.

Thanks a lot,
Vinayak
CODE:

value,(0x%08x)\n",(unsigned long)(status), (unsigned long)(RMI.EAX));

memset (&RMI, 0, sizeof(RMI));

RMI.EAX = 0x7305;


RMI.ECX = 0xFFFF;
RMI.DS = block_mysegment;
RMI.EBX = 0;

RMI.EDX = Drive; // drive: 0x1H = A, ...


RMI.ESI = 0L;
Command = 0x21;

Block.SectorNumber = SectorNo ;


Block.ReadSectors = 1 ;
Block.TransferAddress = mysegment;

// copy Block to allocated DOS memory
memcpy((unsigned char*)(block_mysegment<<4),(unsigned
char*)&Block,sizeof(Block));

/* use DPMI call 300h to issue DOS interrupt */


r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);
memcpy((unsigned char*)&Block,(unsigned
char*)(block_mysegment<<4),sizeof(Block));
memcpy(Buffer,(unsigned char*)(Block.TransferAddress<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;
if (status)
{
printf (

"After using Block, int 0x21/ax=7305h, Carry Flag value, (0x%08x),


Error value, (0x%08x)\n",
(unsigned long)(status), (unsigned long)(RMI.EAX));
}
}

// Free Dos Memory Block


r.w.ax = 0x101;
r.w.dx = block_selector;
r.w.cflag = 0x000;
int386x (0x31, &r, &r, &s);
}

// Free Dos Memory Block
r.w.ax = 0x101;
r.w.dx = selector;
r.w.cflag = 0x000;
int386x (0x31, &r, &r, &s);

if(!status)
{
printf ("\n");
for (i = 0;i < 512; i+=16)
{
if (i % 32 == 0)
printf
("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x
%02x %02x "
" %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",

Buffer[i+0],Buffer[i+1],Buffer[i+2],Buffer[i+3],Buffer[i+4],Buffer[i+5],

Buffer[i+6],Buffer[i+7],


Buffer[i+8],Buffer[i+9],Buffer[i+10],Buffer[i+11],Buffer[i+12],Buffer[i+13],
Buffer[i+14],Buffer[i+15],


dotch(Buffer[i+0]),dotch(Buffer[i+1]),dotch(Buffer[i+2]),dotch(Buffer[i+3]),

dotch(Buffer[i+4]),dotch(Buffer[i+5]),dotch(Buffer[i+6]),dotch(Buffer[i+7]),


dotch(Buffer[i+8]),dotch(Buffer[i+9]),dotch(Buffer[i+10]),dotch(Buffer[i+11]
),

dotch(Buffer[i+12]),dotch(Buffer[i+13]),dotch(Buffer[i+14]),dotch(Buffer[i+1
5]));
}
}

return(0);
}

int main(void)
{
unsigned char *bufr;
bufr=malloc(BLOCKSIZE);

printf("1:");
AbsAccess(RD,0,0,bufr); /* read, A:, sector0, buf*/

#if 1

Rod Pemberton

unread,
Jul 22, 2005, 11:35:59 PM7/22/05
to

"Vinayak Belamkar" <belamkar...@hotmail.com> wrote in message
news:dbo6vm$dvo$1...@www1.scitechsoft.com...

> Here is Rod Pemberton's code that I modified a bit to include int
> 21h/ax=7305h;
> Works fine now with DOS622 also, as well as Win98's DOS.
>
> Thanks a lot,
> Vinayak

You're welcome.

> 1) the address in block is offset/segment as you had
> --- as I had ??? do u mean the "TransferAddress" member
> in the Block structure in this code ?

Yes, "unsigned long TransferAddress" is the same as
"unsigned short BufferOffset" and "unsigned short BufferSegment"
put together.

"Block.TransferAddress = mysegment;" is the same as

"Block.BufferOffset=0;"
"Block.BufferSegment=mysegment;"


Later,

Rod Pemberton


Rod Pemberton

unread,
Jul 22, 2005, 11:36:00 PM7/22/05
to
"RMI.EDX=Drive;" shoud be "RMI.EDX=Drive +1;" in the int 0x21,ax=7305
section.

> With Win98 too? I don't think the int0x25, cx=0xFFFF works on
> my Win98SE... It gets different results from MS-DOS 7.10.

Oops, that's wrong.
int0x25 works for MS-DOS 7.10 and Win98SE
int0x25,cx=0xFFFF works for MS-DOS 7.10 and Win98SE
int 0x21,7305 works for MS-DOS 7.10

int 0x21,7305 *FAILS* with a page fault on Win98SE...

Rod Pemberton

Rod Pemberton

unread,
Jul 22, 2005, 11:36:00 PM7/22/05
to

"Vinayak Belamkar" <belamkar...@hotmail.com> wrote in message
news:dbo6vm$dvo$1...@www1.scitechsoft.com...

> Here is Rod Pemberton's code that I modified a bit to include int
> 21h/ax=7305h;
> Works fine now with DOS622 also, as well as Win98's DOS.
>

With Win98 too? I don't think the int0x25, cx=0xFFFF works on


my Win98SE... It gets different results from MS-DOS 7.10.

Rod Pemberton


Vinayak Belamkar

unread,
Jul 25, 2005, 11:39:02 PM7/25/05
to
Hi,
I dont know if this is really some problem or not....but the code seems to
have som problem.
Take the global variables r, s, and RMI within the scope of the function.
...and the program starts giving a Page Fault.

I hadn;t noticed it with the global variables.
Where could be the problem?

Regards,
Vinayak


"Rod Pemberton" <dont...@noreply.bit> wrote in message

news:dbqdgt$gm2$1...@www1.scitechsoft.com...

Rod Pemberton

unread,
Jul 25, 2005, 11:39:04 PM7/25/05
to
> int 0x21,7305 *FAILS* with a Page Fault on Win98SE...
no fix found yet.

> Take the global variables r, s, and RMI within the scope of the function.

> and the program starts giving a Page Fault.

problem confirmed for PMODEW. works with DOS4GW
Win98SE has same Page Fault as above.

One difficult problem found:
int 0x31, AX=0x0101 doesn't release memory
properly with DOS4GW. Since freeing memory fails,
multiple calls to AbsAccess() cause int 0x31, AX=0x0100
to act as a memory leak. You'll probably have to move
the 0x100 and 0x101 memory calls to main() so they are
only called once. This will prevents moving r,s,RMI into
AbsAccess()...


A few minor problems:

// for 0x0100 and 0x0101 calls, can use int386()
int386x(0x31,&r,&r,&s)
int386(0x31,&r,&r)

// should be long
unsigned int selector,mysegment,block_selector,block_mysegment;
unsigned long selector,mysegment,block_selector,block_mysegment;

// int 0x21,ax=7305
RMI.EDX=Drive;
RMI.EDX=Drive +1;

// allocates too much, 2nd 0x0100 call
r.w.bx = sizeof(Block);
r.w.bx = 1+(sizeof(Block)>>4);

// all should be unsigned


struct {
long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;

struct {
unsigned long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
unsigned short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;


Rod Pemberton


Rod Pemberton

unread,
Jul 25, 2005, 11:39:04 PM7/25/05
to

Also,

Win98SE doesn't call int 0x25/cx=0xFFFF for FAT16, it calls regular int
0x25.
Perhaps, you should obtain the filesystem type first then call one of the
three DOS read functions. The filesystem type can be found with:
int 0x21, ax=0x440d subf 0x66 (Get Volume Serial Number)
or
int 0x21, ax=0x69 subf 0x00 (Get Disk Serial Number)

Rod Pemberton


"Rod Pemberton" <dont...@noreply.bit> wrote in message

news:dc3mbl$2ke$1...@www1.scitechsoft.com...

Rod Pemberton

unread,
Jul 26, 2005, 11:39:25 PM7/26/05
to
> int 0x21,7305 *FAILS* with a Page Fault on Win98SE... I separated out int
0x25,cx=0xFFFF to test in Win98SE.
It fails with a Page Fault on Win98SE. Both routines that use the Block
structure fail with a Page Fault on Win98SE. I'm still trying to locate this
problem.

I found out that Block should be packed as you had it. I intuitively
corrected for the extra padding by adjusting the code. Anyway, I've
attached what I'm currently using with all fixes.

Rod Pemberton

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <bios.h>
#include <dos.h>
#include <i86.h>

#define RD 0
#define WR 1

#define BLOCKSIZE 512


#define dotch(i) (isprint(i)?(i):'.')

unsigned long selector,mysegment,block_selector,block_mysegment;

union REGS r;
struct SREGS s;

#pragma pack(1)


struct {
unsigned long EDI,ESI,EBP,rsvd,EBX,EDX,ECX,EAX;
unsigned short flags,ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;

struct {


unsigned long SectorNumber;
unsigned short ReadSectors;

unsigned long TransferAddress; // offset, segment
} Block;
#pragma pack()

// Cmd = 0 to read,
// 1 to write;
// Drive number,
// ....
int AbsAccess(int Cmd, int Drive, unsigned long SectorNo, unsigned char
*Buffer)
{

int Command=0x25;


int offset = 0, i, status;

printf ("1st try.\n");

if(Cmd == RD)
Command = 0x25;
else
Command = 0x26;

RMI.EAX = Drive;
RMI.ECX = 1;
RMI.EDX = SectorNo;
RMI.DS = mysegment;
RMI.EBX = 0;

/* use DPMI call 300h to issue DOS interrupt */
r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);
memcpy(Buffer,(unsigned char*)(mysegment<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;
if (status)
{
// printf ("After 1st try, Carry Flag value, (0x%08x), Error


value,(0x%08x)\n",(unsigned long)(status), (unsigned long)(RMI.EAX));

printf ("2nd try.\n");

Block.SectorNumber = SectorNo;
Block.ReadSectors = 1;

Block.TransferAddress = mysegment<<16;

// copy Block to allocated DOS memory
memcpy((unsigned char*)(block_mysegment<<4),(unsigned
char*)&Block,sizeof(Block));

RMI.EAX = Drive;
RMI.ECX = 0xFFFF;
RMI.DS = block_mysegment;
RMI.EBX = 0;

/* use DPMI call 300h to issue DOS interrupt */
r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);

memcpy(Buffer,(unsigned char*)(mysegment<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;
if (status)
{
// printf ("After using Block, Carry Flag value, (0x%08x), Error value,


(0x%08x)\n",(unsigned long)(status), (unsigned long)(RMI.EAX));

printf ("3rd try.\n");


/* EAX will be 0x207 for FAT32 under DOS, but will be 0x1 for FAT32
under Win98 SE */

RMI.EAX = 0x7305;
RMI.ECX = 0xFFFF;
RMI.EDX = Drive+1;
if(Cmd == RD)
RMI.ESI = 0L;
else
RMI.ESI = 0L; // bit 1 set for write
// RMI.ESI = 0x6001L; // file
// RMI.ESI = 0x4001L; // dir
// RMI.ESI = 0x2001L; // FAT
// RMI.ESI = 0x0001L; // other


RMI.DS = block_mysegment;
RMI.EBX = 0;

Command = 0x21;

Block.SectorNumber = SectorNo;
Block.ReadSectors = 1;

Block.TransferAddress = mysegment<<16;

// copy Block to allocated DOS memory
memcpy((unsigned char*)(block_mysegment<<4),(unsigned
char*)&Block,sizeof(Block));

/* use DPMI call 300h to issue DOS interrupt */
r.w.ax = 0x0300;
r.h.bl = Command; // interrupt number
r.h.bh = 0;
r.w.cx = 0; // dont push anything on the stack
s.es = FP_SEG(&RMI);
r.x.edi = FP_OFF(&RMI);
r.w.cflag = 0;
int386x(0x31, &r, &r, &s);

memcpy(Buffer,(unsigned char*)(mysegment<<4),BLOCKSIZE);

status=RMI.flags&INTR_CF;
if (status)
{
// printf ("After using Block, int 0x21/ax=7305h, Carry Flag value, (0x%0
8x), Error value, (0x%08x)\n", (unsigned long)(status), (unsigned
long)(RMI.EAX));
printf("3rd failed.\n");
}
}
}


#if 1


if(!status)
{
printf ("\n");
for (i = 0;i < 512; i+=16)
{
if (i % 32 == 0)
printf
("%02x%02x%02x%02x%02x%02x%02x%02x"

":%02x%02x%02x%02x%02x%02x%02x%02x"
":%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",


Buffer[i+0],Buffer[i+1],Buffer[i+2],Buffer[i+3],

Buffer[i+4],Buffer[i+5],Buffer[i+6],Buffer[i+7],


Buffer[i+8],Buffer[i+9],Buffer[i+10],Buffer[i+11],

Buffer[i+12],Buffer[i+13],Buffer[i+14],Buffer[i+15],


dotch(Buffer[i+0]),dotch(Buffer[i+1]),dotch(Buffer[i+2]),
dotch(Buffer[i+3]),dotch(Buffer[i+4]),dotch(Buffer[i+5]),
dotch(Buffer[i+6]),dotch(Buffer[i+7]),dotch(Buffer[i+8]),
dotch(Buffer[i+9]),dotch(Buffer[i+10]),dotch(Buffer[i+11]),
dotch(Buffer[i+12]),dotch(Buffer[i+13]),dotch(Buffer[i+14]),
dotch(Buffer[i+15]));
}
}

#endif

return(0);
}

int main(void)
{
unsigned char *bufr;
bufr=malloc(BLOCKSIZE);

// error in DOS4GW 0x0101
// does not free memory properly
// avoid calling 0x0100 and 0x0101

// allocate DOS memory;
r.w.ax = 0x0100;
r.w.bx = BLOCKSIZE>>4; /* paragraph = 16 bytes */

int386 (0x31, &r, &r);
if (r.w.cflag&INTR_CF)


{
printf("alloc failed\n");
}

mysegment = r.w.ax;
selector = r.w.dx;

// allocate more DOS memory for Block;
r.w.ax = 0x0100;
r.w.bx = 1+(sizeof(Block)>>4); /* paragraph = 16 bytes */
int386 (0x31, &r, &r);
if (r.w.cflag&INTR_CF)


{
printf("alloc failed\n");
}

block_mysegment = r.w.ax;
block_selector = r.w.dx;

#if 1


printf("1:");
AbsAccess(RD,0,0,bufr); /* read, A:, sector0, buf*/

#endif

#if 1
printf("2:");

AbsAccess(RD,3,0,bufr); /* read, D:, sector0, buf*/
#endif

#if 1
printf("3:");


AbsAccess(RD,2,0,bufr); /* read, C:, sector0, buf*/
#endif

#if 0


printf("4:");
AbsAccess(RD,3,130,bufr); /* read, D:, sector0, buf*/
#endif

#if 0
printf("5:");
AbsAccess(RD,3,0x192ff6c,bufr); /* read, D:, sector0, buf*/
#endif

// Free Dos Memory Block
r.w.ax = 0x0101;
r.w.dx = block_selector;
r.w.cflag = 0x0000;
int386 (0x31, &r, &r);
if (r.w.cflag&INTR_CF)
{
printf("dealloc failed\n");
}

// Free Dos Memory Block

r.w.ax = 0x0101;
r.w.dx = selector;
r.w.cflag = 0x0000;
int386 (0x31, &r, &r);
if (r.w.cflag&INTR_CF)
{
printf("dealloc failed\n");
}

return(0);
}

Rod Pemberton

unread,
Jul 28, 2005, 11:39:04 PM7/28/05
to
> It fails with a Page Fault on Win98SE. Both routines that use the Block
> structure fail with a Page Fault on Win98SE. I'm still trying to locate
this
> problem.

I've found the basic problem. I'm still working on fix though...

I located some DJGPP code for the same disk routines. It had the same Page
Fault under Win98SE. The problem appears to be with the DOS memory used for
the Block structure. I'd assume that the RMI structure may also have a
problem. It appears that int 0x31, ax=0x0100, which is supposed to allocate
DOS memory, allocates memory but the memory is not below 1Mb. The memory is
in the program application space... int 0x31, ax=0x0800, map physical
memory confirms this by returning a different physical address than the
linear address for the Block. So do these, referencing GlobalDOSAlloc(),
from Micro$oft:

http://support.microsoft.com/default.aspx?scid=kb;en-us;95545
http://support.microsoft.com/default.aspx?scid=kb;en-us;124729

It appears that a new descriptor must be setup for real 1Mb memory. I am
not sure exactly how to allocate the real 1Mb memory thought. I also am not
sure how to force the paging DPMI host under Win98SE to map the memory into
it's page tables. I've found one Dr. Dobb's Journal article which indicates
that allocating the descriptor and setting the base should be enough for
Win98SE... We'll see.

Rod Pemberton


PS. Info. included below

From 95545:
> GlobalDosAlloc() allocates memory below 1 MB in linear
> address space. In standard mode, this memory is in the first
> megabyte of physical memory because linear addresses are
> the same as physical addresses. In 386 enhanced mode,
> however, linear addresses are not the same as physical
> addresses. Memory allocated via GlobalDosAlloc() is not
> guaranteed to reside in the first megabyte of physical
> memory nor to be physically contiguous. Furthermore,
> because the physical address of a memory block allocated
> via GlobalDosAlloc() is not known in 386 enhanced mode,
> it is not suitable for DMA transfers or memory-mapped
> hardware. In 386 enhanced mode Windows,
> GlobalDosAlloc() allocates memory blocks in the
> Windows virtual machine only

From 124729:
> GlobalDosAlloc() does not guarantee anything about
> the physical memory properties of the memory it
> allocates. In particular, the memory may not be
> physically contiguous, and it may be physically
> located above one megabyte. However, it does
> guarantee that the linear address of memory is
> below one megabyte.
> ...
> In enhanced mode Windows, GlobalAlloc() can
> allocate memory with a linear address above 16
> megabytes. In particular, the address should be
> above two gigabytes if it is not below one megabyte.


Rod Pemberton

unread,
Jul 30, 2005, 11:38:04 PM7/30/05
to
Well,

I eventually found some memory that Win98SE had mapped and wasn't using.
The code still generated a page fault.

Then, I ran across a mention that Win98SE uses drive locking. So, I tried:
A) lock levels 0 to 3 with physical locking and registers specified by MSDN
B) lock levels 0 to 3 with logical locking and registers specified by MSDN
C) lock levels 0 to 3 with physical locking and registers specified by RBIL
(different from MSDN...)
D) lock levels 0 to 3 with logical locking and registers specified by RBIL
(different from MSDN...)

All combinations failed.

Anyway, I've spent a large amount of time trying to get the DOS code to work
under Win98SE.
I don't need the code and very few people ever will need the code.

So, I've quit working on this problem.


Rod Pemberton


Rod Pemberton

unread,
Aug 4, 2005, 11:37:58 PM8/4/05
to
I may resume looking at this. It appears that Ortin Glueck (Odi's LFN
Tools) managed to get the locking issue resolved for MSVC...


0 new messages