461 lines
10 KiB
C
461 lines
10 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dosmem.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for allocating and freeing DOS memory.
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) 12-Dec-1996
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "softpc.h"
|
|
#include <malloc.h>
|
|
#include <xlathlp.h>
|
|
|
|
#define DOSERR_NOT_ENOUGH_MEMORY 8
|
|
#define DOSERR_INVALID_BLOCK 9
|
|
|
|
MEM_DPMI DosMemHead = { NULL, 0, &DosMemHead, &DosMemHead, 0};
|
|
|
|
|
|
VOID
|
|
DpmiAllocateDosMem(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates a block of DOS memory. The client is switched
|
|
to V86 mode, and DOS is called to allocate the memory. Then a selector
|
|
is allocated for the PM app to reference the memory.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DECLARE_LocalVdmContext;
|
|
PMEM_DPMI DosMemBlock;
|
|
CLIENT_REGS SaveRegs;
|
|
USHORT Sel;
|
|
USHORT Seg;
|
|
ULONG ParaSize = getBX();
|
|
ULONG MemSize = ((ULONG)ParaSize) << 4;
|
|
USHORT DosError = 0;
|
|
USHORT SizeLargest = 0;
|
|
|
|
SAVE_CLIENT_REGS(SaveRegs);
|
|
|
|
if (WOWAllocSeg) {
|
|
PUCHAR VdmStackPointer;
|
|
ULONG NewSP;
|
|
|
|
//
|
|
// WOW is doing the allocation
|
|
//
|
|
|
|
BuildStackFrame(4, &VdmStackPointer, &NewSP);
|
|
|
|
setCS(WOWAllocSeg);
|
|
setIP(WOWAllocFunc);
|
|
|
|
*(PDWORD16)(VdmStackPointer-4) = MemSize;
|
|
*(PWORD16)(VdmStackPointer-6) = (USHORT) (PmBopFe >> 16);
|
|
*(PWORD16)(VdmStackPointer-8) = (USHORT) PmBopFe;
|
|
setSP((WORD)NewSP);
|
|
|
|
host_simulate();
|
|
|
|
Sel = getAX();
|
|
Seg = getDX();
|
|
if (!Sel) {
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
} else {
|
|
USHORT SelCount;
|
|
|
|
//
|
|
// DOS is doing the allocation
|
|
// First get a mem_block to track the allocation
|
|
//
|
|
|
|
DosMemBlock = malloc(sizeof(MEM_DPMI));
|
|
|
|
if (!DosMemBlock) {
|
|
|
|
// Couldn't get the MEM_DPMI
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Next allocate the selector array
|
|
//
|
|
|
|
SelCount = (USHORT) ((MemSize+65535)>>16);
|
|
Sel = ALLOCATE_SELECTORS(SelCount);
|
|
|
|
if (!Sel) {
|
|
|
|
// Couldn't get the selectors
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
free(DosMemBlock);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Now have DOS allocate the memory
|
|
//
|
|
|
|
DpmiSwitchToRealMode();
|
|
|
|
setBX((WORD)ParaSize);
|
|
setAX(0x4800);
|
|
|
|
DPMI_EXEC_INT(0x21);
|
|
|
|
if (getCF()) {
|
|
USHORT i;
|
|
|
|
// Couldn't get the memory
|
|
DosError = getAX();
|
|
SizeLargest = getBX();
|
|
for (i = 0; i < SelCount; i++, Sel+=8) {
|
|
FreeSelector(Sel);
|
|
}
|
|
free(DosMemBlock);
|
|
|
|
} else {
|
|
ULONG Base;
|
|
|
|
//
|
|
// Got the block. Save the allocation info, and set
|
|
// up the descriptors
|
|
//
|
|
|
|
Seg = getAX();
|
|
Base = ((ULONG)Seg) << 4;
|
|
|
|
DosMemBlock->Address = (PVOID)Seg;
|
|
DosMemBlock->Length = (ULONG)ParaSize;
|
|
DosMemBlock->Sel = Sel;
|
|
DosMemBlock->SelCount = SelCount;
|
|
DosMemBlock->Owner = 0;
|
|
INSERT_BLOCK(DosMemBlock, DosMemHead);
|
|
|
|
SetDescriptorArray(Sel, Base, MemSize);
|
|
}
|
|
|
|
DpmiSwitchToProtectedMode();
|
|
}
|
|
}
|
|
}
|
|
|
|
SET_CLIENT_REGS(SaveRegs);
|
|
|
|
if (DosError) {
|
|
setAX(DosError);
|
|
setBX(SizeLargest);
|
|
setCF(1);
|
|
} else {
|
|
setDX(Sel);
|
|
setAX(Seg);
|
|
setCF(0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DpmiFreeDosMem(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees a block of DOS memory.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DECLARE_LocalVdmContext;
|
|
PMEM_DPMI DosMemBlock;
|
|
CLIENT_REGS SaveRegs;
|
|
USHORT Sel = getDX();
|
|
USHORT DosError = 0;
|
|
|
|
SAVE_CLIENT_REGS(SaveRegs);
|
|
|
|
if (WOWFreeSeg) {
|
|
PUCHAR VdmStackPointer;
|
|
ULONG NewSP;
|
|
|
|
//
|
|
// WOW is doing the free
|
|
//
|
|
|
|
BuildStackFrame(3, &VdmStackPointer, &NewSP);
|
|
|
|
setCS(WOWFreeSeg);
|
|
setIP(WOWFreeFunc);
|
|
|
|
*(PWORD16)(VdmStackPointer-2) = Sel;
|
|
*(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
|
|
*(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
|
|
setSP((WORD)NewSP);
|
|
|
|
host_simulate();
|
|
|
|
Sel = getAX();
|
|
if (!Sel) {
|
|
DosError = DOSERR_INVALID_BLOCK;
|
|
}
|
|
|
|
} else {
|
|
USHORT i;
|
|
|
|
DosError = DOSERR_INVALID_BLOCK; // assume failure
|
|
//
|
|
// DOS is doing the free
|
|
// First find the mem_block for this allocation
|
|
//
|
|
DosMemBlock = DosMemHead.Next;
|
|
|
|
while(DosMemBlock != &DosMemHead) {
|
|
|
|
if (DosMemBlock->Sel == Sel) {
|
|
|
|
DpmiSwitchToRealMode();
|
|
|
|
setES((WORD)DosMemBlock->Address);
|
|
setAX(0x4900);
|
|
|
|
DPMI_EXEC_INT(0x21);
|
|
|
|
if (getCF()) {
|
|
|
|
// Couldn't free the memory
|
|
DosError = getAX();
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < DosMemBlock->SelCount; i++, Sel+=8) {
|
|
FreeSelector(Sel);
|
|
}
|
|
DELETE_BLOCK(DosMemBlock);
|
|
free(DosMemBlock);
|
|
DosError = 0;
|
|
}
|
|
|
|
DpmiSwitchToProtectedMode();
|
|
|
|
break;
|
|
}
|
|
DosMemBlock = DosMemBlock->Next;
|
|
}
|
|
}
|
|
|
|
SET_CLIENT_REGS(SaveRegs);
|
|
|
|
if (DosError) {
|
|
setAX(DosError);
|
|
setCF(1);
|
|
} else {
|
|
setCF(0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DpmiSizeDosMem(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls DOS to resize a DOS memory block, or to get
|
|
the largest available block.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
DECLARE_LocalVdmContext;
|
|
PMEM_DPMI DosMemBlock;
|
|
CLIENT_REGS SaveRegs;
|
|
USHORT Sel = getDX();
|
|
ULONG ParaSize = getBX();
|
|
ULONG MemSize = ((ULONG)ParaSize) << 4;
|
|
USHORT DosError = 0;
|
|
|
|
SAVE_CLIENT_REGS(SaveRegs);
|
|
|
|
if (WOWFreeSeg) {
|
|
|
|
//
|
|
// WOW is doing the resize
|
|
//
|
|
|
|
// Not implemented
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
USHORT SelCount;
|
|
USHORT i;
|
|
|
|
//
|
|
// DOS is doing the resize
|
|
// Find the mem_block for this allocation
|
|
// First see if we need a new selector array
|
|
//
|
|
|
|
DosError = DOSERR_INVALID_BLOCK; // assume failure
|
|
DosMemBlock = DosMemHead.Next;
|
|
|
|
while(DosMemBlock != &DosMemHead) {
|
|
|
|
if (DosMemBlock->Sel == Sel) {
|
|
USHORT NewSel = 0;
|
|
USHORT NewSelCount = 0;
|
|
|
|
//
|
|
// If we have to grow the selector array, make sure
|
|
// we can grow it in place
|
|
//
|
|
SelCount = (USHORT) ((MemSize+65535)>>16);
|
|
|
|
if (SelCount > DosMemBlock->SelCount) {
|
|
USHORT TmpSel;
|
|
|
|
NewSel = Sel+(DosMemBlock->SelCount*8);
|
|
NewSelCount = SelCount - DosMemBlock->SelCount;
|
|
|
|
//
|
|
// First check to see if the selectors are really all free
|
|
//
|
|
for (i=0,TmpSel = NewSel; i < NewSelCount; i++, TmpSel+=8) {
|
|
if (!IS_SELECTOR_FREE(TmpSel)) {
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
goto dpmi_size_error;
|
|
}
|
|
}
|
|
//
|
|
// Now attempt to remove them off the free list
|
|
//
|
|
for (i=0; i < NewSelCount; i++, NewSel+=8) {
|
|
if (!RemoveFreeSelector(NewSel)) {
|
|
// If this happens, we must have a bogus free
|
|
// selector list
|
|
DosError = DOSERR_NOT_ENOUGH_MEMORY;
|
|
goto dpmi_size_error;
|
|
}
|
|
}
|
|
}
|
|
|
|
DpmiSwitchToRealMode();
|
|
|
|
setBX((WORD)ParaSize);
|
|
setES((WORD)DosMemBlock->Address);
|
|
setAX(0x4A00);
|
|
|
|
DPMI_EXEC_INT(0x21);
|
|
|
|
if (getCF()) {
|
|
|
|
// Couldn't resize the memory
|
|
DosError = getAX();
|
|
|
|
// Free selectors, if we got new ones
|
|
if (NewSelCount) {
|
|
for (i = 0; i < NewSelCount; i++, NewSel+=8) {
|
|
FreeSelector(NewSel);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
ULONG Base;
|
|
|
|
//
|
|
// Resized the block. Update the allocation info, and set
|
|
// up the descriptors
|
|
//
|
|
|
|
|
|
if (SelCount < DosMemBlock->SelCount) {
|
|
USHORT OldSel = Sel+SelCount*8;
|
|
USHORT OldSelCount = DosMemBlock->SelCount - SelCount;
|
|
//
|
|
// Count of selectors has shrunk. Free 'em up.
|
|
//
|
|
|
|
for (i = 0; i < OldSelCount; i++, OldSel+=8) {
|
|
FreeSelector(OldSel);
|
|
}
|
|
|
|
}
|
|
|
|
DosMemBlock->Length = (ULONG)ParaSize;
|
|
DosMemBlock->SelCount = SelCount;
|
|
|
|
Base = ((ULONG)DosMemBlock->Address) << 4;
|
|
|
|
SetDescriptorArray(Sel, Base, MemSize);
|
|
DosError = 0;
|
|
|
|
}
|
|
|
|
DpmiSwitchToProtectedMode();
|
|
|
|
break;
|
|
}
|
|
DosMemBlock = DosMemBlock->Next;
|
|
}
|
|
}
|
|
|
|
dpmi_size_error:
|
|
SET_CLIENT_REGS(SaveRegs);
|
|
|
|
if (DosError) {
|
|
setAX(DosError);
|
|
setCF(1);
|
|
} else {
|
|
setCF(0);
|
|
}
|
|
|
|
}
|