Changeset 9946 for trunk/src/kernel32/mmap.cpp
- Timestamp:
- Mar 27, 2003, 3:13:11 PM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kernel32/mmap.cpp
r9911 r9946 1 /* $Id: mmap.cpp,v 1.6 3 2003-03-06 10:44:34sandervl Exp $ */1 /* $Id: mmap.cpp,v 1.64 2003-03-27 14:13:10 sandervl Exp $ */ 2 2 3 3 /* 4 4 * Win32 Memory mapped file & view classes 5 5 * 6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)6 * Copyright 1999-2003 Sander van Leeuwen (sandervl@xs4all.nl) 7 7 * 8 8 * NOTE: Memory mapping DOES NOT work when kernel-mode code causes … … 36 36 #include <winimagepeldr.h> 37 37 #include <custombuild.h> 38 #include "asmutil.h" 38 39 39 40 #define DBG_LOCALLOG DBG_mmap 40 41 #include "dbglocal.h" 42 43 41 44 42 45 //Global DLL Data … … 45 48 CRITICAL_SECTION_OS2 globalmapcritsect = {0}; 46 49 #pragma data_seg() 47 Win32MemMapView *Win32MemMapView::mapviews = NULL;48 50 49 51 … … 72 74 //****************************************************************************** 73 75 Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName) 74 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), image(0) 76 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), 77 image(0), pWriteBitmap(NULL) 75 78 { 76 79 DosEnterCriticalSection(&globalmapcritsect); … … 83 86 mSize = size; 84 87 mProtFlags = fdwProtect; 88 85 89 mProcessId = GetCurrentProcessId(); 86 90 … … 96 100 //****************************************************************************** 97 101 Win32MemMap::Win32MemMap(Win32PeLdrImage *pImage, ULONG baseAddress, ULONG size) 98 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), image(0) 102 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), 103 image(0), pWriteBitmap(NULL) 99 104 { 100 105 DosEnterCriticalSection(&globalmapcritsect); … … 171 176 Win32MemMapView::deleteViews(this); //delete all views of our memory mapped file 172 177 173 dprintf(("Win32MemMap dtor: deleting view%x %x", pMapping, mSize));178 dprintf(("Win32MemMap dtor: deleting map %x %x", pMapping, mSize)); 174 179 175 180 mapMutex.enter(); … … 190 195 hMemFile = -1; 191 196 } 197 if(pWriteBitmap) free(pWriteBitmap); 198 192 199 mapMutex.leave(); 193 200 … … 212 219 } 213 220 //****************************************************************************** 214 // Win32MemMap::setProtFlags 215 // 216 // Change the protection flags of this memory map if required 217 // This is currently only used when creating a mapping for a file which already 218 // has an existing mapping. 219 // 220 // 221 // Parameters: 222 // 223 // DWORD dwNewProtect - new protection flags 224 // 225 // Returns: 226 // TRUE - success 227 // FALSE - failure 228 // 229 // NOTE: 230 // We're ignoring the SEC_* flags for now 231 // 232 //****************************************************************************** 233 BOOL Win32MemMap::setProtFlags(DWORD dwNewProtect) 234 { 235 if(!(dwNewProtect & (PAGE_READWRITE|PAGE_WRITECOPY))) return TRUE; //no need for changes 236 237 if(!(mProtFlags & PAGE_READWRITE)) 238 {//ok, current mapping is readonly; need to change it to readwrite 239 mProtFlags &= ~PAGE_READONLY; 240 mProtFlags |= PAGE_READWRITE; 241 242 //that's all we need to do for now; memory mappings are readwrite by 243 //default (see mapViewOfFile) 244 } 245 return TRUE; 246 } 247 //****************************************************************************** 248 //If memory map has no more views left, then we can safely delete it when 249 //it's handle is closed 250 //****************************************************************************** 251 void Win32MemMap::Release() 221 //****************************************************************************** 222 int Win32MemMap::Release() 252 223 { 253 224 dprintf(("Win32MemMap::Release %s (%d)", lpszMapName, referenced-1)); 254 225 --referenced; 255 if( nrMappings == 0 &&referenced == 0) {226 if(referenced == 0) { 256 227 delete this; 257 } 228 return 0; 229 } 230 return referenced; 258 231 } 259 232 //****************************************************************************** … … 327 300 LPVOID lpPageFaultAddr = (LPVOID)((ULONG)pMapping + offset); 328 301 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF; 329 DWORD oldProt, newProt, nrBytesRead , size;302 DWORD oldProt, newProt, nrBytesRead; 330 303 int i; 331 304 … … 333 306 334 307 if(image) { 335 return image->commitPage(pageAddr, fWriteAccess); 336 } 337 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY); 308 return image->commitPage(pageAddr, fWriteAccess); 309 } 338 310 339 311 dprintf(("Win32MemMap::commitPage %x (faultaddr %x)", pageAddr, lpPageFaultAddr)); 340 if(hMemFile != -1) 312 313 //align at page boundary 314 offset &= ~0xFFF; 315 316 //If it's a write access violation and the view is readonly, then fail 317 if(fWriteAccess) { 318 Win32MemMapView *view = Win32MemMapView::findView(ulFaultAddr); 319 if(view) { 320 if(!(view->getAccessFlags() & MEMMAP_ACCESS_WRITE)) { 321 dprintf(("Write access for a readonly view!!")); 322 return FALSE; 323 } 324 } 325 else { 326 DebugInt3(); //can't happen 327 return FALSE; 328 } 329 } 330 331 int faultsize = nrpages*PAGE_SIZE; 332 333 if(fWriteAccess) 334 {//write access needs special care, so do that on a per page basis 335 dprintf(("Write access -> handle only one page")); 336 faultsize = PAGE_SIZE; 337 } 338 339 offset = pageAddr - (ULONG)pMapping; 340 if(offset + faultsize > mSize) { 341 faultsize = mSize - offset; 342 } 343 344 while(faultsize) 341 345 { 342 int faultsize = nrpages*PAGE_SIZE;343 344 offset = pageAddr - (ULONG)pMapping;345 if(offset + faultsize > mSize) {346 faultsize = mSize - offset;347 }348 349 while(faultsize) {350 346 if(VirtualQuery((LPSTR)pageAddr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) { 351 347 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE)); … … 362 358 goto fail; 363 359 } 364 offset = pageAddr - (ULONG)pMapping; 365 size = memInfo.RegionSize; 366 if(offset + size > mSize) { 367 dprintf(("Adjusting size from %d to %d", size, mSize - offset)); 368 size = mSize - offset; 369 } 370 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) { 371 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset)); 372 goto fail; 373 } 374 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) { 375 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr)); 376 goto fail; 377 } 378 if(nrBytesRead != size) { 379 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr)); 380 goto fail; 381 } 382 if(newProt != PAGE_READWRITE) { 383 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) { 360 361 //Part of the memory map has been committed, so now we can change 362 //the protection flags of the aliases (DosSetMem fails for reserved pages) 363 updateViewPages(offset, memInfo.RegionSize, (fWriteAccess) ? PAGEVIEW_VIEW : PAGEVIEW_READONLY); 364 365 if(hMemFile != -1) 366 {//now read the page(s) from disk 367 DWORD size; 368 369 offset = pageAddr - (ULONG)pMapping; 370 size = memInfo.RegionSize; 371 if(offset + size > mSize) { 372 dprintf(("Adjusting size from %d to %d", size, mSize - offset)); 373 size = mSize - offset; 374 } 375 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) { 376 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset)); 377 goto fail; 378 } 379 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) { 380 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr)); 381 goto fail; 382 } 383 if(nrBytesRead != size) { 384 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr)); 385 goto fail; 386 } 387 } 388 //We set the protection flags to PAGE_READONLY, unless this pagefault 389 //was due to a write access 390 //This way we can track dirty pages which need to be flushed to 391 //disk when FlushViewOfFile is called or the map is closed. 392 if(!fWriteAccess) 393 { 394 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, PAGE_READONLY, &oldProt) == FALSE) { 395 dprintf(("VirtualProtect %x %x PAGE_READWRITE failed with %d!!", pageAddr, memInfo.RegionSize, GetLastError())); 384 396 goto fail; 385 397 } 386 398 } 399 else 400 {//make these pages as dirty 401 ULONG startPage = (pageAddr - (ULONG)pMapping) >> PAGE_SHIFT; 402 ULONG nrPages = memInfo.RegionSize >> PAGE_SHIFT; 403 404 if(memInfo.RegionSize & 0xFFF) 405 nrPages++; 406 407 dprintf(("Mark %d page(s) starting at %x as dirty", nrPages, pageAddr)); 408 markDirtyPages(startPage, nrPages); 409 } 410 } 411 else 412 if(fWriteAccess) 413 { 414 //mark these pages as dirty 415 ULONG startPage = (pageAddr - (ULONG)pMapping) >> PAGE_SHIFT; 416 ULONG nrPages = memInfo.RegionSize >> PAGE_SHIFT; 417 418 if(memInfo.RegionSize & 0xFFF) 419 nrPages++; 420 421 dprintf(("Mark %d page(s) starting at %x as dirty", nrPages, pageAddr)); 422 markDirtyPages(startPage, nrPages); 423 424 //and turn on a write access 425 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, PAGE_READWRITE, &oldProt) == FALSE) { 426 dprintf(("VirtualProtect %x %x PAGE_READWRITE failed with %d!!", pageAddr, memInfo.RegionSize, GetLastError())); 427 goto fail; 428 } 429 //Now change all the aliased pages according to their view protection flags 430 updateViewPages(offset, memInfo.RegionSize, PAGEVIEW_VIEW); 387 431 } 388 432 faultsize -= memInfo.RegionSize; 389 433 pageAddr += memInfo.RegionSize; 390 }391 }392 else {393 ULONG sizeleft = nrpages*PAGE_SIZE;394 while(sizeleft)395 {396 if(VirtualQuery((LPSTR)pageAddr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) {397 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed", pageAddr, sizeleft));398 goto fail;399 }400 memInfo.RegionSize = min(memInfo.RegionSize, sizeleft);401 402 if(!(memInfo.State & MEM_COMMIT))403 {//if it's already committed, then the app tried to write to it404 if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, newProt) == FALSE)405 goto fail;406 }407 memInfo.RegionSize = (memInfo.RegionSize+PAGE_SIZE-1) & ~0xfff;408 pageAddr += memInfo.RegionSize;409 sizeleft -= memInfo.RegionSize;410 }411 434 } 412 435 … … 420 443 // Win32MemMap::commitGuardPage 421 444 // 422 // Handle a guard page exception for a copy-on-write view (one page only)445 // Handle a guard page exception 423 446 // 424 447 // Parameters: … … 436 459 BOOL Win32MemMap::commitGuardPage(ULONG ulFaultAddr, ULONG ulOffset, BOOL fWriteAccess) 437 460 { 438 return FALSE; 439 } 440 //****************************************************************************** 441 // Win32MemMap::invalidatePages 442 // 443 // Invalidate map pages. (called by WriteFile) 461 MEMORY_BASIC_INFORMATION memInfo; 462 BOOL ret; 463 DWORD pageAddr = ulFaultAddr & ~0xFFF; 464 DWORD dwNewProt, dwOldProt; 465 466 dprintf(("Win32MemMap::commitGuardPage %x (faultaddr %x)", pageAddr, ulFaultAddr)); 467 468 //align at page boundary 469 ulOffset &= ~0xFFF; 470 471 return TRUE; 472 fail: 473 return FALSE; 474 } 475 //****************************************************************************** 476 // Win32MemMap::updateViewPages 477 // 478 // Update the page flags of all views 444 479 // 445 480 // Parameters: 446 481 // 447 482 // ULONG offset - offset in memory map 448 // ULONG size - invalid range size 483 // ULONG size - range size 484 // PAGEVIEW flags - page flags 485 // PAGEVIEW_READONLY -> set page flags to readonly 486 // PAGEVIEW_VIEW -> set page flags to view default 449 487 // 450 488 // Returns: … … 453 491 // 454 492 //****************************************************************************** 455 BOOL Win32MemMap::invalidatePages(ULONG offset, ULONG size) 456 { 457 return FALSE; 458 } 459 //****************************************************************************** 460 // Win32MemMap::unmapViewOfFile 461 // 462 // Unmap the view identified by addr 493 BOOL Win32MemMap::updateViewPages(ULONG offset, ULONG size, PAGEVIEW flags) 494 { 495 Win32MemMapView **views = (Win32MemMapView **)alloca(sizeof(Win32MemMapView*)*nrMappings); 496 if(views) 497 { 498 if(Win32MemMapView::findViews(this, nrMappings, views) == nrMappings) 499 { 500 for(int i=0;i<nrMappings;i++) 501 { 502 views[i]->changePageFlags(offset, size, flags); 503 } 504 } 505 else DebugInt3(); //oh, oh 506 } 507 return TRUE; 508 } 509 //****************************************************************************** 510 // Win32MemMap::invalidatePages 511 // 512 // Invalidate map pages. (called by WriteFile) 463 513 // 464 514 // Parameters: 465 515 // 466 // LPVOID addr - view address; doesn't need to be the address 467 // returned by MapViewOfFile(Ex) (as MSDN clearly says); 468 // can be any address within the view range 516 // ULONG offset - offset in memory map 517 // ULONG size - invalid range size 469 518 // 470 519 // Returns: … … 473 522 // 474 523 //****************************************************************************** 475 BOOL Win32MemMap::unmapViewOfFile(LPVOID addr) 476 { 477 Win32MemMapView *view; 478 479 dprintf(("Win32MemMap::unmapViewOfFile %x (nrmaps=%d)", addr, nrMappings)); 480 mapMutex.enter(); 481 482 if(nrMappings == 0) 483 goto fail; 484 485 view = Win32MemMapView::findView((ULONG)addr); 486 if(view == NULL) 487 goto fail; 488 489 delete view; 490 491 if(--nrMappings == 0) { 492 VirtualFree(pMapping, 0, MEM_RELEASE); 493 pMapping = NULL; 494 } 495 mapMutex.leave(); 496 497 //if there are no more mappings left and the memory map's handle has been 498 //closed, then delete the object 499 if(nrMappings == 0 && referenced == 0) { 500 delete this; 524 BOOL Win32MemMap::invalidatePages(ULONG offset, ULONG size) 525 { 526 ULONG diff = offset & 0xFFF; 527 BOOL ret; 528 529 offset &= ~0xFFF; 530 size += diff; 531 532 dprintf(("Win32MemMap::invalidatePages %x %x", offset, size)); 533 ret = VirtualFree((LPSTR)pMapping + offset, size, MEM_DECOMMIT); 534 if(ret == FALSE) { 535 dprintf(("ERROR: Win32MemMap::invalidatePages: VirtualFree failed!!")); 501 536 } 502 537 return TRUE; 503 fail: 504 mapMutex.leave(); 505 return FALSE; 506 } 507 //****************************************************************************** 508 //****************************************************************************** 509 LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess) 510 { 511 DWORD processId = GetCurrentProcessId(); 512 513 mapMutex.enter(); 514 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY)); 538 } 539 //****************************************************************************** 540 // Win32MemMap::allocateMap 541 // 542 // Allocate memory for the map if not yet already done. 543 // 544 // Returns: 545 // FALSE - success 546 // TRUE - failure 547 // 548 //****************************************************************************** 549 BOOL Win32MemMap::allocateMap() 550 { 515 551 ULONG fAlloc = 0; 516 Win32MemMapView *mapview; 517 518 //@@@PH: if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY)) 519 // Docs say FILE_MAP_ALL_ACCESS is same as FILE_MAP_WRITE. Doesn't match reality though. 520 if(fdwAccess & ~FILE_MAP_ALL_ACCESS) 521 goto parmfail; 522 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE)) 523 goto parmfail; 524 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY))) 525 goto parmfail; 526 527 //@@@PH 528 if (fdwAccess != FILE_MAP_ALL_ACCESS) 529 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY)) 530 goto parmfail; 531 532 if(offset+size > mSize && (!(fdwAccess & FILE_MAP_WRITE) || hMemFile == -1)) 533 goto parmfail; 534 535 //SvL: TODO: Doesn't work for multiple views 536 if(offset+size > mSize) { 537 mSize = offset+size; 538 } 539 540 //TODO: If committed, read file into memory 541 #if 0 542 if(mProtFlags & SEC_COMMIT) 543 fAlloc |= MEM_COMMIT; 544 else 545 if(mProtFlags & SEC_RESERVE) 546 fAlloc |= MEM_RESERVE; 547 #else 552 548 553 fAlloc = MEM_RESERVE; 549 #endif550 554 551 555 //Memory has already been allocated for executable image maps (only used internally) … … 567 571 } 568 572 if(pMapping == NULL) { 569 dprintf(("Win32MemMap::map FileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));573 dprintf(("Win32MemMap::mapViewOfFile: VirtualAlloc %x %x failed!", mSize, fAlloc)); 570 574 goto fail; 571 575 } … … 574 578 VirtualAlloc(pMapping, mSize, MEM_COMMIT, PAGE_READWRITE); 575 579 } 580 581 DWORD nrPages = mSize >> PAGE_SHIFT; 582 if(mSize & 0xFFF) 583 nrPages++; 584 576 585 if(hMemFile != -1 && (mProtFlags & SEC_COMMIT)) { 577 DWORD nrPages = mSize >> PAGE_SHIFT; 578 if(mSize & 0xFFF) 579 nrPages++; 580 581 commitPage(0, FALSE, nrPages); 582 } 583 } 586 commitPage((ULONG)pMapping, 0, FALSE, nrPages); 587 } 588 //Allocate bitmap for all pages to keep track of write access (file maps only) 589 //Necessary for FlushViewOfFile. 590 if(hMemFile != -1) { 591 int sizebitmap = nrPages/8 + 1; 592 593 pWriteBitmap = (char *)_smalloc(sizebitmap); 594 if(pWriteBitmap == NULL) { 595 DebugInt3(); 596 goto fail; 597 } 598 memset(pWriteBitmap, 0, sizebitmap); 599 } 600 } 601 return TRUE; 602 603 fail: 604 return FALSE; 605 } 606 //****************************************************************************** 607 // Win32MemMap::mapViewOfFile 608 // 609 // Map the view identified by addr 610 // 611 // Parameters: 612 // 613 // ULONG size - size of view 614 // ULONG offset - offset in memory map 615 // ULONG fdwAccess - access flags 616 // FILE_MAP_WRITE, FILE_MAP_READ, FILE_MAP_COPY 617 // FILE_MAP_ALL_ACCESS 618 // 619 // 620 // Returns: 621 // <>NULL - success, view address 622 // NULL - failure 623 // 624 //****************************************************************************** 625 LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess) 626 { 627 DWORD processId = GetCurrentProcessId(); 628 629 mapMutex.enter(); 630 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY)); 631 Win32MemMapView *mapview; 632 633 //@@@PH: if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY)) 634 // Docs say FILE_MAP_ALL_ACCESS is same as FILE_MAP_WRITE. Doesn't match reality though. 635 if(fdwAccess & ~FILE_MAP_ALL_ACCESS) 636 goto parmfail; 637 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE)) 638 goto parmfail; 639 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY))) 640 goto parmfail; 641 642 if (fdwAccess != FILE_MAP_ALL_ACCESS) 643 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY)) 644 goto parmfail; 645 646 if(offset+size > mSize && (!(fdwAccess & FILE_MAP_WRITE) || hMemFile == -1)) 647 goto parmfail; 648 649 //SvL: TODO: Doesn't work for multiple views 650 if(offset+size > mSize) { 651 mSize = offset+size; 652 } 653 654 if(allocateMap() == FALSE) { 655 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 656 goto fail; 657 } 658 584 659 mapview = new Win32MemMapView(this, offset, (size == 0) ? (mSize - offset) : size, fdwAccess); 585 660 if(mapview == NULL) { … … 587 662 } 588 663 if(mapview->everythingOk() == FALSE) { 589 dprintf(("Win32MemMap::map FileView: !mapview->everythingOk"));664 dprintf(("Win32MemMap::mapViewOfFile: !mapview->everythingOk")); 590 665 delete mapview; 591 666 goto fail; 592 667 } 593 nrMappings++;594 668 mapMutex.leave(); 669 SetLastError(ERROR_SUCCESS); 595 670 return mapview->getViewAddr(); 596 671 597 672 parmfail: 598 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER")); 599 SetLastError(ERROR_INVALID_PARAMETER); 673 dprintf(("Win32MemMap::mapViewOfFile: invalid parameter (ERROR_ACCESS_DENIED)")); 674 //NT4 SP6 returns ERROR_ACCESS_DENIED for most invalid parameters 675 SetLastError(ERROR_ACCESS_DENIED); 600 676 fail: 601 677 mapMutex.leave(); … … 603 679 } 604 680 //****************************************************************************** 681 // Win32MemMap::unmapViewOfFile 682 // 683 // Unmap the view identified by addr 684 // 685 // Parameters: 686 // 687 // LPVOID addr - view address; doesn't need to be the address 688 // returned by MapViewOfFile(Ex) (as MSDN clearly says); 689 // can be any address within the view range 690 // 691 // Returns: 692 // TRUE - success 693 // FALSE - failure 694 // 695 //****************************************************************************** 696 BOOL Win32MemMap::unmapViewOfFile(LPVOID addr) 697 { 698 Win32MemMapView *view; 699 700 dprintf(("Win32MemMap::unmapViewOfFile %x (nrmaps=%d)", addr, nrMappings)); 701 mapMutex.enter(); 702 703 if(nrMappings == 0) 704 goto fail; 705 706 view = Win32MemMapView::findView((ULONG)addr); 707 if(view == NULL) 708 goto fail; 709 710 delete view; 711 712 if(nrMappings == 0) { 713 VirtualFree(pMapping, 0, MEM_RELEASE); 714 pMapping = NULL; 715 } 716 mapMutex.leave(); 717 718 SetLastError(ERROR_SUCCESS); 719 return TRUE; 720 fail: 721 mapMutex.leave(); 722 SetLastError(ERROR_INVALID_ADDRESS); 723 return FALSE; 724 } 725 //****************************************************************************** 605 726 //We determine whether a page has been modified by checking it's protection flags 606 727 //If the write flag is set, this means commitPage had to enable this due to a pagefault … … 612 733 BOOL Win32MemMap::flushView(ULONG viewaddr, ULONG offset, ULONG cbFlush) 613 734 { 614 LPVOID lpvBase = (LPVOID)((ULONG)pMapping+offset); 615 MEMORY_BASIC_INFORMATION memInfo; 616 ULONG nrBytesWritten, size; 617 int i; 735 ULONG nrBytesWritten, size, accessflags, oldProt; 736 Win32MemMapView *view; 737 int i; 738 739 dprintf(("Win32MemMap::flushView: %x %x", (ULONG)pMapping+offset, cbFlush)); 618 740 619 741 if(image) //no flushing for image maps 620 return TRUE; 621 622 dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush)); 623 if(nrMappings == 0) 624 goto parmfail; 742 return TRUE; 743 744 if(hMemFile == -1) 745 goto success; //TODO: Return an error here? 746 747 if(offset > mSize) 748 goto parmfail; 749 750 if(viewaddr != MMAP_FLUSHVIEW_ALL) 751 { 752 view = Win32MemMapView::findView(viewaddr); 753 if(nrMappings == 0 || view == NULL) { 754 DebugInt3(); //should never happen 755 goto parmfail; 756 } 757 accessflags = view->getAccessFlags(); 758 } 759 else { 760 //force a flush to disk; only those pages marked dirty are flushed anyway 761 accessflags = FILE_MAP_WRITE; 762 } 763 //If the view is readonly or copy on write, then the flush is ignored 764 if(!(accessflags & MEMMAP_ACCESS_WRITE) || (accessflags & MEMMAP_ACCESS_COPYONWRITE)) 765 { 766 dprintf(("Readonly or Copy-On-Write memory map -> ignore flush")); 767 //this is not a failure; NT4 SP6 returns success 768 goto success; 769 } 625 770 626 771 if(cbFlush == 0) 627 cbFlush = mSize;628 629 if( lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)630 goto parmfail;631 632 if(mProtFlags & PAGE_READONLY) 633 goto parmfail;634 635 if(hMemFile == -1)636 goto success; //TODO: Return an error here?637 638 while(cbFlush) { 639 if(VirtualQuery((LPSTR)lpvBase, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) {640 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));641 goto fail;642 }643 //If a page (or range of pages) is reserved or write protected, we644 //won't bother flushing it to disk645 if(memInfo.State & MEM_COMMIT && 646 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))647 {//committed and allowed for writing?648 offset = (ULONG)lpvBase - (ULONG)pMapping;649 size = memInfo.RegionSize;650 if(size > cbFlush) {651 size = cbFlush;652 }653 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));654 655 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {656 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));657 goto fail;658 }659 if(WriteFile(hMemFile, (LPSTR)lpvBase, size, &nrBytesWritten, NULL) == FALSE) { 660 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase));661 goto fail;662 }663 if(nrBytesWritten != size) {664 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase));665 goto fail;666 }667 }668 lpvBase = (LPVOID)((ULONG)lpvBase + memInfo.RegionSize); 669 670 if(cbFlush < memInfo.RegionSize)671 break; 672 673 cbFlush -= memInfo.RegionSize;772 cbFlush = mSize; 773 774 if(offset + cbFlush > mSize) { 775 cbFlush -= (offset + cbFlush - mSize); 776 } 777 778 //Check the write page bitmap for dirty pages and write them to disk 779 while(cbFlush) 780 { 781 int startPage = offset >> PAGE_SHIFT; 782 size = PAGE_SIZE; 783 784 if(isDirtyPage(startPage)) 785 { 786 if(size > cbFlush) { 787 size = cbFlush; 788 } 789 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size)); 790 791 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) { 792 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset)); 793 goto fail; 794 } 795 if(WriteFile(hMemFile, (LPSTR)((ULONG)pMapping + offset), size, &nrBytesWritten, NULL) == FALSE) { 796 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)pMapping + offset)); 797 goto fail; 798 } 799 if(nrBytesWritten != size) { 800 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)pMapping + offset)); 801 goto fail; 802 } 803 clearDirtyPages(startPage, 1); 804 805 //We've just flushed the page to disk, so we need to track future writes 806 //again; Set page to readonly (first memory map, then alias(es)) 807 if(VirtualProtect((LPVOID)((ULONG)pMapping + offset), size, PAGE_READONLY, &oldProt) == FALSE) { 808 dprintf(("VirtualProtect %x %x PAGE_READWRITE failed with %d!!", (ULONG)pMapping + offset, size, GetLastError())); 809 goto fail; 810 } 811 updateViewPages(offset, size, PAGEVIEW_READONLY); 812 } 813 814 if(cbFlush < size) 815 break; 816 817 cbFlush -= size; 818 offset += size; 674 819 } 675 820 success: 821 SetLastError(ERROR_SUCCESS); 676 822 return TRUE; 823 677 824 parmfail: 678 825 SetLastError(ERROR_INVALID_PARAMETER); … … 724 871 if(map) map->AddRef(); 725 872 DosLeaveCriticalSection(&globalmapcritsect); 726 if(!map) dprintf (("Win32MemMap::findMapByFile: couldn't find map with file handle %x", hFile));873 if(!map) dprintf2(("Win32MemMap::findMapByFile: couldn't find map with file handle %x", hFile)); 727 874 return map; 728 875 } … … 752 899 void Win32MemMap::deleteAll() 753 900 { 754 Win32MemMap *map = memmaps, *nextmap;901 Win32MemMap *map, *nextmap; 755 902 DWORD processId = GetCurrentProcessId(); 756 903 757 904 //delete all maps created by this process 758 905 DosEnterCriticalSection(&globalmapcritsect); 906 907 startdeleteviews: 908 map = memmaps; 759 909 while(map) { 760 nextmap = map->next; 761 if(map->getProcessId() == processId) { 762 //Delete map directly for executable images (only used internally) 763 if(map->getImage()) { 764 delete map; 765 } 766 else { 767 delete map; 768 } 769 } 770 else { 771 //delete all views created by this process for this map 772 Win32MemMapView::deleteViews(map); 773 } 774 map = nextmap; 910 map->AddRef(); //make sure it doesn't get deleted 911 912 //delete all views created by this process for this map 913 Win32MemMapView::deleteViews(map); 914 915 nextmap = map->next; 916 917 //map->Release can delete multiple objects (duplicate memory map), so make 918 //sure our nextmap pointer remains valid by increasing the refcount 919 if(nextmap) nextmap->AddRef(); 920 map->Release(); 921 922 if(nextmap && nextmap->Release() == 0) { 923 //oops, nextmap was just deleted and is no longer valid 924 //can't continue from here, so let's start again 925 dprintf(("oops, nextmap is invalid -> start again (1)")); 926 goto startdeleteviews; 927 } 928 929 map = nextmap; 930 } 931 startdelete: 932 map = memmaps; 933 while(map) { 934 nextmap = map->next; 935 if(map->getProcessId() == processId) 936 { 937 //delete map can delete multiple objects (duplicate memory map), so make 938 //sure our nextmap pointer remains valid by increasing the refcount 939 if(nextmap) nextmap->AddRef(); 940 delete map; 941 942 if(nextmap && nextmap->Release() == 0) { 943 //oops, nextmap was just deleted and is no longer valid 944 //can't continue from here, so let's start again 945 dprintf(("oops, nextmap is invalid -> start again (2)")); 946 goto startdelete; 947 } 948 } 949 map = nextmap; 775 950 } 776 951 DosLeaveCriticalSection(&globalmapcritsect); 777 952 } 778 953 //****************************************************************************** 779 //****************************************************************************** 780 Win32MemMapView::Win32MemMapView(Win32MemMap *map, ULONG offset, ULONG size, 781 ULONG fdwAccess) 782 { 783 LPVOID viewaddr = (LPVOID)((ULONG)map->getMappingAddr()+offset); 784 ULONG accessAttr = 0; 785 Win32MemMapView *tmpview = mapviews; 786 787 errorState = 0; 788 mParentMap = map; 789 mSize = size; 790 mOffset = offset; 791 mProcessId = GetCurrentProcessId(); 792 pShareViewAddr = NULL; 793 794 switch(fdwAccess) { 795 case FILE_MAP_READ: 796 accessAttr = PAG_READ; 797 mfAccess = MEMMAP_ACCESS_READ; 798 break; 799 case FILE_MAP_ALL_ACCESS: 800 case FILE_MAP_WRITE: 801 case FILE_MAP_WRITE|FILE_MAP_READ: 802 case FILE_MAP_COPY: 803 accessAttr = (PAG_READ|PAG_WRITE); 804 mfAccess = MEMMAP_ACCESS_READ | MEMMAP_ACCESS_WRITE; 805 break; 806 } 807 //Named file mappings from other processes are always shared; 808 //map into our address space 809 if(map->getMemName() != NULL && map->getProcessId() != mProcessId) 810 { 811 //shared memory map, so map it into our address space 812 if(OSLibDosGetNamedSharedMem((LPVOID *)&viewaddr, map->getMemName()) != OSLIB_NOERROR) { 813 dprintf(("new OSLibDosGetNamedSharedMem FAILED")); 814 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 815 errorState = 1; 816 return; 817 } 818 pShareViewAddr = viewaddr; 819 } 820 821 //view == memory mapping for executable images (only used internally) 822 if(map->getImage()) { 823 pMapView = map->getMappingAddr(); 824 } 825 else { 826 if(OSLibDosAliasMem(viewaddr, size, &pMapView, accessAttr) != OSLIB_NOERROR) { 827 dprintf(("new OSLibDosAliasMem FAILED")); 828 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 829 errorState = 1; 830 return; 831 } 832 } 833 dprintf(("Win32MemMapView::Win32MemMapView: created %x (alias for %x), size %d", pMapView, viewaddr, size)); 834 835 DosEnterCriticalSection(&globalmapcritsect); 836 if(tmpview == NULL || tmpview->getViewAddr() > pMapView) { 837 next = mapviews; 838 mapviews = this; 839 } 840 else { 841 while(tmpview->next) { 842 if(tmpview->next->getViewAddr() > pMapView) { 843 break; 844 } 845 tmpview = tmpview->next; 846 } 847 next = tmpview->next; 848 tmpview->next = this; 849 } 850 DosLeaveCriticalSection(&globalmapcritsect); 851 } 852 //****************************************************************************** 853 //****************************************************************************** 854 Win32MemMapView::~Win32MemMapView() 855 { 856 if(errorState != 0) 857 return; 858 859 dprintf(("Win32MemMapView dtor: deleting view %x %x", mOffset, mSize)); 860 861 if(mfAccess & MEMMAP_ACCESS_WRITE) 862 mParentMap->flushView(MMAP_FLUSHVIEW_ALL, mOffset, mSize); 863 864 //Don't free memory for executable image map views (only used internally) 865 if(!mParentMap->getImage()) 866 OSLibDosFreeMem(pMapView); 867 868 if(pShareViewAddr) { 869 OSLibDosFreeMem(pShareViewAddr); 870 } 871 872 DosEnterCriticalSection(&globalmapcritsect); 873 Win32MemMapView *view = mapviews; 874 875 if(view == this) { 876 mapviews = next; 877 } 878 else { 879 while(view->next) { 880 if(view->next == this) 881 break; 882 view = view->next; 883 } 884 if(view->next) { 885 view->next = next; 886 } 887 else dprintf(("Win32MemMapView::~Win32MemMapView: map not found!! (%x)", this)); 888 } 889 DosLeaveCriticalSection(&globalmapcritsect); 890 } 891 //****************************************************************************** 892 //****************************************************************************** 893 void Win32MemMapView::deleteViews(Win32MemMap *map) 894 { 895 DosEnterCriticalSection(&globalmapcritsect); 896 Win32MemMapView *view = mapviews, *nextview; 897 898 if(view != NULL) { 899 while(view) { 900 nextview = view->next; 901 if(view->getParentMap() == map) 902 { 903 DosLeaveCriticalSection(&globalmapcritsect); 904 delete view; 905 DosEnterCriticalSection(&globalmapcritsect); 906 } 907 view = nextview; 908 } 909 } 910 DosLeaveCriticalSection(&globalmapcritsect); 911 } 912 //****************************************************************************** 913 //****************************************************************************** 914 // Win32MemMap::findMapByView 915 // 916 // Find the map of the view that contains the specified starting address 917 // and has the specified access type 954 // Win32MemMapView::markDirtyPages 955 // 956 // Mark pages as dirty (changed) in the write page bitmap 918 957 // 919 958 // Parameters: 920 959 // 921 // ULONG address - view address 922 // ULONG *offset - address of ULONG that receives the offset 923 // in the returned memory map 924 // ULONG accessType - access type: 925 // MEMMAP_ACCESS_READ 926 // MEMMAP_ACCESS_WRITE 927 // MEMMAP_ACCESS_EXECUTE 928 // 929 // Returns: 930 // <> NULL - success, address of parent map object 931 // NULL - failure 932 // 933 //****************************************************************************** 934 //****************************************************************************** 935 Win32MemMap *Win32MemMapView::findMapByView(ULONG address, 936 ULONG *offset, 937 ULONG accessType) 938 { 939 Win32MemMap *map = NULL; 940 ULONG ulOffset; 941 942 if(mapviews == NULL) return NULL; 943 944 DosEnterCriticalSection(&globalmapcritsect); 945 Win32MemMapView *view = mapviews; 946 ULONG ulViewAddr; 947 948 if(!offset) offset = &ulOffset; 949 950 *offset = 0; 951 952 if(view != NULL) 953 { 954 do 955 { 956 ulViewAddr = (ULONG)view->getViewAddr(); 957 958 // if ulViewAddr is > address, we've exhausted 959 // the sorted list already and can abort search. 960 if(ulViewAddr <= address) 961 { 962 if(ulViewAddr + view->getSize() > address && 963 view->getAccessFlags() >= accessType) 964 { 965 *offset = view->getOffset() + (address - ulViewAddr); 966 goto success; 967 } 968 969 // Not found yet, continue search with next map 970 view = view->next; 971 } 972 else 973 { 974 // list is exhausted, abort loop 975 view = NULL; 976 } 977 } 978 while(view); 979 980 //failure if we get here 981 view = NULL; 982 } 983 success: 984 #ifdef DEBUG 985 if(view && !view->getParentMap()->isImageMap()) 986 dprintf(("findMapByView %x %x -> %x off %x", 987 address, 988 accessType, 989 view->getViewAddr(), 990 *offset)); 991 #endif 992 993 if(view) { 994 map = view->getParentMap(); 995 if(map) map->AddRef(); 996 } 997 998 DosLeaveCriticalSection(&globalmapcritsect); 999 1000 return map; 1001 } 1002 //****************************************************************************** 1003 // Win32MemMap::findView 1004 // 1005 // Find the view that contains the specified starting address 960 // int startpage - start page 961 // int nrpages - number of pages 962 // 963 // 964 //****************************************************************************** 965 void Win32MemMap::markDirtyPages(int startpage, int nrpages) 966 { 967 if(pWriteBitmap == NULL) return; //can be NULL for non-file mappings 968 969 for(int i=startpage;i<startpage+nrpages;i++) { 970 set_bit(i, pWriteBitmap); 971 } 972 } 973 //****************************************************************************** 974 // Win32MemMapView::clearDirtyPages 975 // 976 // Mark pages as clean in the write page bitmap 1006 977 // 1007 978 // Parameters: 1008 979 // 1009 // LPVOID address - view address 1010 // 1011 // Returns: 1012 // <> NULL - success, address view object 1013 // NULL - failure 1014 // 1015 //****************************************************************************** 1016 Win32MemMapView *Win32MemMapView::findView(ULONG address) 1017 { 1018 ULONG ulViewAddr; 1019 1020 DosEnterCriticalSection(&globalmapcritsect); 1021 Win32MemMapView *view = mapviews; 1022 1023 if(view != NULL) { 1024 while(view) { 1025 ulViewAddr = (ULONG)view->getViewAddr(); 1026 if(ulViewAddr <= address && ulViewAddr + view->getSize() > address) 1027 { 1028 break; 1029 } 1030 view = view->next; 1031 } 1032 } 1033 DosLeaveCriticalSection(&globalmapcritsect); 1034 return view; 1035 } 1036 //****************************************************************************** 1037 //****************************************************************************** 980 // int startpage - start page 981 // int nrpages - number of pages 982 // 983 // 984 //****************************************************************************** 985 void Win32MemMap::clearDirtyPages(int startpage, int nrpages) 986 { 987 if(pWriteBitmap == NULL) return; //can be NULL for non-file mappings 988 989 for(int i=startpage;i<startpage+nrpages;i++) { 990 clear_bit(i, pWriteBitmap); 991 } 992 } 993 //****************************************************************************** 994 //******************************************************************************
Note:
See TracChangeset
for help on using the changeset viewer.