Ignore:
Timestamp:
Jul 15, 2002, 4:28:53 PM (23 years ago)
Author:
sandervl
Message:

Rewrote algorithm for 64kb alignment in VirtualAlloc'ed memory; allocation changes for heap (in 64kb chunks) & PE image (align at 64kb)

File:
1 edited

Legend:

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

    r8866 r8877  
    1 /* $Id: virtual.cpp,v 1.47 2002-07-13 16:30:40 sandervl Exp $ */
     1/* $Id: virtual.cpp,v 1.48 2002-07-15 14:28:52 sandervl Exp $ */
    22
    33/*
     
    2828#include "mmap.h"
    2929#include "oslibdos.h"
     30#include "oslibmem.h"
    3031
    3132#define DBG_LOCALLOG    DBG_virtual
     
    270271                             DWORD  fdwProtect)
    271272{
    272   PVOID Address = lpvAddress;
    273   ULONG flag = 0, base;
    274   DWORD rc;
    275 
    276   SetLastError(ERROR_SUCCESS);
    277 
    278   if (cbSize > 0x7fc00000)  /* 2Gb - 4Mb */
    279   {
    280     dprintf(("VirtualAlloc: size too large"));
     273    PVOID Address = lpvAddress;
     274    ULONG flag = 0, base;
     275    DWORD rc;
     276
     277    SetLastError(ERROR_SUCCESS);
     278
     279    if (cbSize > 0x7fc00000)  /* 2Gb - 4Mb */
     280    {
     281        dprintf(("VirtualAlloc: size too large"));
    281282        SetLastError( ERROR_OUTOFMEMORY );
    282283        return NULL;
    283   }
    284 
    285   if (!(fdwAllocationType & (MEM_COMMIT | MEM_RESERVE)) ||
     284    }
     285
     286    if (!(fdwAllocationType & (MEM_COMMIT | MEM_RESERVE)) ||
    286287       (fdwAllocationType & ~(MEM_COMMIT | MEM_RESERVE)))
    287   {
     288    {
    288289        dprintf(("VirtualAlloc: Invalid parameter"));
    289290        SetLastError( ERROR_INVALID_PARAMETER );
    290291        return NULL;
    291   }
    292 
    293   if(fdwAllocationType & MEM_COMMIT)
    294   {
     292    }
     293
     294    if(fdwAllocationType & MEM_COMMIT)
     295    {
    295296        dprintf(("VirtualAlloc: commit\n"));
    296297        flag = PAG_COMMIT;
    297   }
    298 
    299   if(fdwAllocationType & MEM_RESERVE) {
    300     //SvL: DosRead crashes if memory is initially reserved with write
     298    }
     299
     300    if(fdwAllocationType & MEM_RESERVE) {
     301        //SvL: DosRead crashes if memory is initially reserved with write
    301302        //     access disabled (OS/2 bug) even if the commit sets the page
    302303        //     flags to read/write:
    303     // DosSetMem does not alter the 16 bit selectors so if you change memory
    304     // attributes and then access the memory with a 16 bit API (such as DosRead),
    305     // it will have the old (alloc time) attributes
    306     flag |= PAG_READ|PAG_WRITE;
    307   }
    308   if(fdwProtect & PAGE_READONLY)     flag |= PAG_READ;
    309   if(fdwProtect & PAGE_NOACCESS)     flag |= PAG_READ; //can't do this in OS/2
    310   if(fdwProtect & PAGE_READWRITE)    flag |= (PAG_READ | PAG_WRITE);
    311   if(fdwProtect & PAGE_WRITECOPY)    flag |= (PAG_READ | PAG_WRITE);
    312 
    313   if(fdwProtect & PAGE_EXECUTE_READWRITE) flag |= (PAG_EXECUTE | PAG_WRITE | PAG_READ);
    314   if(fdwProtect & PAGE_EXECUTE_READ) flag |= (PAG_EXECUTE | PAG_READ);
    315   if(fdwProtect & PAGE_EXECUTE)      flag |= PAG_EXECUTE;
    316 
    317   if(fdwProtect & PAGE_GUARD) {
     304        // DosSetMem does not alter the 16 bit selectors so if you change memory
     305        // attributes and then access the memory with a 16 bit API (such as DosRead),
     306        // it will have the old (alloc time) attributes
     307        flag |= PAG_READ|PAG_WRITE;
     308    }
     309    if(fdwProtect & PAGE_READONLY)     flag |= PAG_READ;
     310    if(fdwProtect & PAGE_NOACCESS)     flag |= PAG_READ; //can't do this in OS/2
     311    if(fdwProtect & PAGE_READWRITE)    flag |= (PAG_READ | PAG_WRITE);
     312    if(fdwProtect & PAGE_WRITECOPY)    flag |= (PAG_READ | PAG_WRITE);
     313
     314    if(fdwProtect & PAGE_EXECUTE_READWRITE) flag |= (PAG_EXECUTE | PAG_WRITE | PAG_READ);
     315    if(fdwProtect & PAGE_EXECUTE_READ) flag |= (PAG_EXECUTE | PAG_READ);
     316    if(fdwProtect & PAGE_EXECUTE)      flag |= PAG_EXECUTE;
     317
     318    if(fdwProtect & PAGE_GUARD) {
    318319        dprintf(("ERROR: PAGE_GUARD bit set for VirtualAlloc -> we don't support this right now!"));
    319320        flag |= PAG_GUARD;
    320   }
    321 
    322   //just do this if other options are used
    323   if(!(flag & (PAG_READ | PAG_WRITE | PAG_EXECUTE)) || flag == 0)
    324   {
    325     dprintf(("VirtualAlloc: Unknown protection flags, default to read/write"));
    326     flag |= PAG_READ | PAG_WRITE;
    327   }
    328 
    329   if(lpvAddress)
    330   {
    331     Win32MemMap *map;
    332     ULONG offset, nrpages, accessflags = 0;
     321    }
    333322   
    334     nrpages = cbSize >> PAGE_SHIFT;
    335     if(cbSize & 0xFFF)
    336         nrpages++;
    337 
    338     if(flag & PAG_READ) {
    339         accessflags |= MEMMAP_ACCESS_READ;
    340     }
    341     if(flag & PAG_WRITE) {
    342         accessflags |= MEMMAP_ACCESS_WRITE;
    343     }
    344     if(flag & PAG_EXECUTE) {
    345         accessflags |= MEMMAP_ACCESS_EXECUTE;
    346     }
    347     map = Win32MemMapView::findMapByView((ULONG)lpvAddress, &offset, accessflags);
    348     if(map) {
    349         //TODO: We don't allow protection flag changes for mmaped files now
    350         map->commitPage(offset, FALSE, nrpages);
    351         return lpvAddress;
    352     }
    353   }
    354 
    355   // commit memory
    356   if(fdwAllocationType & MEM_COMMIT)
    357   {
    358     Address = lpvAddress;
    359 
    360     rc = OSLibDosSetMem(lpvAddress, cbSize, flag);
    361 
    362     //might try to commit larger part with same base address
    363     if(rc == OSLIB_ERROR_ACCESS_DENIED && cbSize > 4096 )
    364     { //knut: AND more than one page
    365         char *newbase = (char *)lpvAddress + ((cbSize-1) & 0xFFFFF000); //knut: lets not start after the last page!
    366         ULONG size, os2flags;
    367 
    368         while(newbase >= (char *)lpvAddress)
    369         {     //knut: should check first page to!!
    370             size     = 4096;
    371             os2flags = 0;
    372             rc = OSLibDosQueryMem(newbase, &size, &os2flags);
    373             if(rc)
    374                 break;
    375 
    376             if(os2flags & PAG_COMMIT)
     323    //just do this if other options are used
     324    if(!(flag & (PAG_READ | PAG_WRITE | PAG_EXECUTE)) || flag == 0)
     325    {
     326        dprintf(("VirtualAlloc: Unknown protection flags, default to read/write"));
     327        flag |= PAG_READ | PAG_WRITE;
     328    }
     329
     330    if(lpvAddress)
     331    {
     332        Win32MemMap *map;
     333        ULONG offset, nrpages, accessflags = 0;
     334   
     335        nrpages = cbSize >> PAGE_SHIFT;
     336        if(cbSize & 0xFFF)
     337            nrpages++;
     338
     339        if(flag & PAG_READ) {
     340            accessflags |= MEMMAP_ACCESS_READ;
     341        }
     342        if(flag & PAG_WRITE) {
     343            accessflags |= MEMMAP_ACCESS_WRITE;
     344        }
     345        if(flag & PAG_EXECUTE) {
     346            accessflags |= MEMMAP_ACCESS_EXECUTE;
     347        }
     348        map = Win32MemMapView::findMapByView((ULONG)lpvAddress, &offset, accessflags);
     349        if(map) {
     350            //TODO: We don't allow protection flag changes for mmaped files now
     351            map->commitPage(offset, FALSE, nrpages);
     352            return lpvAddress;
     353        }
     354    }
     355
     356    // commit memory
     357    if(fdwAllocationType & MEM_COMMIT)
     358    {
     359        Address = lpvAddress;
     360
     361        rc = OSLibDosSetMem(lpvAddress, cbSize, flag);
     362
     363        //might try to commit larger part with same base address
     364        if(rc == OSLIB_ERROR_ACCESS_DENIED && cbSize > 4096 )
     365        { //knut: AND more than one page
     366            char *newbase = (char *)lpvAddress + ((cbSize-1) & 0xFFFFF000); //knut: lets not start after the last page!
     367            ULONG size, os2flags;
     368   
     369            while(newbase >= (char *)lpvAddress)
     370            {     //knut: should check first page to!!
     371                size     = 4096;
     372                os2flags = 0;
     373                rc = OSLibDosQueryMem(newbase, &size, &os2flags);
     374                if(rc)
     375                    break;
     376
     377                if(os2flags & PAG_COMMIT)
     378                {
     379                    newbase += 4096;
     380                    break;
     381                }
     382                newbase -= 4096;
     383            }
     384
     385            if(rc == 0)
    377386            {
    378                 newbase += 4096;
    379                 break;
     387                //In case it wants to commit bytes that fall into the last
     388                //page of the previous commit command
     389                if(cbSize > ((int)newbase - (int)lpvAddress))
     390                    rc = OSLibDosSetMem(newbase, cbSize - ((int)newbase - (int)lpvAddress), flag);
    380391            }
    381             newbase -= 4096;
    382         }
    383 
    384         if(rc == 0)
     392            else  return(NULL);
     393        }
     394        else
    385395        {
    386             //In case it wants to commit bytes that fall into the last
    387             //page of the previous commit command
    388             if(cbSize > ((int)newbase - (int)lpvAddress))
    389                 rc = OSLibDosSetMem(newbase, cbSize - ((int)newbase - (int)lpvAddress), flag);
    390         }
    391         else  return(NULL);
    392 
    393     }
    394     else
    395     {
    396         if(rc == OSLIB_ERROR_INVALID_ADDRESS) {
    397             rc = OSLibDosAllocMem(&Address, cbSize, flag );
    398         }
    399         else {
    400             if(rc) {
    401                 //check if the app tries to commit an already commited part of memory or change the protection flags
    402                 ULONG size = cbSize, os2flags, newrc;
    403                 newrc = OSLibDosQueryMem(lpvAddress, &size, &os2flags);
    404                 if(newrc == 0) {
    405                     if(size >= cbSize && (os2flags & PAG_COMMIT)) {
    406                             dprintf(("VirtualAlloc: commit on committed memory"));
    407                             if((flag & (PAG_READ|PAG_WRITE|PAG_EXECUTE)) != (os2flags & (PAG_READ|PAG_WRITE|PAG_EXECUTE)))
    408                             {   //change protection flags
    409                                 DWORD tmp;
    410                                 if(VirtualProtect(lpvAddress, cbSize, fdwProtect, &tmp) == TRUE) {
    411                                     return lpvAddress;
     396            if(rc == OSLIB_ERROR_INVALID_ADDRESS) {
     397                rc = OSLibDosAllocMem(&Address, cbSize, flag );
     398            }           
     399            else {
     400                if(rc) {
     401                    //check if the app tries to commit an already commited part of memory or change the protection flags
     402                    ULONG size = cbSize, os2flags, newrc;
     403                    newrc = OSLibDosQueryMem(lpvAddress, &size, &os2flags);
     404                    if(newrc == 0) {
     405                        if(size >= cbSize && (os2flags & PAG_COMMIT)) {
     406                                dprintf(("VirtualAlloc: commit on committed memory"));
     407                                if((flag & (PAG_READ|PAG_WRITE|PAG_EXECUTE)) != (os2flags & (PAG_READ|PAG_WRITE|PAG_EXECUTE)))
     408                                {   //change protection flags
     409                                    DWORD tmp;
     410                                    if(VirtualProtect(lpvAddress, cbSize, fdwProtect, &tmp) == TRUE) {
     411                                        return lpvAddress;
     412                                    }
     413                                    dprintf(("ERROR: VirtualAlloc: commit on committed memory -> VirtualProtect failed!!"));
     414                                    return NULL;
    412415                                }
    413                                 dprintf(("ERROR: VirtualAlloc: commit on committed memory -> VirtualProtect failed!!"));
    414                                 return NULL;
    415                             }
    416                             //else everything ok
    417                             return lpvAddress;
     416                                //else everything ok
     417                                return lpvAddress;
     418                        }
     419                        else    dprintf(("Unexpected DosSetMem error %x", rc));
    418420                    }
    419                     else    dprintf(("Unexpected DosSetMem error %x", rc));
    420                 }
    421                 else {
    422                     dprintf(("Unexpected DosQueryMem error %x", newrc));
     421                    else {
     422                        dprintf(("Unexpected DosQueryMem error %x", newrc));
     423                    }
    423424                }
    424425            }
    425426        }
    426427    }
    427   }
    428   else
    429   {
    430     rc = OSLibDosAllocMem(&Address, cbSize, flag);
    431   }
    432 
    433   if(rc)
    434   {
    435     dprintf(("DosSetMem returned %d\n", rc));
    436     SetLastError( ERROR_OUTOFMEMORY );
    437     return(NULL);
    438   }
    439 
    440   dprintf(("VirtualAlloc returned %X\n", Address));
    441   return(Address);
     428    else
     429    {
     430        rc = OSLibDosAllocMem(&Address, cbSize, flag);
     431    }
     432
     433    if(rc)
     434    {
     435        dprintf(("DosSetMem returned %d\n", rc));
     436        SetLastError( ERROR_OUTOFMEMORY );
     437        return(NULL);
     438    }
     439
     440    dprintf(("VirtualAlloc returned %X\n", Address));
     441    return(Address);
    442442}
    443443//******************************************************************************
     
    665665    //      flags used in the initial call to VirtualAlloc
    666666    pmbiBuffer->AllocationProtect = pmbiBuffer->Protect;
    667     if(dAttr & PAG_BASE) {
    668         pmbiBuffer->AllocationBase = lpBase;
    669     }
    670     else
    671     {
    672         pmbiBuffer->AllocationBase = 0;
    673         while(lpBase > 0)
    674         {
    675             rc = OSLibDosQueryMem(lpBase, &cbRangeSize, &dAttr);
    676             if(rc) {
    677                 dprintf(("VirtualQuery - OSLibDosQueryMem %x %x returned %d\n",
    678                           lpBase, cbLength, rc));
    679                 break;
    680             }
    681             if(dAttr & PAG_BASE) {
    682                 pmbiBuffer->AllocationBase = lpBase;
    683                 break;
    684             }
    685             lpBase = (LPVOID)((ULONG)lpBase - PAGE_SIZE);
    686         }
    687     }
    688 #if 0
    689     //TODO!!!!!!!!!!!!
    690     //NOTE: !!!!!!!!!!!!!!!!!!!!!!!
    691     //Allocation base is always aligned at 64kb
    692     //the page with the PAG_BASE attribute might not be the real allocation base
    693     //(due to extra alloc + rounding (see oslibmem.cpp)
    694     //Only exception to this rule is the stack
    695     TEB *teb = GetThreadTEB();
    696     if(teb) {
    697         if(pmbiBuffer->AllocationBase >= teb->stack_low && pmbiBuffer->AllocationBase < teb->stack_top) {
    698              pmbiBuffer->AllocationBase = pmbiBuffer->AllocationBase;
    699         }
    700         else pmbiBuffer->AllocationBase = (LPVOID)(((DWORD)pmbiBuffer->AllocationBase + 0xFFFF) & 0xFFFF);
    701     }
    702     else pmbiBuffer->AllocationBase = (LPVOID)(((DWORD)pmbiBuffer->AllocationBase + 0xFFFF) & 0xFFFF);
    703     //END NOTE: !!!!!!!!!!!!!!!!!!!
    704 #endif
     667    pmbiBuffer->AllocationBase    = OSLibDosFindMemBase(lpBase);
    705668
    706669    dprintf(("Memory region alloc base          0x%08x", pmbiBuffer->AllocationBase));
Note: See TracChangeset for help on using the changeset viewer.