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.
 
 
 
 
 
 

2775 lines
88 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
srvvm.c
Abstract:
Memory Management API
Author:
Steve Wood (stevewo) 11-Oct-1989
Revision History:
--*/
#define INCL_OS2V20_MEMORY
#define INCL_OS2V20_ERRORS
#include "os2srv.h"
#include "os2tile.h"
#include "os2ldr.h"
//
// 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 ROUND_UP_TO_PAGES(x) (((ULONG)(x)+0xfff)&(~0xfff))
NTSTATUS
Os2InitializeMemory( VOID )
/*++
Routine Description:
This function performs the global initialization for the shared memory
component of the OS/2 Subsystem.
Each shared memory object allocated with the DosAllocSharedMem API call
has an associated shared memory object descriptor created that contains
the NT section handle that points to the memory for the object, the
page level protection that is associated with the memory, along with
a reference count of the number of processes that have attached to this
shared memory object. The descriptors are linked together on a doubly
linked list, the head of which is the global variable Os2SharedMemoryList.
For each process that has attached to a shared memory object, there is
a process reference object created that points to the shared memory
object descriptor. Each OS/2 process object contains the head of a
doubly linked list of process reference objects. This list is used
to detect multiple references to the same shared memory object from
the same process. This list is also used during process termination
to free all of a processes references to shared memory objects.
Any process reference object that points to a named shared memory
object descriptor also contains a reference count of the number of
times the process has referenced the object's name. This allows the
DosFreeMem API to know when to actually unmap a view of a shared
memory object from the caller's address space (i.e. when the
reference count goes to zero).
Both linked lists are protected by the ProcessStructureLock, so that
nothing relevant can changed while we are playing with the lists.
Arguments:
None.
Return Value:
Status value - STATUS_SUCCESS always.
--*/
{
//
// Initialize the global list of shared memory object descriptors
// to be the empty list.
//
InitializeListHead( &Os2SharedMemoryList );
//
// Always return success.
//
return( STATUS_SUCCESS );
}
POS2_SHARED_MEMORY_OBJECT
Os2CreateSharedMemoryObject(
IN POS2_API_MSG m,
IN PVOID BaseAddress,
IN ULONG Index,
IN ULONG RegionSize,
IN HANDLE SectionHandle,
IN ULONG AllocationFlags,
IN PSTRING SecName
)
/*++
Routine Description:
This function creates a shared memory object descriptor and appends
it to the global linked list of shared memory object descriptors.
It sets the reference count to zero, as no process reference objects
are pointing to this shared memory object descriptor yet.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
m - pointer to an OS/2 API message structure where any error code is
returned in the ReturnedErrorValue field.
BaseAddress - base address of the shared memory object for all processes
that attach to this shared memory object.
Index - An index into the BitMap to allocate the shared memory object.
RegionSize - Size of the shared memory object.
SectionHandle - an NT handle to the section object that describes the
shared memory. This is always a SEC_BASED section.
AllocationFlags - any of the following flags:
OBJ_GETTABLE and/or OBJ_GIVEABLE
if neither is set, then must be named shared memory
that will be reference counted by process.
Return Value:
Point to the shared memory object descriptor or NULL if unsuccessful.
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
//
// First see if the specified base address is already in the list
// of shared memory objects. If it is, then return an error.
//
ListHead = &Os2SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryObject = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_OBJECT,
Link
);
if (MemoryObject->BaseAddress == BaseAddress) {
m->ReturnedErrorValue = ERROR_ALREADY_EXISTS;
return( NULL );
}
ListNext = ListNext->Flink;
}
//
// Not in the list, so allocate the shared memory object descriptor,
// initialize it and append it to the global list of shared memory
// objects. Return an error if not enough memory to allocated the
// shared memory object descriptor.
//
MemoryObject = RtlAllocateHeap( Os2Heap, 0, sizeof( *MemoryObject ) );
if (MemoryObject != NULL) {
MemoryObject->IsHuge = FALSE;
MemoryObject->RefCount = 0;
MemoryObject->BaseAddress = BaseAddress;
MemoryObject->Index = Index;
MemoryObject->RegionSize = RegionSize;
MemoryObject->SectionHandle = SectionHandle;
MemoryObject->AllocationFlags = AllocationFlags;
if (SecName == NULL || SecName->Buffer == NULL) {
MemoryObject->SectionName.Buffer = NULL;
}
else {
MemoryObject->SectionName.Buffer = (PCHAR)RtlAllocateHeap (Os2Heap, 0, SecName->Length);
if (MemoryObject->SectionName.Buffer == NULL) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
RtlFreeHeap (Os2Heap, 0, MemoryObject);
return(NULL);
}
MemoryObject->SectionName.Length = SecName->Length;
MemoryObject->SectionName.MaximumLength = SecName->Length;
RtlMoveMemory( MemoryObject->SectionName.Buffer,
SecName->Buffer,
SecName->Length);
}
InsertTailList( &Os2SharedMemoryList, &MemoryObject->Link );
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: CreateSharedMemoryObject (%lX) ->BaseAddress = %lX\n",
MemoryObject, MemoryObject->BaseAddress
);
}
#endif
}
else {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
}
//
// Return a pointer to the newly created shared memory object descriptor
// or NULL if unable to allocate.
//
return( MemoryObject );
}
VOID
Os2FreeSharedMemoryObject(
POS2_SHARED_MEMORY_OBJECT MemoryObject
)
/*++
Routine Description:
This function removes the passed shared memory object descriptor from
the global list, closes the NT section handle stored in the descriptor,
and returns the space occupied by the descriptor to the heap.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
MemoryObject - pointer to the shared memory object descriptor to free.
Return Value:
None.
--*/
{
//
// Free the buffer used for holding the shared memory name
//
if (MemoryObject->SectionName.Buffer != NULL) {
RtlFreeHeap(Os2Heap, 0, MemoryObject->SectionName.Buffer);
}
//
// Remove the descriptor from the global linked list.
//
RemoveEntryList( &MemoryObject->Link );
//
// Close the NT Section Handle that points to the memory. The memory
// and any associated name, will actually be freed when the last view
// of the memory is unmap, which will be real soon now since the caller
// of this function is going to do it or process termination will.
//
NtClose( MemoryObject->SectionHandle );
//
// Return the space for the descriptor back to the heap.
//
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: FreeSharedMemoryObject (%lX) ->BaseAddress = %lX\n",
MemoryObject, MemoryObject->BaseAddress
);
}
#endif
RtlFreeHeap( Os2Heap, 0, MemoryObject );
return;
}
POS2_SHARED_MEMORY_PROCESS_REF
Os2CreateProcessRefToSharedMemory(
IN POS2_PROCESS Process,
IN POS2_SHARED_MEMORY_OBJECT MemoryObject
)
/*++
Routine Description:
This function creates a shared memory reference object that points
to the specified shared memory object descriptor. The shared memory
reference object will be appended to the linked list rooted in the
specified OS/2 process.
If the specified process already contains a shared memory reference
object for the specified shared memory, then just bump the reference
count in the shared memory reference object.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
Process - points to an OS/2 process structure that is the process
that is making the reference to the shared memory object.
MemoryObject - points to the shared memory object descriptor being
referenced by the specified process.
Return Value:
Returns a pointer to the shared memory reference object or NULL if
unable to allocate heap space for it.
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
//
// First search the list of shared memory reference objects for the
// specified process. If a shared memory reference object is found
// for this shared memory descriptor, then just return a pointer to
// the reference object.
//
ListHead = &Process->SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryProcessRef = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
if (MemoryProcessRef->SharedMemoryObject == MemoryObject) {
++MemoryProcessRef->RefCount;
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
Process->ProcessId,
MemoryProcessRef,
MemoryProcessRef->SharedMemoryObject->BaseAddress,
MemoryProcessRef->RefCount
);
}
#endif
return( MemoryProcessRef );
}
ListNext = ListNext->Flink;
}
//
// Process is attaching to this shared memory for the first time, so
// allocated the shared memory reference object and fill it in. Return
// NULL if unable to allocate the space. Otherwise, append to the
// list reference objects pointed to by the specified process and
// increment the reference count in the shared memory object descriptor.
//
MemoryProcessRef = RtlAllocateHeap( Os2Heap, 0, sizeof( *MemoryProcessRef ) );
if (MemoryProcessRef == NULL) {
return( NULL );
}
MemoryProcessRef->SharedMemoryObject = MemoryObject;
MemoryProcessRef->RefCount = 1;
MemoryProcessRef->AllocationFlags = 0;
InsertTailList( &Process->SharedMemoryList, &MemoryProcessRef->Link );
//
// Count the number of processes that contain pointers to this shared
// memory object descriptor.
//
++MemoryObject->RefCount;
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
Process->ProcessId,
MemoryProcessRef,
MemoryObject->BaseAddress,
MemoryProcessRef->RefCount
);
DbgPrint( " MemoryObject (%lX) ->RefCount = %ld\n",
MemoryObject,
MemoryObject->RefCount
);
}
#endif
//
// Return a pointer to the shared memory reference object.
//
return( MemoryProcessRef );
}
BOOLEAN
Os2FreeProcessRefToSharedMemory(
IN POS2_PROCESS Process,
IN POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef
)
/*++
Routine Description:
This function frees a process's reference to a shared memory object.
It does so by first decrementing the count of the number of references
the process has made to the shared memory object and if the count goes
to zero, it removes the shared memory reference object from the list
pointed to by the referencing process, frees the shared memory reference object and
then decrements the reference count in the shared memory object descriptor
pointed to by this reference object. If that reference count goes to
zero then free the shared memory object descriptor as well.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
MemoryProcessRef - points to the shared memory reference object to free.
Return Value:
Boolean value, where TRUE means that this was the last reference for
the process to this shared memory object and that the process's view
of the shared memory can thus be unmapped. Returns FALSE if the
reference count for this shared memory reference object is still not
zero.
--*/
{
POS2_SHARED_MEMORY_OBJECT MemoryObject;
//
// Decrement the reference count for the process.
//
if (--MemoryProcessRef->RefCount == 0) {
//
// If the count goes to zero, then remove the reference object from
// its list and return the space occupied by the reference object
// to the heap.
//
MemoryObject = MemoryProcessRef->SharedMemoryObject;
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - freeing MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
Process->ProcessId,
MemoryProcessRef,
MemoryObject->BaseAddress,
MemoryProcessRef->RefCount
);
DbgPrint( " MemoryObject (%lX) ->RefCount = %ld\n",
MemoryObject,
MemoryObject->RefCount
);
}
#endif
RemoveEntryList( &MemoryProcessRef->Link );
RtlFreeHeap( Os2Heap, 0, MemoryProcessRef );
//
// Decrement the reference count in the shared memory object descriptor
// pointed to by the reference object just freed. If the count goes
// to zero then free the shared memory object descriptor.
//
if (--MemoryObject->RefCount == 0) {
ldrFreeSel(MemoryObject->Index,
(MemoryObject->RegionSize + (_64K - 1)) / _64K
);
Os2FreeSharedMemoryObject( MemoryObject );
}
//
// Return TRUE to indicate to caller that the process no longer
// has a reference object for the shared memory object descriptor.
//
return( TRUE );
}
else {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - decrementing MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
Process->ProcessId,
MemoryProcessRef,
MemoryProcessRef->SharedMemoryObject->BaseAddress,
MemoryProcessRef->RefCount
);
}
#endif
//
// Return FALSE to indicate to caller that the process still has
// a reference object for the shared memory object descriptor.
//
return( FALSE );
}
}
VOID
Os2FreeAllSharedMemoryForProcess(
IN POS2_PROCESS Process
)
/*++
Routine Description:
This function is called during process termination to free all
shared memory reference objects for the specified process.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
Process - points to an OS/2 process structure that is the process
that is terminating.
Return Value:
None.
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
//
// Walk the list of shared memory reference objects for this process
// and free each one. Force the free by setting the reference count
// in the reference object to 1.
//
ListHead = &Process->SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryProcessRef = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
ListNext = ListNext->Flink;
MemoryProcessRef->RefCount = 1;
#if DBG
IF_OS2_DEBUG( CLEANUP ) {
DbgPrint( "OS2SRV: Pid: %lX - DosFreeMem( %lX )\n",
Process->ProcessId,
MemoryProcessRef->SharedMemoryObject->BaseAddress
);
}
#endif
Os2FreeProcessRefToSharedMemory( Process, MemoryProcessRef );
}
return;
}
POS2_SHARED_MEMORY_OBJECT
Os2FindSharedMemoryObject(
IN PVOID BaseAddress,
IN POS2_PROCESS Process
)
/*++
Routine Description:
This function searchs the global list of shared memory object descriptors
to see if the passed base address is described by one of them.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
BaseAddress - Supplies the base address of the shared memory we are
looking for.
Process - Optional pointer to the process that will be used to restrict
the search. If specified, this function succeeds only if the process
has a reference outstanding to the shared memory.
Return Value:
Pointer to the shared memory object descriptor if found or NULL if
not found.
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
if (ARGUMENT_PRESENT( Process )) {
//
// Search the list of shared memory reference objects for the
// specified process. If a shared memory reference object is found
// for this shared memory descriptor, then just return a pointer to
// the shared memory object descriptor.
//
ListHead = &Process->SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryProcessRef = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
MemoryObject = MemoryProcessRef->SharedMemoryObject;
if (MemoryObject->BaseAddress == BaseAddress) {
return( MemoryObject );
}
ListNext = ListNext->Flink;
}
return( NULL );
}
ListHead = &Os2SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryObject = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_OBJECT,
Link
);
if (MemoryObject->BaseAddress == BaseAddress) {
return( MemoryObject );
}
ListNext = ListNext->Flink;
}
return( NULL );
}
POS2_SHARED_MEMORY_OBJECT
Os2FindNamedSharedMemoryObject(
PSTRING SecName
)
/*++
Routine Description:
This function searchs the global list of shared memory object descriptors
to see if the passed shared memory name is described by one of them.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
SecName - Supplies the name of the shared memory we are
looking for.
Return Value:
Pointer to the shared memory object descriptor if found or NULL if
not found.
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
//
// find a shared memory object with the desired name
//
ListHead = &Os2SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryObject = CONTAINING_RECORD(ListNext, OS2_SHARED_MEMORY_OBJECT, Link);
if (MemoryObject->SectionName.Buffer != NULL) {
if (RtlEqualString(&MemoryObject->SectionName, SecName, TRUE)) {
return (MemoryObject);
}
}
ListNext = ListNext->Flink;
}
return(NULL);
}
APIRET
Os2MapViewOfSharedMemoryObject(
POS2_SHARED_MEMORY_OBJECT MemoryObject,
POS2_PROCESS Process,
BOOLEAN ProcessIsSelf,
ULONG RequiredAccess,
ULONG Protection
)
/*++
Routine Description:
This function maps a view of the specified memory object into the
specified process. Creates a shared memory reference object to
keep track of the reference.
This function must be called within the scope of the
ProcessStructureLock.
Arguments:
MemoryObject - Points to the shared memory object descriptor that
describes the shared memory being mapped.
Process - points to an OS/2 process structure that is the process
that is to receive the mapped view of the shared memory.
ProcessIsSelf - boolean parameter that specifies that the calling
application process is manipulating his own address.
RequiredAccess - one or neither of the following flags:
OBJ_GETTABLE and/or OBJ_GIVEABLE
if neither is set, access if always granted.
Protection - specifies the NT Page level protection for pages in
this view of the shared memory object.
Return Value:
OS/2 Error code or NO_ERROR if successful.
--*/
{
APIRET rc;
NTSTATUS Status;
MEMORY_BASIC_INFORMATION MemoryInformation;
PVOID BaseAddress = NULL;
ULONG RegionSize = 0;
ULONG OldProtection;
ULONG OldFlags, NewFlags;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
//
// Return access denied if gettable bits. Must be consistent with
// how the shared memory object was created. So:
//
// - if named shared memory, can only get by name.
// - if unnamed shared memory, can only give and/or get.
//
RequiredAccess &= (OBJ_GIVEABLE | OBJ_GETTABLE);
if (RequiredAccess != 0 &&
(MemoryObject->AllocationFlags & RequiredAccess) == 0
) {
return( ERROR_ACCESS_DENIED );
}
rc = Or2MapProtectionToFlags( Protection, &NewFlags );
if (rc != NO_ERROR) {
return( rc );
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: MapSharedMem( ToPid=%lX ) - MemoryObject (%lX)->BaseAddress = %lX\n",
Process->ProcessId,
MemoryObject,
MemoryObject->BaseAddress
);
}
#endif
//
// Create a shared memory reference object for this process and
// shared memory object descriptor.
//
MemoryProcessRef = Os2CreateProcessRefToSharedMemory( Process,
MemoryObject
);
//
// If unsuccessful, free the shared memory object descriptor if newly
// created by caller and return an error code.
//
if (MemoryProcessRef == NULL) {
if (MemoryObject->RefCount == 0) {
ldrFreeSel(
MemoryObject->Index,
(MemoryObject->RegionSize + (_64K - 1)) / _64K
);
Os2FreeSharedMemoryObject( MemoryObject );
}
return( ERROR_NOT_ENOUGH_MEMORY );
}
//
// Assume success and attempt to map a view of the shared memory
// into the specified process's address space.
//
rc = NO_ERROR;
BaseAddress = MemoryObject->BaseAddress;
Status = NtMapViewOfSection( MemoryObject->SectionHandle,
Process->ProcessHandle,
&BaseAddress,
0,
0,
NULL,
&RegionSize,
ViewUnmap,
0,
Protection
);
//
// If unsuccessful, special logic.
//
if (!NT_SUCCESS( Status )) {
if (Status == STATUS_CONFLICTING_ADDRESSES &&
(ProcessIsSelf || MemoryProcessRef->RefCount > 1)
) {
//
// If reason for failure is already mapped, then change the
// page protection instead.
//
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: ProtectSharedMem( ToPid=%lX ) - MemoryObject (%lX)->BaseAddress = %lX Flags= %lX\n",
Process->ProcessId,
MemoryObject,
MemoryObject->BaseAddress,
Protection
);
}
#endif
//
// First figure out how big the memory object is, and the page
// protection it was allocated with.
//
BaseAddress = MemoryObject->BaseAddress;
Status = NtQueryVirtualMemory( Process->ProcessHandle,
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (NT_SUCCESS( Status ) && MemoryInformation.State != MEM_RESERVE) {
//
// New protection flags are the OR of the old and new flags.
//
rc = Or2MapProtectionToFlags( MemoryInformation.Protect,
&OldFlags
);
NewFlags |= OldFlags;
//
// Now change the page protection for those pages.
//
Or2MapFlagsToProtection( NewFlags, &Protection );
Status = NtProtectVirtualMemory( Process->ProcessHandle,
&BaseAddress,
&MemoryInformation.RegionSize,
Protection,
&OldProtection
);
}
}
else {
//
// Not already mapped, so free the shared memory reference
// object we created.
//
Os2FreeProcessRefToSharedMemory( Process, MemoryProcessRef );
}
//
// If unsuccessful, map status code.
//
if (!NT_SUCCESS( Status )) {
switch (Status) {
case STATUS_OBJECT_NAME_COLLISION:
rc = ERROR_ALREADY_EXISTS;
break;
default:
rc = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
}
}
}
if (rc == NO_ERROR) {
MemoryProcessRef->AllocationFlags |= NewFlags;
}
//
// Return OS/2 error code.
//
return( rc );
}
typedef enum _LDTENTRY_TYPE {
INVALID, EXECUTE_CODE, EXECUTE_READ_CODE, READ_DATA, READ_WRITE_DATA
} LDTENTRY_TYPE;
NTSTATUS
Os2SetLDT
(
HANDLE Process,
LDTENTRY_TYPE Type,
PVOID BaseAddress,
ULONG Limit
)
{
/* 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;
ULONG Sel = FLATTOSEL(BaseAddress);
LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
tmp = (PULONG)(LDTDesc);
//
// zero the descriptor
//
*tmp++ = 0;
*tmp = 0;
switch (Type) {
case INVALID:
break;
case READ_WRITE_DATA:
LDTDesc->d_access = 0xf3; // read/write, present, ring 3
LDTDesc->d_limit = (USHORT)(Limit);
LDTDesc->d_loaddr = (USHORT)((ULONG)BaseAddress & 0xffff);
LDTDesc->d_hiaddr = (UCHAR)(((ULONG)BaseAddress >> 16) & 0xff);
LDTDesc->d_extaddr = (UCHAR)(((ULONG)BaseAddress >> 24) & 0xff);
break;
default:
{
#if DBG
DbgPrint ("OS2SRV: Os2SetLDT - 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( Process,
ProcessLdtInformation,
&LdtInformation,
sizeof(PROCESS_LDT_INFORMATION)
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("OS2SRV: Os2SetLDT - Invalid request, status=%x\n", Status);
#endif
return (Status);
}
return (STATUS_SUCCESS);
}
// This function remove memory object, but not remove LDT entry.
ULONG Os2FreeMemory(
IN POS2_THREAD t,
PVOID BaseAddress,
PBOOLEAN pUnmapped
)
{
NTSTATUS Status;
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
ULONG ReturnedErrorValue = ERROR_INVALID_ADDRESS;
*pUnmapped = FALSE;
ListHead = &t->Process->SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryProcessRef = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
ListNext = ListNext->Flink;
if (MemoryProcessRef->SharedMemoryObject->BaseAddress == BaseAddress ) {
ReturnedErrorValue = NO_ERROR;
//
// Force free if unnamed shared memory. Otherwise only free if
// this is last reference to named shared memory by this process.
//
if (MemoryProcessRef->SharedMemoryObject->SectionName.Buffer == NULL) {
MemoryProcessRef->RefCount = 1;
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - Os2FreeMememory( %lX ) - MemoryRefObject = %lX Count = %ld\n",
t->Process->ProcessId,
BaseAddress,
MemoryProcessRef,
MemoryProcessRef->RefCount
);
}
#endif
if (Os2FreeProcessRefToSharedMemory( t->Process, MemoryProcessRef )) {
Status = NtUnmapViewOfSection( t->Process->ProcessHandle,
BaseAddress
);
if (!NT_SUCCESS( Status )) {
switch (Status) {
case STATUS_OBJECT_NAME_COLLISION:
ReturnedErrorValue = ERROR_ALREADY_EXISTS;
break;
default:
ReturnedErrorValue = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
}
}
*pUnmapped = TRUE;
}
break;
}
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - Os2FreeMemory( %lX ) - failed, rc = %ld\n",
t->Process->ProcessId,
BaseAddress,
ReturnedErrorValue
);
}
}
#endif
return( ReturnedErrorValue );
}
// Remove memory object and LDT entry if the client process ask for the last
// service.
BOOLEAN Os2DosFreeMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSFREEMEM_MSG a = &m->u.DosFreeMem;
BOOLEAN Unmapped;
NTSTATUS Status;
m->ReturnedErrorValue = Os2FreeMemory(t, a->BaseAddress, &Unmapped);
if (Unmapped && a->RemoveLDTEntry && (m->ReturnedErrorValue == NO_ERROR)) {
Status = Os2SetLDT(
t->Process->ProcessHandle,
INVALID,
a->BaseAddress,
0L);
if (!NT_SUCCESS(Status)) {
m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
}
}
return( TRUE );
}
BOOLEAN Os2DosGiveSharedMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSGIVESHAREDMEM_MSG a = &m->u.DosGiveSharedMem;
POS2_PROCESS Process;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
NTSTATUS Status;
MEMORY_BASIC_INFORMATION MemoryInformation;
Process = Os2LocateProcessByProcessId( m,
t->Process,
a->ProcessId,
FALSE
);
if (Process == NULL) {
return( TRUE );
}
MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, t->Process );
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - MemoryObject = %lX\n",
t->Process->ProcessId,
a->BaseAddress,
Process->ProcessId,
MemoryObject
);
}
#endif
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
Process,
(BOOLEAN)(t->Process == Process),
OBJ_GIVEABLE,
a->PageProtection
);
}
else {
Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
a->BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (NT_SUCCESS( Status ) && MemoryInformation.State == MEM_PRIVATE) {
m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - failed, rc = %ld\n",
t->Process->ProcessId,
a->BaseAddress,
Process->ProcessId,
m->ReturnedErrorValue
);
}
}
#endif
return( TRUE );
}
BOOLEAN Os2DosGetSharedMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSGETSHAREDMEM_MSG a = &m->u.DosGetSharedMem;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, NULL );
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - MemoryObject = %lX\n",
t->Process->ProcessId,
a->BaseAddress,
MemoryObject
);
}
#endif
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
t->Process,
TRUE,
OBJ_GETTABLE,
a->PageProtection
);
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - failed, rc = %ld\n",
t->Process->ProcessId,
a->BaseAddress,
m->ReturnedErrorValue
);
}
}
#endif
return( TRUE );
}
BOOLEAN Os2DosGetNamedSharedMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSGETNAMEDSHAREDMEM_MSG a = &m->u.DosGetNamedSharedMem;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
if (a->ObjectName.Buffer == NULL) {
m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
return( TRUE );
}
MemoryObject = Os2FindNamedSharedMemoryObject (&a->ObjectName);
if (MemoryObject == NULL) {
m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
return(TRUE);
}
a->BaseAddress = MemoryObject->BaseAddress;
MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, NULL );
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - MemoryObject (%lX)->BaseAddress = %lX\n",
t->Process->ProcessId,
&a->ObjectName,
MemoryObject,
MemoryObject->BaseAddress
);
}
#endif
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
t->Process,
TRUE,
0,
a->PageProtection
);
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - failed, rc = %ld\n",
t->Process->ProcessId,
&a->ObjectName,
m->ReturnedErrorValue
);
}
}
#endif
return( TRUE );
}
BOOLEAN Os2DosAllocSharedMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSALLOCSHAREDMEM_MSG a = &m->u.DosAllocSharedMem;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE SectionHandle;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
ULONG AllocationAttributes;
UNICODE_STRING ObjectName_U;
LARGE_INTEGER SectionSize;
PVOID BaseAddress;
ULONG Index;
ULONG ReserveSize;
// Resurve 64K for the non-huge segment. For the huge segment resurve
// the amount that the client asks.
ReserveSize = a->RegionSize < _64K ? _64K : a->RegionSize;
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
if (a->ObjectName.Buffer != NULL) {
//
// UNICODE conversion -
//
Status = Or2MBStringToUnicodeString(
&ObjectName_U,
&a->ObjectName,
TRUE);
ASSERT (NT_SUCCESS(Status));
ObjectAttributes.ObjectName = &ObjectName_U;
}
if (a->Flags & PAG_COMMIT) {
AllocationAttributes = SEC_COMMIT;
}
else {
AllocationAttributes = SEC_RESERVE;
}
SectionSize.LowPart = ReserveSize;
SectionSize.HighPart = 0;
Status = NtCreateSection( &SectionHandle,
SECTION_ALL_ACCESS,
&ObjectAttributes,
&SectionSize,
PAGE_EXECUTE_READWRITE,
AllocationAttributes,
NULL
);
if (a->ObjectName.Buffer != NULL) {
RtlFreeUnicodeString (&ObjectName_U);
}
if (!NT_SUCCESS( Status )) {
switch (Status) {
case STATUS_OBJECT_NAME_COLLISION:
m->ReturnedErrorValue = ERROR_ALREADY_EXISTS;
break;
default:
m->ReturnedErrorValue = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
}
return( TRUE );
}
Index = ldrAllocateSel((a->RegionSize + (_64K - 1)) / _64K,
TRUE // Top down allocation
);
if (Index == 0xffffffff) {
// selector allocation failed
NtClose( SectionHandle );
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
return( TRUE );
}
BaseAddress = SELTOFLAT(Index);
a->BaseAddress = BaseAddress;
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosAllocSharedMem( %s, %ld ), BaseAddress = %lX\n",
t->Process->ProcessId,
ObjectAttributes.ObjectName ? a->ObjectName.Buffer : "(null)",
ReserveSize,
a->BaseAddress
);
}
#endif
MemoryObject = Os2CreateSharedMemoryObject( m,
a->BaseAddress,
Index,
ReserveSize,
SectionHandle,
a->Flags,
&a->ObjectName
);
if (MemoryObject != NULL) {
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
t->Process,
TRUE,
0,
a->PageProtection
);
}
if (m->ReturnedErrorValue != NO_ERROR) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosAllocSharedMem( %s, %ld ) - failed, rc = %ld\n",
t->Process->ProcessId,
ObjectAttributes.ObjectName ? a->ObjectName.Buffer : "(null)",
a->RegionSize,
m->ReturnedErrorValue
);
}
#endif
NtClose( SectionHandle );
}
else {
// Memory was allocated successfully
if (a->CreateLDTEntry) {
BOOLEAN Unmapped;
Status = Os2SetLDT(
t->Process->ProcessHandle,
READ_WRITE_DATA,
BaseAddress,
a->RegionSize - 1);
if (!NT_SUCCESS(Status)) {
Os2FreeMemory(t, BaseAddress, &Unmapped);
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
return( TRUE );
}
BOOLEAN Os2InternalQueryVirtualMemory(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_QUERYVIRTUALMEMORY_MSG a = &m->u.QueryVirtualMemory;
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
a->SharedMemory = FALSE;
ListHead = &t->Process->SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryProcessRef = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
ListNext = ListNext->Flink;
if (MemoryProcessRef->SharedMemoryObject->BaseAddress == a->BaseAddress) {
MemoryObject = MemoryProcessRef->SharedMemoryObject;
a->SharedMemory = TRUE;
a->AllocationFlags = MemoryProcessRef->AllocationFlags;
a->IsHuge = MemoryObject->IsHuge;;
a->MaxSegments = MemoryObject->MaxSegments;
a->NumOfSegments = MemoryObject->NumOfSegments;
a->SizeOfPartialSeg = MemoryObject->SizeOfPartialSeg;
a->Sizeable = MemoryObject->Sizeable;
break;
}
}
return( TRUE );
}
BOOLEAN Os2InternalMarkSharedMemAsHuge(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_MARKSHAREDMEMASHUGE_MSG a = &m->u.MarkSharedMemAsHuge;
PLIST_ENTRY ListHead, ListNext;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
//
// Find a shared memory object with the specified base address
// in the list of shared memory objects.
//
ListHead = &Os2SharedMemoryList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MemoryObject = CONTAINING_RECORD( ListNext,
OS2_SHARED_MEMORY_OBJECT,
Link
);
if (MemoryObject->BaseAddress == a->BaseAddress) {
MemoryObject->IsHuge = TRUE;
MemoryObject->MaxSegments = a->MaxSegments;
MemoryObject->NumOfSegments = a->NumOfSegments;
MemoryObject->SizeOfPartialSeg = a->SizeOfPartialSeg;
MemoryObject->Sizeable = a->Sizeable;
m->ReturnedErrorValue = NO_ERROR;
return( TRUE );
}
ListNext = ListNext->Flink;
}
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
return( TRUE );
}
APIRET Os2CopyLDT(
HANDLE SourceProcessHandle,
HANDLE TargetProcessHandle,
ULONG Index,
ULONG NumOfEntriesToCopy
)
{
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;
NTSTATUS Status;
ULONG i;
//
// get source LDT entry
//
LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
for (i = 0; i < NumOfEntriesToCopy; i++) {
LdtInfo.Length = sizeof(LDT_ENTRY);
LdtInfo.Start = (Index + (i*8)) & 0xfffffff8;
Status = NtQueryInformationProcess(
SourceProcessHandle,
ProcessLdtInformation,
&LdtInfo,
sizeof(PROCESS_LDT_INFORMATION),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("Os2DosCopySeg NtQueryInformationProcess failed. \n");
#endif
return(ERROR_INVALID_PARAMETER);
}
//
// Copy of a non huge entry should always be for a valid segment
//
if ((i == 0) && ((LDTDesc->d_access & 0x80) != 0x80)) {
return(ERROR_INVALID_SEGMENT_NUMBER);
}
//
// Update The Target LDT
//
LdtInfo.Length = sizeof(LDT_ENTRY);
LdtInfo.Start = (Index + (i*8)) & 0xfffffff8;
Status = NtSetInformationProcess(
TargetProcessHandle,
ProcessLdtInformation,
&LdtInfo,
sizeof(PROCESS_LDT_INFORMATION)
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("Os2DosReallocSharedMem NtSetInformationProcess failed. %lx\n",
Status);
#endif
return(ERROR_INVALID_PARAMETER);
}
}
return(NO_ERROR);
}
BOOLEAN Os2DosGiveSeg(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_GIVESEG_MSG a = &m->u.DosGiveSeg;
POS2_PROCESS Process;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
NTSTATUS Status;
MEMORY_BASIC_INFORMATION MemoryInformation;
PVOID BaseAddress;
ULONG EntriesToCopy;
m->ReturnedErrorValue = NO_ERROR;
Process = Os2LocateProcessByProcessId( m,
t->Process,
a->TargetPid,
FALSE
);
if (Process == NULL) {
m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
return( TRUE );
}
BaseAddress = SELTOFLAT((a->Selector));
MemoryObject = Os2FindSharedMemoryObject( BaseAddress, t->Process );
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGiveSeg( %lX, ToPid=%lX ) - MemoryObject = %lX\n",
t->Process->ProcessId,
BaseAddress,
Process->ProcessId,
MemoryObject
);
}
#endif
Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (!NT_SUCCESS( Status )){
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
return( TRUE );
}
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject(
MemoryObject,
Process,
(BOOLEAN)(t->Process == Process),
OBJ_GIVEABLE,
MemoryInformation.Protect
);
}
else {
Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (NT_SUCCESS( Status ) && MemoryInformation.State == MEM_PRIVATE) {
m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - failed, rc = %ld\n",
t->Process->ProcessId,
BaseAddress,
Process->ProcessId,
m->ReturnedErrorValue
);
}
}
#endif
if (m->ReturnedErrorValue == NO_ERROR) {
if (MemoryObject->IsHuge) {
if (MemoryObject->MaxSegments != 0)
EntriesToCopy = MemoryObject->MaxSegments;
else {
EntriesToCopy = MemoryObject->NumOfSegments;
if (MemoryObject->SizeOfPartialSeg) {
++EntriesToCopy;
}
}
}
else
EntriesToCopy = 1;
m->ReturnedErrorValue = Os2CopyLDT(
t->Process->ProcessHandle,
Process->ProcessHandle,
a->Selector,
EntriesToCopy
);
}
return( TRUE );
}
BOOLEAN Os2DosGetSeg(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
PLIST_ENTRY ProcListHead, ProcListNext;
POS2_GETSEG_MSG a = &m->u.DosGetSeg;
POS2_PROCESS ProcessRef;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
PVOID BaseAddress;
MEMORY_BASIC_INFORMATION MemoryInformation;
BOOLEAN found;
NTSTATUS Status;
ULONG Index;
ULONG EntriesToCopy;
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;
BaseAddress = SELTOFLAT(a->Selector);
MemoryObject = Os2FindSharedMemoryObject( BaseAddress, NULL );
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetSeg( %lX ) - MemoryObject = %lX\n",
t->Process->ProcessId,
BaseAddress,
MemoryObject
);
}
#endif
Index = FLATTOSEL(BaseAddress);
//
// find a process that owns this segment.
//
found = FALSE;
ProcListHead = &Os2RootProcess->ListLink;
ProcListNext = ProcListHead->Flink;
while (ProcListNext != ProcListHead) {
ProcessRef = CONTAINING_RECORD( ProcListNext,
OS2_PROCESS,
ListLink
);
// get LDT entry
LdtInfo.Length = sizeof(LDT_ENTRY);
LdtInfo.Start = Index & 0xfffffff8;
LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
Status = NtQueryInformationProcess(
ProcessRef->ProcessHandle,
ProcessLdtInformation,
&LdtInfo,
sizeof(PROCESS_LDT_INFORMATION),
NULL
);
if (!NT_SUCCESS(Status)) {
m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
#if DBG
DbgPrint("Os2DosGetSeg NtQueryInformationProcess failed\n");
#endif
return(TRUE);
}
if (LDTDesc->d_access & 0x80) {
Status = NtQueryVirtualMemory( ProcessRef->ProcessHandle,
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if ( NT_SUCCESS(Status) &&
((MemoryInformation.Protect & PAGE_NOACCESS) != PAGE_NOACCESS)) {
found = TRUE;
break;
}
}
ProcListNext = ProcListNext->Flink;
} // process loop
if ((!NT_SUCCESS( Status )) || (!found)){
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
return( TRUE );
}
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
t->Process,
(BOOLEAN)(t->Process == ProcessRef),
OBJ_GETTABLE,
MemoryInformation.Protect
);
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - failed, rc = %ld\n",
t->Process->ProcessId,
BaseAddress,
m->ReturnedErrorValue
);
}
}
#endif
if (m->ReturnedErrorValue == NO_ERROR) {
if (MemoryObject->IsHuge) {
if (MemoryObject->MaxSegments != 0)
EntriesToCopy = MemoryObject->MaxSegments;
else {
EntriesToCopy = MemoryObject->NumOfSegments;
if (MemoryObject->SizeOfPartialSeg) {
++EntriesToCopy;
}
}
}
else
EntriesToCopy = 1;
m->ReturnedErrorValue = Os2CopyLDT(
ProcessRef->ProcessHandle,
t->Process->ProcessHandle,
a->Selector,
EntriesToCopy
);
}
return(TRUE);
}
BOOLEAN Os2DosGetShrSeg(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DOSGETSHRSEG_MSG a = &m->u.DosGetShrSeg;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
BOOLEAN Shared;
PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
POS2_PROCESS ProcessRef;
MEMORY_BASIC_INFORMATION MemoryInformation;
NTSTATUS Status;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
if (a->ObjectName.Buffer == NULL) {
m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
return( TRUE );
}
MemoryObject = Os2FindNamedSharedMemoryObject (&a->ObjectName);
if (MemoryObject == NULL) {
m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
return(TRUE);
}
a->Selector = MemoryObject->Index;
MemoryObject = Os2FindSharedMemoryObject( SELTOFLAT(a->Selector), NULL );
Shared = FALSE;
if (MemoryObject != NULL) {
#if DBG
IF_OS2_DEBUG( MEMORY ) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - MemoryObject (%lX)->BaseAddress = %lX\n",
t->Process->ProcessId,
&a->ObjectName,
MemoryObject,
MemoryObject->BaseAddress
);
}
#endif
m->ReturnedErrorValue = NO_ERROR;
// Loop on all OS/2 Process
ProcListHead = &Os2RootProcess->ListLink;
ProcListNext = ProcListHead->Flink;
while (ProcListNext != ProcListHead) {
// Loop on all Shared Memory references of an OS/2 process
ProcessRef = CONTAINING_RECORD( ProcListNext,
OS2_PROCESS,
ListLink
);
MemListHead = &ProcessRef->SharedMemoryList;
MemListNext = MemListHead->Flink;
while (MemListNext != MemListHead){
MemoryProcessRef = CONTAINING_RECORD( MemListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
if (MemoryProcessRef->SharedMemoryObject == MemoryObject) {
Status = NtQueryVirtualMemory( ProcessRef->ProcessHandle,
MemoryObject->BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if ( NT_SUCCESS(Status) &&
((MemoryInformation.Protect & PAGE_NOACCESS) !=
PAGE_NOACCESS)) {
Shared = TRUE;
break;
}
}
MemListNext = MemListNext->Flink;
} // process memory objects loop
if (Shared) {
break;
}
ProcListNext = ProcListNext->Flink;
} // process loop
}
else {
m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
}
if (Shared) {
m->ReturnedErrorValue =
Os2MapViewOfSharedMemoryObject( MemoryObject,
t->Process,
TRUE,
0,
MemoryInformation.Protect
);
}
if (m->ReturnedErrorValue == NO_ERROR) {
m->ReturnedErrorValue = Os2CopyLDT(
ProcessRef->ProcessHandle,
t->Process->ProcessHandle,
MemoryObject->Index,
1
);
}
#if DBG
IF_OS2_DEBUG( MEMORY ) {
if (m->ReturnedErrorValue != NO_ERROR) {
DbgPrint( "OS2SRV: Pid: %lX - DosGetShrSeg( %Z ) - failed, rc = %ld\n",
t->Process->ProcessId,
&a->ObjectName,
m->ReturnedErrorValue
);
}
}
#endif
return( TRUE );
}
APIRET Os2ResizeSharedMemory(
HANDLE ProcessHandle,
PVOID AllocFreeBaseAddress, // start address of new allocation/free
ULONG Index, // Selector of resized segment
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;
// according 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
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);
}
BOOLEAN Os2DosReallocSharedMem(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
POS2_PROCESS ProcessRef;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
ULONG Index;
APIRET rc;
BOOLEAN LdrModified;
POS2_REALLOCSHAREDMEM_MSG a = &m->u.ReallocSharedMem;
// mark as not shared
a->SharedMemory = FALSE;
m->ReturnedErrorValue = NO_ERROR;
rc = NO_ERROR;
// Loop on all OS/2 Process
ProcListHead = &Os2RootProcess->ListLink;
ProcListNext = ProcListHead->Flink;
while (ProcListNext != ProcListHead) {
// Loop on all Shared Memory references of an OS/2 process
ProcessRef = CONTAINING_RECORD( ProcListNext,
OS2_PROCESS,
ListLink
);
MemListHead = &ProcessRef->SharedMemoryList;
MemListNext = MemListHead->Flink;
while (MemListNext != MemListHead){
MemoryProcessRef = CONTAINING_RECORD( MemListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
MemoryObject = MemoryProcessRef->SharedMemoryObject;
if (MemoryObject->BaseAddress == a->BaseAddress) {
a->SharedMemory = TRUE;
rc = Os2ResizeSharedMemory(
ProcessRef->ProcessHandle,
a->AllocFreeBaseAddress,
MemoryObject->Index,
a->CurrentSize,
a->NewLdtLimit,
a->NewRegionSize,
a->Flags
);
break;
}
MemListNext = MemListNext->Flink;
} // process memory objects loop
if (rc != NO_ERROR) {
if (ProcessRef->ProcessHandle == t->Process->ProcessHandle) {
#if DBG
DbgPrint ("OS2SRV: Os2DosReallocSharedMem failed due to current process (PID %d). \n",
ProcessRef->ProcessId );
#endif
m->ReturnedErrorValue = rc;
return(TRUE);
} else {
#if DBG
DbgPrint ("OS2SRV: Os2ResizeSharedMem failed due to other process (PID %d). \n",
ProcessRef->ProcessId );
#endif
}
}
ProcListNext = ProcListNext->Flink;
} // process loop
if (a->SharedMemory == FALSE) {
//
// This is a shared segment of the loader so loop on all process
// and fix all the references
//
ProcListHead = &Os2RootProcess->ListLink;
ProcListNext = ProcListHead->Flink;
while (ProcListNext != ProcListHead) {
ProcessRef = CONTAINING_RECORD( ProcListNext,
OS2_PROCESS,
ListLink
);
Index = FLATTOSEL((a->BaseAddress));
rc = Os2ResizeSharedMemory(
ProcessRef->ProcessHandle,
a->AllocFreeBaseAddress,
Index,
a->CurrentSize,
a->NewLdtLimit,
a->NewRegionSize,
a->Flags
);
//
// ERROR_INVALID_SEGMENT_NUMBER is an internal status returned
// by Os2ResizeSharedMemory when the P bit in the ldt is 0.
// This marks that the ldt entry is not in use
//
if (rc == NO_ERROR) {
//
// Check if the shared data segment of the loader was already
// modified for this segment.
// If not, modify it. Otherwise, skip the modification
//
if (a->SharedMemory == FALSE) {
LdrModified = LDRModifySizeOfSharedSegment(t, Index, a->NewLdtLimit);
ASSERT(LdrModified == TRUE);
}
a->SharedMemory = TRUE;
}
else if (rc == ERROR_INVALID_SEGMENT_NUMBER) {
rc = NO_ERROR;
}
ProcListNext = ProcListNext->Flink;
} // process loop
if (a->SharedMemory) {
m->ReturnedErrorValue = NO_ERROR;
} else {
m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
}
}
return( TRUE );
}
APIRET
AllocHugeMem(
HANDLE ProcessHandle,
ULONG BaseAddress,
ULONG Size,
ULONG Protect
)
{
NTSTATUS Status;
PVOID TmpAllocFreeBaseAddress = (PVOID)BaseAddress;
Status = NtAllocateVirtualMemory(
ProcessHandle,
&TmpAllocFreeBaseAddress,
1,
&Size,
MEM_COMMIT,
Protect
);
if (NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)) {
return(NO_ERROR);
}
else {
return(ERROR_ACCESS_DENIED);
}
}
//
// Utility routines to handle LDT setting
//
NTSTATUS
SetEntryLDT(
HANDLE ProcessHandle,
ULONG BaseAddress,
ULONG Size
)
{
/* 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;
ULONG Sel;
PROCESS_LDT_INFORMATION LdtInformation;
NTSTATUS Status;
Sel = FLATTOSEL(BaseAddress);
LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
tmp = (PULONG)(LDTDesc);
//
// zero the descriptor
//
*tmp++ = 0;
*tmp = 0;
LDTDesc->d_access = 0xf3; // read/write, present, ring 3
LDTDesc->d_limit = (USHORT)(Size-1);
LDTDesc->d_loaddr = (USHORT)(BaseAddress & 0xffff);
LDTDesc->d_hiaddr = (UCHAR)((BaseAddress >> 16) & 0xff);
LDTDesc->d_extaddr = (UCHAR)((BaseAddress >> 24) & 0xff);
//
// adjust LDTDesc by the LDT base and the index of this selector
//
LdtInformation.Length = sizeof(LDT_ENTRY);
LdtInformation.Start = Sel & 0xfffffff8;
Status = NtSetInformationProcess( ProcessHandle,
ProcessLdtInformation,
&LdtInformation,
sizeof(PROCESS_LDT_INFORMATION)
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("OS2SRV: SetEntryLDT failed, Status=%x\n", Status);
#endif
return (STATUS_INVALID_PARAMETER);
}
return (STATUS_SUCCESS);
}
NTSTATUS
ClearEntryLDT(
HANDLE ProcessHandle,
ULONG BaseAddress
)
{
/* 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;
ULONG Sel;
PROCESS_LDT_INFORMATION LdtInformation;
NTSTATUS Status;
Sel = FLATTOSEL(BaseAddress);
LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
tmp = (PULONG)(LDTDesc);
//
// zero the descriptor
//
*tmp++ = 0;
*tmp = 0;
//
// adjust LDTDesc by the LDT base and the index of this selector
//
LdtInformation.Length = sizeof(LDT_ENTRY);
LdtInformation.Start = Sel & 0xfffffff8;
Status = NtSetInformationProcess( ProcessHandle,
ProcessLdtInformation,
&LdtInformation,
sizeof(PROCESS_LDT_INFORMATION)
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("OS2SRV: ClearEntryLDT failed, Status=%x\n", Status);
#endif
return (STATUS_INVALID_PARAMETER);
}
return (STATUS_SUCCESS);
}
APIRET Os2ResizeSharedHuge(
HANDLE ProcessHandle,
POS2_SHARED_MEMORY_OBJECT MemoryObject,
ULONG NewNumOfSegments,
ULONG NewSizeOfPartialSeg
)
{
ULONG BaseAddress;
ULONG cNewSegs;
ULONG CommitSize;
ULONG cDelSegs;
ULONG RoundedUpCurrentPartial;
ULONG RoundedUpNewPartial;
ULONG Op = 0;
ULONG i;
APIRET rc = NO_ERROR;
// according to the new size allocate/free memory
if (MemoryObject->SizeOfPartialSeg != 0) {
Op |= H_CUR_PARTIAL;
}
if (NewSizeOfPartialSeg != 0) {
Op |= H_NEW_PARTIAL;
}
if (NewNumOfSegments > MemoryObject->NumOfSegments) {
Op |= H_SEG_INC;
}
else if (NewNumOfSegments < MemoryObject->NumOfSegments) {
Op |= H_SEG_DEC;
}
switch (Op) {
case H_SAME_SEG_NO_PARTIAL:
break;
case H_SAME_SEG_NEW_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
rc = AllocHugeMem(ProcessHandle, BaseAddress,
NewSizeOfPartialSeg, PAGE_READWRITE);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Set LDT entry
//
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
case H_SAME_SEG_DEL_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
//
// Set LDT entry
//
ClearEntryLDT(ProcessHandle, BaseAddress);
break;
case H_SAME_SEG_CHG_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
if (RoundedUpNewPartial > RoundedUpCurrentPartial) {
rc = AllocHugeMem(ProcessHandle,
BaseAddress + RoundedUpCurrentPartial,
RoundedUpNewPartial - RoundedUpCurrentPartial,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
//
// Set LDT entry
//
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
case H_INC_SEG_NO_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
cNewSegs = NewNumOfSegments - MemoryObject->NumOfSegments;
CommitSize = cNewSegs * _64K;
rc = AllocHugeMem(ProcessHandle,
BaseAddress,
CommitSize,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
}
break;
case H_INC_SEG_NEW_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
cNewSegs = NewNumOfSegments - MemoryObject->NumOfSegments;
CommitSize = cNewSegs * _64K + NewSizeOfPartialSeg;
rc = AllocHugeMem(ProcessHandle,
BaseAddress,
CommitSize,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
}
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
case H_INC_SEG_DEL_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
if (_64K - RoundedUpCurrentPartial) {
rc = AllocHugeMem(ProcessHandle,
BaseAddress + RoundedUpCurrentPartial,
_64K - RoundedUpCurrentPartial,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
cNewSegs = NewNumOfSegments - (MemoryObject->NumOfSegments + 1);
if (cNewSegs == 0) {
return(NO_ERROR);
}
BaseAddress += _64K;
CommitSize = cNewSegs * _64K;
rc = AllocHugeMem(ProcessHandle,
BaseAddress,
CommitSize,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
}
break;
case H_INC_SEG_CHG_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
if (_64K - RoundedUpCurrentPartial) {
rc = AllocHugeMem(ProcessHandle,
BaseAddress + RoundedUpCurrentPartial,
_64K - RoundedUpCurrentPartial,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
cNewSegs = NewNumOfSegments - (MemoryObject->NumOfSegments + 1);
BaseAddress += _64K;
if (cNewSegs != 0) {
CommitSize = cNewSegs * _64K;
rc = AllocHugeMem(ProcessHandle,
BaseAddress,
CommitSize,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
SetEntryLDT(ProcessHandle, BaseAddress, _64K);
}
}
rc = AllocHugeMem(ProcessHandle,
BaseAddress,
NewSizeOfPartialSeg,
PAGE_READWRITE
);
if (rc != NO_ERROR) {
#if DBG
IF_OS2_DEBUG ( MEMORY ) {
DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
case H_DEC_SEG_NO_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
cDelSegs = MemoryObject->NumOfSegments - NewNumOfSegments;
//
// Clear LDT entry
//
for (i = 0; i < cDelSegs; i++, BaseAddress += _64K) {
ClearEntryLDT(ProcessHandle, BaseAddress);
}
break;
case H_DEC_SEG_NEW_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * (NewNumOfSegments+1));
cDelSegs = MemoryObject->NumOfSegments - (NewNumOfSegments+1);
if (cDelSegs != 0) {
//
// Clear LDT entry
//
for (i = 0; i < cDelSegs; i++, BaseAddress += _64K) {
ClearEntryLDT(ProcessHandle, BaseAddress);
}
}
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
//
// Set LDT entry
//
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
case H_DEC_SEG_DEL_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
cDelSegs = MemoryObject->NumOfSegments - NewNumOfSegments;
//
// Clear LDT entry
//
for (i = 0; i <= cDelSegs; i++, BaseAddress += _64K) {
ClearEntryLDT(ProcessHandle, BaseAddress);
}
break;
case H_DEC_SEG_CHG_PARTIAL:
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * (NewNumOfSegments+1));
cDelSegs = MemoryObject->NumOfSegments - (NewNumOfSegments+1);
//
// Clear LDT entry
//
for (i = 0; i <= cDelSegs; i++, BaseAddress += _64K) {
ClearEntryLDT(ProcessHandle, BaseAddress);
}
BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
//
// Set LDT entry
//
SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
break;
}
return(rc);
}
BOOLEAN Os2InternalReallocSharedHuge(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
POS2_PROCESS ProcessRef;
POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
POS2_SHARED_MEMORY_OBJECT MemoryObject;
APIRET rc;
POS2_REALLOCSHAREDHUGE_MSG a = &m->u.ReallocSharedHuge;
m->ReturnedErrorValue = NO_ERROR;
rc = NO_ERROR;
// Loop on all OS/2 Process
ProcListHead = &Os2RootProcess->ListLink;
ProcListNext = ProcListHead->Flink;
while (ProcListNext != ProcListHead) {
// Loop on all Shared Memory references of an OS/2 process
ProcessRef = CONTAINING_RECORD( ProcListNext,
OS2_PROCESS,
ListLink
);
MemListHead = &ProcessRef->SharedMemoryList;
MemListNext = MemListHead->Flink;
while (MemListNext != MemListHead){
MemoryProcessRef = CONTAINING_RECORD( MemListNext,
OS2_SHARED_MEMORY_PROCESS_REF,
Link
);
MemoryObject = MemoryProcessRef->SharedMemoryObject;
if (MemoryObject->BaseAddress == a->BaseAddress) {
rc = Os2ResizeSharedHuge(
ProcessRef->ProcessHandle,
MemoryObject,
a->NumOfSegments,
a->SizeOfPartialSeg
);
break;
}
MemListNext = MemListNext->Flink;
} // process memory objects loop
if (rc != NO_ERROR) {
#if DBG
DbgPrint ("Os2InternalReallocSharedHuge Memory Reallocation failed.\n");
#endif
m->ReturnedErrorValue = rc;
return(TRUE);
}
ProcListNext = ProcListNext->Flink;
} // process loop
//
// Update the MemoryObject information to contain the new size of the
// Huge shared segment
//
MemoryObject->NumOfSegments = a->NumOfSegments;
MemoryObject->SizeOfPartialSeg = a->SizeOfPartialSeg;
return( TRUE );
}