blob: 178c237fbaa98604c0686f5468a3e87459cae16f [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
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 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000037
bellardfd6ce8f2003-05-14 19:00:11 +000038//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000039//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000040//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000041
42/* make various TB consistency checks */
43//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000044//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* threshold to flush the translated code buffer */
47#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
48
bellard9fa3e852004-01-04 18:06:42 +000049#define SMC_BITMAP_USE_THRESHOLD 10
50
51#define MMAP_AREA_START 0x00000000
52#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000053
54TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
55TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
bellard9fa3e852004-01-04 18:06:42 +000056TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000057int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000058/* any access to the tbs or the page table must use this lock */
59spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000060
bellardb8076a72005-04-07 22:20:31 +000061uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000062uint8_t *code_gen_ptr;
63
bellard9fa3e852004-01-04 18:06:42 +000064int phys_ram_size;
65int phys_ram_fd;
66uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000067uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000068
bellard54936002003-05-13 00:25:15 +000069typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000070 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000071 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000072 /* in order to optimize self modifying code, we count the number
73 of lookups we do to a given page to use a bitmap */
74 unsigned int code_write_count;
75 uint8_t *code_bitmap;
76#if defined(CONFIG_USER_ONLY)
77 unsigned long flags;
78#endif
bellard54936002003-05-13 00:25:15 +000079} PageDesc;
80
bellard92e873b2004-05-21 14:52:29 +000081typedef struct PhysPageDesc {
82 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +000083 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +000084} PhysPageDesc;
85
bellard90f18422005-07-24 10:17:31 +000086/* Note: the VirtPage handling is absolete and will be suppressed
87 ASAP */
bellard9fa3e852004-01-04 18:06:42 +000088typedef struct VirtPageDesc {
89 /* physical address of code page. It is valid only if 'valid_tag'
90 matches 'virt_valid_tag' */
91 target_ulong phys_addr;
92 unsigned int valid_tag;
93#if !defined(CONFIG_SOFTMMU)
94 /* original page access rights. It is valid only if 'valid_tag'
95 matches 'virt_valid_tag' */
96 unsigned int prot;
97#endif
98} VirtPageDesc;
99
bellard54936002003-05-13 00:25:15 +0000100#define L2_BITS 10
101#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
102
103#define L1_SIZE (1 << L1_BITS)
104#define L2_SIZE (1 << L2_BITS)
105
bellard33417e72003-08-10 21:47:01 +0000106static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000107
bellard83fb7ad2004-07-05 21:25:26 +0000108unsigned long qemu_real_host_page_size;
109unsigned long qemu_host_page_bits;
110unsigned long qemu_host_page_size;
111unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000112
bellard92e873b2004-05-21 14:52:29 +0000113/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000114static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000115PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000116
bellard9fa3e852004-01-04 18:06:42 +0000117#if !defined(CONFIG_USER_ONLY)
bellard90f18422005-07-24 10:17:31 +0000118#if TARGET_LONG_BITS > 32
119#define VIRT_L_BITS 9
120#define VIRT_L_SIZE (1 << VIRT_L_BITS)
121static void *l1_virt_map[VIRT_L_SIZE];
122#else
bellard9fa3e852004-01-04 18:06:42 +0000123static VirtPageDesc *l1_virt_map[L1_SIZE];
bellard90f18422005-07-24 10:17:31 +0000124#endif
bellard9fa3e852004-01-04 18:06:42 +0000125static unsigned int virt_valid_tag;
126#endif
127
bellard33417e72003-08-10 21:47:01 +0000128/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000129CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
130CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000131void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000132static int io_mem_nb;
133
bellard34865132003-10-05 14:28:56 +0000134/* log support */
135char *logfilename = "/tmp/qemu.log";
136FILE *logfile;
137int loglevel;
138
bellarde3db7222005-01-26 22:00:47 +0000139/* statistics */
140static int tlb_flush_count;
141static int tb_flush_count;
142static int tb_phys_invalidate_count;
143
bellardb346ff42003-06-15 20:05:50 +0000144static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000145{
bellard83fb7ad2004-07-05 21:25:26 +0000146 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000147 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000148#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000149 {
150 SYSTEM_INFO system_info;
151 DWORD old_protect;
152
153 GetSystemInfo(&system_info);
154 qemu_real_host_page_size = system_info.dwPageSize;
155
156 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
157 PAGE_EXECUTE_READWRITE, &old_protect);
158 }
bellard67b915a2004-03-31 23:37:16 +0000159#else
bellard83fb7ad2004-07-05 21:25:26 +0000160 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000161 {
162 unsigned long start, end;
163
164 start = (unsigned long)code_gen_buffer;
165 start &= ~(qemu_real_host_page_size - 1);
166
167 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
168 end += qemu_real_host_page_size - 1;
169 end &= ~(qemu_real_host_page_size - 1);
170
171 mprotect((void *)start, end - start,
172 PROT_READ | PROT_WRITE | PROT_EXEC);
173 }
bellard67b915a2004-03-31 23:37:16 +0000174#endif
bellardd5a8f072004-09-29 21:15:28 +0000175
bellard83fb7ad2004-07-05 21:25:26 +0000176 if (qemu_host_page_size == 0)
177 qemu_host_page_size = qemu_real_host_page_size;
178 if (qemu_host_page_size < TARGET_PAGE_SIZE)
179 qemu_host_page_size = TARGET_PAGE_SIZE;
180 qemu_host_page_bits = 0;
181 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
182 qemu_host_page_bits++;
183 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard9fa3e852004-01-04 18:06:42 +0000184#if !defined(CONFIG_USER_ONLY)
185 virt_valid_tag = 1;
186#endif
bellard0a962c02005-02-10 22:00:27 +0000187 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
188 memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
bellard54936002003-05-13 00:25:15 +0000189}
190
bellardfd6ce8f2003-05-14 19:00:11 +0000191static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000192{
bellard54936002003-05-13 00:25:15 +0000193 PageDesc **lp, *p;
194
bellard54936002003-05-13 00:25:15 +0000195 lp = &l1_map[index >> L2_BITS];
196 p = *lp;
197 if (!p) {
198 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000199 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000200 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000201 *lp = p;
202 }
203 return p + (index & (L2_SIZE - 1));
204}
205
bellardfd6ce8f2003-05-14 19:00:11 +0000206static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000207{
bellard54936002003-05-13 00:25:15 +0000208 PageDesc *p;
209
bellard54936002003-05-13 00:25:15 +0000210 p = l1_map[index >> L2_BITS];
211 if (!p)
212 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000213 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000214}
215
bellard92e873b2004-05-21 14:52:29 +0000216static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
217{
218 PhysPageDesc **lp, *p;
219
220 lp = &l1_phys_map[index >> L2_BITS];
221 p = *lp;
222 if (!p) {
223 /* allocate if not found */
bellard0a962c02005-02-10 22:00:27 +0000224 p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
bellard92e873b2004-05-21 14:52:29 +0000225 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
226 *lp = p;
227 }
228 return p + (index & (L2_SIZE - 1));
229}
230
231static inline PhysPageDesc *phys_page_find(unsigned int index)
232{
233 PhysPageDesc *p;
234
235 p = l1_phys_map[index >> L2_BITS];
236 if (!p)
237 return 0;
238 return p + (index & (L2_SIZE - 1));
239}
240
bellard9fa3e852004-01-04 18:06:42 +0000241#if !defined(CONFIG_USER_ONLY)
bellard4f2ac232004-04-26 19:44:02 +0000242static void tlb_protect_code(CPUState *env, target_ulong addr);
243static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000244
bellard90f18422005-07-24 10:17:31 +0000245static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
bellard9fa3e852004-01-04 18:06:42 +0000246{
bellardc27004e2005-01-03 23:35:10 +0000247#if TARGET_LONG_BITS > 32
bellard90f18422005-07-24 10:17:31 +0000248 void **p, **lp;
249
250 p = l1_virt_map;
251 lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
252 p = *lp;
253 if (!p) {
254 if (!alloc)
255 return NULL;
256 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
257 *lp = p;
258 }
259 lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
260 p = *lp;
261 if (!p) {
262 if (!alloc)
263 return NULL;
264 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
265 *lp = p;
266 }
267 lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
268 p = *lp;
269 if (!p) {
270 if (!alloc)
271 return NULL;
272 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
273 *lp = p;
274 }
275 lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
276 p = *lp;
277 if (!p) {
278 if (!alloc)
279 return NULL;
280 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
281 *lp = p;
282 }
283 lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
284 p = *lp;
285 if (!p) {
286 if (!alloc)
287 return NULL;
288 p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
289 *lp = p;
290 }
291 return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
292#else
293 VirtPageDesc *p, **lp;
294
bellard9fa3e852004-01-04 18:06:42 +0000295 lp = &l1_virt_map[index >> L2_BITS];
296 p = *lp;
297 if (!p) {
298 /* allocate if not found */
bellard90f18422005-07-24 10:17:31 +0000299 if (!alloc)
300 return NULL;
301 p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000302 *lp = p;
303 }
304 return p + (index & (L2_SIZE - 1));
bellard90f18422005-07-24 10:17:31 +0000305#endif
bellard9fa3e852004-01-04 18:06:42 +0000306}
307
bellard90f18422005-07-24 10:17:31 +0000308static inline VirtPageDesc *virt_page_find(target_ulong index)
bellard9fa3e852004-01-04 18:06:42 +0000309{
bellard90f18422005-07-24 10:17:31 +0000310 return virt_page_find_alloc(index, 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000311}
312
bellard90f18422005-07-24 10:17:31 +0000313#if TARGET_LONG_BITS > 32
314static void virt_page_flush_internal(void **p, int level)
315{
316 int i;
317 if (level == 0) {
318 VirtPageDesc *q = (VirtPageDesc *)p;
319 for(i = 0; i < VIRT_L_SIZE; i++)
320 q[i].valid_tag = 0;
321 } else {
322 level--;
323 for(i = 0; i < VIRT_L_SIZE; i++) {
324 if (p[i])
325 virt_page_flush_internal(p[i], level);
326 }
327 }
328}
329#endif
330
bellard9fa3e852004-01-04 18:06:42 +0000331static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000332{
bellard9fa3e852004-01-04 18:06:42 +0000333 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000334
bellard9fa3e852004-01-04 18:06:42 +0000335 if (virt_valid_tag == 0) {
336 virt_valid_tag = 1;
bellard90f18422005-07-24 10:17:31 +0000337#if TARGET_LONG_BITS > 32
338 virt_page_flush_internal(l1_virt_map, 5);
339#else
340 {
341 int i, j;
342 VirtPageDesc *p;
343 for(i = 0; i < L1_SIZE; i++) {
344 p = l1_virt_map[i];
345 if (p) {
346 for(j = 0; j < L2_SIZE; j++)
347 p[j].valid_tag = 0;
348 }
bellard9fa3e852004-01-04 18:06:42 +0000349 }
bellardfd6ce8f2003-05-14 19:00:11 +0000350 }
bellard90f18422005-07-24 10:17:31 +0000351#endif
bellard54936002003-05-13 00:25:15 +0000352 }
353}
bellard9fa3e852004-01-04 18:06:42 +0000354#else
355static void virt_page_flush(void)
356{
357}
358#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000359
bellardb346ff42003-06-15 20:05:50 +0000360void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000361{
362 if (!code_gen_ptr) {
363 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000364 page_init();
bellard33417e72003-08-10 21:47:01 +0000365 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000366 }
367}
368
bellard9fa3e852004-01-04 18:06:42 +0000369static inline void invalidate_page_bitmap(PageDesc *p)
370{
371 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000372 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000373 p->code_bitmap = NULL;
374 }
375 p->code_write_count = 0;
376}
377
bellardfd6ce8f2003-05-14 19:00:11 +0000378/* set to NULL all the 'first_tb' fields in all PageDescs */
379static void page_flush_tb(void)
380{
381 int i, j;
382 PageDesc *p;
383
384 for(i = 0; i < L1_SIZE; i++) {
385 p = l1_map[i];
386 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000387 for(j = 0; j < L2_SIZE; j++) {
388 p->first_tb = NULL;
389 invalidate_page_bitmap(p);
390 p++;
391 }
bellardfd6ce8f2003-05-14 19:00:11 +0000392 }
393 }
394}
395
396/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000397/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000398void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000399{
bellard01243112004-01-04 15:48:17 +0000400#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000401 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
402 code_gen_ptr - code_gen_buffer,
403 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000404 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000405#endif
406 nb_tbs = 0;
bellard8a8a6082004-10-03 13:36:49 +0000407 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000408 virt_page_flush();
409
bellard8a8a6082004-10-03 13:36:49 +0000410 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000411 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000412
bellardfd6ce8f2003-05-14 19:00:11 +0000413 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000414 /* XXX: flush processor icache at this point if cache flush is
415 expensive */
bellarde3db7222005-01-26 22:00:47 +0000416 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000417}
418
419#ifdef DEBUG_TB_CHECK
420
421static void tb_invalidate_check(unsigned long address)
422{
423 TranslationBlock *tb;
424 int i;
425 address &= TARGET_PAGE_MASK;
426 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
427 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
428 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
429 address >= tb->pc + tb->size)) {
430 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
431 address, tb->pc, tb->size);
432 }
433 }
434 }
435}
436
437/* verify that all the pages have correct rights for code */
438static void tb_page_check(void)
439{
440 TranslationBlock *tb;
441 int i, flags1, flags2;
442
443 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
444 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
445 flags1 = page_get_flags(tb->pc);
446 flags2 = page_get_flags(tb->pc + tb->size - 1);
447 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
448 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
449 tb->pc, tb->size, flags1, flags2);
450 }
451 }
452 }
453}
454
bellardd4e81642003-05-25 16:46:15 +0000455void tb_jmp_check(TranslationBlock *tb)
456{
457 TranslationBlock *tb1;
458 unsigned int n1;
459
460 /* suppress any remaining jumps to this TB */
461 tb1 = tb->jmp_first;
462 for(;;) {
463 n1 = (long)tb1 & 3;
464 tb1 = (TranslationBlock *)((long)tb1 & ~3);
465 if (n1 == 2)
466 break;
467 tb1 = tb1->jmp_next[n1];
468 }
469 /* check end of list */
470 if (tb1 != tb) {
471 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
472 }
473}
474
bellardfd6ce8f2003-05-14 19:00:11 +0000475#endif
476
477/* invalidate one TB */
478static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
479 int next_offset)
480{
481 TranslationBlock *tb1;
482 for(;;) {
483 tb1 = *ptb;
484 if (tb1 == tb) {
485 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
486 break;
487 }
488 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
489 }
490}
491
bellard9fa3e852004-01-04 18:06:42 +0000492static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
493{
494 TranslationBlock *tb1;
495 unsigned int n1;
496
497 for(;;) {
498 tb1 = *ptb;
499 n1 = (long)tb1 & 3;
500 tb1 = (TranslationBlock *)((long)tb1 & ~3);
501 if (tb1 == tb) {
502 *ptb = tb1->page_next[n1];
503 break;
504 }
505 ptb = &tb1->page_next[n1];
506 }
507}
508
bellardd4e81642003-05-25 16:46:15 +0000509static inline void tb_jmp_remove(TranslationBlock *tb, int n)
510{
511 TranslationBlock *tb1, **ptb;
512 unsigned int n1;
513
514 ptb = &tb->jmp_next[n];
515 tb1 = *ptb;
516 if (tb1) {
517 /* find tb(n) in circular list */
518 for(;;) {
519 tb1 = *ptb;
520 n1 = (long)tb1 & 3;
521 tb1 = (TranslationBlock *)((long)tb1 & ~3);
522 if (n1 == n && tb1 == tb)
523 break;
524 if (n1 == 2) {
525 ptb = &tb1->jmp_first;
526 } else {
527 ptb = &tb1->jmp_next[n1];
528 }
529 }
530 /* now we can suppress tb(n) from the list */
531 *ptb = tb->jmp_next[n];
532
533 tb->jmp_next[n] = NULL;
534 }
535}
536
537/* reset the jump entry 'n' of a TB so that it is not chained to
538 another TB */
539static inline void tb_reset_jump(TranslationBlock *tb, int n)
540{
541 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
542}
543
bellard9fa3e852004-01-04 18:06:42 +0000544static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000545{
bellardd4e81642003-05-25 16:46:15 +0000546 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000547 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000548
bellard36bdbe52003-11-19 22:12:02 +0000549 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000550
bellardfd6ce8f2003-05-14 19:00:11 +0000551 /* remove the TB from the hash list */
552 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000553 ptb = &tb_hash[h];
554 for(;;) {
555 tb1 = *ptb;
556 /* NOTE: the TB is not necessarily linked in the hash. It
557 indicates that it is not currently used */
558 if (tb1 == NULL)
559 return;
560 if (tb1 == tb) {
561 *ptb = tb1->hash_next;
562 break;
563 }
564 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000565 }
bellardd4e81642003-05-25 16:46:15 +0000566
567 /* suppress this TB from the two jump lists */
568 tb_jmp_remove(tb, 0);
569 tb_jmp_remove(tb, 1);
570
571 /* suppress any remaining jumps to this TB */
572 tb1 = tb->jmp_first;
573 for(;;) {
574 n1 = (long)tb1 & 3;
575 if (n1 == 2)
576 break;
577 tb1 = (TranslationBlock *)((long)tb1 & ~3);
578 tb2 = tb1->jmp_next[n1];
579 tb_reset_jump(tb1, n1);
580 tb1->jmp_next[n1] = NULL;
581 tb1 = tb2;
582 }
583 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000584}
585
bellard9fa3e852004-01-04 18:06:42 +0000586static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000587{
bellardfd6ce8f2003-05-14 19:00:11 +0000588 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000589 unsigned int h;
590 target_ulong phys_pc;
591
592 /* remove the TB from the hash list */
593 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
594 h = tb_phys_hash_func(phys_pc);
595 tb_remove(&tb_phys_hash[h], tb,
596 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000597
bellard9fa3e852004-01-04 18:06:42 +0000598 /* remove the TB from the page list */
599 if (tb->page_addr[0] != page_addr) {
600 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
601 tb_page_remove(&p->first_tb, tb);
602 invalidate_page_bitmap(p);
603 }
604 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
605 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
606 tb_page_remove(&p->first_tb, tb);
607 invalidate_page_bitmap(p);
608 }
609
610 tb_invalidate(tb);
bellarde3db7222005-01-26 22:00:47 +0000611 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000612}
613
614static inline void set_bits(uint8_t *tab, int start, int len)
615{
616 int end, mask, end1;
617
618 end = start + len;
619 tab += start >> 3;
620 mask = 0xff << (start & 7);
621 if ((start & ~7) == (end & ~7)) {
622 if (start < end) {
623 mask &= ~(0xff << (end & 7));
624 *tab |= mask;
625 }
626 } else {
627 *tab++ |= mask;
628 start = (start + 8) & ~7;
629 end1 = end & ~7;
630 while (start < end1) {
631 *tab++ = 0xff;
632 start += 8;
633 }
634 if (start < end) {
635 mask = ~(0xff << (end & 7));
636 *tab |= mask;
637 }
638 }
639}
640
641static void build_page_bitmap(PageDesc *p)
642{
643 int n, tb_start, tb_end;
644 TranslationBlock *tb;
645
bellard59817cc2004-02-16 22:01:13 +0000646 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000647 if (!p->code_bitmap)
648 return;
649 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
650
651 tb = p->first_tb;
652 while (tb != NULL) {
653 n = (long)tb & 3;
654 tb = (TranslationBlock *)((long)tb & ~3);
655 /* NOTE: this is subtle as a TB may span two physical pages */
656 if (n == 0) {
657 /* NOTE: tb_end may be after the end of the page, but
658 it is not a problem */
659 tb_start = tb->pc & ~TARGET_PAGE_MASK;
660 tb_end = tb_start + tb->size;
661 if (tb_end > TARGET_PAGE_SIZE)
662 tb_end = TARGET_PAGE_SIZE;
663 } else {
664 tb_start = 0;
665 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
666 }
667 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
668 tb = tb->page_next[n];
669 }
670}
671
bellardd720b932004-04-25 17:57:43 +0000672#ifdef TARGET_HAS_PRECISE_SMC
673
674static void tb_gen_code(CPUState *env,
675 target_ulong pc, target_ulong cs_base, int flags,
676 int cflags)
677{
678 TranslationBlock *tb;
679 uint8_t *tc_ptr;
680 target_ulong phys_pc, phys_page2, virt_page2;
681 int code_gen_size;
682
bellardc27004e2005-01-03 23:35:10 +0000683 phys_pc = get_phys_addr_code(env, pc);
684 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000685 if (!tb) {
686 /* flush must be done */
687 tb_flush(env);
688 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000689 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000690 }
691 tc_ptr = code_gen_ptr;
692 tb->tc_ptr = tc_ptr;
693 tb->cs_base = cs_base;
694 tb->flags = flags;
695 tb->cflags = cflags;
696 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
697 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
698
699 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000700 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000701 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000702 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000703 phys_page2 = get_phys_addr_code(env, virt_page2);
704 }
705 tb_link_phys(tb, phys_pc, phys_page2);
706}
707#endif
708
bellard9fa3e852004-01-04 18:06:42 +0000709/* invalidate all TBs which intersect with the target physical page
710 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000711 the same physical page. 'is_cpu_write_access' should be true if called
712 from a real cpu write access: the virtual CPU will exit the current
713 TB if code is modified inside this TB. */
714void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
715 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000716{
bellardd720b932004-04-25 17:57:43 +0000717 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000718 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000719 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000720 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000721 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000722 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000723
724 p = page_find(start >> TARGET_PAGE_BITS);
725 if (!p)
726 return;
727 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000728 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
729 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000730 /* build code bitmap */
731 build_page_bitmap(p);
732 }
733
734 /* we remove all the TBs in the range [start, end[ */
735 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000736 current_tb_not_found = is_cpu_write_access;
737 current_tb_modified = 0;
738 current_tb = NULL; /* avoid warning */
739 current_pc = 0; /* avoid warning */
740 current_cs_base = 0; /* avoid warning */
741 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000742 tb = p->first_tb;
743 while (tb != NULL) {
744 n = (long)tb & 3;
745 tb = (TranslationBlock *)((long)tb & ~3);
746 tb_next = tb->page_next[n];
747 /* NOTE: this is subtle as a TB may span two physical pages */
748 if (n == 0) {
749 /* NOTE: tb_end may be after the end of the page, but
750 it is not a problem */
751 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
752 tb_end = tb_start + tb->size;
753 } else {
754 tb_start = tb->page_addr[1];
755 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
756 }
757 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000758#ifdef TARGET_HAS_PRECISE_SMC
759 if (current_tb_not_found) {
760 current_tb_not_found = 0;
761 current_tb = NULL;
762 if (env->mem_write_pc) {
763 /* now we have a real cpu fault */
764 current_tb = tb_find_pc(env->mem_write_pc);
765 }
766 }
767 if (current_tb == tb &&
768 !(current_tb->cflags & CF_SINGLE_INSN)) {
769 /* If we are modifying the current TB, we must stop
770 its execution. We could be more precise by checking
771 that the modification is after the current PC, but it
772 would require a specialized function to partially
773 restore the CPU state */
774
775 current_tb_modified = 1;
776 cpu_restore_state(current_tb, env,
777 env->mem_write_pc, NULL);
778#if defined(TARGET_I386)
779 current_flags = env->hflags;
780 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
781 current_cs_base = (target_ulong)env->segs[R_CS].base;
782 current_pc = current_cs_base + env->eip;
783#else
784#error unsupported CPU
785#endif
786 }
787#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000788 saved_tb = env->current_tb;
789 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000790 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000791 env->current_tb = saved_tb;
792 if (env->interrupt_request && env->current_tb)
793 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000794 }
795 tb = tb_next;
796 }
797#if !defined(CONFIG_USER_ONLY)
798 /* if no code remaining, no need to continue to use slow writes */
799 if (!p->first_tb) {
800 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000801 if (is_cpu_write_access) {
802 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
803 }
804 }
805#endif
806#ifdef TARGET_HAS_PRECISE_SMC
807 if (current_tb_modified) {
808 /* we generate a block containing just the instruction
809 modifying the memory. It will ensure that it cannot modify
810 itself */
bellardea1c1802004-06-14 18:56:36 +0000811 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000812 tb_gen_code(env, current_pc, current_cs_base, current_flags,
813 CF_SINGLE_INSN);
814 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000815 }
816#endif
817}
818
819/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000820static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000821{
822 PageDesc *p;
823 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000824#if 0
bellarda4193c82004-06-03 14:01:43 +0000825 if (1) {
826 if (loglevel) {
827 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
828 cpu_single_env->mem_write_vaddr, len,
829 cpu_single_env->eip,
830 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
831 }
bellard59817cc2004-02-16 22:01:13 +0000832 }
833#endif
bellard9fa3e852004-01-04 18:06:42 +0000834 p = page_find(start >> TARGET_PAGE_BITS);
835 if (!p)
836 return;
837 if (p->code_bitmap) {
838 offset = start & ~TARGET_PAGE_MASK;
839 b = p->code_bitmap[offset >> 3] >> (offset & 7);
840 if (b & ((1 << len) - 1))
841 goto do_invalidate;
842 } else {
843 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000844 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000845 }
846}
847
bellard9fa3e852004-01-04 18:06:42 +0000848#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000849static void tb_invalidate_phys_page(target_ulong addr,
850 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000851{
bellardd720b932004-04-25 17:57:43 +0000852 int n, current_flags, current_tb_modified;
853 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000854 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000855 TranslationBlock *tb, *current_tb;
856#ifdef TARGET_HAS_PRECISE_SMC
857 CPUState *env = cpu_single_env;
858#endif
bellard9fa3e852004-01-04 18:06:42 +0000859
860 addr &= TARGET_PAGE_MASK;
861 p = page_find(addr >> TARGET_PAGE_BITS);
862 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000863 return;
864 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000865 current_tb_modified = 0;
866 current_tb = NULL;
867 current_pc = 0; /* avoid warning */
868 current_cs_base = 0; /* avoid warning */
869 current_flags = 0; /* avoid warning */
870#ifdef TARGET_HAS_PRECISE_SMC
871 if (tb && pc != 0) {
872 current_tb = tb_find_pc(pc);
873 }
874#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000875 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000876 n = (long)tb & 3;
877 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000878#ifdef TARGET_HAS_PRECISE_SMC
879 if (current_tb == tb &&
880 !(current_tb->cflags & CF_SINGLE_INSN)) {
881 /* If we are modifying the current TB, we must stop
882 its execution. We could be more precise by checking
883 that the modification is after the current PC, but it
884 would require a specialized function to partially
885 restore the CPU state */
886
887 current_tb_modified = 1;
888 cpu_restore_state(current_tb, env, pc, puc);
889#if defined(TARGET_I386)
890 current_flags = env->hflags;
891 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
892 current_cs_base = (target_ulong)env->segs[R_CS].base;
893 current_pc = current_cs_base + env->eip;
894#else
895#error unsupported CPU
896#endif
897 }
898#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000899 tb_phys_invalidate(tb, addr);
900 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000901 }
902 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000903#ifdef TARGET_HAS_PRECISE_SMC
904 if (current_tb_modified) {
905 /* we generate a block containing just the instruction
906 modifying the memory. It will ensure that it cannot modify
907 itself */
bellardea1c1802004-06-14 18:56:36 +0000908 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000909 tb_gen_code(env, current_pc, current_cs_base, current_flags,
910 CF_SINGLE_INSN);
911 cpu_resume_from_signal(env, puc);
912 }
913#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000914}
bellard9fa3e852004-01-04 18:06:42 +0000915#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000916
917/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000918static inline void tb_alloc_page(TranslationBlock *tb,
919 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000920{
921 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000922 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000923
bellard9fa3e852004-01-04 18:06:42 +0000924 tb->page_addr[n] = page_addr;
925 p = page_find(page_addr >> TARGET_PAGE_BITS);
926 tb->page_next[n] = p->first_tb;
927 last_first_tb = p->first_tb;
928 p->first_tb = (TranslationBlock *)((long)tb | n);
929 invalidate_page_bitmap(p);
930
bellard107db442004-06-22 18:48:46 +0000931#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000932
bellard9fa3e852004-01-04 18:06:42 +0000933#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000934 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000935 unsigned long host_start, host_end, addr;
936 int prot;
937
bellardfd6ce8f2003-05-14 19:00:11 +0000938 /* force the host page as non writable (writes will have a
939 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000940 host_start = page_addr & qemu_host_page_mask;
941 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000942 prot = 0;
943 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
944 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000945 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000946 (prot & PAGE_BITS) & ~PAGE_WRITE);
947#ifdef DEBUG_TB_INVALIDATE
948 printf("protecting code page: 0x%08lx\n",
949 host_start);
950#endif
951 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000952 }
bellard9fa3e852004-01-04 18:06:42 +0000953#else
954 /* if some code is already present, then the pages are already
955 protected. So we handle the case where only the first TB is
956 allocated in a physical page */
957 if (!last_first_tb) {
958 target_ulong virt_addr;
959
960 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
961 tlb_protect_code(cpu_single_env, virt_addr);
962 }
963#endif
bellardd720b932004-04-25 17:57:43 +0000964
965#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000966}
967
968/* Allocate a new translation block. Flush the translation buffer if
969 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000970TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000971{
972 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000973
974 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
975 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000976 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000977 tb = &tbs[nb_tbs++];
978 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000979 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000980 return tb;
981}
982
bellard9fa3e852004-01-04 18:06:42 +0000983/* add a new TB and link it to the physical page tables. phys_page2 is
984 (-1) to indicate that only one page contains the TB. */
985void tb_link_phys(TranslationBlock *tb,
986 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000987{
bellard9fa3e852004-01-04 18:06:42 +0000988 unsigned int h;
989 TranslationBlock **ptb;
990
991 /* add in the physical hash table */
992 h = tb_phys_hash_func(phys_pc);
993 ptb = &tb_phys_hash[h];
994 tb->phys_hash_next = *ptb;
995 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000996
997 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000998 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
999 if (phys_page2 != -1)
1000 tb_alloc_page(tb, 1, phys_page2);
1001 else
1002 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +00001003#ifdef DEBUG_TB_CHECK
1004 tb_page_check();
1005#endif
bellard9fa3e852004-01-04 18:06:42 +00001006}
1007
1008/* link the tb with the other TBs */
1009void tb_link(TranslationBlock *tb)
1010{
1011#if !defined(CONFIG_USER_ONLY)
1012 {
1013 VirtPageDesc *vp;
1014 target_ulong addr;
1015
1016 /* save the code memory mappings (needed to invalidate the code) */
1017 addr = tb->pc & TARGET_PAGE_MASK;
bellard90f18422005-07-24 10:17:31 +00001018 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard98857882004-01-18 21:52:14 +00001019#ifdef DEBUG_TLB_CHECK
1020 if (vp->valid_tag == virt_valid_tag &&
1021 vp->phys_addr != tb->page_addr[0]) {
1022 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
1023 addr, tb->page_addr[0], vp->phys_addr);
1024 }
1025#endif
bellard9fa3e852004-01-04 18:06:42 +00001026 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +00001027 if (vp->valid_tag != virt_valid_tag) {
1028 vp->valid_tag = virt_valid_tag;
1029#if !defined(CONFIG_SOFTMMU)
1030 vp->prot = 0;
1031#endif
1032 }
bellard9fa3e852004-01-04 18:06:42 +00001033
1034 if (tb->page_addr[1] != -1) {
1035 addr += TARGET_PAGE_SIZE;
bellard90f18422005-07-24 10:17:31 +00001036 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard98857882004-01-18 21:52:14 +00001037#ifdef DEBUG_TLB_CHECK
1038 if (vp->valid_tag == virt_valid_tag &&
1039 vp->phys_addr != tb->page_addr[1]) {
1040 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
1041 addr, tb->page_addr[1], vp->phys_addr);
1042 }
1043#endif
bellard9fa3e852004-01-04 18:06:42 +00001044 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +00001045 if (vp->valid_tag != virt_valid_tag) {
1046 vp->valid_tag = virt_valid_tag;
1047#if !defined(CONFIG_SOFTMMU)
1048 vp->prot = 0;
1049#endif
1050 }
bellard9fa3e852004-01-04 18:06:42 +00001051 }
1052 }
1053#endif
1054
bellardd4e81642003-05-25 16:46:15 +00001055 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1056 tb->jmp_next[0] = NULL;
1057 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +00001058#ifdef USE_CODE_COPY
1059 tb->cflags &= ~CF_FP_USED;
1060 if (tb->cflags & CF_TB_FP_USED)
1061 tb->cflags |= CF_FP_USED;
1062#endif
bellardd4e81642003-05-25 16:46:15 +00001063
1064 /* init original jump addresses */
1065 if (tb->tb_next_offset[0] != 0xffff)
1066 tb_reset_jump(tb, 0);
1067 if (tb->tb_next_offset[1] != 0xffff)
1068 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +00001069}
1070
bellarda513fe12003-05-27 23:29:48 +00001071/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1072 tb[1].tc_ptr. Return NULL if not found */
1073TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1074{
1075 int m_min, m_max, m;
1076 unsigned long v;
1077 TranslationBlock *tb;
1078
1079 if (nb_tbs <= 0)
1080 return NULL;
1081 if (tc_ptr < (unsigned long)code_gen_buffer ||
1082 tc_ptr >= (unsigned long)code_gen_ptr)
1083 return NULL;
1084 /* binary search (cf Knuth) */
1085 m_min = 0;
1086 m_max = nb_tbs - 1;
1087 while (m_min <= m_max) {
1088 m = (m_min + m_max) >> 1;
1089 tb = &tbs[m];
1090 v = (unsigned long)tb->tc_ptr;
1091 if (v == tc_ptr)
1092 return tb;
1093 else if (tc_ptr < v) {
1094 m_max = m - 1;
1095 } else {
1096 m_min = m + 1;
1097 }
1098 }
1099 return &tbs[m_max];
1100}
bellard75012672003-06-21 13:11:07 +00001101
bellardea041c02003-06-25 16:16:50 +00001102static void tb_reset_jump_recursive(TranslationBlock *tb);
1103
1104static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1105{
1106 TranslationBlock *tb1, *tb_next, **ptb;
1107 unsigned int n1;
1108
1109 tb1 = tb->jmp_next[n];
1110 if (tb1 != NULL) {
1111 /* find head of list */
1112 for(;;) {
1113 n1 = (long)tb1 & 3;
1114 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1115 if (n1 == 2)
1116 break;
1117 tb1 = tb1->jmp_next[n1];
1118 }
1119 /* we are now sure now that tb jumps to tb1 */
1120 tb_next = tb1;
1121
1122 /* remove tb from the jmp_first list */
1123 ptb = &tb_next->jmp_first;
1124 for(;;) {
1125 tb1 = *ptb;
1126 n1 = (long)tb1 & 3;
1127 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1128 if (n1 == n && tb1 == tb)
1129 break;
1130 ptb = &tb1->jmp_next[n1];
1131 }
1132 *ptb = tb->jmp_next[n];
1133 tb->jmp_next[n] = NULL;
1134
1135 /* suppress the jump to next tb in generated code */
1136 tb_reset_jump(tb, n);
1137
bellard01243112004-01-04 15:48:17 +00001138 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001139 tb_reset_jump_recursive(tb_next);
1140 }
1141}
1142
1143static void tb_reset_jump_recursive(TranslationBlock *tb)
1144{
1145 tb_reset_jump_recursive2(tb, 0);
1146 tb_reset_jump_recursive2(tb, 1);
1147}
1148
bellard1fddef42005-04-17 19:16:13 +00001149#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001150static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1151{
1152 target_ulong phys_addr;
1153
1154 phys_addr = cpu_get_phys_page_debug(env, pc);
1155 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1156}
bellardc27004e2005-01-03 23:35:10 +00001157#endif
bellardd720b932004-04-25 17:57:43 +00001158
bellardc33a3462003-07-29 20:50:33 +00001159/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1160 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001161int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001162{
bellard1fddef42005-04-17 19:16:13 +00001163#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001164 int i;
bellardd720b932004-04-25 17:57:43 +00001165
bellard4c3a88a2003-07-26 12:06:08 +00001166 for(i = 0; i < env->nb_breakpoints; i++) {
1167 if (env->breakpoints[i] == pc)
1168 return 0;
1169 }
1170
1171 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1172 return -1;
1173 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001174
1175 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001176 return 0;
1177#else
1178 return -1;
1179#endif
1180}
1181
1182/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001183int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001184{
bellard1fddef42005-04-17 19:16:13 +00001185#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001186 int i;
1187 for(i = 0; i < env->nb_breakpoints; i++) {
1188 if (env->breakpoints[i] == pc)
1189 goto found;
1190 }
1191 return -1;
1192 found:
bellard4c3a88a2003-07-26 12:06:08 +00001193 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001194 if (i < env->nb_breakpoints)
1195 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001196
1197 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001198 return 0;
1199#else
1200 return -1;
1201#endif
1202}
1203
bellardc33a3462003-07-29 20:50:33 +00001204/* enable or disable single step mode. EXCP_DEBUG is returned by the
1205 CPU loop after each instruction */
1206void cpu_single_step(CPUState *env, int enabled)
1207{
bellard1fddef42005-04-17 19:16:13 +00001208#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001209 if (env->singlestep_enabled != enabled) {
1210 env->singlestep_enabled = enabled;
1211 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001212 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001213 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001214 }
1215#endif
1216}
1217
bellard34865132003-10-05 14:28:56 +00001218/* enable or disable low levels log */
1219void cpu_set_log(int log_flags)
1220{
1221 loglevel = log_flags;
1222 if (loglevel && !logfile) {
1223 logfile = fopen(logfilename, "w");
1224 if (!logfile) {
1225 perror(logfilename);
1226 _exit(1);
1227 }
bellard9fa3e852004-01-04 18:06:42 +00001228#if !defined(CONFIG_SOFTMMU)
1229 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1230 {
1231 static uint8_t logfile_buf[4096];
1232 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1233 }
1234#else
bellard34865132003-10-05 14:28:56 +00001235 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001236#endif
bellard34865132003-10-05 14:28:56 +00001237 }
1238}
1239
1240void cpu_set_log_filename(const char *filename)
1241{
1242 logfilename = strdup(filename);
1243}
bellardc33a3462003-07-29 20:50:33 +00001244
bellard01243112004-01-04 15:48:17 +00001245/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001246void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001247{
1248 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001249 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001250
bellard68a79312003-06-30 13:12:32 +00001251 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001252 /* if the cpu is currently executing code, we must unlink it and
1253 all the potentially executing TB */
1254 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001255 if (tb && !testandset(&interrupt_lock)) {
1256 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001257 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001258 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001259 }
1260}
1261
bellardb54ad042004-05-20 13:42:52 +00001262void cpu_reset_interrupt(CPUState *env, int mask)
1263{
1264 env->interrupt_request &= ~mask;
1265}
1266
bellardf193c792004-03-21 17:06:25 +00001267CPULogItem cpu_log_items[] = {
1268 { CPU_LOG_TB_OUT_ASM, "out_asm",
1269 "show generated host assembly code for each compiled TB" },
1270 { CPU_LOG_TB_IN_ASM, "in_asm",
1271 "show target assembly code for each compiled TB" },
1272 { CPU_LOG_TB_OP, "op",
1273 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1274#ifdef TARGET_I386
1275 { CPU_LOG_TB_OP_OPT, "op_opt",
1276 "show micro ops after optimization for each compiled TB" },
1277#endif
1278 { CPU_LOG_INT, "int",
1279 "show interrupts/exceptions in short format" },
1280 { CPU_LOG_EXEC, "exec",
1281 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001282 { CPU_LOG_TB_CPU, "cpu",
1283 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001284#ifdef TARGET_I386
1285 { CPU_LOG_PCALL, "pcall",
1286 "show protected mode far calls/returns/exceptions" },
1287#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001288#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001289 { CPU_LOG_IOPORT, "ioport",
1290 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001291#endif
bellardf193c792004-03-21 17:06:25 +00001292 { 0, NULL, NULL },
1293};
1294
1295static int cmp1(const char *s1, int n, const char *s2)
1296{
1297 if (strlen(s2) != n)
1298 return 0;
1299 return memcmp(s1, s2, n) == 0;
1300}
1301
1302/* takes a comma separated list of log masks. Return 0 if error. */
1303int cpu_str_to_log_mask(const char *str)
1304{
1305 CPULogItem *item;
1306 int mask;
1307 const char *p, *p1;
1308
1309 p = str;
1310 mask = 0;
1311 for(;;) {
1312 p1 = strchr(p, ',');
1313 if (!p1)
1314 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001315 if(cmp1(p,p1-p,"all")) {
1316 for(item = cpu_log_items; item->mask != 0; item++) {
1317 mask |= item->mask;
1318 }
1319 } else {
bellardf193c792004-03-21 17:06:25 +00001320 for(item = cpu_log_items; item->mask != 0; item++) {
1321 if (cmp1(p, p1 - p, item->name))
1322 goto found;
1323 }
1324 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001325 }
bellardf193c792004-03-21 17:06:25 +00001326 found:
1327 mask |= item->mask;
1328 if (*p1 != ',')
1329 break;
1330 p = p1 + 1;
1331 }
1332 return mask;
1333}
bellardea041c02003-06-25 16:16:50 +00001334
bellard75012672003-06-21 13:11:07 +00001335void cpu_abort(CPUState *env, const char *fmt, ...)
1336{
1337 va_list ap;
1338
1339 va_start(ap, fmt);
1340 fprintf(stderr, "qemu: fatal: ");
1341 vfprintf(stderr, fmt, ap);
1342 fprintf(stderr, "\n");
1343#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001344 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1345#else
1346 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001347#endif
1348 va_end(ap);
1349 abort();
1350}
1351
bellard01243112004-01-04 15:48:17 +00001352#if !defined(CONFIG_USER_ONLY)
1353
bellardee8b7022004-02-03 23:35:10 +00001354/* NOTE: if flush_global is true, also flush global entries (not
1355 implemented yet) */
1356void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001357{
bellard33417e72003-08-10 21:47:01 +00001358 int i;
bellard01243112004-01-04 15:48:17 +00001359
bellard9fa3e852004-01-04 18:06:42 +00001360#if defined(DEBUG_TLB)
1361 printf("tlb_flush:\n");
1362#endif
bellard01243112004-01-04 15:48:17 +00001363 /* must reset current TB so that interrupts cannot modify the
1364 links while we are modifying them */
1365 env->current_tb = NULL;
1366
bellard33417e72003-08-10 21:47:01 +00001367 for(i = 0; i < CPU_TLB_SIZE; i++) {
1368 env->tlb_read[0][i].address = -1;
1369 env->tlb_write[0][i].address = -1;
1370 env->tlb_read[1][i].address = -1;
1371 env->tlb_write[1][i].address = -1;
1372 }
bellard9fa3e852004-01-04 18:06:42 +00001373
1374 virt_page_flush();
bellard8a8a6082004-10-03 13:36:49 +00001375 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001376
1377#if !defined(CONFIG_SOFTMMU)
1378 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1379#endif
bellard0a962c02005-02-10 22:00:27 +00001380#ifdef USE_KQEMU
1381 if (env->kqemu_enabled) {
1382 kqemu_flush(env, flush_global);
1383 }
1384#endif
bellarde3db7222005-01-26 22:00:47 +00001385 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001386}
1387
bellard274da6b2004-05-20 21:56:27 +00001388static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001389{
1390 if (addr == (tlb_entry->address &
1391 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1392 tlb_entry->address = -1;
1393}
1394
bellard2e126692004-04-25 21:28:44 +00001395void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001396{
bellard9fa3e852004-01-04 18:06:42 +00001397 int i, n;
1398 VirtPageDesc *vp;
1399 PageDesc *p;
1400 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001401
bellard9fa3e852004-01-04 18:06:42 +00001402#if defined(DEBUG_TLB)
1403 printf("tlb_flush_page: 0x%08x\n", addr);
1404#endif
bellard01243112004-01-04 15:48:17 +00001405 /* must reset current TB so that interrupts cannot modify the
1406 links while we are modifying them */
1407 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001408
bellard61382a52003-10-27 21:22:23 +00001409 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001410 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001411 tlb_flush_entry(&env->tlb_read[0][i], addr);
1412 tlb_flush_entry(&env->tlb_write[0][i], addr);
1413 tlb_flush_entry(&env->tlb_read[1][i], addr);
1414 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001415
bellard9fa3e852004-01-04 18:06:42 +00001416 /* remove from the virtual pc hash table all the TB at this
1417 virtual address */
1418
1419 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1420 if (vp && vp->valid_tag == virt_valid_tag) {
1421 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1422 if (p) {
1423 /* we remove all the links to the TBs in this virtual page */
1424 tb = p->first_tb;
1425 while (tb != NULL) {
1426 n = (long)tb & 3;
1427 tb = (TranslationBlock *)((long)tb & ~3);
1428 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1429 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1430 tb_invalidate(tb);
1431 }
1432 tb = tb->page_next[n];
1433 }
1434 }
bellard98857882004-01-18 21:52:14 +00001435 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001436 }
1437
bellard01243112004-01-04 15:48:17 +00001438#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001439 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001440 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001441#endif
bellard0a962c02005-02-10 22:00:27 +00001442#ifdef USE_KQEMU
1443 if (env->kqemu_enabled) {
1444 kqemu_flush_page(env, addr);
1445 }
1446#endif
bellard9fa3e852004-01-04 18:06:42 +00001447}
1448
bellard4f2ac232004-04-26 19:44:02 +00001449static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001450{
1451 if (addr == (tlb_entry->address &
1452 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001453 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1454 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001455 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001456 }
bellard61382a52003-10-27 21:22:23 +00001457}
1458
bellard9fa3e852004-01-04 18:06:42 +00001459/* update the TLBs so that writes to code in the virtual page 'addr'
1460 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001461static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001462{
bellard61382a52003-10-27 21:22:23 +00001463 int i;
1464
1465 addr &= TARGET_PAGE_MASK;
1466 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001467 tlb_protect_code1(&env->tlb_write[0][i], addr);
1468 tlb_protect_code1(&env->tlb_write[1][i], addr);
1469#if !defined(CONFIG_SOFTMMU)
1470 /* NOTE: as we generated the code for this page, it is already at
1471 least readable */
1472 if (addr < MMAP_AREA_END)
1473 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1474#endif
1475}
1476
bellard9fa3e852004-01-04 18:06:42 +00001477static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001478 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001479{
1480 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1481 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001482 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001483 }
1484}
1485
1486/* update the TLB so that writes in physical page 'phys_addr' are no longer
1487 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001488static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001489{
1490 int i;
1491
1492 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001493 phys_addr += (long)phys_ram_base;
1494 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1495 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1496 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1497}
1498
1499static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1500 unsigned long start, unsigned long length)
1501{
1502 unsigned long addr;
1503 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1504 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1505 if ((addr - start) < length) {
1506 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1507 }
1508 }
1509}
1510
bellard0a962c02005-02-10 22:00:27 +00001511void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
1512 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001513{
1514 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001515 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001516 int i, mask, len;
1517 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001518
1519 start &= TARGET_PAGE_MASK;
1520 end = TARGET_PAGE_ALIGN(end);
1521
1522 length = end - start;
1523 if (length == 0)
1524 return;
bellard0a962c02005-02-10 22:00:27 +00001525 mask = ~dirty_flags;
1526 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1527 len = length >> TARGET_PAGE_BITS;
1528 for(i = 0; i < len; i++)
1529 p[i] &= mask;
bellard1ccde1c2004-02-06 19:46:14 +00001530
1531 env = cpu_single_env;
1532 /* we modify the TLB cache so that the dirty bit will be set again
1533 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001534 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001535 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001536 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001537 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001538 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1539
1540#if !defined(CONFIG_SOFTMMU)
1541 /* XXX: this is expensive */
1542 {
1543 VirtPageDesc *p;
1544 int j;
1545 target_ulong addr;
1546
1547 for(i = 0; i < L1_SIZE; i++) {
1548 p = l1_virt_map[i];
1549 if (p) {
1550 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1551 for(j = 0; j < L2_SIZE; j++) {
1552 if (p->valid_tag == virt_valid_tag &&
1553 p->phys_addr >= start && p->phys_addr < end &&
1554 (p->prot & PROT_WRITE)) {
1555 if (addr < MMAP_AREA_END) {
1556 mprotect((void *)addr, TARGET_PAGE_SIZE,
1557 p->prot & ~PROT_WRITE);
1558 }
1559 }
1560 addr += TARGET_PAGE_SIZE;
1561 p++;
1562 }
1563 }
1564 }
1565 }
1566#endif
bellard1ccde1c2004-02-06 19:46:14 +00001567}
1568
1569static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1570 unsigned long start)
1571{
1572 unsigned long addr;
1573 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1574 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1575 if (addr == start) {
1576 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1577 }
1578 }
1579}
1580
1581/* update the TLB corresponding to virtual page vaddr and phys addr
1582 addr so that it is no longer dirty */
1583static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1584{
1585 CPUState *env = cpu_single_env;
1586 int i;
1587
bellard0a962c02005-02-10 22:00:27 +00001588 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff;
bellard1ccde1c2004-02-06 19:46:14 +00001589
1590 addr &= TARGET_PAGE_MASK;
1591 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1592 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1593 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001594}
1595
bellard59817cc2004-02-16 22:01:13 +00001596/* add a new TLB entry. At most one entry for a given virtual address
1597 is permitted. Return 0 if OK or 2 if the page could not be mapped
1598 (can only happen in non SOFTMMU mode for I/O pages or pages
1599 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001600int tlb_set_page(CPUState *env, target_ulong vaddr,
1601 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001602 int is_user, int is_softmmu)
1603{
bellard92e873b2004-05-21 14:52:29 +00001604 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001605 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001606 TranslationBlock *first_tb;
1607 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001608 target_ulong address;
1609 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001610 int ret;
1611
bellard92e873b2004-05-21 14:52:29 +00001612 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1613 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001614 if (!p) {
1615 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001616 } else {
bellard92e873b2004-05-21 14:52:29 +00001617 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001618 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001619 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1620 /* NOTE: we also allocate the page at this stage */
1621 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1622 first_tb = p1->first_tb;
1623 }
bellard9fa3e852004-01-04 18:06:42 +00001624 }
1625#if defined(DEBUG_TLB)
1626 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1627 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1628#endif
1629
1630 ret = 0;
1631#if !defined(CONFIG_SOFTMMU)
1632 if (is_softmmu)
1633#endif
1634 {
1635 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1636 /* IO memory case */
1637 address = vaddr | pd;
1638 addend = paddr;
1639 } else {
1640 /* standard memory */
1641 address = vaddr;
1642 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1643 }
1644
bellard90f18422005-07-24 10:17:31 +00001645 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001646 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001647 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001648 env->tlb_read[is_user][index].address = address;
1649 env->tlb_read[is_user][index].addend = addend;
1650 } else {
1651 env->tlb_read[is_user][index].address = -1;
1652 env->tlb_read[is_user][index].addend = -1;
1653 }
bellard67b915a2004-03-31 23:37:16 +00001654 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001655 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1656 /* ROM: access is ignored (same as unassigned) */
1657 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001658 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001659 } else
1660 /* XXX: the PowerPC code seems not ready to handle
1661 self modifying code with DCBI */
1662#if defined(TARGET_HAS_SMC) || 1
1663 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001664 /* if code is present, we use a specific memory
1665 handler. It works only for physical memory access */
1666 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001667 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001668 } else
1669#endif
1670 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001671 !cpu_physical_memory_is_dirty(pd)) {
1672 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1673 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001674 } else {
1675 env->tlb_write[is_user][index].address = address;
1676 env->tlb_write[is_user][index].addend = addend;
1677 }
1678 } else {
1679 env->tlb_write[is_user][index].address = -1;
1680 env->tlb_write[is_user][index].addend = -1;
1681 }
1682 }
1683#if !defined(CONFIG_SOFTMMU)
1684 else {
1685 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1686 /* IO access: no mapping is done as it will be handled by the
1687 soft MMU */
1688 if (!(env->hflags & HF_SOFTMMU_MASK))
1689 ret = 2;
1690 } else {
1691 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001692
bellard59817cc2004-02-16 22:01:13 +00001693 if (vaddr >= MMAP_AREA_END) {
1694 ret = 2;
1695 } else {
1696 if (prot & PROT_WRITE) {
1697 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001698#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001699 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001700#endif
bellard59817cc2004-02-16 22:01:13 +00001701 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1702 !cpu_physical_memory_is_dirty(pd))) {
1703 /* ROM: we do as if code was inside */
1704 /* if code is present, we only map as read only and save the
1705 original mapping */
1706 VirtPageDesc *vp;
1707
bellard90f18422005-07-24 10:17:31 +00001708 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001709 vp->phys_addr = pd;
1710 vp->prot = prot;
1711 vp->valid_tag = virt_valid_tag;
1712 prot &= ~PAGE_WRITE;
1713 }
bellard9fa3e852004-01-04 18:06:42 +00001714 }
bellard59817cc2004-02-16 22:01:13 +00001715 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1716 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1717 if (map_addr == MAP_FAILED) {
1718 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1719 paddr, vaddr);
1720 }
bellard9fa3e852004-01-04 18:06:42 +00001721 }
1722 }
1723 }
1724#endif
1725 return ret;
1726}
1727
1728/* called from signal handler: invalidate the code and unprotect the
1729 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001730int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001731{
1732#if !defined(CONFIG_SOFTMMU)
1733 VirtPageDesc *vp;
1734
1735#if defined(DEBUG_TLB)
1736 printf("page_unprotect: addr=0x%08x\n", addr);
1737#endif
1738 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001739
1740 /* if it is not mapped, no need to worry here */
1741 if (addr >= MMAP_AREA_END)
1742 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001743 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1744 if (!vp)
1745 return 0;
1746 /* NOTE: in this case, validate_tag is _not_ tested as it
1747 validates only the code TLB */
1748 if (vp->valid_tag != virt_valid_tag)
1749 return 0;
1750 if (!(vp->prot & PAGE_WRITE))
1751 return 0;
1752#if defined(DEBUG_TLB)
1753 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1754 addr, vp->phys_addr, vp->prot);
1755#endif
bellard59817cc2004-02-16 22:01:13 +00001756 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1757 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1758 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001759 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001760 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001761 /* flush the code inside */
1762 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001763 return 1;
1764#else
1765 return 0;
1766#endif
bellard33417e72003-08-10 21:47:01 +00001767}
1768
bellard01243112004-01-04 15:48:17 +00001769#else
1770
bellardee8b7022004-02-03 23:35:10 +00001771void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001772{
1773}
1774
bellard2e126692004-04-25 21:28:44 +00001775void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001776{
1777}
1778
bellard2e126692004-04-25 21:28:44 +00001779int tlb_set_page(CPUState *env, target_ulong vaddr,
1780 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001781 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001782{
bellard9fa3e852004-01-04 18:06:42 +00001783 return 0;
1784}
bellard33417e72003-08-10 21:47:01 +00001785
bellard9fa3e852004-01-04 18:06:42 +00001786/* dump memory mappings */
1787void page_dump(FILE *f)
1788{
1789 unsigned long start, end;
1790 int i, j, prot, prot1;
1791 PageDesc *p;
1792
1793 fprintf(f, "%-8s %-8s %-8s %s\n",
1794 "start", "end", "size", "prot");
1795 start = -1;
1796 end = -1;
1797 prot = 0;
1798 for(i = 0; i <= L1_SIZE; i++) {
1799 if (i < L1_SIZE)
1800 p = l1_map[i];
1801 else
1802 p = NULL;
1803 for(j = 0;j < L2_SIZE; j++) {
1804 if (!p)
1805 prot1 = 0;
1806 else
1807 prot1 = p[j].flags;
1808 if (prot1 != prot) {
1809 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1810 if (start != -1) {
1811 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1812 start, end, end - start,
1813 prot & PAGE_READ ? 'r' : '-',
1814 prot & PAGE_WRITE ? 'w' : '-',
1815 prot & PAGE_EXEC ? 'x' : '-');
1816 }
1817 if (prot1 != 0)
1818 start = end;
1819 else
1820 start = -1;
1821 prot = prot1;
1822 }
1823 if (!p)
1824 break;
1825 }
bellard33417e72003-08-10 21:47:01 +00001826 }
bellard33417e72003-08-10 21:47:01 +00001827}
1828
bellard9fa3e852004-01-04 18:06:42 +00001829int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001830{
bellard9fa3e852004-01-04 18:06:42 +00001831 PageDesc *p;
1832
1833 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001834 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001835 return 0;
1836 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001837}
1838
bellard9fa3e852004-01-04 18:06:42 +00001839/* modify the flags of a page and invalidate the code if
1840 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1841 depending on PAGE_WRITE */
1842void page_set_flags(unsigned long start, unsigned long end, int flags)
1843{
1844 PageDesc *p;
1845 unsigned long addr;
1846
1847 start = start & TARGET_PAGE_MASK;
1848 end = TARGET_PAGE_ALIGN(end);
1849 if (flags & PAGE_WRITE)
1850 flags |= PAGE_WRITE_ORG;
1851 spin_lock(&tb_lock);
1852 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1853 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1854 /* if the write protection is set, then we invalidate the code
1855 inside */
1856 if (!(p->flags & PAGE_WRITE) &&
1857 (flags & PAGE_WRITE) &&
1858 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001859 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001860 }
1861 p->flags = flags;
1862 }
1863 spin_unlock(&tb_lock);
1864}
1865
1866/* called from signal handler: invalidate the code and unprotect the
1867 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001868int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001869{
1870 unsigned int page_index, prot, pindex;
1871 PageDesc *p, *p1;
1872 unsigned long host_start, host_end, addr;
1873
bellard83fb7ad2004-07-05 21:25:26 +00001874 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001875 page_index = host_start >> TARGET_PAGE_BITS;
1876 p1 = page_find(page_index);
1877 if (!p1)
1878 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001879 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001880 p = p1;
1881 prot = 0;
1882 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1883 prot |= p->flags;
1884 p++;
1885 }
1886 /* if the page was really writable, then we change its
1887 protection back to writable */
1888 if (prot & PAGE_WRITE_ORG) {
1889 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1890 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001891 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001892 (prot & PAGE_BITS) | PAGE_WRITE);
1893 p1[pindex].flags |= PAGE_WRITE;
1894 /* and since the content will be modified, we must invalidate
1895 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001896 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001897#ifdef DEBUG_TB_CHECK
1898 tb_invalidate_check(address);
1899#endif
1900 return 1;
1901 }
1902 }
1903 return 0;
1904}
1905
1906/* call this function when system calls directly modify a memory area */
1907void page_unprotect_range(uint8_t *data, unsigned long data_size)
1908{
1909 unsigned long start, end, addr;
1910
1911 start = (unsigned long)data;
1912 end = start + data_size;
1913 start &= TARGET_PAGE_MASK;
1914 end = TARGET_PAGE_ALIGN(end);
1915 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001916 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001917 }
1918}
1919
bellard1ccde1c2004-02-06 19:46:14 +00001920static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1921{
1922}
bellard9fa3e852004-01-04 18:06:42 +00001923#endif /* defined(CONFIG_USER_ONLY) */
1924
bellard33417e72003-08-10 21:47:01 +00001925/* register physical memory. 'size' must be a multiple of the target
1926 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1927 io memory page */
bellard2e126692004-04-25 21:28:44 +00001928void cpu_register_physical_memory(target_phys_addr_t start_addr,
1929 unsigned long size,
1930 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001931{
1932 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001933 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001934
bellard5fd386f2004-05-23 21:11:22 +00001935 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001936 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001937 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001938 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001939 p->phys_offset = phys_offset;
1940 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001941 phys_offset += TARGET_PAGE_SIZE;
1942 }
1943}
1944
bellarda4193c82004-06-03 14:01:43 +00001945static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001946{
1947 return 0;
1948}
1949
bellarda4193c82004-06-03 14:01:43 +00001950static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001951{
1952}
1953
1954static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1955 unassigned_mem_readb,
1956 unassigned_mem_readb,
1957 unassigned_mem_readb,
1958};
1959
1960static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1961 unassigned_mem_writeb,
1962 unassigned_mem_writeb,
1963 unassigned_mem_writeb,
1964};
1965
bellard9fa3e852004-01-04 18:06:42 +00001966/* self modifying code support in soft mmu mode : writing to a page
1967 containing code comes to these functions */
1968
bellarda4193c82004-06-03 14:01:43 +00001969static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001970{
bellard1ccde1c2004-02-06 19:46:14 +00001971 unsigned long phys_addr;
1972
bellard274da6b2004-05-20 21:56:27 +00001973 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001974#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001975 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001976#endif
bellardc27004e2005-01-03 23:35:10 +00001977 stb_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00001978 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00001979}
1980
bellarda4193c82004-06-03 14:01:43 +00001981static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001982{
bellard1ccde1c2004-02-06 19:46:14 +00001983 unsigned long phys_addr;
1984
bellard274da6b2004-05-20 21:56:27 +00001985 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001986#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001987 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001988#endif
bellardc27004e2005-01-03 23:35:10 +00001989 stw_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00001990 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00001991}
1992
bellarda4193c82004-06-03 14:01:43 +00001993static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001994{
bellard1ccde1c2004-02-06 19:46:14 +00001995 unsigned long phys_addr;
1996
bellard274da6b2004-05-20 21:56:27 +00001997 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001998#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001999 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00002000#endif
bellardc27004e2005-01-03 23:35:10 +00002001 stl_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00002002 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00002003}
2004
2005static CPUReadMemoryFunc *code_mem_read[3] = {
2006 NULL, /* never used */
2007 NULL, /* never used */
2008 NULL, /* never used */
2009};
2010
2011static CPUWriteMemoryFunc *code_mem_write[3] = {
2012 code_mem_writeb,
2013 code_mem_writew,
2014 code_mem_writel,
2015};
bellard33417e72003-08-10 21:47:01 +00002016
bellarda4193c82004-06-03 14:01:43 +00002017static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002018{
bellardc27004e2005-01-03 23:35:10 +00002019 stb_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00002020 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002021}
2022
bellarda4193c82004-06-03 14:01:43 +00002023static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002024{
bellardc27004e2005-01-03 23:35:10 +00002025 stw_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00002026 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002027}
2028
bellarda4193c82004-06-03 14:01:43 +00002029static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002030{
bellardc27004e2005-01-03 23:35:10 +00002031 stl_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00002032 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002033}
2034
2035static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2036 notdirty_mem_writeb,
2037 notdirty_mem_writew,
2038 notdirty_mem_writel,
2039};
2040
bellard33417e72003-08-10 21:47:01 +00002041static void io_mem_init(void)
2042{
bellarda4193c82004-06-03 14:01:43 +00002043 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
2044 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
2045 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
2046 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002047 io_mem_nb = 5;
2048
2049 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002050 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002051}
2052
2053/* mem_read and mem_write are arrays of functions containing the
2054 function to access byte (index 0), word (index 1) and dword (index
2055 2). All functions must be supplied. If io_index is non zero, the
2056 corresponding io zone is modified. If it is zero, a new io zone is
2057 allocated. The return value can be used with
2058 cpu_register_physical_memory(). (-1) is returned if error. */
2059int cpu_register_io_memory(int io_index,
2060 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002061 CPUWriteMemoryFunc **mem_write,
2062 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002063{
2064 int i;
2065
2066 if (io_index <= 0) {
2067 if (io_index >= IO_MEM_NB_ENTRIES)
2068 return -1;
2069 io_index = io_mem_nb++;
2070 } else {
2071 if (io_index >= IO_MEM_NB_ENTRIES)
2072 return -1;
2073 }
2074
2075 for(i = 0;i < 3; i++) {
2076 io_mem_read[io_index][i] = mem_read[i];
2077 io_mem_write[io_index][i] = mem_write[i];
2078 }
bellarda4193c82004-06-03 14:01:43 +00002079 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002080 return io_index << IO_MEM_SHIFT;
2081}
bellard61382a52003-10-27 21:22:23 +00002082
bellard8926b512004-10-10 15:14:20 +00002083CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2084{
2085 return io_mem_write[io_index >> IO_MEM_SHIFT];
2086}
2087
2088CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2089{
2090 return io_mem_read[io_index >> IO_MEM_SHIFT];
2091}
2092
bellard13eb76e2004-01-24 15:23:36 +00002093/* physical memory access (slow version, mainly for debug) */
2094#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002095void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002096 int len, int is_write)
2097{
2098 int l, flags;
2099 target_ulong page;
2100
2101 while (len > 0) {
2102 page = addr & TARGET_PAGE_MASK;
2103 l = (page + TARGET_PAGE_SIZE) - addr;
2104 if (l > len)
2105 l = len;
2106 flags = page_get_flags(page);
2107 if (!(flags & PAGE_VALID))
2108 return;
2109 if (is_write) {
2110 if (!(flags & PAGE_WRITE))
2111 return;
2112 memcpy((uint8_t *)addr, buf, len);
2113 } else {
2114 if (!(flags & PAGE_READ))
2115 return;
2116 memcpy(buf, (uint8_t *)addr, len);
2117 }
2118 len -= l;
2119 buf += l;
2120 addr += l;
2121 }
2122}
bellard8df1cd02005-01-28 22:37:22 +00002123
2124/* never used */
2125uint32_t ldl_phys(target_phys_addr_t addr)
2126{
2127 return 0;
2128}
2129
2130void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2131{
2132}
2133
2134void stl_phys(target_phys_addr_t addr, uint32_t val)
2135{
2136}
2137
bellard13eb76e2004-01-24 15:23:36 +00002138#else
bellard2e126692004-04-25 21:28:44 +00002139void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002140 int len, int is_write)
2141{
2142 int l, io_index;
2143 uint8_t *ptr;
2144 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002145 target_phys_addr_t page;
2146 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002147 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002148
2149 while (len > 0) {
2150 page = addr & TARGET_PAGE_MASK;
2151 l = (page + TARGET_PAGE_SIZE) - addr;
2152 if (l > len)
2153 l = len;
bellard92e873b2004-05-21 14:52:29 +00002154 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002155 if (!p) {
2156 pd = IO_MEM_UNASSIGNED;
2157 } else {
2158 pd = p->phys_offset;
2159 }
2160
2161 if (is_write) {
2162 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2163 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2164 if (l >= 4 && ((addr & 3) == 0)) {
2165 /* 32 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002166 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002167 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002168 l = 4;
2169 } else if (l >= 2 && ((addr & 1) == 0)) {
2170 /* 16 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002171 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002172 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002173 l = 2;
2174 } else {
2175 /* 8 bit access */
bellardc27004e2005-01-03 23:35:10 +00002176 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002177 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002178 l = 1;
2179 }
2180 } else {
bellardb448f2f2004-02-25 23:24:04 +00002181 unsigned long addr1;
2182 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002183 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002184 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002185 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002186 /* invalidate code */
2187 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2188 /* set dirty bit */
bellard0a962c02005-02-10 22:00:27 +00002189 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
bellard13eb76e2004-01-24 15:23:36 +00002190 }
2191 } else {
2192 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2193 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2194 /* I/O case */
2195 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2196 if (l >= 4 && ((addr & 3) == 0)) {
2197 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002198 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002199 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002200 l = 4;
2201 } else if (l >= 2 && ((addr & 1) == 0)) {
2202 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002203 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002204 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002205 l = 2;
2206 } else {
2207 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002208 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002209 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002210 l = 1;
2211 }
2212 } else {
2213 /* RAM case */
2214 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2215 (addr & ~TARGET_PAGE_MASK);
2216 memcpy(buf, ptr, l);
2217 }
2218 }
2219 len -= l;
2220 buf += l;
2221 addr += l;
2222 }
2223}
bellard8df1cd02005-01-28 22:37:22 +00002224
2225/* warning: addr must be aligned */
2226uint32_t ldl_phys(target_phys_addr_t addr)
2227{
2228 int io_index;
2229 uint8_t *ptr;
2230 uint32_t val;
2231 unsigned long pd;
2232 PhysPageDesc *p;
2233
2234 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2235 if (!p) {
2236 pd = IO_MEM_UNASSIGNED;
2237 } else {
2238 pd = p->phys_offset;
2239 }
2240
2241 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2242 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2243 /* I/O case */
2244 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2245 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2246 } else {
2247 /* RAM case */
2248 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2249 (addr & ~TARGET_PAGE_MASK);
2250 val = ldl_p(ptr);
2251 }
2252 return val;
2253}
2254
2255/* warning: addr must be aligned. The ram page is not masked as dirty
2256 and the code inside is not invalidated. It is useful if the dirty
2257 bits are used to track modified PTEs */
2258void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2259{
2260 int io_index;
2261 uint8_t *ptr;
2262 unsigned long pd;
2263 PhysPageDesc *p;
2264
2265 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2266 if (!p) {
2267 pd = IO_MEM_UNASSIGNED;
2268 } else {
2269 pd = p->phys_offset;
2270 }
2271
2272 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2273 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2274 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2275 } else {
2276 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2277 (addr & ~TARGET_PAGE_MASK);
2278 stl_p(ptr, val);
2279 }
2280}
2281
2282/* warning: addr must be aligned */
2283/* XXX: optimize code invalidation test */
2284void stl_phys(target_phys_addr_t addr, uint32_t val)
2285{
2286 int io_index;
2287 uint8_t *ptr;
2288 unsigned long pd;
2289 PhysPageDesc *p;
2290
2291 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2292 if (!p) {
2293 pd = IO_MEM_UNASSIGNED;
2294 } else {
2295 pd = p->phys_offset;
2296 }
2297
2298 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2299 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2300 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2301 } else {
2302 unsigned long addr1;
2303 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2304 /* RAM case */
2305 ptr = phys_ram_base + addr1;
2306 stl_p(ptr, val);
2307 /* invalidate code */
2308 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2309 /* set dirty bit */
bellard0a962c02005-02-10 22:00:27 +00002310 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
bellard8df1cd02005-01-28 22:37:22 +00002311 }
2312}
2313
bellard13eb76e2004-01-24 15:23:36 +00002314#endif
2315
2316/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002317int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2318 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002319{
2320 int l;
2321 target_ulong page, phys_addr;
2322
2323 while (len > 0) {
2324 page = addr & TARGET_PAGE_MASK;
2325 phys_addr = cpu_get_phys_page_debug(env, page);
2326 /* if no physical page mapped, return an error */
2327 if (phys_addr == -1)
2328 return -1;
2329 l = (page + TARGET_PAGE_SIZE) - addr;
2330 if (l > len)
2331 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002332 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2333 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002334 len -= l;
2335 buf += l;
2336 addr += l;
2337 }
2338 return 0;
2339}
2340
bellarde3db7222005-01-26 22:00:47 +00002341void dump_exec_info(FILE *f,
2342 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2343{
2344 int i, target_code_size, max_target_code_size;
2345 int direct_jmp_count, direct_jmp2_count, cross_page;
2346 TranslationBlock *tb;
2347
2348 target_code_size = 0;
2349 max_target_code_size = 0;
2350 cross_page = 0;
2351 direct_jmp_count = 0;
2352 direct_jmp2_count = 0;
2353 for(i = 0; i < nb_tbs; i++) {
2354 tb = &tbs[i];
2355 target_code_size += tb->size;
2356 if (tb->size > max_target_code_size)
2357 max_target_code_size = tb->size;
2358 if (tb->page_addr[1] != -1)
2359 cross_page++;
2360 if (tb->tb_next_offset[0] != 0xffff) {
2361 direct_jmp_count++;
2362 if (tb->tb_next_offset[1] != 0xffff) {
2363 direct_jmp2_count++;
2364 }
2365 }
2366 }
2367 /* XXX: avoid using doubles ? */
2368 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2369 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2370 nb_tbs ? target_code_size / nb_tbs : 0,
2371 max_target_code_size);
2372 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2373 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2374 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2375 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2376 cross_page,
2377 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2378 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2379 direct_jmp_count,
2380 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2381 direct_jmp2_count,
2382 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2383 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2384 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2385 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2386}
2387
bellard61382a52003-10-27 21:22:23 +00002388#if !defined(CONFIG_USER_ONLY)
2389
2390#define MMUSUFFIX _cmmu
2391#define GETPC() NULL
2392#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002393#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002394
2395#define SHIFT 0
2396#include "softmmu_template.h"
2397
2398#define SHIFT 1
2399#include "softmmu_template.h"
2400
2401#define SHIFT 2
2402#include "softmmu_template.h"
2403
2404#define SHIFT 3
2405#include "softmmu_template.h"
2406
2407#undef env
2408
2409#endif