mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3240 lines
96 KiB
3240 lines
96 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllvm16.c
|
|
|
|
Abstract:
|
|
|
|
This module implements 32 equivalents of OS/2 V1.21 Memory Management
|
|
API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
|
|
|
|
|
|
Author:
|
|
|
|
Yaron Shamir (YaronS) 12-Apr-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_MEMORY
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2dll.h"
|
|
#include "os2dll16.h"
|
|
|
|
APIRET
|
|
Od2SuspendAllThreads( VOID );
|
|
|
|
APIRET
|
|
Od2ResumeAllThreads( VOID );
|
|
|
|
VOID
|
|
DosExit(
|
|
IN ULONG ExitAction,
|
|
IN ULONG ExitResult
|
|
);
|
|
|
|
APIRET
|
|
DosHoldSignal(
|
|
ULONG fDisable,
|
|
ULONG pstack
|
|
);
|
|
|
|
#if DBG
|
|
// Set the values as appropriate (with NTSD or at compile-time) to see all
|
|
// APIs which allocate/free memory and affect this selector.
|
|
// To disable this feature, leave the variable at 0.
|
|
USHORT Os2DebugSel = 0x0;
|
|
#endif
|
|
|
|
//
|
|
// Masks used to determine the correct action to be taken
|
|
// for DosReallocHuge()
|
|
//
|
|
#define H_NEW_PARTIAL 1
|
|
#define H_CUR_PARTIAL 2
|
|
#define H_SEG_INC 4
|
|
#define H_SEG_DEC 8
|
|
#define H_SAME_SEG_NO_PARTIAL 0
|
|
#define H_SAME_SEG_NEW_PARTIAL H_NEW_PARTIAL
|
|
#define H_SAME_SEG_DEL_PARTIAL H_CUR_PARTIAL
|
|
#define H_SAME_SEG_CHG_PARTIAL (H_NEW_PARTIAL | H_CUR_PARTIAL)
|
|
#define H_INC_SEG_NO_PARTIAL H_SEG_INC
|
|
#define H_INC_SEG_NEW_PARTIAL (H_SEG_INC | H_NEW_PARTIAL)
|
|
#define H_INC_SEG_DEL_PARTIAL (H_SEG_INC | H_CUR_PARTIAL)
|
|
#define H_INC_SEG_CHG_PARTIAL (H_SEG_INC | H_NEW_PARTIAL | H_CUR_PARTIAL)
|
|
#define H_DEC_SEG_NO_PARTIAL H_SEG_DEC
|
|
#define H_DEC_SEG_NEW_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL)
|
|
#define H_DEC_SEG_DEL_PARTIAL (H_SEG_DEC | H_CUR_PARTIAL)
|
|
#define H_DEC_SEG_CHG_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL | H_CUR_PARTIAL)
|
|
|
|
|
|
#define LDT_NUMBER_OF_PRIVATE_SEGMENTS (0x2000 - LDT_DISJOINT_ENTRIES)
|
|
//
|
|
// segment 0 is illegal in Os/2, skip it.
|
|
//
|
|
PVOID Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
|
|
|
|
static PVOID ldtBMHeap;
|
|
static RTL_BITMAP ldtBitMapHeader;
|
|
//
|
|
// The ResourceUsage[] array is used to keep track of the number of times
|
|
// A segment containing a resource was allocated using the DosGetResource()
|
|
// and DosGetResource2() APIs. This prevents DosFreeSeg() and DosFreeResource()
|
|
// from freeing the segment until the use count becomes 0.
|
|
//
|
|
CHAR ResourceUsage[LDT_DISJOINT_ENTRIES];
|
|
|
|
BOOLEAN
|
|
ldtCreateSelBitmap(
|
|
)
|
|
{
|
|
|
|
ldtBMHeap = RtlAllocateHeap(Od2Heap, 0, (LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8);
|
|
if (ldtBMHeap == NULL) {
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
ldtBMHeap = RtlCreateHeap( HEAP_GROWABLE,
|
|
NULL,
|
|
(LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8, // 8 bits per byte
|
|
(LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8, // 8 bits per byte
|
|
NULL,
|
|
0
|
|
);
|
|
if (ldtBMHeap == NULL) {
|
|
return(FALSE);
|
|
}
|
|
*/
|
|
RtlInitializeBitMap(&ldtBitMapHeader ,ldtBMHeap, LDT_NUMBER_OF_PRIVATE_SEGMENTS);
|
|
RtlClearAllBits(&ldtBitMapHeader);
|
|
RtlSetBits (&ldtBitMapHeader,0,1); // selector 0 never freed.
|
|
return(TRUE);
|
|
}
|
|
|
|
ULONG
|
|
ldtAllocateSelectors(
|
|
ULONG NumberOfSel,
|
|
ULONG Index
|
|
)
|
|
{
|
|
ULONG LocalIndex = Index;
|
|
if (Index > (LDT_NUMBER_OF_PRIVATE_SEGMENTS - NumberOfSel)) {
|
|
#if DBG
|
|
DbgPrint("Os2: ldt bitmap overflow\n");
|
|
#endif
|
|
LocalIndex = 1;
|
|
}
|
|
if((RtlFindClearBitsAndSet( &ldtBitMapHeader,
|
|
NumberOfSel,
|
|
LocalIndex
|
|
)) == 0xffffffff) {
|
|
//
|
|
// Not found above Local Index
|
|
//
|
|
if (LocalIndex == 1){
|
|
//
|
|
// No slot available
|
|
//
|
|
return(0xffffffff);
|
|
}
|
|
else {
|
|
//
|
|
// try to search from ground up
|
|
//
|
|
return(RtlFindClearBitsAndSet( &ldtBitMapHeader,
|
|
NumberOfSel,
|
|
LocalIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ldtFreeSelectors(
|
|
ULONG Index,
|
|
ULONG NumberOfSel
|
|
)
|
|
{
|
|
if (Index > (LDT_NUMBER_OF_PRIVATE_SEGMENTS - NumberOfSel)) {
|
|
return;
|
|
}
|
|
RtlClearBits( &ldtBitMapHeader,
|
|
Index,
|
|
NumberOfSel
|
|
);
|
|
}
|
|
|
|
//
|
|
// A utility routine to verify a segment for write.
|
|
// returns:
|
|
// 1 if segment reachable
|
|
// 0 if segment not reachable
|
|
// Implemented using inline i386 VERW instruction
|
|
//
|
|
|
|
extern int _cdecl IsLegalSelector(unsigned short aSelector);
|
|
|
|
//
|
|
// A utility routine to encapsulate the NT support for LDT mgmt
|
|
//
|
|
NTSTATUS
|
|
Nt386GetDescriptorLDT
|
|
(
|
|
HANDLE LDT,
|
|
ULONG Sel,
|
|
I386DESCRIPTOR *Desc
|
|
)
|
|
{
|
|
/* Descriptor definition */
|
|
|
|
struct desctab {
|
|
USHORT d_limit; /* Segment limit */
|
|
USHORT d_loaddr; /* Low word of physical address */
|
|
UCHAR d_hiaddr; /* High byte of physical address */
|
|
UCHAR d_access; /* Access byte */
|
|
UCHAR d_attr; /* Attributes/extended limit */
|
|
UCHAR d_extaddr; /* Extended physical address byte */
|
|
} *LDTDesc;
|
|
ULONG TmpAddress;
|
|
PROCESS_LDT_INFORMATION LdtInformation;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(LDT);
|
|
|
|
//
|
|
// adjust LDTDesc by the LDT base and the index of this selector
|
|
//
|
|
|
|
LdtInformation.Length = sizeof(LDT_ENTRY);
|
|
LdtInformation.Start = Sel & 0xfffffff8;
|
|
LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
|
|
|
|
Status = NtQueryInformationProcess( NtCurrentProcess(),
|
|
ProcessLdtInformation,
|
|
&LdtInformation,
|
|
sizeof(PROCESS_LDT_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("Nt386GetDescriptorLDT: Invalid request\n");
|
|
#endif
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Desc->Limit = (ULONG)(LDTDesc->d_limit);
|
|
TmpAddress = ((((ULONG)(LDTDesc->d_extaddr)) << 8) +
|
|
((ULONG)(LDTDesc->d_hiaddr))) << 16;
|
|
TmpAddress += ((ULONG)(LDTDesc->d_loaddr));
|
|
Desc->BaseAddress = TmpAddress;
|
|
if (TmpAddress == 0) {
|
|
#if DBG
|
|
DbgPrint ("Nt386GetDescriptorLDT: Invalid Descriptor for Sel %x\n", Sel );
|
|
#endif
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Nt386SetDescriptorLDT
|
|
(
|
|
HANDLE LDT,
|
|
ULONG Sel,
|
|
I386DESCRIPTOR Desc
|
|
)
|
|
{
|
|
/* Descriptor definition */
|
|
|
|
struct desctab {
|
|
USHORT d_limit; /* Segment limit */
|
|
USHORT d_loaddr; /* Low word of physical address */
|
|
UCHAR d_hiaddr; /* High byte of physical address */
|
|
UCHAR d_access; /* Access byte */
|
|
UCHAR d_attr; /* Attributes/extended limit */
|
|
UCHAR d_extaddr; /* Extended physical address byte */
|
|
} *LDTDesc;
|
|
PULONG tmp;
|
|
PROCESS_LDT_INFORMATION LdtInformation;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(LDT);
|
|
|
|
|
|
LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
|
|
tmp = (PULONG)(LDTDesc);
|
|
//
|
|
// zero the descriptor
|
|
//
|
|
*tmp++ = 0;
|
|
*tmp = 0;
|
|
|
|
switch (Desc.Type) {
|
|
|
|
case INVALID:
|
|
break;
|
|
|
|
case READ_WRITE_DATA:
|
|
LDTDesc->d_access = 0xf3; // read/write, present, ring 3
|
|
LDTDesc->d_limit = (USHORT)(Desc.Limit);
|
|
LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
|
|
LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
|
|
LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
|
|
break;
|
|
|
|
case READ_DATA:
|
|
LDTDesc->d_access = 0xf1; // read only, present, ring 3
|
|
LDTDesc->d_limit = (USHORT)(Desc.Limit);
|
|
LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
|
|
LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
|
|
LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
|
|
break;
|
|
|
|
case EXECUTE_READ_CODE:
|
|
LDTDesc->d_access = 0xfb; // read/exec, present, ring 3
|
|
LDTDesc->d_limit = (USHORT)(Desc.Limit);
|
|
LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
|
|
LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
|
|
LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
|
|
break;
|
|
case EXECUTE_CODE:
|
|
default:
|
|
{
|
|
#if DBG
|
|
DbgPrint ("Nt386SetDescriptorLDT: Invalid type request\n");
|
|
#endif
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
//
|
|
// adjust LDTDesc by the LDT base and the index of this selector
|
|
//
|
|
|
|
LdtInformation.Length = sizeof(LDT_ENTRY);
|
|
LdtInformation.Start = Sel & 0xfffffff8;
|
|
Status = NtSetInformationProcess( NtCurrentProcess(),
|
|
ProcessLdtInformation,
|
|
&LdtInformation,
|
|
sizeof(PROCESS_LDT_INFORMATION)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("Nt386SetDescriptorLDT: Invalid request\n");
|
|
#endif
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
#if PMNT
|
|
|
|
APIRET
|
|
PMNTAllocLDTSelector(
|
|
ULONG BaseAddress,
|
|
ULONG cbSize,
|
|
OUT PSEL pSel
|
|
)
|
|
/*++
|
|
|
|
Parameters:
|
|
|
|
BaseAddress - 32-bit virtual address for which to create an LDT entry.
|
|
|
|
cbSize - Size of segment for which an LDT entry is required.
|
|
|
|
pSel - Variable for storing the resulting selector.
|
|
|
|
--*/
|
|
{
|
|
I386DESCRIPTOR Desc;
|
|
NTSTATUS Status;
|
|
SEL Sel;
|
|
|
|
//
|
|
// Set A Data segment selector in the LDT
|
|
//
|
|
|
|
Desc.BaseAddress = BaseAddress;
|
|
Desc.Limit = cbSize-1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
|
|
//
|
|
// Apply tiling scheme
|
|
//
|
|
Sel = (SEL)FLATTOSEL((Desc.BaseAddress));
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
Sel,
|
|
Desc);
|
|
if (!NT_SUCCESS( Status ))
|
|
{
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
*pSel = (USHORT) Sel;
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
#endif /* PMNT */
|
|
|
|
APIRET
|
|
DosAllocSeg(
|
|
IN USHORT cbSize,
|
|
OUT PSEL pSel,
|
|
IN USHORT fsAlloc
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc;
|
|
ULONG Size, flags;
|
|
ULONG Index;
|
|
BOOLEAN PrivateSeg;
|
|
|
|
//
|
|
// probe pSel pointer.
|
|
//
|
|
|
|
try {
|
|
*pSel = 0;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
//
|
|
// check validity of fsAlloc
|
|
//
|
|
if (fsAlloc & ~(SEG_GIVEABLE | SEG_GETTABLE | SEG_DISCARDABLE | SEG_SIZEABLE)) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// OS2 1.X treats a 0 size request as (64k -1)
|
|
//
|
|
if (cbSize == 0)
|
|
Size = _64K;
|
|
else
|
|
Size = cbSize;
|
|
|
|
//
|
|
// First we reserve 64K, then we commit the size
|
|
// requested, rounded up to page granularity, by DosSetMem.
|
|
//
|
|
if ((fsAlloc == SEG_NONSHARED) || (fsAlloc == SEG_DISCARDABLE)) {
|
|
PrivateSeg = TRUE;
|
|
Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
|
|
Index = ldtAllocateSelectors(
|
|
1, // NumberOfSel
|
|
Index // StartOfMark
|
|
);
|
|
|
|
if (Index == 0xffffffff){
|
|
//
|
|
// not found - no memory
|
|
//
|
|
Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Od2MemoryAllocationBase = BaseAddress = (PVOID)((Index * _64K) + BASE_TILE);
|
|
|
|
flags = fALLOC - PAG_GUARD;
|
|
rc = DosAllocMem(
|
|
&BaseAddress,
|
|
_64K,
|
|
(flags - PAG_COMMIT));
|
|
}
|
|
else {
|
|
PrivateSeg = FALSE;
|
|
//
|
|
// we ignore discardable, and make it givable and gettable
|
|
// (see DosAllocSharedMem).
|
|
//
|
|
|
|
// we use page execute to mark that the data segments is
|
|
// sizeable
|
|
|
|
if (fsAlloc & SEG_SIZEABLE)
|
|
flags = fALLOCSHR - PAG_GUARD;
|
|
else
|
|
flags = fALLOCSHR - PAG_GUARD - PAG_EXECUTE;
|
|
|
|
rc = DosAllocSharedMem(
|
|
&BaseAddress,
|
|
NULL,
|
|
Size, // The real size of the segment will be used to
|
|
// create proper LDT entry. In any case 64K will
|
|
// be reserved.
|
|
(flags - PAG_COMMIT),
|
|
TRUE // Create LDT entry of shared, non huge, unnamed
|
|
// segment.
|
|
);
|
|
}
|
|
|
|
if (rc != NO_ERROR) {
|
|
if (PrivateSeg) {
|
|
ldtFreeSelectors(Index, 1);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
rc = DosSetMem(
|
|
BaseAddress,
|
|
Size,
|
|
flags & ~(OBJ_GETTABLE | OBJ_GIVEABLE));
|
|
|
|
if (rc != NO_ERROR){
|
|
BOOLEAN RemoveLDTEntry = TRUE;
|
|
|
|
DosFreeMem(BaseAddress, &RemoveLDTEntry);
|
|
if (PrivateSeg) {
|
|
ldtFreeSelectors(Index, 1);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
if (PrivateSeg) {
|
|
|
|
SEL Sel;
|
|
I386DESCRIPTOR Desc;
|
|
//
|
|
// Set A Data segment selector in the LDT
|
|
//
|
|
Desc.BaseAddress = (ULONG) BaseAddress;
|
|
Desc.Limit = cbSize-1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
|
|
//
|
|
// Apply tiling scheme
|
|
//
|
|
Sel = (SEL)FLATTOSEL((Desc.BaseAddress));
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
Sel,
|
|
Desc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
BOOLEAN RemoveLDTEntry = FALSE;
|
|
|
|
DosFreeMem(BaseAddress, &RemoveLDTEntry);
|
|
ldtFreeSelectors(Index, 1);
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
|
|
*pSel = FLATTOSEL(BaseAddress);
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (*pSel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosAllocSeg returning sel=%x (size=%x, fsAlloc=%x)\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
*pSel,
|
|
cbSize,
|
|
fsAlloc);
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosFreeSeg(
|
|
IN SEL sel
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc;
|
|
I386DESCRIPTOR Desc;
|
|
PHUGE_SEG_RECORD pHuge, pHugePrev;
|
|
ULONG i;
|
|
SEL Sel;
|
|
USHORT SelIndex;
|
|
ULONG ActualSegs = 1;
|
|
BOOLEAN RemoveLDTEntry = TRUE; // Initially ask to remove LDT entry
|
|
BOOLEAN ResourceFree = FALSE; // Initially consider that the segment
|
|
// isn't a resource
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// check for an obviously invalid selector
|
|
//
|
|
|
|
if (((sel & 0x7) != 0x7) ||
|
|
((sel & 0xfff8) == 0)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Invalid selector: %x\n", sel);
|
|
}
|
|
#endif
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
//
|
|
// Calculate base address (tiling)
|
|
//
|
|
BaseAddress = SELTOFLAT(sel);
|
|
|
|
|
|
//
|
|
// Now Free Descriptors:
|
|
// o lookup for a huge segment
|
|
// if not huge - free one segment
|
|
// else
|
|
// if in the middle - return error.
|
|
// free all segments
|
|
// free huge record and unlink
|
|
//
|
|
Desc.Type = INVALID;
|
|
|
|
//
|
|
// Make sure other threads don't muck with HugeSeg list
|
|
//
|
|
AcquireTaskLock();
|
|
|
|
//
|
|
// Check if we are freeing a resource
|
|
//
|
|
SelIndex = (USHORT)sel >> 3;
|
|
if ((SelIndex >= LDT_NUMBER_OF_PRIVATE_SEGMENTS) &&
|
|
(ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS] > 0)
|
|
) {
|
|
ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS]--;
|
|
if (ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS] > 0) {
|
|
ReleaseTaskLock();
|
|
return(NO_ERROR);
|
|
}
|
|
ResourceFree = TRUE; // This segment is resource and it will be freed
|
|
// For resources critical section must be longer
|
|
// to avoid incosistancy with ResourceUsage array
|
|
}
|
|
for (pHuge = pHugeSegHead;
|
|
pHuge != NULL;
|
|
pHugePrev = pHuge, pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
|
|
if (pHuge->BaseSelector == (ULONG)(sel)) {
|
|
ActualSegs = pHuge->cNumSeg;
|
|
if (pHuge->PartialSeg != 0) {
|
|
ActualSegs++;
|
|
}
|
|
for (i = 0, Sel = sel; i < ActualSegs; i++, Sel += 8) {
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
Sel,
|
|
Desc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosFreeSeg fails to set descriptor\n");
|
|
#endif
|
|
ReleaseTaskLock();
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
|
|
}
|
|
#endif
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
}
|
|
//
|
|
// After descriptors are freed,
|
|
// Unlink and free Huge Seg structure.
|
|
//
|
|
if (pHuge == pHugeSegHead)
|
|
//
|
|
// Get rid of first on the list
|
|
//
|
|
pHugeSegHead = (PHUGE_SEG_RECORD)(pHuge->Next);
|
|
else
|
|
pHugePrev->Next = pHuge->Next;
|
|
RtlFreeHeap(Od2Heap, 0,pHuge);
|
|
RemoveLDTEntry = FALSE; // LDT entries were removed for huge
|
|
// segments. Sign that they must not
|
|
// be removed any more.
|
|
break;
|
|
}
|
|
//
|
|
// Look for a selector in the middle of a DosHugeAlloc
|
|
// Alloction
|
|
//
|
|
else if ( (sel > (SEL)(pHuge->BaseSelector)) &&
|
|
(sel < (SEL)(pHuge->BaseSelector + 8 * ActualSegs)) ) {
|
|
|
|
ReleaseTaskLock();
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning INVALID_ADDRESS\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
|
|
if (!ResourceFree)
|
|
ReleaseTaskLock(); // For resources, critical section will be longer.
|
|
//
|
|
// Free the memory
|
|
//
|
|
rc = DosFreeMem (BaseAddress, &RemoveLDTEntry); // Free memory and LDT entry
|
|
// if it is needed
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_INVALID_ADDRESS) {
|
|
|
|
//
|
|
// try to see if this is a CSAlias (see CreateCsAlias)
|
|
// in this case, we unmap the view
|
|
//
|
|
|
|
POS21X_CSALIAS pCSAlias, pCSAliasPrev;
|
|
POS21X_CS pCS, pCSPrev;
|
|
|
|
if (!ResourceFree)
|
|
AcquireTaskLock();
|
|
if (Od2CSAliasListHead != 0) {
|
|
for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
|
|
pCSAlias != NULL;
|
|
pCSAliasPrev = pCSAlias, pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)
|
|
) {
|
|
if (pCSAlias->selDS == sel) {
|
|
//
|
|
// Trying to free the base DS, to which the aliases
|
|
// were mapped
|
|
//
|
|
if (pCSAlias->pCSList == NULL) {
|
|
//
|
|
// No aliases left, close section and free everything
|
|
//
|
|
NtClose(pCSAlias->SectionHandle);
|
|
if (pCSAlias == (POS21X_CSALIAS)Od2CSAliasListHead) {
|
|
|
|
//
|
|
// Get rid of first on the list
|
|
//
|
|
Od2CSAliasListHead = pCSAlias->Next;
|
|
}
|
|
else {
|
|
pCSAliasPrev->Next = pCSAlias->Next;
|
|
}
|
|
RtlFreeHeap(Od2Heap, 0, pCSAlias);
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Freeing the DS of a CSAlias, with the section. selDS %x \n",
|
|
sel);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
//
|
|
// The DS base of an alias section was freed, but some CSs
|
|
// exist (legal in OS/2). Change the selDS field
|
|
// to NULL, so subsequent CreateCSAlias will fail
|
|
// to find it
|
|
//
|
|
pCSAlias->selDS = (SEL)NULL;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Freeing the DS of a CSAlias. code segemnt are still around selDS %x \n",
|
|
sel);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
else {
|
|
//
|
|
// walk thru the CS aliases of this section, see if
|
|
// we are freeing one of the code segments
|
|
//
|
|
|
|
BOOLEAN CSFound;
|
|
|
|
for ( CSFound = FALSE, pCS = (POS21X_CS) pCSAlias->pCSList;
|
|
pCS != NULL ;
|
|
pCSPrev = pCS, pCS = (POS21X_CS)pCS->Next) {
|
|
|
|
if (pCS->selCS == sel) {
|
|
//
|
|
// found it - unlink from CSList and free
|
|
//
|
|
if (pCS == pCSAlias->pCSList) {
|
|
|
|
//
|
|
// Get rid of first on the list
|
|
//
|
|
pCSAlias->pCSList = (POS21X_CS)(pCS->Next);
|
|
if (pCSAlias->pCSList == NULL) {
|
|
//
|
|
// just removed the last one,
|
|
// see if the DS is still alive, and if
|
|
// not - remove the structure
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Freed the last CSAlias. selDS is %x. selCS is %x \n",
|
|
pCSAlias->selDS, sel);
|
|
}
|
|
#endif
|
|
if (pCSAlias->selDS == (SEL)NULL) {
|
|
NtClose(pCSAlias->SectionHandle);
|
|
RtlFreeHeap(Od2Heap, 0, pCSAlias);
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Freed Section and heap for CSAlias last CSAlias. selCS is %x\n",
|
|
sel);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
pCSPrev->Next = pCS->Next;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Freeing a CSAlias. selDS is %x. selCS is %x\n",
|
|
pCSAlias->selDS, sel);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CSFound = TRUE;
|
|
RtlFreeHeap(Od2Heap, 0, pCS);
|
|
break;
|
|
}
|
|
}
|
|
if (CSFound) {
|
|
//
|
|
// break out of the lookup for csalias
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!ResourceFree)
|
|
ReleaseTaskLock();
|
|
|
|
Status = NtUnmapViewOfSection(NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosFreeSeg: Can't UnmapView, Status=%lx\n", Status);
|
|
}
|
|
#endif
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning INVALID_ADDRESS\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
if (ResourceFree)
|
|
ReleaseTaskLock();
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel,
|
|
rc);
|
|
}
|
|
#endif
|
|
if (ResourceFree)
|
|
ReleaseTaskLock();
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
if (RemoveLDTEntry) {
|
|
|
|
// LDT entry wasn't removed yet. It is TRUE for private segments
|
|
// and for the named shared segments and for aliases.
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
sel,
|
|
Desc);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosFreeSeg fails to set descriptor\n");
|
|
#endif
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
if (ResourceFree)
|
|
ReleaseTaskLock();
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
}
|
|
|
|
if (ResourceFree)
|
|
ReleaseTaskLock();
|
|
|
|
ldtFreeSelectors(
|
|
(sel >> 3), // Index,
|
|
ActualSegs // Numofbits
|
|
);
|
|
|
|
//
|
|
// Update the base segment for allocation of segments
|
|
//
|
|
if (Od2MemoryAllocationBase > BaseAddress)
|
|
Od2MemoryAllocationBase = BaseAddress;
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosGetSeg(
|
|
IN SEL InSel
|
|
)
|
|
{
|
|
OS2_API_MSG m;
|
|
POS2_GETSEG_MSG a = &m.u.DosGetSeg;
|
|
|
|
a->Selector = InSel;
|
|
Od2CallSubsystem( &m, NULL, Os2GetSeg, sizeof( *a ) );
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (InSel == Os2DebugSel))
|
|
{
|
|
if (m.ReturnedErrorValue == NO_ERROR)
|
|
DbgPrint("[%x,%x] DosGetSeg called on sel=%x (successfull)\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
InSel);
|
|
else
|
|
DbgPrint("[%x,%x] DosGetSeg called on sel=%x, rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
InSel,
|
|
m.ReturnedErrorValue);
|
|
}
|
|
#endif
|
|
|
|
return(m.ReturnedErrorValue);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosGiveSeg(
|
|
IN SEL sel,
|
|
IN PID pid,
|
|
OUT PSEL pSelRecipient
|
|
)
|
|
{
|
|
OS2_API_MSG m;
|
|
POS2_GIVESEG_MSG a = &m.u.DosGiveSeg;
|
|
|
|
try {
|
|
*pSelRecipient = 0;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
*pSelRecipient = sel;
|
|
|
|
a->Selector = sel;
|
|
a->TargetPid = pid;
|
|
|
|
Od2CallSubsystem( &m, NULL, Os2GiveSeg, sizeof( *a ) );
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
if (m.ReturnedErrorValue == NO_ERROR)
|
|
DbgPrint("[%x,%x] DosGetSeg called on sel=%x (successfull)\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
else
|
|
DbgPrint("[%x,%x] DosGetSeg called on sel=%x, rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel,
|
|
m.ReturnedErrorValue);
|
|
}
|
|
#endif
|
|
|
|
return(m.ReturnedErrorValue);
|
|
}
|
|
|
|
APIRET ResizeSharedMemory(
|
|
HANDLE ProcessHandle,
|
|
PVOID AllocFreeBaseAddress, // start address of new allocation / free
|
|
ULONG Index,
|
|
ULONG CurrentSize, // ldt limit rounded to pages
|
|
USHORT NewLdtLimit, // New segment size in bytes
|
|
ULONG NewRegionSize, // New segment size rounded to pages
|
|
ULONG Flags // Flags of new allocated memory
|
|
)
|
|
{
|
|
PVOID TmpAllocFreeBaseAddress;
|
|
PROCESS_LDT_INFORMATION LdtInfo;
|
|
struct desctab {
|
|
USHORT d_limit; /* Segment limit */
|
|
USHORT d_loaddr; /* Low word of physical address */
|
|
UCHAR d_hiaddr; /* High byte of physical address */
|
|
UCHAR d_access; /* Access byte */
|
|
UCHAR d_attr; /* Attributes/extended limit */
|
|
UCHAR d_extaddr; /* Extended physical address byte */
|
|
} *LDTDesc;
|
|
ULONG RegionSize;
|
|
NTSTATUS Status;
|
|
APIRET rc;
|
|
rc = NO_ERROR;
|
|
// acording to the new size allocate / free memory
|
|
|
|
// get current LDT entry
|
|
LdtInfo.Length = sizeof(LDT_ENTRY);
|
|
LdtInfo.Start = Index & 0xfffffff8;
|
|
LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
|
|
Status = NtQueryInformationProcess(
|
|
ProcessHandle,
|
|
ProcessLdtInformation,
|
|
&LdtInfo,
|
|
sizeof(PROCESS_LDT_INFORMATION),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("Os2DosReallocSharedMem NtQueryInformationProcess failed. \n");
|
|
#endif
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
if ((LDTDesc->d_access & 0x80) == 0) {
|
|
return(ERROR_INVALID_SEGMENT_NUMBER); // This is an internal error code
|
|
// passed to the caller of this
|
|
// procedure to notify that the
|
|
// segment was not updated since
|
|
// it was not in use.
|
|
}
|
|
|
|
|
|
// Update The Segment Size in LDT
|
|
|
|
if (LDTDesc->d_limit != NewLdtLimit) {
|
|
LDTDesc->d_limit = NewLdtLimit;
|
|
LdtInfo.Length = sizeof(LDT_ENTRY);
|
|
LdtInfo.Start = Index & 0xfffffff8;
|
|
Status = NtSetInformationProcess(
|
|
ProcessHandle,
|
|
ProcessLdtInformation,
|
|
&LdtInfo,
|
|
sizeof(PROCESS_LDT_INFORMATION)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("Os2DosReallocSharedMem NtSetInformationProcess failed. %lx\n",
|
|
Status);
|
|
#endif
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
return(NO_ERROR);
|
|
|
|
if (CurrentSize < NewRegionSize) {
|
|
// alloc mem
|
|
RegionSize = NewRegionSize - CurrentSize;
|
|
TmpAllocFreeBaseAddress = AllocFreeBaseAddress;
|
|
Status = NtAllocateVirtualMemory(
|
|
ProcessHandle,
|
|
&TmpAllocFreeBaseAddress,
|
|
1,
|
|
&RegionSize,
|
|
MEM_COMMIT,
|
|
Flags
|
|
);
|
|
if (NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)) {
|
|
rc = NO_ERROR;
|
|
}
|
|
else if (Status == STATUS_CONFLICTING_ADDRESSES) {
|
|
|
|
MEMORY_BASIC_INFORMATION MemoryInformation;
|
|
PVOID AllocationBase = (PVOID) ((ULONG)AllocFreeBaseAddress & 0xffff0000);
|
|
PBYTE pSegmentCopy;
|
|
|
|
Status = NtQueryVirtualMemory(
|
|
ProcessHandle,
|
|
(PVOID)((ULONG)AllocationBase + NewRegionSize - 1),
|
|
MemoryBasicInformation,
|
|
&MemoryInformation,
|
|
sizeof( MemoryInformation ),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status) || MemoryInformation.State != MEM_FREE) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail with STATUS_CONFLICTING_ADDRESSES, State=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
MemoryInformation.State
|
|
);
|
|
#endif // DBG
|
|
return (ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
pSegmentCopy = RtlAllocateHeap(Od2Heap, 0, CurrentSize);
|
|
if (pSegmentCopy == NULL) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail to allocate from local heap\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId()
|
|
);
|
|
#endif // DBG
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
Od2SuspendAllThreads();
|
|
|
|
RtlCopyMemory(pSegmentCopy, (PBYTE)AllocationBase, CurrentSize);
|
|
|
|
Status = NtUnmapViewOfSection(
|
|
ProcessHandle,
|
|
AllocationBase
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail on NtUnmapViewOfSection, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status
|
|
);
|
|
ASSERT(FALSE);
|
|
#endif // DBG
|
|
Od2ResumeAllThreads();
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
RtlFreeHeap(Od2Heap, 0, pSegmentCopy);
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
RegionSize = _64K;
|
|
|
|
Status = NtAllocateVirtualMemory(
|
|
ProcessHandle,
|
|
&AllocationBase,
|
|
1,
|
|
&RegionSize,
|
|
MEM_RESERVE,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory (RESERVE), Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status
|
|
);
|
|
ASSERT(FALSE);
|
|
#endif // DBG
|
|
DosExit(EXIT_PROCESS, ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
RegionSize = NewRegionSize;
|
|
|
|
Status = NtAllocateVirtualMemory(
|
|
ProcessHandle,
|
|
&AllocationBase,
|
|
1,
|
|
&RegionSize,
|
|
MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
RtlCopyMemory(AllocationBase, pSegmentCopy, CurrentSize);
|
|
rc = NO_ERROR;
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory (COMMIT), Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status
|
|
);
|
|
#endif // DBG
|
|
DosExit(EXIT_PROCESS, ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Od2ResumeAllThreads();
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
RtlFreeHeap(Od2Heap, 0, pSegmentCopy);
|
|
#if DBG
|
|
IF_OD2_DEBUG( MEMORY ) {
|
|
Status = NtQueryVirtualMemory(
|
|
ProcessHandle,
|
|
AllocationBase,
|
|
MemoryBasicInformation,
|
|
&MemoryInformation,
|
|
sizeof( MemoryInformation ),
|
|
NULL
|
|
);
|
|
DbgPrint("[%d,%d]Reallocation of the private data segment:\n\tBaseAddress=%x\n\tAllocationBase=%x\n\tAllocationProtect=%x\n\tRegionSize=%x\n\tState=%x\n\tProtect=%x\n\tType=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
MemoryInformation.BaseAddress,
|
|
MemoryInformation.AllocationBase,
|
|
MemoryInformation.AllocationProtect,
|
|
MemoryInformation.RegionSize,
|
|
MemoryInformation.State,
|
|
MemoryInformation.Protect,
|
|
MemoryInformation.Type
|
|
);
|
|
Status = NtQueryVirtualMemory(
|
|
ProcessHandle,
|
|
(PVOID)((ULONG)AllocationBase+RegionSize),
|
|
MemoryBasicInformation,
|
|
&MemoryInformation,
|
|
sizeof( MemoryInformation ),
|
|
NULL
|
|
);
|
|
DbgPrint("\n\tBaseAddress=%x\n\tAllocationBase=%x\n\tAllocationProtect=%x\n\tRegionSize=%x\n\tState=%x\n\tProtect=%x\n\tType=%x\n",
|
|
MemoryInformation.BaseAddress,
|
|
MemoryInformation.AllocationBase,
|
|
MemoryInformation.AllocationProtect,
|
|
MemoryInformation.RegionSize,
|
|
MemoryInformation.State,
|
|
MemoryInformation.Protect,
|
|
MemoryInformation.Type
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory with Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status
|
|
);
|
|
#endif // DBG
|
|
rc = ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CurrentSize > NewRegionSize) {
|
|
// freemem
|
|
RegionSize = CurrentSize - NewRegionSize;
|
|
TmpAllocFreeBaseAddress =
|
|
(PVOID)((long)AllocFreeBaseAddress - (long)RegionSize);
|
|
Status = NtFreeVirtualMemory(
|
|
ProcessHandle,
|
|
&TmpAllocFreeBaseAddress,
|
|
&RegionSize,
|
|
MEM_DECOMMIT
|
|
);
|
|
//
|
|
// The STATUS_UNABLE_TO_FREE_VM status is returned when
|
|
// trying to decommit pages of mapped sections. This error
|
|
// should not be reported to the user program.
|
|
//
|
|
if (NT_SUCCESS(Status) ||
|
|
(Status == STATUS_UNABLE_TO_FREE_VM) ||
|
|
(Status == STATUS_UNABLE_TO_DELETE_SECTION))
|
|
rc = NO_ERROR;
|
|
else
|
|
rc = ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
APIRET
|
|
DosReallocSeg(
|
|
IN USHORT cbNewSize,
|
|
IN SEL sel
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc = NO_ERROR;
|
|
ULONG Size, CurrentSize;
|
|
I386DESCRIPTOR Desc;
|
|
MEMORY_BASIC_INFORMATION MemoryInformation;
|
|
OS2_API_MSG m;
|
|
POS2_REALLOCSHAREDMEM_MSG a = &m.u.ReallocSharedMem;
|
|
ULONG Index;
|
|
POS21X_CSALIAS pCSAlias;
|
|
BOOLEAN SelIsCSADS;
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, new size=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel,
|
|
cbNewSize);
|
|
}
|
|
#endif
|
|
//
|
|
// OS2 1.X treats a 0 size request as (64k -1)
|
|
//
|
|
if (cbNewSize == 0)
|
|
Size = _64K;
|
|
else
|
|
Size = ROUND_UP_TO_PAGES(cbNewSize);
|
|
|
|
|
|
if (!IsLegalSelector(sel)){
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning ACCES_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
//
|
|
// Calculate base address (tiling)
|
|
//
|
|
BaseAddress = SELTOFLAT(sel);
|
|
|
|
//
|
|
// Get the current LDT setting
|
|
//
|
|
Status = Nt386GetDescriptorLDT (
|
|
NULL,
|
|
sel,
|
|
&Desc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosReallocSeg fails to get descriptor info\n");
|
|
#endif
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("DosReallocSeg called on sel=%x, returning INVALID_PARAMETER\n",
|
|
sel);
|
|
}
|
|
#endif
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
Status = NtQueryVirtualMemory(
|
|
NtCurrentProcess(),
|
|
BaseAddress,
|
|
MemoryBasicInformation,
|
|
&MemoryInformation,
|
|
sizeof( MemoryInformation ),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosReallocSeg fails to QueryVirtualMemory\n");
|
|
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning INVALID_PARAMETER\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
CurrentSize = ROUND_UP_TO_PAGES(Desc.Limit + 1);
|
|
|
|
// Check if this is a Data Segment of a CSAlias Only for "Pseodo shared
|
|
// READ/WRITE Data Segments
|
|
// This is done since when creating a CSAlias we change the DS page
|
|
// protection from PAGE_EXECUTE_WRITE_COPY TO PAGE_READ_WRITE since it is
|
|
// mapped tweice (once to the DS and once to the CS)
|
|
|
|
SelIsCSADS = FALSE;
|
|
if (MemoryInformation.AllocationProtect == PAGE_READWRITE) {
|
|
AcquireTaskLock();
|
|
if (Od2CSAliasListHead != 0) {
|
|
for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
|
|
pCSAlias != NULL;
|
|
pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)) {
|
|
if (pCSAlias->selDS == sel) {
|
|
SelIsCSADS = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ReleaseTaskLock();
|
|
}
|
|
|
|
if ((sel < FIRST_SHARED_SELECTOR) ||
|
|
(MemoryInformation.AllocationProtect == PAGE_EXECUTE_WRITECOPY) ||
|
|
SelIsCSADS ||
|
|
(MemoryInformation.Type == MEM_PRIVATE))
|
|
{ // This is a non shared segment
|
|
|
|
Index = FLATTOSEL(BaseAddress);
|
|
|
|
rc = ResizeSharedMemory(
|
|
NtCurrentProcess(),
|
|
(PVOID)(((ULONG)BaseAddress)+CurrentSize),
|
|
Index,
|
|
CurrentSize,
|
|
(USHORT)(cbNewSize-1),
|
|
Size,
|
|
MemoryInformation.AllocationProtect
|
|
);
|
|
}
|
|
else
|
|
{ // this is a shared segment
|
|
|
|
a->BaseAddress = (PVOID) BaseAddress;
|
|
a->NewRegionSize = Size;
|
|
a->AllocFreeBaseAddress = (PVOID)(((ULONG)BaseAddress)+CurrentSize);
|
|
a->NewLdtLimit = cbNewSize-1;
|
|
a->Flags = MemoryInformation.AllocationProtect;
|
|
a->CurrentSize = CurrentSize;
|
|
if ( Desc.Limit <= (ULONG)(cbNewSize-1)) {
|
|
|
|
Od2CallSubsystem( &m, NULL, Os2ReallocSharedMem, sizeof( *a ) );
|
|
rc = m.ReturnedErrorValue ;
|
|
}
|
|
else {
|
|
switch (MemoryInformation.AllocationProtect) {
|
|
case PAGE_EXECUTE_READWRITE :
|
|
|
|
// if ( Size < CurrentSize ) {
|
|
Od2CallSubsystem( &m, NULL,
|
|
Os2ReallocSharedMem, sizeof( *a ) );
|
|
rc = m.ReturnedErrorValue ;
|
|
// }
|
|
break;
|
|
case PAGE_READONLY :
|
|
case PAGE_READWRITE :
|
|
case PAGE_WRITECOPY :
|
|
case PAGE_EXECUTE :
|
|
case PAGE_EXECUTE_READ :
|
|
rc = ERROR_ACCESS_DENIED;
|
|
break;
|
|
default:
|
|
rc = ERROR_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel) && (rc != NO_ERROR))
|
|
{
|
|
DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel, rc);
|
|
}
|
|
#endif
|
|
|
|
return (rc);
|
|
}
|
|
|
|
APIRET
|
|
DosAllocHuge(
|
|
IN ULONG cSegs,
|
|
IN USHORT cbPartialSeg,
|
|
OUT PSEL pSel,
|
|
IN ULONG cMaxSegs,
|
|
IN USHORT fsAlloc
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc;
|
|
SEL Sel;
|
|
ULONG ReservedSize, flags, CommittedSize, cMax, i;
|
|
I386DESCRIPTOR Desc;
|
|
PHUGE_SEG_RECORD pHuge;
|
|
BOOLEAN PartialSeg = FALSE;
|
|
ULONG Index;
|
|
OS2_API_MSG m;
|
|
POS2_MARKSHAREDMEMASHUGE_MSG a = &m.u.MarkSharedMemAsHuge;
|
|
BOOLEAN HugeSegIsShared = FALSE;
|
|
BOOLEAN HugeSegIsSizeable = FALSE;
|
|
|
|
//
|
|
// probe pSel pointer.
|
|
//
|
|
|
|
try {
|
|
*pSel = 0;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
//
|
|
// calculate how many segments to actually allocate
|
|
//
|
|
if (cbPartialSeg) {
|
|
PartialSeg = TRUE;
|
|
}
|
|
|
|
//
|
|
// cMaxSegs==0 means it can't grow
|
|
//
|
|
if (cMaxSegs == 0) {
|
|
cMax = cSegs;
|
|
if (PartialSeg) {
|
|
cMax++;
|
|
}
|
|
}
|
|
else {
|
|
cMax = cMaxSegs;
|
|
}
|
|
|
|
//
|
|
// check the parameters
|
|
//
|
|
if (cSegs == 0 && !PartialSeg) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
if ((cSegs > cMax) || ((cSegs == cMax) && PartialSeg)) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
if (fsAlloc & ~(SEG_GIVEABLE | SEG_GETTABLE | SEG_DISCARDABLE | SEG_SIZEABLE)) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
ReservedSize = cMax * _64K;
|
|
|
|
CommittedSize = cSegs * _64K + cbPartialSeg;
|
|
|
|
pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
|
|
if (pHuge == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
|
|
Index = ldtAllocateSelectors(
|
|
cMax, // NumberOfSel
|
|
Index // StartOfMark
|
|
);
|
|
|
|
if (Index == 0xffffffff){
|
|
//
|
|
// not found - no memory
|
|
//
|
|
Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
|
|
RtlFreeHeap(Od2Heap, 0, pHuge);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
BaseAddress = Od2MemoryAllocationBase = (PVOID)((Index * _64K) + BASE_TILE);
|
|
//
|
|
// First we reserve (64K gran), then we commit the size
|
|
// requested, rounded up to page granularity, by DosSetMem.
|
|
//
|
|
|
|
if ((fsAlloc == SEG_NONSHARED) || (fsAlloc == SEG_DISCARDABLE)) {
|
|
flags = fALLOC - PAG_GUARD;
|
|
rc = DosAllocMem(
|
|
&BaseAddress,
|
|
ReservedSize,
|
|
(flags - PAG_COMMIT));
|
|
}
|
|
else {
|
|
HugeSegIsShared = TRUE;
|
|
//
|
|
// we ignore discardable, and make it givable and gettable
|
|
// (see DosAllocSharedMem).
|
|
//
|
|
flags = fALLOCSHR - (PAG_GUARD | OBJ_GETTABLE | OBJ_GIVEABLE);
|
|
|
|
// we use page execute to mark that the data segments is
|
|
// sizeable
|
|
|
|
if ((fsAlloc & SEG_SIZEABLE) == 0) {
|
|
flags &= ~PAG_EXECUTE;
|
|
}
|
|
else {
|
|
HugeSegIsSizeable = TRUE;
|
|
}
|
|
|
|
rc = DosAllocSharedMem(
|
|
&BaseAddress,
|
|
NULL,
|
|
ReservedSize,
|
|
((flags - PAG_COMMIT) | OBJ_GETTABLE | OBJ_GIVEABLE),
|
|
FALSE // Don't create LDT entry for huge segments.
|
|
);
|
|
}
|
|
|
|
if (rc != NO_ERROR) {
|
|
ldtFreeSelectors(Index, cMax);
|
|
RtlFreeHeap(Od2Heap, 0, pHuge);
|
|
return (rc);
|
|
}
|
|
|
|
rc = DosSetMem(
|
|
BaseAddress,
|
|
CommittedSize,
|
|
flags);
|
|
|
|
if (rc != NO_ERROR){
|
|
BOOLEAN RemoveLDTEntry = FALSE;
|
|
|
|
DosFreeMem (BaseAddress, &RemoveLDTEntry);
|
|
ldtFreeSelectors(Index, cMax);
|
|
RtlFreeHeap(Od2Heap, 0, pHuge);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Set Data segments in the LDT
|
|
//
|
|
//
|
|
// first do the full 64k segments
|
|
//
|
|
Desc.Limit = _64K - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG) BaseAddress;
|
|
|
|
Sel = (SEL)(FLATTOSEL(Desc.BaseAddress));
|
|
for (i = 0;
|
|
i < cSegs;
|
|
i++, Sel += 8, Desc.BaseAddress += _64K) {
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
Sel,
|
|
Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
|
|
//
|
|
// Do the partial seg
|
|
//
|
|
if (PartialSeg) {
|
|
Desc.Limit = cbPartialSeg - 1;
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
Sel,
|
|
Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
|
|
//
|
|
// Mark at the server the allocated memory as huge memory
|
|
//
|
|
if ((fsAlloc & SEG_GETTABLE) || (fsAlloc & SEG_GIVEABLE)) {
|
|
a->BaseAddress = BaseAddress;
|
|
a->MaxSegments = cMax;
|
|
a->NumOfSegments = cSegs;
|
|
a->SizeOfPartialSeg = cbPartialSeg;
|
|
a->Sizeable = (fsAlloc & SEG_SIZEABLE) ? TRUE : FALSE;
|
|
Od2CallSubsystem( &m, NULL, Oi2MarkSharedMemAsHuge, sizeof( *a ) );
|
|
}
|
|
|
|
//
|
|
// Return the Selector of the allocation base
|
|
//
|
|
|
|
*pSel = FLATTOSEL(((ULONG)BaseAddress));
|
|
|
|
//
|
|
// Now we record that this segment
|
|
// is Huge so we free and realloc accordingly
|
|
//
|
|
AcquireTaskLock();
|
|
pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
|
|
pHuge->MaxNumSeg = cMax;
|
|
pHuge->BaseSelector = *pSel;
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
pHuge->fShared = HugeSegIsShared;
|
|
pHuge->fSizeable = HugeSegIsSizeable;
|
|
|
|
pHugeSegHead = pHuge;
|
|
ReleaseTaskLock();
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosReallocHuge(
|
|
IN USHORT cSegs,
|
|
IN USHORT cbPartialSeg,
|
|
IN SEL sel
|
|
)
|
|
{
|
|
OS2_API_MSG m;
|
|
POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
|
|
POS2_REALLOCSHAREDHUGE_MSG b = &m.u.ReallocSharedHuge;
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc;
|
|
SEL Sel = 0;
|
|
ULONG CommitSize;
|
|
ULONG DecommitSize;
|
|
I386DESCRIPTOR Desc;
|
|
PHUGE_SEG_RECORD pHuge;
|
|
ULONG i, cNewSegs, cDelSegs, SegSize;
|
|
ULONG Op = 0;
|
|
|
|
//
|
|
// Make sure other threads don't muck with HugeSeg list while we
|
|
// scan it
|
|
//
|
|
AcquireTaskLock();
|
|
//
|
|
// lookup the HugeSeg list to find out if sel is a valid Huge memory
|
|
//
|
|
for (pHuge = pHugeSegHead;
|
|
pHuge != NULL;
|
|
pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
|
|
if (pHuge->BaseSelector == (ULONG)(sel)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pHuge == NULL) {
|
|
|
|
//
|
|
// Did not find a Huge Seg that starts with sel
|
|
//
|
|
//
|
|
// The huge seg may be a shared huge seg which was allocated
|
|
// by another process. Sync with the huge seg info which is
|
|
// kept in the server
|
|
//
|
|
a->BaseAddress = SELTOFLAT(sel);
|
|
Od2CallSubsystem( &m, NULL, Oi2QueryVirtualMemory, sizeof( *a ));
|
|
if (a->SharedMemory && a->IsHuge) {
|
|
pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
|
|
if (pHuge == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
|
|
pHuge->MaxNumSeg = a->MaxSegments;
|
|
pHuge->BaseSelector = sel;
|
|
pHuge->cNumSeg = a->NumOfSegments;
|
|
pHuge->PartialSeg = a->SizeOfPartialSeg;
|
|
pHuge->fShared = TRUE;
|
|
pHuge->fSizeable = a->Sizeable;
|
|
|
|
pHugeSegHead = pHuge;
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: selector is not a base of HugeSeg\n");
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
//
|
|
// found! validate that size is within limits, then
|
|
// alloc or free accordingly
|
|
//
|
|
if (((ULONG)cSegs > pHuge->MaxNumSeg) ||
|
|
(((ULONG)cSegs == pHuge->MaxNumSeg) && (cbPartialSeg != 0))
|
|
) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
//
|
|
// Verify, for shared segments that are reduced in size that the
|
|
// SEG_SIZEABLE flag is set.
|
|
//
|
|
if (pHuge->fShared
|
|
&&
|
|
(((ULONG)cSegs < pHuge->cNumSeg) ||
|
|
(((ULONG)cSegs == pHuge->cNumSeg) && (cbPartialSeg < pHuge->PartialSeg))
|
|
)
|
|
&&
|
|
!pHuge->fSizeable
|
|
) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
//
|
|
// If the huge segment is a shared segment, pass the work to the server
|
|
//
|
|
if (pHuge->fShared) {
|
|
b->BaseAddress = SELTOFLAT(sel);
|
|
b->NumOfSegments = cSegs;
|
|
b->SizeOfPartialSeg = cbPartialSeg;
|
|
rc = Od2CallSubsystem( &m, NULL, Oi2ReallocSharedHuge, sizeof( *a ));
|
|
if (rc == NO_ERROR) {
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
}
|
|
ReleaseTaskLock();
|
|
return(rc);
|
|
}
|
|
|
|
if (pHuge->PartialSeg != 0) {
|
|
Op |= H_CUR_PARTIAL;
|
|
}
|
|
if (cbPartialSeg != 0) {
|
|
Op |= H_NEW_PARTIAL;
|
|
}
|
|
if ((ULONG)(cSegs) > pHuge->cNumSeg) {
|
|
Op |= H_SEG_INC;
|
|
}
|
|
else if ((ULONG)(cSegs) < pHuge->cNumSeg) {
|
|
Op |= H_SEG_DEC;
|
|
}
|
|
|
|
switch (Op) {
|
|
case H_SAME_SEG_NO_PARTIAL:
|
|
|
|
ReleaseTaskLock();
|
|
break;
|
|
|
|
case H_SAME_SEG_NEW_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
rc = DosSetMem(BaseAddress, cbPartialSeg,
|
|
(fPERM + PAG_COMMIT - PAG_GUARD));
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
ReleaseTaskLock();
|
|
//
|
|
// Set LDT entry
|
|
//
|
|
Desc.Limit = cbPartialSeg - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG)BaseAddress;
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
break;
|
|
|
|
case H_SAME_SEG_DEL_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
rc = DosSizeSeg(Sel, &SegSize);
|
|
if (rc != NO_ERROR){
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return (ERROR_INVALID_PARAMETER);
|
|
}
|
|
rc = DosSetMem(BaseAddress, SegSize, PAG_DECOMMIT);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
//
|
|
// Set LDT entry
|
|
//
|
|
Desc.Type = INVALID;
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
break;
|
|
|
|
case H_SAME_SEG_CHG_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
rc = DosReallocSeg(cbPartialSeg, Sel);
|
|
if (rc == NO_ERROR) {
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
}
|
|
ReleaseTaskLock();
|
|
return(rc);
|
|
|
|
case H_INC_SEG_NO_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*pHuge->cNumSeg);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cNewSegs = cSegs - pHuge->cNumSeg;
|
|
CommitSize = cNewSegs * _64K;
|
|
rc = DosSetMem(BaseAddress, CommitSize,
|
|
fPERM + PAG_COMMIT - PAG_GUARD);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
ReleaseTaskLock();
|
|
Desc.Limit = _64K - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG)BaseAddress;
|
|
for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
break;
|
|
|
|
case H_INC_SEG_NEW_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*pHuge->cNumSeg);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cNewSegs = cSegs - pHuge->cNumSeg;
|
|
CommitSize = (cNewSegs * _64K) + cbPartialSeg;
|
|
rc = DosSetMem(BaseAddress, CommitSize,
|
|
fPERM + PAG_COMMIT - PAG_GUARD);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
ReleaseTaskLock();
|
|
Desc.Limit = _64K - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG)BaseAddress;
|
|
for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
Desc.Limit = cbPartialSeg - 1;
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
break;
|
|
|
|
case H_INC_SEG_DEL_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*pHuge->cNumSeg);
|
|
rc = DosReallocSeg(0, Sel);
|
|
if (rc != NO_ERROR){
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
cNewSegs = cSegs - (pHuge->cNumSeg + 1);
|
|
if (cNewSegs == 0) {
|
|
pHuge->cNumSeg += 1;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
return(NO_ERROR);
|
|
}
|
|
Sel += 8;
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
CommitSize = cNewSegs * _64K;
|
|
rc = DosSetMem(BaseAddress, CommitSize,
|
|
fPERM + PAG_COMMIT - PAG_GUARD);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
pHuge->cNumSeg += 1;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
Desc.Limit = _64K - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG)BaseAddress;
|
|
for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
break;
|
|
|
|
case H_INC_SEG_CHG_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*pHuge->cNumSeg);
|
|
rc = DosReallocSeg(0, Sel);
|
|
if (rc != NO_ERROR){
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
cNewSegs = cSegs - (pHuge->cNumSeg + 1);
|
|
Sel += 8;
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
CommitSize = (cNewSegs * _64K) + cbPartialSeg;
|
|
rc = DosSetMem(BaseAddress, CommitSize,
|
|
fPERM + PAG_COMMIT - PAG_GUARD);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
pHuge->cNumSeg += 1;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
ReleaseTaskLock();
|
|
Desc.Limit = _64K - 1;
|
|
Desc.Type = READ_WRITE_DATA;
|
|
Desc.BaseAddress = (ULONG)BaseAddress;
|
|
for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
//
|
|
// Set LDT entry for the partial seg
|
|
//
|
|
Desc.Limit = cbPartialSeg - 1;
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
break;
|
|
|
|
case H_DEC_SEG_NO_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cDelSegs = pHuge->cNumSeg - cSegs;
|
|
DecommitSize = cDelSegs * _64K;
|
|
rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
ReleaseTaskLock();
|
|
Desc.Type = INVALID;
|
|
for (i = 0; i < cDelSegs; i++, Sel += 8) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
break;
|
|
|
|
case H_DEC_SEG_NEW_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*(cSegs + 1));
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cDelSegs = pHuge->cNumSeg - (cSegs + 1);
|
|
if (cDelSegs != 0) {
|
|
DecommitSize = cDelSegs * _64K;
|
|
rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
Desc.Type = INVALID;
|
|
for (i = 0; i < cDelSegs; i++, Sel += 8) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
}
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
rc = DosReallocSeg(cbPartialSeg, Sel);
|
|
if (rc != NO_ERROR) {
|
|
pHuge->cNumSeg = cSegs + 1;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
ReleaseTaskLock();
|
|
break;
|
|
|
|
case H_DEC_SEG_DEL_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cDelSegs = pHuge->cNumSeg - cSegs;
|
|
rc = DosSizeSeg((SEL)(sel + (SEL)(8*pHuge->cNumSeg)), &SegSize);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
DecommitSize = (cDelSegs * _64K) + SegSize;
|
|
rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
Desc.Type = INVALID;
|
|
for (i = 0; i <= cDelSegs; i++, Sel += 8) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
break;
|
|
|
|
case H_DEC_SEG_CHG_PARTIAL:
|
|
|
|
Sel = sel + (SEL)(8*(cSegs + 1));
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
cDelSegs = pHuge->cNumSeg - (cSegs + 1);
|
|
rc = DosSizeSeg((SEL)(sel + (SEL)(8*pHuge->cNumSeg)), &SegSize);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
DecommitSize = (cDelSegs * _64K) + SegSize;
|
|
rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
Desc.Type = INVALID;
|
|
for (i = 0; i <= cDelSegs; i++, Sel += 8) {
|
|
Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
|
|
ASSERT (NT_SUCCESS( Status ));
|
|
}
|
|
Sel = sel + (SEL)(8*cSegs);
|
|
rc = DosReallocSeg(cbPartialSeg, Sel);
|
|
if (rc != NO_ERROR){
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
|
|
}
|
|
#endif
|
|
pHuge->cNumSeg = cSegs + 1;
|
|
pHuge->PartialSeg = 0;
|
|
ReleaseTaskLock();
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->cNumSeg = cSegs;
|
|
pHuge->PartialSeg = cbPartialSeg;
|
|
ReleaseTaskLock();
|
|
break;
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosGetHugeShift(
|
|
OUT PUSHORT pusShiftCount
|
|
)
|
|
{
|
|
try {
|
|
*pusShiftCount = 3;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosAllocShrSeg(
|
|
IN USHORT cbSize,
|
|
IN PSZ pszSegName,
|
|
OUT PSEL pSel
|
|
)
|
|
{
|
|
PVOID BaseAddress;
|
|
APIRET rc;
|
|
ULONG Size, flags;
|
|
|
|
//
|
|
// probe pSel pointer.
|
|
//
|
|
|
|
try {
|
|
*pSel = 0;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
//
|
|
// OS2 1.X treats a 0 size request as (64k -1)
|
|
//
|
|
|
|
if (cbSize == 0)
|
|
Size = _64K;
|
|
else
|
|
Size = cbSize;
|
|
|
|
//
|
|
// First we reserve 64K, then we commit the size
|
|
// requested, rounded up to page granularity, by DosSetMem.
|
|
//
|
|
|
|
//
|
|
// we make it givable and gettable
|
|
// (see DosAllocSharedMem).
|
|
//
|
|
|
|
flags = fALLOCSHR - (PAG_GUARD | OBJ_GETTABLE | OBJ_GIVEABLE);
|
|
if (pszSegName == NULL)
|
|
{
|
|
flags |= (OBJ_GETTABLE | OBJ_GIVEABLE);
|
|
}
|
|
rc = DosAllocSharedMem(
|
|
&BaseAddress,
|
|
pszSegName,
|
|
Size,
|
|
(flags - (PAG_COMMIT | PAG_EXECUTE)),
|
|
TRUE // Create LDT entry
|
|
);
|
|
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_DISK_FULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
return (rc);
|
|
}
|
|
|
|
rc = DosSetMem(
|
|
BaseAddress,
|
|
Size,
|
|
(flags - PAG_EXECUTE));
|
|
|
|
if (rc != NO_ERROR){
|
|
BOOLEAN RemoveLDTEntry = TRUE;
|
|
DosFreeMem (BaseAddress, &RemoveLDTEntry);
|
|
if (rc == ERROR_DISK_FULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
return (rc);
|
|
}
|
|
|
|
*pSel = FLATTOSEL(BaseAddress);
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (*pSel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosAllocShrSeg returning sel=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
*pSel);
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
#if PMNT
|
|
|
|
// Lotus Notes 3.0 patch for $lib.dll
|
|
|
|
#include <stdio.h>
|
|
|
|
#pragma pack(1)
|
|
|
|
APIRET
|
|
DosQueryModuleHandleNE(
|
|
IN PSZ pszModName,
|
|
OUT PUSHORT phMod
|
|
);
|
|
|
|
APIRET
|
|
DosGetProcAddrNE(
|
|
IN ULONG hMod,
|
|
IN PSZ pszProcName,
|
|
OUT PULONG pProcAddr
|
|
);
|
|
|
|
APIRET
|
|
DosSemRequest(
|
|
IN HSEM hsem,
|
|
IN LONG lTimeOut
|
|
);
|
|
|
|
APIRET
|
|
DosSemClear(
|
|
IN HSEM hsem
|
|
);
|
|
|
|
typedef struct _od2_context16 {
|
|
USHORT junk;
|
|
USHORT rSS;
|
|
USHORT rBP;
|
|
USHORT rDX;
|
|
USHORT rBX;
|
|
USHORT rCX;
|
|
USHORT rSI;
|
|
USHORT rDI;
|
|
USHORT rES;
|
|
USHORT rDS;
|
|
USHORT rIP;
|
|
USHORT rCS;
|
|
} OD2_CONTEXT16, *POD2_CONTEXT16;
|
|
|
|
typedef struct _lnotes_descriptor {
|
|
UCHAR junk1[10];
|
|
USHORT selector;
|
|
UCHAR junk2[16];
|
|
SHORT usage;
|
|
ULONG semaphore;
|
|
} LNOTES_DESCRIPTOR, *PLNOTES_DESCRIPTOR;
|
|
|
|
BOOLEAN LNotesPatchEnabled = TRUE;
|
|
BOOLEAN LNotesPatchChecked = FALSE;
|
|
ULONG LNotesPatchCodeSegment;
|
|
|
|
PLNOTES_DESCRIPTOR LNotesPatchCheck(POD2_CONTEXT16 pContext)
|
|
{
|
|
ULONG hMod;
|
|
ULONG pOSMEMALLOC;
|
|
PUSHORT pDescriptorSegment;
|
|
PLNOTES_DESCRIPTOR pDescriptor;
|
|
FILE *file;
|
|
APIRET rc;
|
|
|
|
if (!LNotesPatchEnabled) return FALSE;
|
|
if (!LNotesPatchChecked) {
|
|
LNotesPatchChecked = TRUE;
|
|
if (rc = DosQueryModuleHandleNE("$LIB", (PUSHORT) &hMod)) {
|
|
//#if DBG
|
|
// DbgPrint("[%d] This is not Lotus Notes process (rc=%d)\n",
|
|
// Od2Process->Pib.ProcessId, rc);
|
|
//#endif // DBG
|
|
LNotesPatchEnabled = FALSE;
|
|
return NULL;
|
|
}
|
|
#if DBG
|
|
DbgPrint("[%d] This process belongs to Lotus Notes\n",
|
|
Od2Process->Pib.ProcessId);
|
|
#endif // DBG
|
|
file = fopen("c:\\os2\\pmnt.pth", "r");
|
|
if (file == NULL) {
|
|
file = fopen("c:\\os2\\pmnt.pth", "w");
|
|
}
|
|
else
|
|
{
|
|
fclose(file);
|
|
file = NULL;
|
|
}
|
|
if (rc = DosGetProcAddrNE(hMod, "OSMEMALLOC", &pOSMEMALLOC)) {
|
|
#if DBG
|
|
DbgPrint("[%d] Lotus Notes patch. OSMEMALLOC doesn't exist (rc=%d)\n",
|
|
Od2Process->Pib.ProcessId, rc);
|
|
#endif // DBG
|
|
if (file) {
|
|
fprintf(file, "[%d] Lotus Notes patch. OSMEMALLOC doesn't exist (rc=%d)\n",
|
|
Od2Process->Pib.ProcessId, rc);
|
|
fclose(file);
|
|
}
|
|
LNotesPatchEnabled = FALSE;
|
|
return NULL;
|
|
}
|
|
if ((pOSMEMALLOC & 0xFFFF) != 0x6C0) {
|
|
#if DBG
|
|
DbgPrint("[%d] Lotus Notes patch. OSMEMALLOC offset = %x\n",
|
|
Od2Process->Pib.ProcessId, pOSMEMALLOC & 0xFFFF);
|
|
#endif // DBG
|
|
if (file) {
|
|
fprintf(file, "[%d] Lotus Notes patch. OSMEMALLOC offset = %x\n",
|
|
Od2Process->Pib.ProcessId, pOSMEMALLOC & 0xFFFF);
|
|
fclose(file);
|
|
}
|
|
LNotesPatchEnabled = FALSE;
|
|
return NULL;
|
|
}
|
|
LNotesPatchCodeSegment = ((pOSMEMALLOC & 0xFFFF0000) >> 16);
|
|
}
|
|
|
|
if ((ULONG)(pContext->rCS) != LNotesPatchCodeSegment) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] Lotus Notes patch from %04x:%04X. OSMEMALLOC segment = %04X\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
pContext->rCS,
|
|
pContext->rIP,
|
|
(pOSMEMALLOC & 0xFFFF) >> 16);
|
|
#endif // DBG
|
|
return NULL;
|
|
}
|
|
|
|
if (pContext->rIP == 0x33E ||
|
|
pContext->rIP == 0x3DD ||
|
|
pContext->rIP == 0x37E) {
|
|
|
|
pDescriptorSegment = (PUSHORT)
|
|
((PUCHAR)SELTOFLAT(pContext->rSS) + pContext->rBP - 6);
|
|
pDescriptor = (PLNOTES_DESCRIPTOR)
|
|
((PUCHAR)SELTOFLAT(*pDescriptorSegment) + pContext->rSI);
|
|
|
|
return pDescriptor;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void LNotesPatchLock(POD2_CONTEXT16 pContext)
|
|
{
|
|
PLNOTES_DESCRIPTOR pDescriptor;
|
|
|
|
if (pDescriptor = LNotesPatchCheck(pContext)) {
|
|
pDescriptor->usage++;
|
|
if (pDescriptor->usage > 0) {
|
|
DosSemRequest(&(pDescriptor->semaphore), -1L);
|
|
#if DBG
|
|
DbgPrint("[%d,%d] LNotes lock from %04x:%04x sel=%x sem=%d:%08x at %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
pContext->rCS,
|
|
pContext->rIP,
|
|
pDescriptor->selector,
|
|
pDescriptor->usage,
|
|
pDescriptor->semaphore,
|
|
&(pDescriptor->semaphore));
|
|
#endif // DBG
|
|
}
|
|
}
|
|
}
|
|
|
|
void LNotesPatchUnlock(POD2_CONTEXT16 pContext)
|
|
{
|
|
PLNOTES_DESCRIPTOR pDescriptor;
|
|
|
|
if (pDescriptor = LNotesPatchCheck(pContext)) {
|
|
pDescriptor->usage--;
|
|
if (pDescriptor->usage >= 0) {
|
|
DosSemClear(&(pDescriptor->semaphore));
|
|
#if DBG
|
|
DbgPrint("[%d,%d] LNotes unlock from %04x:%04x sel=%x sem=%d:%x at %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
pContext->rCS,
|
|
pContext->rIP,
|
|
pDescriptor->selector,
|
|
pDescriptor->usage,
|
|
pDescriptor->semaphore,
|
|
&(pDescriptor->semaphore));
|
|
#endif // DBG
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma pack()
|
|
|
|
#endif // PMNT
|
|
|
|
APIRET
|
|
#if PMNT
|
|
PMNT_DosLockSeg(
|
|
#else
|
|
DosLockSeg(
|
|
#endif // PMNT
|
|
IN SEL sel
|
|
)
|
|
{
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosLockSeg called on sel=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
|
|
if (!IsLegalSelector(sel)){
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosLockSeg called on sel=%x, returning ACCES_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
#if PMNT
|
|
PMNT_DosUnlockSeg(
|
|
#else
|
|
DosUnlockSeg(
|
|
#endif // PMNT
|
|
IN SEL sel
|
|
)
|
|
{
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosUnlockSeg called on sel=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
|
|
if (!IsLegalSelector(sel)){
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosUnlockSeg called on sel=%x, returning ACCES_DENIED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
sel);
|
|
}
|
|
#endif
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosGetShrSeg(
|
|
IN PSZ pszSegName,
|
|
OUT PSEL pSel
|
|
)
|
|
{
|
|
OS2_API_MSG m;
|
|
POS2_DOSGETSHRSEG_MSG a = &m.u.DosGetShrSeg;
|
|
APIRET rc;
|
|
POS2_CAPTURE_HEADER CaptureBuffer;
|
|
//
|
|
// probe pSel pointer.
|
|
//
|
|
try {
|
|
*pSel = 0;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
rc = Od2CaptureObjectName( pszSegName,
|
|
CANONICALIZE_SHARED_MEMORY,
|
|
0,
|
|
&CaptureBuffer,
|
|
&a->ObjectName
|
|
);
|
|
if (rc != NO_ERROR) {
|
|
return( rc );
|
|
}
|
|
Od2CallSubsystem( &m, CaptureBuffer, Os2GetShrSeg, sizeof( *a ) );
|
|
Od2FreeCaptureBuffer( CaptureBuffer );
|
|
if (m.ReturnedErrorValue == NO_ERROR) {
|
|
*pSel = (SEL)(a->Selector);
|
|
}
|
|
return( m.ReturnedErrorValue );
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosMemAvail(
|
|
OUT PULONG pcbFree
|
|
)
|
|
{
|
|
try {
|
|
*pcbFree = 64512;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint ("DosMemAvail: Returning bogus value\n");
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosCreateCSAlias(
|
|
IN SEL selDS,
|
|
OUT PSEL pselCS
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
APIRET rc = NO_ERROR;
|
|
ULONG usSize;
|
|
I386DESCRIPTOR dsDesc,csDesc;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE SectionHandle;
|
|
ULONG AllocationAttributes;
|
|
LARGE_INTEGER SectionSize;
|
|
ULONG RegionSize = 0;
|
|
POS21X_CS pCS;
|
|
POS21X_CSALIAS pCSAlias;
|
|
BOOLEAN SectionExists = FALSE;
|
|
MEMORY_BASIC_INFORMATION MemoryBasicInfo;
|
|
ULONG ReturnedLength;
|
|
ULONG Index;
|
|
|
|
//
|
|
// We have a problem with tiling, so we need to make the
|
|
// CS memory area and the data memory area mapped to
|
|
// each other.
|
|
//
|
|
// What we do for CSAlias is:
|
|
// - Create a section object.
|
|
// - Map the section and make the map out CS area
|
|
// - WriteVirtualMemory from datasegment to codesegment
|
|
// - Free DataSeg
|
|
// - MapView the code area back into the data area
|
|
// - get a selctor for the code area
|
|
//
|
|
|
|
try {
|
|
*pselCS = 0;
|
|
}
|
|
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
#if DBG
|
|
if ((Os2DebugSel != 0) && (selDS == Os2DebugSel))
|
|
{
|
|
DbgPrint("[%x,%x] DosCreateCsAlias DS sel=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
selDS);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Query the size of the Data Segment
|
|
//
|
|
Status = Nt386GetDescriptorLDT (
|
|
NULL,
|
|
selDS,
|
|
&dsDesc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to get descriptor info\n");
|
|
#endif
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
usSize = dsDesc.Limit+1;
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
|
|
|
|
AllocationAttributes = SEC_RESERVE;
|
|
|
|
//
|
|
// Lookup if this DS was already aliased before
|
|
// Leave task Locked if not, then alias and free lock
|
|
//
|
|
AcquireTaskLock();
|
|
if (Od2CSAliasListHead != 0) {
|
|
for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
|
|
pCSAlias != NULL;
|
|
pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)) {
|
|
if (pCSAlias->selDS == selDS) {
|
|
SectionHandle = pCSAlias->SectionHandle;
|
|
SectionExists = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// The task is locked (see above)
|
|
// this is to prevent races
|
|
// with two threads doing CSAlias the
|
|
// same time.
|
|
//
|
|
|
|
if (!(SectionExists)) {
|
|
|
|
//
|
|
// We need to reserve 64K, then commit usSize
|
|
//
|
|
SectionSize.LowPart = _64K;
|
|
SectionSize.HighPart = 0;
|
|
Status = NtCreateSection( &SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&SectionSize,
|
|
PAGE_EXECUTE_READWRITE,
|
|
AllocationAttributes,
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to CreateSection\n");
|
|
#endif
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
|
|
Index = ldtAllocateSelectors(
|
|
1, // NumberOfSel
|
|
Index // StartOfMark
|
|
);
|
|
|
|
if (Index == 0xffffffff){
|
|
//
|
|
// not found - no memory
|
|
//
|
|
Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
|
|
if (!SectionExists) {
|
|
NtClose (SectionHandle);
|
|
}
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Od2MemoryAllocationBase = BaseAddress = (PVOID)((Index * _64K) + BASE_TILE);
|
|
|
|
Status = NtMapViewOfSection( SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
BASE_TILE_ZERO_BITS,
|
|
usSize,
|
|
NULL,
|
|
&RegionSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to MapViewSection to CS\n Error: %x\n", Status);
|
|
#endif
|
|
if (!SectionExists) {
|
|
NtClose (SectionHandle);
|
|
}
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
csDesc.BaseAddress = (ULONG) BaseAddress;
|
|
csDesc.Limit = usSize-1;
|
|
csDesc.Type = EXECUTE_READ_CODE;
|
|
*pselCS = FLATTOSEL(csDesc.BaseAddress);
|
|
|
|
Status = Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCSAlias fails to set CS descriptor\n");
|
|
#endif
|
|
*pselCS = 0;
|
|
if (!SectionExists) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
}
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
if (SectionExists) {
|
|
pCS = (POS21X_CS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CS));
|
|
if (!pCS){
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CS\n",
|
|
Status);
|
|
#endif
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
//
|
|
// link the new CS into the CSList of the CSAlias Section
|
|
//
|
|
pCS->Next = (struct OS21X_CS *)(pCSAlias->pCSList);
|
|
pCSAlias->pCSList = (POS21X_CS) pCS;
|
|
pCS->selCS = *pselCS;
|
|
ReleaseTaskLock();
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// Copy the data into the code segment
|
|
//
|
|
try {
|
|
RtlCopyMemory (
|
|
(PUCHAR)(csDesc.BaseAddress),
|
|
(PUCHAR)(dsDesc.BaseAddress),
|
|
usSize);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
#if DBG
|
|
DbgPrint ("Exception in DosCSAlias, RtlMoveMemory\n");
|
|
#endif
|
|
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
Od2ExitGP();
|
|
}
|
|
|
|
//
|
|
// Check the type of the aliased data segment.
|
|
// If it was a private segment then do NtFreeVirtualMemory()
|
|
// If it was a shared segment then do NtUnmapVieOfSection
|
|
//
|
|
|
|
Status = NtQueryVirtualMemory( NtCurrentProcess(),
|
|
(PVOID)dsDesc.BaseAddress,
|
|
MemoryBasicInformation,
|
|
&MemoryBasicInfo,
|
|
sizeof(MEMORY_BASIC_INFORMATION),
|
|
&ReturnedLength
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCSAlias fails to NtQueryVirtualMemory(), Status %lx\n", Status);
|
|
#endif
|
|
ASSERT(NT_SUCCESS(Status));
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
#if 0
|
|
DbgPrint("*** Mem=%x\n"
|
|
"*** ReturnedLength=%x, sizeof=%x\n"
|
|
"*** BaesAddr=%x, AllocationBase=%x\n"
|
|
"*** AllocProtect = %lx, RegionSize=%x, State=%x, Protect = %lx\n",
|
|
dsDesc.BaseAddress,
|
|
ReturnedLength, sizeof(MEMORY_BASIC_INFORMATION),
|
|
MemoryBasicInfo.BaseAddress, MemoryBasicInfo.AllocationBase,
|
|
MemoryBasicInfo.AllocationProtect, MemoryBasicInfo.RegionSize,
|
|
MemoryBasicInfo.State, MemoryBasicInfo.Protect);
|
|
#endif
|
|
|
|
if ((MemoryBasicInfo.Type & MEM_PRIVATE) != 0) {
|
|
//
|
|
// Now Free the data segment and
|
|
// MapView it from the new section
|
|
//
|
|
BaseAddress = (PVOID)(dsDesc.BaseAddress);
|
|
RegionSize = 0;
|
|
Status = NtFreeVirtualMemory( NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&RegionSize,
|
|
MEM_RELEASE
|
|
);
|
|
#if DBG
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint ("DosCSAlias fails to NtFreeVirtualMemory, Status %lx\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
else if ((MemoryBasicInfo.Type & MEM_MAPPED) != 0) {
|
|
if ((MemoryBasicInfo.AllocationProtect & PAGE_EXECUTE_WRITECOPY) != 0) {
|
|
//
|
|
// This is a data segment mapped by the loader but it is not global
|
|
//
|
|
Status = NtUnmapViewOfSection( NtCurrentProcess(),
|
|
(PVOID)dsDesc.BaseAddress
|
|
);
|
|
#if DBG
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint ("DosCSAlias fails to NtUnmapViewOfSection, Status %lx\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint ("DosCSAlias: Trying to alias Shared memory\n");
|
|
#endif
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint ("DosCSAlias: Illegal type of aliased data, Status %lx\n", Status);
|
|
#endif
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
ASSERT(NT_SUCCESS(Status));
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
RegionSize = 0;
|
|
Status = NtMapViewOfSection( SectionHandle,
|
|
NtCurrentProcess(),
|
|
&(PVOID)(dsDesc.BaseAddress),
|
|
BASE_TILE_ZERO_BITS,
|
|
usSize,
|
|
NULL,
|
|
&RegionSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails at MapViewSection DS\n Error: %x\n",
|
|
Status);
|
|
#endif
|
|
dsDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
selDS,
|
|
dsDesc);
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
pCS = (POS21X_CS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CS));
|
|
if (!pCS){
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CS\n",
|
|
Status);
|
|
#endif
|
|
dsDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
selDS,
|
|
dsDesc);
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)dsDesc.BaseAddress
|
|
);
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
pCSAlias = (POS21X_CSALIAS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CSALIAS));
|
|
if (!pCSAlias){
|
|
#if DBG
|
|
DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CSAlias\n",
|
|
Status);
|
|
#endif
|
|
dsDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
selDS,
|
|
dsDesc);
|
|
csDesc.Type = INVALID;
|
|
Nt386SetDescriptorLDT (
|
|
NULL,
|
|
*pselCS,
|
|
csDesc);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)csDesc.BaseAddress
|
|
);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
(PVOID)dsDesc.BaseAddress
|
|
);
|
|
RtlFreeHeap(Od2Heap, 0,pCS);
|
|
|
|
NtClose (SectionHandle);
|
|
ReleaseTaskLock();
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
//
|
|
// link the new CS into the CSList of the CSAlias Section
|
|
//
|
|
pCS->Next = NULL;
|
|
pCS->selCS = *pselCS;
|
|
pCSAlias->pCSList = pCS;
|
|
//
|
|
// Set rest of the fields
|
|
//
|
|
pCSAlias->selDS = selDS;
|
|
pCSAlias->SectionHandle = SectionHandle;
|
|
pCSAlias->Next = Od2CSAliasListHead;
|
|
Od2CSAliasListHead = (struct OS21X_CSALIAS *) pCSAlias;
|
|
ReleaseTaskLock();
|
|
#if DBG
|
|
IF_OD2_DEBUG ( MEMORY ) {
|
|
DbgPrint ("DosCreateCSAlias: selDS %x is mapped to selCS %x\n",
|
|
selDS, *pselCS);
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosSizeSeg(
|
|
IN SEL sel,
|
|
PULONG pcbSize
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
I386DESCRIPTOR Desc;
|
|
OS2_API_MSG m;
|
|
POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
|
|
PHUGE_SEG_RECORD pHuge;
|
|
|
|
//
|
|
// lookup the HugeSeg list to find out if sel is a valid Huge memory
|
|
//
|
|
for (pHuge = pHugeSegHead;
|
|
pHuge != NULL;
|
|
pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
|
|
if (pHuge->BaseSelector == (ULONG)(sel)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pHuge == NULL) {
|
|
|
|
//
|
|
// Did not find a Huge Seg that starts with sel
|
|
//
|
|
//
|
|
// The huge seg may be a shared huge seg which was allocated
|
|
// by another process. Sync with the huge seg info which is
|
|
// kept in the server
|
|
//
|
|
a->BaseAddress = SELTOFLAT(sel);
|
|
Od2CallSubsystem( &m, NULL, Oi2QueryVirtualMemory, sizeof( *a ));
|
|
if (a->SharedMemory && a->IsHuge) {
|
|
pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
|
|
if (pHuge == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
|
|
pHuge->MaxNumSeg = a->MaxSegments;
|
|
pHuge->BaseSelector = sel;
|
|
pHuge->cNumSeg = a->NumOfSegments;
|
|
pHuge->PartialSeg = a->SizeOfPartialSeg;
|
|
pHuge->fShared = TRUE;
|
|
pHuge->fSizeable = a->Sizeable;
|
|
|
|
pHugeSegHead = pHuge;
|
|
}
|
|
else { // This selector is not for huge memory block.
|
|
//
|
|
// Query for the current setting in LDT
|
|
//
|
|
|
|
Status = Nt386GetDescriptorLDT (
|
|
NULL,
|
|
sel,
|
|
&Desc);
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint ("DosSizeSeg: Error %d; Sel %x\n",
|
|
ERROR_INVALID_PARAMETER, sel);
|
|
#endif
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
try {
|
|
*pcbSize = Desc.Limit + 1;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate huge memory block size
|
|
//
|
|
try {
|
|
*pcbSize = pHuge->cNumSeg * _64K + pHuge->PartialSeg;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosR2StackRealloc(
|
|
USHORT NewSize
|
|
)
|
|
{
|
|
PR2StackEntry pStackEntry;
|
|
APIRET rc;
|
|
|
|
pStackEntry = (PR2StackEntry)R2STACKS_BASE;
|
|
pStackEntry += Od2CurrentThreadId();
|
|
if (pStackEntry->R2StackSel == 0) {
|
|
rc = DosAllocSeg(NewSize, (PSEL)&pStackEntry->R2StackSel, 0);
|
|
}
|
|
else {
|
|
rc = DosReallocSeg(NewSize, (SEL)pStackEntry->R2StackSel);
|
|
}
|
|
if (rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
pStackEntry->R2StackSize = NewSize;
|
|
|
|
return NO_ERROR;
|
|
}
|