Windows NT 4.0 source code leak
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

/*++
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;
}