winedos: implement MCB

Markus Amsler markus.amsler at oribi.org
Fri Dec 9 08:07:44 CST 2005


With this patch freecom 0.82pl3 from freedos [1] starts.
 $wineconsole backend=user command.com
There are still some issues but it works.

Thanks to Eric Pouech for the dosmem separation.

[1] http://freedos.sourceforge.net/freecom/packages/082pl3/

Changelog:
 Markus Amsler <markus.amsler at oribi.org>
 Implement Memory Control Block management in dosmem.

-------------- next part --------------
? dlls/winedos/dosmem_mcb.diff
? dlls/winedos/winedos.dll.dbg.c
Index: dlls/winedos/dosmem.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosmem.c,v
retrieving revision 1.3
diff -u -r1.3 dosmem.c
--- dlls/winedos/dosmem.c	26 Aug 2005 08:53:32 -0000	1.3
+++ dlls/winedos/dosmem.c	9 Dec 2005 13:43:05 -0000
@@ -51,38 +51,48 @@
 static char *DOSMEM_dosmem;
 static char *DOSMEM_sysmem;
 
-/* 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__
+ * Memory Control Block (MCB) definition
+ * FIXME: implement Allocation Strategy
  */
 
-typedef struct {
-   unsigned	size;
-} dosmem_entry;
+#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) )
+
+/* FIXME: should we check more? */
+#define MCB_VALID(mc) \
+    ((mc->type==MCB_TYPE_NORMAL) || (mc->type==MCB_TYPE_LAST))
+
+
+#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_ALIGN_BYTE DECLSPEC_ALIGN(1);
 
 typedef struct {
-  unsigned      blocks;
-  unsigned      free;
-} dosmem_info;
+    BYTE type;
+    WORD_ALIGN_BYTE psp;     /* segment of owner psp */
+    WORD_ALIGN_BYTE size;    /* in paragraphs */
+    BYTE pad[3];
+    BYTE name[8];
+} MCB;
 
-static inline dosmem_entry* next_block(dosmem_entry* block)
-{
-    return (dosmem_entry*)((char*)block +
-                           sizeof(dosmem_entry) + (block->size & DM_BLOCK_MASK));
-}
+/*
+#define __DOSMEM_DEBUG__
+ */
 
 #define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
 #define VM_STUB_SEGMENT 0xf000         /* BIOS segment */
 
-/* FIXME: this should be moved to the LOL, and the whole allocation strategy
- * should use real MCB
- */
-static dosmem_info* DOSMEM_info_block;
+/* FIXME: this should be moved to the LOL */
+static MCB* DOSMEM_root_block;
 
 /***********************************************************************
  *           DOSMEM_MemoryTop
@@ -95,18 +105,6 @@
 }
 
 /***********************************************************************
- *           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_info_block) +
-                           ((((sizeof(dosmem_info) + 0xf) & ~0xf) - sizeof(dosmem_entry))));
-}
-
-/***********************************************************************
  *           DOSMEM_FillIsrTable
  *
  * Fill the interrupt table with fake BIOS calls to BIOSSEG (0xf000).
@@ -234,78 +232,82 @@
 }
 
 /***********************************************************************
+ *           DOSMEM_Collapse
+ *
+ * Helper function for internal use only.
+ * Atach all following free blocks to this one, even if this one is not free.
+ */
+void DOSMEM_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 );
+    }
+}
+
+/***********************************************************************
  *           DOSMEM_AllocBlock
  *
  * Carve a chunk of the DOS memory block (without selector).
  */
 LPVOID DOSMEM_AllocBlock(UINT size, UINT16* pseg)
 {
-   UINT  	 blocksize;
-   char         *block = NULL;
-   dosmem_info  *info_block = DOSMEM_info_block;
-   dosmem_entry *dm;
-#ifdef __DOSMEM_DEBUG_
-   dosmem_entry *prev = NULL;
-#endif
-
-   if( size > info_block->free ) return NULL;
-   dm = DOSMEM_RootBlock();
+    MCB *curr = DOSMEM_root_block;
+    MCB *next = NULL;
+    WORD psp = DOSVM_psp;
+    
+    if (!psp)
+        psp = MCB_PSP_DOS;
+    
+    *pseg = 0;
+    
+    TRACE( "(%04xh)\n", size );
+    
+    /* round up to paragraph */
+    size = (size + 15) >> 4;
 
-   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
+    DOSMEM_Available();     /* checks the whole MCB list */
 #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;
+    
+    /* loop over all MCB and search the next large enough MCB */
+    while (curr)
+    {
+        if (!MCB_VALID (curr))
+        {
+            ERR( "MCB List Corrupt\n" );
+            MCB_DUMP( curr );
+            return NULL;
+        }
+        if (curr->psp == MCB_PSP_FREE)
+        {
+            DOSMEM_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) << 4));
+                    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;
+                if( pseg ) *pseg = (((char*)curr) + 16 - (char*)DOSMEM_dosmem) >> 4;
+                return (LPVOID) ((char*)curr + 16);
+            }
+        }
+        curr = MCB_NEXT(curr);
+    }
+    return NULL;
 }
 
 /***********************************************************************
@@ -313,28 +315,24 @@
  */
 BOOL DOSMEM_FreeBlock(void* ptr)
 {
-   dosmem_info  *info_block = DOSMEM_info_block;
-
-   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));
+    MCB* mcb = (MCB*) ((char*)ptr - 16);
+    
+    TRACE( "(%p)\n", ptr );
 
