aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Hensl <jara@hensl.cz>2023-06-28 22:04:13 +0200
committerJaroslav Hensl <jara@hensl.cz>2023-06-28 22:04:13 +0200
commit7f80983c1b9431380a9dce18586e0eea57be5707 (patch)
tree48c295786a1f749f883989cef3063fd123134370
parent14395d1ce8759ce490beb87c80ddb1f7ed35904f (diff)
downloadvmdisp9x-7f80983c1b9431380a9dce18586e0eea57be5707.tar.gz
SVGA3D: better GMR allocator, some 32bit calls support, API version update
-rw-r--r--control.c25
-rw-r--r--control_vxd.c16
-rw-r--r--control_vxd.h4
-rw-r--r--dbgprint.c6
-rw-r--r--makefile2
-rw-r--r--version.h2
-rw-r--r--vmdisp9x.inf2
-rw-r--r--vmm.h25
-rw-r--r--vmwsvxd.c275
9 files changed, 319 insertions, 38 deletions
diff --git a/control.c b/control.c
index 548f2e1..2f7c132 100644
--- a/control.c
+++ b/control.c
@@ -306,7 +306,7 @@ void SVGAHDA_init()
SVGAHDA.ul_fence_index = SVGAHDA.ul_flags_index + 5;
SVGAHDA.ul_gmr_start = SVGAHDA.ul_fence_index + 1;
SVGAHDA.ul_gmr_count = SVGA_ReadReg(SVGA_REG_GMR_MAX_IDS);
- SVGAHDA.ul_ctx_start = SVGAHDA.ul_gmr_start + SVGAHDA.ul_gmr_count*3;
+ SVGAHDA.ul_ctx_start = SVGAHDA.ul_gmr_start + SVGAHDA.ul_gmr_count*4;
SVGAHDA.ul_ctx_count = GetDevCap(SVGA3D_DEVCAP_MAX_CONTEXT_IDS);
SVGAHDA.ul_surf_start = SVGAHDA.ul_ctx_start + SVGAHDA.ul_ctx_count;
SVGAHDA.ul_surf_count = GetDevCap(SVGA3D_DEVCAP_MAX_SURFACE_IDS);
@@ -372,12 +372,17 @@ void SVGAHDA_update(DWORD width, DWORD height, DWORD bpp, DWORD pitch)
FBHDA_REQ
* 2) access VMWare SVGA II registers and memory to real GPU acceleration
*
+ * 2023-II:
+ * Added DCICOMMAND to query DirectDraw/DirectX interface
+ *
**/
LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
LPVOID lpInput, LPVOID lpOutput)
{
LONG rc = -1;
+ dbg_printf("Control (16bit): %d (0x%x)\n", function, function);
+
if(function == QUERYESCSUPPORT)
{
WORD function_code = 0;
@@ -442,7 +447,7 @@ LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
}
else if(function == DCICOMMAND) /* input ptr DCICMD */
{
- DCICMD_t __far *lpDCICMD = lpInput;
+ DCICMD_t __far *lpDCICMD = lpInput;
if(lpDCICMD != NULL)
{
if(lpDCICMD->dwVersion == DD_VERSION)
@@ -563,18 +568,19 @@ LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
uint32_t __far *lpOut = lpOutput;
uint32_t rid = lpIn[0];
- dbg_printf("Region id = %ld\n", rid);
+ dbg_printf("Region id = %ld, max desc = %ld\n", rid, SVGA_ReadReg(SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH));
if(rid)
{
uint32_t lAddr;
uint32_t ppn;
+ uint32_t pgblk;
VXD_load();
- if(VXD_CreateRegion(lpIn[1], &lAddr, &ppn)) /* allocate physical memory */
+ if(VXD_CreateRegion(lpIn[1], &lAddr, &ppn, &pgblk)) /* allocate physical memory */
{
- dbg_printf("Region address = %lX, PPN = %lX\n", lAddr, ppn);
+ dbg_printf("Region address = %lX, PPN = %lX, GMRBLK = %lX\n", lAddr, ppn, pgblk);
SVGA_WriteReg(SVGA_REG_GMR_ID, rid);
SVGA_WriteReg(SVGA_REG_GMR_DESCRIPTOR, ppn);
@@ -583,12 +589,14 @@ LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
SVGA_Flush();
lpOut[0] = rid;
- lpOut[1] = lAddr + 4096;
+ lpOut[1] = lAddr;
+ lpOut[2] = pgblk;
}
else
{
lpOut[0] = 0;
lpOut[1] = 0;
+ lpOut[2] = 0;
}
}
@@ -598,7 +606,8 @@ LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
{
uint32_t __far *lpin = lpInput;
uint32_t id = lpin[0];
- uint32_t linear = lpin[1] - 4096;
+ uint32_t linear = lpin[1];
+ uint32_t pgblk = lpin[2];
/* flush all register inc. fifo so make sure, that all commands are processed */
SVGA_Flush();
@@ -611,7 +620,7 @@ LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
/* region physical delete */
VXD_load();
- VXD_FreeRegion(linear);
+ VXD_FreeRegion(linear, pgblk);
rc = 1;
}
diff --git a/control_vxd.c b/control_vxd.c
index 23630af..aaefb18 100644
--- a/control_vxd.c
+++ b/control_vxd.c
@@ -73,11 +73,12 @@ BOOL VXD_load()
return VXD_srv != 0;
}
-BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN)
+BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN, uint32_t __far *lpPGBLKAddr)
{
static uint32_t snPages;
static uint32_t sLAddr;
static uint32_t sPPN;
+ static uint32_t sPGBLKAddr;
static uint16_t state = 0;
snPages = nPages;
@@ -90,6 +91,7 @@ BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *
push eax
push edx
push ecx
+ push ebx
mov edx, VMWSVXD_PM16_CREATE_REGION
mov ecx, [snPages]
@@ -97,7 +99,9 @@ BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *
mov [state], ax
mov [sLAddr], edx
mov [sPPN], ecx
+ mov [sPGBLKAddr], ebx
+ pop ebx
pop ecx
pop edx
pop eax
@@ -107,6 +111,7 @@ BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *
{
*lpLAddr = sLAddr;
*lpPPN = sPPN;
+ *lpPGBLKAddr = sPGBLKAddr;
return TRUE;
}
@@ -119,12 +124,14 @@ BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *
return FALSE;
}
-BOOL VXD_FreeRegion(uint32_t LAddr)
+BOOL VXD_FreeRegion(uint32_t LAddr, uint32_t PGBLKAddr)
{
static uint32_t sLAddr;
static uint16_t state;
+ static uint32_t sPGBLKAddr;
sLAddr = LAddr;
+ sPGBLKAddr = PGBLKAddr;
if(VXD_srv != 0)
{
@@ -134,12 +141,15 @@ BOOL VXD_FreeRegion(uint32_t LAddr)
push eax
push edx
push ecx
+ push ebx
mov edx, VMWSVXD_PM16_DESTROY_REGION
- mov ecx, [LAddr]
+ mov ecx, [sLAddr]
+ mov ebx, [sPGBLKAddr]
call dword ptr [VXD_srv]
mov [state], ax
+ pop ebx
pop ecx
pop edx
pop eax
diff --git a/control_vxd.h b/control_vxd.h
index a515731..e2b624f 100644
--- a/control_vxd.h
+++ b/control_vxd.h
@@ -2,8 +2,8 @@
#define __CONTROL_VXD_H__INCLUDED__
BOOL VXD_load();
-BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN);
-BOOL VXD_FreeRegion(uint32_t LAddr);
+BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN, uint32_t __far *lpPGBLKAddr);
+BOOL VXD_FreeRegion(uint32_t LAddr, uint32_t PGBLKAddr);
void VXD_zeromem(uint32_t LAddr, uint32_t size);
uint32_t VXD_apiver();
diff --git a/dbgprint.c b/dbgprint.c
index d460c0c..e5aa1fa 100644
--- a/dbgprint.c
+++ b/dbgprint.c
@@ -231,6 +231,11 @@ void dbg_printf( const char *s, ... )
if( conv ) {
/* Time to start grabbing stuff off the stack. */
+#ifdef VXD32
+ /* in 32-bit are all args 32bit... */
+ dword = va_arg( args, uint32_t );
+ word = (dword & 0xFFFF);
+#else
word = va_arg( args, uint16_t );
/* If argument is double wide, build a doubleword. */
if( type_len == 'l' || type_len == 'W' ) {
@@ -238,6 +243,7 @@ void dbg_printf( const char *s, ... )
dword <<= 16;
dword |= word;
}
+#endif
if( conv == 'c' ) {
prt_ch( word );
} else if( conv == 'd' ) {
diff --git a/makefile b/makefile
index ed64c25..61f85c6 100644
--- a/makefile
+++ b/makefile
@@ -14,7 +14,7 @@ FLAGS = -DDRV_VER_BUILD=$(VER_BUILD) -DCAP_R5G6B5_ALWAYS_WRONG
#FLAGS += -DHWBLT
# Set DBGPRINT to add debug printf logging.
-DBGPRINT = 1
+#DBGPRINT = 1
!ifdef DBGPRINT
FLAGS += -DDBGPRINT
diff --git a/version.h b/version.h
index f135e2f..a0d77b1 100644
--- a/version.h
+++ b/version.h
@@ -5,7 +5,7 @@
#define DRV_STR(x) DRV_STR_(x)
/* DRV, VXD and DLL have to have the same */
-#define DRV_API_LEVEL 20230326UL
+#define DRV_API_LEVEL 20230628UL
/* on binaries equals 1 and for INF is 1 = separate driver, 2 = softgpu pack */
#define DRV_VER_MAJOR 1
diff --git a/vmdisp9x.inf b/vmdisp9x.inf
index 39c9fce..6ea79ef 100644
--- a/vmdisp9x.inf
+++ b/vmdisp9x.inf
@@ -31,7 +31,7 @@ vmwsmini.vxd=1
;mesa:vmwsgl32.dll=1
;openglide:glide2x.dll=1
;openglide:glide3x.dll=1
-;openglide:wined3d.dll=1
+;wined3d:wined3d.dll=1
;wined3d:dwine.dll=1
;wined3d:ddraw.dll=1
;wined3d:ddrawme.dll=1
diff --git a/vmm.h b/vmm.h
index 72bab3a..a67f5eb 100644
--- a/vmm.h
+++ b/vmm.h
@@ -701,4 +701,29 @@ typedef struct tagCRS_32
#define D_ACCESSED 1 /* segment accessed bit */
+/* contains information that an aplication passed to VXD by calling DeviceIoControl function */
+struct DIOCParams
+{
+ DWORD Intrenal1;
+ DWORD VMHandle;
+ DWORD Internal2;
+ DWORD dwIoControlCode;
+ DWORD lpInBuffer;
+ DWORD cbInBuffer;
+ DWORD lpOutBuffer;
+ DWORD cbOutBuffer;
+ DWORD lpcbBytesReturned;
+ DWORD lpOverlapped;
+ DWORD hDevice;
+ DWORD tagProcess;
+};
+
+/* vWin32 communicates with Vxds on behalf of Win32 apps thru this mechanism. */
+#define W32_DEVICEIOCONTROL 0x0023
+
+/* sub-functions */
+#define DIOC_GETVERSION 0x0
+#define DIOC_OPEN DIOC_GETVERSION
+#define DIOC_CLOSEHANDLE -1
+
#endif /* __VMM_H__INCLUDED__ */
diff --git a/vmwsvxd.c b/vmwsvxd.c
index 72c282f..e7c90cd 100644
--- a/vmwsvxd.c
+++ b/vmwsvxd.c
@@ -84,12 +84,20 @@ DDB VMWS_DDB = {
};
/* string tables */
+#ifdef DBGPRINT
char dbg_hello[] = "Hello world!\n";
char dbg_version[] = "VMM version: ";
char dbg_region_err[] = "region create error\n";
char dbg_Device_Init_proc[] = "Device_Init_proc\n";
char dbg_Device_Init_proc_succ[] = "Device_Init_proc success\n";
+char dbg_dic_ring[] = "DeviceIOControl: Ring\n";
+char dbg_dic_sync[] = "DeviceIOControl: Sync\n";
+char dbg_dic_unknown[] = "DeviceIOControl: Unknown: %d\n";
+char dbg_dic_system[] = "DeviceIOControl: System code: %d\n";
+char dbg_get_ppa[] = "%lx -> %lx\n";
+char dbg_get_ppa_beg[] = "Virtual: %lx\n";
+#endif
DWORD *DispatchTable = 0;
DWORD DispatchTableLength = 0;
@@ -124,6 +132,21 @@ ULONG __declspec(naked) __cdecl _PageFree(PVOID hMem, DWORD flags)
VMMJmp(_PageFree);
}
+ULONG __declspec(naked) __cdecl _CopyPageTable(ULONG LinPgNum, ULONG nPages, DWORD *PageBuf, ULONG flags)
+{
+ VMMJmp(_CopyPageTable);
+}
+
+ULONG __declspec(naked) __cdecl _LinPageLock(ULONG page, ULONG npages, ULONG flags)
+{
+ VMMJmp(_LinPageLock);
+}
+
+ULONG __declspec(naked) __cdecl _LinPageUnLock(ULONG page, ULONG npages, ULONG flags)
+{
+ VMMJmp(_LinPageUnLock);
+}
+
/**
* VDD calls wrapers
**/
@@ -142,6 +165,46 @@ void Sys_Critical_Init_proc()
// nop
}
+/*
+ * 32-bit DeviceIoControl ends here
+ *
+ */
+
+#define SVGA_SYNC 0x1116
+#define SVGA_RING 0x1117
+
+DWORD __stdcall Device_IO_Control_entry(struct DIOCParams *params)
+{
+ switch(params->dwIoControlCode)
+ {
+ case DIOC_OPEN:
+ case DIOC_CLOSEHANDLE:
+ dbg_printf(dbg_dic_system, params->dwIoControlCode);
+ return 0;
+ case SVGA_SYNC:
+ //dbg_printf(dbg_dic_sync);
+ SVGA_Flush();
+ return 0;
+ case SVGA_RING:
+ //dbg_printf(dbg_dic_ring);
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ return 0;
+ }
+
+ dbg_printf(dbg_dic_unknown, params->dwIoControlCode);
+
+ return 1;
+}
+
+void __declspec(naked) Device_IO_Control_proc()
+{
+ _asm {
+ push esi /* struct DIOCParams */
+ call Device_IO_Control_entry
+ retn
+ }
+}
+
void Device_Init_proc();
/*
@@ -157,61 +220,226 @@ void __declspec(naked) VMWS_Control()
// eax = 0x23 - device IO control
_asm {
- pushad
cmp eax,Sys_Critical_Init
jnz control_1
- call Sys_Critical_Init_proc
+ pushad
+ call Sys_Critical_Init_proc
+ popad
+ clc
+ ret
control_1:
cmp eax,Device_Init
jnz control_2
+ pushad
call Device_Init_proc
+ popad
+ clc
+ ret
control_2:
cmp eax,0x1B
jnz control_3
+ pushad
call Device_Init_proc
+ popad
+ clc
+ ret
control_3:
- popad
+ cmp eax,W32_DEVICEIOCONTROL
+ jnz control_4
+ jmp Device_IO_Control_proc
+ control_4:
clc
ret
};
}
/**
- * PM16 driver RING0 calls
+ * Return PPN (physical page number) from virtual address
+ *
**/
-BOOL CreateRegion(unsigned int nPages, ULONG *lpLAddr, ULONG *lpPPN)
+static DWORD getPPN(DWORD virtualaddr)
+{
+ DWORD phy = 0;
+ _CopyPageTable(virtualaddr/P_SIZE, 1, &phy, 0);
+ return phy/P_SIZE;
+}
+
+/**
+ * Allocate guest memory region (GMR) - HW needs know memory physical
+ * addressed of pages in (virtual) memory block.
+ * Technically this allocate 2 memory block, 1st for data and 2nd as its
+ * physical description.
+ *
+ * @param nPages: number of pages to allocate
+ * @param outDataAddr: linear address (system space) of data block
+ * @param outGMRAddr: linear address of GMR block
+ * @param outPPN: physical page number of outGMRAddr (first page)
+ *
+ * @return: TRUE on success
+ *
+ **/
+static BOOL GMRAlloc(ULONG nPages, ULONG *outDataAddr, ULONG *outGMRAddr, ULONG *outPPN)
{
ULONG phy;
+ ULONG pgblk_phy;
ULONG laddr;
+ ULONG pgblk;
SVGAGuestMemDescriptor *desc;
- laddr = _PageAllocate(nPages + 1, PG_SYS, 0, 0x00000000, 0, 0x100000, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+ laddr = _PageAllocate(nPages, PG_SYS, 0, 0, 0x0, 0x100000, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
if(laddr)
{
- desc = (SVGAGuestMemDescriptor*)laddr;
- desc->ppn = (phy/P_SIZE) + 1;
- desc->numPages = nPages;
- desc++;
- desc->ppn = 0;
- desc->numPages = 0;
+ pgblk = _PageAllocate(1, PG_SYS, 0, 0, 0x0, 0x100000, &pgblk_phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+ if(pgblk)
+ {
+ desc = (SVGAGuestMemDescriptor*)pgblk;
+ desc->ppn = (phy/P_SIZE);
+ desc->numPages = nPages;
+ desc++;
+ desc->ppn = 0;
+ desc->numPages = 0;
- *lpLAddr = laddr;
- *lpPPN = (phy/P_SIZE);
+ *outDataAddr = laddr;
+ *outGMRAddr = pgblk;
+ *outPPN = (pgblk_phy/P_SIZE);
- return TRUE;
+ return TRUE;
+ }
+ else
+ {
+ _PageFree((PVOID)laddr, 0);
+ return FALSE;
+ }
+ }
+ else
+ {
+ ULONG taddr;
+ ULONG tppn;
+ ULONG pgi;
+ ULONG base_ppn;
+ ULONG base_cnt;
+ ULONG blocks = 1;
+ ULONG blk_pages = 0;
+
+ laddr = _PageAllocate(nPages, PG_SYS, 0, 0, 0x0, 0x100000, NULL, PAGEFIXED);
+
+ if(laddr)
+ {
+ /* determine how many physical continuous blocks we have */
+ base_ppn = getPPN(laddr);
+ base_cnt = 1;
+ for(pgi = 1; pgi < nPages; pgi++)
+ {
+ taddr = laddr + pgi*P_SIZE;
+ tppn = getPPN(taddr);
+
+ if(tppn != base_ppn + base_cnt)
+ {
+ base_ppn = tppn;
+ base_cnt = 1;
+ blocks++;
+ }
+ else
+ {
+ base_cnt++;
+ }
+ }
+
+ // number of pages to store regions information
+ blk_pages = ((blocks+1)/(P_SIZE/sizeof(SVGAGuestMemDescriptor))) + 1;
+
+ // add extra descriptors for pages edge
+ blk_pages = ((blocks+blk_pages+1)/(P_SIZE/sizeof(SVGAGuestMemDescriptor))) + 1;
+
+ pgblk = _PageAllocate(blk_pages, PG_SYS, 0, 0, 0x0, 0x100000, &pgblk_phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+ if(pgblk)
+ {
+ desc = (SVGAGuestMemDescriptor*)pgblk;
+ desc->ppn = getPPN(laddr);
+ desc->numPages = 1;
+ blocks = 1;
+
+ for(pgi = 1; pgi < nPages; pgi++)
+ {
+ taddr = laddr + pgi*P_SIZE;
+ tppn = getPPN(taddr);
+
+ if(tppn == desc->ppn + desc->numPages)
+ {
+ desc->numPages++;
+ }
+ else
+ {
+ /* next descriptor is on page edge */
+ if((blocks+1) % (P_SIZE/sizeof(SVGAGuestMemDescriptor)) == 0)
+ {
+ desc++;
+ desc->numPages = 0;
+ desc->ppn = getPPN((DWORD)(desc+1));
+ //dbg_printf(old_new_ppn, blocks, getPPN((DWORD)(desc)), getPPN((DWORD)(desc+1)), getPPN((DWORD)(desc+2)));
+ blocks++;
+ }
+
+ desc++;
+ desc->ppn = tppn;
+ desc->numPages = 1;
+ blocks++;
+ }
+ }
+
+ desc++;
+ desc->ppn = 0;
+ desc->numPages = 0;
+
+ *outDataAddr = laddr;
+ *outGMRAddr = pgblk;
+ *outPPN = (pgblk_phy/P_SIZE);
+
+ return TRUE;
+ }
+ else
+ {
+ _PageFree((PVOID)laddr, 0);
+ return FALSE;
+ }
+ }
}
return FALSE;
}
-BOOL FreeRegion(ULONG LAddr)
+/**
+ * Free data allocated by GMRAlloc
+ *
+ **/
+static BOOL GMRFree(ULONG DataAddr, ULONG GMRAddr)
{
- if(_PageFree((PVOID)LAddr, 0) != 0)
+ BOOL ret = FALSE;
+
+ if(_PageFree((PVOID)DataAddr, 0) != 0)
{
- return TRUE;
+ ret = TRUE;
}
- return FALSE;
+ if(_PageFree((PVOID)GMRAddr, 0) != 0)
+ {
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+/**
+ * PM16 driver RING0 calls
+ **/
+BOOL CreateRegion(unsigned int nPages, ULONG *lpLAddr, ULONG *lpPPN, ULONG *lpPGBLK)
+{
+ return GMRAlloc(nPages, lpLAddr, lpPGBLK, lpPPN);
+}
+
+BOOL FreeRegion(ULONG LAddr, ULONG PGBLK)
+{
+ return GMRFree(LAddr, PGBLK);
}
#define MOB_PER_PAGE_CNT (P_SIZE/sizeof(ULONG))
@@ -222,7 +450,7 @@ BOOL CreateMOB(unsigned int nPages, ULONG *lpLAddr, ULONG *lpPPN)
ULONG phy;
ULONG laddr;
- laddr = _PageAllocate(nPages + mobBasePages, PG_SYS, 0, 0x00000000, 0, 0x100000, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+ laddr = _PageAllocate(nPages + mobBasePages, PG_SYS, 0, 0x0, 0, 0x0fffff, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
if(laddr)
{
unsigned int i;
@@ -270,17 +498,20 @@ WORD __stdcall VMWS_API_Proc(PCRS_32 state)
{
ULONG lAddr;
ULONG PPN;
+ ULONG PGBLK;
- if(CreateRegion(state->Client_ECX, &lAddr, &PPN))
+ if(CreateRegion(state->Client_ECX, &lAddr, &PPN, &PGBLK))
{
state->Client_ECX = PPN;
state->Client_EDX = lAddr;
+ state->Client_EBX = PGBLK;
rc = 1;
}
else
{
state->Client_ECX = 0;
state->Client_EDX = 0;
+ state->Client_EBX = 0;
dbg_printf(dbg_region_err);
@@ -291,7 +522,7 @@ WORD __stdcall VMWS_API_Proc(PCRS_32 state)
/* free region = input: ECX: lin. address */
case VMWSVXD_PM16_DESTROY_REGION:
{
- if(FreeRegion(state->Client_ECX))
+ if(FreeRegion(state->Client_ECX, state->Client_EBX))
{
rc = 1;
}