DOSBox-X
|
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 }