dosbox-wii/include/paging.h
2009-05-02 22:28:34 +00:00

343 lines
9.6 KiB
C++

/*
* Copyright (C) 2002-2007 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: paging.h,v 1.24 2007/01/08 19:45:37 qbix79 Exp $ */
#ifndef DOSBOX_PAGING_H
#define DOSBOX_PAGING_H
#ifndef DOSBOX_DOSBOX_H
#include "dosbox.h"
#endif
#ifndef DOSBOX_MEM_H
#include "mem.h"
#endif
class PageDirectory;
#define MEM_PAGE_SIZE (4096)
#define XMS_START (0x110)
#define TLB_SIZE (1024*1024)
#define PFLAG_READABLE 0x1
#define PFLAG_WRITEABLE 0x2
#define PFLAG_HASROM 0x4
#define PFLAG_HASCODE 0x8 //Page contains dynamic code
#define PFLAG_NOCODE 0x10 //No dynamic code can be generated here
#define PFLAG_INIT 0x20 //No dynamic code can be generated here
#define LINK_START ((1024+64)/4) //Start right after the HMA
//Allow 128 mb of memory to be linked
#define PAGING_LINKS (128*1024/4)
class PageHandler {
public:
virtual ~PageHandler(void) { }
virtual Bitu readb(PhysPt addr);
virtual Bitu readw(PhysPt addr);
virtual Bitu readd(PhysPt addr);
virtual void writeb(PhysPt addr,Bitu val);
virtual void writew(PhysPt addr,Bitu val);
virtual void writed(PhysPt addr,Bitu val);
virtual HostPt GetHostReadPt(Bitu phys_page);
virtual HostPt GetHostWritePt(Bitu phys_page);
virtual bool readb_checked(PhysPt addr, Bitu * val);
virtual bool readw_checked(PhysPt addr, Bitu * val);
virtual bool readd_checked(PhysPt addr, Bitu * val);
virtual bool writeb_checked(PhysPt addr,Bitu val);
virtual bool writew_checked(PhysPt addr,Bitu val);
virtual bool writed_checked(PhysPt addr,Bitu val);
Bitu flags;
};
/* Some other functions */
void PAGING_Enable(bool enabled);
bool PAGING_Enabled(void);
Bitu PAGING_GetDirBase(void);
void PAGING_SetDirBase(Bitu cr3);
void PAGING_InitTLB(void);
void PAGING_ClearTLB(void);
void PAGING_LinkPage(Bitu lin_page,Bitu phys_page);
void PAGING_UnlinkPages(Bitu lin_page,Bitu pages);
/* This maps the page directly, only use when paging is disabled */
void PAGING_MapPage(Bitu lin_page,Bitu phys_page);
bool PAGING_MakePhysPage(Bitu & page);
void MEM_SetLFB( Bitu page, Bitu pages, PageHandler *handler);
void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
void MEM_ResetPageHandler(Bitu phys_page, Bitu pages);
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct X86_PageEntryBlock{
#ifdef WORDS_BIGENDIAN
Bit32u base:20;
Bit32u avl:3;
Bit32u g:1;
Bit32u pat:1;
Bit32u d:1;
Bit32u a:1;
Bit32u pcd:1;
Bit32u pwt:1;
Bit32u us:1;
Bit32u wr:1;
Bit32u p:1;
#else
Bit32u p:1;
Bit32u wr:1;
Bit32u us:1;
Bit32u pwt:1;
Bit32u pcd:1;
Bit32u a:1;
Bit32u d:1;
Bit32u pat:1;
Bit32u g:1;
Bit32u avl:3;
Bit32u base:20;
#endif
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
union X86PageEntry {
Bit32u load;
X86_PageEntryBlock block;
};
struct PagingBlock {
Bitu cr3;
Bitu cr2;
struct {
Bitu page;
PhysPt addr;
} base;
struct {
HostPt read[TLB_SIZE];
HostPt write[TLB_SIZE];
PageHandler * handler[TLB_SIZE];
Bit32u phys_page[TLB_SIZE];
} tlb;
struct {
Bitu used;
Bit32u entries[PAGING_LINKS];
} links;
Bit32u firstmb[LINK_START];
bool enabled;
};
extern PagingBlock paging;
/* Some support functions */
PageHandler * MEM_GetPageHandler(Bitu phys_page);
/* Use this helper function to access linear addresses in readX/writeX functions */
INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
return (paging.tlb.phys_page[linePage>>12]<<12);
}
INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff);
}
/* Unaligned address handlers */
Bit16u mem_unalignedreadw(PhysPt address);
Bit32u mem_unalignedreadd(PhysPt address);
void mem_unalignedwritew(PhysPt address,Bit16u val);
void mem_unalignedwrited(PhysPt address,Bit32u val);
bool mem_unalignedreadw_checked_x86(PhysPt address,Bit16u * val);
bool mem_unalignedreadd_checked_x86(PhysPt address,Bit32u * val);
bool mem_unalignedwritew_checked_x86(PhysPt address,Bit16u val);
bool mem_unalignedwrited_checked_x86(PhysPt address,Bit32u val);
/* Special inlined memory reading/writing */
INLINE Bit8u mem_readb_inline(PhysPt address) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) return host_readb(paging.tlb.read[index]+address);
else return paging.tlb.handler[index]->readb(address);
}
INLINE Bit16u mem_readw_inline(PhysPt address) {
if (!(address & 1)) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) return host_readw(paging.tlb.read[index]+address);
else return paging.tlb.handler[index]->readw(address);
} else return mem_unalignedreadw(address);
}
INLINE Bit32u mem_readd_inline(PhysPt address) {
if (!(address & 3)) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) return host_readd(paging.tlb.read[index]+address);
else return paging.tlb.handler[index]->readd(address);
} else return mem_unalignedreadd(address);
}
INLINE void mem_writeb_inline(PhysPt address,Bit8u val) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) host_writeb(paging.tlb.write[index]+address,val);
else paging.tlb.handler[index]->writeb(address,val);
}
INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
if (!(address & 1)) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) host_writew(paging.tlb.write[index]+address,val);
else paging.tlb.handler[index]->writew(address,val);
} else mem_unalignedwritew(address,val);
}
INLINE void mem_writed_inline(PhysPt address,Bit32u val) {
if (!(address & 3)) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) host_writed(paging.tlb.write[index]+address,val);
else paging.tlb.handler[index]->writed(address,val);
} else mem_unalignedwrited(address,val);
}
INLINE Bit16u mem_readw_dyncorex86(PhysPt address) {
if ((address & 0xfff)<0xfff) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) return host_readw(paging.tlb.read[index]+address);
else return paging.tlb.handler[index]->readw(address);
} else return mem_unalignedreadw(address);
}
INLINE Bit32u mem_readd_dyncorex86(PhysPt address) {
if ((address & 0xfff)<0xffd) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) return host_readd(paging.tlb.read[index]+address);
else return paging.tlb.handler[index]->readd(address);
} else return mem_unalignedreadd(address);
}
INLINE void mem_writew_dyncorex86(PhysPt address,Bit16u val) {
if ((address & 0xfff)<0xfff) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) host_writew(paging.tlb.write[index]+address,val);
else paging.tlb.handler[index]->writew(address,val);
} else mem_unalignedwritew(address,val);
}
INLINE void mem_writed_dyncorex86(PhysPt address,Bit32u val) {
if ((address & 0xfff)<0xffd) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) host_writed(paging.tlb.write[index]+address,val);
else paging.tlb.handler[index]->writed(address,val);
} else mem_unalignedwrited(address,val);
}
INLINE bool mem_readb_checked_x86(PhysPt address, Bit8u * val) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) {
*val=host_readb(paging.tlb.read[index]+address);
return false;
} else {
Bitu uval;
bool retval;
retval=paging.tlb.handler[index]->readb_checked(address, &uval);
*val=(Bit8u)uval;
return retval;
}
}
INLINE bool mem_readw_checked_x86(PhysPt address, Bit16u * val) {
if ((address & 0xfff)<0xfff) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) {
*val=host_readw(paging.tlb.read[index]+address);
return false;
} else {
Bitu uval;
bool retval;
retval=paging.tlb.handler[index]->readw_checked(address, &uval);
*val=(Bit16u)uval;
return retval;
}
} else return mem_unalignedreadw_checked_x86(address, val);
}
INLINE bool mem_readd_checked_x86(PhysPt address, Bit32u * val) {
if ((address & 0xfff)<0xffd) {
Bitu index=(address>>12);
if (paging.tlb.read[index]) {
*val=host_readd(paging.tlb.read[index]+address);
return false;
} else {
Bitu uval;
bool retval;
retval=paging.tlb.handler[index]->readd_checked(address, &uval);
*val=(Bit32u)uval;
return retval;
}
} else return mem_unalignedreadd_checked_x86(address, val);
}
INLINE bool mem_writeb_checked_x86(PhysPt address,Bit8u val) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) {
host_writeb(paging.tlb.write[index]+address,val);
return false;
} else return paging.tlb.handler[index]->writeb_checked(address,val);
}
INLINE bool mem_writew_checked_x86(PhysPt address,Bit16u val) {
if ((address & 0xfff)<0xfff) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) {
host_writew(paging.tlb.write[index]+address,val);
return false;
} else return paging.tlb.handler[index]->writew_checked(address,val);
} else return mem_unalignedwritew_checked_x86(address,val);
}
INLINE bool mem_writed_checked_x86(PhysPt address,Bit32u val) {
if ((address & 0xfff)<0xffd) {
Bitu index=(address>>12);
if (paging.tlb.write[index]) {
host_writed(paging.tlb.write[index]+address,val);
return false;
} else return paging.tlb.handler[index]->writed_checked(address,val);
} else return mem_unalignedwrited_checked_x86(address,val);
}
#endif