/* * Copyright (C) 2002-2019 The DOSBox Team * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "dosbox.h" #include "mem.h" #include "paging.h" #include "regs.h" #include "lazyflags.h" #include "cpu.h" #include "debug.h" #include "setup.h" #define LINK_TOTAL (64*1024) #define USERWRITE_PROHIBITED ((cpu.cpl&cpu.mpl)==3) PagingBlock paging; Bitu PageHandler::readb(PhysPt addr) { E_Exit("No byte handler for read from %d",addr); return 0; } Bitu PageHandler::readw(PhysPt addr) { Bitu ret = (readb(addr+0) << 0); ret |= (readb(addr+1) << 8); return ret; } Bitu PageHandler::readd(PhysPt addr) { Bitu ret = (readb(addr+0) << 0); ret |= (readb(addr+1) << 8); ret |= (readb(addr+2) << 16); ret |= (readb(addr+3) << 24); return ret; } void PageHandler::writeb(PhysPt addr,Bitu /*val*/) { E_Exit("No byte handler for write to %d",addr); } void PageHandler::writew(PhysPt addr,Bitu val) { writeb(addr+0,(Bit8u) (val >> 0)); writeb(addr+1,(Bit8u) (val >> 8)); } void PageHandler::writed(PhysPt addr,Bitu val) { writeb(addr+0,(Bit8u) (val >> 0)); writeb(addr+1,(Bit8u) (val >> 8)); writeb(addr+2,(Bit8u) (val >> 16)); writeb(addr+3,(Bit8u) (val >> 24)); } HostPt PageHandler::GetHostReadPt(Bitu /*phys_page*/) { return 0; } HostPt PageHandler::GetHostWritePt(Bitu /*phys_page*/) { return 0; } bool PageHandler::readb_checked(PhysPt addr, Bit8u * val) { *val=(Bit8u)readb(addr); return false; } bool PageHandler::readw_checked(PhysPt addr, Bit16u * val) { *val=(Bit16u)readw(addr); return false; } bool PageHandler::readd_checked(PhysPt addr, Bit32u * val) { *val=(Bit32u)readd(addr); return false; } bool PageHandler::writeb_checked(PhysPt addr,Bitu val) { writeb(addr,val); return false; } bool PageHandler::writew_checked(PhysPt addr,Bitu val) { writew(addr,val); return false; } bool PageHandler::writed_checked(PhysPt addr,Bitu val) { writed(addr,val); return false; } struct PF_Entry { Bitu cs; Bitu eip; Bitu page_addr; Bitu mpl; }; #define PF_QUEUESIZE 16 static struct { Bitu used; PF_Entry entries[PF_QUEUESIZE]; } pf_queue; static Bits PageFaultCore(void) { CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=1; Bits ret=CPU_Core_Full_Run(); CPU_CycleLeft+=CPU_Cycles; if (ret<0) E_Exit("Got a dosbox close machine in pagefault core?"); if (ret) return ret; if (!pf_queue.used) E_Exit("PF Core without PF"); PF_Entry * entry=&pf_queue.entries[pf_queue.used-1]; X86PageEntry pentry; pentry.load=phys_readd(entry->page_addr); if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) { cpu.mpl=entry->mpl; return -1; } return 0; } #if C_DEBUG Bitu DEBUG_EnableDebugger(void); #endif bool first=false; void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu faultcode) { /* Save the state of the cpu cores */ LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); CPU_Decoder * old_cpudecoder; old_cpudecoder=cpudecoder; cpudecoder=&PageFaultCore; paging.cr2=lin_addr; PF_Entry * entry=&pf_queue.entries[pf_queue.used++]; LOG(LOG_PAGING,LOG_NORMAL)("PageFault at %X type [%x] queue %d",lin_addr,faultcode,pf_queue.used); // LOG_MSG("EAX:%04X ECX:%04X EDX:%04X EBX:%04X",reg_eax,reg_ecx,reg_edx,reg_ebx); // LOG_MSG("CS:%04X EIP:%08X SS:%04x SP:%08X",SegValue(cs),reg_eip,SegValue(ss),reg_esp); entry->cs=SegValue(cs); entry->eip=reg_eip; entry->page_addr=page_addr; entry->mpl=cpu.mpl; cpu.mpl=3; CPU_Exception(EXCEPTION_PF,faultcode); #if C_DEBUG // DEBUG_EnableDebugger(); #endif DOSBOX_RunMachine(); pf_queue.used--; LOG(LOG_PAGING,LOG_NORMAL)("Left PageFault for %x queue %d",lin_addr,pf_queue.used); memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; // LOG_MSG("SS:%04x SP:%08X",SegValue(ss),reg_esp); } static INLINE void InitPageUpdateLink(Bitu relink,PhysPt addr) { if (relink==0) return; if (paging.links.used) { if (paging.links.entries[paging.links.used-1]==(addr>>12)) { paging.links.used--; PAGING_UnlinkPages(addr>>12,1); } } if (relink>1) PAGING_LinkPage_ReadOnly(addr>>12,relink); } static INLINE void InitPageCheckPresence(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) { Bitu lin_page=lin_addr >> 12; Bitu d_index=lin_page >> 10; Bitu t_index=lin_page & 0x3ff; Bitu table_addr=(paging.base.page<<12)+d_index*4; table.load=phys_readd(table_addr); if (!table.block.p) { LOG(LOG_PAGING,LOG_NORMAL)("NP Table"); PAGING_PageFault(lin_addr,table_addr, (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04)); table.load=phys_readd(table_addr); if (GCC_UNLIKELY(!table.block.p)) E_Exit("Pagefault didn't correct table"); } Bitu entry_addr=(table.block.base<<12)+t_index*4; entry.load=phys_readd(entry_addr); if (!entry.block.p) { // LOG(LOG_PAGING,LOG_NORMAL)("NP Page"); PAGING_PageFault(lin_addr,entry_addr, (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04)); entry.load=phys_readd(entry_addr); if (GCC_UNLIKELY(!entry.block.p)) E_Exit("Pagefault didn't correct page"); } } static INLINE bool InitPageCheckPresence_CheckOnly(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) { Bitu lin_page=lin_addr >> 12; Bitu d_index=lin_page >> 10; Bitu t_index=lin_page & 0x3ff; Bitu table_addr=(paging.base.page<<12)+d_index*4; table.load=phys_readd(table_addr); if (!table.block.p) { paging.cr2=lin_addr; cpu.exception.which=EXCEPTION_PF; cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04); return false; } Bitu entry_addr=(table.block.base<<12)+t_index*4; entry.load=phys_readd(entry_addr); if (!entry.block.p) { paging.cr2=lin_addr; cpu.exception.which=EXCEPTION_PF; cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04); return false; } return true; } // check if a user-level memory access would trigger a privilege page fault static INLINE bool InitPage_CheckUseraccess(Bitu u1,Bitu u2) { switch (CPU_ArchitectureType) { case CPU_ARCHTYPE_MIXED: case CPU_ARCHTYPE_386SLOW: case CPU_ARCHTYPE_386FAST: default: return ((u1)==0) && ((u2)==0); case CPU_ARCHTYPE_486OLDSLOW: case CPU_ARCHTYPE_486NEWSLOW: case CPU_ARCHTYPE_PENTIUMSLOW: return ((u1)==0) || ((u2)==0); } } class InitPageHandler : public PageHandler { public: InitPageHandler() { flags=PFLAG_INIT|PFLAG_NOCODE; } Bitu readb(PhysPt addr) { Bitu needs_reset=InitPage(addr,false); Bit8u val=mem_readb(addr); InitPageUpdateLink(needs_reset,addr); return val; } Bitu readw(PhysPt addr) { Bitu needs_reset=InitPage(addr,false); Bit16u val=mem_readw(addr); InitPageUpdateLink(needs_reset,addr); return val; } Bitu readd(PhysPt addr) { Bitu needs_reset=InitPage(addr,false); Bit32u val=mem_readd(addr); InitPageUpdateLink(needs_reset,addr); return val; } void writeb(PhysPt addr,Bitu val) { Bitu needs_reset=InitPage(addr,true); mem_writeb(addr,val); InitPageUpdateLink(needs_reset,addr); } void writew(PhysPt addr,Bitu val) { Bitu needs_reset=InitPage(addr,true); mem_writew(addr,val); InitPageUpdateLink(needs_reset,addr); } void writed(PhysPt addr,Bitu val) { Bitu needs_reset=InitPage(addr,true); mem_writed(addr,val); InitPageUpdateLink(needs_reset,addr); } bool readb_checked(PhysPt addr, Bit8u * val) { if (InitPageCheckOnly(addr,false)) { *val=mem_readb(addr); return false; } else return true; } bool readw_checked(PhysPt addr, Bit16u * val) { if (InitPageCheckOnly(addr,false)){ *val=mem_readw(addr); return false; } else return true; } bool readd_checked(PhysPt addr, Bit32u * val) { if (InitPageCheckOnly(addr,false)) { *val=mem_readd(addr); return false; } else return true; } bool writeb_checked(PhysPt addr,Bitu val) { if (InitPageCheckOnly(addr,true)) { mem_writeb(addr,val); return false; } else return true; } bool writew_checked(PhysPt addr,Bitu val) { if (InitPageCheckOnly(addr,true)) { mem_writew(addr,val); return false; } else return true; } bool writed_checked(PhysPt addr,Bitu val) { if (InitPageCheckOnly(addr,true)) { mem_writed(addr,val); return false; } else return true; } Bitu InitPage(Bitu lin_addr,bool writing) { Bitu lin_page=lin_addr >> 12; Bitu phys_page; if (paging.enabled) { X86PageEntry table; X86PageEntry entry; InitPageCheckPresence(lin_addr,writing,table,entry); // 0: no action // 1: can (but currently does not) fail a user-level access privilege check // 2: can (but currently does not) fail a write privilege check // 3: fails a privilege check Bitu priv_check=0; if (InitPage_CheckUseraccess(entry.block.us,table.block.us)) { if ((cpu.cpl&cpu.mpl)==3) priv_check=3; else { switch (CPU_ArchitectureType) { case CPU_ARCHTYPE_MIXED: case CPU_ARCHTYPE_386FAST: default: // priv_check=0; // default break; case CPU_ARCHTYPE_386SLOW: case CPU_ARCHTYPE_486OLDSLOW: case CPU_ARCHTYPE_486NEWSLOW: case CPU_ARCHTYPE_PENTIUMSLOW: priv_check=1; break; } } } if ((entry.block.wr==0) || (table.block.wr==0)) { // page is write-protected for user mode if (priv_check==0) { switch (CPU_ArchitectureType) { case CPU_ARCHTYPE_MIXED: case CPU_ARCHTYPE_386FAST: default: // priv_check=0; // default break; case CPU_ARCHTYPE_386SLOW: case CPU_ARCHTYPE_486OLDSLOW: case CPU_ARCHTYPE_486NEWSLOW: case CPU_ARCHTYPE_PENTIUMSLOW: priv_check=2; break; } } // check if actually failing the write-protected check if (writing && USERWRITE_PROHIBITED) priv_check=3; } if (priv_check==3) { LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x05 | (writing?0x02:0x00)); priv_check=0; } if (!table.block.a) { table.block.a=1; // set page table accessed phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); } if ((!entry.block.a) || (!entry.block.d)) { entry.block.a=1; // set page accessed // page is dirty if we're writing to it, or if we're reading but the // page will be fully linked so we can't track later writes if (writing || (priv_check==0)) entry.block.d=1; // mark page as dirty phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); } phys_page=entry.block.base; // now see how the page should be linked best, if we need to catch privilege // checks later on it should be linked as read-only page if (priv_check==0) { // if reading we could link the page as read-only to later cacth writes, // will slow down pretty much but allows catching all dirty events PAGING_LinkPage(lin_page,phys_page); } else { if (priv_check==1) { PAGING_LinkPage(lin_page,phys_page); return 1; } else if (writing) { PageHandler * handler=MEM_GetPageHandler(phys_page); PAGING_LinkPage(lin_page,phys_page); if (!(handler->flags & PFLAG_READABLE)) return 1; if (!(handler->flags & PFLAG_WRITEABLE)) return 1; if (get_tlb_read(lin_addr)!=get_tlb_write(lin_addr)) return 1; if (phys_page>1) return phys_page; else return 1; } else { PAGING_LinkPage_ReadOnly(lin_page,phys_page); } } } else { if (lin_page> 12; if (paging.enabled) { X86PageEntry table; X86PageEntry entry; if (!InitPageCheckPresence_CheckOnly(lin_addr,writing,table,entry)) return false; if (!USERWRITE_PROHIBITED) return true; if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)) && writing)) { LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); paging.cr2=lin_addr; cpu.exception.which=EXCEPTION_PF; cpu.exception.error=0x05 | (writing?0x02:0x00); return false; } } else { Bitu phys_page; if (lin_page> 12; Bitu phys_page; if (paging.enabled) { X86PageEntry table; X86PageEntry entry; InitPageCheckPresence(lin_addr,false,table,entry); if (!table.block.a) { table.block.a=1; //Set access phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); } if (!entry.block.a) { entry.block.a=1; //Set access phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); } phys_page=entry.block.base; // maybe use read-only page here if possible } else { if (lin_page1) tlb_addr=get_tlb_read(addr); else tlb_addr=get_tlb_write(addr); host_writeb(tlb_addr+addr,(Bit8u)(val&0xff)); return false; } return true; } bool writew_checked(PhysPt addr,Bitu val) { Bitu writecode=InitPageCheckOnly(addr,(Bit16u)(val&0xffff)); if (writecode) { HostPt tlb_addr; if (writecode>1) tlb_addr=get_tlb_read(addr); else tlb_addr=get_tlb_write(addr); host_writew(tlb_addr+addr,(Bit16u)(val&0xffff)); return false; } return true; } bool writed_checked(PhysPt addr,Bitu val) { Bitu writecode=InitPageCheckOnly(addr,(Bit32u)val); if (writecode) { HostPt tlb_addr; if (writecode>1) tlb_addr=get_tlb_read(addr); else tlb_addr=get_tlb_write(addr); host_writed(tlb_addr+addr,(Bit32u)val); return false; } return true; } void InitPage(Bitu lin_addr,Bitu val) { Bitu lin_page=lin_addr >> 12; Bitu phys_page; if (paging.enabled) { if (!USERWRITE_PROHIBITED) return; X86PageEntry table; X86PageEntry entry; InitPageCheckPresence(lin_addr,true,table,entry); LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x07); if (!table.block.a) { table.block.a=1; //Set access phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); } if ((!entry.block.a) || (!entry.block.d)) { entry.block.a=1; //Set access entry.block.d=1; //Set dirty phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); } phys_page=entry.block.base; PAGING_LinkPage(lin_page,phys_page); } else { if (lin_page> 12; if (paging.enabled) { if (!USERWRITE_PROHIBITED) return 2; X86PageEntry table; X86PageEntry entry; if (!InitPageCheckPresence_CheckOnly(lin_addr,true,table,entry)) return 0; if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)))) { LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); paging.cr2=lin_addr; cpu.exception.which=EXCEPTION_PF; cpu.exception.error=0x07; return 0; } PAGING_LinkPage(lin_page,entry.block.base); } else { Bitu phys_page; if (lin_page> 12; Bitu phys_page; if (paging.enabled) { X86PageEntry table; X86PageEntry entry; InitPageCheckPresence(lin_addr,true,table,entry); if (!table.block.a) { table.block.a=1; //Set access phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); } if (!entry.block.a) { entry.block.a=1; //Set access phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); } phys_page=entry.block.base; } else { if (lin_page> 10; Bitu t_index=page & 0x3ff; X86PageEntry table; table.load=phys_readd((paging.base.page<<12)+d_index*4); if (!table.block.p) return false; X86PageEntry entry; entry.load=phys_readd((table.block.base<<12)+t_index*4); if (!entry.block.p) return false; page=entry.block.base; } else { if (page>12,1); init_page_handler_userro.InitPageForced(lin_addr); return true; } return false; } #if defined(USE_FULL_TLB) void PAGING_InitTLB(void) { for (Bitu i=0;i0;paging.links.used--) { Bitu page=*entries++; paging.tlb.read[page]=0; paging.tlb.write[page]=0; paging.tlb.readhandler[page]=&init_page_handler; paging.tlb.writehandler[page]=&init_page_handler; } paging.links.used=0; } void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) { for (;pages>0;pages--) { paging.tlb.read[lin_page]=0; paging.tlb.write[lin_page]=0; paging.tlb.readhandler[lin_page]=&init_page_handler; paging.tlb.writehandler[lin_page]=&init_page_handler; lin_page++; } } void PAGING_MapPage(Bitu lin_page,Bitu phys_page) { if (lin_page=TLB_SIZE || phys_page>=TLB_SIZE) E_Exit("Illegal page"); if (paging.links.used>=PAGING_LINKS) { LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); PAGING_ClearTLB(); } paging.tlb.phys_page[lin_page]=phys_page; if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base; else paging.tlb.read[lin_page]=0; if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=handler->GetHostWritePt(phys_page)-lin_base; else paging.tlb.write[lin_page]=0; paging.links.entries[paging.links.used++]=lin_page; paging.tlb.readhandler[lin_page]=handler; paging.tlb.writehandler[lin_page]=handler; } void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) { PageHandler * handler=MEM_GetPageHandler(phys_page); Bitu lin_base=lin_page << 12; if (lin_page>=TLB_SIZE || phys_page>=TLB_SIZE) E_Exit("Illegal page"); if (paging.links.used>=PAGING_LINKS) { LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); PAGING_ClearTLB(); } paging.tlb.phys_page[lin_page]=phys_page; if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base; else paging.tlb.read[lin_page]=0; paging.tlb.write[lin_page]=0; paging.links.entries[paging.links.used++]=lin_page; paging.tlb.readhandler[lin_page]=handler; paging.tlb.writehandler[lin_page]=&init_page_handler_userro; } #else static INLINE void InitTLBInt(tlb_entry *bank) { for (Bitu i=0;i0;paging.links.used--) { Bitu page=*entries++; tlb_entry *entry = get_tlb_entry(page<<12); entry->read=0; entry->write=0; entry->readhandler=&init_page_handler; entry->writehandler=&init_page_handler; } paging.links.used=0; } void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) { for (;pages>0;pages--) { tlb_entry *entry = get_tlb_entry(lin_page<<12); entry->read=0; entry->write=0; entry->readhandler=&init_page_handler; entry->writehandler=&init_page_handler; lin_page++; } } void PAGING_MapPage(Bitu lin_page,Bitu phys_page) { if (lin_page=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) E_Exit("Illegal page"); if (paging.links.used>=PAGING_LINKS) { LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); PAGING_ClearTLB(); } tlb_entry *entry = get_tlb_entry(lin_base); entry->phys_page=phys_page; if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base; else entry->read=0; if (handler->flags & PFLAG_WRITEABLE) entry->write=handler->GetHostWritePt(phys_page)-lin_base; else entry->write=0; paging.links.entries[paging.links.used++]=lin_page; entry->readhandler=handler; entry->writehandler=handler; } void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) { PageHandler * handler=MEM_GetPageHandler(phys_page); Bitu lin_base=lin_page << 12; if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) E_Exit("Illegal page"); if (paging.links.used>=PAGING_LINKS) { LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); PAGING_ClearTLB(); } tlb_entry *entry = get_tlb_entry(lin_base); entry->phys_page=phys_page; if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base; else entry->read=0; entry->write=0; paging.links.entries[paging.links.used++]=lin_page; entry->readhandler=handler; entry->writehandler=&init_page_handler_userro; } #endif void PAGING_SetDirBase(Bitu cr3) { paging.cr3=cr3; paging.base.page=cr3 >> 12; paging.base.addr=cr3 & ~4095; // LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,paging.base.page); if (paging.enabled) { PAGING_ClearTLB(); } } void PAGING_Enable(bool enabled) { /* If paging is disabled, we work from a default paging table */ if (paging.enabled==enabled) return; paging.enabled=enabled; if (enabled) { if (GCC_UNLIKELY(cpudecoder==CPU_Core_Simple_Run)) { // LOG_MSG("CPU core simple won't run this game,switching to normal"); cpudecoder=CPU_Core_Normal_Run; CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=0; } // LOG(LOG_PAGING,LOG_NORMAL)("Enabled"); PAGING_SetDirBase(paging.cr3); } PAGING_ClearTLB(); } bool PAGING_Enabled(void) { return paging.enabled; } class PAGING:public Module_base{ public: PAGING(Section* configuration):Module_base(configuration){ /* Setup default Page Directory, force it to update */ paging.enabled=false; PAGING_InitTLB(); Bitu i; for (i=0;i