📄 mem_win32.c
字号:
/*****************************************************************************
*
* 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 <windows.h>
#if defined(_MSC_VER) && !defined(TARGET_WINCE)
#include <crtdbg.h>
#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<Count;++n)
FuncFreePhysMem(Blocks[n].Private);
Count = 0;
}
}
*/
if (Count)
{
p = VirtualAlloc(NULL,Length,MEM_RESERVE,PAGE_READWRITE);
if (p)
{
Pos = 0;
for (n=0;n<Count;++n)
{
if (!FuncVirtualCopy((char*)p+Pos,(LPVOID)(Blocks[n].Addr >> 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<Count;++n)
FuncFreePhysMem(Blocks[n].Private);
Count = 0;
}
}
}
if (!p && FuncLockPages && FuncUnlockPages)
{
do
{
p = VirtualAlloc(NULL,Length,MEM_COMMIT,PAGE_READWRITE);
}
while (!p && Length && NodeHibernate());
if (p)
{
int Pages = Length / PageSize;
DWORD* PFN = (DWORD*) alloca(sizeof(DWORD)*Pages);
if (FuncLockPages(p,Length,PFN,LOCKFLAG_WRITE))
{
DWORD Last = (DWORD)-1;
for (n=0;n<Pages;++n)
{
if (PFN[n] != Last)
{
if (Count >= *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;n<BlockCount;++n)
{
if (Blocks[n].Private)
break;
Size += Blocks[n].Length;
}
if (Size)
FuncUnlockPages(p,Size);
}
VirtualFree(p,0,MEM_RELEASE);
if (FuncAllocPhysMem && FuncFreePhysMem && FuncVirtualCopy)
for (n=0;n<BlockCount;++n)
if (Blocks[n].Private)
FuncFreePhysMem(Blocks[n].Private);
}
#endif
}
#if defined(TARGET_WINCE)
static void SafeVirtualFree(PVOID p,DWORD Size)
{
#ifdef ARM
// O2 Atom destroys video memory and LCD descriptors unless this code... (WM5)
if (FuncVirtualSetAttributes)
FuncVirtualSetAttributes(p,Size,0,0xFFFFF000,NULL);
#endif
VirtualFree(p,0,MEM_RELEASE);
}
#endif
void* PhyMemBeginEx(phymemblock* Blocks,int BlockCount,bool_t Cached)
{
#if defined(TARGET_WINCE)
if (FuncVirtualCopy && Blocks && BlockCount)
{
int n;
int Mode;
phymem* p;
for (p=PhyMem;p!=PhyMem+MAXPHY;++p)
if (p->BlockCount == BlockCount && p->Length == Blocks[0].Length && p->Phy == Blocks[0].Addr)
{
for (n=1;n<BlockCount;++n)
if (p->Blocks[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;n<BlockCount;++n)
Size += Blocks[n].Length;
p->BlockCount = 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<BlockCount;++n)
{
if (!FuncVirtualCopy(Virt,(LPVOID)(Blocks[n].Addr >> 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));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -