DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dyn_x86/cache.h
00001 /*
00002  *  Copyright (C) 2002-2015  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 class CacheBlock {
00021 public:
00022         void Clear(void);
00023         void LinkTo(Bitu index,CacheBlock * toblock) {
00024                 assert(toblock);
00025                 link[index].to=toblock;
00026                 link[index].next=toblock->link[index].from;
00027                 toblock->link[index].from=this;
00028         }
00029         struct {
00030                 Bit16u start,end;                               //Where the page is the original code
00031                 CodePageHandler * handler;              //Page containing this code
00032         } page;
00033         struct {
00034                 Bit8u * start;                                  //Where in the cache are we
00035                 Bitu size;
00036                 CacheBlock * next;
00037                 Bit8u * wmapmask;
00038                 Bit16u maskstart;
00039                 Bit16u masklen;
00040         } cache;
00041         struct {
00042                 Bitu index;
00043                 CacheBlock * next;
00044         } hash;
00045         struct {
00046                 CacheBlock * to;
00047                 CacheBlock * next;
00048                 CacheBlock * from;
00049         } link[2];
00050         CacheBlock * crossblock;
00051 };
00052 
00053 static struct {
00054         struct {
00055                 CacheBlock * first;
00056                 CacheBlock * active;
00057                 CacheBlock * free;
00058                 CacheBlock * running;
00059         } block;
00060         Bit8u * pos;
00061         CodePageHandler * free_pages;
00062         CodePageHandler * used_pages;
00063         CodePageHandler * last_page;
00064 } cache;
00065 
00066 static CacheBlock link_blocks[2];
00067 
00068 class CodePageHandler : public PageHandler {
00069 public:
00070         CodePageHandler() : PageHandler(0) {
00071                 invalidation_map=NULL;
00072         }
00073 
00074         void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) {
00075                 phys_page=_phys_page;
00076                 old_pagehandler=_old_pagehandler;
00077                 Bitu newflags = old_pagehandler->getFlags() | PFLAG_HASCODE;
00078                 newflags&=~PFLAG_WRITEABLE;
00079                 setFlags(newflags);
00080                 active_blocks=0;
00081                 active_count=16;
00082                 memset(&hash_map,0,sizeof(hash_map));
00083                 memset(&write_map,0,sizeof(write_map));
00084                 if (invalidation_map!=NULL) {
00085                         free(invalidation_map);
00086                         invalidation_map=NULL;
00087                 }
00088         }
00089         bool InvalidateRange(Bitu start,Bitu end) {
00090                 Bits index=1+(end>>DYN_HASH_SHIFT);
00091                 bool is_current_block=false;
00092                 Bit32u ip_point=SegPhys(cs)+reg_eip;
00093                 ip_point=(PAGING_GetPhysicalPage(ip_point)-(phys_page<<12))+(ip_point&0xfff);
00094                 while (index>=0) {
00095                         Bitu map=0;
00096                         for (Bitu count=start;count<=end;count++) map+=write_map[count];
00097                         if (!map) return is_current_block;
00098                         CacheBlock * block=hash_map[index];
00099                         while (block) {
00100                                 CacheBlock * nextblock=block->hash.next;
00101                                 if (start<=block->page.end && end>=block->page.start) {
00102                                         if (ip_point<=block->page.end && ip_point>=block->page.start) is_current_block=true;
00103                                         block->Clear();
00104                                 }
00105                                 block=nextblock;
00106                         }
00107                         index--;
00108                 }
00109                 return is_current_block;
00110         }
00111         void writeb(PhysPt addr,Bitu val){
00112                 if (GCC_UNLIKELY(old_pagehandler->getFlags() & PFLAG_HASROM)) return;
00113                 if (GCC_UNLIKELY((old_pagehandler->getFlags() & PFLAG_READABLE)!=PFLAG_READABLE)) {
00114                         E_Exit("wb:non-readable code page found that is no ROM page");
00115                 }
00116                 addr&=4095;
00117                 if (host_readb(hostmem+addr)==(Bit8u)val) return;
00118                 host_writeb(hostmem+addr,val);
00119                 if (!*(Bit8u*)&write_map[addr]) {
00120                         if (active_blocks) return;
00121                         active_count--;
00122                         if (!active_count) Release();
00123                         return;
00124                 } else if (!invalidation_map) {
00125                         invalidation_map=(Bit8u*)malloc(4096);
00126                         memset(invalidation_map,0,4096);
00127                 }
00128                 invalidation_map[addr]++;
00129                 InvalidateRange(addr,addr);
00130         }
00131         void writew(PhysPt addr,Bitu val){
00132                 if (GCC_UNLIKELY(old_pagehandler->getFlags() & PFLAG_HASROM)) return;
00133                 if (GCC_UNLIKELY((old_pagehandler->getFlags() & PFLAG_READABLE)!=PFLAG_READABLE)) {
00134                         E_Exit("ww:non-readable code page found that is no ROM page");
00135                 }
00136                 addr&=4095;
00137                 if (host_readw(hostmem+addr)==(Bit16u)val) return;
00138                 host_writew(hostmem+addr,val);
00139                 if ((*(Bit16u*)&write_map[addr]) == 0) {
00140                         if (active_blocks) return;
00141                         active_count--;
00142                         if (!active_count) Release();
00143                         return;
00144                 } else if (!invalidation_map) {
00145                         invalidation_map=(Bit8u*)malloc(4096);
00146                         memset(invalidation_map,0,4096);
00147                 }
00148                 (*(Bit16u*)&invalidation_map[addr])+=0x101;
00149                 InvalidateRange(addr,addr+1);
00150         }
00151         void writed(PhysPt addr,Bitu val){
00152                 if (GCC_UNLIKELY(old_pagehandler->getFlags() & PFLAG_HASROM)) return;
00153                 if (GCC_UNLIKELY((old_pagehandler->getFlags() & PFLAG_READABLE)!=PFLAG_READABLE)) {
00154                         E_Exit("wd:non-readable code page found that is no ROM page");
00155                 }
00156                 addr&=4095;
00157                 if (host_readd(hostmem+addr)==(Bit32u)val) return;
00158                 host_writed(hostmem+addr,val);
00159                 if ((*(Bit32u*)&write_map[addr]) == 0) {
00160                         if (active_blocks) return;
00161                         active_count--;
00162                         if (!active_count) Release();
00163                         return;
00164                 } else if (!invalidation_map) {
00165                         invalidation_map=(Bit8u*)malloc(4096);
00166                         memset(invalidation_map,0,4096);
00167                 }
00168                 (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
00169                 InvalidateRange(addr,addr+3);
00170         }
00171         bool writeb_checked(PhysPt addr,Bitu val) {
00172                 if (GCC_UNLIKELY(old_pagehandler->getFlags()&PFLAG_HASROM)) return false;
00173                 if (GCC_UNLIKELY((old_pagehandler->getFlags()&PFLAG_READABLE)!=PFLAG_READABLE)) {
00174                         E_Exit("cb:non-readable code page found that is no ROM page");
00175                 }
00176                 addr&=4095;
00177                 if (host_readb(hostmem+addr)==(Bit8u)val) return false;
00178                 if (!*(Bit8u*)&write_map[addr]) {
00179                         if (!active_blocks) {
00180                                 active_count--;
00181                                 if (!active_count) Release();
00182                         }
00183                 } else {
00184                         if (!invalidation_map) {
00185                                 invalidation_map=(Bit8u*)malloc(4096);
00186                                 memset(invalidation_map,0,4096);
00187                         }
00188                         invalidation_map[addr]++;
00189                         if (InvalidateRange(addr,addr)) {
00190                                 cpu.exception.which=SMC_CURRENT_BLOCK;
00191                                 return true;
00192                         }
00193                 }
00194                 host_writeb(hostmem+addr,val);
00195                 return false;
00196         }
00197         bool writew_checked(PhysPt addr,Bitu val) {
00198                 if (GCC_UNLIKELY(old_pagehandler->getFlags() & PFLAG_HASROM)) return false;
00199                 if (GCC_UNLIKELY((old_pagehandler->getFlags() & PFLAG_READABLE)!=PFLAG_READABLE)) {
00200                         E_Exit("cw:non-readable code page found that is no ROM page");
00201                 }
00202                 addr&=4095;
00203                 if (host_readw(hostmem+addr)==(Bit16u)val) return false;
00204                 if ((*(Bit16u*)&write_map[addr]) == 0) {
00205                         if (!active_blocks) {
00206                                 active_count--;
00207                                 if (!active_count) Release();
00208                         }
00209                 } else {
00210                         if (!invalidation_map) {
00211                                 invalidation_map=(Bit8u*)malloc(4096);
00212                                 memset(invalidation_map,0,4096);
00213                         }
00214                         (*(Bit16u*)&invalidation_map[addr])+=0x101;
00215                         if (InvalidateRange(addr,addr+1)) {
00216                                 cpu.exception.which=SMC_CURRENT_BLOCK;
00217                                 return true;
00218                         }
00219                 }
00220                 host_writew(hostmem+addr,val);
00221                 return false;
00222         }
00223         bool writed_checked(PhysPt addr,Bitu val) {
00224                 if (GCC_UNLIKELY(old_pagehandler->getFlags() & PFLAG_HASROM)) return false;
00225                 if (GCC_UNLIKELY((old_pagehandler->getFlags() & PFLAG_READABLE)!=PFLAG_READABLE)) {
00226                         E_Exit("cd:non-readable code page found that is no ROM page");
00227                 }
00228                 addr&=4095;
00229                 if (host_readd(hostmem+addr)==(Bit32u)val) return false;
00230                 if ((*(Bit32u*)&write_map[addr]) == 0) {
00231                         if (!active_blocks) {
00232                                 active_count--;
00233                                 if (!active_count) Release();
00234                         }
00235                 } else {
00236                         if (!invalidation_map) {
00237                                 invalidation_map=(Bit8u*)malloc(4096);
00238                                 memset(invalidation_map,0,4096);
00239                         }
00240                         (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
00241                         if (InvalidateRange(addr,addr+3)) {
00242                                 cpu.exception.which=SMC_CURRENT_BLOCK;
00243                                 return true;
00244                         }
00245                 }
00246                 host_writed(hostmem+addr,val);
00247                 return false;
00248         }
00249     void AddCacheBlock(CacheBlock * block) {
00250                 Bitu index=1+(block->page.start>>DYN_HASH_SHIFT);
00251                 block->hash.next=hash_map[index];
00252                 block->hash.index=index;
00253                 hash_map[index]=block;
00254                 block->page.handler=this;
00255                 active_blocks++;
00256         }
00257     void AddCrossBlock(CacheBlock * block) {
00258                 block->hash.next=hash_map[0];
00259                 block->hash.index=0;
00260                 hash_map[0]=block;
00261                 block->page.handler=this;
00262                 active_blocks++;
00263         }
00264         void DelCacheBlock(CacheBlock * block) {
00265                 active_blocks--;
00266                 active_count=16;
00267                 CacheBlock * * where=&hash_map[block->hash.index];
00268                 while (*where!=block) {
00269                         where=&((*where)->hash.next);
00270                         //Will crash if a block isn't found, which should never happen.
00271                 }
00272                 *where=block->hash.next;
00273                 if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) {
00274                         for (Bitu i=block->page.start;i<block->cache.maskstart;i++) {
00275                                 if (write_map[i]) write_map[i]--;
00276                         }
00277                         Bitu maskct=0;
00278                         for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) {
00279                                 if (write_map[i]) {
00280                                         if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--;
00281                                 }
00282                         }
00283                         free(block->cache.wmapmask);
00284                         block->cache.wmapmask=NULL;
00285                 } else {
00286                         for (Bitu i=block->page.start;i<=block->page.end;i++) {
00287                                 if (write_map[i]) write_map[i]--;
00288                         }
00289                 }
00290         }
00291         void Release(void) {
00292                 MEM_SetPageHandler(phys_page,1,old_pagehandler);
00293                 PAGING_ClearTLB();
00294                 if (prev) prev->next=next;
00295                 else cache.used_pages=next;
00296                 if (next) next->prev=prev;
00297                 else cache.last_page=prev;
00298                 next=cache.free_pages;
00299                 cache.free_pages=this;
00300                 prev=0;
00301         }
00302         void ClearRelease(void) {
00303                 for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) {
00304                         CacheBlock * block=hash_map[index];
00305                         while (block) {
00306                                 CacheBlock * nextblock=block->hash.next;
00307                                 block->page.handler=0;                  //No need, full clear
00308                                 block->Clear();
00309                                 block=nextblock;
00310                         }
00311                 }
00312                 Release();
00313         }
00314         CacheBlock * FindCacheBlock(Bitu start) {
00315                 CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)];
00316                 while (block) {
00317                         if (block->page.start==start) return block;
00318                         block=block->hash.next;
00319                 }
00320                 return 0;
00321         }
00322         HostPt GetHostReadPt(Bitu phys_page) { 
00323                 hostmem=old_pagehandler->GetHostReadPt(phys_page);
00324                 return hostmem;
00325         }
00326         HostPt GetHostWritePt(Bitu phys_page) { 
00327                 return GetHostReadPt( phys_page );
00328         }
00329 public:
00330         Bit8u write_map[4096];
00331         Bit8u * invalidation_map;
00332         CodePageHandler * next, * prev;
00333 private:
00334         PageHandler * old_pagehandler;
00335         CacheBlock * hash_map[1+DYN_PAGE_HASH];
00336         Bitu active_blocks;
00337         Bitu active_count;
00338         HostPt hostmem; 
00339         Bitu phys_page;
00340 };
00341 
00342 
00343 static INLINE void cache_addunsedblock(CacheBlock * block) {
00344         block->cache.next=cache.block.free;
00345         cache.block.free=block;
00346 }
00347 
00348 static CacheBlock * cache_getblock(void) {
00349         CacheBlock * ret=cache.block.free;
00350         if (!ret) E_Exit("Ran out of CacheBlocks" );
00351         cache.block.free=ret->cache.next;
00352         ret->cache.next=0;
00353         return ret;
00354 }
00355 
00356 void CacheBlock::Clear(void) {
00357         Bitu ind;
00358         /* Check if this is not a cross page block */
00359         if (hash.index) for (ind=0;ind<2;ind++) {
00360                 CacheBlock * fromlink=link[ind].from;
00361                 link[ind].from=0;
00362                 while (fromlink) {
00363                         CacheBlock * nextlink=fromlink->link[ind].next;
00364                         fromlink->link[ind].next=0;
00365                         fromlink->link[ind].to=&link_blocks[ind];
00366                         fromlink=nextlink;
00367                 }
00368                 if (link[ind].to!=&link_blocks[ind]) {
00369                         CacheBlock * * wherelink=&link[ind].to->link[ind].from;
00370                         while (*wherelink != this && *wherelink) {
00371                                 wherelink = &(*wherelink)->link[ind].next;
00372                         }
00373                         if(*wherelink) 
00374                                 *wherelink = (*wherelink)->link[ind].next;
00375                         else
00376                                 LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate");
00377                 }
00378         } else 
00379                 cache_addunsedblock(this);
00380         if (crossblock) {
00381                 crossblock->crossblock=0;
00382                 crossblock->Clear();
00383                 crossblock=0;
00384         }
00385         if (page.handler) {
00386                 page.handler->DelCacheBlock(this);
00387                 page.handler=0;
00388         }
00389         if (cache.wmapmask){
00390                 free(cache.wmapmask);
00391                 cache.wmapmask=NULL;
00392         }
00393 }
00394 
00395 
00396 static CacheBlock * cache_openblock(void) {
00397         CacheBlock * block=cache.block.active;
00398         /* check for enough space in this block */
00399         Bitu size=block->cache.size;
00400         CacheBlock * nextblock=block->cache.next;
00401         if (block->page.handler) 
00402                 block->Clear();
00403         while (size<CACHE_MAXSIZE) {
00404                 if (!nextblock) 
00405                         goto skipresize;
00406                 size+=nextblock->cache.size;
00407                 CacheBlock * tempblock=nextblock->cache.next;
00408                 if (nextblock->page.handler) 
00409                         nextblock->Clear();
00410                 cache_addunsedblock(nextblock);
00411                 nextblock=tempblock;
00412         }
00413 skipresize:
00414         block->cache.size=size;
00415         block->cache.next=nextblock;
00416         cache.pos=block->cache.start;
00417         return block;
00418 }
00419 
00420 static void cache_closeblock(void) {
00421         CacheBlock * block=cache.block.active;
00422         block->link[0].to=&link_blocks[0];
00423         block->link[1].to=&link_blocks[1];
00424         block->link[0].from=0;
00425         block->link[1].from=0;
00426         block->link[0].next=0;
00427         block->link[1].next=0;
00428         /* Close the block with correct alignments */
00429         Bitu written=cache.pos-block->cache.start;
00430         if (written>block->cache.size) {
00431                 if (!block->cache.next) {
00432                         if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size);       
00433                 } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size);     
00434         } else {
00435                 Bitu new_size;
00436                 Bitu left=block->cache.size-written;
00437                 /* Smaller than cache align then don't bother to resize */
00438                 if (left>CACHE_ALIGN) {
00439                         new_size=((written-1)|(CACHE_ALIGN-1))+1;
00440                         CacheBlock * newblock=cache_getblock();
00441                         newblock->cache.start=block->cache.start+new_size;
00442                         newblock->cache.size=block->cache.size-new_size;
00443                         newblock->cache.next=block->cache.next;
00444                         block->cache.next=newblock;
00445                         block->cache.size=new_size;
00446                 }
00447         }
00448         /* Advance the active block pointer */
00449         if (!block->cache.next) {
00450 //              LOG_MSG("Cache full restarting");
00451                 cache.block.active=cache.block.first;
00452         } else {
00453                 cache.block.active=block->cache.next;
00454         }
00455 }
00456 
00457 static INLINE void cache_addb(Bit8u val) {
00458         *cache.pos++=val;
00459 }
00460 
00461 static INLINE void cache_addw(Bit16u val) {
00462         *(Bit16u*)cache.pos=val;
00463         cache.pos+=2;
00464 }
00465 
00466 static INLINE void cache_addd(Bit32u val) {
00467         *(Bit32u*)cache.pos=val;
00468         cache.pos+=4;
00469 }
00470 
00471 
00472 static void gen_return(BlockReturn retcode);
00473 
00474 static Bit8u * cache_code_start_ptr=NULL;
00475 static Bit8u * cache_code=NULL;
00476 static Bit8u * cache_code_link_blocks=NULL;
00477 static CacheBlock * cache_blocks=NULL;
00478 
00479 /* Define temporary pagesize so the MPROTECT case and the regular case share as much code as possible */
00480 #if (C_HAVE_MPROTECT)
00481 #define PAGESIZE_TEMP PAGESIZE
00482 #else 
00483 #define PAGESIZE_TEMP 4096
00484 #endif
00485 
00486 static bool cache_initialized = false;
00487 
00488 static void cache_init(bool enable) {
00489         Bits i;
00490         if (enable) {
00491                 if (cache_initialized) return;
00492                 cache_initialized = true;
00493                 if (cache_blocks == NULL) {
00494                         cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock));
00495                         if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");
00496                         memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS);
00497                         cache.block.free=&cache_blocks[0];
00498                         for (i=0;i<CACHE_BLOCKS-1;i++) {
00499                                 cache_blocks[i].link[0].to=(CacheBlock *)1;
00500                                 cache_blocks[i].link[1].to=(CacheBlock *)1;
00501                                 cache_blocks[i].cache.next=&cache_blocks[i+1];
00502                         }
00503                 }
00504                 if (cache_code_start_ptr==NULL) {
00505 #if defined (WIN32)
00506                         cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
00507                                 MEM_COMMIT,PAGE_EXECUTE_READWRITE);
00508                         if (!cache_code_start_ptr)
00509                                 cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
00510 #else
00511                         cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
00512 #endif
00513                         if(!cache_code_start_ptr) E_Exit("Allocating dynamic core cache memory failed");
00514 
00515                         cache_code=(Bit8u*)(((Bitu)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //Bitu is same size as a pointer.
00516 
00517                         cache_code_link_blocks=cache_code;
00518                         cache_code+=PAGESIZE_TEMP;
00519 
00520 #if (C_HAVE_MPROTECT)
00521                         if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
00522                                 LOG_MSG("Setting excute permission on the code cache has failed!");
00523 #endif
00524                         CacheBlock * block=cache_getblock();
00525                         cache.block.first=block;
00526                         cache.block.active=block;
00527                         block->cache.start=&cache_code[0];
00528                         block->cache.size=CACHE_TOTAL;
00529                         block->cache.next=0;                                                            //Last block in the list
00530                 }
00531                 /* Setup the default blocks for block linkage returns */
00532                 cache.pos=&cache_code_link_blocks[0];
00533                 link_blocks[0].cache.start=cache.pos;
00534                 gen_return(BR_Link1);
00535                 cache.pos=&cache_code_link_blocks[32];
00536                 link_blocks[1].cache.start=cache.pos;
00537                 gen_return(BR_Link2);
00538                 cache.free_pages=0;
00539                 cache.last_page=0;
00540                 cache.used_pages=0;
00541                 /* Setup the code pages */
00542                 for (i=0;i<CACHE_PAGES;i++) {
00543                         CodePageHandler * newpage=new CodePageHandler();
00544                         newpage->next=cache.free_pages;
00545                         cache.free_pages=newpage;
00546                 }
00547         }
00548 }
00549 
00550 static void cache_close(void) {
00551 /*      for (;;) {
00552                 if (cache.used_pages) {
00553                         CodePageHandler * cpage=cache.used_pages;
00554                         CodePageHandler * npage=cache.used_pages->next;
00555                         cpage->ClearRelease();
00556                         delete cpage;
00557                         cache.used_pages=npage;
00558                 } else break;
00559         }
00560         if (cache_blocks != NULL) {
00561                 free(cache_blocks);
00562                 cache_blocks = NULL;
00563         }
00564         if (cache_code_start_ptr != NULL) {
00565                 ### care: under windows VirtualFree() has to be used if
00566                 ###       VirtualAlloc was used for memory allocation
00567                 free(cache_code_start_ptr);
00568                 cache_code_start_ptr = NULL;
00569         }
00570         cache_code = NULL;
00571         cache_code_link_blocks = NULL;
00572         cache_initialized = false; */
00573 }
00574 
00575 static void cache_reset(void) {
00576         if (cache_initialized) {
00577                 for (;;) {
00578                         if (cache.used_pages) {
00579                                 CodePageHandler * cpage=cache.used_pages;
00580                                 CodePageHandler * npage=cache.used_pages->next;
00581                                 cpage->ClearRelease();
00582                                 delete cpage;
00583                                 cache.used_pages=npage;
00584                         } else break;
00585                 }
00586 
00587                 if (cache_blocks == NULL) {
00588                         cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock));
00589                         if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");
00590                 }
00591                 memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS);
00592                 cache.block.free=&cache_blocks[0];
00593                 for (Bits i=0;i<CACHE_BLOCKS-1;i++) {
00594                         cache_blocks[i].link[0].to=(CacheBlock *)1;
00595                         cache_blocks[i].link[1].to=(CacheBlock *)1;
00596                         cache_blocks[i].cache.next=&cache_blocks[i+1];
00597                 }
00598 
00599                 if (cache_code_start_ptr==NULL) {
00600 #if defined (WIN32)
00601                         cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
00602                                 MEM_COMMIT,PAGE_EXECUTE_READWRITE);
00603                         if (!cache_code_start_ptr)
00604                                 cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
00605 #else
00606                         cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
00607 #endif
00608                         if (!cache_code_start_ptr) E_Exit("Allocating dynamic core cache memory failed");
00609 
00610                         cache_code=(Bit8u*)(((Bitu)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //Bitu is same size as a pointer.
00611 
00612                         cache_code_link_blocks=cache_code;
00613                         cache_code+=PAGESIZE_TEMP;
00614 
00615 #if (C_HAVE_MPROTECT)
00616                         if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
00617                                 LOG_MSG("Setting excute permission on the code cache has failed!");
00618 #endif
00619                 }
00620 
00621                 CacheBlock * block=cache_getblock();
00622                 cache.block.first=block;
00623                 cache.block.active=block;
00624                 block->cache.start=&cache_code[0];
00625                 block->cache.size=CACHE_TOTAL;
00626                 block->cache.next=0;                                                            //Last block in the list
00627 
00628                 /* Setup the default blocks for block linkage returns */
00629                 cache.pos=&cache_code_link_blocks[0];
00630                 link_blocks[0].cache.start=cache.pos;
00631                 gen_return(BR_Link1);
00632                 cache.pos=&cache_code_link_blocks[32];
00633                 link_blocks[1].cache.start=cache.pos;
00634                 gen_return(BR_Link2);
00635                 cache.free_pages=0;
00636                 cache.last_page=0;
00637                 cache.used_pages=0;
00638                 /* Setup the code pages */
00639                 for (Bitu i=0;i<CACHE_PAGES;i++) {
00640                         CodePageHandler * newpage=new CodePageHandler();
00641                         newpage->next=cache.free_pages;
00642                         cache.free_pages=newpage;
00643                 }
00644         }
00645 }