/** * Change the protection of one or more pages in an allocation. * * (This will of course only work correctly on memory allocated by kHlpPageAlloc().) * * @returns 0 on success, non-zero OS status code on failure. * @param pv First page. Page aligned. * @param cb Number of bytes. Page aligned. * @param enmProt The new protection. Copy-on-write is invalid. */ KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt)); if (!rc) return 0; /** @todo convert errno -> kErrors */ kHlpAssert(0); return rc; #elif K_OS == K_OS_OS2 APIRET rc; ULONG fFlags = kHlpPageProtToNative(enmProt); /* * The non-stub pages. */ rc = DosSetMem(pv, cb, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT); if (rc) { /* Try page by page. */ while (cb > 0) { rc = DosSetMem(pv, 0x1000, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT); if (rc) return rc; pv = (void *)((KUPTR)pv + 0x1000); cb -= 0x1000; } } kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS DWORD fOldProt = 0; DWORD fProt = kHlpPageProtToNative(enmProt); int rc = 0; if (!VirtualProtect(pv, cb, fProt, &fOldProt)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif }
/* * @todo Currently we reserve a static block of HEAP_SIZE at LIBCx init * which we commit/release as needed. The disadvantage is obvious - we * constantly occupy the address space that could be needed for other * purposes, but limit the max memory size which may be not enough under * certain LIBCx load. But in order to allow for dynamic allocation of * shared memory we need to track all proccess IDs that are currently * using LIBCx so that we give them the newly allocated shared memory. * This is for later. See https://github.com/bitwiseworks/libcx/issues/9. */ static void *mem_alloc(Heap_t h, size_t *psize, int *pclean) { APIRET arc; char *mem; size_t size; TRACE("psize %d\n", *psize); /* Round requested size up to HEAP_INC_SIZE */ size = (*psize + HEAP_INC_SIZE - 1) / HEAP_INC_SIZE * HEAP_INC_SIZE; if (size + gpData->size > HEAP_SIZE) { TRACE("out of memory"); return NULL; } mem = (char *)gpData + gpData->size; /* Commit the new block */ arc = DosSetMem(mem, size, PAG_DEFAULT | PAG_COMMIT); TRACE("DosSetMem(%p, %d) = %ld\n", mem, size, arc); if (arc) return NULL; /* DosAllocSharedMem gives us zeroed mem */ *pclean = _BLOCK_CLEAN; /* Return the actually allocated number of bytes */ *psize = size; gpData->size += size; return mem; }
void *os2ldcalloc(size_t num_elem, size_t size_elem) { APIRET rc; int ret; if (FirstTime) { if ((rc=DosAllocMem(&os2ldBase,RESERVED_BLOCKS * 4096, PAG_READ | PAG_WRITE | PAG_EXECUTE)) != 0) { xf86Msg(X_ERROR, "OS2LD: DosAllocMem failed, rc=%d\n", rc); return NULL; } /* Now commit the first 128Kb, the rest will * be done dynamically */ if ((rc=DosSetMem(os2ldBase, 32*4096, PAG_DEFAULT | PAG_COMMIT)) != 0) { xf86Msg(X_ERROR, "OS2LD: DosSetMem failed, rc=%d\n",rc); DosFreeMem(os2ldBase); return NULL; } os2ldCommitedTop = os2ldBase + 32*4096; os2ldTotalCommitedBlocks = 32; #ifdef DEBUG xf86Msg(X_INFO, "OS2LD: Initial heap at addr=%p\n", os2ldBase); #endif if ((os2ldHeap=_ucreate(os2ldBase, 32*4096, _BLOCK_CLEAN, _HEAP_REGULAR, os2ldAddToHeap, os2ldRemoveFromHeap)) == NULL) { xf86Msg(X_ERROR, "OS2LD: heap creation failed\n"); DosFreeMem(os2ldBase); return NULL; } if ((ret=_uopen(os2ldHeap)) != 0) { xf86Msg(X_ERROR, "OS2LD: heap open failed\n"); ret = _udestroy(os2ldHeap,_FORCE); DosFreeMem(os2ldBase); return(NULL); } FirstTime = FALSE; #ifdef DEBUG xf86Msg(X_INFO,"OS2LD: Created module heap at addr=%p\n", os2ldHeap); #endif } return _ucalloc(os2ldHeap,num_elem,size_elem); }
ULONG APIENTRY FileExceptionHandler( PEXCEPTIONREPORTRECORD pReport, struct _EXCEPTIONREGISTRATIONRECORD * pXReg, PCONTEXTRECORD pContext, PVOID pDispatch) { CAMJXRR * pReg = (CAMJXRR*)pXReg; ULONG ulRtn = XCPT_CONTINUE_SEARCH; ULONG rc = 0; ULONG ulSize; ULONG ulAttr; LONG lOffs; char * pErr = 0; PVOID pMem; do { if (pReport->fHandlerFlags || pReport->ExceptionNum != XCPT_ACCESS_VIOLATION || pReport->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN || pReport->ExceptionInfo[0] != XCPT_READ_ACCESS || pReport->ExceptionInfo[1] == XCPT_DATA_UNKNOWN || pReport->ExceptionInfo[1] < (ULONG)pReg->pBase || pReport->ExceptionInfo[1] >= (ULONG)pReg->pEnd) { printf( "*** Exception not handled - %08lx\n", pReport->ExceptionNum); return (ulRtn); } if (pReg->lFilePtr >= pReg->lEOF) ERRMSG( "already at EOF") pMem = (PVOID)(pReport->ExceptionInfo[1] & ~0xFFF); ulSize = 1; ulAttr = 0; rc = DosQueryMem( pMem, &ulSize, &ulAttr); if (rc) ERRMSG( "DosQueryMem") if (ulAttr & (PAG_FREE | PAG_COMMIT)) { rc = ulAttr; ERRMSG( "unexpected memory attributes") } rc = DosSetMem( pMem, 0x1000, PAG_COMMIT | PAG_DEFAULT); if (rc) ERRMSG( "DosSetMem") lOffs = (BYTE*)pMem - pReg->pBase; if (lOffs != pReg->lFilePtr) { rc = DosSetFilePtr( pReg->hFile, lOffs, FILE_BEGIN, &pReg->lFilePtr); if (rc) ERRMSG( "DosSetFilePtr") if (lOffs != pReg->lFilePtr) { rc = lOffs; ERRMSG( "seek beyond EOF") }
void *os2ldAddToHeap(Heap_t H, size_t *new_size, int *PCLEAN) { PVOID NewBase; long adjusted_size; long blocks; APIRET rc; if (H != os2ldHeap) { xf86Msg(X_ERROR, "OS2LD: Heap corruption in GrowHeap, p=%08x\n",H); return NULL; } NewBase = os2ldCommitedTop; adjusted_size = (*new_size/65536) * 65536; if ((*new_size % 65536) > 0) adjusted_size += 65536; blocks = adjusted_size / 4096; if ((os2ldTotalCommitedBlocks + blocks) > RESERVED_BLOCKS) { xf86Msg(X_ERROR, "OS2LD: Out of memory in GrowHeap\n"); xf86Msg(X_ERROR, "OS2LD: Max available memory is of %ld bytes\n", RESERVED_BLOCKS * 4096); return NULL; } if ((rc=DosSetMem(NewBase, adjusted_size, PAG_DEFAULT | PAG_COMMIT)) != 0) { xf86Msg(X_ERROR, "OS2LD: DosSetMem failed in GrowHeap, size req'd=%d, rc=%d\n", adjusted_size, rc); return NULL; } os2ldCommitedTop += adjusted_size; os2ldTotalCommitedBlocks += blocks; *PCLEAN = _BLOCK_CLEAN; *new_size = adjusted_size; #ifdef DEBUG xf86Msg(X_INFO,"OS2LD: Heap extended by %d bytes, addr=%p\n", adjusted_size, NewBase); #endif return NewBase; }
static void test7( void ) { printf("***** Test7: Decommit source memory which is destination memory " "of other source memory...\n"); static const char *p1Str = "6789067890"; static const char *p3Str = "1234567890"; char *p1; char *p2; char *p3; DosAllocMem(( PPVOID )&p1, ALLOC_SIZE, fPERM | PAG_COMMIT ); strcpy( p1, p3Str); p2 = copyOnWrite( p1, COPY_SIZE ); p3 = copyOnWrite( p2, COPY_SIZE ); printf("p1 = %p, p2 = %p, p3 = %p\n", p1, p2, p3 ); printf("p1 = [%s], p2 = [%s], p3 = [%s]\n", p1, p2, p3 ); printf("Decommiting p2\n"); printf("DosSetMem( p2 ) = %ld\n", DosSetMem( p2, COPY_SIZE, PAG_DECOMMIT )); printf("Copying %.5s to p1\n", p1 + 5 ); memcpy( p1, p1 + 5, 5 ); printf("p1 = [%s], p3 = [%s]\n", p1, p3 ); fprintf( stderr, "Test7: "); if( memcmp( p1, p1Str, strlen( p1Str )) || memcmp( p3, p3Str, strlen( p3Str ))) fprintf( stderr, "Failed\n"); else fprintf( stderr, "Succeeded\n"); DosFreeMem( p3 ); DosFreeMem( p2 ); DosFreeMem( p1 ); }
void * _MD_MemMap(PRFileMap *fmap, PROffset64 offset, PRUint32 len) { PRUint32 rv; void *addr; /* prevent mappings beyond EOF + remainder of page */ if (offset + len > fmap->md.maxExtent) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } if (PR_Seek64(fmap->fd, offset, PR_SEEK_SET) == -1) { return NULL; } /* try for high memory, fall back to low memory if hi-mem fails */ #if defined(MOZ_OS2_HIGH_MEMORY) rv = DosAllocMem(&addr, len, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE); if (rv) #endif { rv = DosAllocMem(&addr, len, PAG_COMMIT | PAG_READ | PAG_WRITE); if (rv) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, rv); return NULL; } } if (PR_Read(fmap->fd, addr, len) == -1) { DosFreeMem(addr); return NULL; } /* don't permit writes if readonly */ if (fmap->prot == PR_PROT_READONLY) { rv = DosSetMem(addr, len, PAG_READ); if (rv) { DosFreeMem(addr); PR_SetError(PR_UNKNOWN_ERROR, rv); return NULL; } } return addr; }
/* * Exception handler; attempt to commit memory if access violation occures. */ static ULONG _System exception_handler(PEXCEPTIONREPORTRECORD pERepRec, PEXCEPTIONREGISTRATIONRECORD pERegRep, PCONTEXTRECORD pCtxRec, PVOID p) { ULONG ulRet = XCPT_CONTINUE_EXECUTION; switch(pERepRec->ExceptionNum) { case XCPT_ACCESS_VIOLATION: ulRet = XCPT_CONTINUE_SEARCH; if(pERepRec->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN) { } else { APIRET rc = NO_ERROR; ULONG cbMem = 1; ULONG flMem = 0; rc = DosQueryMem((PVOID)pERepRec->ExceptionInfo[1], &cbMem, &flMem); if((flMem & PAG_FREE) == 0) { rc = DosSetMem((PVOID)pERepRec->ExceptionInfo[1], 4096, PAG_DEFAULT | PAG_COMMIT); if(rc == NO_ERROR) { ulRet = XCPT_CONTINUE_EXECUTION; } } } break; default: ulRet = XCPT_CONTINUE_SEARCH; break; } return ulRet; }
void OSAllocator::decommit(void* address, size_t bytes) { if (DosSetMem(address, bytes, PAG_DECOMMIT)) CRASH(); }
void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable) { if (DosSetMem(address, bytes, PAG_COMMIT | protection(writable, executable))) CRASH(); }
ULONG FileGetJPEGInfo( CAMJpgInfo * pji, char * szFile, ULONG cbFile) { ULONG rc; ULONG ul; ULONG cbAlloc; BOOL fHandler = FALSE; CAMJXRR reg; do { memset( ®, 0, sizeof(CAMJXRR)); memset( pji, 0, sizeof(CAMJpgInfo)); rc = DosOpen( szFile, ®.hFile, &ul, 0, 0, OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, 0); if (rc) { printf( "DosOpen - rc= 0x%x\n", (int)rc); break; } // allocate a lot of uncommited memory cbAlloc = ((cbFile + 0xfff) & ~0xfff); rc = DosAllocMem( (void**)(®.pBase), cbAlloc, PAG_READ | PAG_WRITE); if (rc) { printf( "DosAllocMem - rc= 0x%x\n", (int)rc); break; } // get up to the first 16k of the file - this is enough // for my Canon but not enough for a Sony I've tried ul = (cbFile >= 0x4000) ? 0x4000 : cbAlloc; rc = DosSetMem( reg.pBase, ul, PAG_COMMIT | PAG_DEFAULT); if (rc) { printf( "FileGetJPEGInfo - DosSetMem - rc= 0x%x\n", (int)rc); break; } ul = (cbFile >= 0x4000) ? 0x4000 : cbFile; ul = FileReadFile( reg.hFile, reg.pBase, ul, szFile); if (!ul) { rc = CAMERR_NEEDDATA; break; } // any access beyond 16k will generate an exception; // the handler will commit the page and read the corresponding // 4k from the file; if it encounters a file error, it will // longjmp() back to here so we can abort reg.lFilePtr += ul; reg.lEOF = cbFile; reg.pEnd = reg.pBase + cbAlloc; reg.szFile = szFile; reg.xrr.ExceptionHandler = FileExceptionHandler; // since the handler is lower on the stack than the jmpbuf, // longjmp() will unwind it before returning, so prevent // the cleanup code below from unsetting it if (setjmp( reg.jmpbuf)) { fHandler = FALSE; break; } rc = DosSetExceptionHandler( ®.xrr); if (rc) { printf( "DosSetExceptionHandler - rc= 0x%x\n", (int)rc); break; } fHandler = TRUE; // parse the file rc = FileIdentifyFile( pji, reg.pBase); if (rc) { printf( "FileIdentifyFile - rc= 0x%x\n", (int)rc); break; } // change the address of the thumb into an offset into the file if (pji->pThumb) pji->offsThumb = pji->pThumb - reg.pBase; } while (0); if (fHandler) { rc = DosUnsetExceptionHandler( ®.xrr); if (rc) printf( "DosUnsetExceptionHandler - rc= 0x%lx\n", rc); } if (reg.pBase) { rc = DosFreeMem( reg.pBase); if (rc) printf( "DosFreeMem - rc= 0x%x\n", (int)rc); } if (reg.hFile) { rc = DosClose( reg.hFile); if (rc) printf( "DosClose - rc= 0x%x\n", (int)rc); } return (0); }
static bool MakeRegionExecutable(void *page) { rc = DosSetMem(page, PAGESIZE, PAG_READ | PAG_WRITE | PAG_EXECUTE); return rc ? true : false; }
/** * Free memory allocated by kHlpPageAlloc(). * * @returns 0 on success, non-zero OS status code on failure. * @param pv The address returned by kHlpPageAlloc(). * @param cb The byte count requested from kHlpPageAlloc(). */ KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_munmap(pv, cb); if (!rc) return 0; /** @todo convert errno -> kErrors */ return rc; #elif K_OS == K_OS_OS2 APIRET rc; /* * Deal with any portion overlapping with the stub. */ KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub; if (offStub < g_cbStub) { /* decommit the pages in the stub. */ KSIZE cbStub = K_MIN(g_cbStub - offStub, cb); rc = DosSetMem(pv, cbStub, PAG_DECOMMIT); if (rc) { /* Page by page, ignoring errors after the first success. */ while (cbStub > 0) { if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT)) rc = 0; pv = (void *)((KUPTR)pv + 0x1000); cbStub -= 0x1000; cb -= 0x1000; } if (rc) { kHlpAssert(!rc); return rc; } } else { cb -= cbStub; if (!cb) return 0; pv = (void *)((KUPTR)pv + cbStub); } } /* * Free the object. */ rc = DosFreeMem(pv); kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS /* * Free the object. */ int rc = 0; if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif }
/** * Initializes the shared structures. */ static void shared_init() { APIRET arc; int rc; arc = DosExitList(EXLST_ADD, ProcessExit); ASSERT_MSG(arc == NO_ERROR, "%ld", arc); #if defined(TRACE_ENABLED) && !defined(TRACE_USE_LIBC_LOG) /* * Allocate a larger buffer to fit lengthy TRACE messages and disable * auto-flush on EOL (to avoid breaking lines by stdout operations * from other threads/processes). */ setvbuf(stdout, NULL, _IOFBF, 0x10000); #endif while (1) { /* First, try to open the mutex */ arc = DosOpenMutexSem(MUTEX_LIBCX, &gMutex); TRACE("DosOpenMutexSem = %lu\n", arc); if (arc == NO_ERROR) { /* * Init is (being) done by another process, request the mutex to * guarantee shared memory is already alloated, then get access to * it and open shared heap located in that memory. */ arc = DosRequestMutexSem(gMutex, SEM_INDEFINITE_WAIT); ASSERT_MSG(arc == NO_ERROR, "%ld", arc); if (arc == NO_ERROR) { arc = DosGetNamedSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, PAG_READ | PAG_WRITE); TRACE("DosGetNamedSharedMem = %lu\n", arc); if (arc) { /* * This failure means that another process was too fast to do what * it wanted and initiated global uninitialization before we got the * mutex so shared memory was already freed by this time. Retry. */ DosReleaseMutexSem(gMutex); DosCloseMutexSem(gMutex); continue; } /* * It's an ordinary LIBCx process. Increase coutners. */ TRACE("gpData->heap = %p\n", gpData->heap); ASSERT(gpData->heap); rc = _uopen(gpData->heap); ASSERT_MSG(rc == 0, "%d (%d)", rc, errno); ASSERT(gpData->refcnt); gpData->refcnt++; TRACE("gpData->refcnt = %d\n", gpData->refcnt); } break; } if (arc == ERROR_SEM_NOT_FOUND) { /* We are the first process, create the mutex */ arc = DosCreateMutexSem(MUTEX_LIBCX, &gMutex, 0, TRUE); TRACE("DosCreateMutexSem = %ld\n", arc); if (arc == ERROR_DUPLICATE_NAME) { /* Another process is faster, attempt to open the mutex again */ continue; } } ASSERT_MSG(arc == NO_ERROR, "%ld", arc); /* * It's a process that successfully created the main mutex, i.e. the first * LIBCx process. Proceed with the initial setup by allocating shared * memory and heap. */ /* Allocate shared memory */ arc = DosAllocSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, HEAP_SIZE, PAG_READ | PAG_WRITE | OBJ_ANY); TRACE("DosAllocSharedMem(OBJ_ANY) = %ld\n", arc); if (arc && arc != ERROR_ALREADY_EXISTS) { /* High memory may be unavailable, try w/o OBJ_ANY */ arc = DosAllocSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, HEAP_SIZE, PAG_READ | PAG_WRITE); TRACE("DosAllocSharedMem = %ld\n", arc); } ASSERT_MSG(arc == NO_ERROR, "%ld", arc); TRACE("gpData %p\n", gpData); /* Commit the initial block */ arc = DosSetMem(gpData, HEAP_INIT_SIZE, PAG_DEFAULT | PAG_COMMIT); ASSERT_MSG(arc == NO_ERROR, "%ld", arc); gpData->size = HEAP_INIT_SIZE; /* Create shared heap */ gpData->heap = _ucreate(gpData + 1, HEAP_INIT_SIZE - sizeof(*gpData), _BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED, mem_alloc, NULL); TRACE("gpData->heap = %p\n", gpData->heap); ASSERT(gpData->heap); rc = _uopen(gpData->heap); ASSERT_MSG(rc == 0, "%d (%d)", rc, errno); gpData->refcnt = 1; /* Initialize common structures */ GLOBAL_NEW_ARRAY(gpData->procs, PROC_DESC_HASH_SIZE); TRACE("gpData->procs = %p\n", gpData->procs); ASSERT(gpData->procs); GLOBAL_NEW_ARRAY(gpData->files, FILE_DESC_HASH_SIZE); TRACE("gpData->files = %p\n", gpData->files); ASSERT(gpData->files); break; } /* * Perform common initialization (both for the first and ordinary processes). */ /* Make sure a process description for this process is created */ ProcDesc *proc = get_proc_desc(getpid()); ASSERT(proc); /* Initialize individual components */ mmap_init(proc); fcntl_locking_init(proc); /* Check if it's a spawn2 wrapper (e.g. spawn2-wrapper.c) */ { char dll[CCHMAXPATH + sizeof(SPAWN2_WRAPPERNAME) + 1]; if (get_module_name(dll, sizeof(dll))) { strcpy(_getname(dll), SPAWN2_WRAPPERNAME); char exe[CCHMAXPATH + 1]; if (_execname(exe, sizeof(exe)) == 0 && stricmp(dll, exe) == 0) { proc->flags |= Proc_Spawn2Wrapper; TRACE("spawn2 wrapper\n"); /* Make sure the semaphore is available (needed for spawn2-wrapper.c) */ ASSERT(gpData->spawn2_sem); global_spawn2_sem(proc); } } } DosReleaseMutexSem(gMutex); TRACE("done\n"); }