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