DOS / Move DPMI segments to winedos

Jukka Heinonen jhei at iki.fi
Mon Dec 2 13:45:29 CST 2002


DPMI segments (a bit misleading name) are only used in winedos dll.
This patch moves their initialization to that dll. Also, segments
are no longer carved out of DOS conventional memory. This should both
preserve a small amount of conventional memory and also allow late
initialization of memory which should make it possible to give
more than 600k to DOS programs.



Changelog:
  Move DPMI segments to winedos.



Index: msdos/dosmem.c
===================================================================
RCS file: /home/wine/wine/msdos/dosmem.c,v
retrieving revision 1.45
diff -u -r1.45 dosmem.c
--- msdos/dosmem.c	18 Nov 2002 23:11:18 -0000	1.45
+++ msdos/dosmem.c	2 Dec 2002 19:35:21 -0000
@@ -87,17 +87,6 @@
  * and only relocated to NULL when absolutely necessary */
 static char *DOSMEM_sysmem;
 
-/* various real-mode code stubs */
-struct DPMI_segments DOSMEM_dpmi_segments;
-
-/***********************************************************************
- *           DOSMEM_GetDPMISegments
- */
-const struct DPMI_segments *DOSMEM_GetDPMISegments(void)
-{
-    return &DOSMEM_dpmi_segments;
-}
-
 /***********************************************************************
  *           DOSMEM_MemoryTop
  *
@@ -158,82 +147,6 @@
     for (x=0; x<256; x++) stub[x]=VM_STUB(x);
 }
 
-/***********************************************************************
- *           DOSMEM_InitDPMI
- *
- * Allocate the global DPMI RMCB wrapper.
- */
-static void DOSMEM_InitDPMI(void)
-{
-    LPSTR ptr;
-    int   i;
-
-    static const char wrap_code[]={
-     0xCD,0x31, /* int $0x31 */
-     0xCB       /* lret */
-    };
-
-    static const char enter_xms[]=
-    {
-        /* XMS hookable entry point */
-        0xEB,0x03,           /* jmp entry */
-        0x90,0x90,0x90,      /* nop;nop;nop */
-                             /* entry: */
-        /* real entry point */
-        /* for simplicity, we'll just use the same hook as DPMI below */
-        0xCD,0x31,           /* int $0x31 */
-        0xCB                 /* lret */
-    };
-
-    static const char enter_pm[]=
-    {
-        0x50,                /* pushw %ax */
-        0x52,                /* pushw %dx */
-        0x55,                /* pushw %bp */
-        0x89,0xE5,           /* movw %sp,%bp */
-        /* get return CS */
-        0x8B,0x56,0x08,      /* movw 8(%bp),%dx */
-        /* just call int 31 here to get into protected mode... */
-        /* it'll check whether it was called from dpmi_seg... */
-        0xCD,0x31,           /* int $0x31 */
-        /* we are now in the context of a 16-bit relay call */
-        /* need to fixup our stack;
-         * 16-bit relay return address will be lost, but we won't worry quite yet */
-        0x8E,0xD0,           /* movw %ax,%ss */
-        0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */
-        /* set return CS */
-        0x89,0x56,0x08,      /* movw %dx,8(%bp) */
-        0x5D,                /* popw %bp */
-        0x5A,                /* popw %dx */
-        0x58,                /* popw %ax */
-        0xCB                 /* lret */
-    };
-
-    ptr = DOSMEM_GetBlock( sizeof(wrap_code), &DOSMEM_dpmi_segments.wrap_seg );
-    memcpy( ptr, wrap_code, sizeof(wrap_code) );
-    ptr = DOSMEM_GetBlock( sizeof(enter_xms), &DOSMEM_dpmi_segments.xms_seg );
-    memcpy( ptr, enter_xms, sizeof(enter_xms) );
-    ptr = DOSMEM_GetBlock( sizeof(enter_pm), &DOSMEM_dpmi_segments.dpmi_seg );
-    memcpy( ptr, enter_pm, sizeof(enter_pm) );
-    DOSMEM_dpmi_segments.dpmi_sel = SELECTOR_AllocBlock( ptr, sizeof(enter_pm), WINE_LDT_FLAGS_CODE );
-
-    ptr = DOSMEM_GetBlock( 6 * 256, &DOSMEM_dpmi_segments.int48_seg );
-    for(i=0; i<256; i++) {
-        /*
-         * Each 32-bit interrupt handler is 6 bytes:
-         * 0xCD,<i>            = int <i> (nested 16-bit interrupt)
-         * 0x66,0xCA,0x04,0x00 = ret 4   (32-bit far return and pop 4 bytes)
-         */
-        ptr[i * 6 + 0] = 0xCD;
-        ptr[i * 6 + 1] = i;
-        ptr[i * 6 + 2] = 0x66;
-        ptr[i * 6 + 3] = 0xCA;
-        ptr[i * 6 + 4] = 0x04;
-        ptr[i * 6 + 5] = 0x00;
-    }
-    DOSMEM_dpmi_segments.int48_sel = SELECTOR_AllocBlock( ptr, 6 * 256, WINE_LDT_FLAGS_CODE );
-}
-
 static BIOSDATA * DOSMEM_BiosData(void)
 {
     return (BIOSDATA *)(DOSMEM_sysmem + 0x400);
@@ -569,7 +482,6 @@
         DOSMEM_InitMemory();
         DOSMEM_InitCollateTable();
         DOSMEM_InitErrorTable();
-        DOSMEM_InitDPMI();
         already_done = 1;
     }
     else if (dos_init && !already_mapped)




