PAGE_EXEC support in TLBs
[qemu] / softmmu_header.h
1 /*
2  *  Software MMU support
3  * 
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #if DATA_SIZE == 8
21 #define SUFFIX q
22 #define USUFFIX q
23 #define DATA_TYPE uint64_t
24 #elif DATA_SIZE == 4
25 #define SUFFIX l
26 #define USUFFIX l
27 #define DATA_TYPE uint32_t
28 #elif DATA_SIZE == 2
29 #define SUFFIX w
30 #define USUFFIX uw
31 #define DATA_TYPE uint16_t
32 #define DATA_STYPE int16_t
33 #elif DATA_SIZE == 1
34 #define SUFFIX b
35 #define USUFFIX ub
36 #define DATA_TYPE uint8_t
37 #define DATA_STYPE int8_t
38 #else
39 #error unsupported data size
40 #endif
41
42 #if ACCESS_TYPE == 0
43
44 #define CPU_MEM_INDEX 0
45 #define MMUSUFFIX _mmu
46
47 #elif ACCESS_TYPE == 1
48
49 #define CPU_MEM_INDEX 1
50 #define MMUSUFFIX _mmu
51
52 #elif ACCESS_TYPE == 2
53
54 #ifdef TARGET_I386
55 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
56 #elif defined (TARGET_PPC)
57 #define CPU_MEM_INDEX (msr_pr)
58 #elif defined (TARGET_MIPS)
59 #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
60 #elif defined (TARGET_SPARC)
61 #define CPU_MEM_INDEX ((env->psrs) == 0)
62 #elif defined (TARGET_ARM)
63 #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
64 #else
65 #error unsupported CPU
66 #endif
67 #define MMUSUFFIX _mmu
68
69 #elif ACCESS_TYPE == 3
70
71 #ifdef TARGET_I386
72 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
73 #elif defined (TARGET_PPC)
74 #define CPU_MEM_INDEX (msr_pr)
75 #elif defined (TARGET_MIPS)
76 #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
77 #elif defined (TARGET_SPARC)
78 #define CPU_MEM_INDEX ((env->psrs) == 0)
79 #elif defined (TARGET_ARM)
80 #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
81 #else
82 #error unsupported CPU
83 #endif
84 #define MMUSUFFIX _cmmu
85
86 #else
87 #error invalid ACCESS_TYPE
88 #endif
89
90 #if DATA_SIZE == 8
91 #define RES_TYPE uint64_t
92 #else
93 #define RES_TYPE int
94 #endif
95
96 #if ACCESS_TYPE == 3
97 #define ADDR_READ addr_code
98 #else
99 #define ADDR_READ addr_read
100 #endif
101
102 DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
103                                                          int is_user);
104 void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user);
105
106 #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \
107     (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU)
108
109 #define CPU_TLB_ENTRY_BITS 4
110
111 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
112 {
113     int res;
114
115     asm volatile ("movl %1, %%edx\n"
116                   "movl %1, %%eax\n"
117                   "shrl %3, %%edx\n"
118                   "andl %4, %%eax\n"
119                   "andl %2, %%edx\n"
120                   "leal %5(%%edx, %%ebp), %%edx\n"
121                   "cmpl (%%edx), %%eax\n"
122                   "movl %1, %%eax\n"
123                   "je 1f\n"
124                   "pushl %6\n"
125                   "call %7\n"
126                   "popl %%edx\n"
127                   "movl %%eax, %0\n"
128                   "jmp 2f\n"
129                   "1:\n"
130                   "addl 12(%%edx), %%eax\n"
131 #if DATA_SIZE == 1
132                   "movzbl (%%eax), %0\n"
133 #elif DATA_SIZE == 2
134                   "movzwl (%%eax), %0\n"
135 #elif DATA_SIZE == 4
136                   "movl (%%eax), %0\n"
137 #else
138 #error unsupported size
139 #endif
140                   "2:\n"
141                   : "=r" (res)
142                   : "r" (ptr), 
143                   "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
144                   "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
145                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
146                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
147                   "i" (CPU_MEM_INDEX),
148                   "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
149                   : "%eax", "%ecx", "%edx", "memory", "cc");
150     return res;
151 }
152
153 #if DATA_SIZE <= 2
154 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
155 {
156     int res;
157
158     asm volatile ("movl %1, %%edx\n"
159                   "movl %1, %%eax\n"
160                   "shrl %3, %%edx\n"
161                   "andl %4, %%eax\n"
162                   "andl %2, %%edx\n"
163                   "leal %5(%%edx, %%ebp), %%edx\n"
164                   "cmpl (%%edx), %%eax\n"
165                   "movl %1, %%eax\n"
166                   "je 1f\n"
167                   "pushl %6\n"
168                   "call %7\n"
169                   "popl %%edx\n"
170 #if DATA_SIZE == 1
171                   "movsbl %%al, %0\n"
172 #elif DATA_SIZE == 2
173                   "movswl %%ax, %0\n"
174 #else
175 #error unsupported size
176 #endif
177                   "jmp 2f\n"
178                   "1:\n"
179                   "addl 12(%%edx), %%eax\n"
180 #if DATA_SIZE == 1
181                   "movsbl (%%eax), %0\n"
182 #elif DATA_SIZE == 2
183                   "movswl (%%eax), %0\n"
184 #else
185 #error unsupported size
186 #endif
187                   "2:\n"
188                   : "=r" (res)
189                   : "r" (ptr), 
190                   "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
191                   "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
192                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
193                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
194                   "i" (CPU_MEM_INDEX),
195                   "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
196                   : "%eax", "%ecx", "%edx", "memory", "cc");
197     return res;
198 }
199 #endif
200
201 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
202 {
203     asm volatile ("movl %0, %%edx\n"
204                   "movl %0, %%eax\n"
205                   "shrl %3, %%edx\n"
206                   "andl %4, %%eax\n"
207                   "andl %2, %%edx\n"
208                   "leal %5(%%edx, %%ebp), %%edx\n"
209                   "cmpl (%%edx), %%eax\n"
210                   "movl %0, %%eax\n"
211                   "je 1f\n"
212 #if DATA_SIZE == 1
213                   "movzbl %b1, %%edx\n"
214 #elif DATA_SIZE == 2
215                   "movzwl %w1, %%edx\n"
216 #elif DATA_SIZE == 4
217                   "movl %1, %%edx\n"
218 #else
219 #error unsupported size
220 #endif
221                   "pushl %6\n"
222                   "call %7\n"
223                   "popl %%eax\n"
224                   "jmp 2f\n"
225                   "1:\n"
226                   "addl 8(%%edx), %%eax\n"
227 #if DATA_SIZE == 1
228                   "movb %b1, (%%eax)\n"
229 #elif DATA_SIZE == 2
230                   "movw %w1, (%%eax)\n"
231 #elif DATA_SIZE == 4
232                   "movl %1, (%%eax)\n"
233 #else
234 #error unsupported size
235 #endif
236                   "2:\n"
237                   : 
238                   : "r" (ptr), 
239 /* NOTE: 'q' would be needed as constraint, but we could not use it
240    with T1 ! */
241                   "r" (v), 
242                   "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
243                   "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
244                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
245                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)),
246                   "i" (CPU_MEM_INDEX),
247                   "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX))
248                   : "%eax", "%ecx", "%edx", "memory", "cc");
249 }
250
251 #else
252
253 /* generic load/store macros */
254
255 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
256 {
257     int index;
258     RES_TYPE res;
259     target_ulong addr;
260     unsigned long physaddr;
261     int is_user;
262
263     addr = ptr;
264     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
265     is_user = CPU_MEM_INDEX;
266     if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != 
267                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
268         res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
269     } else {
270         physaddr = addr + env->tlb_table[is_user][index].addend;
271         res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
272     }
273     return res;
274 }
275
276 #if DATA_SIZE <= 2
277 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
278 {
279     int res, index;
280     target_ulong addr;
281     unsigned long physaddr;
282     int is_user;
283
284     addr = ptr;
285     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
286     is_user = CPU_MEM_INDEX;
287     if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != 
288                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
289         res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
290     } else {
291         physaddr = addr + env->tlb_table[is_user][index].addend;
292         res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
293     }
294     return res;
295 }
296 #endif
297
298 #if ACCESS_TYPE != 3
299
300 /* generic store macro */
301
302 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
303 {
304     int index;
305     target_ulong addr;
306     unsigned long physaddr;
307     int is_user;
308
309     addr = ptr;
310     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
311     is_user = CPU_MEM_INDEX;
312     if (__builtin_expect(env->tlb_table[is_user][index].addr_write != 
313                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
314         glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user);
315     } else {
316         physaddr = addr + env->tlb_table[is_user][index].addend;
317         glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
318     }
319 }
320
321 #endif /* ACCESS_TYPE != 3 */
322
323 #endif /* !asm */
324
325 #if ACCESS_TYPE != 3
326
327 #if DATA_SIZE == 8
328 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr)
329 {
330     union {
331         float64 d;
332         uint64_t i;
333     } u;
334     u.i = glue(ldq, MEMSUFFIX)(ptr);
335     return u.d;
336 }
337
338 static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v)
339 {
340     union {
341         float64 d;
342         uint64_t i;
343     } u;
344     u.d = v;
345     glue(stq, MEMSUFFIX)(ptr, u.i);
346 }
347 #endif /* DATA_SIZE == 8 */
348
349 #if DATA_SIZE == 4
350 static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr)
351 {
352     union {
353         float32 f;
354         uint32_t i;
355     } u;
356     u.i = glue(ldl, MEMSUFFIX)(ptr);
357     return u.f;
358 }
359
360 static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
361 {
362     union {
363         float32 f;
364         uint32_t i;
365     } u;
366     u.f = v;
367     glue(stl, MEMSUFFIX)(ptr, u.i);
368 }
369 #endif /* DATA_SIZE == 4 */
370
371 #endif /* ACCESS_TYPE != 3 */
372
373 #undef RES_TYPE
374 #undef DATA_TYPE
375 #undef DATA_STYPE
376 #undef SUFFIX
377 #undef USUFFIX
378 #undef DATA_SIZE
379 #undef CPU_MEM_INDEX
380 #undef MMUSUFFIX
381 #undef ADDR_READ