winedos:MCB implementation

Markus Amsler markus.amsler at oribi.org
Wed Sep 15 13:32:14 CDT 2004


Alexandre Julliard wrote:

>The main problem is that you now have both the MCB and the DOSMEM code
>trying to allocate memory in the same area, that won't work. What you
>probably want is to make the DOSMEM functions call out to the MCB
>ones.
>  
>
Thanks, I forgot the win16 side completly.
While writing a win16 dos memory test appliction (see attachement, 
winetest is just win32 right?), i noticed windows (win 3.11, ntvdm) 
handles win16 dos memory quite different than wine:
(everything in win16 protected mode)
- int21 memory alloction dos not affect GlobalDOSAlloc and vice versa.
- int21 can allocate much more then 1 MB memory, and returns proteced 
mode selectors (wine returns real mode selectors)
=> windows maps GlobalDOSAlloc, protected mode int 21 and real mode 
int21 calls to different DOS areas.

Further the alloction overhead (memory that's "missing" after 
alloction)  in protected mode can be 0 bytes.
=> No additional MCB structures in win16 DOS memory, just alignment padding.

So I thought about seperating protected mode and real mode DOS area. In 
the PM using the DOSMEM functions and in RM using the MCB ones. PM int21 
would call GlobalDosAlloc. PM  initialization would be done by the 
kernel, RM by winedos.
pros:
  - complete seperation of kernel and winedos
  - do it similiar like windows (i know that's not a reason)
cons:
  - double the allocation code
  - some more work

Before I waste my time, is this the way to go?

Markus
-------------- next part --------------
/*
 * win16 dos memory test programm
 *
 * 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
 */
 
/*
 * Compiled with Open Watcom C16 Version 1.3 (http://www.openwatcom.org)
 *
 * Tests following functions:
 *   GlobalDosAlloc
 *   GlobalDosFree
 *   GlobalFree
 *   GlobalReAlloc
 *   GlobelHandle
 *   GlobalSize
 *
 * FIXME: test more functions
 *
 * direct DOS memory manipulation with int 21 didn't work in win 3.11 nor in 
 * ntvdm (but in wine :-) ).
 *
 * FIXME: add dpmi memory tests
 * FIXME: fill allocated memory
 */
 
#include <stdio.h>
#include <windows.h>
#include <toolhelp.h>
#include <i86.h>


// #define DEBUG 0;




int dos_free_paragraphs (void){
	union REGS rin;
	union REGS rout;

	rin.x.ax=0x4800;
	rin.x.bx=0xffff;

	int86(0x21,&rin,&rout);

	if (!rout.x.cflag){
		printf("dos_free_paragraphs failed!\n");
		printf(" context in: ");
		dump_context (&rin);
		printf(" context out: ");
		dump_context (&rout);
		return 0;
	}
	return rout.x.bx;
}

void dump_context (union REGS *r){
	printf ("ax=%04x bx=%04xh cx=%04xh dx=%04xh cflag=%04xh\n", r->x.ax, r->x.bx, r->x.cx, r->x.dx, r->x.cflag); 
	
}

int dos_alloc (WORD paras){
	union REGS rin;
	union REGS rout;

	rin.x.ax=0x4800;
	rin.x.bx=paras;

	int86(0x21,&rin,&rout);
#ifdef DEBUG
  dump_context (&rout);
#endif

	if (rout.x.cflag){
		printf("dos_alloc failed!\n");
		printf(" context in: ");
		dump_context (&rin);
		printf(" context out: ");
		dump_context (&rout);
		return 0;
	}
	return 1;
}










/*
 * checks wether the given amount of memory could be reserved
 */
BOOL got_memory (DWORD size){
	DWORD ret;
	WORD sel;
	
	ret = GlobalDosAlloc (size);
	if (!ret) return FALSE;
	GlobalDosFree (LOWORD(ret));
	return TRUE;
}

/*
 * returns the largest block size in bytes that could be reserved.
 * pretty time consuming, but good testing. It probes with alloc / free
 */
DWORD dos_largest (void){
	DWORD max, current, step;
	BOOL gotit;
	
	/* do some sort of binary search */
	max = 0x100000; 
	current = max >> 1;
	step = max >> 2;
	
	while (step>0){
		gotit = got_memory(current);
#ifdef DEBUG
		printf ("dos_largest max=%04x%04xh current=%04x%04xh step=%04x%04xh gotit=%d\n", HIWORD(max), LOWORD(max), 
		           HIWORD(current), LOWORD(current), HIWORD(step), LOWORD(step), gotit);
#endif
		if (gotit){
			current += step;	
		}else{
			current -= step;
		}
		step = step >> 1;
	}

	if (current==1){
		/* FIXME: 1 byte is not eactly no memory */
		return 0;
	}

	if (! got_memory(current-1)){
		printf("ERROR: didn't got_memory(current-1) should not happen\n");
		return 0;
	}

	if (got_memory(current)){
		printf("ERROR: got_memory(current) should not happen\n");
		return 0;
	}

	if (got_memory(current+1)){
		printf("ERROR: got_memory(current+1) should not happen\n");
		return 0;
	}

	return current-1;
}


/*
 * The total amount of DOS memory in bytes.
 * pretty time consuming, but good testing. It sums up the largest blocks recursivly.
 */
DWORD dos_available(void){
	DWORD ret, largest, avail;
	WORD sel;
	
	largest = dos_largest();
	if (!largest){
		/* recursion termination: no DOS memory */
#ifdef DEBUG
		printf("dos_available return 0\n");
#endif
		return 0;
	}

	ret = GlobalDosAlloc (largest);
	if (!ret) return 0;
	avail = dos_available();
	GlobalDosFree (LOWORD(ret));

#ifdef DEBUG
	printf("dos_available largest=%04x%04xh available=%04x%04xh\n", HIWORD(largest), LOWORD(largest)
	          , HIWORD(avail), LOWORD(avail));
#endif
	return largest + avail;
}

/* returns allocation overhead for given block size or -1 on error */
int dos_alloc_overhead (DWORD size){
	DWORD largest_start, avail_start;
	DWORD avail,dos;
	int ret;
	
	avail = dos_available();
	dos = GlobalDosAlloc (size);
	if (!dos){
		return -1;
	}
	ret = avail - dos_available() - size;
	GlobalDosFree(LOWORD (dos));
	return ret;
}


int main (int argc, char** argv){
	DWORD largest_start, avail_start;
	DWORD avail, size;
	DWORD dos, dos2, ret;
	WORD sel, sel2, seg, seg2;
	DWORD handle, h2, h3, h4;

	printf ("Win16 DOS memory test programm\n\n");

	/* First check if dos_largest and dos_available works */
	printf ("Checking available memory\n");
	largest_start = dos_largest();
	printf ("  Largest Block %04x%04xh bytes\n", HIWORD(largest_start), LOWORD(largest_start));

	avail_start = dos_available();
	printf ("  Available memory %04x%04xh bytes\n", HIWORD(avail_start), LOWORD(avail_start));

	/* Checking allocation overhead */
	printf ("\nChecking allocation overhead\n");
	size = 1;
	while (size < 0x20){
		printf ("  Allocation Overhead for %04x%04xh = %d bytes\n", 
		        HIWORD(size), LOWORD(size), dos_alloc_overhead(size));
		size = size << 1;
	}

	size = 0x21;
	printf ("  Allocation Overhead for %04x%04xh = %d\n", 
	        HIWORD(size), LOWORD(size), dos_alloc_overhead(size));

	size = 0x1000;
	printf ("  Allocation Overhead for %04x%04xh = %d\n", 
	        HIWORD(size), LOWORD(size), dos_alloc_overhead(size));

	size = largest_start >> 2;
	printf ("  Allocation Overhead for %04x%04xh = %d\n", 
	        HIWORD(size), LOWORD(size), dos_alloc_overhead(size));

	/* Allocate some memory and check what happens with available memory */
	printf ("\nChecking wether alloc/free works\n");
	size = largest_start >> 2;
	dos = GlobalDosAlloc (size);
	if (!dos){
		printf ("ERROR: couldn't alloc largest/4 memory\n");
	}

	avail = dos_available();
	printf ("  Available memory %04x%04xh bytes\n", HIWORD(avail), LOWORD(avail));
	printf ("  size %04x%04xh bytes\n", HIWORD(size), LOWORD(size));
	printf ("  sum %04x%04xh bytes\n", HIWORD(size+avail), LOWORD(size+avail));
	printf ("  alloc overhead=%04xh\n", avail_start-size-avail);
	
	ret = GlobalDosFree(LOWORD (dos));
	if (ret){
		printf ("ERROR: couldn't free largest/4 memory\n");
	}
	
	avail = dos_available();
  printf ("  Available memory %04x%04xh bytes\n", HIWORD(avail), LOWORD(avail));
  printf ("  dos_free_paragraphs %04xh\n", dos_free_paragraphs() );

	size = 1;
	while (size<0x10000){
		dos_alloc (size);
		size = size << 1;
	}

  printf ("  Allocating 0x200000 of DOS memory with int 21\n");

	dos_alloc (0x8000);
	dos_alloc (0x8000);
	dos_alloc (0x8000);
	dos_alloc (0x8000);

/*
	while (dos_alloc (0x8000)){
	}
*/	
	avail = dos_available();
	printf ("  Available memory %04x%04xh bytes\n", HIWORD(avail), LOWORD(avail));
  printf ("  dos_free_paragraphs %04xh\n", dos_free_paragraphs() );

	printf ("\n\nDONE\n");

	return 0;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dosmem.exe
Type: application/x-msdownload
Size: 35938 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20040915/231e16f7/dosmem.bin


More information about the wine-devel mailing list