Index: include/miscemu.h
===================================================================
RCS file: /home/wine/wine/include/miscemu.h,v
retrieving revision 1.61
diff -u -r1.61 miscemu.h
--- include/miscemu.h	27 Nov 2002 20:18:50 -0000	1.61
+++ include/miscemu.h	2 Dec 2002 19:35:28 -0000
@@ -164,21 +164,7 @@
 extern WORD DOSMEM_BiosSysSeg;
 extern DWORD DOSMEM_CollateTable;
 
-/* various real-mode code stubs */
-struct DPMI_segments
-{
-    WORD wrap_seg;
-    WORD xms_seg;
-    WORD dpmi_seg;
-    WORD dpmi_sel;
-    WORD int48_seg;
-    WORD int48_sel;
-};
-
 /* msdos/dosmem.c */
-extern struct DPMI_segments DOSMEM_dpmi_segments;
-extern const struct DPMI_segments *DOSMEM_GetDPMISegments(void);
-
 extern BOOL DOSMEM_Init(BOOL);
 extern void   DOSMEM_Tick(WORD timer);
 extern WORD   DOSMEM_AllocSelector(WORD);




Index: dlls/winedos/dosexe.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v
retrieving revision 1.18
diff -u -r1.18 dosexe.h
--- dlls/winedos/dosexe.h	27 Nov 2002 20:18:50 -0000	1.18
+++ dlls/winedos/dosexe.h	2 Dec 2002 19:35:35 -0000
@@ -28,7 +28,16 @@
 #include "miscemu.h"
 
 struct _DOSEVENT;
