blob: 818fe21a31bee206753dcc7cade9e82709fe3763 [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"
pbrook53a59602006-03-25 19:31:22 +000037#if defined(CONFIG_USER_ONLY)
38#include <qemu.h>
39#endif
bellard54936002003-05-13 00:25:15 +000040
bellardfd6ce8f2003-05-14 19:00:11 +000041//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000042//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000043//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000044//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* make various TB consistency checks */
47//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000048//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000049
ths1196be32007-03-17 15:17:58 +000050//#define DEBUG_IOPORT
51
pbrook99773bd2006-04-16 15:14:59 +000052#if !defined(CONFIG_USER_ONLY)
53/* TB consistency checks only implemented for usermode emulation. */
54#undef DEBUG_TB_CHECK
55#endif
56
bellardfd6ce8f2003-05-14 19:00:11 +000057/* threshold to flush the translated code buffer */
58#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
59
bellard9fa3e852004-01-04 18:06:42 +000060#define SMC_BITMAP_USE_THRESHOLD 10
61
62#define MMAP_AREA_START 0x00000000
63#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000064
bellard108c49b2005-07-24 12:55:09 +000065#if defined(TARGET_SPARC64)
66#define TARGET_PHYS_ADDR_SPACE_BITS 41
67#elif defined(TARGET_PPC64)
68#define TARGET_PHYS_ADDR_SPACE_BITS 42
69#else
70/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
71#define TARGET_PHYS_ADDR_SPACE_BITS 32
72#endif
73
bellardfd6ce8f2003-05-14 19:00:11 +000074TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000075TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000076int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000077/* any access to the tbs or the page table must use this lock */
78spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000079
bellardb8076a72005-04-07 22:20:31 +000080uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000081uint8_t *code_gen_ptr;
82
bellard9fa3e852004-01-04 18:06:42 +000083int phys_ram_size;
84int phys_ram_fd;
85uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000086uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +000087static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000088
bellard6a00d602005-11-21 23:25:50 +000089CPUState *first_cpu;
90/* current CPU in the current thread. It is only valid inside
91 cpu_exec() */
92CPUState *cpu_single_env;
93
bellard54936002003-05-13 00:25:15 +000094typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000095 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000096 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000097 /* in order to optimize self modifying code, we count the number
98 of lookups we do to a given page to use a bitmap */
99 unsigned int code_write_count;
100 uint8_t *code_bitmap;
101#if defined(CONFIG_USER_ONLY)
102 unsigned long flags;
103#endif
bellard54936002003-05-13 00:25:15 +0000104} PageDesc;
105
bellard92e873b2004-05-21 14:52:29 +0000106typedef struct PhysPageDesc {
107 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000108 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000109} PhysPageDesc;
110
bellard54936002003-05-13 00:25:15 +0000111#define L2_BITS 10
112#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
113
114#define L1_SIZE (1 << L1_BITS)
115#define L2_SIZE (1 << L2_BITS)
116
bellard33417e72003-08-10 21:47:01 +0000117static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000118
bellard83fb7ad2004-07-05 21:25:26 +0000119unsigned long qemu_real_host_page_size;
120unsigned long qemu_host_page_bits;
121unsigned long qemu_host_page_size;
122unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000123
bellard92e873b2004-05-21 14:52:29 +0000124/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000125static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000126PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000127
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;
pbrook6658ffb2007-03-16 23:58:11 +0000133#if defined(CONFIG_SOFTMMU)
134static int io_mem_watch;
135#endif
bellard33417e72003-08-10 21:47:01 +0000136
bellard34865132003-10-05 14:28:56 +0000137/* log support */
138char *logfilename = "/tmp/qemu.log";
139FILE *logfile;
140int loglevel;
141
bellarde3db7222005-01-26 22:00:47 +0000142/* statistics */
143static int tlb_flush_count;
144static int tb_flush_count;
145static int tb_phys_invalidate_count;
146
bellardb346ff42003-06-15 20:05:50 +0000147static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000148{
bellard83fb7ad2004-07-05 21:25:26 +0000149 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000150 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000151#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000152 {
153 SYSTEM_INFO system_info;
154 DWORD old_protect;
155
156 GetSystemInfo(&system_info);
157 qemu_real_host_page_size = system_info.dwPageSize;
158
159 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
160 PAGE_EXECUTE_READWRITE, &old_protect);
161 }
bellard67b915a2004-03-31 23:37:16 +0000162#else
bellard83fb7ad2004-07-05 21:25:26 +0000163 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000164 {
165 unsigned long start, end;
166
167 start = (unsigned long)code_gen_buffer;
168 start &= ~(qemu_real_host_page_size - 1);
169
170 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
171 end += qemu_real_host_page_size - 1;
172 end &= ~(qemu_real_host_page_size - 1);
173
174 mprotect((void *)start, end - start,
175 PROT_READ | PROT_WRITE | PROT_EXEC);
176 }
bellard67b915a2004-03-31 23:37:16 +0000177#endif
bellardd5a8f072004-09-29 21:15:28 +0000178
bellard83fb7ad2004-07-05 21:25:26 +0000179 if (qemu_host_page_size == 0)
180 qemu_host_page_size = qemu_real_host_page_size;
181 if (qemu_host_page_size < TARGET_PAGE_SIZE)
182 qemu_host_page_size = TARGET_PAGE_SIZE;
183 qemu_host_page_bits = 0;
184 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
185 qemu_host_page_bits++;
186 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000187 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
188 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
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
bellard108c49b2005-07-24 12:55:09 +0000216static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000217{
bellard108c49b2005-07-24 12:55:09 +0000218 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000219 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000220
bellard108c49b2005-07-24 12:55:09 +0000221 p = (void **)l1_phys_map;
222#if TARGET_PHYS_ADDR_SPACE_BITS > 32
223
224#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
225#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
226#endif
227 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000228 p = *lp;
229 if (!p) {
230 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000231 if (!alloc)
232 return NULL;
233 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
234 memset(p, 0, sizeof(void *) * L1_SIZE);
235 *lp = p;
236 }
237#endif
238 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000239 pd = *lp;
240 if (!pd) {
241 int i;
bellard108c49b2005-07-24 12:55:09 +0000242 /* allocate if not found */
243 if (!alloc)
244 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000245 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
246 *lp = pd;
247 for (i = 0; i < L2_SIZE; i++)
248 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000249 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000250 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000251}
252
bellard108c49b2005-07-24 12:55:09 +0000253static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000254{
bellard108c49b2005-07-24 12:55:09 +0000255 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000256}
257
bellard9fa3e852004-01-04 18:06:42 +0000258#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000259static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000260static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
261 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000262#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000263
bellard6a00d602005-11-21 23:25:50 +0000264void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000265{
bellard6a00d602005-11-21 23:25:50 +0000266 CPUState **penv;
267 int cpu_index;
268
bellardfd6ce8f2003-05-14 19:00:11 +0000269 if (!code_gen_ptr) {
270 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000271 page_init();
bellard33417e72003-08-10 21:47:01 +0000272 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000273 }
bellard6a00d602005-11-21 23:25:50 +0000274 env->next_cpu = NULL;
275 penv = &first_cpu;
276 cpu_index = 0;
277 while (*penv != NULL) {
278 penv = (CPUState **)&(*penv)->next_cpu;
279 cpu_index++;
280 }
281 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000282 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000283 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000284}
285
bellard9fa3e852004-01-04 18:06:42 +0000286static inline void invalidate_page_bitmap(PageDesc *p)
287{
288 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000289 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000290 p->code_bitmap = NULL;
291 }
292 p->code_write_count = 0;
293}
294
bellardfd6ce8f2003-05-14 19:00:11 +0000295/* set to NULL all the 'first_tb' fields in all PageDescs */
296static void page_flush_tb(void)
297{
298 int i, j;
299 PageDesc *p;
300
301 for(i = 0; i < L1_SIZE; i++) {
302 p = l1_map[i];
303 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000304 for(j = 0; j < L2_SIZE; j++) {
305 p->first_tb = NULL;
306 invalidate_page_bitmap(p);
307 p++;
308 }
bellardfd6ce8f2003-05-14 19:00:11 +0000309 }
310 }
311}
312
313/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000314/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000315void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000316{
bellard6a00d602005-11-21 23:25:50 +0000317 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000318#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000319 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
320 code_gen_ptr - code_gen_buffer,
321 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000322 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000323#endif
324 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000325
326 for(env = first_cpu; env != NULL; env = env->next_cpu) {
327 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
328 }
bellard9fa3e852004-01-04 18:06:42 +0000329
bellard8a8a6082004-10-03 13:36:49 +0000330 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000331 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000332
bellardfd6ce8f2003-05-14 19:00:11 +0000333 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000334 /* XXX: flush processor icache at this point if cache flush is
335 expensive */
bellarde3db7222005-01-26 22:00:47 +0000336 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000337}
338
339#ifdef DEBUG_TB_CHECK
340
j_mayerbc98a7e2007-04-04 07:55:12 +0000341static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000342{
343 TranslationBlock *tb;
344 int i;
345 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000346 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
347 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000348 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
349 address >= tb->pc + tb->size)) {
350 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000351 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000352 }
353 }
354 }
355}
356
357/* verify that all the pages have correct rights for code */
358static void tb_page_check(void)
359{
360 TranslationBlock *tb;
361 int i, flags1, flags2;
362
pbrook99773bd2006-04-16 15:14:59 +0000363 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
364 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000365 flags1 = page_get_flags(tb->pc);
366 flags2 = page_get_flags(tb->pc + tb->size - 1);
367 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
368 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000369 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000370 }
371 }
372 }
373}
374
bellardd4e81642003-05-25 16:46:15 +0000375void tb_jmp_check(TranslationBlock *tb)
376{
377 TranslationBlock *tb1;
378 unsigned int n1;
379
380 /* suppress any remaining jumps to this TB */
381 tb1 = tb->jmp_first;
382 for(;;) {
383 n1 = (long)tb1 & 3;
384 tb1 = (TranslationBlock *)((long)tb1 & ~3);
385 if (n1 == 2)
386 break;
387 tb1 = tb1->jmp_next[n1];
388 }
389 /* check end of list */
390 if (tb1 != tb) {
391 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
392 }
393}
394
bellardfd6ce8f2003-05-14 19:00:11 +0000395#endif
396
397/* invalidate one TB */
398static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
399 int next_offset)
400{
401 TranslationBlock *tb1;
402 for(;;) {
403 tb1 = *ptb;
404 if (tb1 == tb) {
405 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
406 break;
407 }
408 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
409 }
410}
411
bellard9fa3e852004-01-04 18:06:42 +0000412static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
413{
414 TranslationBlock *tb1;
415 unsigned int n1;
416
417 for(;;) {
418 tb1 = *ptb;
419 n1 = (long)tb1 & 3;
420 tb1 = (TranslationBlock *)((long)tb1 & ~3);
421 if (tb1 == tb) {
422 *ptb = tb1->page_next[n1];
423 break;
424 }
425 ptb = &tb1->page_next[n1];
426 }
427}
428
bellardd4e81642003-05-25 16:46:15 +0000429static inline void tb_jmp_remove(TranslationBlock *tb, int n)
430{
431 TranslationBlock *tb1, **ptb;
432 unsigned int n1;
433
434 ptb = &tb->jmp_next[n];
435 tb1 = *ptb;
436 if (tb1) {
437 /* find tb(n) in circular list */
438 for(;;) {
439 tb1 = *ptb;
440 n1 = (long)tb1 & 3;
441 tb1 = (TranslationBlock *)((long)tb1 & ~3);
442 if (n1 == n && tb1 == tb)
443 break;
444 if (n1 == 2) {
445 ptb = &tb1->jmp_first;
446 } else {
447 ptb = &tb1->jmp_next[n1];
448 }
449 }
450 /* now we can suppress tb(n) from the list */
451 *ptb = tb->jmp_next[n];
452
453 tb->jmp_next[n] = NULL;
454 }
455}
456
457/* reset the jump entry 'n' of a TB so that it is not chained to
458 another TB */
459static inline void tb_reset_jump(TranslationBlock *tb, int n)
460{
461 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
462}
463
bellard9fa3e852004-01-04 18:06:42 +0000464static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000465{
bellard6a00d602005-11-21 23:25:50 +0000466 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000467 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000468 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000469 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000470 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000471
472 /* remove the TB from the hash list */
473 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
474 h = tb_phys_hash_func(phys_pc);
475 tb_remove(&tb_phys_hash[h], tb,
476 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000477
bellard9fa3e852004-01-04 18:06:42 +0000478 /* remove the TB from the page list */
479 if (tb->page_addr[0] != page_addr) {
480 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
481 tb_page_remove(&p->first_tb, tb);
482 invalidate_page_bitmap(p);
483 }
484 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
485 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
486 tb_page_remove(&p->first_tb, tb);
487 invalidate_page_bitmap(p);
488 }
489
bellard8a40a182005-11-20 10:35:40 +0000490 tb_invalidated_flag = 1;
491
492 /* remove the TB from the hash list */
493 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000494 for(env = first_cpu; env != NULL; env = env->next_cpu) {
495 if (env->tb_jmp_cache[h] == tb)
496 env->tb_jmp_cache[h] = NULL;
497 }
bellard8a40a182005-11-20 10:35:40 +0000498
499 /* suppress this TB from the two jump lists */
500 tb_jmp_remove(tb, 0);
501 tb_jmp_remove(tb, 1);
502
503 /* suppress any remaining jumps to this TB */
504 tb1 = tb->jmp_first;
505 for(;;) {
506 n1 = (long)tb1 & 3;
507 if (n1 == 2)
508 break;
509 tb1 = (TranslationBlock *)((long)tb1 & ~3);
510 tb2 = tb1->jmp_next[n1];
511 tb_reset_jump(tb1, n1);
512 tb1->jmp_next[n1] = NULL;
513 tb1 = tb2;
514 }
515 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
516
bellarde3db7222005-01-26 22:00:47 +0000517 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000518}
519
520static inline void set_bits(uint8_t *tab, int start, int len)
521{
522 int end, mask, end1;
523
524 end = start + len;
525 tab += start >> 3;
526 mask = 0xff << (start & 7);
527 if ((start & ~7) == (end & ~7)) {
528 if (start < end) {
529 mask &= ~(0xff << (end & 7));
530 *tab |= mask;
531 }
532 } else {
533 *tab++ |= mask;
534 start = (start + 8) & ~7;
535 end1 = end & ~7;
536 while (start < end1) {
537 *tab++ = 0xff;
538 start += 8;
539 }
540 if (start < end) {
541 mask = ~(0xff << (end & 7));
542 *tab |= mask;
543 }
544 }
545}
546
547static void build_page_bitmap(PageDesc *p)
548{
549 int n, tb_start, tb_end;
550 TranslationBlock *tb;
551
bellard59817cc2004-02-16 22:01:13 +0000552 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000553 if (!p->code_bitmap)
554 return;
555 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
556
557 tb = p->first_tb;
558 while (tb != NULL) {
559 n = (long)tb & 3;
560 tb = (TranslationBlock *)((long)tb & ~3);
561 /* NOTE: this is subtle as a TB may span two physical pages */
562 if (n == 0) {
563 /* NOTE: tb_end may be after the end of the page, but
564 it is not a problem */
565 tb_start = tb->pc & ~TARGET_PAGE_MASK;
566 tb_end = tb_start + tb->size;
567 if (tb_end > TARGET_PAGE_SIZE)
568 tb_end = TARGET_PAGE_SIZE;
569 } else {
570 tb_start = 0;
571 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
572 }
573 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
574 tb = tb->page_next[n];
575 }
576}
577
bellardd720b932004-04-25 17:57:43 +0000578#ifdef TARGET_HAS_PRECISE_SMC
579
580static void tb_gen_code(CPUState *env,
581 target_ulong pc, target_ulong cs_base, int flags,
582 int cflags)
583{
584 TranslationBlock *tb;
585 uint8_t *tc_ptr;
586 target_ulong phys_pc, phys_page2, virt_page2;
587 int code_gen_size;
588
bellardc27004e2005-01-03 23:35:10 +0000589 phys_pc = get_phys_addr_code(env, pc);
590 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000591 if (!tb) {
592 /* flush must be done */
593 tb_flush(env);
594 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000595 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000596 }
597 tc_ptr = code_gen_ptr;
598 tb->tc_ptr = tc_ptr;
599 tb->cs_base = cs_base;
600 tb->flags = flags;
601 tb->cflags = cflags;
602 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
603 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
604
605 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000606 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000607 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000608 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000609 phys_page2 = get_phys_addr_code(env, virt_page2);
610 }
611 tb_link_phys(tb, phys_pc, phys_page2);
612}
613#endif
614
bellard9fa3e852004-01-04 18:06:42 +0000615/* invalidate all TBs which intersect with the target physical page
616 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000617 the same physical page. 'is_cpu_write_access' should be true if called
618 from a real cpu write access: the virtual CPU will exit the current
619 TB if code is modified inside this TB. */
620void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
621 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000622{
bellardd720b932004-04-25 17:57:43 +0000623 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000624 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000625 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000626 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000627 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000628 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000629
630 p = page_find(start >> TARGET_PAGE_BITS);
631 if (!p)
632 return;
633 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000634 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
635 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000636 /* build code bitmap */
637 build_page_bitmap(p);
638 }
639
640 /* we remove all the TBs in the range [start, end[ */
641 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000642 current_tb_not_found = is_cpu_write_access;
643 current_tb_modified = 0;
644 current_tb = NULL; /* avoid warning */
645 current_pc = 0; /* avoid warning */
646 current_cs_base = 0; /* avoid warning */
647 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000648 tb = p->first_tb;
649 while (tb != NULL) {
650 n = (long)tb & 3;
651 tb = (TranslationBlock *)((long)tb & ~3);
652 tb_next = tb->page_next[n];
653 /* NOTE: this is subtle as a TB may span two physical pages */
654 if (n == 0) {
655 /* NOTE: tb_end may be after the end of the page, but
656 it is not a problem */
657 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
658 tb_end = tb_start + tb->size;
659 } else {
660 tb_start = tb->page_addr[1];
661 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
662 }
663 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000664#ifdef TARGET_HAS_PRECISE_SMC
665 if (current_tb_not_found) {
666 current_tb_not_found = 0;
667 current_tb = NULL;
668 if (env->mem_write_pc) {
669 /* now we have a real cpu fault */
670 current_tb = tb_find_pc(env->mem_write_pc);
671 }
672 }
673 if (current_tb == tb &&
674 !(current_tb->cflags & CF_SINGLE_INSN)) {
675 /* If we are modifying the current TB, we must stop
676 its execution. We could be more precise by checking
677 that the modification is after the current PC, but it
678 would require a specialized function to partially
679 restore the CPU state */
680
681 current_tb_modified = 1;
682 cpu_restore_state(current_tb, env,
683 env->mem_write_pc, NULL);
684#if defined(TARGET_I386)
685 current_flags = env->hflags;
686 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
687 current_cs_base = (target_ulong)env->segs[R_CS].base;
688 current_pc = current_cs_base + env->eip;
689#else
690#error unsupported CPU
691#endif
692 }
693#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000694 /* we need to do that to handle the case where a signal
695 occurs while doing tb_phys_invalidate() */
696 saved_tb = NULL;
697 if (env) {
698 saved_tb = env->current_tb;
699 env->current_tb = NULL;
700 }
bellard9fa3e852004-01-04 18:06:42 +0000701 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000702 if (env) {
703 env->current_tb = saved_tb;
704 if (env->interrupt_request && env->current_tb)
705 cpu_interrupt(env, env->interrupt_request);
706 }
bellard9fa3e852004-01-04 18:06:42 +0000707 }
708 tb = tb_next;
709 }
710#if !defined(CONFIG_USER_ONLY)
711 /* if no code remaining, no need to continue to use slow writes */
712 if (!p->first_tb) {
713 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000714 if (is_cpu_write_access) {
715 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
716 }
717 }
718#endif
719#ifdef TARGET_HAS_PRECISE_SMC
720 if (current_tb_modified) {
721 /* we generate a block containing just the instruction
722 modifying the memory. It will ensure that it cannot modify
723 itself */
bellardea1c1802004-06-14 18:56:36 +0000724 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000725 tb_gen_code(env, current_pc, current_cs_base, current_flags,
726 CF_SINGLE_INSN);
727 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000728 }
729#endif
730}
731
732/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000733static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000734{
735 PageDesc *p;
736 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000737#if 0
bellarda4193c82004-06-03 14:01:43 +0000738 if (1) {
739 if (loglevel) {
740 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
741 cpu_single_env->mem_write_vaddr, len,
742 cpu_single_env->eip,
743 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
744 }
bellard59817cc2004-02-16 22:01:13 +0000745 }
746#endif
bellard9fa3e852004-01-04 18:06:42 +0000747 p = page_find(start >> TARGET_PAGE_BITS);
748 if (!p)
749 return;
750 if (p->code_bitmap) {
751 offset = start & ~TARGET_PAGE_MASK;
752 b = p->code_bitmap[offset >> 3] >> (offset & 7);
753 if (b & ((1 << len) - 1))
754 goto do_invalidate;
755 } else {
756 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000757 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000758 }
759}
760
bellard9fa3e852004-01-04 18:06:42 +0000761#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000762static void tb_invalidate_phys_page(target_ulong addr,
763 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000764{
bellardd720b932004-04-25 17:57:43 +0000765 int n, current_flags, current_tb_modified;
766 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000767 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000768 TranslationBlock *tb, *current_tb;
769#ifdef TARGET_HAS_PRECISE_SMC
770 CPUState *env = cpu_single_env;
771#endif
bellard9fa3e852004-01-04 18:06:42 +0000772
773 addr &= TARGET_PAGE_MASK;
774 p = page_find(addr >> TARGET_PAGE_BITS);
775 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000776 return;
777 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000778 current_tb_modified = 0;
779 current_tb = NULL;
780 current_pc = 0; /* avoid warning */
781 current_cs_base = 0; /* avoid warning */
782 current_flags = 0; /* avoid warning */
783#ifdef TARGET_HAS_PRECISE_SMC
784 if (tb && pc != 0) {
785 current_tb = tb_find_pc(pc);
786 }
787#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000788 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000789 n = (long)tb & 3;
790 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000791#ifdef TARGET_HAS_PRECISE_SMC
792 if (current_tb == tb &&
793 !(current_tb->cflags & CF_SINGLE_INSN)) {
794 /* If we are modifying the current TB, we must stop
795 its execution. We could be more precise by checking
796 that the modification is after the current PC, but it
797 would require a specialized function to partially
798 restore the CPU state */
799
800 current_tb_modified = 1;
801 cpu_restore_state(current_tb, env, pc, puc);
802#if defined(TARGET_I386)
803 current_flags = env->hflags;
804 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
805 current_cs_base = (target_ulong)env->segs[R_CS].base;
806 current_pc = current_cs_base + env->eip;
807#else
808#error unsupported CPU
809#endif
810 }
811#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000812 tb_phys_invalidate(tb, addr);
813 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000814 }
815 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000816#ifdef TARGET_HAS_PRECISE_SMC
817 if (current_tb_modified) {
818 /* we generate a block containing just the instruction
819 modifying the memory. It will ensure that it cannot modify
820 itself */
bellardea1c1802004-06-14 18:56:36 +0000821 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000822 tb_gen_code(env, current_pc, current_cs_base, current_flags,
823 CF_SINGLE_INSN);
824 cpu_resume_from_signal(env, puc);
825 }
826#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000827}
bellard9fa3e852004-01-04 18:06:42 +0000828#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000829
830/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000831static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000832 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000833{
834 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000835 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000836
bellard9fa3e852004-01-04 18:06:42 +0000837 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000838 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000839 tb->page_next[n] = p->first_tb;
840 last_first_tb = p->first_tb;
841 p->first_tb = (TranslationBlock *)((long)tb | n);
842 invalidate_page_bitmap(p);
843
bellard107db442004-06-22 18:48:46 +0000844#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000845
bellard9fa3e852004-01-04 18:06:42 +0000846#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000847 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000848 target_ulong addr;
849 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000850 int prot;
851
bellardfd6ce8f2003-05-14 19:00:11 +0000852 /* force the host page as non writable (writes will have a
853 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000854 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000855 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000856 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
857 addr += TARGET_PAGE_SIZE) {
858
859 p2 = page_find (addr >> TARGET_PAGE_BITS);
860 if (!p2)
861 continue;
862 prot |= p2->flags;
863 p2->flags &= ~PAGE_WRITE;
864 page_get_flags(addr);
865 }
866 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000867 (prot & PAGE_BITS) & ~PAGE_WRITE);
868#ifdef DEBUG_TB_INVALIDATE
869 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000870 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000871#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000872 }
bellard9fa3e852004-01-04 18:06:42 +0000873#else
874 /* if some code is already present, then the pages are already
875 protected. So we handle the case where only the first TB is
876 allocated in a physical page */
877 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000878 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000879 }
880#endif
bellardd720b932004-04-25 17:57:43 +0000881
882#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000883}
884
885/* Allocate a new translation block. Flush the translation buffer if
886 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000887TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000888{
889 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000890
891 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
892 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000893 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000894 tb = &tbs[nb_tbs++];
895 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000896 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000897 return tb;
898}
899
bellard9fa3e852004-01-04 18:06:42 +0000900/* add a new TB and link it to the physical page tables. phys_page2 is
901 (-1) to indicate that only one page contains the TB. */
902void tb_link_phys(TranslationBlock *tb,
903 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000904{
bellard9fa3e852004-01-04 18:06:42 +0000905 unsigned int h;
906 TranslationBlock **ptb;
907
908 /* add in the physical hash table */
909 h = tb_phys_hash_func(phys_pc);
910 ptb = &tb_phys_hash[h];
911 tb->phys_hash_next = *ptb;
912 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000913
914 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000915 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
916 if (phys_page2 != -1)
917 tb_alloc_page(tb, 1, phys_page2);
918 else
919 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000920
bellardd4e81642003-05-25 16:46:15 +0000921 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
922 tb->jmp_next[0] = NULL;
923 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000924#ifdef USE_CODE_COPY
925 tb->cflags &= ~CF_FP_USED;
926 if (tb->cflags & CF_TB_FP_USED)
927 tb->cflags |= CF_FP_USED;
928#endif
bellardd4e81642003-05-25 16:46:15 +0000929
930 /* init original jump addresses */
931 if (tb->tb_next_offset[0] != 0xffff)
932 tb_reset_jump(tb, 0);
933 if (tb->tb_next_offset[1] != 0xffff)
934 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000935
936#ifdef DEBUG_TB_CHECK
937 tb_page_check();
938#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000939}
940
bellarda513fe12003-05-27 23:29:48 +0000941/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
942 tb[1].tc_ptr. Return NULL if not found */
943TranslationBlock *tb_find_pc(unsigned long tc_ptr)
944{
945 int m_min, m_max, m;
946 unsigned long v;
947 TranslationBlock *tb;
948
949 if (nb_tbs <= 0)
950 return NULL;
951 if (tc_ptr < (unsigned long)code_gen_buffer ||
952 tc_ptr >= (unsigned long)code_gen_ptr)
953 return NULL;
954 /* binary search (cf Knuth) */
955 m_min = 0;
956 m_max = nb_tbs - 1;
957 while (m_min <= m_max) {
958 m = (m_min + m_max) >> 1;
959 tb = &tbs[m];
960 v = (unsigned long)tb->tc_ptr;
961 if (v == tc_ptr)
962 return tb;
963 else if (tc_ptr < v) {
964 m_max = m - 1;
965 } else {
966 m_min = m + 1;
967 }
968 }
969 return &tbs[m_max];
970}
bellard75012672003-06-21 13:11:07 +0000971
bellardea041c02003-06-25 16:16:50 +0000972static void tb_reset_jump_recursive(TranslationBlock *tb);
973
974static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
975{
976 TranslationBlock *tb1, *tb_next, **ptb;
977 unsigned int n1;
978
979 tb1 = tb->jmp_next[n];
980 if (tb1 != NULL) {
981 /* find head of list */
982 for(;;) {
983 n1 = (long)tb1 & 3;
984 tb1 = (TranslationBlock *)((long)tb1 & ~3);
985 if (n1 == 2)
986 break;
987 tb1 = tb1->jmp_next[n1];
988 }
989 /* we are now sure now that tb jumps to tb1 */
990 tb_next = tb1;
991
992 /* remove tb from the jmp_first list */
993 ptb = &tb_next->jmp_first;
994 for(;;) {
995 tb1 = *ptb;
996 n1 = (long)tb1 & 3;
997 tb1 = (TranslationBlock *)((long)tb1 & ~3);
998 if (n1 == n && tb1 == tb)
999 break;
1000 ptb = &tb1->jmp_next[n1];
1001 }
1002 *ptb = tb->jmp_next[n];
1003 tb->jmp_next[n] = NULL;
1004
1005 /* suppress the jump to next tb in generated code */
1006 tb_reset_jump(tb, n);
1007
bellard01243112004-01-04 15:48:17 +00001008 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001009 tb_reset_jump_recursive(tb_next);
1010 }
1011}
1012
1013static void tb_reset_jump_recursive(TranslationBlock *tb)
1014{
1015 tb_reset_jump_recursive2(tb, 0);
1016 tb_reset_jump_recursive2(tb, 1);
1017}
1018
bellard1fddef42005-04-17 19:16:13 +00001019#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001020static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1021{
pbrookc2f07f82006-04-08 17:14:56 +00001022 target_ulong addr, pd;
1023 ram_addr_t ram_addr;
1024 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001025
pbrookc2f07f82006-04-08 17:14:56 +00001026 addr = cpu_get_phys_page_debug(env, pc);
1027 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1028 if (!p) {
1029 pd = IO_MEM_UNASSIGNED;
1030 } else {
1031 pd = p->phys_offset;
1032 }
1033 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001034 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001035}
bellardc27004e2005-01-03 23:35:10 +00001036#endif
bellardd720b932004-04-25 17:57:43 +00001037
pbrook6658ffb2007-03-16 23:58:11 +00001038/* Add a watchpoint. */
1039int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1040{
1041 int i;
1042
1043 for (i = 0; i < env->nb_watchpoints; i++) {
1044 if (addr == env->watchpoint[i].vaddr)
1045 return 0;
1046 }
1047 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1048 return -1;
1049
1050 i = env->nb_watchpoints++;
1051 env->watchpoint[i].vaddr = addr;
1052 tlb_flush_page(env, addr);
1053 /* FIXME: This flush is needed because of the hack to make memory ops
1054 terminate the TB. It can be removed once the proper IO trap and
1055 re-execute bits are in. */
1056 tb_flush(env);
1057 return i;
1058}
1059
1060/* Remove a watchpoint. */
1061int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1062{
1063 int i;
1064
1065 for (i = 0; i < env->nb_watchpoints; i++) {
1066 if (addr == env->watchpoint[i].vaddr) {
1067 env->nb_watchpoints--;
1068 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1069 tlb_flush_page(env, addr);
1070 return 0;
1071 }
1072 }
1073 return -1;
1074}
1075
bellardc33a3462003-07-29 20:50:33 +00001076/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1077 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001078int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001079{
bellard1fddef42005-04-17 19:16:13 +00001080#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001081 int i;
bellardd720b932004-04-25 17:57:43 +00001082
bellard4c3a88a2003-07-26 12:06:08 +00001083 for(i = 0; i < env->nb_breakpoints; i++) {
1084 if (env->breakpoints[i] == pc)
1085 return 0;
1086 }
1087
1088 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1089 return -1;
1090 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001091
1092 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001093 return 0;
1094#else
1095 return -1;
1096#endif
1097}
1098
1099/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001100int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001101{
bellard1fddef42005-04-17 19:16:13 +00001102#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001103 int i;
1104 for(i = 0; i < env->nb_breakpoints; i++) {
1105 if (env->breakpoints[i] == pc)
1106 goto found;
1107 }
1108 return -1;
1109 found:
bellard4c3a88a2003-07-26 12:06:08 +00001110 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001111 if (i < env->nb_breakpoints)
1112 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001113
1114 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001115 return 0;
1116#else
1117 return -1;
1118#endif
1119}
1120
bellardc33a3462003-07-29 20:50:33 +00001121/* enable or disable single step mode. EXCP_DEBUG is returned by the
1122 CPU loop after each instruction */
1123void cpu_single_step(CPUState *env, int enabled)
1124{
bellard1fddef42005-04-17 19:16:13 +00001125#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001126 if (env->singlestep_enabled != enabled) {
1127 env->singlestep_enabled = enabled;
1128 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001129 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001130 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001131 }
1132#endif
1133}
1134
bellard34865132003-10-05 14:28:56 +00001135/* enable or disable low levels log */
1136void cpu_set_log(int log_flags)
1137{
1138 loglevel = log_flags;
1139 if (loglevel && !logfile) {
1140 logfile = fopen(logfilename, "w");
1141 if (!logfile) {
1142 perror(logfilename);
1143 _exit(1);
1144 }
bellard9fa3e852004-01-04 18:06:42 +00001145#if !defined(CONFIG_SOFTMMU)
1146 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1147 {
1148 static uint8_t logfile_buf[4096];
1149 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1150 }
1151#else
bellard34865132003-10-05 14:28:56 +00001152 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001153#endif
bellard34865132003-10-05 14:28:56 +00001154 }
1155}
1156
1157void cpu_set_log_filename(const char *filename)
1158{
1159 logfilename = strdup(filename);
1160}
bellardc33a3462003-07-29 20:50:33 +00001161
bellard01243112004-01-04 15:48:17 +00001162/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001163void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001164{
1165 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001166 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001167
bellard68a79312003-06-30 13:12:32 +00001168 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001169 /* if the cpu is currently executing code, we must unlink it and
1170 all the potentially executing TB */
1171 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001172 if (tb && !testandset(&interrupt_lock)) {
1173 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001174 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001175 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001176 }
1177}
1178
bellardb54ad042004-05-20 13:42:52 +00001179void cpu_reset_interrupt(CPUState *env, int mask)
1180{
1181 env->interrupt_request &= ~mask;
1182}
1183
bellardf193c792004-03-21 17:06:25 +00001184CPULogItem cpu_log_items[] = {
1185 { CPU_LOG_TB_OUT_ASM, "out_asm",
1186 "show generated host assembly code for each compiled TB" },
1187 { CPU_LOG_TB_IN_ASM, "in_asm",
1188 "show target assembly code for each compiled TB" },
1189 { CPU_LOG_TB_OP, "op",
1190 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1191#ifdef TARGET_I386
1192 { CPU_LOG_TB_OP_OPT, "op_opt",
1193 "show micro ops after optimization for each compiled TB" },
1194#endif
1195 { CPU_LOG_INT, "int",
1196 "show interrupts/exceptions in short format" },
1197 { CPU_LOG_EXEC, "exec",
1198 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001199 { CPU_LOG_TB_CPU, "cpu",
1200 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001201#ifdef TARGET_I386
1202 { CPU_LOG_PCALL, "pcall",
1203 "show protected mode far calls/returns/exceptions" },
1204#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001205#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001206 { CPU_LOG_IOPORT, "ioport",
1207 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001208#endif
bellardf193c792004-03-21 17:06:25 +00001209 { 0, NULL, NULL },
1210};
1211
1212static int cmp1(const char *s1, int n, const char *s2)
1213{
1214 if (strlen(s2) != n)
1215 return 0;
1216 return memcmp(s1, s2, n) == 0;
1217}
1218
1219/* takes a comma separated list of log masks. Return 0 if error. */
1220int cpu_str_to_log_mask(const char *str)
1221{
1222 CPULogItem *item;
1223 int mask;
1224 const char *p, *p1;
1225
1226 p = str;
1227 mask = 0;
1228 for(;;) {
1229 p1 = strchr(p, ',');
1230 if (!p1)
1231 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001232 if(cmp1(p,p1-p,"all")) {
1233 for(item = cpu_log_items; item->mask != 0; item++) {
1234 mask |= item->mask;
1235 }
1236 } else {
bellardf193c792004-03-21 17:06:25 +00001237 for(item = cpu_log_items; item->mask != 0; item++) {
1238 if (cmp1(p, p1 - p, item->name))
1239 goto found;
1240 }
1241 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001242 }
bellardf193c792004-03-21 17:06:25 +00001243 found:
1244 mask |= item->mask;
1245 if (*p1 != ',')
1246 break;
1247 p = p1 + 1;
1248 }
1249 return mask;
1250}
bellardea041c02003-06-25 16:16:50 +00001251
bellard75012672003-06-21 13:11:07 +00001252void cpu_abort(CPUState *env, const char *fmt, ...)
1253{
1254 va_list ap;
1255
1256 va_start(ap, fmt);
1257 fprintf(stderr, "qemu: fatal: ");
1258 vfprintf(stderr, fmt, ap);
1259 fprintf(stderr, "\n");
1260#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001261 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1262#else
1263 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001264#endif
1265 va_end(ap);
1266 abort();
1267}
1268
thsc5be9f02007-02-28 20:20:53 +00001269CPUState *cpu_copy(CPUState *env)
1270{
1271 CPUState *new_env = cpu_init();
1272 /* preserve chaining and index */
1273 CPUState *next_cpu = new_env->next_cpu;
1274 int cpu_index = new_env->cpu_index;
1275 memcpy(new_env, env, sizeof(CPUState));
1276 new_env->next_cpu = next_cpu;
1277 new_env->cpu_index = cpu_index;
1278 return new_env;
1279}
1280
bellard01243112004-01-04 15:48:17 +00001281#if !defined(CONFIG_USER_ONLY)
1282
bellardee8b7022004-02-03 23:35:10 +00001283/* NOTE: if flush_global is true, also flush global entries (not
1284 implemented yet) */
1285void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001286{
bellard33417e72003-08-10 21:47:01 +00001287 int i;
bellard01243112004-01-04 15:48:17 +00001288
bellard9fa3e852004-01-04 18:06:42 +00001289#if defined(DEBUG_TLB)
1290 printf("tlb_flush:\n");
1291#endif
bellard01243112004-01-04 15:48:17 +00001292 /* must reset current TB so that interrupts cannot modify the
1293 links while we are modifying them */
1294 env->current_tb = NULL;
1295
bellard33417e72003-08-10 21:47:01 +00001296 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001297 env->tlb_table[0][i].addr_read = -1;
1298 env->tlb_table[0][i].addr_write = -1;
1299 env->tlb_table[0][i].addr_code = -1;
1300 env->tlb_table[1][i].addr_read = -1;
1301 env->tlb_table[1][i].addr_write = -1;
1302 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001303 }
bellard9fa3e852004-01-04 18:06:42 +00001304
bellard8a40a182005-11-20 10:35:40 +00001305 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001306
1307#if !defined(CONFIG_SOFTMMU)
1308 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1309#endif
bellard0a962c02005-02-10 22:00:27 +00001310#ifdef USE_KQEMU
1311 if (env->kqemu_enabled) {
1312 kqemu_flush(env, flush_global);
1313 }
1314#endif
bellarde3db7222005-01-26 22:00:47 +00001315 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001316}
1317
bellard274da6b2004-05-20 21:56:27 +00001318static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001319{
bellard84b7b8e2005-11-28 21:19:04 +00001320 if (addr == (tlb_entry->addr_read &
1321 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1322 addr == (tlb_entry->addr_write &
1323 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1324 addr == (tlb_entry->addr_code &
1325 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1326 tlb_entry->addr_read = -1;
1327 tlb_entry->addr_write = -1;
1328 tlb_entry->addr_code = -1;
1329 }
bellard61382a52003-10-27 21:22:23 +00001330}
1331
bellard2e126692004-04-25 21:28:44 +00001332void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001333{
bellard8a40a182005-11-20 10:35:40 +00001334 int i;
bellard9fa3e852004-01-04 18:06:42 +00001335 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001336
bellard9fa3e852004-01-04 18:06:42 +00001337#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001338 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001339#endif
bellard01243112004-01-04 15:48:17 +00001340 /* must reset current TB so that interrupts cannot modify the
1341 links while we are modifying them */
1342 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001343
bellard61382a52003-10-27 21:22:23 +00001344 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001345 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001346 tlb_flush_entry(&env->tlb_table[0][i], addr);
1347 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001348
pbrookb362e5e2006-11-12 20:40:55 +00001349 /* Discard jump cache entries for any tb which might potentially
1350 overlap the flushed page. */
1351 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1352 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1353
1354 i = tb_jmp_cache_hash_page(addr);
1355 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001356
bellard01243112004-01-04 15:48:17 +00001357#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001358 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001359 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001360#endif
bellard0a962c02005-02-10 22:00:27 +00001361#ifdef USE_KQEMU
1362 if (env->kqemu_enabled) {
1363 kqemu_flush_page(env, addr);
1364 }
1365#endif
bellard9fa3e852004-01-04 18:06:42 +00001366}
1367
bellard9fa3e852004-01-04 18:06:42 +00001368/* update the TLBs so that writes to code in the virtual page 'addr'
1369 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001370static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001371{
bellard6a00d602005-11-21 23:25:50 +00001372 cpu_physical_memory_reset_dirty(ram_addr,
1373 ram_addr + TARGET_PAGE_SIZE,
1374 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001375}
1376
bellard9fa3e852004-01-04 18:06:42 +00001377/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001378 tested for self modifying code */
1379static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1380 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001381{
bellard3a7d9292005-08-21 09:26:42 +00001382 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001383}
1384
1385static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1386 unsigned long start, unsigned long length)
1387{
1388 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001389 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1390 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001391 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001392 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001393 }
1394 }
1395}
1396
bellard3a7d9292005-08-21 09:26:42 +00001397void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001398 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001399{
1400 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001401 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001402 int i, mask, len;
1403 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001404
1405 start &= TARGET_PAGE_MASK;
1406 end = TARGET_PAGE_ALIGN(end);
1407
1408 length = end - start;
1409 if (length == 0)
1410 return;
bellard0a962c02005-02-10 22:00:27 +00001411 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001412#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001413 /* XXX: should not depend on cpu context */
1414 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001415 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001416 ram_addr_t addr;
1417 addr = start;
1418 for(i = 0; i < len; i++) {
1419 kqemu_set_notdirty(env, addr);
1420 addr += TARGET_PAGE_SIZE;
1421 }
bellard3a7d9292005-08-21 09:26:42 +00001422 }
1423#endif
bellardf23db162005-08-21 19:12:28 +00001424 mask = ~dirty_flags;
1425 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1426 for(i = 0; i < len; i++)
1427 p[i] &= mask;
1428
bellard1ccde1c2004-02-06 19:46:14 +00001429 /* we modify the TLB cache so that the dirty bit will be set again
1430 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001431 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001432 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1433 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001434 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001435 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001436 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001437 }
bellard59817cc2004-02-16 22:01:13 +00001438
1439#if !defined(CONFIG_SOFTMMU)
1440 /* XXX: this is expensive */
1441 {
1442 VirtPageDesc *p;
1443 int j;
1444 target_ulong addr;
1445
1446 for(i = 0; i < L1_SIZE; i++) {
1447 p = l1_virt_map[i];
1448 if (p) {
1449 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1450 for(j = 0; j < L2_SIZE; j++) {
1451 if (p->valid_tag == virt_valid_tag &&
1452 p->phys_addr >= start && p->phys_addr < end &&
1453 (p->prot & PROT_WRITE)) {
1454 if (addr < MMAP_AREA_END) {
1455 mprotect((void *)addr, TARGET_PAGE_SIZE,
1456 p->prot & ~PROT_WRITE);
1457 }
1458 }
1459 addr += TARGET_PAGE_SIZE;
1460 p++;
1461 }
1462 }
1463 }
1464 }
1465#endif
bellard1ccde1c2004-02-06 19:46:14 +00001466}
1467
bellard3a7d9292005-08-21 09:26:42 +00001468static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1469{
1470 ram_addr_t ram_addr;
1471
bellard84b7b8e2005-11-28 21:19:04 +00001472 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1473 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001474 tlb_entry->addend - (unsigned long)phys_ram_base;
1475 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001476 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001477 }
1478 }
1479}
1480
1481/* update the TLB according to the current state of the dirty bits */
1482void cpu_tlb_update_dirty(CPUState *env)
1483{
1484 int i;
1485 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001486 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001487 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001488 tlb_update_dirty(&env->tlb_table[1][i]);
bellard3a7d9292005-08-21 09:26:42 +00001489}
1490
bellard1ccde1c2004-02-06 19:46:14 +00001491static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001492 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001493{
1494 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001495 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1496 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001497 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001498 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001499 }
1500 }
1501}
1502
1503/* update the TLB corresponding to virtual page vaddr and phys addr
1504 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001505static inline void tlb_set_dirty(CPUState *env,
1506 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001507{
bellard1ccde1c2004-02-06 19:46:14 +00001508 int i;
1509
bellard1ccde1c2004-02-06 19:46:14 +00001510 addr &= TARGET_PAGE_MASK;
1511 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001512 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1513 tlb_set_dirty1(&env->tlb_table[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001514}
1515
bellard59817cc2004-02-16 22:01:13 +00001516/* add a new TLB entry. At most one entry for a given virtual address
1517 is permitted. Return 0 if OK or 2 if the page could not be mapped
1518 (can only happen in non SOFTMMU mode for I/O pages or pages
1519 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001520int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1521 target_phys_addr_t paddr, int prot,
1522 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001523{
bellard92e873b2004-05-21 14:52:29 +00001524 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001525 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001526 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001527 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001528 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001529 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001530 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001531 int i;
bellard9fa3e852004-01-04 18:06:42 +00001532
bellard92e873b2004-05-21 14:52:29 +00001533 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001534 if (!p) {
1535 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001536 } else {
1537 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001538 }
1539#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001540 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
bellard84b7b8e2005-11-28 21:19:04 +00001541 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001542#endif
1543
1544 ret = 0;
1545#if !defined(CONFIG_SOFTMMU)
1546 if (is_softmmu)
1547#endif
1548 {
bellard2a4188a2006-06-25 21:54:59 +00001549 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001550 /* IO memory case */
1551 address = vaddr | pd;
1552 addend = paddr;
1553 } else {
1554 /* standard memory */
1555 address = vaddr;
1556 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1557 }
pbrook6658ffb2007-03-16 23:58:11 +00001558
1559 /* Make accesses to pages with watchpoints go via the
1560 watchpoint trap routines. */
1561 for (i = 0; i < env->nb_watchpoints; i++) {
1562 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1563 if (address & ~TARGET_PAGE_MASK) {
1564 env->watchpoint[i].is_ram = 0;
1565 address = vaddr | io_mem_watch;
1566 } else {
1567 env->watchpoint[i].is_ram = 1;
1568 /* TODO: Figure out how to make read watchpoints coexist
1569 with code. */
1570 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1571 }
1572 }
1573 }
bellard9fa3e852004-01-04 18:06:42 +00001574
bellard90f18422005-07-24 10:17:31 +00001575 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001576 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001577 te = &env->tlb_table[is_user][index];
1578 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001579 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001580 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001581 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001582 te->addr_read = -1;
1583 }
1584 if (prot & PAGE_EXEC) {
1585 te->addr_code = address;
1586 } else {
1587 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001588 }
bellard67b915a2004-03-31 23:37:16 +00001589 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001590 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1591 (pd & IO_MEM_ROMD)) {
1592 /* write access calls the I/O callback */
1593 te->addr_write = vaddr |
1594 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001595 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001596 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001597 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001598 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001599 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001600 }
1601 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001602 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001603 }
1604 }
1605#if !defined(CONFIG_SOFTMMU)
1606 else {
1607 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1608 /* IO access: no mapping is done as it will be handled by the
1609 soft MMU */
1610 if (!(env->hflags & HF_SOFTMMU_MASK))
1611 ret = 2;
1612 } else {
1613 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001614
bellard59817cc2004-02-16 22:01:13 +00001615 if (vaddr >= MMAP_AREA_END) {
1616 ret = 2;
1617 } else {
1618 if (prot & PROT_WRITE) {
1619 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001620#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001621 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001622#endif
bellard59817cc2004-02-16 22:01:13 +00001623 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1624 !cpu_physical_memory_is_dirty(pd))) {
1625 /* ROM: we do as if code was inside */
1626 /* if code is present, we only map as read only and save the
1627 original mapping */
1628 VirtPageDesc *vp;
1629
bellard90f18422005-07-24 10:17:31 +00001630 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001631 vp->phys_addr = pd;
1632 vp->prot = prot;
1633 vp->valid_tag = virt_valid_tag;
1634 prot &= ~PAGE_WRITE;
1635 }
bellard9fa3e852004-01-04 18:06:42 +00001636 }
bellard59817cc2004-02-16 22:01:13 +00001637 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1638 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1639 if (map_addr == MAP_FAILED) {
1640 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1641 paddr, vaddr);
1642 }
bellard9fa3e852004-01-04 18:06:42 +00001643 }
1644 }
1645 }
1646#endif
1647 return ret;
1648}
1649
1650/* called from signal handler: invalidate the code and unprotect the
1651 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001652int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001653{
1654#if !defined(CONFIG_SOFTMMU)
1655 VirtPageDesc *vp;
1656
1657#if defined(DEBUG_TLB)
1658 printf("page_unprotect: addr=0x%08x\n", addr);
1659#endif
1660 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001661
1662 /* if it is not mapped, no need to worry here */
1663 if (addr >= MMAP_AREA_END)
1664 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001665 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1666 if (!vp)
1667 return 0;
1668 /* NOTE: in this case, validate_tag is _not_ tested as it
1669 validates only the code TLB */
1670 if (vp->valid_tag != virt_valid_tag)
1671 return 0;
1672 if (!(vp->prot & PAGE_WRITE))
1673 return 0;
1674#if defined(DEBUG_TLB)
1675 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1676 addr, vp->phys_addr, vp->prot);
1677#endif
bellard59817cc2004-02-16 22:01:13 +00001678 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1679 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1680 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001681 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001682 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001683 /* flush the code inside */
1684 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001685 return 1;
1686#else
1687 return 0;
1688#endif
bellard33417e72003-08-10 21:47:01 +00001689}
1690
bellard01243112004-01-04 15:48:17 +00001691#else
1692
bellardee8b7022004-02-03 23:35:10 +00001693void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001694{
1695}
1696
bellard2e126692004-04-25 21:28:44 +00001697void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001698{
1699}
1700
bellard84b7b8e2005-11-28 21:19:04 +00001701int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1702 target_phys_addr_t paddr, int prot,
1703 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001704{
bellard9fa3e852004-01-04 18:06:42 +00001705 return 0;
1706}
bellard33417e72003-08-10 21:47:01 +00001707
bellard9fa3e852004-01-04 18:06:42 +00001708/* dump memory mappings */
1709void page_dump(FILE *f)
1710{
1711 unsigned long start, end;
1712 int i, j, prot, prot1;
1713 PageDesc *p;
1714
1715 fprintf(f, "%-8s %-8s %-8s %s\n",
1716 "start", "end", "size", "prot");
1717 start = -1;
1718 end = -1;
1719 prot = 0;
1720 for(i = 0; i <= L1_SIZE; i++) {
1721 if (i < L1_SIZE)
1722 p = l1_map[i];
1723 else
1724 p = NULL;
1725 for(j = 0;j < L2_SIZE; j++) {
1726 if (!p)
1727 prot1 = 0;
1728 else
1729 prot1 = p[j].flags;
1730 if (prot1 != prot) {
1731 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1732 if (start != -1) {
1733 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1734 start, end, end - start,
1735 prot & PAGE_READ ? 'r' : '-',
1736 prot & PAGE_WRITE ? 'w' : '-',
1737 prot & PAGE_EXEC ? 'x' : '-');
1738 }
1739 if (prot1 != 0)
1740 start = end;
1741 else
1742 start = -1;
1743 prot = prot1;
1744 }
1745 if (!p)
1746 break;
1747 }
bellard33417e72003-08-10 21:47:01 +00001748 }
bellard33417e72003-08-10 21:47:01 +00001749}
1750
pbrook53a59602006-03-25 19:31:22 +00001751int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001752{
bellard9fa3e852004-01-04 18:06:42 +00001753 PageDesc *p;
1754
1755 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001756 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001757 return 0;
1758 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001759}
1760
bellard9fa3e852004-01-04 18:06:42 +00001761/* modify the flags of a page and invalidate the code if
1762 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1763 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001764void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001765{
1766 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001767 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001768
1769 start = start & TARGET_PAGE_MASK;
1770 end = TARGET_PAGE_ALIGN(end);
1771 if (flags & PAGE_WRITE)
1772 flags |= PAGE_WRITE_ORG;
1773 spin_lock(&tb_lock);
1774 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1775 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1776 /* if the write protection is set, then we invalidate the code
1777 inside */
1778 if (!(p->flags & PAGE_WRITE) &&
1779 (flags & PAGE_WRITE) &&
1780 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001781 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001782 }
1783 p->flags = flags;
1784 }
1785 spin_unlock(&tb_lock);
1786}
1787
1788/* called from signal handler: invalidate the code and unprotect the
1789 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001790int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001791{
1792 unsigned int page_index, prot, pindex;
1793 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001794 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001795
bellard83fb7ad2004-07-05 21:25:26 +00001796 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001797 page_index = host_start >> TARGET_PAGE_BITS;
1798 p1 = page_find(page_index);
1799 if (!p1)
1800 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001801 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001802 p = p1;
1803 prot = 0;
1804 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1805 prot |= p->flags;
1806 p++;
1807 }
1808 /* if the page was really writable, then we change its
1809 protection back to writable */
1810 if (prot & PAGE_WRITE_ORG) {
1811 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1812 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001813 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001814 (prot & PAGE_BITS) | PAGE_WRITE);
1815 p1[pindex].flags |= PAGE_WRITE;
1816 /* and since the content will be modified, we must invalidate
1817 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001818 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001819#ifdef DEBUG_TB_CHECK
1820 tb_invalidate_check(address);
1821#endif
1822 return 1;
1823 }
1824 }
1825 return 0;
1826}
1827
1828/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001829/* ??? This should be redundant now we have lock_user. */
1830void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001831{
pbrook53a59602006-03-25 19:31:22 +00001832 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001833
pbrook53a59602006-03-25 19:31:22 +00001834 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001835 end = start + data_size;
1836 start &= TARGET_PAGE_MASK;
1837 end = TARGET_PAGE_ALIGN(end);
1838 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001839 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001840 }
1841}
1842
bellard6a00d602005-11-21 23:25:50 +00001843static inline void tlb_set_dirty(CPUState *env,
1844 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001845{
1846}
bellard9fa3e852004-01-04 18:06:42 +00001847#endif /* defined(CONFIG_USER_ONLY) */
1848
bellard33417e72003-08-10 21:47:01 +00001849/* register physical memory. 'size' must be a multiple of the target
1850 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1851 io memory page */
bellard2e126692004-04-25 21:28:44 +00001852void cpu_register_physical_memory(target_phys_addr_t start_addr,
1853 unsigned long size,
1854 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001855{
bellard108c49b2005-07-24 12:55:09 +00001856 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001857 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001858 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001859
bellard5fd386f2004-05-23 21:11:22 +00001860 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001861 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001862 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001863 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001864 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001865 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1866 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001867 phys_offset += TARGET_PAGE_SIZE;
1868 }
bellard9d420372006-06-25 22:25:22 +00001869
1870 /* since each CPU stores ram addresses in its TLB cache, we must
1871 reset the modified entries */
1872 /* XXX: slow ! */
1873 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1874 tlb_flush(env, 1);
1875 }
bellard33417e72003-08-10 21:47:01 +00001876}
1877
bellardba863452006-09-24 18:41:10 +00001878/* XXX: temporary until new memory mapping API */
1879uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1880{
1881 PhysPageDesc *p;
1882
1883 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1884 if (!p)
1885 return IO_MEM_UNASSIGNED;
1886 return p->phys_offset;
1887}
1888
bellarde9a1ab12007-02-08 23:08:38 +00001889/* XXX: better than nothing */
1890ram_addr_t qemu_ram_alloc(unsigned int size)
1891{
1892 ram_addr_t addr;
1893 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1894 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
1895 size, phys_ram_size);
1896 abort();
1897 }
1898 addr = phys_ram_alloc_offset;
1899 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1900 return addr;
1901}
1902
1903void qemu_ram_free(ram_addr_t addr)
1904{
1905}
1906
bellarda4193c82004-06-03 14:01:43 +00001907static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001908{
pbrook67d3b952006-12-18 05:03:52 +00001909#ifdef DEBUG_UNASSIGNED
1910 printf("Unassigned mem read 0x%08x\n", (int)addr);
1911#endif
bellard33417e72003-08-10 21:47:01 +00001912 return 0;
1913}
1914
bellarda4193c82004-06-03 14:01:43 +00001915static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001916{
pbrook67d3b952006-12-18 05:03:52 +00001917#ifdef DEBUG_UNASSIGNED
1918 printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
1919#endif
bellard33417e72003-08-10 21:47:01 +00001920}
1921
1922static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1923 unassigned_mem_readb,
1924 unassigned_mem_readb,
1925 unassigned_mem_readb,
1926};
1927
1928static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1929 unassigned_mem_writeb,
1930 unassigned_mem_writeb,
1931 unassigned_mem_writeb,
1932};
1933
bellarda4193c82004-06-03 14:01:43 +00001934static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001935{
bellard3a7d9292005-08-21 09:26:42 +00001936 unsigned long ram_addr;
1937 int dirty_flags;
1938 ram_addr = addr - (unsigned long)phys_ram_base;
1939 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1940 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1941#if !defined(CONFIG_USER_ONLY)
1942 tb_invalidate_phys_page_fast(ram_addr, 1);
1943 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1944#endif
1945 }
bellardc27004e2005-01-03 23:35:10 +00001946 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001947#ifdef USE_KQEMU
1948 if (cpu_single_env->kqemu_enabled &&
1949 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1950 kqemu_modify_page(cpu_single_env, ram_addr);
1951#endif
bellardf23db162005-08-21 19:12:28 +00001952 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1953 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1954 /* we remove the notdirty callback only if the code has been
1955 flushed */
1956 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001957 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001958}
1959
bellarda4193c82004-06-03 14:01:43 +00001960static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001961{
bellard3a7d9292005-08-21 09:26:42 +00001962 unsigned long ram_addr;
1963 int dirty_flags;
1964 ram_addr = addr - (unsigned long)phys_ram_base;
1965 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1966 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1967#if !defined(CONFIG_USER_ONLY)
1968 tb_invalidate_phys_page_fast(ram_addr, 2);
1969 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1970#endif
1971 }
bellardc27004e2005-01-03 23:35:10 +00001972 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001973#ifdef USE_KQEMU
1974 if (cpu_single_env->kqemu_enabled &&
1975 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1976 kqemu_modify_page(cpu_single_env, ram_addr);
1977#endif
bellardf23db162005-08-21 19:12:28 +00001978 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1979 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1980 /* we remove the notdirty callback only if the code has been
1981 flushed */
1982 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001983 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001984}
1985
bellarda4193c82004-06-03 14:01:43 +00001986static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001987{
bellard3a7d9292005-08-21 09:26:42 +00001988 unsigned long ram_addr;
1989 int dirty_flags;
1990 ram_addr = addr - (unsigned long)phys_ram_base;
1991 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1992 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1993#if !defined(CONFIG_USER_ONLY)
1994 tb_invalidate_phys_page_fast(ram_addr, 4);
1995 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1996#endif
1997 }
bellardc27004e2005-01-03 23:35:10 +00001998 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001999#ifdef USE_KQEMU
2000 if (cpu_single_env->kqemu_enabled &&
2001 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2002 kqemu_modify_page(cpu_single_env, ram_addr);
2003#endif
bellardf23db162005-08-21 19:12:28 +00002004 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2005 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2006 /* we remove the notdirty callback only if the code has been
2007 flushed */
2008 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002009 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002010}
2011
bellard3a7d9292005-08-21 09:26:42 +00002012static CPUReadMemoryFunc *error_mem_read[3] = {
2013 NULL, /* never used */
2014 NULL, /* never used */
2015 NULL, /* never used */
2016};
2017
bellard1ccde1c2004-02-06 19:46:14 +00002018static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2019 notdirty_mem_writeb,
2020 notdirty_mem_writew,
2021 notdirty_mem_writel,
2022};
2023
pbrook6658ffb2007-03-16 23:58:11 +00002024#if defined(CONFIG_SOFTMMU)
2025/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2026 so these check for a hit then pass through to the normal out-of-line
2027 phys routines. */
2028static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2029{
2030 return ldub_phys(addr);
2031}
2032
2033static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2034{
2035 return lduw_phys(addr);
2036}
2037
2038static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2039{
2040 return ldl_phys(addr);
2041}
2042
2043/* Generate a debug exception if a watchpoint has been hit.
2044 Returns the real physical address of the access. addr will be a host
2045 address in the is_ram case. */
2046static target_ulong check_watchpoint(target_phys_addr_t addr)
2047{
2048 CPUState *env = cpu_single_env;
2049 target_ulong watch;
2050 target_ulong retaddr;
2051 int i;
2052
2053 retaddr = addr;
2054 for (i = 0; i < env->nb_watchpoints; i++) {
2055 watch = env->watchpoint[i].vaddr;
2056 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
2057 if (env->watchpoint[i].is_ram)
2058 retaddr = addr - (unsigned long)phys_ram_base;
2059 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2060 cpu_single_env->watchpoint_hit = i + 1;
2061 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2062 break;
2063 }
2064 }
2065 }
2066 return retaddr;
2067}
2068
2069static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2070 uint32_t val)
2071{
2072 addr = check_watchpoint(addr);
2073 stb_phys(addr, val);
2074}
2075
2076static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2077 uint32_t val)
2078{
2079 addr = check_watchpoint(addr);
2080 stw_phys(addr, val);
2081}
2082
2083static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2084 uint32_t val)
2085{
2086 addr = check_watchpoint(addr);
2087 stl_phys(addr, val);
2088}
2089
2090static CPUReadMemoryFunc *watch_mem_read[3] = {
2091 watch_mem_readb,
2092 watch_mem_readw,
2093 watch_mem_readl,
2094};
2095
2096static CPUWriteMemoryFunc *watch_mem_write[3] = {
2097 watch_mem_writeb,
2098 watch_mem_writew,
2099 watch_mem_writel,
2100};
2101#endif
2102
bellard33417e72003-08-10 21:47:01 +00002103static void io_mem_init(void)
2104{
bellard3a7d9292005-08-21 09:26:42 +00002105 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002106 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002107 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002108 io_mem_nb = 5;
2109
pbrook6658ffb2007-03-16 23:58:11 +00002110#if defined(CONFIG_SOFTMMU)
2111 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2112 watch_mem_write, NULL);
2113#endif
bellard1ccde1c2004-02-06 19:46:14 +00002114 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002115 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002116 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002117}
2118
2119/* mem_read and mem_write are arrays of functions containing the
2120 function to access byte (index 0), word (index 1) and dword (index
2121 2). All functions must be supplied. If io_index is non zero, the
2122 corresponding io zone is modified. If it is zero, a new io zone is
2123 allocated. The return value can be used with
2124 cpu_register_physical_memory(). (-1) is returned if error. */
2125int cpu_register_io_memory(int io_index,
2126 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002127 CPUWriteMemoryFunc **mem_write,
2128 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002129{
2130 int i;
2131
2132 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002133 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002134 return -1;
2135 io_index = io_mem_nb++;
2136 } else {
2137 if (io_index >= IO_MEM_NB_ENTRIES)
2138 return -1;
2139 }
bellardb5ff1b32005-11-26 10:38:39 +00002140
bellard33417e72003-08-10 21:47:01 +00002141 for(i = 0;i < 3; i++) {
2142 io_mem_read[io_index][i] = mem_read[i];
2143 io_mem_write[io_index][i] = mem_write[i];
2144 }
bellarda4193c82004-06-03 14:01:43 +00002145 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002146 return io_index << IO_MEM_SHIFT;
2147}
bellard61382a52003-10-27 21:22:23 +00002148
bellard8926b512004-10-10 15:14:20 +00002149CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2150{
2151 return io_mem_write[io_index >> IO_MEM_SHIFT];
2152}
2153
2154CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2155{
2156 return io_mem_read[io_index >> IO_MEM_SHIFT];
2157}
2158
bellard13eb76e2004-01-24 15:23:36 +00002159/* physical memory access (slow version, mainly for debug) */
2160#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002161void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002162 int len, int is_write)
2163{
2164 int l, flags;
2165 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002166 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002167
2168 while (len > 0) {
2169 page = addr & TARGET_PAGE_MASK;
2170 l = (page + TARGET_PAGE_SIZE) - addr;
2171 if (l > len)
2172 l = len;
2173 flags = page_get_flags(page);
2174 if (!(flags & PAGE_VALID))
2175 return;
2176 if (is_write) {
2177 if (!(flags & PAGE_WRITE))
2178 return;
pbrook53a59602006-03-25 19:31:22 +00002179 p = lock_user(addr, len, 0);
2180 memcpy(p, buf, len);
2181 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002182 } else {
2183 if (!(flags & PAGE_READ))
2184 return;
pbrook53a59602006-03-25 19:31:22 +00002185 p = lock_user(addr, len, 1);
2186 memcpy(buf, p, len);
2187 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002188 }
2189 len -= l;
2190 buf += l;
2191 addr += l;
2192 }
2193}
bellard8df1cd02005-01-28 22:37:22 +00002194
bellard13eb76e2004-01-24 15:23:36 +00002195#else
bellard2e126692004-04-25 21:28:44 +00002196void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002197 int len, int is_write)
2198{
2199 int l, io_index;
2200 uint8_t *ptr;
2201 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002202 target_phys_addr_t page;
2203 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002204 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002205
2206 while (len > 0) {
2207 page = addr & TARGET_PAGE_MASK;
2208 l = (page + TARGET_PAGE_SIZE) - addr;
2209 if (l > len)
2210 l = len;
bellard92e873b2004-05-21 14:52:29 +00002211 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002212 if (!p) {
2213 pd = IO_MEM_UNASSIGNED;
2214 } else {
2215 pd = p->phys_offset;
2216 }
2217
2218 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002219 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002220 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002221 /* XXX: could force cpu_single_env to NULL to avoid
2222 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002223 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002224 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002225 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002226 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002227 l = 4;
2228 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002229 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002230 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002231 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002232 l = 2;
2233 } else {
bellard1c213d12005-09-03 10:49:04 +00002234 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002235 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002236 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002237 l = 1;
2238 }
2239 } else {
bellardb448f2f2004-02-25 23:24:04 +00002240 unsigned long addr1;
2241 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002242 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002243 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002244 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002245 if (!cpu_physical_memory_is_dirty(addr1)) {
2246 /* invalidate code */
2247 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2248 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002249 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2250 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002251 }
bellard13eb76e2004-01-24 15:23:36 +00002252 }
2253 } else {
bellard2a4188a2006-06-25 21:54:59 +00002254 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2255 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002256 /* I/O case */
2257 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2258 if (l >= 4 && ((addr & 3) == 0)) {
2259 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002260 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002261 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002262 l = 4;
2263 } else if (l >= 2 && ((addr & 1) == 0)) {
2264 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002265 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002266 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002267 l = 2;
2268 } else {
bellard1c213d12005-09-03 10:49:04 +00002269 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002270 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002271 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002272 l = 1;
2273 }
2274 } else {
2275 /* RAM case */
2276 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2277 (addr & ~TARGET_PAGE_MASK);
2278 memcpy(buf, ptr, l);
2279 }
2280 }
2281 len -= l;
2282 buf += l;
2283 addr += l;
2284 }
2285}
bellard8df1cd02005-01-28 22:37:22 +00002286
bellardd0ecd2a2006-04-23 17:14:48 +00002287/* used for ROM loading : can write in RAM and ROM */
2288void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2289 const uint8_t *buf, int len)
2290{
2291 int l;
2292 uint8_t *ptr;
2293 target_phys_addr_t page;
2294 unsigned long pd;
2295 PhysPageDesc *p;
2296
2297 while (len > 0) {
2298 page = addr & TARGET_PAGE_MASK;
2299 l = (page + TARGET_PAGE_SIZE) - addr;
2300 if (l > len)
2301 l = len;
2302 p = phys_page_find(page >> TARGET_PAGE_BITS);
2303 if (!p) {
2304 pd = IO_MEM_UNASSIGNED;
2305 } else {
2306 pd = p->phys_offset;
2307 }
2308
2309 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002310 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2311 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002312 /* do nothing */
2313 } else {
2314 unsigned long addr1;
2315 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2316 /* ROM/RAM case */
2317 ptr = phys_ram_base + addr1;
2318 memcpy(ptr, buf, l);
2319 }
2320 len -= l;
2321 buf += l;
2322 addr += l;
2323 }
2324}
2325
2326
bellard8df1cd02005-01-28 22:37:22 +00002327/* warning: addr must be aligned */
2328uint32_t ldl_phys(target_phys_addr_t addr)
2329{
2330 int io_index;
2331 uint8_t *ptr;
2332 uint32_t val;
2333 unsigned long pd;
2334 PhysPageDesc *p;
2335
2336 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2337 if (!p) {
2338 pd = IO_MEM_UNASSIGNED;
2339 } else {
2340 pd = p->phys_offset;
2341 }
2342
bellard2a4188a2006-06-25 21:54:59 +00002343 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2344 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002345 /* I/O case */
2346 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2347 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2348 } else {
2349 /* RAM case */
2350 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2351 (addr & ~TARGET_PAGE_MASK);
2352 val = ldl_p(ptr);
2353 }
2354 return val;
2355}
2356
bellard84b7b8e2005-11-28 21:19:04 +00002357/* warning: addr must be aligned */
2358uint64_t ldq_phys(target_phys_addr_t addr)
2359{
2360 int io_index;
2361 uint8_t *ptr;
2362 uint64_t val;
2363 unsigned long pd;
2364 PhysPageDesc *p;
2365
2366 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2367 if (!p) {
2368 pd = IO_MEM_UNASSIGNED;
2369 } else {
2370 pd = p->phys_offset;
2371 }
2372
bellard2a4188a2006-06-25 21:54:59 +00002373 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2374 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002375 /* I/O case */
2376 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2377#ifdef TARGET_WORDS_BIGENDIAN
2378 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2379 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2380#else
2381 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2382 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2383#endif
2384 } else {
2385 /* RAM case */
2386 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2387 (addr & ~TARGET_PAGE_MASK);
2388 val = ldq_p(ptr);
2389 }
2390 return val;
2391}
2392
bellardaab33092005-10-30 20:48:42 +00002393/* XXX: optimize */
2394uint32_t ldub_phys(target_phys_addr_t addr)
2395{
2396 uint8_t val;
2397 cpu_physical_memory_read(addr, &val, 1);
2398 return val;
2399}
2400
2401/* XXX: optimize */
2402uint32_t lduw_phys(target_phys_addr_t addr)
2403{
2404 uint16_t val;
2405 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2406 return tswap16(val);
2407}
2408
bellard8df1cd02005-01-28 22:37:22 +00002409/* warning: addr must be aligned. The ram page is not masked as dirty
2410 and the code inside is not invalidated. It is useful if the dirty
2411 bits are used to track modified PTEs */
2412void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2413{
2414 int io_index;
2415 uint8_t *ptr;
2416 unsigned long pd;
2417 PhysPageDesc *p;
2418
2419 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2420 if (!p) {
2421 pd = IO_MEM_UNASSIGNED;
2422 } else {
2423 pd = p->phys_offset;
2424 }
2425
bellard3a7d9292005-08-21 09:26:42 +00002426 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002427 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2428 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2429 } else {
2430 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2431 (addr & ~TARGET_PAGE_MASK);
2432 stl_p(ptr, val);
2433 }
2434}
2435
j_mayerbc98a7e2007-04-04 07:55:12 +00002436void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2437{
2438 int io_index;
2439 uint8_t *ptr;
2440 unsigned long pd;
2441 PhysPageDesc *p;
2442
2443 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2444 if (!p) {
2445 pd = IO_MEM_UNASSIGNED;
2446 } else {
2447 pd = p->phys_offset;
2448 }
2449
2450 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2451 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2452#ifdef TARGET_WORDS_BIGENDIAN
2453 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2454 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2455#else
2456 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2457 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2458#endif
2459 } else {
2460 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2461 (addr & ~TARGET_PAGE_MASK);
2462 stq_p(ptr, val);
2463 }
2464}
2465
bellard8df1cd02005-01-28 22:37:22 +00002466/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002467void stl_phys(target_phys_addr_t addr, uint32_t val)
2468{
2469 int io_index;
2470 uint8_t *ptr;
2471 unsigned long pd;
2472 PhysPageDesc *p;
2473
2474 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2475 if (!p) {
2476 pd = IO_MEM_UNASSIGNED;
2477 } else {
2478 pd = p->phys_offset;
2479 }
2480
bellard3a7d9292005-08-21 09:26:42 +00002481 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002482 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2483 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2484 } else {
2485 unsigned long addr1;
2486 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2487 /* RAM case */
2488 ptr = phys_ram_base + addr1;
2489 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002490 if (!cpu_physical_memory_is_dirty(addr1)) {
2491 /* invalidate code */
2492 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2493 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002494 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2495 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002496 }
bellard8df1cd02005-01-28 22:37:22 +00002497 }
2498}
2499
bellardaab33092005-10-30 20:48:42 +00002500/* XXX: optimize */
2501void stb_phys(target_phys_addr_t addr, uint32_t val)
2502{
2503 uint8_t v = val;
2504 cpu_physical_memory_write(addr, &v, 1);
2505}
2506
2507/* XXX: optimize */
2508void stw_phys(target_phys_addr_t addr, uint32_t val)
2509{
2510 uint16_t v = tswap16(val);
2511 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2512}
2513
2514/* XXX: optimize */
2515void stq_phys(target_phys_addr_t addr, uint64_t val)
2516{
2517 val = tswap64(val);
2518 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2519}
2520
bellard13eb76e2004-01-24 15:23:36 +00002521#endif
2522
2523/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002524int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2525 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002526{
2527 int l;
2528 target_ulong page, phys_addr;
2529
2530 while (len > 0) {
2531 page = addr & TARGET_PAGE_MASK;
2532 phys_addr = cpu_get_phys_page_debug(env, page);
2533 /* if no physical page mapped, return an error */
2534 if (phys_addr == -1)
2535 return -1;
2536 l = (page + TARGET_PAGE_SIZE) - addr;
2537 if (l > len)
2538 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002539 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2540 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002541 len -= l;
2542 buf += l;
2543 addr += l;
2544 }
2545 return 0;
2546}
2547
bellarde3db7222005-01-26 22:00:47 +00002548void dump_exec_info(FILE *f,
2549 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2550{
2551 int i, target_code_size, max_target_code_size;
2552 int direct_jmp_count, direct_jmp2_count, cross_page;
2553 TranslationBlock *tb;
2554
2555 target_code_size = 0;
2556 max_target_code_size = 0;
2557 cross_page = 0;
2558 direct_jmp_count = 0;
2559 direct_jmp2_count = 0;
2560 for(i = 0; i < nb_tbs; i++) {
2561 tb = &tbs[i];
2562 target_code_size += tb->size;
2563 if (tb->size > max_target_code_size)
2564 max_target_code_size = tb->size;
2565 if (tb->page_addr[1] != -1)
2566 cross_page++;
2567 if (tb->tb_next_offset[0] != 0xffff) {
2568 direct_jmp_count++;
2569 if (tb->tb_next_offset[1] != 0xffff) {
2570 direct_jmp2_count++;
2571 }
2572 }
2573 }
2574 /* XXX: avoid using doubles ? */
2575 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2576 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2577 nb_tbs ? target_code_size / nb_tbs : 0,
2578 max_target_code_size);
2579 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2580 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2581 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2582 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2583 cross_page,
2584 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2585 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2586 direct_jmp_count,
2587 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2588 direct_jmp2_count,
2589 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2590 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2591 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2592 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2593}
2594
bellard61382a52003-10-27 21:22:23 +00002595#if !defined(CONFIG_USER_ONLY)
2596
2597#define MMUSUFFIX _cmmu
2598#define GETPC() NULL
2599#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002600#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002601
2602#define SHIFT 0
2603#include "softmmu_template.h"
2604
2605#define SHIFT 1
2606#include "softmmu_template.h"
2607
2608#define SHIFT 2
2609#include "softmmu_template.h"
2610
2611#define SHIFT 3
2612#include "softmmu_template.h"
2613
2614#undef env
2615
2616#endif