Ignore:
Timestamp:
Aug 27, 1999, 6:51:01 PM (26 years ago)
Author:
sandervl
Message:

Implemented multiple views of memory mapped files + some bugfixes to PE loader code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/mmap.cpp

    r708 r712  
    1 /* $Id: mmap.cpp,v 1.16 1999-08-26 17:56:25 sandervl Exp $ */
     1/* $Id: mmap.cpp,v 1.17 1999-08-27 16:51:00 sandervl Exp $ */
    22
    33/*
    4  * Win32 Memory mapped file class
     4 * Win32 Memory mapped file & view classes
    55 *
    66 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
     
    2828#include <handlemanager.h>
    2929#include "mmap.h"
     30#include "oslibdos.h"
    3031
    3132VMutex globalmapMutex;
     33VMutex globalviewMutex;
    3234
    3335//******************************************************************************
     
    3537//******************************************************************************
    3638Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
    37                : fMapped(FALSE), pMapping(NULL), mMapAccess(0), referenced(0)
     39               : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0)
    3840{
    3941  globalmapMutex.enter();
     
    7274        }
    7375  }
     76
     77  dprintf(("CreateFileMappingA for file %x, prot %x size %d, name %s", hMemFile, mProtFlags, mSize, lpszMapName));
    7478  this->hMemMap = hMemMap;
    7579  mapMutex.leave();
     
    8387Win32MemMap::~Win32MemMap()
    8488{
    85   unmapViewOfFile();
     89  for(int i=0;i<nrMappings;i++) {
     90        Win32MemMapView::deleteView(this); //delete all views of our memory mapped file
     91  }
     92  mapMutex.enter();
    8693  if(lpszMapName) {
    8794        free(lpszMapName);
    8895  }
    89   mapMutex.enter();
    9096  if(pMapping) {
    9197        VirtualFree(pMapping, mSize, MEM_RELEASE);
     
    118124}
    119125//******************************************************************************
    120 //******************************************************************************
    121 BOOL Win32MemMap::hasReadAccess()
    122 {
    123   return TRUE; //should have at least this
    124 }
    125 //******************************************************************************
    126 //******************************************************************************
    127 BOOL Win32MemMap::hasWriteAccess()
    128 {
    129   return !(mProtFlags & PAGE_READONLY);
    130 }
    131 //******************************************************************************
    132 //Might want to add this feature for memory mapping executable & dll files in
    133 //the loader (done in Win32 with the SEC_IMAGE flag?)
    134 //******************************************************************************
    135 BOOL Win32MemMap::hasExecuteAccess()
    136 {
    137   return FALSE;
    138 }
    139 //******************************************************************************
    140126//We determine whether a page has been modified by checking it's protection flags
    141127//If the write flag is set, this means commitPage had to enable this due to a pagefault
    142128//(all pages are readonly until the app tries to write to it)
    143129//******************************************************************************
    144 BOOL Win32MemMap::commitPage(LPVOID lpPageFaultAddr, ULONG nrpages, BOOL fWriteAccess)
     130BOOL Win32MemMap::commitPage(ULONG offset, BOOL fWriteAccess)
    145131{
    146132 MEMORY_BASIC_INFORMATION memInfo;
    147  DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
    148  DWORD oldProt, newProt, nrBytesRead, offset, size;
    149  
     133 LPVOID lpPageFaultAddr = (LPVOID)((ULONG)pMapping + offset);
     134 DWORD pageAddr         = (DWORD)lpPageFaultAddr & ~0xFFF;
     135 DWORD oldProt, newProt, nrBytesRead, size;
     136
    150137//  mapMutex.enter();
     138 
    151139  newProt  = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
    152140
    153   dprintf(("Win32MemMap::commitPage %x (faultaddr %x), nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));
     141  dprintf(("Win32MemMap::commitPage %x (faultaddr %x)", pageAddr, lpPageFaultAddr));
    154142  if(hMemFile != -1) {
    155         if(VirtualQuery((LPSTR)pageAddr, &memInfo, nrpages*PAGE_SIZE) == 0) {
    156                 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
    157                 goto fail;
    158         }
     143        if(VirtualQuery((LPSTR)pageAddr, &memInfo, NRPAGES_TOCOMMIT*PAGE_SIZE) == 0) {
     144                dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, NRPAGES_TOCOMMIT*PAGE_SIZE));
     145                goto fail;
     146        }
     147        //Only changes the state of the pages with the same attribute flags
     148        //(returned in memInfo.RegionSize)
     149        //If it's smaller than the mNrPages, it simply means one or more of the
     150        //other pages have already been committed
    159151        if(memInfo.State & MEM_COMMIT)
    160152        {//if it's already committed, then the app tried to write to it
    161153                if(!fWriteAccess) {
    162                         dprintf(("Win32MemMap::commitPage: Huh? Already committed and not trying to write (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
    163                         goto fail;
    164                 }
    165                 if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
    166                         dprintf(("Win32MemMap::commitPage: Failed to set write flag on page (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
     154                        dprintf(("Win32MemMap::commitPage: Huh? Already committed and not trying to write (%x,%x) failed for %x", pageAddr, memInfo.RegionSize));
     155                        goto fail;
     156                }
     157                if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) {
     158                        dprintf(("Win32MemMap::commitPage: Failed to set write flag on page (%x,%x) failed for %x", pageAddr, memInfo.RegionSize));
    167159                        goto fail;
    168160                }
    169161        }
    170162        else {
    171                 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE) == FALSE) {
     163                if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE) == FALSE) {
    172164                        goto fail;
    173165                }
    174166                offset = pageAddr - (ULONG)pMapping;
    175                 size   = nrpages*PAGE_SIZE;
     167                size   = memInfo.RegionSize;
    176168                if(offset + size > mSize) {
     169                        dprintf(("Adjusting size from %d to %d", size, mSize - offset));
    177170                        size = mSize - offset;
    178171                }
     
    190183                }
    191184                if(mProtFlags & PAGE_READONLY) {
    192                         if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
     185                        if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) {
    193186                                goto fail;
    194187                        }
     
    197190  }
    198191  else {
    199         if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, newProt) == FALSE) {
     192        if(VirtualQuery((LPSTR)pageAddr, &memInfo, NRPAGES_TOCOMMIT*PAGE_SIZE) == 0) {
     193                dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, NRPAGES_TOCOMMIT*PAGE_SIZE));
     194                goto fail;
     195        }
     196        if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, newProt) == FALSE) {
    200197                goto fail;
    201198        }
     
    209206}
    210207//******************************************************************************
    211 //******************************************************************************
    212 BOOL Win32MemMap::unmapViewOfFile()
    213 {
    214   if(fMapped == FALSE)
    215         return FALSE;
    216 
    217   flushView(pMapping, mSize);
     208//todo: unalias memory
     209//******************************************************************************
     210BOOL Win32MemMap::unmapViewOfFile(Win32MemMapView *view)
     211{
    218212  mapMutex.enter();
    219   if(pMapping) {
     213
     214  if(nrMappings == 0)
     215        goto fail;
     216
     217  delete view;
     218
     219  if(--nrMappings) {
    220220        VirtualFree(pMapping, mSize, MEM_RELEASE);
    221   }
    222   pMapping = NULL;
    223   fMapped = FALSE;
     221        pMapping = NULL;
     222  }
    224223  mapMutex.leave();
    225224  return TRUE;
     225fail:
     226  mapMutex.leave();
     227  return FALSE;
    226228}
    227229//******************************************************************************
     
    232234  ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
    233235  ULONG fAlloc   = 0;
    234   LPVOID mapview;
    235 
     236  Win32MemMapView *mapview;
     237
     238  if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY))
     239        goto parmfail;
    236240  if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE))
    237241        goto parmfail;
     
    240244  if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY))
    241245        goto parmfail;
     246  if(offset+size > mSize)
     247        goto parmfail;
    242248
    243249//TODO: If committed, read file into memory
    244 #if 0 
     250#if 0
    245251  if(mProtFlags & SEC_COMMIT)
    246252        fAlloc |= MEM_COMMIT;
     
    252258#endif
    253259
    254   if(fMapped == FALSE) {//if not mapped, reserve/commit entire view
     260  if(nrMappings == 0) {//if not mapped, reserve/commit entire view
    255261        //SvL: Always read/write access or else ReadFile will crash once we
    256         //     start decommitting pages.
     262        //     start committing pages.
    257263        //     This is most likely an OS/2 bug and doesn't happen in Aurora
    258264        //     when allocating memory with the PAG_ANY bit set. (without this
     
    263269                goto fail;
    264270        }
    265         fMapped = TRUE;
    266   }
    267   mapview = (LPVOID)((ULONG)pMapping + offset);
    268   mapMutex.leave();
    269   return mapview;
     271  }
     272  mapview = new Win32MemMapView(this, offset, (size == 0) ? mSize : size, fdwAccess);
     273  if(mapview == NULL) {
     274        goto fail;
     275  }
     276  if(mapview->everythingOk() == FALSE) {
     277        delete mapview;
     278        goto fail;
     279  }
     280  nrMappings++;
     281  mapMutex.leave();
     282  return mapview->getViewAddr();
    270283
    271284parmfail:
     
    279292//We determine whether a page has been modified by checking it's protection flags
    280293//If the write flag is set, this means commitPage had to enable this due to a pagefault
    281 //(all pages are readonly until the app tries to modify it)
     294//(all pages are readonly until the app tries to modify the contents of the page)
    282295//
    283296//TODO: Are apps allowed to change the protection flags of memory mapped pages?
    284297//      I'm assuming they aren't for now.
    285298//******************************************************************************
    286 BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
    287 {
     299BOOL Win32MemMap::flushView(ULONG offset, ULONG cbFlush)
     300{
     301 LPVOID lpvBase = (LPVOID)((ULONG)pMapping+offset);
    288302 MEMORY_BASIC_INFORMATION memInfo;
    289  ULONG nrpages, nrBytesWritten, offset, size;
     303 ULONG nrBytesWritten, size;
    290304 int   i;
    291305
    292 //  mapMutex.enter();
    293306  dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush));
    294   if(fMapped == FALSE)
     307  if(nrMappings == 0)
    295308        goto parmfail;
    296309
     
    307320        goto success; //TODO: Return an error here?
    308321
    309   nrpages = cbFlush/PAGE_SIZE;
    310   if(cbFlush & 0xFFF)  nrpages++;
    311 
    312   for(i=0;i<nrpages;i++) {
    313         if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
     322  while(cbFlush) {
     323        if(VirtualQuery((LPSTR)lpvBase, &memInfo, cbFlush) == 0) {
    314324                dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
    315325                goto fail;
    316326        }
    317         //If a page is reserved or write protected, we won't bother flushing it to disk
     327        //If a page (or range of pages) is reserved or write protected, we
     328        //won't bother flushing it to disk
    318329        if(memInfo.State & MEM_COMMIT &&
    319330           memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
    320331        {//committed and allowed for writing?
    321                 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
    322                 size   = PAGE_SIZE;
    323                 if(offset + size > mSize) {
    324                         size = mSize - offset;
     332                offset = (ULONG)lpvBase - (ULONG)pMapping;
     333                size   = memInfo.RegionSize;
     334                if(size > cbFlush) {
     335                        size = cbFlush;
    325336                }
    326337                dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
     
    330341                        goto fail;
    331342                }
    332                 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
    333                         dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
     343                if(WriteFile(hMemFile, (LPSTR)lpvBase, size, &nrBytesWritten, NULL) == FALSE) {
     344                        dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase));
    334345                        goto fail;
    335346                }
    336347                if(nrBytesWritten != size) {
    337                         dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
    338                         goto fail;
    339                 }
    340         }
     348                        dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase));
     349                        goto fail;
     350                }
     351        }
     352        lpvBase = (LPVOID)((ULONG)lpvBase + memInfo.RegionSize);
     353
     354        if(cbFlush < memInfo.RegionSize)
     355                break;
     356
     357        cbFlush -= memInfo.RegionSize;
    341358  }
    342359success:
    343 //  mapMutex.leave();
    344360  return TRUE;
    345361parmfail:
    346362  SetLastError(ERROR_INVALID_PARAMETER);
    347 //  mapMutex.leave();
    348363  return FALSE;
    349364fail:
    350 //  mapMutex.leave();
    351365  return FALSE;
    352366}
     
    390404}
    391405//******************************************************************************
     406//Assumes mutex has been acquired
    392407//******************************************************************************
    393408void Win32MemMap::deleteAll()
     
    400415//******************************************************************************
    401416Win32MemMap *Win32MemMap::memmaps = NULL;
     417
     418//******************************************************************************
     419//******************************************************************************
     420Win32MemMapView::Win32MemMapView(Win32MemMap *map, ULONG offset, ULONG size,
     421                                 ULONG fdwAccess)
     422{
     423 LPVOID           viewaddr = (LPVOID)((ULONG)map->getMappingAddr()+offset);
     424 ULONG            accessAttr = 0;
     425 Win32MemMapView *tmpview  = mapviews;
     426
     427  errorState = 0;
     428  mParentMap = map;
     429  mSize    = size;
     430  mOffset  = offset;
     431
     432  switch(fdwAccess) {
     433  case FILE_MAP_READ:
     434        accessAttr = PAG_READ;
     435        mfAccess   = MEMMAP_ACCESS_READ;
     436        break;
     437  case FILE_MAP_WRITE:
     438  case FILE_MAP_COPY:
     439        accessAttr = (PAG_READ|PAG_WRITE);
     440        mfAccess   = MEMMAP_ACCESS_WRITE;
     441        break;
     442  }
     443  if(OSLibDosAliasMem(viewaddr, size, &pMapView, accessAttr) != OSLIB_NOERROR) {
     444        dprintf(("new OSLibDosAliasMem FAILED"));
     445        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
     446        errorState = 1;
     447        return;
     448  }
     449
     450  dprintf(("Win32MemMapView::Win32MemMapView: created %x (alias for %x), size %d", pMapView, viewaddr, size));
     451
     452  globalviewMutex.enter();
     453  if(tmpview == NULL || tmpview->getViewAddr() > pMapView) {
     454        next     = mapviews;
     455        mapviews = this;
     456  }
     457  else {
     458        while(tmpview->next) {
     459                if(tmpview->next->getViewAddr() > pMapView) {
     460                        break;
     461                }
     462                tmpview = tmpview->next;
     463        }
     464        next          = tmpview->next;
     465        tmpview->next = this;
     466  }
     467  globalviewMutex.leave();
     468}
     469//******************************************************************************
     470//******************************************************************************
     471Win32MemMapView::~Win32MemMapView()
     472{
     473  if(errorState != 0)
     474        return;
     475
     476  if(mfAccess != MEMMAP_ACCESS_READ)
     477        mParentMap->flushView(mOffset, mSize);
     478
     479  OSLibDosFreeMem(pMapView);
     480
     481  globalviewMutex.enter();
     482  Win32MemMapView *view = mapviews;
     483
     484  if(view == this) {
     485        mapviews = next;
     486  }
     487  else {
     488        while(view->next) {
     489                if(view->next == this)
     490                        break;
     491                view = view->next;
     492        }
     493        if(view->next) {
     494                view->next = next;
     495        }
     496        else    dprintf(("Win32MemMapView::~Win32MemMapView: map not found!! (%x)", this));
     497  }
     498  globalviewMutex.leave();
     499}
     500//******************************************************************************
     501//******************************************************************************
     502void Win32MemMapView::deleteView(Win32MemMap *map)
     503{
     504  globalviewMutex.enter();
     505  Win32MemMapView *view = mapviews;
     506
     507  if(view != NULL) {
     508        while(view) {
     509                if(view->getParentMap() == map)
     510                {
     511                        globalviewMutex.leave();
     512                        delete view;
     513                        return;
     514                }
     515                view = view->next;
     516        }
     517  }
     518  globalviewMutex.leave();
     519}
     520//******************************************************************************
     521//******************************************************************************
     522Win32MemMap *Win32MemMapView::findMapByView(ULONG address, ULONG *offset,
     523                                            ULONG accessType,
     524                                            Win32MemMapView **pView)
     525{
     526  globalviewMutex.enter();
     527  Win32MemMapView *view = mapviews;
     528
     529  *offset = 0;
     530
     531  if(view != NULL) {
     532        while(view && (ULONG)view->getViewAddr() <= address) {
     533                if((ULONG)view->getViewAddr() <= address &&
     534                   (ULONG)view->getViewAddr() + view->getSize() >= address &&
     535                   view->getAccessFlags() >= accessType)
     536                {
     537                        *offset = view->getOffset() + (address - (ULONG)view->getViewAddr());
     538                        goto success;
     539                }
     540                view = view->next;
     541        }
     542        //failure if we get here
     543        view = NULL;
     544  }
     545success:
     546  globalviewMutex.leave();
     547  if(pView) *pView = view;
     548  return (view) ? view->getParentMap() : NULL;
     549}
     550//******************************************************************************
     551//******************************************************************************
     552Win32MemMapView *Win32MemMapView::findView(LPVOID address)
     553{
     554  Win32MemMapView *view = mapviews;
     555
     556  if(view != NULL) {
     557        while(view) {
     558                if(view->getViewAddr() == address)
     559                {
     560                        break;
     561                }
     562                view = view->next;
     563        }
     564  }
     565  return view;
     566}
     567//******************************************************************************
     568//******************************************************************************
     569Win32MemMapView *Win32MemMapView::mapviews = NULL;
     570
Note: See TracChangeset for help on using the changeset viewer.