mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
636 lines
17 KiB
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 );
|
|
}
|