home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
pgmutl
/
val_link.arc
/
MEMORY.C
< prev
next >
Wrap
Text File
|
1989-02-18
|
11KB
|
263 lines
/* MEMORY.C */
/* Memory management presents a challenge if one desires to be compatible
with OS/2. The problem centers on the fact that memory references
(e.g., a memory address) differ between the real (8086) and protected
(80286) modes of operation. In the real mode, a memory reference is
is via a "segment/offset" while in the protected mode, a memory reference
is via a "descriptor/offset". Both are 32-bit items with the 16-bit
offset working the same in both. However, segments and descriptors are
not necessarily the same. If compatibility with OS/2 and DOS is an
objective, then one must not use a descriptor as if it were a segment.
It is however safe to use a segment as if it were a descriptor. In
effect, this means you cannot treat the segment as if it is related to
a memory address by a factor of 16. A segment must be treated as if
were a descriptor. That is, a segment is treated as a reference (not
necessarily an address) to the beginning of an area of memory which can
be up to 64K. Each byte within the area of memory is accessed via the
offset mechanism. */
/* The data structure for memory is handled as follows: At the beginning
of execution, all available far memory is allocated in 64K chunks, with
a "memory descriptor" for each chunk. The memory desciptors for these
chunks are linked together into memory pools. Initially, all descriptors
are linked to the free pool. As a chunk is needed, it is allocated to
a pool. Some pools are needed only for a brief time. In these cases,
when a chunk is no longer needed it is returned to the free pool. */
/*+-------------------------------------------------------------------------+
| |
| add_chunk_to_pool |
| |
+-------------------------------------------------------------------------+*/
memory_descriptor_ptr add_chunk_to_pool(pool_descriptor_ptr pool,
bit_32 size)
BeginDeclarations
#define Pool (*pool)
memory_descriptor_ptr desc;
#define Desc (*desc)
memory_descriptor_ptr prior;
#define Prior (*prior)
EndDeclarations
BeginCode
prior = Null;
desc = free_pool.memory_descriptor_list;
While desc IsNotNull
BeginWhile
If Desc.available NotLessThan size
Then
If prior IsNull
Then
free_pool.memory_descriptor_list = Desc.next;
Else
Prior.next = Desc.next;
EndIf;
free_pool.pool_size -= Desc.available;
Pool.pool_size += Desc.available;
Desc.next = Pool.memory_descriptor_list;
Pool.memory_descriptor_list = desc;
far_set(Desc.chunk, 0, Bit_16(Desc.available));
return(desc);
EndIf;
prior = desc;
Next(desc);
EndWhile;
linker_error (8,"No more free far memory for pool \"%s\"\n."
"\tTry running again with smaller buffersize and/or\n"
"\tvirtualized fixup processing.\n",
Pool.pool_id);
return(desc); /* To kill warning */
EndCode
#undef Pool
#undef Desc
#undef Prior
/*+-------------------------------------------------------------------------+
| |
| allocate_memory |
| |
+-------------------------------------------------------------------------+*/
byte_ptr allocate_memory (pool_descriptor_ptr pool, bit_32 size)
BeginDeclarations
#define Pool (*pool)
#define Desc (*desc)
#define Prev (*prev)
memory_descriptor_ptr desc;
memory_descriptor_ptr prev;
byte_ptr element;
EndDeclarations
BeginCode
/* Traverse the memory descriptor list and allocate the space from the
first memory descriptor which has enough available space for the entire
element to be allocated. */
prev = NULL;
desc = Pool.memory_descriptor_list;
While desc IsNotNull
BeginWhile
If size NotGreaterThan Desc.available
Then /* We can take the element from this chunk */
Pool.used_bytes += size;
element = Desc.unused_base;
Desc.unused_base += Bit_16(size);
Desc.available -= size;
If prev IsNotNull
Then
Prev.next = Desc.next;
Desc.next = Pool.memory_descriptor_list;
Pool.memory_descriptor_list = desc;
EndIf;
return(element);
EndIf;
prev = desc;
Next(desc);
EndWhile;
/* Well, none of the memory descriptors had enough space to allocate this
element. So, we will have to get another chunk, add it to this pool and
allocate the space from the new chunk. */
desc = add_chunk_to_pool(pool, size);
Pool.used_bytes += size;
element = Desc.unused_base;
Desc.unused_base += Bit_16(size);
Desc.available -= size;
return(element);
EndCode
#undef Pool
#undef Desc
#undef Prev
/*+-------------------------------------------------------------------------+
| |
| initialize_memory |
| |
| O/S dependent |
| |
+-------------------------------------------------------------------------+*/
void initialize_memory()
BeginDeclarations
byte huge *far_memory;
bit_32 far_memory_size;
bit_32 size_this_chunk;
bit_16 rc;
memory_descriptor_ptr desc;
#define Desc (*desc)
EndDeclarations
BeginCode
/* First step for PC-DOS is to gobble all free paragraphs above the heap.
The variable "far_memory" will point to that area. */
inregs.h.ah = 0x48; /* DOS allocate memory */
inregs.x.bx = 0xFFFF; /* Ask for too much memory */
rc = intdos(Addr(inregs),Addr(outregs));/* Do the allocate expecting to fail*/
If (outregs.x.cflag IsFalse) OrIf (rc IsNot 8)
Then
DOS_error("Problem allocating memory above heap.\n");
EndIf;
inregs.x.bx = outregs.x.bx; /* Ask for the right amount this time*/
DOS_int21("Problem allocating memory above heap.\n");
far_memory = (byte huge *) MakeFarPtr(outregs.x.ax,0);
far_memory_size = Bit_32(inregs.x.bx) ShiftedLeft 4;
If far_memory_size LessThan 65536L
Then
linker_error(8,"Too little memory above heap.\n"
"\tTry running again with smaller buffersize and/or\n"
"\tvirtualized fixup processing.\n");
EndIf;
/* Initialize the static pool with it's first chunk. This is a little
tricky because the initial value of several data structures are
initialized simutaneously. */
far_set(BytePtr(far_memory), 0, 0); /* Clear initial chunk */
desc = (memory_descriptor_ptr) far_memory;
static_pool.memory_descriptor_list = desc;
static_pool.used_bytes = sizeof(memory_descriptor_type);
static_pool.pool_size =
Desc.size =
Desc.available = 65536L;
Desc.chunk =
Desc.unused_base = BytePtr(far_memory);
Desc.next = NULL;
far_memory += Desc.available;
far_memory_size -= Desc.available;
Desc.available -= sizeof(memory_descriptor_type);
Desc.unused_base += sizeof(memory_descriptor_type);
/* Now set up the free pool */
free_pool.pool_size =
free_pool.used_bytes = 0L;
free_pool.memory_descriptor_list = NULL;
While far_memory_size IsNotZero
BeginWhile
desc = (memory_descriptor_ptr)
allocate_memory(Addr(static_pool),
Bit_32(sizeof(memory_descriptor_type)));
If far_memory_size Exceeds 65536L
Then
size_this_chunk = 65536L;
Else
size_this_chunk = far_memory_size;
EndIf;
Desc.chunk =
Desc.unused_base = BytePtr(far_memory);
Desc.size =
Desc.available = size_this_chunk;
free_pool.pool_size += size_this_chunk;
Desc.next = free_pool.memory_descriptor_list;
free_pool.memory_descriptor_list = desc;
far_memory += size_this_chunk;
far_memory_size -= size_this_chunk;
EndWhile;
free_pool.pool_id = "Free pool";
static_pool.pool_id = "Static pool";
dynamic_pool.pool_id = "Dynamic pool";
dynamic_pool.memory_descriptor_list = Null;
dynamic_pool.pool_size =
dynamic_pool.used_bytes = 0L;
return;
EndCode
#undef Desc
/*+-------------------------------------------------------------------------+
| |
| release_pool |
| |
+-------------------------------------------------------------------------+*/
void release_pool(pool_descriptor_ptr pool)
BeginDeclarations
#define Pool (*pool)
memory_descriptor_ptr desc;
#define Desc (*desc)
memory_descriptor_ptr next;
EndDeclarations
BeginCode
desc = Pool.memory_descriptor_list;
While desc IsNotNull
BeginWhile
Desc.available = Desc.size;
Desc.unused_base = Desc.chunk;
free_pool.pool_size += Desc.available;
next = Desc.next;
Desc.next = free_pool.memory_descriptor_list;
free_pool.memory_descriptor_list = desc;
desc = next;
EndWhile;
Pool.memory_descriptor_list = Null;
Pool.pool_size =
Pool.used_bytes = 0L;
return;
EndCode
#undef Pool
#undef Desc