DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/cpu/paging.cpp
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 #include <stdlib.h>
00021 #include <assert.h>
00022 #include <string.h>
00023 
00024 #include "dosbox.h"
00025 #include "mem.h"
00026 #include "paging.h"
00027 #include "regs.h"
00028 #include "lazyflags.h"
00029 #include "cpu.h"
00030 #include "debug.h"
00031 #include "setup.h"
00032 
00033 PagingBlock paging;
00034 
00035 // Pagehandler implementation
00036 Bitu PageHandler::readb(PhysPt addr) {
00037         E_Exit("No byte handler for read from %x",addr);        
00038         return 0;
00039 }
00040 Bitu PageHandler::readw(PhysPt addr) {
00041         Bitu ret = (readb(addr+0) << 0);
00042         ret     |= (readb(addr+1) << 8);
00043         return ret;
00044 }
00045 Bitu PageHandler::readd(PhysPt addr) {
00046         Bitu ret = (readb(addr+0) << 0);
00047         ret     |= (readb(addr+1) << 8);
00048         ret     |= (readb(addr+2) << 16);
00049         ret     |= (readb(addr+3) << 24);
00050         return ret;
00051 }
00052 
00053 void PageHandler::writeb(PhysPt addr,Bitu /*val*/) {
00054         E_Exit("No byte handler for write to %x",addr); 
00055 }
00056 
00057 void PageHandler::writew(PhysPt addr,Bitu val) {
00058         writeb(addr+0,(Bit8u) (val >> 0));
00059         writeb(addr+1,(Bit8u) (val >> 8));
00060 }
00061 void PageHandler::writed(PhysPt addr,Bitu val) {
00062         writeb(addr+0,(Bit8u) (val >> 0));
00063         writeb(addr+1,(Bit8u) (val >> 8));
00064         writeb(addr+2,(Bit8u) (val >> 16));
00065         writeb(addr+3,(Bit8u) (val >> 24));
00066 }
00067 
00068 HostPt PageHandler::GetHostReadPt(Bitu /*phys_page*/) {
00069         return 0;
00070 }
00071 
00072 HostPt PageHandler::GetHostWritePt(Bitu /*phys_page*/) {
00073         return 0;
00074 }
00075 
00076 bool PageHandler::readb_checked(PhysPt addr, Bit8u * val) {
00077         *val=(Bit8u)readb(addr);        return false;
00078 }
00079 bool PageHandler::readw_checked(PhysPt addr, Bit16u * val) {
00080         *val=(Bit16u)readw(addr);       return false;
00081 }
00082 bool PageHandler::readd_checked(PhysPt addr, Bit32u * val) {
00083         *val=(Bit32u)readd(addr);       return false;
00084 }
00085 bool PageHandler::writeb_checked(PhysPt addr,Bitu val) {
00086         writeb(addr,val);       return false;
00087 }
00088 bool PageHandler::writew_checked(PhysPt addr,Bitu val) {
00089         writew(addr,val);       return false;
00090 }
00091 bool PageHandler::writed_checked(PhysPt addr,Bitu val) {
00092         writed(addr,val);       return false;
00093 }
00094 
00095 
00096 
00097 struct PF_Entry {
00098         Bitu cs;
00099         Bitu eip;
00100         Bitu page_addr;
00101         Bitu mpl;
00102 };
00103 
00104 #define PF_QUEUESIZE 80
00105 static struct {
00106         Bitu used;
00107         PF_Entry entries[PF_QUEUESIZE];
00108 } pf_queue;
00109 
00110 Bits PageFaultCore(void) {
00111         CPU_CycleLeft+=CPU_Cycles;
00112         CPU_Cycles=1;
00113 //      Bits ret=CPU_Core_Full_Run();
00114         Bits ret=CPU_Core_Normal_Run();
00115         CPU_CycleLeft+=CPU_Cycles;
00116         if (ret<0) E_Exit("Got a dosbox close machine in pagefault core?");
00117         if (ret) 
00118                 return ret;
00119         if (!pf_queue.used) E_Exit("PF Core without PF");
00120         PF_Entry * entry=&pf_queue.entries[pf_queue.used-1];
00121         X86PageEntry pentry;
00122         pentry.load=phys_readd(entry->page_addr);
00123         if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) {
00124                 cpu.mpl=entry->mpl;
00125                 return -1;
00126         }
00127         return 0;
00128 }
00129 #if C_DEBUG
00130 Bitu DEBUG_EnableDebugger(void);
00131 #endif
00132 
00133 #define ACCESS_KR  0
00134 #define ACCESS_KRW 1
00135 #define ACCESS_UR  2
00136 #define ACCESS_URW 3
00137 #define ACCESS_TABLEFAULT 4
00138 //const char* const mtr[] = {"KR ","KRW","UR ","URW","PFL"};
00139 
00140 // bit0 entry write
00141 // bit1 entry access
00142 // bit2 table write
00143 // bit3 table access
00144 // These arrays define how the access bits in the page table and entry
00145 // result in access rights.
00146 // The used array is switched depending on the CPU under emulation.
00147 
00148 // Intel says the lowest numeric value wins for both 386 and 486+
00149 // There's something strange about KR with WP=1 though
00150 static const Bit8u translate_array[] = {
00151         ACCESS_KR,              // 00 00
00152         ACCESS_KR,              // 00 01
00153         ACCESS_KR,              // 00 10
00154         ACCESS_KR,              // 00 11
00155         ACCESS_KR,              // 01 00
00156         ACCESS_KRW,             // 01 01
00157         ACCESS_KR, //   ACCESS_KRW,             // 01 10
00158         ACCESS_KRW,             // 01 11
00159         ACCESS_KR,              // 10 00
00160         ACCESS_KR, //   ACCESS_KRW,             // 10 01
00161         ACCESS_UR,              // 10 10
00162         ACCESS_UR,              // 10 11
00163         ACCESS_KR,              // 11 00
00164         ACCESS_KRW,             // 11 01
00165         ACCESS_UR,              // 11 10
00166         ACCESS_URW              // 11 11
00167 };
00168 
00169 // This array defines how a page is mapped depending on 
00170 // page access right, cpl==3, and WP.
00171 // R = map handler as read, W = map handler as write, E = map exception handler
00172 #define ACMAP_RW 0
00173 #define ACMAP_RE 1
00174 #define ACMAP_EE 2
00175 
00176 //static const char* const lnm[] = {"RW ","RE ","EE "}; // debug stuff
00177 
00178 // bit0-1 ACCESS_ type
00179 // bit2   1=user mode
00180 // bit3   WP on
00181 
00182 static const Bit8u xlat_mapping[] = {
00183 //  KR        KRW       UR        URW
00184         // index 0-3   kernel, wp 0
00185         ACMAP_RW, ACMAP_RW, ACMAP_RW, ACMAP_RW,
00186         // index 4-7   user,   wp 0
00187         ACMAP_EE, ACMAP_EE, ACMAP_RE, ACMAP_RW,
00188         // index 8-11  kernel, wp 1
00189         ACMAP_RE, ACMAP_RW, ACMAP_RE, ACMAP_RW,
00190         // index 11-15 user,   wp 1 (same as user, wp 0)
00191         ACMAP_EE, ACMAP_EE, ACMAP_RE, ACMAP_RW,
00192 };
00193 
00194 // This table can figure out if we are going to fault right now in the init handler
00195 // (1=fault) 
00196 // bit0-1 ACCESS_ type
00197 // bit2   1=user mode
00198 // bit3   1=writing
00199 // bit4   wp
00200 
00201 static const Bit8u fault_table[] = {
00202 //      KR      KRW     UR      URW
00203         // WP 0
00204         // index 0-3   kernel, reading
00205         0,      0,      0,      0,
00206         // index 4-7   user,   reading
00207         1,      1,      0,      0,
00208         // index 8-11  kernel, writing
00209         0,      0,      0,      0,
00210         // index 11-15 user,   writing
00211         1,      1,      1,      0,
00212         // WP 1
00213         // index 0-3   kernel, reading
00214         0,      0,      0,      0,
00215         // index 4-7   user,   reading
00216         1,      1,      0,      0,
00217         // index 8-11  kernel, writing
00218         1,      0,      1,      0,
00219         // index 11-15 user,   writing
00220         1,      1,      1,      0,
00221 };
00222 
00223 #define PHYSPAGE_DITRY 0x10000000
00224 #define PHYSPAGE_ADDR  0x000FFFFF
00225 
00226 // helper functions for calculating table entry addresses
00227 static inline PhysPt GetPageDirectoryEntryAddr(PhysPt lin_addr) {
00228         return paging.base.addr | ((lin_addr >> 22u) << 2u);
00229 }
00230 static inline PhysPt GetPageTableEntryAddr(PhysPt lin_addr, X86PageEntry& dir_entry) {
00231         return ((PhysPt)dir_entry.block.base << (PhysPt)12U) | ((lin_addr >> 10U) & 0xffcu);
00232 }
00233 /*
00234 void PrintPageInfo(const char* string, PhysPt lin_addr, bool writing, bool prepare_only) {
00235 
00236         Bitu lin_page=lin_addr >> 12;
00237 
00238         X86PageEntry dir_entry, table_entry;
00239         bool isUser = (((cpu.cpl & cpu.mpl)==3)? true:false);
00240 
00241         PhysPt dirEntryAddr = GetPageDirectoryEntryAddr(lin_addr);
00242         PhysPt tableEntryAddr = 0;
00243         dir_entry.load=phys_readd(dirEntryAddr);
00244         Bitu result = 4;
00245         bool dirty = false;
00246         Bitu ft_index = 0;
00247 
00248         if (dir_entry.block.p) {
00249                 tableEntryAddr = GetPageTableEntryAddr(lin_addr, dir_entry);
00250                 table_entry.load=phys_readd(tableEntryAddr);
00251                 if (table_entry.block.p) {
00252                         result =
00253                                 translate_array[((dir_entry.load<<1)&0xc) | ((table_entry.load>>1)&0x3)];
00254 
00255                         ft_index = result | (writing? 8:0) | (isUser? 4:0) |
00256                                 (paging.wp? 16:0);
00257 
00258                         dirty = table_entry.block.d? true:false;
00259                 }
00260         }
00261         LOG_MSG("%s %s LIN% 8x PHYS% 5x wr%x ch%x wp%x d%x c%x m%x f%x a%x [%x/%x/%x]",
00262                 string, mtr[result], lin_addr, table_entry.block.base,
00263                 writing, prepare_only, paging.wp,
00264                 dirty, cpu.cpl, cpu.mpl, fault_table[ft_index],
00265                 ((dir_entry.load<<1)&0xc) | ((table_entry.load>>1)&0x3),
00266                 dirEntryAddr, tableEntryAddr, table_entry.load);
00267 }
00268 */
00269 
00270 bool use_dynamic_core_with_paging = false; /* allow dynamic core even with paging (AT YOUR OWN RISK!!!!) */
00271 bool dosbox_allow_nonrecursive_page_fault = false;      /* when set, do nonrecursive mode (when executing instruction) */
00272 
00273 // PAGING_NewPageFault
00274 // lin_addr, page_addr: the linear and page address the fault happened at
00275 // prepare_only: true in case the calling core handles the fault, else the PageFaultCore does
00276 static void PAGING_NewPageFault(PhysPt lin_addr, Bitu page_addr, bool prepare_only, Bitu faultcode) {
00277         paging.cr2=lin_addr;
00278         //LOG_MSG("FAULT q%d, code %x",  pf_queue.used, faultcode);
00279         //PrintPageInfo("FA+",lin_addr,faultcode, prepare_only);
00280 
00281         if (prepare_only) {
00282                 cpu.exception.which = EXCEPTION_PF;
00283                 cpu.exception.error = faultcode;
00284         } else if (dosbox_allow_nonrecursive_page_fault) {
00285                 throw GuestPageFaultException(lin_addr,page_addr,faultcode);
00286         } else {
00287                 // Save the state of the cpu cores
00288                 LazyFlags old_lflags;
00289                 memcpy(&old_lflags,&lflags,sizeof(LazyFlags));
00290                 CPU_Decoder * old_cpudecoder;
00291                 old_cpudecoder=cpudecoder;
00292                 cpudecoder=&PageFaultCore;
00293                 LOG(LOG_PAGING,LOG_NORMAL)("Recursive PageFault for %lx used=%d",(unsigned long)lin_addr,(int)pf_queue.used);
00294                 if (pf_queue.used >= PF_QUEUESIZE) E_Exit("PF queue overrun.");
00295                 if (pf_queue.used != 0) LOG_MSG("Warning: PAGING_NewPageFault() more than one level, now using level %d\n",(int)pf_queue.used+1);
00296                 PF_Entry * entry=&pf_queue.entries[pf_queue.used++];
00297                 entry->cs=SegValue(cs);
00298                 entry->eip=reg_eip;
00299                 entry->page_addr=page_addr;
00300                 entry->mpl=cpu.mpl;
00301                 cpu.mpl=3;
00302                 CPU_Exception(EXCEPTION_PF,faultcode);
00303                 DOSBOX_RunMachine();
00304                 pf_queue.used--;
00305                 memcpy(&lflags,&old_lflags,sizeof(LazyFlags));
00306                 cpudecoder=old_cpudecoder;
00307         }
00308 }
00309 
00310 class PageFoilHandler : public PageHandler {
00311 private:
00312         void work(PhysPt addr) {
00313                 Bitu lin_page = addr >> 12;
00314                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00315                         
00316                 // set the page dirty in the tlb
00317                 paging.tlb.phys_page[lin_page] |= PHYSPAGE_DITRY;
00318 
00319                 // mark the page table entry dirty
00320                 X86PageEntry dir_entry, table_entry;
00321 
00322                 PhysPt dirEntryAddr = GetPageDirectoryEntryAddr(addr);
00323                 dir_entry.load=phys_readd(dirEntryAddr);
00324                 if (!dir_entry.block.p) E_Exit("Undesired situation 1 in page foiler.");
00325 
00326                 PhysPt tableEntryAddr = GetPageTableEntryAddr(addr, dir_entry);
00327                 table_entry.load=phys_readd(tableEntryAddr);
00328                 if (!table_entry.block.p) E_Exit("Undesired situation 2 in page foiler.");
00329 
00330                 // for debugging...
00331                 if (table_entry.block.base != phys_page)
00332                         E_Exit("Undesired situation 3 in page foiler.");
00333 
00334                 // map the real write handler in our place
00335                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00336 
00337                 // debug
00338 //              LOG_MSG("FOIL            LIN% 8x PHYS% 8x [%x/%x/%x] WRP % 8x", addr, phys_page,
00339 //                      dirEntryAddr, tableEntryAddr, table_entry.load, wtest);
00340 
00341                 // this can happen when the same page table is used at two different
00342                 // page directory entries / linear locations (WfW311)
00343                 // if (table_entry.block.d) E_Exit("% 8x Already dirty!!",table_entry.load);
00344                 
00345                 
00346                 // set the dirty bit
00347                 table_entry.block.d=1;
00348                 phys_writed(tableEntryAddr,table_entry.load);
00349                 
00350                 // replace this handler with the real thing
00351                 if (handler->getFlags() & PFLAG_WRITEABLE)
00352                         paging.tlb.write[lin_page] = handler->GetHostWritePt(phys_page) - (lin_page << 12);
00353                 else paging.tlb.write[lin_page]=0;
00354                 paging.tlb.writehandler[lin_page]=handler;
00355 
00356                 return;
00357         }
00358 
00359         void read() {
00360                 E_Exit("The page foiler shouldn't be read.");
00361         }
00362 public:
00363         PageFoilHandler() : PageHandler(PFLAG_INIT|PFLAG_NOCODE) {}
00364         Bitu readb(PhysPt addr) {(void)addr;read();return 0;}
00365         Bitu readw(PhysPt addr) {(void)addr;read();return 0;}
00366         Bitu readd(PhysPt addr) {(void)addr;read();return 0;}
00367 
00368     void writeb(PhysPt addr,Bitu val) {
00369         work(addr);
00370         // execute the write:
00371         // no need to care about mpl because we won't be entered
00372         // if write isn't allowed
00373         mem_writeb(addr,val);
00374     }
00375     void writew(PhysPt addr,Bitu val) {
00376         work(addr);
00377         mem_writew(addr,val);
00378     }
00379     void writed(PhysPt addr,Bitu val) {
00380         work(addr);
00381         mem_writed(addr,val);
00382     }
00383 
00384     bool readb_checked(PhysPt addr, Bit8u * val) {(void)addr;(void)val;read();return true;}
00385     bool readw_checked(PhysPt addr, Bit16u * val) {(void)addr;(void)val;read();return true;}
00386     bool readd_checked(PhysPt addr, Bit32u * val) {(void)addr;(void)val;read();return true;}
00387 
00388     bool writeb_checked(PhysPt addr,Bitu val) {
00389         work(addr);
00390         mem_writeb(addr,val);
00391         return false;
00392     }
00393     bool writew_checked(PhysPt addr,Bitu val) {
00394         work(addr);
00395         mem_writew(addr,val);
00396         return false;
00397     }
00398     bool writed_checked(PhysPt addr,Bitu val) {
00399         work(addr);
00400         mem_writed(addr,val);
00401         return false;
00402     }
00403 };
00404 
00405 class ExceptionPageHandler : public PageHandler {
00406 private:
00407         PageHandler* getHandler(PhysPt addr) {
00408                 Bitu lin_page = addr >> 12;
00409                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00410                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00411                 return handler;
00412                                         }
00413 
00414         bool hack_check(PhysPt addr) {
00415                 // First Encounters
00416                 // They change the page attributes without clearing the TLB.
00417                 // On a real 486 they get away with it because its TLB has only 32 or so 
00418                 // elements. The changed page attribs get overwritten and re-read before
00419                 // the exception happens. Here we have gazillions of TLB entries so the
00420                 // exception occurs if we don't check for it.
00421 
00422                 Bitu old_attirbs = paging.tlb.phys_page[addr>>12] >> 30;
00423                 X86PageEntry dir_entry, table_entry;
00424                 
00425                 dir_entry.load = phys_readd(GetPageDirectoryEntryAddr(addr));
00426                 if (!dir_entry.block.p) return false;
00427                 table_entry.load = phys_readd(GetPageTableEntryAddr(addr, dir_entry));
00428                 if (!table_entry.block.p) return false;
00429                 Bitu result =
00430                 translate_array[((dir_entry.load<<1)&0xc) | ((table_entry.load>>1)&0x3)];
00431                 if (result != old_attirbs) return true;
00432                 return false;
00433                                 }
00434 
00435         void Exception(PhysPt addr, bool writing, bool checked) {
00436                 //PrintPageInfo("XCEPT",addr,writing, checked);
00437                 //LOG_MSG("XCEPT LIN% 8x wr%d, ch%d, cpl%d, mpl%d",addr, writing, checked, cpu.cpl, cpu.mpl);
00438                 PhysPt tableaddr = 0;
00439                 if (!checked) {
00440                         X86PageEntry dir_entry;
00441                         dir_entry.load = phys_readd(GetPageDirectoryEntryAddr(addr));
00442                         if (!dir_entry.block.p) E_Exit("Undesired situation 1 in exception handler.");
00443                         
00444                         // page table entry
00445                         tableaddr = GetPageTableEntryAddr(addr, dir_entry);
00446                         //Bitu d_index=(addr >> 12) >> 10;
00447                         //tableaddr=(paging.base.page<<12) | (d_index<<2);
00448                 } 
00449                 PAGING_NewPageFault(addr, tableaddr, checked,
00450                         1u | (writing ? 2u : 0u) | (((cpu.cpl&cpu.mpl) == 3u) ? 4u : 0u));
00451                 
00452                 PAGING_ClearTLB(); // TODO got a better idea?
00453         }
00454 
00455         Bitu readb_through(PhysPt addr) {
00456                 Bitu lin_page = addr >> 12;
00457                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00458                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00459                 if (handler->getFlags() & PFLAG_READABLE) {
00460                         return host_readb(handler->GetHostReadPt(phys_page) + (addr&0xfff));
00461                         }
00462                 else return handler->readb(addr);
00463                                         }
00464         Bitu readw_through(PhysPt addr) {
00465                 Bitu lin_page = addr >> 12;
00466                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00467                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00468                 if (handler->getFlags() & PFLAG_READABLE) {
00469                         return host_readw(handler->GetHostReadPt(phys_page) + (addr&0xfff));
00470                                 }
00471                 else return handler->readw(addr);
00472                         }
00473         Bitu readd_through(PhysPt addr) {
00474                 Bitu lin_page = addr >> 12;
00475                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00476                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00477                 if (handler->getFlags() & PFLAG_READABLE) {
00478                         return host_readd(handler->GetHostReadPt(phys_page) + (addr&0xfff));
00479                 }
00480                 else return handler->readd(addr);
00481                         }
00482 
00483         void writeb_through(PhysPt addr, Bitu val) {
00484                 Bitu lin_page = addr >> 12;
00485                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00486                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00487                 if (handler->getFlags() & PFLAG_WRITEABLE) {
00488                         return host_writeb(handler->GetHostWritePt(phys_page) + (addr&0xfff), (Bit8u)val);
00489                 }
00490                 else return handler->writeb(addr, val);
00491                         }
00492 
00493         void writew_through(PhysPt addr, Bitu val) {
00494                 Bitu lin_page = addr >> 12;
00495                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00496                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00497                 if (handler->getFlags() & PFLAG_WRITEABLE) {
00498                         return host_writew(handler->GetHostWritePt(phys_page) + (addr&0xfff), (Bit16u)val);
00499                 }
00500                 else return handler->writew(addr, val);
00501         }
00502 
00503         void writed_through(PhysPt addr, Bitu val) {
00504                 Bitu lin_page = addr >> 12;
00505                 Bit32u phys_page = paging.tlb.phys_page[lin_page] & PHYSPAGE_ADDR;
00506                 PageHandler* handler = MEM_GetPageHandler(phys_page);
00507                 if (handler->getFlags() & PFLAG_WRITEABLE) {
00508                         return host_writed(handler->GetHostWritePt(phys_page) + (addr&0xfff), val);
00509                 }
00510                 else return handler->writed(addr, val);
00511                         }
00512 
00513 public:
00514         ExceptionPageHandler() : PageHandler(PFLAG_INIT|PFLAG_NOCODE) {}
00515         Bitu readb(PhysPt addr) {
00516                 if (!cpu.mpl) return readb_through(addr);
00517                         
00518                 Exception(addr, false, false);
00519                 return mem_readb(addr); // read the updated page (unlikely to happen?)
00520                                 }
00521         Bitu readw(PhysPt addr) {
00522                 // access type is supervisor mode (temporary)
00523                 // we are always allowed to read in superuser mode
00524                 // so get the handler and address and read it
00525                 if (!cpu.mpl) return readw_through(addr);
00526 
00527                 Exception(addr, false, false);
00528                 return mem_readw(addr);
00529                         }
00530         Bitu readd(PhysPt addr) {
00531                 if (!cpu.mpl) return readd_through(addr);
00532 
00533                 Exception(addr, false, false);
00534                 return mem_readd(addr);
00535                 }
00536         void writeb(PhysPt addr,Bitu val) {
00537                 if (!cpu.mpl) {
00538                         writeb_through(addr, val);
00539                         return;
00540         }
00541                 Exception(addr, true, false);
00542                 mem_writeb(addr, val);
00543                         }
00544         void writew(PhysPt addr,Bitu val) {
00545                 if (!cpu.mpl) {
00546                         // TODO Exception on a KR-page?
00547                         writew_through(addr, val);
00548                         return;
00549                 }
00550                 if (hack_check(addr)) {
00551                         LOG_MSG("Page attributes modified without clear");
00552                         PAGING_ClearTLB();
00553                         mem_writew(addr,val);
00554                         return;
00555                 }
00556                 // firstenc here
00557                 Exception(addr, true, false);
00558                 mem_writew(addr, val);
00559         }
00560         void writed(PhysPt addr,Bitu val) {
00561                 if (!cpu.mpl) {
00562                         writed_through(addr, val);
00563                         return;
00564                 }
00565                 Exception(addr, true, false);
00566                 mem_writed(addr, val);
00567         }
00568         // returning true means an exception was triggered for these _checked functions
00569         bool readb_checked(PhysPt addr, Bit8u * val) {
00570         (void)val;//UNUSED
00571                 Exception(addr, false, true);
00572                 return true;
00573         }
00574         bool readw_checked(PhysPt addr, Bit16u * val) {
00575         (void)val;//UNUSED
00576                 Exception(addr, false, true);
00577                 return true;
00578                         }
00579         bool readd_checked(PhysPt addr, Bit32u * val) {
00580         (void)val;//UNUSED
00581                 Exception(addr, false, true);
00582                 return true;
00583                 }
00584         bool writeb_checked(PhysPt addr,Bitu val) {
00585         (void)val;//UNUSED
00586                 Exception(addr, true, true);
00587                 return true;
00588         }
00589         bool writew_checked(PhysPt addr,Bitu val) {
00590                 if (hack_check(addr)) {
00591                         LOG_MSG("Page attributes modified without clear");
00592                         PAGING_ClearTLB();
00593                         mem_writew(addr,val); // TODO this makes us recursive again?
00594                         return false;
00595                 }
00596                 Exception(addr, true, true);
00597                 return true;
00598         }
00599         bool writed_checked(PhysPt addr,Bitu val) {
00600         (void)val;//UNUSED
00601                 Exception(addr, true, true);
00602                 return true;
00603         }
00604 };
00605 
00606 static void PAGING_LinkPageNew(Bitu lin_page, Bitu phys_page, Bitu linkmode, bool dirty);
00607 
00608 class NewInitPageHandler : public PageHandler {
00609 public:
00610         NewInitPageHandler() : PageHandler(PFLAG_INIT|PFLAG_NOCODE) {}
00611         Bitu readb(PhysPt addr) {
00612                 InitPage(addr, false, false);
00613                 return mem_readb(addr);
00614         }
00615         Bitu readw(PhysPt addr) {
00616                 InitPage(addr, false, false);
00617                 return mem_readw(addr);
00618         }
00619         Bitu readd(PhysPt addr) {
00620                 InitPage(addr, false, false);
00621                 return mem_readd(addr);
00622         }
00623         void writeb(PhysPt addr,Bitu val) {
00624                 InitPage(addr, true, false);
00625                 mem_writeb(addr,val);
00626         }
00627         void writew(PhysPt addr,Bitu val) {
00628                 InitPage(addr, true, false);
00629                 mem_writew(addr,val);
00630         }
00631         void writed(PhysPt addr,Bitu val) {
00632                 InitPage(addr, true, false);
00633                 mem_writed(addr,val);
00634         }
00635 
00636         bool readb_checked(PhysPt addr, Bit8u * val) {
00637                 if (InitPage(addr, false, true)) return true;
00638                 *val=mem_readb(addr);
00639                         return false;
00640                 }
00641         bool readw_checked(PhysPt addr, Bit16u * val) {
00642                 if (InitPage(addr, false, true)) return true;
00643                 *val=mem_readw(addr);
00644                 return false;
00645         }
00646         bool readd_checked(PhysPt addr, Bit32u * val) {
00647                 if (InitPage(addr, false, true)) return true;
00648                 *val=mem_readd(addr);
00649                         return false;
00650                 }
00651         bool writeb_checked(PhysPt addr,Bitu val) {
00652                 if (InitPage(addr, true, true)) return true;
00653                 mem_writeb(addr,val);
00654                 return false;
00655         }
00656         bool writew_checked(PhysPt addr,Bitu val) {
00657                 if (InitPage(addr, true, true)) return true;
00658                 mem_writew(addr,val);
00659                         return false;
00660                 }
00661         bool writed_checked(PhysPt addr,Bitu val) {
00662                 if (InitPage(addr, true, true)) return true;
00663                 mem_writed(addr,val);
00664                 return false;
00665         }
00666         bool InitPage(PhysPt lin_addr, bool writing, bool prepare_only) {
00667                 Bitu lin_page=lin_addr >> 12;
00668                 Bitu phys_page;
00669                 if (paging.enabled) {
00670 initpage_retry:
00671                         X86PageEntry dir_entry, table_entry;
00672                         bool isUser = (((cpu.cpl & cpu.mpl)==3)? true:false);
00673 
00674                         // Read the paging stuff, throw not present exceptions if needed
00675                         // and find out how the page should be mapped
00676                         PhysPt dirEntryAddr = GetPageDirectoryEntryAddr(lin_addr);
00677                         dir_entry.load=phys_readd(dirEntryAddr);
00678 
00679                         if (!dir_entry.block.p) {
00680                                 // table pointer is not present, do a page fault
00681                                 PAGING_NewPageFault(lin_addr, dirEntryAddr, prepare_only,
00682                                         (writing ? 2u : 0u) | (isUser ? 4u : 0u));
00683                                 
00684                                 if (prepare_only) return true;
00685                                 else goto initpage_retry; // TODO maybe E_Exit after a few loops
00686                         }
00687                         PhysPt tableEntryAddr = GetPageTableEntryAddr(lin_addr, dir_entry);
00688                         table_entry.load=phys_readd(tableEntryAddr);
00689 
00690                         // set page table accessed (IA manual: A is set whenever the entry is 
00691                         // used in a page translation)
00692                         if (!dir_entry.block.a) {
00693                                 dir_entry.block.a = 1;          
00694                                 phys_writed(dirEntryAddr, dir_entry.load);
00695                 }
00696 
00697                         if (!table_entry.block.p) {
00698                                 // physpage pointer is not present, do a page fault
00699                                 PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
00700                                          (writing ? 2u : 0u) | (isUser ? 4u : 0u));
00701                                 
00702                                 if (prepare_only) return true;
00703                                 else goto initpage_retry;
00704         }
00705                         //PrintPageInfo("INI",lin_addr,writing,prepare_only);
00706 
00707                         Bitu result =
00708                                 translate_array[((dir_entry.load<<1)&0xc) | ((table_entry.load>>1)&0x3)];
00709                         
00710                         // If a page access right exception occurs we shouldn't change a or d
00711                         // I'd prefer running into the prepared exception handler but we'd need
00712                         // an additional handler that sets the 'a' bit - idea - foiler read?
00713                         Bitu ft_index = result | (writing ? 8u : 0u) | (isUser ? 4u : 0u) |
00714                                 (paging.wp ? 16u : 0u);
00715                         
00716                         if (GCC_UNLIKELY(fault_table[ft_index])) {
00717                                 // exception error code format: 
00718                                 // bit0 - protection violation, bit1 - writing, bit2 - user mode
00719                                 PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
00720                                         1u | (writing ? 2u : 0u) | (isUser ? 4u : 0u));
00721                                 
00722                                 if (prepare_only) return true;
00723                                 else goto initpage_retry; // unlikely to happen?
00724                         }
00725                         // save load to see if it changed later
00726                         Bit32u table_load = table_entry.load;
00727 
00728                         // if we are writing we can set it right here to save some CPU
00729                         if (writing) table_entry.block.d = 1;
00730 
00731                         // set page accessed
00732                         table_entry.block.a = 1;
00733                         
00734                         // update if needed
00735                         if (table_load != table_entry.load)
00736                                 phys_writed(tableEntryAddr, table_entry.load);
00737 
00738                         // if the page isn't dirty and we are reading we need to map the foiler
00739                         // (dirty = false)
00740                         bool dirty = table_entry.block.d? true:false;
00741 /*
00742                         LOG_MSG("INIT  %s LIN% 8x PHYS% 5x wr%x ch%x wp%x d%x c%x m%x a%x [%x/%x/%x]",
00743                                 mtr[result], lin_addr, table_entry.block.base,
00744                                 writing, prepare_only, paging.wp,
00745                                 dirty, cpu.cpl, cpu.mpl,
00746                                 ((dir_entry.load<<1)&0xc) | ((table_entry.load>>1)&0x3),
00747                                 dirEntryAddr, tableEntryAddr, table_entry.load);
00748 */
00749                         // finally install the new page
00750                         PAGING_LinkPageNew(lin_page, table_entry.block.base, result, dirty);
00751 
00752                 } else { // paging off
00753                         if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
00754                         else phys_page=lin_page;
00755                         PAGING_LinkPage(lin_page,phys_page);
00756                 }
00757                 return false;
00758         }
00759 };
00760 
00761 bool PAGING_MakePhysPage(Bitu & page) {
00762         // page is the linear address on entry
00763         if (paging.enabled) {
00764                 // check the page directory entry for this address
00765                 X86PageEntry dir_entry;
00766                 dir_entry.load = phys_readd(GetPageDirectoryEntryAddr(page<<12));
00767                 if (!dir_entry.block.p) return false;
00768                 
00769                 // check the page table entry
00770                 X86PageEntry tbl_entry;
00771                 tbl_entry.load = phys_readd(GetPageTableEntryAddr(page<<12, dir_entry));
00772                 if (!tbl_entry.block.p) return false;
00773 
00774                 // return it
00775                 page = tbl_entry.block.base;
00776         } else {
00777                 if (page<LINK_START) page=paging.firstmb[page];
00778                 //Else keep it the same
00779         }
00780         return true;
00781 }
00782 
00783 static NewInitPageHandler init_page_handler;
00784 static ExceptionPageHandler exception_handler;
00785 static PageFoilHandler foiling_handler;
00786 
00787 Bitu PAGING_GetDirBase(void) {
00788         return paging.cr3;
00789 }
00790 
00791 #if defined(USE_FULL_TLB)
00792 void PAGING_InitTLB(void) {
00793         for (Bitu i=0;i<TLB_SIZE;i++) {
00794                 paging.tlb.read[i]=0;
00795                 paging.tlb.write[i]=0;
00796                 paging.tlb.readhandler[i]=&init_page_handler;
00797                 paging.tlb.writehandler[i]=&init_page_handler;
00798         }
00799         paging.ur_links.used=0;
00800         paging.krw_links.used=0;
00801         paging.kr_links.used=0;
00802         paging.links.used=0;
00803 }
00804 
00805 void PAGING_ClearTLB(void) {
00806 //      LOG_MSG("CLEAR                          m% 4u, kr% 4u, krw% 4u, ur% 4u",
00807 //              paging.links.used, paging.kro_links.used, paging.krw_links.used, paging.ure_links.used);
00808 
00809         Bit32u * entries=&paging.links.entries[0];
00810         for (;paging.links.used>0;paging.links.used--) {
00811                 Bitu page=*entries++;
00812                 paging.tlb.read[page]=0;
00813                 paging.tlb.write[page]=0;
00814                 paging.tlb.readhandler[page]=&init_page_handler;
00815                 paging.tlb.writehandler[page]=&init_page_handler;
00816         }
00817         paging.ur_links.used=0;
00818         paging.krw_links.used=0;
00819         paging.kr_links.used=0;
00820         paging.links.used=0;
00821 }
00822 
00823 void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) {
00824         for (;pages>0;pages--) {
00825                 paging.tlb.read[lin_page]=0;
00826                 paging.tlb.write[lin_page]=0;
00827                 paging.tlb.readhandler[lin_page]=&init_page_handler;
00828                 paging.tlb.writehandler[lin_page]=&init_page_handler;
00829                 lin_page++;
00830         }
00831 }
00832 
00833 void PAGING_MapPage(Bitu lin_page,Bitu phys_page) {
00834         if (lin_page<LINK_START) {
00835                 paging.firstmb[lin_page]=phys_page;
00836                 paging.tlb.read[lin_page]=0;
00837                 paging.tlb.write[lin_page]=0;
00838                 paging.tlb.readhandler[lin_page]=&init_page_handler;
00839                 paging.tlb.writehandler[lin_page]=&init_page_handler;
00840         } else {
00841                 PAGING_LinkPage(lin_page,phys_page);
00842         }
00843 }
00844 
00845 static void PAGING_LinkPageNew(Bitu lin_page, Bitu phys_page, Bitu linkmode, bool dirty) {
00846         Bitu xlat_index = linkmode | (paging.wp? 8:0) | ((cpu.cpl==3)? 4:0);
00847         Bit8u outcome = xlat_mapping[xlat_index];
00848 
00849         // get the physpage handler we are going to map 
00850         PageHandler * handler=MEM_GetPageHandler(phys_page);
00851         Bitu lin_base=lin_page << 12;
00852 
00853 //      LOG_MSG("MAPPG %s",lnm[outcome]);
00854         
00855         if (GCC_UNLIKELY(lin_page>=TLB_SIZE || phys_page>=TLB_SIZE)) 
00856                 E_Exit("Illegal page");
00857         if (GCC_UNLIKELY(paging.links.used>=PAGING_LINKS)) {
00858                 LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
00859                 PAGING_ClearTLB();
00860         }
00861         // re-use some of the unused bits in the phys_page variable
00862         // needed in the exception handler and foiler so they can replace themselves appropriately
00863         // bit31-30 ACMAP_
00864         // bit29        dirty
00865         // these bits are shifted off at the places paging.tlb.phys_page is read
00866         paging.tlb.phys_page[lin_page]= phys_page | (linkmode<< 30) | (dirty? PHYSPAGE_DITRY:0);
00867         switch(outcome) {
00868         case ACMAP_RW:
00869                 // read
00870                 if (handler->getFlags() & PFLAG_READABLE) paging.tlb.read[lin_page] = 
00871                         handler->GetHostReadPt(phys_page)-lin_base;
00872         else paging.tlb.read[lin_page]=0;
00873         paging.tlb.readhandler[lin_page]=handler;
00874                 
00875                 // write
00876                 if (dirty) { // in case it is already dirty we don't need to check
00877                         if (handler->getFlags() & PFLAG_WRITEABLE) paging.tlb.write[lin_page] = 
00878                                 handler->GetHostWritePt(phys_page)-lin_base;
00879                         else paging.tlb.write[lin_page]=0;
00880         paging.tlb.writehandler[lin_page]=handler;
00881                 } else {
00882                         paging.tlb.writehandler[lin_page]= &foiling_handler;
00883                         paging.tlb.write[lin_page]=0;
00884                 }
00885                 break;
00886         case ACMAP_RE:
00887                 // read
00888                 if (handler->getFlags() & PFLAG_READABLE) paging.tlb.read[lin_page] = 
00889                         handler->GetHostReadPt(phys_page)-lin_base;
00890                 else paging.tlb.read[lin_page]=0;
00891                 paging.tlb.readhandler[lin_page]=handler;
00892                 // exception
00893                 paging.tlb.writehandler[lin_page]= &exception_handler;
00894                 paging.tlb.write[lin_page]=0;
00895                 break;
00896         case ACMAP_EE:
00897                 paging.tlb.readhandler[lin_page]= &exception_handler;
00898                 paging.tlb.writehandler[lin_page]= &exception_handler;
00899                 paging.tlb.read[lin_page]=0;
00900                 paging.tlb.write[lin_page]=0;
00901                 break;
00902 }
00903 
00904         switch(linkmode) {
00905         case ACCESS_KR:
00906                 paging.kr_links.entries[paging.kr_links.used++]=lin_page;
00907                 break;
00908         case ACCESS_KRW:
00909                 paging.krw_links.entries[paging.krw_links.used++]=lin_page;
00910                 break;
00911         case ACCESS_UR:
00912                 paging.ur_links.entries[paging.ur_links.used++]=lin_page;
00913                 break;
00914         case ACCESS_URW:        // with this access right everything is possible
00915                                                 // thus no need to modify it on a us <-> sv switch
00916                 break;
00917         }
00918         paging.links.entries[paging.links.used++]=lin_page; // "master table"
00919 }
00920 
00921 void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) {
00922         PageHandler * handler=MEM_GetPageHandler(phys_page);
00923         Bitu lin_base=lin_page << 12;
00924         if (lin_page>=TLB_SIZE || phys_page>=TLB_SIZE) 
00925                 E_Exit("Illegal page");
00926 
00927         if (paging.links.used>=PAGING_LINKS) {
00928                 LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
00929                 PAGING_ClearTLB();
00930         }
00931 
00932         paging.tlb.phys_page[lin_page]=phys_page;
00933         if (handler->getFlags() & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base;
00934         else paging.tlb.read[lin_page]=0;
00935         if (handler->getFlags() & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=handler->GetHostWritePt(phys_page)-lin_base;
00936         else paging.tlb.write[lin_page]=0;
00937 
00938         paging.links.entries[paging.links.used++]=lin_page;
00939         paging.tlb.readhandler[lin_page]=handler;
00940         paging.tlb.writehandler[lin_page]=handler;
00941 }
00942 
00943 // parameter is the new cpl mode
00944 void PAGING_SwitchCPL(bool isUser) {
00945 //      LOG_MSG("SWCPL u%d kr%d, krw%d, ur%d",
00946 //              isUser, paging.kro_links.used, paging.krw_links.used, paging.ure_links.used);
00947         
00948         // this function is worth optimizing
00949         // some of this cold be pre-stored?
00950 
00951         // krw - same for WP1 and WP0
00952         if (isUser) {
00953                 // sv -> us: rw -> ee 
00954                 for(Bitu i = 0; i < paging.krw_links.used; i++) {
00955                         Bitu tlb_index = paging.krw_links.entries[i];
00956                         paging.tlb.readhandler[tlb_index] = &exception_handler;
00957                         paging.tlb.writehandler[tlb_index] = &exception_handler;
00958                         paging.tlb.read[tlb_index] = 0;
00959                         paging.tlb.write[tlb_index] = 0;
00960                 }
00961         } else {
00962                 // us -> sv: ee -> rw
00963                 for(Bitu i = 0; i < paging.krw_links.used; i++) {
00964                         Bitu tlb_index = paging.krw_links.entries[i];
00965                         Bitu phys_page = paging.tlb.phys_page[tlb_index];
00966                         Bitu lin_base = tlb_index << 12;
00967                         bool dirty = (phys_page & PHYSPAGE_DITRY)? true:false;
00968                         phys_page &= PHYSPAGE_ADDR;
00969                         PageHandler* handler = MEM_GetPageHandler(phys_page);
00970                         
00971                         // map read handler
00972                         paging.tlb.readhandler[tlb_index] = handler;
00973                         if (handler->getFlags()&PFLAG_READABLE)
00974                                 paging.tlb.read[tlb_index] = handler->GetHostReadPt(phys_page)-lin_base;
00975                         else paging.tlb.read[tlb_index] = 0;
00976                         
00977                         // map write handler
00978                         if (dirty) {
00979                                 paging.tlb.writehandler[tlb_index] = handler;
00980                                 if (handler->getFlags()&PFLAG_WRITEABLE)
00981                                         paging.tlb.write[tlb_index] = handler->GetHostWritePt(phys_page)-lin_base;
00982                                 else paging.tlb.write[tlb_index] = 0;
00983                         } else {
00984                                 paging.tlb.writehandler[tlb_index] = &foiling_handler;
00985                                 paging.tlb.write[tlb_index] = 0;
00986                         }
00987                 }
00988         }
00989         
00990         if (GCC_UNLIKELY(paging.wp)) {
00991                 // ur: no change with WP=1
00992                 // kr
00993                 if (isUser) {
00994                         // sv -> us: re -> ee 
00995                         for(Bitu i = 0; i < paging.kr_links.used; i++) {
00996                                 Bitu tlb_index = paging.kr_links.entries[i];
00997                                 paging.tlb.readhandler[tlb_index] = &exception_handler;
00998                                 paging.tlb.read[tlb_index] = 0;
00999                         }
01000                 } else {
01001                         // us -> sv: ee -> re
01002                         for(Bitu i = 0; i < paging.kr_links.used; i++) {
01003                                 Bitu tlb_index = paging.kr_links.entries[i];
01004                                 Bitu lin_base = tlb_index << 12;
01005                                 Bitu phys_page = paging.tlb.phys_page[tlb_index] & PHYSPAGE_ADDR;
01006                                 PageHandler* handler = MEM_GetPageHandler(phys_page);
01007 
01008                                 paging.tlb.readhandler[tlb_index] = handler;
01009                                 if (handler->getFlags()&PFLAG_READABLE)
01010                                         paging.tlb.read[tlb_index] = handler->GetHostReadPt(phys_page)-lin_base;
01011                                 else paging.tlb.read[tlb_index] = 0;
01012                         }
01013                 }
01014         } else { // WP=0
01015                 // ur
01016                 if (isUser) {
01017                         // sv -> us: rw -> re 
01018                         for(Bitu i = 0; i < paging.ur_links.used; i++) {
01019                                 Bitu tlb_index = paging.ur_links.entries[i];
01020                                 paging.tlb.writehandler[tlb_index] = &exception_handler;
01021                                 paging.tlb.write[tlb_index] = 0;
01022                         }
01023                 } else {
01024                         // us -> sv: re -> rw
01025                         for(Bitu i = 0; i < paging.ur_links.used; i++) {
01026                                 Bitu tlb_index = paging.ur_links.entries[i];
01027                                 Bitu phys_page = paging.tlb.phys_page[tlb_index];
01028                                 bool dirty = (phys_page & PHYSPAGE_DITRY)? true:false;
01029                                 phys_page &= PHYSPAGE_ADDR;
01030                                 PageHandler* handler = MEM_GetPageHandler(phys_page);
01031 
01032                                 if (dirty) {
01033                                         Bitu lin_base = tlb_index << 12;
01034                                         paging.tlb.writehandler[tlb_index] = handler;
01035                                         if (handler->getFlags()&PFLAG_WRITEABLE)
01036                                                 paging.tlb.write[tlb_index] = handler->GetHostWritePt(phys_page)-lin_base;
01037                                         else paging.tlb.write[tlb_index] = 0;
01038                                 } else {
01039                                         paging.tlb.writehandler[tlb_index] = &foiling_handler;
01040                                         paging.tlb.write[tlb_index] = 0;
01041                                 }
01042                         }
01043                 }
01044         }
01045 }
01046 
01047 #else
01048 
01049 static INLINE void InitTLBInt(tlb_entry *bank) {
01050         for (Bitu i=0;i<TLB_SIZE;i++) {
01051                 bank[i].read=0;
01052                 bank[i].write=0;
01053                 bank[i].readhandler=&init_page_handler;
01054                 bank[i].writehandler=&init_page_handler;
01055         }
01056 }
01057 
01058 void PAGING_InitTLBBank(tlb_entry **bank) {
01059         *bank = (tlb_entry *)malloc(sizeof(tlb_entry)*TLB_SIZE);
01060         if(!*bank) E_Exit("Out of Memory");
01061         InitTLBInt(*bank);
01062 }
01063 
01064 void PAGING_InitTLB(void) {
01065         InitTLBInt(paging.tlbh);
01066         paging.links.used=0;
01067 }
01068 
01069 void PAGING_ClearTLB(void) {
01070         Bit32u * entries=&paging.links.entries[0];
01071         for (;paging.links.used>0;paging.links.used--) {
01072                 Bitu page=*entries++;
01073                 tlb_entry *entry = get_tlb_entry(page<<12);
01074                 entry->read=0;
01075                 entry->write=0;
01076                 entry->readhandler=&init_page_handler;
01077                 entry->writehandler=&init_page_handler;
01078         }
01079         paging.links.used=0;
01080 }
01081 
01082 void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) {
01083         for (;pages>0;pages--) {
01084                 tlb_entry *entry = get_tlb_entry(lin_page<<12);
01085                 entry->read=0;
01086                 entry->write=0;
01087                 entry->readhandler=&init_page_handler;
01088                 entry->writehandler=&init_page_handler;
01089                 lin_page++;
01090         }
01091 }
01092 
01093 void PAGING_MapPage(Bitu lin_page,Bitu phys_page) {
01094         if (lin_page<LINK_START) {
01095                 paging.firstmb[lin_page]=phys_page;
01096                 paging.tlbh[lin_page].read=0;
01097                 paging.tlbh[lin_page].write=0;
01098                 paging.tlbh[lin_page].readhandler=&init_page_handler;
01099                 paging.tlbh[lin_page].writehandler=&init_page_handler;
01100         } else {
01101                 PAGING_LinkPage(lin_page,phys_page);
01102         }
01103 }
01104 
01105 void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) {
01106         PageHandler * handler=MEM_GetPageHandler(phys_page);
01107         Bitu lin_base=lin_page << 12;
01108         if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) 
01109                 E_Exit("Illegal page");
01110 
01111         if (paging.links.used>=PAGING_LINKS) {
01112                 LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
01113                 PAGING_ClearTLB();
01114         }
01115 
01116         tlb_entry *entry = get_tlb_entry(lin_base);
01117         entry->phys_page=phys_page;
01118         if (handler->getFlags() & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base;
01119         else entry->read=0;
01120         if (handler->getFlags() & PFLAG_WRITEABLE) entry->write=handler->GetHostWritePt(phys_page)-lin_base;
01121         else entry->write=0;
01122 
01123         paging.links.entries[paging.links.used++]=lin_page;
01124         entry->readhandler=handler;
01125         entry->writehandler=handler;
01126 }
01127 
01128 void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) {
01129         PageHandler * handler=MEM_GetPageHandler(phys_page);
01130         Bitu lin_base=lin_page << 12;
01131         if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) 
01132                 E_Exit("Illegal page");
01133 
01134         if (paging.links.used>=PAGING_LINKS) {
01135                 LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
01136                 PAGING_ClearTLB();
01137         }
01138 
01139         tlb_entry *entry = get_tlb_entry(lin_base);
01140         entry->phys_page=phys_page;
01141         if (handler->getFlags() & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base;
01142         else entry->read=0;
01143         entry->write=0;
01144 
01145         paging.links.entries[paging.links.used++]=lin_page;
01146         entry->readhandler=handler;
01147         entry->writehandler=&init_page_handler_userro;
01148 }
01149 
01150 #endif
01151 
01152 
01153 void PAGING_SetDirBase(Bitu cr3) {
01154         paging.cr3=cr3;
01155         
01156         paging.base.page=cr3 >> 12U;
01157         paging.base.addr=cr3 & ~0xFFFU;
01158 //      LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,paging.base.page);
01159         if (paging.enabled) {
01160                 PAGING_ClearTLB();
01161         }
01162 }
01163 
01164 void PAGING_SetWP(bool wp) {
01165         paging.wp = wp;
01166         if (paging.enabled)
01167                 PAGING_ClearTLB();
01168 }
01169 
01170 void PAGING_Enable(bool enabled) {
01171         /* If paging is disabled, we work from a default paging table */
01172         if (paging.enabled==enabled) return;
01173         paging.enabled=enabled;
01174         if (enabled) {
01175 //              LOG(LOG_PAGING,LOG_NORMAL)("Enabled");
01176                 PAGING_SetDirBase(paging.cr3);
01177         }
01178         PAGING_ClearTLB();
01179 }
01180 
01181 bool PAGING_Enabled(void) {
01182         return paging.enabled;
01183 }
01184 
01185 void PAGING_Init() {
01186         Bitu i;
01187 
01188         // log
01189         LOG(LOG_MISC,LOG_DEBUG)("Initializing paging system (CPU linear -> physical mapping system)");
01190 
01191         /* Setup default Page Directory, force it to update */
01192         paging.enabled=false;
01193         paging.wp=false;
01194         PAGING_InitTLB();
01195         for (i=0;i<LINK_START;i++) paging.firstmb[i]=i;
01196         pf_queue.used=0;
01197 }
01198