|
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 < (NB_MMU_MODES) |
|
43 |
|
44 #define CPU_MMU_INDEX ACCESS_TYPE |
|
45 #define MMUSUFFIX _mmu |
|
46 |
|
47 #elif ACCESS_TYPE == (NB_MMU_MODES) |
|
48 |
|
49 #define CPU_MMU_INDEX (cpu_mmu_index(env)) |
|
50 #define MMUSUFFIX _mmu |
|
51 |
|
52 #elif ACCESS_TYPE == (NB_MMU_MODES + 1) |
|
53 |
|
54 #define CPU_MMU_INDEX (cpu_mmu_index(env)) |
|
55 #define MMUSUFFIX _cmmu |
|
56 |
|
57 #else |
|
58 #error invalid ACCESS_TYPE |
|
59 #endif |
|
60 |
|
61 #if DATA_SIZE == 8 |
|
62 #define RES_TYPE uint64_t |
|
63 #else |
|
64 #define RES_TYPE int |
|
65 #endif |
|
66 |
|
67 #if ACCESS_TYPE == (NB_MMU_MODES + 1) |
|
68 #define ADDR_READ addr_code |
|
69 #else |
|
70 #define ADDR_READ addr_read |
|
71 #endif |
|
72 |
|
73 #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ |
|
74 (ACCESS_TYPE < NB_MMU_MODES) && defined(ASM_SOFTMMU) |
|
75 |
|
76 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) |
|
77 { |
|
78 int res; |
|
79 |
|
80 asm volatile ("movl %1, %%edx\n" |
|
81 "movl %1, %%eax\n" |
|
82 "shrl %3, %%edx\n" |
|
83 "andl %4, %%eax\n" |
|
84 "andl %2, %%edx\n" |
|
85 "leal %5(%%edx, %%ebp), %%edx\n" |
|
86 "cmpl (%%edx), %%eax\n" |
|
87 "movl %1, %%eax\n" |
|
88 "je 1f\n" |
|
89 "movl %6, %%edx\n" |
|
90 "call %7\n" |
|
91 "movl %%eax, %0\n" |
|
92 "jmp 2f\n" |
|
93 "1:\n" |
|
94 "addl 12(%%edx), %%eax\n" |
|
95 #if DATA_SIZE == 1 |
|
96 "movzbl (%%eax), %0\n" |
|
97 #elif DATA_SIZE == 2 |
|
98 "movzwl (%%eax), %0\n" |
|
99 #elif DATA_SIZE == 4 |
|
100 "movl (%%eax), %0\n" |
|
101 #else |
|
102 #error unsupported size |
|
103 #endif |
|
104 "2:\n" |
|
105 : "=r" (res) |
|
106 : "r" (ptr), |
|
107 "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), |
|
108 "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), |
|
109 "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), |
|
110 "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), |
|
111 "i" (CPU_MMU_INDEX), |
|
112 "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) |
|
113 : "%eax", "%ecx", "%edx", "memory", "cc"); |
|
114 return res; |
|
115 } |
|
116 |
|
117 #if DATA_SIZE <= 2 |
|
118 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) |
|
119 { |
|
120 int res; |
|
121 |
|
122 asm volatile ("movl %1, %%edx\n" |
|
123 "movl %1, %%eax\n" |
|
124 "shrl %3, %%edx\n" |
|
125 "andl %4, %%eax\n" |
|
126 "andl %2, %%edx\n" |
|
127 "leal %5(%%edx, %%ebp), %%edx\n" |
|
128 "cmpl (%%edx), %%eax\n" |
|
129 "movl %1, %%eax\n" |
|
130 "je 1f\n" |
|
131 "movl %6, %%edx\n" |
|
132 "call %7\n" |
|
133 #if DATA_SIZE == 1 |
|
134 "movsbl %%al, %0\n" |
|
135 #elif DATA_SIZE == 2 |
|
136 "movswl %%ax, %0\n" |
|
137 #else |
|
138 #error unsupported size |
|
139 #endif |
|
140 "jmp 2f\n" |
|
141 "1:\n" |
|
142 "addl 12(%%edx), %%eax\n" |
|
143 #if DATA_SIZE == 1 |
|
144 "movsbl (%%eax), %0\n" |
|
145 #elif DATA_SIZE == 2 |
|
146 "movswl (%%eax), %0\n" |
|
147 #else |
|
148 #error unsupported size |
|
149 #endif |
|
150 "2:\n" |
|
151 : "=r" (res) |
|
152 : "r" (ptr), |
|
153 "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), |
|
154 "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), |
|
155 "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), |
|
156 "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), |
|
157 "i" (CPU_MMU_INDEX), |
|
158 "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) |
|
159 : "%eax", "%ecx", "%edx", "memory", "cc"); |
|
160 return res; |
|
161 } |
|
162 #endif |
|
163 |
|
164 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) |
|
165 { |
|
166 asm volatile ("movl %0, %%edx\n" |
|
167 "movl %0, %%eax\n" |
|
168 "shrl %3, %%edx\n" |
|
169 "andl %4, %%eax\n" |
|
170 "andl %2, %%edx\n" |
|
171 "leal %5(%%edx, %%ebp), %%edx\n" |
|
172 "cmpl (%%edx), %%eax\n" |
|
173 "movl %0, %%eax\n" |
|
174 "je 1f\n" |
|
175 #if DATA_SIZE == 1 |
|
176 "movzbl %b1, %%edx\n" |
|
177 #elif DATA_SIZE == 2 |
|
178 "movzwl %w1, %%edx\n" |
|
179 #elif DATA_SIZE == 4 |
|
180 "movl %1, %%edx\n" |
|
181 #else |
|
182 #error unsupported size |
|
183 #endif |
|
184 "movl %6, %%ecx\n" |
|
185 "call %7\n" |
|
186 "jmp 2f\n" |
|
187 "1:\n" |
|
188 "addl 8(%%edx), %%eax\n" |
|
189 #if DATA_SIZE == 1 |
|
190 "movb %b1, (%%eax)\n" |
|
191 #elif DATA_SIZE == 2 |
|
192 "movw %w1, (%%eax)\n" |
|
193 #elif DATA_SIZE == 4 |
|
194 "movl %1, (%%eax)\n" |
|
195 #else |
|
196 #error unsupported size |
|
197 #endif |
|
198 "2:\n" |
|
199 : |
|
200 : "r" (ptr), |
|
201 #if DATA_SIZE == 1 |
|
202 "q" (v), |
|
203 #else |
|
204 "r" (v), |
|
205 #endif |
|
206 "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), |
|
207 "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), |
|
208 "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), |
|
209 "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_write)), |
|
210 "i" (CPU_MMU_INDEX), |
|
211 "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) |
|
212 : "%eax", "%ecx", "%edx", "memory", "cc"); |
|
213 } |
|
214 |
|
215 #else |
|
216 |
|
217 /* generic load/store macros */ |
|
218 |
|
219 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) |
|
220 { |
|
221 int page_index; |
|
222 RES_TYPE res; |
|
223 target_ulong addr; |
|
224 unsigned long physaddr; |
|
225 int mmu_idx; |
|
226 |
|
227 addr = ptr; |
|
228 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
|
229 mmu_idx = CPU_MMU_INDEX; |
|
230 if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != |
|
231 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { |
|
232 res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); |
|
233 } else { |
|
234 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; |
|
235 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); |
|
236 } |
|
237 return res; |
|
238 } |
|
239 |
|
240 #if DATA_SIZE <= 2 |
|
241 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) |
|
242 { |
|
243 int res, page_index; |
|
244 target_ulong addr; |
|
245 unsigned long physaddr; |
|
246 int mmu_idx; |
|
247 |
|
248 addr = ptr; |
|
249 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
|
250 mmu_idx = CPU_MMU_INDEX; |
|
251 if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != |
|
252 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { |
|
253 res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); |
|
254 } else { |
|
255 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; |
|
256 res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); |
|
257 } |
|
258 return res; |
|
259 } |
|
260 #endif |
|
261 |
|
262 #if ACCESS_TYPE != (NB_MMU_MODES + 1) |
|
263 |
|
264 /* generic store macro */ |
|
265 |
|
266 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) |
|
267 { |
|
268 int page_index; |
|
269 target_ulong addr; |
|
270 unsigned long physaddr; |
|
271 int mmu_idx; |
|
272 |
|
273 addr = ptr; |
|
274 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
|
275 mmu_idx = CPU_MMU_INDEX; |
|
276 if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != |
|
277 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { |
|
278 glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); |
|
279 } else { |
|
280 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; |
|
281 glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); |
|
282 } |
|
283 } |
|
284 |
|
285 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ |
|
286 |
|
287 #endif /* !asm */ |
|
288 |
|
289 #if ACCESS_TYPE != (NB_MMU_MODES + 1) |
|
290 |
|
291 #if DATA_SIZE == 8 |
|
292 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) |
|
293 { |
|
294 union { |
|
295 float64 d; |
|
296 uint64_t i; |
|
297 } u; |
|
298 u.i = glue(ldq, MEMSUFFIX)(ptr); |
|
299 return u.d; |
|
300 } |
|
301 |
|
302 static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) |
|
303 { |
|
304 union { |
|
305 float64 d; |
|
306 uint64_t i; |
|
307 } u; |
|
308 u.d = v; |
|
309 glue(stq, MEMSUFFIX)(ptr, u.i); |
|
310 } |
|
311 #endif /* DATA_SIZE == 8 */ |
|
312 |
|
313 #if DATA_SIZE == 4 |
|
314 static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) |
|
315 { |
|
316 union { |
|
317 float32 f; |
|
318 uint32_t i; |
|
319 } u; |
|
320 u.i = glue(ldl, MEMSUFFIX)(ptr); |
|
321 return u.f; |
|
322 } |
|
323 |
|
324 static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) |
|
325 { |
|
326 union { |
|
327 float32 f; |
|
328 uint32_t i; |
|
329 } u; |
|
330 u.f = v; |
|
331 glue(stl, MEMSUFFIX)(ptr, u.i); |
|
332 } |
|
333 #endif /* DATA_SIZE == 4 */ |
|
334 |
|
335 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ |
|
336 |
|
337 #undef RES_TYPE |
|
338 #undef DATA_TYPE |
|
339 #undef DATA_STYPE |
|
340 #undef SUFFIX |
|
341 #undef USUFFIX |
|
342 #undef DATA_SIZE |
|
343 #undef CPU_MMU_INDEX |
|
344 #undef MMUSUFFIX |
|
345 #undef ADDR_READ |