diff options
Diffstat (limited to 'private/os2/client/dllvm.c')
-rw-r--r-- | private/os2/client/dllvm.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/private/os2/client/dllvm.c b/private/os2/client/dllvm.c new file mode 100644 index 000000000..278e8ac1d --- /dev/null +++ b/private/os2/client/dllvm.c @@ -0,0 +1,636 @@ +/*++ + +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 ); +} |