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