gps/GPSResources/tcpmp 0.73/common/palmos/mem_palmos.c

586 lines
13 KiB
C
Executable File

/*****************************************************************************
*
* 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_palmos.c 543 2006-01-07 22:06:24Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "../common.h"
//#define TRACKMEMORY
#if defined(TARGET_PALMOS)
#define MIN_DYNAMIC_LIMIT 32768
#define TRY_DYNAMIC 3*1024*1024
#define FTRID_MIN 4096
#define FTRID_MAX 16384
#define MAX_CACHE 32768
#include "pace.h"
extern SysAppInfoPtr SysGetAppInfo(SysAppInfoPtr *uiAppPP, SysAppInfoPtr* actionCodeAppPP);
#ifdef HAVE_PALMONE_SDK
#include <68K/System/PmPalmOSNVFS.h>
#endif
static block FlushCache = {NULL};
static int OutOfMemory = 0;
static UInt16 StorageId = 1;
void free(void *p)
{
if (p)
{
#ifdef TRACKMEMORY
int q = AvailMemory();
#endif
MemPtrFree(p);
#ifdef TRACKMEMORY
DebugMessage("%08x free:%d %d",p,AvailMemory(),q-AvailMemory());
#endif
}
}
void EnableOutOfMemory()
{
OutOfMemory--;
}
void DisableOutOfMemory()
{
OutOfMemory++;
}
void ShowOutOfMemory()
{
if (OutOfMemory<=0)
{
RectangleType r;
Coord Width;
Coord Height;
const tchar_t* s = LangStr(ERR_ID,ERR_OUT_OF_MEMORY);
WinHandle Old = WinSetDrawWindow(WinGetDisplayWindow());
WinGetDisplayExtent(&Width, &Height);
if (Width<60)
Width=60;
r.topLeft.x = (Coord)(Width-80);
r.topLeft.y = 16;
r.extent.x = 79;
r.extent.y = 15;
WinEraseRectangle(&r, 0);
WinDrawChars(s, (Int16)strlen(s), (Coord)(r.topLeft.x+1), (Coord)(r.topLeft.y+1));
if (Old)
WinSetDrawWindow(Old);
}
}
void* malloc(size_t n)
{
#ifdef TRACKMEMORY
int q = AvailMemory();
#endif
void *p = NULL;
if (n)
{
do
{
if ((size_t)AvailMemory()>MIN_DYNAMIC_LIMIT+n)
p = MemGluePtrNew(n);
} while (!p && NodeHibernate());
if (!p)
{
//DebugMessage("malloc %d %d",n,AvailMemory());
ShowOutOfMemory();
}
}
#ifdef TRACKMEMORY
DebugMessage("%08x malloc:%d %d %d",p,n,q,q-AvailMemory());
if (n>1024)
ThreadSleep(300);
#endif
return p;
}
void* realloc(void* p,size_t n)
{
#ifdef TRACKMEMORY
int q = AvailMemory();
#endif
if (!p)
return malloc(n);
else
if (!n)
{
MemPtrFree(p);
#ifdef TRACKMEMORY
DebugMessage("%08x free:%d %d",p,AvailMemory(),q-AvailMemory());
#endif
return NULL;
}
else
if (MemPtrResize(p,n)!=errNone)
{
void *q = NULL;
do
{
if ((size_t)AvailMemory()>MIN_DYNAMIC_LIMIT+n)
q = MemGluePtrNew(n);
} while (!q && NodeHibernate());
if (q)
{
memcpy(q,p,MemPtrSize(p));
MemPtrFree(p);
}
else
ShowOutOfMemory();
p = q;
}
#ifdef TRACKMEMORY
DebugMessage("%08x realloc:%d %d %d",p,n,q,q-AvailMemory());
if (n>1024)
ThreadSleep(300);
#endif
return p;
}
void* CodeAlloc(int Size) { return malloc(Size); }
void CodeFree(void* Code,int Size) { free(Code); }
void CodeLock(void* Code,int Size) {}
void CodeUnlock(void* Code,int Size)
{
// instruction cache flush needed
#ifdef ARM
if (FlushCache.Ptr)
((void(*)())FlushCache.Ptr)();
#endif
}
void WriteBlock(block* Block,int Ofs,const void* Src,int Length)
{
if (IsHeapStorage(Block))
DmWrite((void*)Block->Ptr,Ofs,Src,Length);
else
memcpy((char*)Block->Ptr+Ofs,Src,Length);
}
void FreeBlock(block* Block)
{
if (Block)
{
context* p = Context();
if (IsHeapStorage(Block))
{
int FtrId = Block->Id;
if (p->FtrId > FtrId)
p->FtrId = FtrId;
FtrPtrFree(p->ProgramId,(UInt16)FtrId);
}
else
free((char*)Block->Ptr);
Block->Id = 0;
Block->Ptr = NULL;
}
}
bool_t SetHeapBlock(int n,block* Block,int Heap)
{
block New;
if (!Block->Id && (Heap & HEAP_DYNAMIC))
return 0;
if (IsHeapStorage(Block) && (Heap & HEAP_STORAGE))
return 0;
if (!AllocBlock(n,&New,1,Heap))
return 0;
WriteBlock(&New,0,Block->Ptr,n);
FreeBlock(Block);
*Block = New;
return 1;
}
#ifdef ARM
static NOINLINE void FlushData(volatile const void* ptr)
{
const int zero = 0;
asm volatile ("mcr p15, 0, %0, c7, c14, 1" : : "r" (ptr)); // clean+invalidate D entry
asm volatile ("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero)); // drain write buffer
}
static NOINLINE void FlushTLB()
{
const int zero = 0;
asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero)); // invalidate I and D TLB
}
#endif
static NOINLINE int GetFtrId(context* p)
{
UInt32 v;
int FtrId = max(p->FtrId,FTRID_MIN);
for (;FtrId<FTRID_MAX;++FtrId)
if (FtrGet(p->ProgramId,(UInt16)FtrId,&v)==ftrErrNoSuchFeature)
return FtrId;
return -1;
}
bool_t AllocBlock(size_t n,block* Block,bool_t Optional,int Heap)
{
context* p = Context();
uint32_t Storage,Max;
void* Ptr = NULL;
if (!n)
{
Block->Id = 0;
Block->Ptr = NULL;
return 1;
}
if (Heap == HEAP_ANY && !p->TryDynamic)
Heap = HEAP_STORAGE;
if ((Heap & HEAP_STORAGEWR) && (n<16384 || !QueryAdvanced(ADVANCED_MEMORYOVERRIDE)))
Heap &= ~HEAP_STORAGEWR;
if (Optional)
{
if ((Heap & (HEAP_STORAGE|HEAP_STORAGEWR)) && MemHeapFreeBytes(StorageId,&Storage,&Max)==errNone && (int)Storage<128*1024+n)
Heap &= ~(HEAP_STORAGE|HEAP_STORAGEWR);
if ((Heap & HEAP_DYNAMIC) && AvailMemory()<((Heap & HEAP_STORAGE)?2048:512)*1024+n)
Heap &= ~HEAP_DYNAMIC;
}
if (Heap & HEAP_STORAGEWR)
{
int FtrId = GetFtrId(p);
if (FtrId>=0)
{
do
{
if (FtrPtrNew(p->ProgramId,(UInt16)FtrId,n,&Ptr)==errNone)
break;
} while (NodeHibernate());
if (Ptr)
{
uint32_t Phy = MemVirtToPhy(Ptr);
void* PtrWr = MemAsWritable(Phy);
if (!PtrWr || memcmp(Ptr,PtrWr,n)!=0)
{
//ShowMessage("","Memory tweak failed for address virt:%08x phy:%08x tmp:%08x\nPlease report to developer!",Ptr,Phy,PtrWr);
PtrWr = NULL;
}
if (PtrWr)
{
p->FtrId = FtrId+1;
Block->Id = FtrId;
Block->Ptr = PtrWr;
return 1;
}
FtrPtrFree(p->ProgramId,(UInt16)FtrId);
Ptr = NULL;
}
}
}
if (Heap & HEAP_DYNAMIC)
{
Ptr = malloc(n);
if (Ptr)
{
Block->Ptr = Ptr;
Block->Id = 0;
return 1;
}
}
if (Heap & HEAP_STORAGE)
{
int FtrId = GetFtrId(p);
if (FtrId>=0)
{
do
{
if (MemHeapFreeBytes(StorageId,&Storage,&Max)==errNone && (int)Max<n+8192)
continue;
if (FtrPtrNew(p->ProgramId,(UInt16)FtrId,n,&Ptr)==errNone)
break;
} while (!Optional && NodeHibernate());
if (Ptr)
{
p->FtrId = FtrId+1;
Block->Id = FtrId;
Block->Ptr = Ptr;
return 1;
}
}
}
if (!Optional)
ShowOutOfMemory();
return 0;
}
void* PhyMemAlloc(int Length,phymemblock* Blocks,int* BlockCount) { return NULL; }
void PhyMemFree(void* p,phymemblock* Blocks,int BlockCount) {}
void* PhyMemBeginEx(phymemblock* Blocks,int BlockCount,bool_t Cached) { return NULL; }
void* PhyMemBegin(uint32_t Phy,uint32_t Length,bool_t Cached) { return NULL; }
void PhyMemEnd(void* Virt) {}
void CheckHeap()
{
assert(MemHeapCheck(MemHeapID(0,0))==0);
}
size_t AvailMemory()
{
uint32_t Max = 0;
uint32_t Free = 0;
MemHeapFreeBytes(MemHeapID(0,0),&Free,&Max);
return Free;
}
void CodeFindPages(void* Ptr,uint8_t** PMin,uint8_t** PMax,size_t* PPageSize)
{
if (PMin)
*PMin = (uint8_t*)Ptr;
if (PMax)
*PMax = (uint8_t*)Ptr;
if (PPageSize)
*PPageSize = 4096;
}
bool_t MemGetInfo(memoryinfo* Info)
{
#ifdef ARM
int Model = QueryPlatform(PLATFORM_MODEL);
if (Model == MODEL_TUNGSTEN_T || Model == MODEL_TUNGSTEN_T2)
{
if (Info)
{
memset(Info,0,sizeof(memoryinfo));
Info->TLB = (uint32_t*)0x20010000;
Info->MemBase[0] = 0x10100000;
Info->MemSize[0] = 14;
Info->UnusedArea[0] = 0xB0200000;
Info->MemBase[1] = 0x11000000;
Info->MemSize[1] = 16;
Info->UnusedArea[1] = 0xB1000000;
}
return 1;
}
#endif
return 0;
}
void* MemAsWritable(uint32_t Phy)
{
#ifdef ARM
memoryinfo Info;
uint32_t v;
bool_t Changed;
int n,i,j;
if (!Phy)
return NULL;
if (!MemGetInfo(&Info))
return NULL;
for (n=0;n<2;++n)
if (Phy >= Info.MemBase[n] && Phy < Info.MemBase[n]+(Info.MemSize[n]<<20))
{
Phy = Phy - Info.MemBase[n] + Info.UnusedArea[n];
Changed = 0;
for (n=0;n<2;++n)
{
j = Info.UnusedArea[n]>>20;
v = Info.MemBase[n] | 0xC4E;
for (i=0;i<Info.MemSize[n];i++,v+=1024*1024,++j)
if (Info.TLB[j] != v)
{
Info.TLB[j] = v;
FlushData(Info.TLB+j);
Changed = 1;
}
}
if (Changed)
FlushTLB();
return (void*)Phy;
}
#endif
return NULL;
}
void* MemPhyToVirt(uint32_t Phy)
{
#ifdef ARM
int Model = QueryPlatform(PLATFORM_MODEL);
switch (Model)
{
case MODEL_TUNGSTEN_T3:
case MODEL_TUNGSTEN_T5:
case MODEL_ZIRE_72:
case MODEL_LIFEDRIVE:
case MODEL_PALM_TX:
case MODEL_TREO_650:
if (Phy >= 0x44000000 && Phy < 0x44100000) // XScale LCD
return (void*)(Phy+0x94000000-0x44000000);
break;
case MODEL_TUNGSTEN_C:
case MODEL_TUNGSTEN_E2:
if (Phy >= 0x44000000 && Phy < 0x44100000) // XScale LCD
return (void*)(Phy+0x92000000-0x44000000);
break;
//case MODEL_TUNGSTEN_T: //(borderless mode not supported)
case MODEL_ZIRE_71:
case MODEL_TUNGSTEN_E:
case MODEL_TUNGSTEN_T2:
if (Phy >= 0xFFF00000) // OMAP
return (void*)Phy;
break;
}
#endif
return NULL;
}
uint32_t MemVirtToPhy(void* p)
{
#ifdef ARM
int n;
memoryinfo Info;
uint32_t Ptr = (uint32_t)p;
int Model = QueryPlatform(PLATFORM_MODEL);
switch (Model)
{
case MODEL_ZIRE_72:
case MODEL_TUNGSTEN_C:
case MODEL_TUNGSTEN_E2:
case MODEL_TUNGSTEN_T3:
if (Ptr >= 0x00000000 && Ptr < 0x04000000) //total memory
return Ptr+0xA0000000;
break;
case MODEL_TUNGSTEN_T5:
if (Ptr >= 0x00200000 && Ptr < 0x00600000) //dynamic
return Ptr+0xA1C00000-0x00200000;
// no info about storage yet...
break;
case MODEL_TREO_650:
if (Ptr >= 0x64000000 && Ptr < 0x64500000) //dynamic
return Ptr+0xA1A00000-0x64000000;
if (Ptr >= 0x73100000 && Ptr < 0x73c00000) //storage
return Ptr+0xA0F00000-0x73100000;
break;
case MODEL_LIFEDRIVE:
if (Ptr >= 0x00200000 && Ptr < 0x00800000) //dynamic
return Ptr+0xA1A00000-0x00200000;
if (Ptr >= 0x00800000 && Ptr < 0x01430000) //storage
return Ptr+0xA0DD0000-0x00800000;
break;
case MODEL_PALM_TX:
if (Ptr >= 0x00200000 && Ptr < 0x00800000) //dynamic
return Ptr+0xA1A00000-0x00200000;
if (Ptr >= 0x00800000 && Ptr < 0x013D0000) //storage
return Ptr+0xA0E30000-0x00800000;
break;
case MODEL_ZIRE_71:
if (Ptr >= 0x00100000 && Ptr < 0x00200000) //dynamic
return Ptr+0x10010000-0x00100000;
if (Ptr >= 0x00200000 && Ptr < 0x00fe0000) //storage
return Ptr+0x10120000-0x00200000;
break;
case MODEL_TUNGSTEN_E:
if (Ptr >= 0x00100000 && Ptr < 0x00300000) //dynamic
return Ptr+0x10020000-0x00100000;
if (Ptr >= 0x00300000 && Ptr < 0x01fd0000) //storage
return Ptr+0x10230000-0x00300000;
break;
case MODEL_TUNGSTEN_T:
case MODEL_TUNGSTEN_T2:
if (Ptr >= 0x00100000 && Ptr < 0x001c9000) //dynamic
return Ptr+0x10037000-0x00100000;
if (Ptr >= 0x00200000 && Ptr < 0x01000000) //storage
return Ptr+0x10100000-0x00200000;
if (Ptr >= 0x01000000 && Ptr < 0x02000000) //T2 additional storage
return Ptr+0x11000000-0x01000000;
break;
}
if (MemGetInfo(&Info))
for (n=0;n<2;++n)
if (Ptr >= Info.UnusedArea[n] && Ptr < Info.UnusedArea[n]+(Info.MemSize[n]<<20))
return Ptr-Info.UnusedArea[n]+Info.MemBase[n];
#endif
return 0;
}
void Mem_Init()
{
Context()->TryDynamic = Context()->StartUpMemory > TRY_DYNAMIC;
StorageId = MemHeapID(0,1);
#ifdef HAVE_PALMONE_SDK
{
UInt32 Version;
if (FtrGet(sysFtrCreator,sysFtrNumDmAutoBackup,&Version)==errNone && Version==1)
StorageId = 1|dbCacheFlag;
}
#endif
#ifdef ARM
if (AllocBlock(MAX_CACHE+sizeof(uint32_t),&FlushCache,0,HEAP_ANY))
{
uint32_t p[64];
int i;
for (i=0;i<64;++i)
p[i] = 0xE51F0008; //ldr r0,[pc,#-8]
for (i=0;i<=MAX_CACHE-sizeof(p);i+=sizeof(p))
WriteBlock(&FlushCache,i,p,sizeof(p));
p[0] = 0xE1A0F00E; // mov pc,lr
WriteBlock(&FlushCache,i,p,sizeof(uint32_t));
}
#endif
}
void Mem_Done()
{
#ifdef ARM
FreeBlock(&FlushCache);
#endif
}
#endif