如果你需要一个干净的DPMI解决方案,你可能需要探索以下DPMI函数(摘自Ralf Brown的中断列表):
INT 31 P - DPMI 1.0+ - MAP DEVICE IN MEMORY BLOCK
AX = 0508h
ESI = memory block handle
EBX = page-aligned offset within memory block of page(s) to be mapped
ECX = number of pages to map
EDX = page-aligned physical address of device
Return: CF clear if successful
CF set on error
AX = error code (8001h,8003h,8023h,8025h) (see #03143)
Notes: only supported by 32-bit DPMI hosts, but may be used by 16-bit clients
support of this function is optional; hosts are also allowed to support
the function for some devices but not others
INT 31 P - DPMI 1.0+ - MAP CONVENTIONAL MEMORY IN MEMORY BLOCK
AX = 0509h
ESI = memory block handle
EBX = page-aligned offset within memory block of page(s) to map
ECX = number of pages to map
EDX = page-aligned linear address of conventional (below 1M) memory
Return: CF clear if successful
CF set on error
AX = error code (8001h,8003h,8023h,8025h) (see #03143)
Notes: only supported by 32-bit DPMI hosts, but may be used by 16-bit clients
support of this function is optional
INT 31 P - DPMI 0.9+ - PHYSICAL ADDRESS MAPPING
AX = 0800h
BX:CX = physical address (should be above 1 MB)
SI:DI = size in bytes
Return: CF clear if successful
BX:CX = linear address which maps the requested physical memory
CF set on error
AX = error code (DPMI 1.0+) (8003h,8021h) (see #03143)
Notes: implementations may refuse this call because it can circumvent protects
the caller must build an appropriate selector for the memory
do not use for memory mapped in the first megabyte
如果以上两种方法都无法将虚拟地址映射到物理地址或获取已分配块的物理地址(例如不支持),则需要查看DPMI主机的实现细节(例如是否启用页面转换或是否可以关闭,那么所有地址都是物理地址)。
编辑:看起来您应该能够分配内存(超过1MB)并获得其物理和虚拟地址。首先,使用XMS / Himem.sys分配它并锁定它。这将给您物理地址。接下来,使用DPMI函数0x800获取相应的虚拟地址。
以下是如何执行此操作(请忽略16位版本(使用Borland / Turbo C / C ++编译),仅用于验证XMS例程):
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <limits.h>
#if defined(__WATCOMC__)
#if !defined(__386__)
#error unsupported target, must be 32-bit (DPMI) DOS app
#endif
#elif defined(__TURBOC__)
#if !defined(__SMALL__)
#error unsupported target, must be 16-bit DOS app with small memory model
#endif
#else
#error unsupported compiler
#endif
typedef unsigned uint;
typedef unsigned long ulong;
typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
#if UINT_MIN >= 0xFFFFFFFF
typedef int int32;
typedef unsigned uint32;
#else
typedef long int32;
typedef unsigned long uint32;
#endif
#pragma pack(push, 1)
typedef struct tDpmiRmInt
{
uint32 edi, esi, ebp, resz0, ebx, edx, ecx, eax;
uint16 flags, es, ds, fs, gs, ip, cs, sp, ss;
} tDpmiRmInt;
#pragma pack(pop)
int RmInt(uint8 IntNumber, tDpmiRmInt* pRegs)
{
#if defined(__WATCOMC__)
union REGS inregs, outregs;
memset(&inregs, 0, sizeof(inregs));
memset(&outregs, 0, sizeof(outregs));
inregs.w.ax = 0x300;
inregs.h.bl = IntNumber;
inregs.h.bh = 0;
inregs.w.cx = 0;
inregs.x.edi = (uint32)pRegs;
return int386(0x31, &inregs, &outregs);
#elif defined(__TURBOC__)
struct REGPACK regs;
memset(®s, 0, sizeof(regs));
regs.r_ax = (uint16)pRegs->eax;
regs.r_bx = (uint16)pRegs->ebx;
regs.r_cx = (uint16)pRegs->ecx;
regs.r_dx = (uint16)pRegs->edx;
regs.r_si = (uint16)pRegs->esi;
regs.r_di = (uint16)pRegs->edi;
regs.r_bp = (uint16)pRegs->ebp;
regs.r_flags = pRegs->flags;
regs.r_ds = pRegs->ds;
regs.r_es = pRegs->es;
intr(IntNumber, ®s);
memset(pRegs, 0, sizeof(*pRegs));
pRegs->eax = regs.r_ax;
pRegs->ebx = regs.r_bx;
pRegs->ecx = regs.r_cx;
pRegs->edx = regs.r_dx;
pRegs->esi = regs.r_si;
pRegs->edi = regs.r_di;
pRegs->ebp = regs.r_bp;
pRegs->flags = regs.r_flags;
pRegs->ds = regs.r_ds;
pRegs->es = regs.r_es;
return regs.r_ax;
#endif
}
int RmFarCall(tDpmiRmInt* pRegs)
{
#if defined(__WATCOMC__)
union REGS inregs, outregs;
memset(&inregs, 0, sizeof(inregs));
memset(&outregs, 0, sizeof(outregs));
inregs.w.ax = 0x301;
inregs.h.bh = 0;
inregs.w.cx = 0;
inregs.x.edi = (uint32)pRegs;
return int386(0x31, &inregs, &outregs);
#elif defined(__TURBOC__)
uint8 code[128];
uint8* p = code;
void far* codef = &code[0];
void (far* f)(void) = (void(far*)(void))codef;
*p++ = 0x60;
*p++ = 0x1E;
*p++ = 0x06;
*p++ = 0x68; *p++ = (uint8)pRegs->ds; *p++ = (uint8)(pRegs->ds >> 8);
*p++ = 0x1F;
*p++ = 0x68; *p++ = (uint8)pRegs->es; *p++ = (uint8)(pRegs->es >> 8);
*p++ = 0x07;
*p++ = 0xb8; *p++ = (uint8)pRegs->eax; *p++ = (uint8)(pRegs->eax >> 8);
*p++ = 0xbb; *p++ = (uint8)pRegs->ebx; *p++ = (uint8)(pRegs->ebx >> 8);
*p++ = 0xb9; *p++ = (uint8)pRegs->ecx; *p++ = (uint8)(pRegs->ecx >> 8);
*p++ = 0xba; *p++ = (uint8)pRegs->edx; *p++ = (uint8)(pRegs->edx >> 8);
*p++ = 0xbe; *p++ = (uint8)pRegs->esi; *p++ = (uint8)(pRegs->esi >> 8);
*p++ = 0xbf; *p++ = (uint8)pRegs->edi; *p++ = (uint8)(pRegs->edi >> 8);
*p++ = 0xbd; *p++ = (uint8)pRegs->ebp; *p++ = (uint8)(pRegs->ebp >> 8);
*p++ = 0x9A; *p++ = (uint8)pRegs->ip; *p++ = (uint8)(pRegs->ip >> 8);
*p++ = (uint8)pRegs->cs; *p++ = (uint8)(pRegs->cs >> 8);
*p++ = 0x60;
*p++ = 0x1E;
*p++ = 0x06;
*p++ = 0x89; *p++ = 0xE5;
*p++ = 0x8E; *p++ = 0x5E; *p++ = 0x16;
*p++ = 0x89; *p++ = 0xEE;
*p++ = 0xFC;
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->es; *p++ = (uint8)((uint16)&pRegs->es >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->ds; *p++ = (uint8)((uint16)&pRegs->ds >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->edi; *p++ = (uint8)((uint16)&pRegs->edi >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->esi; *p++ = (uint8)((uint16)&pRegs->esi >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->ebp; *p++ = (uint8)((uint16)&pRegs->ebp >> 8);
*p++ = 0xAD;
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->ebx; *p++ = (uint8)((uint16)&pRegs->ebx >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->edx; *p++ = (uint8)((uint16)&pRegs->edx >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->ecx; *p++ = (uint8)((uint16)&pRegs->ecx >> 8);
*p++ = 0xAD;
*p++ = 0xA3; *p++ = (uint8)&pRegs->eax; *p++ = (uint8)((uint16)&pRegs->eax >> 8);
*p++ = 0x83; *p++ = 0xC4; *p++ = 0x14;
*p++ = 0x07;
*p++ = 0x1F;
*p++ = 0x61;
*p++ = 0xCB;
f();
return (uint16)pRegs->eax;
#endif
}
struct
{
uint16 Ip, Cs;
} XmsEntryPoint = { 0 };
int XmsSupported(void)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x4300;
RmInt(0x2F, ®s);
return (regs.eax & 0xFF) == 0x80;
}
void XmsInit(void)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x4310;
RmInt(0x2F, ®s);
XmsEntryPoint.Cs = regs.es;
XmsEntryPoint.Ip = (uint16)regs.ebx;
}
int XmsQueryVersions(uint16* pXmsVer, uint16* pHimemVer)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x00 << 8;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
if (pXmsVer != NULL)
*pXmsVer = (uint16)regs.eax;
if (pHimemVer != NULL)
*pHimemVer = (uint16)regs.ebx;
return (int)(regs.ebx & 0xFF);
}
int XmsQueryFreeMem(uint16* pLargest, uint16* pTotal)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x08 << 8;
regs.ebx = 0;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
if (pLargest != NULL)
*pLargest = (uint16)regs.eax;
if (pTotal != NULL)
*pTotal = (uint16)regs.edx;
return (int)(regs.ebx & 0xFF);
}
int XmsAllocMem(uint16* pHandle, uint16 Size)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x09 << 8;
regs.edx = Size;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
*pHandle = (uint16)regs.edx;
return (int)(regs.ebx & 0xFF);
}
int XmsFreeMem(uint16 Handle)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x0A << 8;
regs.edx = Handle;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
return (int)(regs.ebx & 0xFF);
}
int XmsLockMem(uint16 Handle, uint32* pPhysAddr)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x0C << 8;
regs.edx = Handle;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
*pPhysAddr = ((regs.edx & 0xFFFF) << 16) | (regs.ebx & 0xFFFF);
return (int)(regs.ebx & 0xFF);
}
#if defined(__TURBOC__)
int XmsCopyMem(uint16 DstHandle, uint32 DstOffs, uint16 SrcHandle, uint32 SrcOffs, uint32 Size)
{
tDpmiRmInt regs;
#pragma pack(push, 1)
struct
{
uint32 Size;
uint16 SrcHandle;
uint32 SrcOffs;
uint16 DstHandle;
uint32 DstOffs;
} emm;
#pragma pack(pop)
emm.Size = Size;
emm.SrcHandle = SrcHandle;
emm.SrcOffs = SrcOffs;
emm.DstHandle = DstHandle;
emm.DstOffs = DstOffs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x0B << 8;
regs.ds = FP_SEG(&emm);
regs.esi = FP_OFF(&emm);
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
return (int)(regs.ebx & 0xFF);
}
#endif
int XmsUnlockMem(uint16 Handle)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x0D << 8;
regs.edx = Handle;
regs.cs = XmsEntryPoint.Cs;
regs.ip = XmsEntryPoint.Ip;
RmFarCall(®s);
return (int)(regs.ebx & 0xFF);
}
#if defined(__WATCOMC__)
int DpmiMap(void** pPtr, uint32 PhysAddr, uint32 Size)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x800;
regs.ebx = PhysAddr >> 16;
regs.ecx = PhysAddr & 0xFFFF;
regs.esi = Size >> 16;
regs.edi = Size & 0xFFFF;
RmInt(0x31, ®s);
*pPtr = (void*)(((regs.ebx & 0xFFFF) << 16) | (regs.ecx & 0xFFFF));
return regs.flags & 1;
}
int DpmiUnmap(void* Ptr)
{
tDpmiRmInt regs;
memset(®s, 0, sizeof(regs));
regs.eax = 0x801;
regs.ebx = (uint32)Ptr >> 16;
regs.ecx = (uint32)Ptr & 0xFFFF;
RmInt(0x31, ®s);
return regs.flags & 1;
}
#endif
int main(void)
{
uint16 xmsVer, himemVer;
uint16 largestFreeSz, totalFreeSz;
uint16 handle;
uint32 physAddr;
#if defined(__WATCOMC__)
{
uint32 cr0__ = 0, cr3__ = 0;
__asm
{
mov eax, cr0
mov cr0__, eax
mov eax, cr3
mov cr3__, eax
}
printf("CR0: 0x%08lX, CR3: 0x%08lX\n", (ulong)cr0__, (ulong)cr3__);
}
#endif
if (!XmsSupported())
{
printf("XMS unsupported\n");
goto Exit;
}
printf("XMS supported\n");
XmsInit();
printf("XMS entry point: 0x%04X:0x%04X\n",
XmsEntryPoint.Cs, XmsEntryPoint.Ip);
XmsQueryVersions(&xmsVer, &himemVer);
printf("XMS version: 0x%X Himem.sys version: 0x%X\n",
xmsVer, himemVer);
XmsQueryFreeMem(&largestFreeSz, &totalFreeSz);
printf("Largest free block size: %u KB Total free memory: %u KB\n",
largestFreeSz, totalFreeSz);
printf("Allocating the DMA buffer...\n");
if (XmsAllocMem(&handle, 64))
{
printf("Failed to allocate the DMA buffer\n");
goto Exit;
}
XmsQueryFreeMem(&largestFreeSz, &totalFreeSz);
printf("Largest free block size: %u KB Total free memory: %u KB\n",
largestFreeSz, totalFreeSz);
printf("Locking the DMA buffer...\n");
if (XmsLockMem(handle, &physAddr))
{
printf("Failed to lock the DMA buffer\n");
}
else
{
printf("The DMA buffer is at physical address: 0x%08lX\n", (ulong)physAddr);
#if defined(__WATCOMC__)
{
uint8* ptr;
printf("Mapping the DMA buffer...\n");
if (DpmiMap((void**)&ptr, physAddr, 64 * 1024UL))
{
printf("Failed to map the DMA buffer\n");
}
else
{
printf("The DMA buffer is at virtual address: 0x%08lX\n", (ulong)ptr);
printf("Using the DMA buffer...\n");
strcpy(ptr, "This is a test string in the DMA buffer.");
printf("%s\n", ptr);
DpmiUnmap(ptr);
}
}
#elif defined(__TURBOC__)
{
char testStr[] = "This is a test string copied to and from the DMA buffer.";
printf("Using the DMA buffer...\n");
if (XmsCopyMem(handle, 0, 0, ((uint32)FP_SEG(testStr) << 16) + FP_OFF(testStr), sizeof(testStr)))
{
printf("Failed to copy to the DMA buffer\n");
}
else
{
memset(testStr, 0, sizeof(testStr));
if (XmsCopyMem(0, ((uint32)FP_SEG(testStr) << 16) + FP_OFF(testStr), handle, 0, sizeof(testStr)))
{
printf("Failed to copy from the DMA buffer\n");
}
else
{
printf("%s\n", testStr);
}
}
}
#endif
XmsUnlockMem(handle);
}
XmsFreeMem(handle);
XmsQueryFreeMem(&largestFreeSz, &totalFreeSz);
printf("Largest free block size: %u KB Total free memory: %u KB\n",
largestFreeSz, totalFreeSz);
Exit:
return 0;
}
样例输出(在DosBox下):
CR0: 0x00000001, CR3: 0x00000000
XMS supported
XMS entry point: 0xC83F:0x0010
XMS version: 0x300 Himem.sys version: 0x301
Largest free block size: 11072 KB Total free memory: 11072 KB
Allocating the DMA buffer...
Largest free block size: 11008 KB Total free memory: 11008 KB
Locking the DMA buffer...
The DMA buffer is at physical address: 0x00530000
Mapping the DMA buffer...
The DMA buffer is at virtual address: 0x00530000
Using the DMA buffer...
This is a test string in the DMA buffer.
Largest free block size: 11072 KB Total free memory: 11072 KB
请注意,DOS/32不启用页面翻译(除非有VCPI)。CR0的PG位为0,CR3为0,获得的物理地址和虚拟地址相同,这一切都说明虚拟地址和物理地址是相同的东西。