1 /*
2  *  Copyright (C) 2002-2010  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* $Id: paging.h,v 1.33 2009-05-27 09:15:41 qbix79 Exp $ */
20 
21 #ifndef DOSBOX_PAGING_H
22 #define DOSBOX_PAGING_H
23 
24 #ifndef DOSBOX_DOSBOX_H
25 #include "dosbox.h"
26 #endif
27 #ifndef DOSBOX_MEM_H
28 #include "mem.h"
29 #endif
30 
31 // disable this to reduce the size of the TLB
32 // NOTE: does not work with the dynamic core (dynrec is fine)
33 #define USE_FULL_TLB
34 
35 class PageDirectory;
36 
37 #define MEM_PAGE_SIZE	(4096)
38 #define XMS_START		(0x110)
39 
40 #if defined(USE_FULL_TLB)
41 #define TLB_SIZE		(1024*1024)
42 #else
43 #define TLB_SIZE		65536	// This must a power of 2 and greater then LINK_START
44 #define BANK_SHIFT		28
45 #define BANK_MASK		0xffff // always the same as TLB_SIZE-1?
46 #define TLB_BANKS		((1024*1024/TLB_SIZE)-1)
47 #endif
48 
49 #define PFLAG_READABLE		0x1
50 #define PFLAG_WRITEABLE		0x2
51 #define PFLAG_HASROM		0x4
52 #define PFLAG_HASCODE		0x8				//Page contains dynamic code
53 #define PFLAG_NOCODE		0x10			//No dynamic code can be generated here
54 #define PFLAG_INIT			0x20			//No dynamic code can be generated here
55 
56 #define LINK_START	((1024+64)/4)			//Start right after the HMA
57 
58 //Allow 128 mb of memory to be linked
59 #define PAGING_LINKS (128*1024/4)
60 
61 class PageHandler {
62 public:
~PageHandler(void)63 	virtual ~PageHandler(void) { }
64 	virtual Bitu readb(PhysPt addr);
65 	virtual Bitu readw(PhysPt addr);
66 	virtual Bitu readd(PhysPt addr);
67 	virtual void writeb(PhysPt addr,Bitu val);
68 	virtual void writew(PhysPt addr,Bitu val);
69 	virtual void writed(PhysPt addr,Bitu val);
70 	virtual HostPt GetHostReadPt(Bitu phys_page);
71 	virtual HostPt GetHostWritePt(Bitu phys_page);
72 	virtual bool readb_checked(PhysPt addr,Bit8u * val);
73 	virtual bool readw_checked(PhysPt addr,Bit16u * val);
74 	virtual bool readd_checked(PhysPt addr,Bit32u * val);
75 	virtual bool writeb_checked(PhysPt addr,Bitu val);
76 	virtual bool writew_checked(PhysPt addr,Bitu val);
77 	virtual bool writed_checked(PhysPt addr,Bitu val);
78 	Bitu flags;
79 };
80 
81 /* Some other functions */
82 void PAGING_Enable(bool enabled);
83 bool PAGING_Enabled(void);
84 
85 Bitu PAGING_GetDirBase(void);
86 void PAGING_SetDirBase(Bitu cr3);
87 void PAGING_InitTLB(void);
88 void PAGING_ClearTLB(void);
89 
90 void PAGING_LinkPage(Bitu lin_page,Bitu phys_page);
91 void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page);
92 void PAGING_UnlinkPages(Bitu lin_page,Bitu pages);
93 /* This maps the page directly, only use when paging is disabled */
94 void PAGING_MapPage(Bitu lin_page,Bitu phys_page);
95 bool PAGING_MakePhysPage(Bitu & page);
96 bool PAGING_ForcePageInit(Bitu lin_addr);
97 
98 void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler, PageHandler *mmiohandler);
99 void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
100 void MEM_ResetPageHandler(Bitu phys_page, Bitu pages);
101 
102 
103 #ifdef _MSC_VER
104 #pragma pack (1)
105 #endif
106 struct X86_PageEntryBlock{
107 #ifdef WORDS_BIGENDIAN
108 	Bit32u		base:20;
109 	Bit32u		avl:3;
110 	Bit32u		g:1;
111 	Bit32u		pat:1;
112 	Bit32u		d:1;
113 	Bit32u		a:1;
114 	Bit32u		pcd:1;
115 	Bit32u		pwt:1;
116 	Bit32u		us:1;
117 	Bit32u		wr:1;
118 	Bit32u		p:1;
119 #else
120 	Bit32u		p:1;
121 	Bit32u		wr:1;
122 	Bit32u		us:1;
123 	Bit32u		pwt:1;
124 	Bit32u		pcd:1;
125 	Bit32u		a:1;
126 	Bit32u		d:1;
127 	Bit32u		pat:1;
128 	Bit32u		g:1;
129 	Bit32u		avl:3;
130 	Bit32u		base:20;
131 #endif
132 } GCC_ATTRIBUTE(packed);
133 #ifdef _MSC_VER
134 #pragma pack ()
135 #endif
136 
137 
138 union X86PageEntry {
139 	Bit32u load;
140 	X86_PageEntryBlock block;
141 };
142 
143 #if !defined(USE_FULL_TLB)
144 typedef struct {
145 	HostPt read;
146 	HostPt write;
147 	PageHandler * readhandler;
148 	PageHandler * writehandler;
149 	Bit32u phys_page;
150 } tlb_entry;
151 #endif
152 
153 struct PagingBlock {
154 	Bitu			cr3;
155 	Bitu			cr2;
156 	struct {
157 		Bitu page;
158 		PhysPt addr;
159 	} base;
160 #if defined(USE_FULL_TLB)
161 	struct {
162 		HostPt read[TLB_SIZE];
163 		HostPt write[TLB_SIZE];
164 		PageHandler * readhandler[TLB_SIZE];
165 		PageHandler * writehandler[TLB_SIZE];
166 		Bit32u	phys_page[TLB_SIZE];
167 	} tlb;
168 #else
169 	tlb_entry tlbh[TLB_SIZE];
170 	tlb_entry *tlbh_banks[TLB_BANKS];
171 #endif
172 	struct {
173 		Bitu used;
174 		Bit32u entries[PAGING_LINKS];
175 	} links;
176 	Bit32u		firstmb[LINK_START];
177 	bool		enabled;
178 };
179 
180 extern PagingBlock paging;
181 
182 /* Some support functions */
183 
184 PageHandler * MEM_GetPageHandler(Bitu phys_page);
185 
186 
187 /* Unaligned address handlers */
188 Bit16u mem_unalignedreadw(PhysPt address);
189 Bit32u mem_unalignedreadd(PhysPt address);
190 void mem_unalignedwritew(PhysPt address,Bit16u val);
191 void mem_unalignedwrited(PhysPt address,Bit32u val);
192 
193 bool mem_unalignedreadw_checked(PhysPt address,Bit16u * val);
194 bool mem_unalignedreadd_checked(PhysPt address,Bit32u * val);
195 bool mem_unalignedwritew_checked(PhysPt address,Bit16u val);
196 bool mem_unalignedwrited_checked(PhysPt address,Bit32u val);
197 
198 #if defined(USE_FULL_TLB)
199 
get_tlb_read(PhysPt address)200 static INLINE HostPt get_tlb_read(PhysPt address) {
201 	return paging.tlb.read[address>>12];
202 }
get_tlb_write(PhysPt address)203 static INLINE HostPt get_tlb_write(PhysPt address) {
204 	return paging.tlb.write[address>>12];
205 }
get_tlb_readhandler(PhysPt address)206 static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
207 	return paging.tlb.readhandler[address>>12];
208 }
get_tlb_writehandler(PhysPt address)209 static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
210 	return paging.tlb.writehandler[address>>12];
211 }
212 
213 /* Use these helper functions to access linear addresses in readX/writeX functions */
PAGING_GetPhysicalPage(PhysPt linePage)214 static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
215 	return (paging.tlb.phys_page[linePage>>12]<<12);
216 }
217 
PAGING_GetPhysicalAddress(PhysPt linAddr)218 static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
219 	return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff);
220 }
221 
222 #else
223 
224 void PAGING_InitTLBBank(tlb_entry **bank);
225 
get_tlb_entry(PhysPt address)226 static INLINE tlb_entry *get_tlb_entry(PhysPt address) {
227 	Bitu index=(address>>12);
228 	if (TLB_BANKS && (index >= TLB_SIZE)) {
229 		Bitu bank=(address>>BANK_SHIFT) - 1;
230 		if (!paging.tlbh_banks[bank])
231 			PAGING_InitTLBBank(&paging.tlbh_banks[bank]);
232 		return &paging.tlbh_banks[bank][index & BANK_MASK];
233 	}
234 	return &paging.tlbh[index];
235 }
236 
get_tlb_read(PhysPt address)237 static INLINE HostPt get_tlb_read(PhysPt address) {
238 	return get_tlb_entry(address)->read;
239 }
get_tlb_write(PhysPt address)240 static INLINE HostPt get_tlb_write(PhysPt address) {
241 	return get_tlb_entry(address)->write;
242 }
get_tlb_readhandler(PhysPt address)243 static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
244 	return get_tlb_entry(address)->readhandler;
245 }
get_tlb_writehandler(PhysPt address)246 static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
247 	return get_tlb_entry(address)->writehandler;
248 }
249 
250 /* Use these helper functions to access linear addresses in readX/writeX functions */
PAGING_GetPhysicalPage(PhysPt linePage)251 static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
252 	tlb_entry *entry = get_tlb_entry(linePage);
253 	return (entry->phys_page<<12);
254 }
255 
PAGING_GetPhysicalAddress(PhysPt linAddr)256 static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
257 	tlb_entry *entry = get_tlb_entry(linAddr);
258 	return (entry->phys_page<<12)|(linAddr&0xfff);
259 }
260 #endif
261 
262 /* Special inlined memory reading/writing */
263 
mem_readb_inline(PhysPt address)264 static INLINE Bit8u mem_readb_inline(PhysPt address) {
265 	HostPt tlb_addr=get_tlb_read(address);
266 	if (tlb_addr) return host_readb(tlb_addr+address);
267 	else return (Bit8u)(get_tlb_readhandler(address))->readb(address);
268 }
269 
mem_readw_inline(PhysPt address)270 static INLINE Bit16u mem_readw_inline(PhysPt address) {
271 	if ((address & 0xfff)<0xfff) {
272 		HostPt tlb_addr=get_tlb_read(address);
273 		if (tlb_addr) return host_readw(tlb_addr+address);
274 		else return (Bit16u)(get_tlb_readhandler(address))->readw(address);
275 	} else return mem_unalignedreadw(address);
276 }
277 
mem_readd_inline(PhysPt address)278 static INLINE Bit32u mem_readd_inline(PhysPt address) {
279 	if ((address & 0xfff)<0xffd) {
280 		HostPt tlb_addr=get_tlb_read(address);
281 		if (tlb_addr) return host_readd(tlb_addr+address);
282 		else return (get_tlb_readhandler(address))->readd(address);
283 	} else return mem_unalignedreadd(address);
284 }
285 
mem_writeb_inline(PhysPt address,Bit8u val)286 static INLINE void mem_writeb_inline(PhysPt address,Bit8u val) {
287 	HostPt tlb_addr=get_tlb_write(address);
288 	if (tlb_addr) host_writeb(tlb_addr+address,val);
289 	else (get_tlb_writehandler(address))->writeb(address,val);
290 }
291 
mem_writew_inline(PhysPt address,Bit16u val)292 static INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
293 	if ((address & 0xfff)<0xfff) {
294 		HostPt tlb_addr=get_tlb_write(address);
295 		if (tlb_addr) host_writew(tlb_addr+address,val);
296 		else (get_tlb_writehandler(address))->writew(address,val);
297 	} else mem_unalignedwritew(address,val);
298 }
299 
mem_writed_inline(PhysPt address,Bit32u val)300 static INLINE void mem_writed_inline(PhysPt address,Bit32u val) {
301 	if ((address & 0xfff)<0xffd) {
302 		HostPt tlb_addr=get_tlb_write(address);
303 		if (tlb_addr) host_writed(tlb_addr+address,val);
304 		else (get_tlb_writehandler(address))->writed(address,val);
305 	} else mem_unalignedwrited(address,val);
306 }
307 
308 
mem_readb_checked(PhysPt address,Bit8u * val)309 static INLINE bool mem_readb_checked(PhysPt address, Bit8u * val) {
310 	HostPt tlb_addr=get_tlb_read(address);
311 	if (tlb_addr) {
312 		*val=host_readb(tlb_addr+address);
313 		return false;
314 	} else return (get_tlb_readhandler(address))->readb_checked(address, val);
315 }
316 
mem_readw_checked(PhysPt address,Bit16u * val)317 static INLINE bool mem_readw_checked(PhysPt address, Bit16u * val) {
318 	if ((address & 0xfff)<0xfff) {
319 		HostPt tlb_addr=get_tlb_read(address);
320 		if (tlb_addr) {
321 			*val=host_readw(tlb_addr+address);
322 			return false;
323 		} else return (get_tlb_readhandler(address))->readw_checked(address, val);
324 	} else return mem_unalignedreadw_checked(address, val);
325 }
326 
mem_readd_checked(PhysPt address,Bit32u * val)327 static INLINE bool mem_readd_checked(PhysPt address, Bit32u * val) {
328 	if ((address & 0xfff)<0xffd) {
329 		HostPt tlb_addr=get_tlb_read(address);
330 		if (tlb_addr) {
331 			*val=host_readd(tlb_addr+address);
332 			return false;
333 		} else return (get_tlb_readhandler(address))->readd_checked(address, val);
334 	} else return mem_unalignedreadd_checked(address, val);
335 }
336 
mem_writeb_checked(PhysPt address,Bit8u val)337 static INLINE bool mem_writeb_checked(PhysPt address,Bit8u val) {
338 	HostPt tlb_addr=get_tlb_write(address);
339 	if (tlb_addr) {
340 		host_writeb(tlb_addr+address,val);
341 		return false;
342 	} else return (get_tlb_writehandler(address))->writeb_checked(address,val);
343 }
344 
mem_writew_checked(PhysPt address,Bit16u val)345 static INLINE bool mem_writew_checked(PhysPt address,Bit16u val) {
346 	if ((address & 0xfff)<0xfff) {
347 		HostPt tlb_addr=get_tlb_write(address);
348 		if (tlb_addr) {
349 			host_writew(tlb_addr+address,val);
350 			return false;
351 		} else return (get_tlb_writehandler(address))->writew_checked(address,val);
352 	} else return mem_unalignedwritew_checked(address,val);
353 }
354 
mem_writed_checked(PhysPt address,Bit32u val)355 static INLINE bool mem_writed_checked(PhysPt address,Bit32u val) {
356 	if ((address & 0xfff)<0xffd) {
357 		HostPt tlb_addr=get_tlb_write(address);
358 		if (tlb_addr) {
359 			host_writed(tlb_addr+address,val);
360 			return false;
361 		} else return (get_tlb_writehandler(address))->writed_checked(address,val);
362 	} else return mem_unalignedwrited_checked(address,val);
363 }
364 
365 
366 #endif
367