]> git.proxmox.com Git - qemu.git/blame - softmmu_template.h
i386: Remove REGPARM
[qemu.git] / softmmu_template.h
CommitLineData
b92e5a22
FB
1/*
2 * Software MMU support
5fafdf24 3 *
efbf29b6
BS
4 * Generate helpers used by TCG for qemu_ld/st ops and code load
5 * functions.
6 *
7 * Included from target op helpers and exec.c.
8 *
b92e5a22
FB
9 * Copyright (c) 2003 Fabrice Bellard
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
8167ee88 22 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
b92e5a22 23 */
29e922b6 24#include "qemu-timer.h"
0e0df1e2 25#include "memory.h"
29e922b6 26
b92e5a22
FB
27#define DATA_SIZE (1 << SHIFT)
28
29#if DATA_SIZE == 8
30#define SUFFIX q
61382a50 31#define USUFFIX q
b92e5a22
FB
32#define DATA_TYPE uint64_t
33#elif DATA_SIZE == 4
34#define SUFFIX l
61382a50 35#define USUFFIX l
b92e5a22
FB
36#define DATA_TYPE uint32_t
37#elif DATA_SIZE == 2
38#define SUFFIX w
61382a50 39#define USUFFIX uw
b92e5a22
FB
40#define DATA_TYPE uint16_t
41#elif DATA_SIZE == 1
42#define SUFFIX b
61382a50 43#define USUFFIX ub
b92e5a22
FB
44#define DATA_TYPE uint8_t
45#else
46#error unsupported data size
47#endif
48
b769d8fe
FB
49#ifdef SOFTMMU_CODE_ACCESS
50#define READ_ACCESS_TYPE 2
84b7b8e7 51#define ADDR_READ addr_code
b769d8fe
FB
52#else
53#define READ_ACCESS_TYPE 0
84b7b8e7 54#define ADDR_READ addr_read
b769d8fe
FB
55#endif
56
5fafdf24 57static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
6ebbf390 58 int mmu_idx,
61382a50 59 void *retaddr);
c227f099 60static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
2e70f6ef
PB
61 target_ulong addr,
62 void *retaddr)
b92e5a22
FB
63{
64 DATA_TYPE res;
37ec01d4
AK
65 MemoryRegion *mr = iotlb_to_region(physaddr);
66
0f459d16 67 physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
2e70f6ef 68 env->mem_io_pc = (unsigned long)retaddr;
37ec01d4
AK
69 if (mr != &io_mem_ram && mr != &io_mem_rom
70 && mr != &io_mem_unassigned
71 && mr != &io_mem_notdirty
2e70f6ef
PB
72 && !can_do_io(env)) {
73 cpu_io_recompile(env, retaddr);
74 }
b92e5a22 75
db8886d3 76 env->mem_io_vaddr = addr;
b92e5a22 77#if SHIFT <= 2
37ec01d4 78 res = io_mem_read(mr, physaddr, 1 << SHIFT);
b92e5a22
FB
79#else
80#ifdef TARGET_WORDS_BIGENDIAN
37ec01d4
AK
81 res = io_mem_read(mr, physaddr, 4) << 32;
82 res |= io_mem_read(mr, physaddr + 4, 4);
b92e5a22 83#else
37ec01d4
AK
84 res = io_mem_read(mr, physaddr, 4);
85 res |= io_mem_read(mr, physaddr + 4, 4) << 32;
b92e5a22
FB
86#endif
87#endif /* SHIFT > 2 */
88 return res;
89}
90
b92e5a22 91/* handle all cases except unaligned access which span two pages */
6a18ae2d 92DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx)
b92e5a22
FB
93{
94 DATA_TYPE res;
61382a50 95 int index;
c27004ec 96 target_ulong tlb_addr;
355b1943
PB
97 target_phys_addr_t ioaddr;
98 unsigned long addend;
b92e5a22 99 void *retaddr;
3b46e624 100
b92e5a22
FB
101 /* test if there is match for unaligned or IO access */
102 /* XXX: could done more in memory macro in a non portable way */
b92e5a22
FB
103 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
104 redo:
6ebbf390 105 tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
b92e5a22 106 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
b92e5a22
FB
107 if (tlb_addr & ~TARGET_PAGE_MASK) {
108 /* IO access */
109 if ((addr & (DATA_SIZE - 1)) != 0)
110 goto do_unaligned_access;
2e70f6ef 111 retaddr = GETPC();
37ec01d4 112 ioaddr = env->iotlb[mmu_idx][index];
355b1943 113 res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
98699967 114 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
b92e5a22
FB
115 /* slow unaligned access (it spans two pages or IO) */
116 do_unaligned_access:
61382a50 117 retaddr = GETPC();
a64d4718 118#ifdef ALIGNED_ONLY
6ebbf390 119 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
a64d4718 120#endif
5fafdf24 121 res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
6ebbf390 122 mmu_idx, retaddr);
b92e5a22 123 } else {
a64d4718
FB
124 /* unaligned/aligned access in the same page */
125#ifdef ALIGNED_ONLY
126 if ((addr & (DATA_SIZE - 1)) != 0) {
127 retaddr = GETPC();
6ebbf390 128 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
a64d4718
FB
129 }
130#endif
0f459d16
PB
131 addend = env->tlb_table[mmu_idx][index].addend;
132 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
b92e5a22
FB
133 }
134 } else {
135 /* the page is not in the TLB : fill it */
61382a50 136 retaddr = GETPC();
a64d4718
FB
137#ifdef ALIGNED_ONLY
138 if ((addr & (DATA_SIZE - 1)) != 0)
6ebbf390 139 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
a64d4718 140#endif
bccd9ec5 141 tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
b92e5a22
FB
142 goto redo;
143 }
144 return res;
145}
146
147/* handle all unaligned cases */
5fafdf24 148static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
6ebbf390 149 int mmu_idx,
61382a50 150 void *retaddr)
b92e5a22
FB
151{
152 DATA_TYPE res, res1, res2;
61382a50 153 int index, shift;
355b1943
PB
154 target_phys_addr_t ioaddr;
155 unsigned long addend;
c27004ec 156 target_ulong tlb_addr, addr1, addr2;
b92e5a22 157
b92e5a22
FB
158 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
159 redo:
6ebbf390 160 tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
b92e5a22 161 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
b92e5a22
FB
162 if (tlb_addr & ~TARGET_PAGE_MASK) {
163 /* IO access */
164 if ((addr & (DATA_SIZE - 1)) != 0)
165 goto do_unaligned_access;
37ec01d4 166 ioaddr = env->iotlb[mmu_idx][index];
355b1943 167 res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
98699967 168 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
b92e5a22
FB
169 do_unaligned_access:
170 /* slow unaligned access (it spans two pages) */
171 addr1 = addr & ~(DATA_SIZE - 1);
172 addr2 = addr1 + DATA_SIZE;
5fafdf24 173 res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
6ebbf390 174 mmu_idx, retaddr);
5fafdf24 175 res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
6ebbf390 176 mmu_idx, retaddr);
b92e5a22
FB
177 shift = (addr & (DATA_SIZE - 1)) * 8;
178#ifdef TARGET_WORDS_BIGENDIAN
179 res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
180#else
181 res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
182#endif
6986f88c 183 res = (DATA_TYPE)res;
b92e5a22
FB
184 } else {
185 /* unaligned/aligned access in the same page */
0f459d16
PB
186 addend = env->tlb_table[mmu_idx][index].addend;
187 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
b92e5a22
FB
188 }
189 } else {
190 /* the page is not in the TLB : fill it */
bccd9ec5 191 tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
b92e5a22
FB
192 goto redo;
193 }
194 return res;
195}
196
b769d8fe
FB
197#ifndef SOFTMMU_CODE_ACCESS
198
5fafdf24
TS
199static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
200 DATA_TYPE val,
6ebbf390 201 int mmu_idx,
b769d8fe
FB
202 void *retaddr);
203
c227f099 204static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
b769d8fe 205 DATA_TYPE val,
0f459d16 206 target_ulong addr,
b769d8fe
FB
207 void *retaddr)
208{
37ec01d4
AK
209 MemoryRegion *mr = iotlb_to_region(physaddr);
210
0f459d16 211 physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
37ec01d4
AK
212 if (mr != &io_mem_ram && mr != &io_mem_rom
213 && mr != &io_mem_unassigned
214 && mr != &io_mem_notdirty
2e70f6ef
PB
215 && !can_do_io(env)) {
216 cpu_io_recompile(env, retaddr);
217 }
b769d8fe 218
2e70f6ef
PB
219 env->mem_io_vaddr = addr;
220 env->mem_io_pc = (unsigned long)retaddr;
b769d8fe 221#if SHIFT <= 2
37ec01d4 222 io_mem_write(mr, physaddr, val, 1 << SHIFT);
b769d8fe
FB
223#else
224#ifdef TARGET_WORDS_BIGENDIAN
37ec01d4
AK
225 io_mem_write(mr, physaddr, (val >> 32), 4);
226 io_mem_write(mr, physaddr + 4, (uint32_t)val, 4);
b769d8fe 227#else
37ec01d4
AK
228 io_mem_write(mr, physaddr, (uint32_t)val, 4);
229 io_mem_write(mr, physaddr + 4, val >> 32, 4);
b769d8fe
FB
230#endif
231#endif /* SHIFT > 2 */
232}
b92e5a22 233
6a18ae2d
BS
234void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val,
235 int mmu_idx)
b92e5a22 236{
355b1943
PB
237 target_phys_addr_t ioaddr;
238 unsigned long addend;
c27004ec 239 target_ulong tlb_addr;
b92e5a22 240 void *retaddr;
61382a50 241 int index;
3b46e624 242
b92e5a22
FB
243 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
244 redo:
6ebbf390 245 tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
b92e5a22 246 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
b92e5a22
FB
247 if (tlb_addr & ~TARGET_PAGE_MASK) {
248 /* IO access */
249 if ((addr & (DATA_SIZE - 1)) != 0)
250 goto do_unaligned_access;
d720b93d 251 retaddr = GETPC();
37ec01d4 252 ioaddr = env->iotlb[mmu_idx][index];
355b1943 253 glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
98699967 254 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
b92e5a22 255 do_unaligned_access:
61382a50 256 retaddr = GETPC();
a64d4718 257#ifdef ALIGNED_ONLY
6ebbf390 258 do_unaligned_access(addr, 1, mmu_idx, retaddr);
a64d4718 259#endif
5fafdf24 260 glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
6ebbf390 261 mmu_idx, retaddr);
b92e5a22
FB
262 } else {
263 /* aligned/unaligned access in the same page */
a64d4718
FB
264#ifdef ALIGNED_ONLY
265 if ((addr & (DATA_SIZE - 1)) != 0) {
266 retaddr = GETPC();
6ebbf390 267 do_unaligned_access(addr, 1, mmu_idx, retaddr);
a64d4718
FB
268 }
269#endif
0f459d16
PB
270 addend = env->tlb_table[mmu_idx][index].addend;
271 glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
b92e5a22
FB
272 }
273 } else {
274 /* the page is not in the TLB : fill it */
61382a50 275 retaddr = GETPC();
a64d4718
FB
276#ifdef ALIGNED_ONLY
277 if ((addr & (DATA_SIZE - 1)) != 0)
6ebbf390 278 do_unaligned_access(addr, 1, mmu_idx, retaddr);
a64d4718 279#endif
bccd9ec5 280 tlb_fill(env, addr, 1, mmu_idx, retaddr);
b92e5a22
FB
281 goto redo;
282 }
283}
284
285/* handles all unaligned cases */
5fafdf24 286static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
61382a50 287 DATA_TYPE val,
6ebbf390 288 int mmu_idx,
61382a50 289 void *retaddr)
b92e5a22 290{
355b1943
PB
291 target_phys_addr_t ioaddr;
292 unsigned long addend;
c27004ec 293 target_ulong tlb_addr;
61382a50 294 int index, i;
b92e5a22 295
b92e5a22
FB
296 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
297 redo:
6ebbf390 298 tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
b92e5a22 299 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
b92e5a22
FB
300 if (tlb_addr & ~TARGET_PAGE_MASK) {
301 /* IO access */
302 if ((addr & (DATA_SIZE - 1)) != 0)
303 goto do_unaligned_access;
37ec01d4 304 ioaddr = env->iotlb[mmu_idx][index];
355b1943 305 glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
98699967 306 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
b92e5a22
FB
307 do_unaligned_access:
308 /* XXX: not efficient, but simple */
6c41b272
AZ
309 /* Note: relies on the fact that tlb_fill() does not remove the
310 * previous page from the TLB cache. */
7221fa98 311 for(i = DATA_SIZE - 1; i >= 0; i--) {
b92e5a22 312#ifdef TARGET_WORDS_BIGENDIAN
5fafdf24 313 glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
6ebbf390 314 mmu_idx, retaddr);
b92e5a22 315#else
5fafdf24 316 glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
6ebbf390 317 mmu_idx, retaddr);
b92e5a22
FB
318#endif
319 }
320 } else {
321 /* aligned/unaligned access in the same page */
0f459d16
PB
322 addend = env->tlb_table[mmu_idx][index].addend;
323 glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
b92e5a22
FB
324 }
325 } else {
326 /* the page is not in the TLB : fill it */
bccd9ec5 327 tlb_fill(env, addr, 1, mmu_idx, retaddr);
b92e5a22
FB
328 goto redo;
329 }
330}
331
b769d8fe
FB
332#endif /* !defined(SOFTMMU_CODE_ACCESS) */
333
334#undef READ_ACCESS_TYPE
b92e5a22
FB
335#undef SHIFT
336#undef DATA_TYPE
337#undef SUFFIX
61382a50 338#undef USUFFIX
b92e5a22 339#undef DATA_SIZE
84b7b8e7 340#undef ADDR_READ