-struct DPMI_segments;
+
+/* various real-mode code stubs */
+struct DPMI_segments
+{
+    WORD wrap_seg;
+    WORD xms_seg;
+    WORD dpmi_seg;
+    WORD dpmi_sel;
+    WORD int48_sel;
+};
 
 /* 48-bit segmented pointers for DOS DPMI32 */
 typedef struct {
@@ -49,7 +58,7 @@
 extern WORD DOSVM_psp;     /* psp of current DOS task */
 extern WORD DOSVM_retval;  /* return value of previous DOS task */
 extern DWORD DOS_LOLSeg;
-extern const struct DPMI_segments *DOSVM_dpmi_segments;
+extern struct DPMI_segments *DOSVM_dpmi_segments;
 
 #if defined(linux) && defined(__i386__) && defined(HAVE_SYS_VM86_H)
 # define MZ_SUPPORTED
@@ -106,6 +115,9 @@
 extern void WINAPI DOSVM_Int3cHandler(CONTEXT86*);
 extern void WINAPI DOSVM_Int3dHandler(CONTEXT86*);
 extern void WINAPI DOSVM_Int3eHandler(CONTEXT86*);
+
+/* himem.c */
+extern void DOSVM_InitSegments(void);
 
 /* int09.c */
 extern void WINAPI DOSVM_Int09Handler(CONTEXT86*);




Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.30
diff -u -r1.30 dosvm.c
--- dlls/winedos/dosvm.c	6 Nov 2002 21:56:52 -0000	1.30
+++ dlls/winedos/dosvm.c	2 Dec 2002 19:35:42 -0000
@@ -60,7 +60,6 @@
 
 WORD DOSVM_psp = 0;
 WORD DOSVM_retval = 0;
-const struct DPMI_segments *DOSVM_dpmi_segments = NULL;
 
 #ifdef MZ_SUPPORTED
 
@@ -649,7 +648,7 @@
 
     if (fdwReason == DLL_PROCESS_ATTACH)
     {
-        DOSVM_dpmi_segments = DOSMEM_GetDPMISegments();
+        DOSVM_InitSegments();
 
 #ifdef MZ_SUPPORTED
         event_notifier = CreateEventA(NULL, FALSE, FALSE, NULL);




Index: dlls/winedos/int67.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int67.c,v
retrieving revision 1.9
diff -u -r1.9 int67.c
--- dlls/winedos/int67.c	6 Nov 2002 19:57:49 -0000	1.9
+++ dlls/winedos/int67.c	2 Dec 2002 19:35:49 -0000
@@ -90,9 +90,9 @@
 static void EMS_init(void)
 {
   /*
-   * FIXME: Should dynamically allocate upper memory block for EMS frame.
+   * Start of 64k EMS frame.
    */
-  ULONG base = 0xd0000;
+  ULONG base = 0xc0000;
 
   if(EMS_record)
     return;




Index: dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.81
diff -u -r1.81 kernel32.spec
--- dlls/kernel/kernel32.spec	2 Dec 2002 18:58:32 -0000	1.81
+++ dlls/kernel/kernel32.spec	2 Dec 2002 19:35:57 -0000
@@ -1053,7 +1053,6 @@
 @ cdecl DOSMEM_Available() DOSMEM_Available
 @ cdecl DOSMEM_FreeBlock(ptr) DOSMEM_FreeBlock
 @ cdecl DOSMEM_GetBlock(long ptr) DOSMEM_GetBlock
-@ cdecl DOSMEM_GetDPMISegments() DOSMEM_GetDPMISegments
 @ cdecl DOSMEM_Init(long) DOSMEM_Init
 @ cdecl DRIVE_OpenDevice(long long) DRIVE_OpenDevice
 @ stdcall INT_Int21Handler(ptr) INT_Int21Handler




Index: dlls/winedos/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/winedos/Makefile.in,v
retrieving revision 1.20
diff -u -r1.20 Makefile.in
--- dlls/winedos/Makefile.in	27 Nov 2002 20:18:50 -0000	1.20
+++ dlls/winedos/Makefile.in	2 Dec 2002 19:36:03 -0000
@@ -16,6 +16,7 @@
 	dosaspi.c \
 	dosvm.c \
 	fpu.c \
+	himem.c \
 	int09.c \
 	int10.c \
 	int11.c \
--- /dev/null	Thu Jan  1 02:00:00 1970
+++ dlls/winedos/himem.c	Sun Dec  1 11:36:07 2002
@@ -0,0 +1,207 @@
+/*
+ * DOS upper memory management.
+ *
+ * Copyright 2002 Jukka Heinonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dosexe.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
+
+/*
+ * Wine DOS memory layout above 640k:
+ *
+ *   a0000 - affff : VGA graphics         (vga.c)
+ *   b0000 - bffff : Monochrome text      (unused)
+ *   b8000 - bffff : VGA text             (vga.c)
+ *   c0000 - cffff : EMS frame            (int67.c)
+ *   d0000 - effff : Free memory for UMBs (himem.c)
+ *   f0000 - fffff : BIOS stuff           (msdos/dosmem.c)
+ *  100000 -10ffff : High memory area     (unused)
+ */
+
+/*
+ * Table of real mode segments and protected mode selectors 
+ * for code stubs and other miscellaneous storage.
+ */
+struct DPMI_segments *DOSVM_dpmi_segments = NULL;
+
+/*
+ * First and last address available for upper memory blocks.
+ */
+#define DOSVM_UMB_BOTTOM 0xd0000
+#define DOSVM_UMB_TOP    0xeffff
+
+/*
+ * First free address for upper memory blocks.
+ */
+static DWORD DOSVM_umb_free = DOSVM_UMB_BOTTOM;
+
+
+/***********************************************************************
+ *           DOSVM_AllocUMB
+ *
+ * Allocate upper memory block (UMB) from upper memory.
+ * Returned pointer is aligned to 16-byte (paragraph) boundary.
+ *
+ * This routine is only for allocating static storage for 
+ * Wine internal uses. Allocated memory can be accessed from
+ * real mode, memory is taken from area already mapped and reserved
+ * by Wine and the allocation has very little memory and speed
+ * overhead. Use of this routine also preserves precious DOS
+ * conventional memory.
+ */
+static LPVOID DOSVM_AllocUMB( DWORD size )
+{
+  LPVOID ptr = (LPVOID)DOSVM_umb_free;
+  
+  size = ((size + 15) >> 4) << 4;
+  
+  if(DOSVM_umb_free + size - 1 > DOSVM_UMB_TOP) {
+    ERR("Out of upper memory area.\n");
+    return 0;
+  }
+
+  DOSVM_umb_free += size;
+  return ptr;
+}
+
+
+/***********************************************************************
+ *           DOSVM_AllocCodeUMB
+ *
+ * Allocate upper memory block for storing code stubs.
+ * Initializes real mode segment and 16-bit protected mode selector 
+ * for the allocated code block.
+ */
+static LPVOID DOSVM_AllocCodeUMB( DWORD size, WORD *segment, WORD *selector )
+{
+  LPVOID ptr = DOSVM_AllocUMB( size );
+  
+  if (segment)
+    *segment = (DWORD)ptr >> 4;
+
+  if (selector)
+    *selector = SELECTOR_AllocBlock( ptr, size, WINE_LDT_FLAGS_CODE );
+
+  return ptr;
+}
+
+
+/***********************************************************************
+ *           DOSVM_InitSegments
+ *
+ * Initializes DOSVM_dpmi_segments. Allocates required memory and
+ * sets up segments and selectors for accessing the memory.
+ */
+void DOSVM_InitSegments( void )
+{
+    LPSTR ptr;
+    int   i;
+
+    static const char wrap_code[]={
+     0xCD,0x31, /* int $0x31 */
+     0xCB       /* lret */
+    };
+
+    static const char enter_xms[]=
+    {
+        /* XMS hookable entry point */
+        0xEB,0x03,           /* jmp entry */
+        0x90,0x90,0x90,      /* nop;nop;nop */
+                             /* entry: */
+        /* real entry point */
+        /* for simplicity, we'll just use the same hook as DPMI below */
+        0xCD,0x31,           /* int $0x31 */
+        0xCB                 /* lret */
+    };
+
+    static const char enter_pm[]=
+    {
+        0x50,                /* pushw %ax */
+        0x52,                /* pushw %dx */
+        0x55,                /* pushw %bp */
+        0x89,0xE5,           /* movw %sp,%bp */
+        /* get return CS */
+        0x8B,0x56,0x08,      /* movw 8(%bp),%dx */
+        /* just call int 31 here to get into protected mode... */
+        /* it'll check whether it was called from dpmi_seg... */
+        0xCD,0x31,           /* int $0x31 */
+        /* we are now in the context of a 16-bit relay call */
+        /* need to fixup our stack;
+         * 16-bit relay return address will be lost, 
+         * but we won't worry quite yet 
+         */
+        0x8E,0xD0,           /* movw %ax,%ss */
+        0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */
+        /* set return CS */
+        0x89,0x56,0x08,      /* movw %dx,8(%bp) */
+        0x5D,                /* popw %bp */
+        0x5A,                /* popw %dx */
+        0x58,                /* popw %ax */
+        0xCB                 /* lret */
+    };
+
+    /*
+     * Allocate pointer array.
+     */
+    DOSVM_dpmi_segments = DOSVM_AllocUMB( sizeof(struct DPMI_segments) );
+
+    /*
+     * RM / offset 0: Exit from real mode.
+     * RM / offset 2: Points to lret opcode.
+     */
+    ptr = DOSVM_AllocCodeUMB( sizeof(wrap_code),
+                              &DOSVM_dpmi_segments->wrap_seg, 0 );
+    memcpy( ptr, wrap_code, sizeof(wrap_code) );
+
+    /*
+     * RM / offset 0: XMS driver entry.
+     */
+    ptr = DOSVM_AllocCodeUMB( sizeof(enter_xms), 
+                              &DOSVM_dpmi_segments->xms_seg, 0 );
+    memcpy( ptr, enter_xms, sizeof(enter_xms) );
+
+    /*
+     * RM / offset 0: Switch to DPMI.
+     * PM / offset 8: DPMI raw mode switch.
+     */
+    ptr = DOSVM_AllocCodeUMB( sizeof(enter_pm), 
+                              &DOSVM_dpmi_segments->dpmi_seg,
+                              &DOSVM_dpmi_segments->dpmi_sel );
+    memcpy( ptr, enter_pm, sizeof(enter_pm) );
+
+    /*
+     * PM / offset N*6: Interrupt N in DPMI32.
+     */
+    ptr = DOSVM_AllocCodeUMB( 6 * 256,
+                              0, &DOSVM_dpmi_segments->int48_sel );
+    for(i=0; i<256; i++) {
+        /*
+         * Each 32-bit interrupt handler is 6 bytes:
+         * 0xCD,<i>            = int <i> (nested 16-bit interrupt)
+         * 0x66,0xCA,0x04,0x00 = ret 4   (32-bit far return and pop 4 bytes)
+         */
+        ptr[i * 6 + 0] = 0xCD;
+        ptr[i * 6 + 1] = i;
+        ptr[i * 6 + 2] = 0x66;
+        ptr[i * 6 + 3] = 0xCA;
+        ptr[i * 6 + 4] = 0x04;
+        ptr[i * 6 + 5] = 0x00;
+    }
+}



-- 
Jukka Heinonen <http://www.iki.fi/jhei/>



More information about the wine-patches mailing list