/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: mem_win32.c 430 2005-12-28 14:50:08Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "../common.h" #if defined(TARGET_WIN32) || defined(TARGET_WINCE) //#define FIND 0xCF9390 //#define SAFEGUARD 32 #define BLOCKGROUP 8 #ifndef STRICT #define STRICT #endif #include #if defined(_MSC_VER) && !defined(TARGET_WINCE) #include #endif #if defined(TARGET_WINCE) #define MAXPHY 16 #define CACHE_SYNC_INSTRUCTIONS 2 #define LOCKFLAG_WRITE 1 #define TBL_CACHE 0x08 #define TBL_BUFFER 0x04 typedef struct phymem { char* Virt; uint32_t Phy; uint32_t Length; uint32_t RefCount; phymemblock* Blocks; int BlockCount; } phymem; static phymem PhyMem[MAXPHY] = { 0 }; static BOOL (WINAPI* FuncVirtualSetAttributes)(LPVOID lpvAddress, DWORD cbSize, DWORD dwNewFlags, DWORD dwMask, LPDWORD lpdwOldFlags) = NULL; static BOOL (WINAPI* FuncFreePhysMem)(LPVOID) = NULL; static BOOL (WINAPI* FuncLockPages)(LPVOID lpvAddress,DWORD cbSize,PDWORD pPFNs,int fOptions) = NULL; static BOOL (WINAPI* FuncUnlockPages)(LPVOID lpvAddress,DWORD cbSize) = NULL; static LPVOID (WINAPI* FuncAllocPhysMem)(DWORD cbSize, DWORD fdwProtect, DWORD dwAlignmentMask, DWORD dwFlags, PULONG pPhysicalAddress) = NULL; static void (WINAPI* FuncCacheSync)(DWORD) = NULL; static BOOL (WINAPI* FuncVirtualCopy)(LPVOID, LPVOID, DWORD, DWORD) = NULL; static HMODULE CoreDLL = NULL; #endif typedef struct blockgroup { block Block; int Mask; int Unused; //align to 16bytes } blockgroup; static int PageSize = 4096; static array BlockGroup = { NULL }; #ifndef NDEBUG static int BlockAllocated = 0; #endif void* PhyMemAlloc(int Length,phymemblock* Blocks,int* BlockCount) { void* p = NULL; #if defined(TARGET_WINCE) if (*BlockCount>=1) { int n,Pos; int Count = 0; Length = (Length + PageSize-1) & ~(PageSize-1); if (FuncAllocPhysMem && FuncFreePhysMem && FuncVirtualCopy) { // try allocate in one continous block Blocks[0].Private = FuncAllocPhysMem(Length,PAGE_READWRITE,PageSize-1,0,&Blocks[0].Addr); if (Blocks[0].Private) { Blocks[0].Length = Length; Count = 1; } /* not worth it. allocphysmem is buggy anyway. won't be able to allocate per one pagesize if (!Count && *BlockCount>1) { int Left = Length; int BlockMax; int BlockSize = (Left+PageSize-1) & ~(PageSize-1); // allocate in separate blocks while (Count < *BlockCount && BlockSize > 0) { Blocks[Count].Private = FuncAllocPhysMem(BlockSize,PAGE_READWRITE,PageSize-1,0,&Blocks[Count].Addr); if (Blocks[Count].Private) { Blocks[Count].Length = BlockSize; ++Count; Left -= BlockSize; BlockMax = (Left+PageSize-1) & ~(PageSize-1); if (BlockSize > BlockMax) BlockSize = BlockMax; } else if (BlockSize > PageSize*8) BlockSize = (BlockSize/2+PageSize-1) & ~(PageSize-1); else BlockSize -= PageSize; } if (Left>0) { for (n=0;n> 8),Blocks[n].Length, PAGE_READWRITE | PAGE_PHYSICAL)) break; Pos += Blocks[n].Length; } if (n!=Count) { VirtualFree(p,0,MEM_RELEASE); p = NULL; } } if (!p) { for (n=0;n= *BlockCount) { Count = 0; break; } Blocks[Count].Addr = PFN[n]; Blocks[Count].Length = PageSize; Blocks[Count].Private = NULL; ++Count; } else Blocks[Count-1].Length += PageSize; Last = PFN[n] + PageSize; } if (!Count) FuncUnlockPages(p,Length); } if (!Count) { VirtualFree(p,0,MEM_RELEASE); p = NULL; } } } #ifdef ARM if (p && FuncVirtualSetAttributes && (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_XSCALE)) FuncVirtualSetAttributes(p,Length,TBL_CACHE|TBL_BUFFER,TBL_CACHE|TBL_BUFFER,NULL); #endif *BlockCount = Count; } #endif return p; } void PhyMemFree(void* p,phymemblock* Blocks,int BlockCount) { #if defined(TARGET_WINCE) if (p) { int n; if (FuncLockPages && FuncUnlockPages) { int Size = 0; for (n=0;nBlockCount == BlockCount && p->Length == Blocks[0].Length && p->Phy == Blocks[0].Addr) { for (n=1;nBlocks[n].Addr != Blocks[n].Addr || p->Blocks[n].Length != Blocks[n].Length) break; if (n==BlockCount) { ++p->RefCount; return p->Virt; } } if (BlockCount==1) return PhyMemBegin(Blocks[0].Addr,Blocks[0].Length,Cached); for (Mode=0;Mode<2;++Mode) for (p=PhyMem;p!=PhyMem+MAXPHY;++p) { if (Mode && !p->RefCount && p->Length) { free(p->Blocks); SafeVirtualFree(p->Virt,p->Length); memset(p,0,sizeof(phymem)); } if (!p->Length) { p->Blocks = (phymemblock*) malloc(sizeof(phymemblock)*BlockCount); if (p->Blocks) { int Size = 0; for (n=0;nBlockCount = BlockCount; p->Virt = (char*) VirtualAlloc(0, Size, MEM_RESERVE, PAGE_NOACCESS); if (p->Virt) { int Mode = PAGE_READWRITE | PAGE_PHYSICAL; char* Virt = p->Virt; if (!Cached) Mode |= PAGE_NOCACHE; for (n=0;n> 8), Blocks[n].Length,Mode)) break; p->Blocks[n].Addr = Blocks[n].Addr; p->Blocks[n].Length = Blocks[n].Length; Virt += Blocks[n].Length; } if (n==BlockCount) { p->RefCount = 1; p->Phy = Blocks[0].Addr; p->Length = Blocks[0].Length; p->BlockCount = BlockCount; #ifdef ARM if (Cached && FuncVirtualSetAttributes && (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_XSCALE)) FuncVirtualSetAttributes(p->Virt,Size,TBL_CACHE|TBL_BUFFER,TBL_CACHE|TBL_BUFFER,NULL); #endif return p->Virt; } VirtualFree(p->Virt,0,MEM_RELEASE); } free(p->Blocks); } memset(p,0,sizeof(phymem)); return NULL; } } } #endif return NULL; } void* PhyMemBegin(uint32_t Phy,uint32_t Length,bool_t Cached) { #if defined(TARGET_WINCE) if (FuncVirtualCopy && Phy && Length) { int Mode; phymem* p; for (p=PhyMem;p!=PhyMem+MAXPHY;++p) if (p->Phy <= Phy && p->Phy+p->Length >= Phy+Length) { ++p->RefCount; return p->Virt + (Phy - p->Phy); } for (Mode=0;Mode<2;++Mode) for (p=PhyMem;p!=PhyMem+MAXPHY;++p) { if (Mode && !p->RefCount && p->Length) { free(p->Blocks); SafeVirtualFree(p->Virt,p->Length); memset(p,0,sizeof(phymem)); } if (!p->Length) { int Align = Phy & 4095; Phy -= Align; Length = (Length + Align + 4095) & ~4095; p->Virt = (char*) VirtualAlloc(0, Length, MEM_RESERVE, PAGE_NOACCESS); if (p->Virt) { int Mode = PAGE_READWRITE | PAGE_PHYSICAL; if (!Cached) Mode |= PAGE_NOCACHE; if (FuncVirtualCopy(p->Virt,(LPVOID)(Phy >> 8), Length, Mode)) { p->RefCount = 1; p->Phy = Phy; p->Length = Length; p->BlockCount = 1; #ifdef ARM if (Cached && FuncVirtualSetAttributes && (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_XSCALE)) FuncVirtualSetAttributes(p->Virt,Length,TBL_CACHE|TBL_BUFFER,TBL_CACHE|TBL_BUFFER,NULL); #endif return p->Virt + Align; } VirtualFree(p->Virt,0,MEM_RELEASE); } return NULL; } } } #endif return NULL; } void PhyMemEnd(void* Virt) { #if defined(TARGET_WINCE) if (Virt) { phymem* p; for (p=PhyMem;p!=PhyMem+MAXPHY;++p) if (p->RefCount && p->Virt <= (char*)Virt && p->Virt+p->Length > (char*)Virt) { --p->RefCount; break; } } #endif } bool_t MemGetInfo(memoryinfo* p) { return 0; } void* CodeAlloc(int Size) { void* p; do { p = VirtualAlloc(NULL,Size,MEM_COMMIT,PAGE_EXECUTE_READ); } while (!p && Size && NodeHibernate()); return p; } void CodeFree(void* Code,int Size) { VirtualFree(Code,Size,MEM_DECOMMIT); VirtualFree(Code,0,MEM_RELEASE); } void CodeLock(void* Code,int Size) { DWORD Protect; VirtualProtect(Code,Size,PAGE_READWRITE|PAGE_NOCACHE,&Protect); } void CodeUnlock(void* Code,int Size) { DWORD Protect; VirtualProtect(Code,Size,PAGE_EXECUTE_READ,&Protect); #if defined(TARGET_WINCE) if (FuncCacheSync) FuncCacheSync(CACHE_SYNC_INSTRUCTIONS); #endif } void CodeFindPages(void* Ptr,uint8_t** PMin,uint8_t** PMax,uintptr_t* PPageSize) { uint8_t* Min; uint8_t* Max; uintptr_t PageSize = #if defined(MIPS) 1024; #else 4096; #endif if (PPageSize) *PPageSize = PageSize; Min = Max = (uint8_t*)((uintptr_t)Ptr & ~(PageSize-1)); while (!IsBadCodePtr((FARPROC)(Min-PageSize))) Min -= PageSize; while (!IsBadCodePtr((FARPROC)Max)) Max += PageSize; *PMin = Min; *PMax = Max; } void CheckHeap() { #if defined(_DEBUG) && defined(_MSC_VER) && (_MSC_VER < 1400) assert(_CrtCheckMemory()); #endif } //#define FIND 0xAD1A30 size_t AvailMemory() { MEMORYSTATUS Status; Status.dwLength = sizeof(Status); GlobalMemoryStatus(&Status); return Status.dwAvailPhys; } void WriteBlock(block* Block,int Ofs,const void* Src,int Length) { memcpy((uint8_t*)Block->Ptr+Ofs,Src,Length); } void FreeBlock(block* p) { if (p) { #ifdef BLOCKGROUP if (p->Id) //group { blockgroup* g = ARRAYBEGIN(BlockGroup,blockgroup)+(p->Id>>8); int Bit = 1 << ((p->Id & 255)-1); if (gMask & Bit) { g->Mask &= ~Bit; if (!g->Mask) FreeBlock(&g->Block); } p->Ptr = NULL; p->Id = 0; return; } #endif #ifndef NDEBUG if (VirtualFree((void*)p->Ptr,0,MEM_RELEASE)) --BlockAllocated; #else VirtualFree((void*)p->Ptr,0,MEM_RELEASE); #endif p->Ptr = NULL; p->Id = 0; } } bool_t SetHeapBlock(int n,block* Block,int Heap) { return 0; } #ifdef BLOCKGROUP static bool_t AllocBlockGroup(block* Block, bool_t Optional) { int n; blockgroup* g; for (g=ARRAYBEGIN(BlockGroup,blockgroup);g!=ARRAYEND(BlockGroup,blockgroup);++g) if (g->Mask && g->Mask != (1<Mask) break; if (g==ARRAYEND(BlockGroup,blockgroup)) { if (!ArrayAppend(&BlockGroup,NULL,sizeof(blockgroup),64)) return 0; g=ARRAYEND(BlockGroup,blockgroup)-1; g->Mask = 0; } if (!AllocBlock(BLOCKSIZE*BLOCKGROUP,&g->Block,1,HEAP_ANY)) return 0; } for (n=0;nMask & (1<Mask |= (1<Id = ((g-ARRAYBEGIN(BlockGroup,blockgroup))<<8)+(n+1); Block->Ptr = g->Block.Ptr + n*BLOCKSIZE; return 1; } return 0; } #endif bool_t AllocBlock(size_t n,block* Block,bool_t Optional,int Heap) { void* p; if (Optional && AvailMemory() < (256+64)*1024+n) // we want to avoid OS low memory warning return 0; #ifdef BLOCKGROUP if (n == BLOCKSIZE && AllocBlockGroup(Block,Optional)) return 1; #endif do { p = VirtualAlloc(NULL,n,MEM_COMMIT,PAGE_READWRITE); } while (!p && !Optional && n && NodeHibernate()); Block->Ptr = p; Block->Id = 0; #ifndef NDEBUG if (p) ++BlockAllocated; #endif return p!=NULL; } #undef malloc #undef realloc #undef free #ifdef SAFEGUARD void* safeset(uint8_t* p,int n,bool_t clear) { if (p) { *(int*)p = n; p += sizeof(int); memset(p,0xDA,SAFEGUARD); p += SAFEGUARD; if (clear) memset(p,0xCC,n); p += n; memset(p,0xDE,SAFEGUARD); p -= n; } return p; } void* safeget(uint8_t* p,bool_t clear) { if (p) { int n = *(int*)(p-SAFEGUARD-sizeof(int)); int i; for (i=0;iLength) { free(p->Blocks); SafeVirtualFree(p->Virt,p->Length); memset(p,0,sizeof(phymem)); } if (CoreDLL) FreeLibrary(CoreDLL); #endif #ifndef NDEBUG assert(BlockAllocated==0); #endif ArrayClear(&BlockGroup); } #endif