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.
 
 
 
 
 
 

636 lines
17 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dllvm.c
Abstract:
This module implements the OS/2 V2.0 Memory Management API Calls
Author:
Steve Wood (stevewo) 02-Nov-1989
Revision History:
YaronS 18-APR-1991 - modified DosAllocMem such that all allocations
are confined to a 512M address space. (set zero bits to 3 when
call NtAllocateVirtualMemory.
YaronS 6-SEP-1992 - flexible base 512M
--*/
#define INCL_OS2V20_MEMORY
#define INCL_OS2V20_ERRORS
#include "os2dll.h"
#include "os2dll16.h"
APIRET
DosAllocMem(
OUT PVOID *BaseAddress,
IN ULONG RegionSize,
IN ULONG Flags
)
{
NTSTATUS Status;
// PVOID MemoryAddress;
APIRET rc;
ULONG AllocationType, Protect;
ULONG Bits;
// PVOID FirstSharedBaseAddress;
if (RegionSize == 0 || (Flags & ~(fALLOC|PAG_GUARD))) {
return( ERROR_INVALID_PARAMETER );
}
rc = Or2MapFlagsToProtection( Flags, &Protect );
if (rc != NO_ERROR) {
return( rc );
}
if (Flags & PAG_COMMIT) {
AllocationType = MEM_COMMIT;
}
else {
AllocationType = MEM_RESERVE;
}
//
// probe address pointer.
//
try {
Od2ProbeForWrite(BaseAddress, sizeof(ULONG), 1);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (Flags & OBJ_TILE)
Bits = 1;
else
Bits = 0;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
BaseAddress,
Bits,
&RegionSize,
AllocationType,
Protect
);
if (!NT_SUCCESS( Status )) {
return( ERROR_NOT_ENOUGH_MEMORY );
}
return( NO_ERROR );
}
BOOLEAN
Od2ValidateBaseAddress(
PVOID BaseAddress,
PMEMORY_BASIC_INFORMATION MemoryInformation
)
{
NTSTATUS Status;
//
// If BaseAddress is within the first 64K of memory then it is not
// a valid address.
//
if (((ULONG)BaseAddress & ~Od2NtSysInfo.AllocationGranularity) == 0) {
return( FALSE );
}
Status = NtQueryVirtualMemory( NtCurrentProcess(),
BaseAddress,
MemoryBasicInformation,
MemoryInformation,
sizeof( *MemoryInformation ),
NULL
);
if (!NT_SUCCESS( Status ) || BaseAddress != MemoryInformation->BaseAddress) {
return( FALSE );
}
else {
return( TRUE );
}
}
// The parameter pRemoveLDTEntry is the pointer to boolean variable. It has
// the value "LDT entry wasn't removed yet".
// So on the entry of the function it will have value TRUE only in the case
// that LDT entry must be removed. On the exit it will be TRUE only in the
// case that LDT entry wasn't removed.
APIRET
DosFreeMem(
PVOID BaseAddress,
PBOOLEAN pRemoveLDTEntry
)
{
OS2_API_MSG m;
POS2_DOSFREEMEM_MSG a = &m.u.DosFreeMem;
ULONG RegionSize = 0;
NTSTATUS Status;
Status = NtFreeVirtualMemory( NtCurrentProcess(),
&BaseAddress,
&RegionSize,
MEM_RELEASE
);
if (NT_SUCCESS( Status )) {
return( NO_ERROR );
}
else
if ((Status == STATUS_UNABLE_TO_FREE_VM) ||
(Status == STATUS_UNABLE_TO_DELETE_SECTION)) {
// Shared memory.
APIRET rc;
a->BaseAddress = BaseAddress;
// If LDT entry must be removed by the server.
a->RemoveLDTEntry = *pRemoveLDTEntry;
rc = Od2CallSubsystem( &m, NULL, Os2FreeMem, sizeof( *a ) );
if (rc == NO_ERROR) {
// If server succeeded to remove LDT entry, sign that it must not
// be removed any more.
*pRemoveLDTEntry = FALSE;
}
return(rc);
}
else {
return( ERROR_INVALID_ADDRESS );
}
}
APIRET
DosSetMem(
IN PVOID BaseAddress,
IN ULONG RegionSize,
IN ULONG Flags
)
{
OS2_API_MSG m;
POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
ULONG Protect, OldProtect;
APIRET rc;
MEMORY_BASIC_INFORMATION MemoryInformation;
NTSTATUS Status;
if (RegionSize == 0) {
return( ERROR_INVALID_PARAMETER );
}
if (Flags != PAG_DECOMMIT
&& (((Flags & (fPERM | PAG_DEFAULT)) == 0) ||
((Flags & (~(fSET|PAG_GUARD) | PAG_DECOMMIT)) != 0) ||
((Flags & (fPERM|PAG_GUARD)) && (Flags & PAG_DEFAULT))
)
) {
return( ERROR_INVALID_PARAMETER );
}
if (Flags == PAG_DECOMMIT) {
Status = NtFreeVirtualMemory( NtCurrentProcess(),
&BaseAddress,
&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 ((Status == STATUS_UNABLE_TO_FREE_VM) ||
(Status == STATUS_UNABLE_TO_DELETE_SECTION)) {
//BUGBUG - aren't there cases where the process is the last one
// to use this memory ? If so, why do we get this error
// from NT (maybe os2srv is holding the section by error).
Status = STATUS_SUCCESS;
}
else
if (Status == STATUS_UNABLE_TO_DECOMMIT_VM) {
return( ERROR_ACCESS_DENIED );
}
}
else {
if (Flags & PAG_DEFAULT) {
a->BaseAddress = BaseAddress;
if (Od2CallSubsystem( &m,
NULL,
Oi2QueryVirtualMemory,
sizeof( *a )
)
) {
return( m.ReturnedErrorValue );
}
if (!a->SharedMemory) {
Status = NtQueryVirtualMemory( NtCurrentProcess(),
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (MemoryInformation.State == MEM_FREE) {
return( ERROR_INVALID_ADDRESS );
}
Protect = MemoryInformation.AllocationProtect;
}
else {
rc = Or2MapFlagsToProtection( a->AllocationFlags, &Protect );
if (rc != NO_ERROR) {
return( rc );
}
}
}
else {
rc = Or2MapFlagsToProtection( Flags, &Protect );
if (rc != NO_ERROR) {
return( rc );
}
}
if (Flags & PAG_COMMIT) {
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&BaseAddress,
1,
&RegionSize,
MEM_COMMIT,
Protect
);
if (Status == STATUS_ALREADY_COMMITTED) {
Status = STATUS_SUCCESS;
}
}
else {
Status = NtProtectVirtualMemory( NtCurrentProcess(),
&BaseAddress,
&RegionSize,
Protect,
&OldProtect
);
if (Status == STATUS_NOT_COMMITTED) {
return( ERROR_ACCESS_DENIED );
}
}
}
if (NT_SUCCESS( Status )) {
return( NO_ERROR );
}
else
if (Status == STATUS_INVALID_PARAMETER) {
return( ERROR_INVALID_ADDRESS );
}
else {
return( Or2MapNtStatusToOs2Error( Status, ERROR_INVALID_ADDRESS ) );
}
}
APIRET
DosGiveSharedMem(
IN PVOID BaseAddress,
IN PID ProcessId,
IN ULONG Flags
)
{
OS2_API_MSG m;
POS2_DOSGIVESHAREDMEM_MSG a = &m.u.DosGiveSharedMem;
MEMORY_BASIC_INFORMATION MemoryInformation;
APIRET rc;
if (!Od2ValidateBaseAddress( BaseAddress, &MemoryInformation )) {
return( ERROR_INVALID_ADDRESS );
}
if ((Flags & fPERM) == 0 || (Flags & ~(fGIVESHR|PAG_GUARD))) {
return( ERROR_INVALID_PARAMETER );
}
if (MemoryInformation.State == MEM_PRIVATE) {
return( ERROR_ACCESS_DENIED );
}
if (ProcessId == 0) {
return( ERROR_INVALID_PROCID );
}
rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
if (rc != NO_ERROR) {
return( rc );
}
a->BaseAddress = BaseAddress;
a->ProcessId = ProcessId;
Od2CallSubsystem( &m, NULL, Os2GiveSharedMem, sizeof( *a ) );
return(m.ReturnedErrorValue);
}
APIRET
DosGetSharedMem(
IN PVOID BaseAddress,
IN ULONG Flags
)
{
OS2_API_MSG m;
POS2_DOSGETSHAREDMEM_MSG a = &m.u.DosGetSharedMem;
APIRET rc;
if ((Flags & fPERM) == 0 || (Flags & ~(fGETSHR|PAG_GUARD))) {
return( ERROR_INVALID_PARAMETER );
}
rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
if (rc != NO_ERROR) {
return( rc );
}
a->BaseAddress = BaseAddress;
Od2CallSubsystem( &m, NULL, Os2GetSharedMem, sizeof( *a ) );
return(m.ReturnedErrorValue);
}
APIRET
DosGetNamedSharedMem(
OUT PVOID *BaseAddress,
IN PSZ ObjectName,
IN ULONG Flags
)
{
OS2_API_MSG m;
POS2_DOSGETNAMEDSHAREDMEM_MSG a = &m.u.DosGetNamedSharedMem;
APIRET rc;
POS2_CAPTURE_HEADER CaptureBuffer;
if ((Flags & fPERM) == 0 || (Flags & ~(fGETNMSHR|PAG_GUARD))) {
return( ERROR_INVALID_PARAMETER );
}
rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
if (rc != NO_ERROR) {
return( rc );
}
a->BaseAddress = NULL;
//
// probe address pointer.
//
try {
*BaseAddress = 0;
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
rc = Od2CaptureObjectName( ObjectName,
CANONICALIZE_SHARED_MEMORY,
0,
&CaptureBuffer,
&a->ObjectName
);
if (rc != NO_ERROR) {
return( rc );
}
Od2CallSubsystem( &m, CaptureBuffer, Os2GetNamedSharedMem, sizeof( *a ) );
if (m.ReturnedErrorValue == NO_ERROR) {
*BaseAddress = a->BaseAddress;
}
Od2FreeCaptureBuffer( CaptureBuffer );
return( m.ReturnedErrorValue );
}
APIRET
DosAllocSharedMem(
OUT PVOID *BaseAddress,
IN PSZ ObjectName,
IN ULONG RegionSize,
IN ULONG Flags,
IN BOOLEAN CreateLDTEntry // Create LDT entry in the server.
)
{
OS2_API_MSG m;
POS2_DOSALLOCSHAREDMEM_MSG a = &m.u.DosAllocSharedMem;
APIRET rc;
POS2_CAPTURE_HEADER CaptureBuffer;
if (RegionSize == 0
|| (Flags & ~(fALLOCSHR|PAG_GUARD))
|| ((Flags & PAG_COMMIT) && (Flags & fPERM) == 0)
|| (ObjectName != NULL) && (Flags & (OBJ_GETTABLE|OBJ_GIVEABLE))
|| (ObjectName == NULL) && (Flags & (OBJ_GETTABLE|OBJ_GIVEABLE)) == 0
) {
return( ERROR_INVALID_PARAMETER );
}
rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
if (rc != NO_ERROR) {
return( rc );
}
a->BaseAddress = NULL;
a->RegionSize = RegionSize;
a->CreateLDTEntry = CreateLDTEntry; // Server will create LDT entry.
//
// probe address pointer.
//
try {
*BaseAddress = 0;
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
rc = Od2CaptureObjectName( ObjectName,
CANONICALIZE_SHARED_MEMORY,
0,
&CaptureBuffer,
&a->ObjectName
);
if (rc != NO_ERROR) {
return( rc );
}
Od2CallSubsystem( &m, CaptureBuffer, Os2AllocSharedMem, sizeof( *a ) );
if (m.ReturnedErrorValue == NO_ERROR) {
*BaseAddress = a->BaseAddress;
}
if (CaptureBuffer != NULL) {
Od2FreeCaptureBuffer( CaptureBuffer );
}
return( m.ReturnedErrorValue );
}
APIRET
DosQueryMem(
IN PVOID BaseAddress,
IN OUT PULONG RegionSize,
OUT PULONG Flags
)
{
NTSTATUS Status;
MEMORY_BASIC_INFORMATION MemoryInformation;
ULONG MemFlags, OriginalBaseAddress, OldEndAddress, NewEndAddress;
ULONG Protection;
SEL sel;
POS21X_CSALIAS pCSAlias;
BOOLEAN SelIsCSADS;
OriginalBaseAddress = (ULONG)BaseAddress;
sel = FLATTOSEL(BaseAddress);
BaseAddress = (PVOID)((ULONG)BaseAddress & ~(Od2NtSysInfo.PageSize - 1));
Status = NtQueryVirtualMemory( NtCurrentProcess(),
BaseAddress,
MemoryBasicInformation,
&MemoryInformation,
sizeof( MemoryInformation ),
NULL
);
if (!NT_SUCCESS( Status )) {
return( ERROR_INVALID_ADDRESS );
}
MemFlags = 0;
Protection = MemoryInformation.Protect;
if (MemoryInformation.State == MEM_COMMIT) {
MemFlags |= PAG_COMMIT;
}
else
if (MemoryInformation.State == MEM_FREE) {
MemFlags |= PAG_FREE;
}
else
if (MemoryInformation.State == MEM_RESERVE) {
Protection = MemoryInformation.AllocationProtect;
}
// Check if this is a Data Segment of a CSAlias Only for "Pseudo 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 twice (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 ((MemoryInformation.Type != MEM_PRIVATE) &&
(MemoryInformation.AllocationProtect != PAGE_EXECUTE_WRITECOPY) &&
(sel >= FIRST_SHARED_SELECTOR) &&
(!SelIsCSADS))
{
MemFlags |= PAG_SHARED;
}
if (MemoryInformation.State != MEM_FREE &&
MemoryInformation.AllocationBase == MemoryInformation.BaseAddress
) {
MemFlags |= PAG_BASE;
}
switch( Protection & 0xFF) {
case PAGE_NOACCESS : break;
case PAGE_READONLY : MemFlags |= PAG_READ; break;
case PAGE_READWRITE : MemFlags |= PAG_READ | PAG_WRITE; break;
case PAGE_WRITECOPY : MemFlags |= PAG_READ | PAG_WRITE; break;
case PAGE_EXECUTE : MemFlags |= PAG_EXECUTE; break;
case PAGE_EXECUTE_READ : MemFlags |= PAG_EXECUTE | PAG_READ; break;
case PAGE_EXECUTE_READWRITE : MemFlags |= PAG_EXECUTE | PAG_READ | PAG_WRITE; break;
case PAGE_EXECUTE_WRITECOPY : MemFlags |= PAG_EXECUTE | PAG_READ | PAG_WRITE; break;
}
if (Protection & PAGE_GUARD) {
MemFlags |= PAG_GUARD;
}
try {
//
// Must specify a non-zero region size to begin with
//
if (*RegionSize == 0) {
return ERROR_INVALID_PARAMETER;
}
//
// See if the specified region size is too large. Either because
// the base address was not the actual base address or the region
// size given was greater than the actual region size.
//
OldEndAddress = OriginalBaseAddress + *RegionSize;
NewEndAddress = (ULONG)MemoryInformation.BaseAddress +
MemoryInformation.RegionSize;
if (OldEndAddress > NewEndAddress) {
*RegionSize = NewEndAddress - OriginalBaseAddress;
}
else
if (*RegionSize > MemoryInformation.RegionSize) {
*RegionSize = MemoryInformation.RegionSize;
}
//
// Return the calculated flags for the region.
//
*Flags = MemFlags;
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return( NO_ERROR );
}