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