CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

ALLOC.CPP (23303B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /***************************************************************************
     17  **   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
     18  ***************************************************************************
     19  *                                                                         *
     20  *                 Project Name : Westwood Library                         *
     21  *                                                                         *
     22  *                    File Name : ALLOC.CPP                                *
     23  *                                                                         *
     24  *                   Programmer : Joe L. Bostic                            *
     25  *                                                                         *
     26  *                   Start Date : February 1, 1992                         *
     27  *                                                                         *
     28  *                  Last Update : March 9, 1995 [JLB]                      *
     29  *                                                                         *
     30  *-------------------------------------------------------------------------*
     31  * Functions:                                                              *
     32  *   Alloc -- Allocates system RAM.                                        *
     33  *   Ram_Free -- Determines the largest free chunk of RAM.                 *
     34  *   Free -- Free an Alloc'ed block of RAM.                                *
     35  *   Resize_Alloc -- Change the size of an allocated block.                *
     36  *   Heap_Size -- Size of the heap we have.                                *
     37  *   Total_Ram_Free -- Total amount of free RAM.                           *
     38  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     39 
     40 #if (0)
     41 
     42 #include <malloc.h>
     43 #include <string.h>
     44 #include <stdlib.h>
     45 #include <dos.h>
     46 #include <bios.h>
     47 #include <stdio.h>
     48 
     49 
     50 #ifndef WWMEM_H
     51 #include "wwmem.h"
     52 #endif
     53 
     54 
     55 extern "C" unsigned long Largest_Mem_Block ( void ) ;
     56 
     57 //
     58 // use double-word alignment for allocs
     59 //
     60 #define LONG_ALIGNMENT			1
     61 
     62 /*
     63 ** Define the equates necessary to call a DPMI interrupt.
     64 */
     65 #define	DPMI_INT									0x0031
     66 #define	DPMI_LOCK_MEM							0x0600
     67 #define	DPMI_UNLOCK_MEM						0x0601
     68 #define  LOGGING									FALSE
     69 /*=========================================================================*/
     70 /* The following PRIVATE functions are in this file:                       */
     71 /*=========================================================================*/
     72 
     73 
     74 /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
     75 
     76 unsigned long MinRam=0L;		// Record of least memory at worst case.
     77 unsigned long MaxRam=0L;		// Record of total allocated at worst case.
     78 static unsigned long TotalRam = 0L;
     79 static unsigned long Memory_Calls = 0L;
     80 static unsigned long RequestedSystemRam = 8*1024*1024;
     81 static unsigned long LargestRamBlock = 0L;
     82 
     83 void (*Memory_Error)(void) = NULL;
     84 void (*Memory_Error_Exit)(char *string) = NULL;
     85 
     86 /***************************************************************************
     87  * DPMI_LOCK -- handles locking a block of DPMI memory                     *
     88  *                                                                         *
     89  * INPUT:                                                                  *
     90  *                                                                         *
     91  * OUTPUT:                                                                 *
     92  *                                                                         *
     93  * WARNINGS:                                                               *
     94  *                                                                         *
     95  * HISTORY:                                                                *
     96  *   06/23/1995 PWG : Created.                                             *
     97  *=========================================================================*/
     98 #include"mono.h"
     99 void DPMI_Lock(VOID const *ptr, long const size)
    100 {
    101 	union REGS regs;
    102 	struct SREGS sregs;
    103 
    104 	/*
    105 	** Lock memory
    106 	** AX = 0x600
    107 	** BX:CX = starting linear address of memory to lock
    108 	** SI:DI = size of region to lock (in bytes)
    109 	** - If Failure, carry flag is set.
    110 	*/
    111 	memset (&regs, 0 ,sizeof(regs));
    112 	segread (&sregs);
    113 	regs.x.eax = DPMI_LOCK_MEM;
    114 	regs.x.ebx = ((long)ptr & 0xffff0000) >> 16;
    115 	regs.x.ecx = ((long)ptr & 0x0000ffff);
    116 	regs.x.esi = ((long)size & 0xffff0000) >> 16;
    117 	regs.x.edi = ((long)size & 0x0000ffff);
    118 	int386x (DPMI_INT, &regs, &regs, &sregs);			// call DPMI
    119 //	if (regs.x.cflag) {
    120 //	}
    121 #if(0)
    122 	char *temp = (char *)ptr;
    123 	char hold;
    124 	for (int lp = 0; lp < size; lp += 2048) {
    125 		hold = *temp;
    126 		temp += 2048;
    127 	}
    128 #endif
    129 
    130 }
    131 
    132 /***************************************************************************
    133  * DPMI_UNLOCK -- Handles unlocking a locked block of DPMI                 *
    134  *                                                                         *
    135  * INPUT:                                                                  *
    136  *                                                                         *
    137  * OUTPUT:                                                                 *
    138  *                                                                         *
    139  * WARNINGS:                                                               *
    140  *                                                                         *
    141  * HISTORY:                                                                *
    142  *   06/23/1995 PWG : Created.                                             *
    143  *=========================================================================*/
    144 void DPMI_Unlock(void const *ptr, long const size)
    145 {
    146 	union REGS regs;
    147 	struct SREGS sregs;
    148 
    149 	/*
    150 	** Unlock the memory
    151 	*/
    152 	memset (&regs, 0 ,sizeof(regs));
    153 	segread (&sregs);
    154 	regs.x.eax = DPMI_UNLOCK_MEM;							// DPMI function to call
    155 	regs.x.ebx = ((long)ptr & 0xffff0000) >> 16;
    156 	regs.x.ecx = ((long)ptr & 0x0000ffff);
    157 	regs.x.esi = ((long)size & 0xffff0000) >> 16;
    158 	regs.x.edi = ((long)size & 0x0000ffff);
    159 	int386x (DPMI_INT, &regs, &regs, &sregs);			// call DPMI
    160 //	if (regs.x.cflag) {
    161 //	}
    162 
    163 }
    164 
    165 /***************************************************************************
    166  * Alloc -- Allocates system RAM.                                          *
    167  *                                                                         *
    168  *    This is the basic RAM allocation function.  It is used for all       *
    169  *    memory allocations needed by the system or the main program.         *
    170  *                                                                         *
    171  * INPUT:   bytes_to_alloc -- LONG value of the number of bytes to alloc.  *
    172  *                                                                         *
    173  *          flags          -- Memory allocation control flags.             *
    174  *             MEM_NORMAL: No special flags.                               *
    175  *             MEM_CLEAR:  Zero out memory block.                        	*
    176  *             MEM_NEW:		Called by a new.                                *
    177  *                                                                         *
    178  * OUTPUT:  Returns with pointer to allocated block.  If NULL was returned *
    179  *          it indicates a failure to allocate.  Note: NULL will never be  *
    180  *          returned if the standard library allocation error routine is   *
    181  *          used.                                                          *
    182  *                                                                         *
    183  * WARNINGS:   If you replace the standard memory allocation error routine *
    184  *             and make it so that Alloc CAN return with a NULL, be sure   *
    185  *             and check for this in your code.                            *
    186  *                                                                         *
    187  * HISTORY:                                                                *
    188  *   09/03/1991 JLB : Documented.                                          *
    189  *   08/09/1993 JLB : Updated with EMS memory support.                     *
    190  *   04/28/1994 JAW : Updated to 32bit Protected mode.                     *
    191  *   03/09/1995 JLB : Fixed                                                *
    192  *=========================================================================*/
    193 void *Alloc(unsigned long bytes_to_alloc, MemoryFlagType flags)
    194 {
    195 	union REGS		regs ;
    196 	struct SREGS 	sregs ;
    197 	unsigned char *retval=NULL;	// Pointer to allocated block.
    198 	unsigned long	original_size;	// Original allocation size.
    199 	unsigned long	bytesfree;		// Number of free bytes.
    200 	long 				*longptr=NULL;	// Pointer used to store selector
    201 	static unsigned char _allocinit=0;
    202 
    203 
    204 	//
    205 	// Init memory system by finding largest block to alloc
    206 	// then allocate it to get one large heap and free it.
    207 	// There may be more memory available from DPMI but we only are
    208 	// for now allocating and freeing the first largest block.
    209 	//
    210 	if ( !_allocinit ) {
    211 		unsigned long largestblock = Largest_Mem_Block();
    212 		largestblock -= 1024;				// subtract for heap header and misc
    213 		largestblock &= 0xffff0000;		// forcing to 64K boundary
    214 
    215 		if ( largestblock ) {
    216 			LargestRamBlock = MIN( largestblock, RequestedSystemRam );
    217 			unsigned char *lptr = (unsigned char *)malloc( LargestRamBlock );
    218 			if ( lptr ) {
    219 				free( (void *)lptr );
    220 			}
    221 		}
    222 
    223 		/*
    224 		**	Initialize the total ram available value.
    225 		*/
    226 		TotalRam = Total_Ram_Free(MEM_NORMAL);
    227 
    228 		_allocinit = 1;
    229 	}
    230 
    231 	/*
    232 	** Save the original allocated space size so that we can clear the
    233 	** exact amount of RAM if they specified MEM_CLEAR.
    234 	*/
    235 	original_size = bytes_to_alloc;
    236 
    237 	/*
    238 	** Reserve one byte for the header of the memory we allocated.
    239 	** We will store the flags variable there for later use.
    240 	*/
    241 #if (LONG_ALIGNMENT)
    242 	bytes_to_alloc += (flags & MEM_LOCK) ? 8 : 4;
    243 #else
    244 	bytes_to_alloc += (flags & MEM_LOCK) ? 5 : 1;
    245 #endif
    246 
    247 
    248 	// Try to allocate the memory out of the protected mode memory
    249 	// chain if we did not require a real mode allocation.  If this
    250 	// fails we will have to try to allocate it out of real mode memory.
    251 	// Real mode memory is a last resort because some types of applications
    252 	// require real mode memory.
    253 	if (!(flags & MEM_REAL)) {
    254 		retval = (unsigned char*)malloc(bytes_to_alloc);
    255 	}
    256 
    257 	// Try to allocate the memory out of the real mode memory using DPMI
    258 	// service 0x100.  Note that retval will be null if we are requesting
    259 	// real mode memory so that we do not have to explicitly check for the
    260 	// real mode flag.  Remember we need to reserve room for the dos
    261 	// selector value at the beginning of our allocated block so rather than
    262 	// adding fifteen and rounding, we need to add 19 and round.
    263 	if (!retval) {
    264 		flags = (MemoryFlagType)(flags | MEM_REAL);
    265 		regs.x.eax = 0x100;
    266 		regs.x.ebx = (bytes_to_alloc + 19) >> 4;
    267 		if (regs.x.ebx & 0xFFFF0000) {
    268 			retval = NULL;
    269 		} else {
    270 			segread ( & sregs ) ;
    271 			int386x ( 0x31 , & regs, & regs , & sregs	) ;
    272 			if (regs.x.cflag)
    273 				retval = NULL;
    274 			else {
    275 #if (LONG_ALIGNMENT)
    276 				longptr		= (long *)(((regs.x.eax & 0xFFFF) << 4)+ 4);
    277 #else
    278 				longptr		= (long *)(((regs.x.eax & 0xFFFF) << 4)+ 1);
    279 #endif
    280 				*longptr++	= regs.x.edx & 0xFFFF;
    281 				retval		= (unsigned char *)longptr;
    282 			}
    283 		}
    284 	}
    285 
    286 	// If the alloc failed then we need to signify a memory error.
    287 	if (retval == NULL) {
    288 		if (Memory_Error != NULL)
    289 			Memory_Error();
    290 		return NULL;
    291 	}
    292 
    293 	// If the memory needs to be DPMI locked then we should store the
    294 	// original size in the header before we store the flags.
    295 	if (flags & MEM_LOCK) {
    296 		longptr		= (long *)retval;
    297 		*longptr++	= original_size;
    298 		retval		= (unsigned char *)longptr;
    299 	}
    300 
    301 
    302 	// Now that we know the alloc was sucessful (and for an extra byte
    303 	// more than the user wanted) we need to stick in the memory flags.
    304 #if (LONG_ALIGNMENT)
    305 	if ( !(flags & (MEM_LOCK|MEM_REAL)) ) {
    306 		//
    307 		// WARNING!!!!!!!!!!
    308 		// USE this only with the WATCOM malloc ALLOCATION!!!!!!!!!
    309 		// it reads the actual block size before the ptr returned.
    310 		// then eors and uses the upper word for a validation later on free.
    311 		//
    312 		longptr = (long *)retval;
    313 		*longptr = ((*(longptr - 1)) ^ 0xffffffff) & 0xffff0000;
    314 		*retval++ 		= flags;
    315 		*retval++ 		= (unsigned char)(flags ^ 0xff);
    316 		retval += 2;
    317 	}
    318 	else {
    319 		*retval++ 		= flags;
    320 		*retval++ 		= (unsigned char)(flags ^ 0xff);
    321 		*retval++ 		= 0;
    322 		*retval++ 		= 0;
    323 	}
    324 #else
    325 	*retval++ 		= (unsigned char)(flags | (((flags ^ 0x07) & 0x07) << 5));
    326 #endif
    327 
    328 	// If the memory needed to be DPMI locked then set it up so it
    329 	// is locked.
    330 	if (flags & MEM_LOCK) {
    331 		DPMI_Lock(retval, original_size);
    332 	}
    333 
    334 	/* Clear the space if they wanted it clear */
    335 
    336 	if (flags & MEM_CLEAR) {
    337 		unsigned char	*ptr;		// Working memory block pointer.
    338 
    339 		ptr = retval;
    340 		memset(ptr, '\0', original_size);
    341 	}
    342 
    343 	bytesfree = Total_Ram_Free(MEM_NORMAL);
    344 	if (bytesfree < MinRam) {
    345 		MinRam = bytesfree;
    346 	}
    347 	if (TotalRam-bytesfree > MaxRam) {
    348 		MaxRam = TotalRam-bytesfree;
    349 	}
    350 
    351 	Memory_Calls++;
    352 
    353 #if(LOGGING)
    354 	int val = _heapchk();
    355 
    356 	FILE *file = fopen("mem.txt","at");
    357 	fprintf(file, "%P Alloc size = %d, Actual Size = %d, flags = %d, heap = %d\n",
    358 						retval,
    359 						original_size,
    360 						bytes_to_alloc,
    361 						flags,
    362 						val);
    363 	fclose(file);
    364 #endif
    365 
    366 	return(retval);
    367 }
    368 
    369 
    370 /***************************************************************************
    371  * Free -- Free an Alloc'ed block of RAM.                                  *
    372  *                                                                         *
    373  * FUNCTION:                                                               *
    374  *                                                                         *
    375  * INPUT:       A pointer to a block of RAM from Alloc.                    *
    376  *                                                                         *
    377  * OUTPUT:      None.                                                      *
    378  *                                                                         *
    379  * WARNINGS:    Don't use this for an Alloc_Block'ed RAM block.            *
    380  *                                                                         *
    381  * HISTORY:                                                                *
    382  *   05/25/1990     : Created.                                             *
    383  ***************************************************************************/
    384 void Free(void const *pointer)
    385 {
    386 	union REGS		regs ;
    387 	struct SREGS 	sregs ;
    388 
    389 	void const *original = pointer;
    390 	char string[80];
    391 
    392 	if (pointer) {
    393 		/*
    394 		** Get a pointer to the flags that we stored off.
    395 		*/
    396 #if (LONG_ALIGNMENT)
    397 		unsigned char *byteptr	= ((unsigned char *)pointer) - 4;
    398 
    399 		//
    400 		// validate the flags with and eor of the flags
    401 		//
    402 		if ( *byteptr != ((*(byteptr + 1)) ^ 0xff) ) {
    403 			if (Memory_Error_Exit != NULL) {
    404 				sprintf( string, "Error freeing pointer %p.  Header invalid!!!\n", pointer );
    405 				Memory_Error_Exit( string );
    406 			}
    407 		}
    408 		else {
    409 			if ( !(*byteptr & (MEM_LOCK|MEM_REAL)) ) {
    410 				unsigned short *wordptr = (unsigned short *)(byteptr - 2);
    411 
    412 				//
    413 				// WARNING!!!!!!!!!!
    414 				// USE this only with the WATCOM malloc ALLOCATION!!!!!!!!!
    415 				// it reads the actual block size before the ptr to be freed.
    416 				// then compares with the EOR to the value stored during allocation.
    417 				//
    418 				if ( *wordptr != ((*(wordptr + 2)) ^ 0xffff) ) {
    419 					if (Memory_Error_Exit != NULL) {
    420 						sprintf( string, "Error freeing pointer %p.  Header invalid!!!\n", pointer );
    421 						Memory_Error_Exit( string );
    422 					}
    423 				}
    424 			}
    425 			else if ( *(byteptr + 2) || *(byteptr + 3) ) {
    426 				if (Memory_Error_Exit != NULL) {
    427 					sprintf( string, "Error freeing pointer %p.  Header invalid!!!\n", pointer );
    428 					Memory_Error_Exit( string );
    429 				}
    430 			}
    431 		}
    432 //		if ( *byteptr != (*(byteptr + 1) ^ 0xff) ||
    433 //			*(byteptr + 2) || *(byteptr + 3) ) {
    434 //			if (Memory_Error_Exit != NULL) {
    435 //				sprintf( string, "Error freeing pointer %p.  Header invalid!!!\n", pointer );
    436 //				Memory_Error_Exit( string );
    437 //			}
    438 //		}
    439 #else
    440 		unsigned char *byteptr	= ((unsigned char *)pointer) - 1;
    441 
    442 		if ( (*byteptr & 0xe0) != (((*byteptr ^ 0x07) & 0x07) << 5) ) {
    443 			if (Memory_Error_Exit != NULL) {
    444 				sprintf( string, "Error freeing pointer %p.  Header invalid!!!\n", pointer );
    445 				Memory_Error_Exit( string );
    446 			}
    447 		}
    448 #endif
    449 
    450 		/*
    451 		** Check to see if this was locked me and if it was unlock it.
    452 		*/
    453 		if (*byteptr & MEM_LOCK) {
    454 			long *longptr = ((long *)byteptr) - 1;
    455 			DPMI_Unlock(pointer, *longptr);
    456 			pointer = (void *)longptr;
    457 		} else
    458 			pointer = (void *)byteptr;
    459 
    460 #if(LOGGING)
    461 		int val = _heapchk();
    462 		FILE *file = fopen("mem.txt","at");
    463 		fprintf(file, "%P Free flags = %d, Heap = %d\n",
    464 							original,
    465 							*byteptr,
    466 							val);
    467 		fclose(file);
    468 #endif
    469 
    470 		// If the pointer is a real mode pointer than it will point to the
    471 		// first megabyte of system memory.  If it does than we need to
    472 		// use DPMI to free it.
    473 		if (*byteptr & MEM_REAL) {
    474 			regs.x.eax	= 0x101;
    475 			regs.x.edx	= *(((long *)pointer) - 1);
    476 			segread ( & sregs ) ;
    477 			int386x(0x31, &regs, &regs, &sregs);
    478 		} else {
    479 			free((void *)pointer);
    480 		}
    481 		Memory_Calls--;
    482 	}
    483 }
    484 
    485 
    486 /***************************************************************************
    487  * Resize_Alloc -- Change the size of an allocated block.                  *
    488  *                                                                         *
    489  *    This routine will take a previously allocated block and change its   *
    490  *    size without unnecessarily altering its contents.                    *
    491  *                                                                         *
    492  * INPUT:   pointer  -- Pointer to the original memory allocation.         *
    493  *                                                                         *
    494  *          new_size -- Size in bytes that it will be converted to.        *
    495  *                                                                         *
    496  * OUTPUT:  Returns with a pointer to the new allocation.                  *
    497  *                                                                         *
    498  * WARNINGS:   ???                                                         *
    499  *                                                                         *
    500  * HISTORY:                                                                *
    501  *   02/01/1992 JLB : Commented.                                           *
    502  *=========================================================================*/
    503 void *Resize_Alloc(void *original_ptr, unsigned long new_size_in_bytes)
    504 {
    505 
    506 	unsigned long *temp;
    507 //	unsigned long diff, flags;
    508 
    509 	temp = (unsigned long*)original_ptr;
    510 
    511 	/* ReAlloc the space */
    512 	temp = (unsigned long *)realloc(temp, new_size_in_bytes);
    513 	if (temp == NULL) {
    514 		if (Memory_Error != NULL)
    515 			Memory_Error();
    516 		return NULL;
    517 	}
    518 
    519 	return(temp);
    520 }
    521 
    522 
    523 /***************************************************************************
    524  * Ram_Free -- Determines the largest free chunk of RAM.                   *
    525  *                                                                         *
    526  *    Use this routine to determine the largest free chunk of available    *
    527  *    RAM for allocation.  It also performs a check of the memory chain.   *
    528  *                                                                         *
    529  * INPUT:   none                                                           *
    530  *                                                                         *
    531  * OUTPUT:  Returns with the size of the largest free chunk of RAM.        *
    532  *                                                                         *
    533  * WARNINGS:   This does not return the TOTAL memory free, only the        *
    534  *             largest free chunk.                                         *
    535  *                                                                         *
    536  * HISTORY:                                                                *
    537  *   09/03/1991 JLB : Commented.                                           *
    538  *=========================================================================*/
    539 long Ram_Free(MemoryFlagType)
    540 {
    541 	return(_memmax());
    542 //	return Largest_Mem_Block();
    543 }
    544 
    545 
    546 /***************************************************************************
    547  * Heap_Size -- Size of the heap we have.                                  *
    548  *                                                                         *
    549  *                                                                         *
    550  *                                                                         *
    551  * INPUT:                                                                  *
    552  *                                                                         *
    553  * OUTPUT:                                                                 *
    554  *                                                                         *
    555  * WARNINGS:                                                               *
    556  *                                                                         *
    557  * HISTORY:                                                                *
    558  *   06/21/1994 SKB : Created.                                             *
    559  *=========================================================================*/
    560 long Heap_Size(MemoryFlagType )
    561 {
    562 	if (!TotalRam) {
    563 		TotalRam = Total_Ram_Free(MEM_NORMAL);
    564 	}
    565 	return(TotalRam);
    566 }
    567 
    568 
    569 /***************************************************************************
    570  * Total_Ram_Free -- Total amount of free RAM.                             *
    571  *                                                                         *
    572  *                                                                         *
    573  *                                                                         *
    574  * INPUT:                                                                  *
    575  *                                                                         *
    576  * OUTPUT:                                                                 *
    577  *                                                                         *
    578  * WARNINGS:                                                               *
    579  *                                                                         *
    580  * HISTORY:                                                                *
    581  *   06/21/1994 SKB : Created.                                             *
    582  *   03/09/1995 JLB : Uses prerecorded heap size maximum.                  *
    583  *=========================================================================*/
    584 long Total_Ram_Free(MemoryFlagType )
    585 {
    586 	return(_memavl());
    587 //	return Largest_Mem_Block () ;
    588 }
    589 
    590 #endif