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