winedos/kernel: MCB implementation Resend

Markus Amsler markus.amsler at oribi.org
Sat Sep 18 10:36:24 CDT 2004


Alexandre Julliard wrote:

>What you probably want is to make the DOSMEM functions call out to the MCB
>ones.
>
Done.
I tested the win16 front end with my test programm (see attachement 
[1]dosmem.exe).
The DOS frontend was tested with running FreeCOM and some apps in it. To 
get FreeCOM started you also need patch[2] (don't aply it, gets 
obsoleted with the IO redirection patch i'm working on).
I tested the win16 side also with DOS area not in first megabyte. But 
there was a problem in himem.c (see next patch).

Please let me know if there's something wrong with this patch.

Markus

[1] http://www.winehq.org/hypermail/wine-devel/2004/09/0438.html
[2] http://www.winehq.org/hypermail/wine-patches/2004/06/0046.html

Changelog:
* Implement memory control block management in DOS convential memory.

-------------- next part --------------
--- /dev/null	2004-07-13 09:22:32.000000000 +0200
+++ dlls/winedos/mcb.c	2004-09-18 16:38:05.000000000 +0200
@@ -0,0 +1,396 @@
+/*
+ * Memory Control Block (MCB) Management.
+ *
+ * Copyright 2004 Markus Amsler
+ *
+ * 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"
+
+#include "wine/winbase16.h"
+
+
+WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
+
+/*
+ * All function parameters and results are in segments and paragraphs,
+ *   so it's impossible to specify non paragraph aligned values.
+ *
+ * FIXME: implement Allocation Strategy
+ */
+
+#define MCB_DUMP(mc) TRACE ("MCB_DUMP base=%p type=%02xh psp=%04xh size=%04xh\n", mc, mc->type, mc->psp , mc->size )
+ 
+#define MCB_NEXT(mc) \
+        (MCB*) ((mc->type==MCB_TYPE_LAST) ? NULL : (char*)(mc) + ((mc->size + 1) << 4) )
+
+#define MCB_TYPE_NORMAL    0x4d
+#define MCB_TYPE_LAST      0x5a
+
+#define MCB_PSP_DOS        0x0060  
+#define MCB_PSP_FREE       0
+
+/* psp and size of MCB needs to be byte aligned */
+typedef WORD WORD_ALIGNED_BYTE DECLSPEC_ALIGN(1);
+
+typedef struct {
+    BYTE type;
+    WORD_ALIGNED_BYTE psp;     /* segment of owner psp */
+    WORD_ALIGNED_BYTE size;    /* in paragraphs */
+    BYTE pad[3];
+    BYTE name[8];
+} MCB;
+
+/* DOS memory base */
+char *MCB_dosmem = NULL;
+
+/* first segment of dos convential memory */
+static WORD MCB_segFirst;
+
+/* last segment of dos convential memory */
+static WORD MCB_segLast;
+
+        
+/***********************************************************************
+ *           MCB_Valid
+ *
+ * Helper function for internal use only.
+ * Checks wether given MCB is not corrupted.
+ */
+BOOL MCB_Valid( MCB* mcb )
+{
+    /* FIXME: should we check more? */
+    return (mcb->type==MCB_TYPE_NORMAL) || (mcb->type==MCB_TYPE_LAST);
+}
+
+
+/***********************************************************************
+ *           MCB_Collapse
+ *
+ * Helper function for internal use only.
+ * Atach all following free blocks to this one, even if this one is not free.
+ */
+void MCB_Collapse( MCB* mcb )
+{
+    MCB* next = MCB_NEXT( mcb );
+
+    while (next && next->psp == MCB_PSP_FREE)
+    {
+        mcb->size = mcb->size + next->size + 1;
+        mcb->type = next->type;    /* make sure keeping MCB_TYPE_LAST */
+        next = MCB_NEXT( next );
+    }
+}
+
+
+/***********************************************************************
+ *           MCB_SegToLin
+ *
+ * DOS real mode segment to linear address.
+ */
+LPVOID MCB_SegToLin( WORD seg ){
+    return (LPVOID) (void*)(((unsigned int)(seg) << 4) + (unsigned int) MCB_dosmem);
+}
+
+
+/***********************************************************************
+ *           MCB_LinToSeg
+ *
+ * Linear address to DOS segment.
+ */
+WORD MCB_LinToSeg( LPVOID lin ){
+    if ((DWORD)lin > (DWORD)MCB_dosmem && (DWORD)lin < ((DWORD)MCB_dosmem + 0x100000))
+    {
+        return (WORD)(((unsigned int)(lin) - (unsigned int)MCB_dosmem) >> 4);
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+/***********************************************************************
+ *           MCB_Init
+ *
+ * Initializes the first MCB.
+ * Gets called on the first call of MCB_First.
+ */
+void MCB_Init( void )
+{
+    /* 
+     * reproduce dosmem, MCB_segFirst from Kernel exported values.
+     * dosmem is the linear start addresse of the DOS memory space 
+     *   (normaly NULL, but can be different in Win16)
+     * MCB_segFirst is the first real mode segment (relative to dosmem)
+     *   of the DOS convential memory
+     */
+    LDT_ENTRY entry;
+    FARPROC16 proc;
+    HMODULE16 hmod;
+    DWORD __0000H, __F000H;
+    hmod = GetModuleHandle16( "KERNEL" );
+    
+    proc = GetProcAddress16( hmod, (LPCSTR)(ULONG_PTR)183 );  /* KERNEL.183: __0000H */
+    wine_ldt_get_entry( LOWORD(proc), &entry );
+    __0000H = (DWORD) wine_ldt_get_base( &entry );
+     
+    proc = GetProcAddress16( hmod, (LPCSTR)(ULONG_PTR)194 );  /* KERNEL.194: __0000H */
+    wine_ldt_get_entry( LOWORD(proc), &entry );
+    __F000H = (DWORD) wine_ldt_get_base( &entry );
+
+    MCB_dosmem = (LPVOID) (__F000H - 0xf0000);
+    
+    if (__0000H)
+    {
+        MCB_segFirst = 0x1000;    /* Win16, with protected first 64k */
+    }else{
+        MCB_segFirst = 0x0060;    /* DOS real mode */
+    }
+            
+    MCB_segLast = 0x9fff;
+    
+    MCB *first = MCB_SegToLin (MCB_segFirst);
+    first->type = MCB_TYPE_LAST;
+    first->psp = MCB_PSP_FREE;
+    first->size = MCB_segLast - MCB_segFirst- 1 ;
+
+    TRACE(" segFirst=%04xh segLast=%04xh dosmem=%p\n", MCB_segFirst, MCB_segLast, MCB_dosmem);
+}
+
+
+/***********************************************************************
+ *           MCB_First
+ *
+ * Get the segment of the first MCB in the chain.
+ */
+WORD MCB_First( void )
+{
+    /* first call => initialize conventional memory */
+    if (!MCB_segFirst)
+    {
+        MCB_Init();
+    }
+    return MCB_segFirst;
+}
+
+
+/***********************************************************************
+ *           MCB_Available
+ *
+ * Returns size of the largest free block.
+ */
+WORD MCB_Available( void )
+{
+    UINT  available = 0;
+    UINT  total = 0;
+    MCB *curr = (MCB*) MCB_SegToLin (MCB_First ());
+    /* loop over all MCB and search the largest free MCB */
+    while (curr)
+    {
+        if (!MCB_Valid (curr))
+        {
+            ERR( "MCB List Corrupt\n" );
+            MCB_DUMP( curr );
+            return 0;
+        }
+        
+        if (curr->psp == MCB_PSP_FREE &&
+            curr->size > available )
+            available = curr->size;
+        
+        total += curr->size + 1;
+        curr = MCB_NEXT( curr );
+    }
+    TRACE( " %04xh of %04xh paragraphs available\n", available, total );
+    return available;
+}
+
+ 
+/***********************************************************************
+ *           MCB_Alloc
+ *
+ * Allocates memory
+ * Returns segment of allocated memory, or 0 on error.
+ */
+WORD MCB_Alloc( WORD size )
+{
+    MCB *curr = MCB_SegToLin (MCB_First ());
+    MCB *next = NULL;
+    WORD psp=DOSVM_psp;
+    
+    if (!psp)
+        psp = MCB_PSP_DOS;
+    
+    /* loop over all MCB and search the next large enough MCB */
+    TRACE( "(%04xh)\n", size );
+    while (curr)
+    {
+        if (!MCB_Valid (curr))
+        {
+            ERR( "MCB List Corrupt\n" );
+            MCB_DUMP( curr );
+            return 0;
+        }
+        if (curr->psp == MCB_PSP_FREE)
+        {
+            MCB_Collapse( curr );            
+            /* is it large enough (one paragaph for the MCB)? */
+            if (curr->size >= size)
+            {
+                if (curr->size > size)
+                {
+                    /* split curr */
+                    next = (MCB *) ((char*) curr + (size+1) * 16);
+                    next->psp = MCB_PSP_FREE;
+                    next->size = curr->size - (size+1);
+                    next->type = curr->type;
+                    curr->type = MCB_TYPE_NORMAL;
+                    curr->size = size;
+                }
+                /* curr is the found block */
+                curr->psp = psp;
+                return MCB_LinToSeg (curr) + 1;
+            }
+        }
+        curr = MCB_NEXT(curr);
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           MCB_Free
+ *
+ * Frees previously allocated memory
+ */
+BOOL MCB_Free( WORD seg )
+{
+    MCB* mcb = (MCB*) MCB_SegToLin (seg-1);
+    
+    TRACE( "(%04xh)\n", seg );
+    
+    if (!MCB_Valid (mcb))
+    {
+        ERR( "MCB invalid\n" );
+        MCB_DUMP( mcb );
+        return FALSE;
+    }
+    
+    mcb->psp = MCB_PSP_FREE;
+    MCB_Collapse( mcb );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           MCB_Resize
+ *
+ * Resize DOS memory block in place. Returns block size or -1 on error.
+ *
+ * If exact is TRUE, returned value is either old or requested block
+ * size. If exact is FALSE, block is expanded even if there is not
+ * enough space for full requested block size.
+ */
+WORD MCB_Resize( WORD seg, WORD size, BOOL exact, WORD* maxsize )
+{
+    MCB* mcb = (MCB*) MCB_SegToLin (seg-1);
+    MCB* next;
+    
+    TRACE( "(%04xh,%04xh,%s,%p)\n", seg, size, exact ? "TRUE" : "FALSE", maxsize );
+    
+    if (!MCB_Valid (mcb))
+    {
+        ERR( "MCB invalid\n" );
+        MCB_DUMP( mcb );
+        *maxsize = 0;
+        return -1;
+    }
+
+    /* resize needed? */
+    if (mcb->size == size)
+        return size;
+
+    /* collapse free blocks */
+    MCB_Collapse( mcb );    
+    
+    /* shrink mcb ? */
+    if (mcb->size > size)
+    {
+        *maxsize = mcb->size;
+        next = (MCB *) ((char*) mcb + (size+1) * 16);
+        next->type = mcb->type;
+        next->psp = MCB_PSP_FREE;
+        next->size = mcb->size - (size+1);
+        mcb->type = MCB_TYPE_NORMAL;
+        mcb->size = size;
+        return size;
+    }
+    
+    if (!exact)
+    {
+        *maxsize = mcb->size;
+        return mcb->size;
+    }
+    
+    return -1;
+}
+ 
+
+/***********************************************************************
+ *           MCB_SetPSP
+ *
+ * set psp property of given MCB
+ */
+BOOL MCB_SetPSP( WORD seg, WORD psp )
+{
+    /* FIXME: check if MCB is a valid PSP */
+    
+    MCB* mcb = (MCB*) MCB_SegToLin (seg-1);
+    TRACE ("(%04xh,%04xh)\n", seg, psp);   
+    
+    if (!MCB_Valid (mcb))
+    {
+        ERR( "given MCB is invalid\n" );
+        MCB_DUMP( mcb );
+        return FALSE;
+    }
+    
+    mcb->psp = psp;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           MCB_FreePSP
+ *
+ * Frees all blocks belonging to given psp
+ */
+BOOL MCB_FreePSP( WORD psp )
+{
+    /* FIXME: check if psp is a valid PSP */
+    
+    MCB *curr = MCB_SegToLin (MCB_First ());
+    TRACE ("(%04xh)\n", psp);   
+    while( curr ) /* collapse free blocks */
+    {
+        if (curr->psp == psp)
+            curr->psp = MCB_PSP_FREE;
+        curr = MCB_NEXT(curr);
+    }
+    return TRUE;
+}
Index: include/miscemu.h
===================================================================
RCS file: /home/wine/wine/include/miscemu.h,v
retrieving revision 1.77
diff -u -r1.77 miscemu.h
--- include/miscemu.h	9 Jan 2004 22:18:49 -0000	1.77
+++ include/miscemu.h	18 Sep 2004 14:42:35 -0000
@@ -92,16 +92,26 @@
 extern WORD DOSMEM_BiosDataSeg;
 extern WORD DOSMEM_BiosSysSeg;
 
-/* msdos/dosmem.c */
+
+/* kernel/dosmem.c */
 extern BOOL DOSMEM_Init(BOOL);
 extern void   DOSMEM_Tick(WORD timer);
 extern WORD   DOSMEM_AllocSelector(WORD);
-extern LPVOID DOSMEM_GetBlock(UINT size, WORD* p);
-extern BOOL DOSMEM_FreeBlock(void* ptr);
-extern UINT DOSMEM_ResizeBlock(void* ptr, UINT size, BOOL exact);
-extern UINT DOSMEM_Available(void);
 extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
 extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
 extern UINT DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */
+
+/* winedos/mcb.c */
+extern LPVOID MCB_SegToLin( WORD seg );
+extern WORD MCB_LinToSeg( LPVOID lin );
+extern WORD MCB_First( void );
+extern WORD MCB_Available( void );
+extern WORD MCB_Alloc( WORD size );
+extern BOOL MCB_Free( WORD seg );
+extern WORD MCB_Resize( WORD seg, WORD size, BOOL exact, WORD* maxsize );
+extern BOOL MCB_FreePSP( WORD psp );
+extern BOOL MCB_SetPSP( WORD seg, WORD psp );
+
+// extern WORD MCB_Alloc (WORD);
 
 #endif /* __WINE_MISCEMU_H */
Index: dlls/kernel/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/kernel/Makefile.in,v
retrieving revision 1.115
diff -u -r1.115 Makefile.in
--- dlls/kernel/Makefile.in	19 Aug 2004 01:20:45 -0000	1.115
+++ dlls/kernel/Makefile.in	18 Sep 2004 14:42:37 -0000
@@ -5,6 +5,7 @@
 VPATH     = @srcdir@
 MODULE    = kernel32.dll
 IMPORTS   = ntdll
+DELAYIMPORTS = winedos
 EXTRALIBS = $(LIBUNICODE) @COREFOUNDATIONLIB@
 
 SPEC_SRCS16 = \
Index: dlls/kernel/dosmem.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/dosmem.c,v
retrieving revision 1.7
diff -u -r1.7 dosmem.c
--- dlls/kernel/dosmem.c	14 Jun 2004 17:04:35 -0000	1.7
+++ dlls/kernel/dosmem.c	18 Sep 2004 14:42:38 -0000
@@ -52,30 +52,6 @@
 WORD DOSMEM_BiosDataSeg;  /* BIOS data segment at 0x40:0 */
 WORD DOSMEM_BiosSysSeg;   /* BIOS ROM segment at 0xf000:0 */
 
-/* use 2 low bits of 'size' for the housekeeping */
-
-#define DM_BLOCK_DEBUG		0xABE00000
-#define DM_BLOCK_TERMINAL	0x00000001
-#define DM_BLOCK_FREE		0x00000002
-#define DM_BLOCK_MASK		0x001FFFFC
-
-/*
-#define __DOSMEM_DEBUG__
- */
-
-typedef struct {
-   unsigned	size;
-} dosmem_entry;
-
-typedef struct {
-  unsigned      blocks;
-  unsigned      free;
-} dosmem_info;
-
-#define NEXT_BLOCK(block) \
-        (dosmem_entry*)(((char*)(block)) + \
-	 sizeof(dosmem_entry) + ((block)->size & DM_BLOCK_MASK))
-
 #define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
 #define VM_STUB_SEGMENT 0xf000         /* BIOS segment */
 
@@ -87,71 +63,6 @@
  * and only relocated to NULL when absolutely necessary */
 static char *DOSMEM_sysmem;
 
-/* Start of DOS conventional memory */
-static char *DOSMEM_membase;
-
-static void DOSMEM_InitMemory(void);
-
-/***********************************************************************
- *           DOSMEM_MemoryTop
- *
- * Gets the DOS memory top.
- */
-static char *DOSMEM_MemoryTop(void)
-{
-    return DOSMEM_dosmem+0x9FFFC; /* 640K */
-}
-
-/***********************************************************************
- *           DOSMEM_InfoBlock
- *
- * Gets the DOS memory info block.
- */
-static dosmem_info *DOSMEM_InfoBlock(void)
-{
-    if (!DOSMEM_membase)
-    {
-        DWORD         reserve;
-
-        /*
-         * Reserve either:
-         * - lowest 64k for NULL pointer catching (Win16)
-         * - lowest 1k for interrupt handlers and 
-         *   another 0.5k for BIOS, DOS and intra-application
-         *   areas (DOS)
-         */
-        if (DOSMEM_dosmem != DOSMEM_sysmem)
-            reserve = 0x10000; /* 64k */
-        else
-            reserve = 0x600; /* 1.5k */
-
-        /*
-         * Round to paragraph boundary in order to make 
-         * sure the alignment is correct.
-         */
-        reserve = ((reserve + 15) >> 4) << 4;
-
-        /*
-         * Set DOS memory base and initialize conventional memory.
-         */
-        DOSMEM_membase = DOSMEM_dosmem + reserve;
-        DOSMEM_InitMemory();
-    }
-
-    return (dosmem_info*)DOSMEM_membase;
-}
-
-/***********************************************************************
- *           DOSMEM_RootBlock
- *
- * Gets the DOS memory root block.
- */
-static dosmem_entry *DOSMEM_RootBlock(void)
-{
-    /* first block has to be paragraph-aligned */
-    return (dosmem_entry*)(((char*)DOSMEM_InfoBlock()) +
-                           ((((sizeof(dosmem_info) + 0xf) & ~0xf) - sizeof(dosmem_entry))));
-}
 
 /***********************************************************************
  *           DOSMEM_FillIsrTable
@@ -173,6 +84,12 @@
     for (x=0; x<256; x++) isr[x]=MAKESEGPTR(VM_STUB_SEGMENT,x*4);
 }
 
+
+/**********************************************************************
+ *          DOSMEM_MakeIsrStubs
+ *
+ * Initializes real mode interrupt stubs
+ */
 static void DOSMEM_MakeIsrStubs(void)
 {
     DWORD *stub = (DWORD*)(DOSMEM_dosmem + (VM_STUB_SEGMENT << 4));
@@ -181,11 +98,18 @@
     for (x=0; x<256; x++) stub[x]=VM_STUB(x);
 }
 
+
+/**********************************************************************
+ *          DOSMEM_BiosData
+ *
+ * Returns linear address of the BIOS
+ */
 static BIOSDATA * DOSMEM_BiosData(void)
 {
     return (BIOSDATA *)(DOSMEM_sysmem + 0x400);
 }
 
+
 /**********************************************************************
  *          DOSMEM_GetTicksSinceMidnight
  *
@@ -208,6 +132,7 @@
                   (tvs.tv_usec / 54927);
 }
 
+
 /***********************************************************************
  *           DOSMEM_FillBiosSegments
  *
@@ -270,34 +195,6 @@
     *(DWORD*)(pBiosSys + 0xfff0) = VM_STUB(0x19);
 }
 
-/***********************************************************************
- *           DOSMEM_InitMemory
- *
- * Initialises the DOS memory structures.
- */
-static void DOSMEM_InitMemory(void)
-{
-    dosmem_info*        info_block = DOSMEM_InfoBlock();
-    dosmem_entry*       root_block = DOSMEM_RootBlock();
-    dosmem_entry*       dm;
-
-    root_block->size = DOSMEM_MemoryTop() - (((char*)root_block) + sizeof(dosmem_entry));
-
-    info_block->blocks = 0;
-    info_block->free = root_block->size;
-
-    dm = NEXT_BLOCK(root_block);
-    dm->size = DM_BLOCK_TERMINAL;
-    root_block->size |= DM_BLOCK_FREE
-#ifdef __DOSMEM_DEBUG__
-		     | DM_BLOCK_DEBUG
-#endif
-		     ;
-
-    TRACE( "DOS conventional memory initialized, %d bytes free.\n", 
-           DOSMEM_Available() );
-}
-
 
 /**********************************************************************
  *		setup_dos_mem
@@ -410,226 +307,6 @@
     if (pBiosData) pBiosData->Ticks++;
 }
 
-/***********************************************************************
- *           DOSMEM_GetBlock
- *
- * Carve a chunk of the DOS memory block (without selector).
- */
-LPVOID DOSMEM_GetBlock(UINT size, UINT16* pseg)
-{
-   UINT  	 blocksize;
-   char         *block = NULL;
-   dosmem_info  *info_block = DOSMEM_InfoBlock();
-   dosmem_entry *dm;
-#ifdef __DOSMEM_DEBUG_
-   dosmem_entry *prev = NULL;
-#endif
-
-   if( size > info_block->free ) return NULL;
-   dm = DOSMEM_RootBlock();
-
-   while (dm && dm->size != DM_BLOCK_TERMINAL)
-   {
-#ifdef __DOSMEM_DEBUG__
-       if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
-       {
-	    WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
-	    return NULL;
-       }
-       prev = dm;
-#endif
-       if( dm->size & DM_BLOCK_FREE )
-       {
-	   dosmem_entry  *next = NEXT_BLOCK(dm);
-
-	   while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
-	   {
-	       dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
-	       next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
-	       next = NEXT_BLOCK(dm);
-	   }
-
-	   blocksize = dm->size & DM_BLOCK_MASK;
-	   if( blocksize >= size )
-           {
-	       block = ((char*)dm) + sizeof(dosmem_entry);
-	       if( blocksize - size > 0x20 )
-	       {
-		   /* split dm so that the next one stays
-		    * paragraph-aligned (and dm loses free bit) */
-
-	           dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
-			         	      sizeof(dosmem_entry));
-	           next = (dosmem_entry*)(((char*)dm) +
-	 		   sizeof(dosmem_entry) + dm->size);
-	           next->size = (blocksize - (dm->size +
-			   sizeof(dosmem_entry))) | DM_BLOCK_FREE
-#ifdef __DOSMEM_DEBUG__
-					          | DM_BLOCK_DEBUG
-#endif
-						  ;
-	       } else dm->size &= DM_BLOCK_MASK;
-
-	       info_block->blocks++;
-	       info_block->free -= dm->size;
-	       if( pseg ) *pseg = (block - DOSMEM_dosmem) >> 4;
-#ifdef __DOSMEM_DEBUG__
-               dm->size |= DM_BLOCK_DEBUG;
-#endif
-	       break;
-	   }
- 	   dm = next;
-       }
-       else dm = NEXT_BLOCK(dm);
-   }
-   return (LPVOID)block;
-}
-
-/***********************************************************************
- *           DOSMEM_FreeBlock
- */
-BOOL DOSMEM_FreeBlock(void* ptr)
-{
-   dosmem_info  *info_block = DOSMEM_InfoBlock();
-
-   if( ptr >= (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) &&
-       ptr < (void*)DOSMEM_MemoryTop() && !((((char*)ptr)
-                  - DOSMEM_dosmem) & 0xf) )
-   {
-       dosmem_entry  *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
-
-       if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
-#ifdef __DOSMEM_DEBUG__
-	 && ((dm->size & DM_BLOCK_DEBUG) == DM_BLOCK_DEBUG )
-#endif
-	 )
-       {
-	     info_block->blocks--;
-	     info_block->free += dm->size;
-
-	     dm->size |= DM_BLOCK_FREE;
-	     return TRUE;
-       }
-   }
-   return FALSE;
-}
-
-/***********************************************************************
- *           DOSMEM_ResizeBlock
- *
- * Resize DOS memory block in place. Returns block size or -1 on error.
- *
- * If exact is TRUE, returned value is either old or requested block
- * size. If exact is FALSE, block is expanded even if there is not
- * enough space for full requested block size.
- */
-UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
-{
-   char         *block = NULL;
-   dosmem_info  *info_block = DOSMEM_InfoBlock();
-   dosmem_entry *dm;
-   dosmem_entry *next;
-   UINT blocksize;
-   UINT orgsize;
-
-   if( (ptr < (void*)(sizeof(dosmem_entry) + (char*)DOSMEM_RootBlock())) ||
-       (ptr >= (void*)DOSMEM_MemoryTop()) ||
-       (((((char*)ptr) - DOSMEM_dosmem) & 0xf) != 0) )
-     return (UINT)-1;
-
-   dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
-   if( dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL) )
-       return (UINT)-1;
-
-   next = NEXT_BLOCK(dm);
-   orgsize = dm->size & DM_BLOCK_MASK;
-
-   /* collapse free blocks */
-   while( next->size & DM_BLOCK_FREE )
-   {
-       dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
-       next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
-       next = NEXT_BLOCK(dm);
-   }
-
-   blocksize = dm->size & DM_BLOCK_MASK;
-
-   /*
-    * If collapse didn't help we either expand block to maximum
-    * available size (exact == FALSE) or give collapsed blocks
-    * back to free storage (exact == TRUE).
-    */
-   if (blocksize < size)
-       size = exact ? orgsize : blocksize;
-
-   block = ((char*)dm) + sizeof(dosmem_entry);
-   if( blocksize - size > 0x20 )
-   {
-       /*
-        * split dm so that the next one stays
-        * paragraph-aligned (and next gains free bit) 
-        */
-
-       dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
-                   sizeof(dosmem_entry));
-       next = (dosmem_entry*)(((char*)dm) +
-                              sizeof(dosmem_entry) + dm->size);
-       next->size = (blocksize - (dm->size +
-                                  sizeof(dosmem_entry))) | DM_BLOCK_FREE;
-   } 
-   else 
-   {
-       dm->size &= DM_BLOCK_MASK;
-   }
-
-   /*
-    * Adjust available memory if block size changes.
-    */
-   info_block->free += orgsize - dm->size;
-
-   return size;
-}
-
-/***********************************************************************
- *           DOSMEM_Available
- */
-UINT DOSMEM_Available(void)
-{
-   UINT  	 blocksize, available = 0;
-   dosmem_entry *dm;
-
-   dm = DOSMEM_RootBlock();
-
-   while (dm && dm->size != DM_BLOCK_TERMINAL)
-   {
-#ifdef __DOSMEM_DEBUG__
-       if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
-       {
-	    WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
-	    return NULL;
-       }
-       prev = dm;
-#endif
-       if( dm->size & DM_BLOCK_FREE )
-       {
-	   dosmem_entry  *next = NEXT_BLOCK(dm);
-
-	   while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
-	   {
-	       dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
-	       next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
-	       next = NEXT_BLOCK(dm);
-	   }
-
-	   blocksize = dm->size & DM_BLOCK_MASK;
-	   if ( blocksize > available ) available = blocksize;
- 	   dm = next;
-       }
-       else dm = NEXT_BLOCK(dm);
-   }
-   return available;
-}
-
 
 /***********************************************************************
  *           DOSMEM_MapLinearToDos
@@ -670,6 +347,7 @@
    TRACE_(selector)("(0x%08lx) returns %p.\n", x, lin );
    return lin;
 }
+
 
 /***********************************************************************
  *           DOSMEM_AllocSelector
Index: dlls/kernel/global16.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/global16.c,v
retrieving revision 1.6
diff -u -r1.6 global16.c
--- dlls/kernel/global16.c	10 Aug 2004 23:43:21 -0000	1.6
+++ dlls/kernel/global16.c	18 Sep 2004 14:42:43 -0000
@@ -268,6 +268,7 @@
                  UINT16 flags      /* [in] How to reallocate object */
 ) {
     WORD selcount;
+    WORD maxsize;
     DWORD oldsize;
     void *ptr, *newptr;
     GLOBALARENA *pArena, *pNewArena;
@@ -292,7 +293,7 @@
             !(pArena->flags & GA_DISCARDABLE) ||
             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
         if (pArena->flags & GA_DOSMEM)
-            DOSMEM_FreeBlock( (void *)pArena->base );
+            MCB_Free( MCB_LinToSeg((void *)pArena->base) );
         else
             HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
         pArena->base = 0;
@@ -330,17 +331,17 @@
 
     if (pArena->flags & GA_DOSMEM)
     {
-        if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size) 
+        if (MCB_Resize(MCB_LinToSeg(ptr), (size+15)>>4, TRUE, &maxsize) == (size+15)>>4) 
             newptr = ptr;
         else if(pArena->pageLockCount > 0)
             newptr = 0;
         else
         {
-            newptr = DOSMEM_GetBlock( size, 0 );
+            newptr = MCB_SegToLin(MCB_Alloc( (size+15)>>4 ) );
             if (newptr)
             {
                 memcpy( newptr, ptr, oldsize );
-                DOSMEM_FreeBlock( ptr );
+                MCB_Free( MCB_LinToSeg(ptr) );
             }
         }
     }
@@ -369,7 +370,7 @@
         if (pArena->pageLockCount <1)
         {
             if (pArena->flags & GA_DOSMEM)
-                DOSMEM_FreeBlock( (void *)pArena->base );
+                MCB_Free( MCB_LinToSeg((void *)pArena->base) );
             else
                 HeapFree( GetProcessHeap(), 0, ptr );
             SELECTOR_FreeBlock( sel );
@@ -385,7 +386,7 @@
     if (!sel)
     {
         if (pArena->flags & GA_DOSMEM)
-            DOSMEM_FreeBlock( (void *)pArena->base );
+            MCB_Free( MCB_LinToSeg((void *)pArena->base) );
         else
             HeapFree( GetProcessHeap(), 0, ptr );
         memset( pArena, 0, sizeof(GLOBALARENA) );
@@ -396,7 +397,7 @@
     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
     {        
         if (pArena->flags & GA_DOSMEM)
-            DOSMEM_FreeBlock( (void *)pArena->base );
+            MCB_Free( MCB_LinToSeg((void *)pArena->base) );
         else
             HeapFree( GetProcessHeap(), 0, ptr );
         SELECTOR_FreeBlock( sel );
@@ -757,14 +758,16 @@
              DWORD size /* [in] Number of bytes to be allocated */
 ) {
    UINT16    uParagraph;
-   LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
+   LPVOID    lpBlock = NULL;
+   uParagraph = MCB_Alloc( (size + 15) >> 4 );
 
-   if( lpBlock )
+   if( uParagraph )
    {
        HMODULE16 hModule = GetModuleHandle16("KERNEL");
        WORD	 wSelector;
        GLOBALARENA *pArena;
 
+       lpBlock = MCB_SegToLin (uParagraph);
        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, hModule, WINE_LDT_FLAGS_DATA );
        pArena = GET_ARENA_PTR(wSelector);
        pArena->flags |= GA_DOSMEM;
@@ -776,6 +779,9 @@
 
 /***********************************************************************
  *           GlobalDOSFree      (KERNEL.185)
+ * NOTES
+ *      On windows returns always success state.
+ *
  * RETURNS
  *	NULL: Success
  *	sel: Failure
@@ -783,16 +789,17 @@
 WORD WINAPI GlobalDOSFree16(
             WORD sel /* [in] Selector */
 ) {
+   WORD    seg;
+   
    DWORD   block = GetSelectorBase(sel);
 
-   if( block && block < 0x100000 )
+   seg = MCB_LinToSeg ((LPVOID)DOSMEM_MapDosToLinear(block));
+   if( block && seg )
    {
-       LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
-       if( DOSMEM_FreeBlock( lpBlock ) )
+       if( MCB_Free( seg ) )
 	   GLOBAL_FreeBlock( sel );
-       sel = 0;
    }
-   return sel;
+   return 0;
 }
 
 
Index: dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.138
diff -u -r1.138 kernel32.spec
--- dlls/kernel/kernel32.spec	24 Aug 2004 18:46:05 -0000	1.138
+++ dlls/kernel/kernel32.spec	18 Sep 2004 14:42:46 -0000
@@ -1166,11 +1166,7 @@
 # Wine dll separation hacks, these will go away, don't use them
 #
 @ cdecl DOSMEM_AllocSelector(long)
-@ cdecl DOSMEM_Available()
-@ cdecl DOSMEM_FreeBlock(ptr)
-@ cdecl DOSMEM_GetBlock(long ptr)
 @ cdecl DOSMEM_Init(long)
-@ cdecl DOSMEM_ResizeBlock(ptr long long)
 @ cdecl LOCAL_Alloc(long long long)
 @ cdecl LOCAL_Compact(long long long)
 @ cdecl LOCAL_CountFree(long)
? dlls/winedos/mcb.c
Index: dlls/winedos/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/winedos/Makefile.in,v
retrieving revision 1.28
diff -u -r1.28 Makefile.in
--- dlls/winedos/Makefile.in	11 Aug 2004 23:59:07 -0000	1.28
+++ dlls/winedos/Makefile.in	18 Sep 2004 14:42:58 -0000
@@ -41,6 +41,7 @@
 	int67.c \
 	interrupts.c \
 	ioports.c \
+	mcb.c \
 	module.c \
 	ppdev.c \
 	relay.c \
Index: dlls/winedos/devices.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/devices.c,v
retrieving revision 1.11
diff -u -r1.11 devices.c
--- dlls/winedos/devices.c	15 Nov 2003 00:13:21 -0000	1.11
+++ dlls/winedos/devices.c	18 Sep 2004 14:42:59 -0000
@@ -475,7 +475,7 @@
   DOS_LOL->sharing_retry_delay	= 1;
   DOS_LOL->ptr_disk_buf		= 0x0;
   DOS_LOL->offs_unread_CON		= 0x0;
-  DOS_LOL->seg_first_MCB		= 0x0;
+  DOS_LOL->seg_first_MCB		= MCB_First();
   DOS_LOL->ptr_first_DPB		= 0x0;
   DOS_LOL->ptr_first_SysFileTable	= 0x0;
   DOS_LOL->ptr_clock_dev_hdr		= 0x0;
Index: dlls/winedos/dosexe.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v
retrieving revision 1.34
diff -u -r1.34 dosexe.h
--- dlls/winedos/dosexe.h	15 Nov 2003 00:13:21 -0000	1.34
+++ dlls/winedos/dosexe.h	18 Sep 2004 14:43:00 -0000
@@ -88,6 +88,7 @@
 extern WORD DOSVM_psp;     /* psp of current DOS task */
 extern WORD DOSVM_retval;  /* return value of previous DOS task */
 extern struct DPMI_segments *DOSVM_dpmi_segments;
+extern char *MCB_dosmem;   /* start of DOS memory */
 
 #if defined(linux) && defined(__i386__) && defined(HAVE_SYS_VM86_H)
 # define MZ_SUPPORTED
Index: dlls/winedos/int21.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int21.c,v
retrieving revision 1.71
diff -u -r1.71 int21.c
--- dlls/winedos/int21.c	8 Sep 2004 19:05:43 -0000	1.71
+++ dlls/winedos/int21.c	18 Sep 2004 14:43:10 -0000
@@ -4097,7 +4105,6 @@
 void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
 {
     BOOL bSetDOSExtendedError = FALSE;
-
     TRACE( "AX=%04x BX=%04x CX=%04x DX=%04x "
            "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
            AX_reg(context), BX_reg(context), 
@@ -4894,7 +4901,7 @@
                 selector = LOWORD( rv );
             }
             else
-                DOSMEM_GetBlock( bytes, &selector );
+                selector = MCB_Alloc (BX_reg (context));
 
             if (selector)
             {
@@ -4905,7 +4912,7 @@
             {
                 SET_CFLAG(context);
                 SET_AX( context, 0x0008 ); /* insufficient memory */
-                SET_BX( context, DOSMEM_Available() >> 4 );
+                SET_BX( context, MCB_Available() );
             }
         }
 	break;
@@ -4924,7 +4931,7 @@
                     context->SegEs = 0;
             }
             else
-                ok = DOSMEM_FreeBlock( (void*)((DWORD)context->SegEs << 4) );
+                ok = MCB_Free( context->SegEs );
 
             if (!ok)
             {
@@ -4939,7 +4946,8 @@
         TRACE( "RESIZE MEMORY segment %04lX to %d paragraphs\n", 
                context->SegEs, BX_reg(context) );
         {
-            DWORD newsize = (DWORD)BX_reg(context) << 4;
+            WORD maxsize;
+            WORD newsize = BX_reg(context);
             
             if (!ISV86(context) && DOSVM_IsWin16())
             {
@@ -4948,8 +4956,7 @@
             }
             else
             {
-                LPVOID address = (void*)((DWORD)context->SegEs << 4);
-                UINT blocksize = DOSMEM_ResizeBlock( address, newsize, FALSE );
+                UINT blocksize = MCB_Resize( context->SegEs, newsize, FALSE, &maxsize );
 
                 RESET_CFLAG(context);
                 if (blocksize == (UINT)-1)
@@ -4961,7 +4968,7 @@
                 {
                     SET_CFLAG( context );
                     SET_AX( context, 0x0008 );    /* insufficient memory */
-                    SET_BX( context, blocksize >> 4 ); /* new block size */
+                    SET_BX( context, blocksize ); /* new block size */
                 }
             }
         }
Index: dlls/winedos/int31.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int31.c,v
retrieving revision 1.41
diff -u -r1.41 int31.c
--- dlls/winedos/int31.c	25 Nov 2003 00:42:27 -0000	1.41
+++ dlls/winedos/int31.c	18 Sep 2004 14:43:13 -0000
@@ -470,7 +470,8 @@
     if (!already) {
         if (!context->SegSs) {
             alloc = 1; /* allocate default stack */
-            stack16 = addr = DOSMEM_GetBlock( 64, (UINT16 *)&(context->SegSs) );
+            context->SegSs = MCB_Alloc( 16 );
+            stack16 = addr = MCB_SegToLin( context->SegSs );
             context->Esp = 64-2;
             stack16 += 32-1;
             if (!addr) {
@@ -511,7 +512,7 @@
         DOSVM_Enter( context );
         TRACE("returned from real-mode call\n");
     }
-    if (alloc) DOSMEM_FreeBlock( addr );
+    if (alloc) MCB_Free( context->SegSs );
     return 0;
 }
 
@@ -649,7 +650,8 @@
 
     if (NewRMCB)
     {
-	LPVOID RMCBmem = DOSMEM_GetBlock(4, &uParagraph);
+    	uParagraph = MCB_Alloc(1);
+ 	LPVOID RMCBmem = MCB_SegToLin(uParagraph);
 	LPBYTE p = RMCBmem;
 
 	*p++ = 0xcd; /* RMCB: */
@@ -697,7 +699,7 @@
 	PrevRMCB->next = CurrRMCB->next;
 	    else
 	FirstRMCB = CurrRMCB->next;
-	DOSMEM_FreeBlock(PTR_REAL_TO_LIN(SELECTOROF(CurrRMCB->address),OFFSETOF(CurrRMCB->address)));
+	MCB_Free(HIWORD(CurrRMCB->address));
 	HeapFree(GetProcessHeap(), 0, CurrRMCB);
 	return 0;
     }
@@ -1042,7 +1044,7 @@
                 SET_DX( context, LOWORD(dw) );
             } else {
                 SET_AX( context, 0x0008 ); /* insufficient memory */
-                SET_BX( context, DOSMEM_Available() >> 4 );
+                SET_BX( context, MCB_Available() );
                 SET_CFLAG(context);
             }
             break;
Index: dlls/winedos/module.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/module.c,v
retrieving revision 1.44
diff -u -r1.44 module.c
--- dlls/winedos/module.c	13 Aug 2004 00:39:16 -0000	1.44
+++ dlls/winedos/module.c	18 Sep 2004 14:43:14 -0000
@@ -167,7 +167,8 @@
   while (env[sz++]) sz+=strlen(env+sz)+1;
  } else sz++;
  /* allocate it */
- envblk=DOSMEM_GetBlock(sz+sizeof(WORD)+strlen(name)+1,&seg);
+ seg = MCB_Alloc( ((sz+sizeof(WORD)+strlen(name))>>4)+1);
+ envblk = (LPSTR) MCB_SegToLin (seg);
  /* fill it */
  if (env) {
   memcpy(envblk,env,sz);
@@ -191,7 +192,6 @@
 
 static BOOL MZ_InitMemory(void)
 {
-    /* initialize the memory */
     TRACE("Initializing DOS memory structures\n");
     DOSMEM_Init(TRUE);
     DOSDEV_InstallDOSDevices();
@@ -265,14 +265,18 @@
 
     /* allocate memory for the executable */
     TRACE("Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
-    avail=DOSMEM_Available();
+    avail=MCB_Available() << 4;
     if (avail<min_size) {
       ERR("insufficient DOS memory\n");
       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
       goto load_error;
     }
     if (avail>max_size) avail=max_size;
-    psp_start=DOSMEM_GetBlock(avail,&DOSVM_psp);
+    DOSVM_psp = MCB_Alloc ((avail+15)>>4);
+    /* A PSP is identified, that the MCB has stored itself as the owner process */
+    MCB_SetPSP (DOSVM_psp, DOSVM_psp);
+    MCB_SetPSP (env_seg, DOSVM_psp);
+    psp_start = MCB_SegToLin (DOSVM_psp);
     if (!psp_start) {
       ERR("error allocating DOS memory\n");
       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -677,10 +681,8 @@
       DOSVM_SetRMHandler(0x23, psp->savedint23);
       DOSVM_SetRMHandler(0x24, psp->savedint24);
       /* FIXME: deallocate file handles etc */
-      /* free process's associated memory
-       * FIXME: walk memory and deallocate all blocks owned by process */
-      DOSMEM_FreeBlock( PTR_REAL_TO_LIN(psp->environment,0) );
-      DOSMEM_FreeBlock( PTR_REAL_TO_LIN(DOSVM_psp,0) );
+      /* free process's associated memory */
+      MCB_FreePSP( DOSVM_psp );
       /* switch to parent's PSP */
       DOSVM_psp = parpsp;
       psp_start = (LPBYTE)((DWORD)parpsp << 4);
Index: dlls/winedos/winedos.spec
===================================================================
RCS file: /home/wine/wine/dlls/winedos/winedos.spec,v
retrieving revision 1.17
diff -u -r1.17 winedos.spec
--- dlls/winedos/winedos.spec	17 Sep 2003 22:45:46 -0000	1.17
+++ dlls/winedos/winedos.spec	18 Sep 2004 14:43:14 -0000
@@ -6,3 +6,11 @@
 # I/O functions
 @ stdcall inport(long long) DOSVM_inport
 @ stdcall outport(long long long) DOSVM_outport
+
+# export DOS memory functions to kernel
+@ stdcall MCB_SegToLin(long) MCB_SegToLin
+@ stdcall MCB_LinToSeg(ptr) MCB_LinToSeg
+@ stdcall MCB_Available() MCB_Available
+@ stdcall MCB_Alloc (long) MCB_Alloc
+@ stdcall MCB_Free (long) MCB_Free
+@ stdcall MCB_Resize (long long long ptr) MCB_Resize


More information about the wine-patches mailing list