-       if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
 #ifdef __DOSMEM_DEBUG__
-	 && ((dm->size & DM_BLOCK_DEBUG) == DM_BLOCK_DEBUG )
+    DOSMEM_Available();
 #endif
-	 )
-       {
-	     info_block->blocks--;
-	     info_block->free += dm->size;
-
-	     dm->size |= DM_BLOCK_FREE;
-	     return TRUE;
-       }
-   }
-   return FALSE;
+    
+    if (!MCB_VALID (mcb))
+    {
+        ERR( "MCB invalid\n" );
+        MCB_DUMP( mcb );
+        return FALSE;
+    }
+    
+    mcb->psp = MCB_PSP_FREE;
+    DOSMEM_Collapse( mcb );
+    return TRUE;
 }
 
 /***********************************************************************
@@ -345,72 +343,55 @@
  * 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.
+ *
+ * TODO: return also biggest block size
  */
 UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
 {
-   char         *block = NULL;
-   dosmem_info  *info_block = DOSMEM_info_block;
-   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;
+    MCB* mcb = (MCB*) ((char*)ptr - 16);
+    MCB* next;
+    
+    TRACE( "(%p,%04xh,%s)\n", ptr, size, exact ? "TRUE" : "FALSE" );
+    
+    /* round up to paragraph */
+    size = (size + 15) >> 4;
+
+#ifdef __DOSMEM_DEBUG__
+    DOSMEM_Available();
+#endif
+    
+    if (!MCB_VALID (mcb))
+    {
+        ERR( "MCB invalid\n" );
+        MCB_DUMP( mcb );
+        return -1;
+    }
 
-   return size;
+    /* resize needed? */
+    if (mcb->size == size)
+        return size;
+
+    /* collapse free blocks */
+    DOSMEM_Collapse( mcb );    
+    
+    /* shrink mcb ? */
+    if (mcb->size > size)
+    {
+        next = (MCB *) ((char*)mcb + ((size+1) << 4));
+        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 << 4;
+    }
+    
+    if (!exact)
+    {
+        return mcb->size << 4;
+    }
+    
+    return -1;
 }
 
 /***********************************************************************
@@ -418,39 +399,30 @@
  */
 UINT DOSMEM_Available(void)
 {
-   UINT  	 blocksize, available = 0;
-   dosmem_entry *dm;
-
-   dm = DOSMEM_RootBlock();
-
-   while (dm && dm->size != DM_BLOCK_TERMINAL)
-   {
+    UINT  available = 0;
+    UINT  total = 0;
+    MCB *curr = DOSMEM_root_block;
+    /* loop over all MCB and search the largest free MCB */
+    while (curr)
+    {
 #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;
+        MCB_DUMP( curr );
 #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;
+        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 << 4;   
 }
 
 /***********************************************************************
@@ -460,26 +432,14 @@
  */
 static void DOSMEM_InitMemory(char* addr)
 {
-    dosmem_entry*       root_block;
-    dosmem_entry*       dm;
-
     DOSMEM_FillBiosSegments();
     DOSMEM_FillIsrTable();
 
-    DOSMEM_info_block = (dosmem_info*)addr;
-    root_block = DOSMEM_RootBlock();
-    root_block->size = DOSMEM_MemoryTop() - (((char*)root_block) + sizeof(dosmem_entry));
-
-    DOSMEM_info_block->blocks = 0;
-    DOSMEM_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
-        ;
+    /* align root block to paragraph */
+    DOSMEM_root_block = (MCB*) (( (DWORD)(addr+0xf) >> 4) << 4);
+    DOSMEM_root_block->type = MCB_TYPE_LAST;
+    DOSMEM_root_block->psp = MCB_PSP_FREE;
+    DOSMEM_root_block->size = (DOSMEM_MemoryTop() - ((char*)DOSMEM_root_block)) >> 4;
 
     TRACE("DOS conventional memory initialized, %d bytes free.\n",
           DOSMEM_Available());


More information about the wine-patches mailing list