blob: 70ad14dc1fb9c603c314283eaece804cb6c07f56 [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000037
bellardfd6ce8f2003-05-14 19:00:11 +000038//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000039//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000040//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000041
42/* make various TB consistency checks */
43//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000044//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* threshold to flush the translated code buffer */
47#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
48
bellard9fa3e852004-01-04 18:06:42 +000049#define SMC_BITMAP_USE_THRESHOLD 10
50
51#define MMAP_AREA_START 0x00000000
52#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000053
bellard108c49b2005-07-24 12:55:09 +000054#if defined(TARGET_SPARC64)
55#define TARGET_PHYS_ADDR_SPACE_BITS 41
56#elif defined(TARGET_PPC64)
57#define TARGET_PHYS_ADDR_SPACE_BITS 42
58#else
59/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
60#define TARGET_PHYS_ADDR_SPACE_BITS 32
61#endif
62
bellardfd6ce8f2003-05-14 19:00:11 +000063TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000064TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000065int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000066/* any access to the tbs or the page table must use this lock */
67spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000068
bellardb8076a72005-04-07 22:20:31 +000069uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000070uint8_t *code_gen_ptr;
71
bellard9fa3e852004-01-04 18:06:42 +000072int phys_ram_size;
73int phys_ram_fd;
74uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000075uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000076
bellard6a00d602005-11-21 23:25:50 +000077CPUState *first_cpu;
78/* current CPU in the current thread. It is only valid inside
79 cpu_exec() */
80CPUState *cpu_single_env;
81
bellard54936002003-05-13 00:25:15 +000082typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000083 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000084 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000085 /* in order to optimize self modifying code, we count the number
86 of lookups we do to a given page to use a bitmap */
87 unsigned int code_write_count;
88 uint8_t *code_bitmap;
89#if defined(CONFIG_USER_ONLY)
90 unsigned long flags;
91#endif
bellard54936002003-05-13 00:25:15 +000092} PageDesc;
93
bellard92e873b2004-05-21 14:52:29 +000094typedef struct PhysPageDesc {
95 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +000096 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +000097} PhysPageDesc;
98
bellard54936002003-05-13 00:25:15 +000099#define L2_BITS 10
100#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
101
102#define L1_SIZE (1 << L1_BITS)
103#define L2_SIZE (1 << L2_BITS)
104
bellard33417e72003-08-10 21:47:01 +0000105static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000106
bellard83fb7ad2004-07-05 21:25:26 +0000107unsigned long qemu_real_host_page_size;
108unsigned long qemu_host_page_bits;
109unsigned long qemu_host_page_size;
110unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000111
bellard92e873b2004-05-21 14:52:29 +0000112/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000113static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000114PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000115
bellard33417e72003-08-10 21:47:01 +0000116/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000117CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
118CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000119void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000120static int io_mem_nb;
121
bellard34865132003-10-05 14:28:56 +0000122/* log support */
123char *logfilename = "/tmp/qemu.log";
124FILE *logfile;
125int loglevel;
126
bellarde3db7222005-01-26 22:00:47 +0000127/* statistics */
128static int tlb_flush_count;
129static int tb_flush_count;
130static int tb_phys_invalidate_count;
131
bellardb346ff42003-06-15 20:05:50 +0000132static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000133{
bellard83fb7ad2004-07-05 21:25:26 +0000134 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000135 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000136#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000137 {
138 SYSTEM_INFO system_info;
139 DWORD old_protect;
140
141 GetSystemInfo(&system_info);
142 qemu_real_host_page_size = system_info.dwPageSize;
143
144 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
145 PAGE_EXECUTE_READWRITE, &old_protect);
146 }
bellard67b915a2004-03-31 23:37:16 +0000147#else
bellard83fb7ad2004-07-05 21:25:26 +0000148 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000149 {
150 unsigned long start, end;
151
152 start = (unsigned long)code_gen_buffer;
153 start &= ~(qemu_real_host_page_size - 1);
154
155 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
156 end += qemu_real_host_page_size - 1;
157 end &= ~(qemu_real_host_page_size - 1);
158
159 mprotect((void *)start, end - start,
160 PROT_READ | PROT_WRITE | PROT_EXEC);
161 }
bellard67b915a2004-03-31 23:37:16 +0000162#endif
bellardd5a8f072004-09-29 21:15:28 +0000163
bellard83fb7ad2004-07-05 21:25:26 +0000164 if (qemu_host_page_size == 0)
165 qemu_host_page_size = qemu_real_host_page_size;
166 if (qemu_host_page_size < TARGET_PAGE_SIZE)
167 qemu_host_page_size = TARGET_PAGE_SIZE;
168 qemu_host_page_bits = 0;
169 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
170 qemu_host_page_bits++;
171 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000172 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
173 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000174}
175
bellardfd6ce8f2003-05-14 19:00:11 +0000176static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000177{
bellard54936002003-05-13 00:25:15 +0000178 PageDesc **lp, *p;
179
bellard54936002003-05-13 00:25:15 +0000180 lp = &l1_map[index >> L2_BITS];
181 p = *lp;
182 if (!p) {
183 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000184 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000185 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000186 *lp = p;
187 }
188 return p + (index & (L2_SIZE - 1));
189}
190
bellardfd6ce8f2003-05-14 19:00:11 +0000191static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000192{
bellard54936002003-05-13 00:25:15 +0000193 PageDesc *p;
194
bellard54936002003-05-13 00:25:15 +0000195 p = l1_map[index >> L2_BITS];
196 if (!p)
197 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000198 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000199}
200
bellard108c49b2005-07-24 12:55:09 +0000201static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000202{
bellard108c49b2005-07-24 12:55:09 +0000203 void **lp, **p;
bellard92e873b2004-05-21 14:52:29 +0000204
bellard108c49b2005-07-24 12:55:09 +0000205 p = (void **)l1_phys_map;
206#if TARGET_PHYS_ADDR_SPACE_BITS > 32
207
208#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
209#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
210#endif
211 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000212 p = *lp;
213 if (!p) {
214 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000215 if (!alloc)
216 return NULL;
217 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
218 memset(p, 0, sizeof(void *) * L1_SIZE);
219 *lp = p;
220 }
221#endif
222 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
223 p = *lp;
224 if (!p) {
225 /* allocate if not found */
226 if (!alloc)
227 return NULL;
bellard0a962c02005-02-10 22:00:27 +0000228 p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
bellard92e873b2004-05-21 14:52:29 +0000229 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
230 *lp = p;
231 }
bellard108c49b2005-07-24 12:55:09 +0000232 return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000233}
234
bellard108c49b2005-07-24 12:55:09 +0000235static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000236{
bellard108c49b2005-07-24 12:55:09 +0000237 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000238}
239
bellard9fa3e852004-01-04 18:06:42 +0000240#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000241static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000242static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
243 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000244#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000245
bellard6a00d602005-11-21 23:25:50 +0000246void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000247{
bellard6a00d602005-11-21 23:25:50 +0000248 CPUState **penv;
249 int cpu_index;
250
bellardfd6ce8f2003-05-14 19:00:11 +0000251 if (!code_gen_ptr) {
252 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000253 page_init();
bellard33417e72003-08-10 21:47:01 +0000254 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000255 }
bellard6a00d602005-11-21 23:25:50 +0000256 env->next_cpu = NULL;
257 penv = &first_cpu;
258 cpu_index = 0;
259 while (*penv != NULL) {
260 penv = (CPUState **)&(*penv)->next_cpu;
261 cpu_index++;
262 }
263 env->cpu_index = cpu_index;
264 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000265}
266
bellard9fa3e852004-01-04 18:06:42 +0000267static inline void invalidate_page_bitmap(PageDesc *p)
268{
269 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000270 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000271 p->code_bitmap = NULL;
272 }
273 p->code_write_count = 0;
274}
275
bellardfd6ce8f2003-05-14 19:00:11 +0000276/* set to NULL all the 'first_tb' fields in all PageDescs */
277static void page_flush_tb(void)
278{
279 int i, j;
280 PageDesc *p;
281
282 for(i = 0; i < L1_SIZE; i++) {
283 p = l1_map[i];
284 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000285 for(j = 0; j < L2_SIZE; j++) {
286 p->first_tb = NULL;
287 invalidate_page_bitmap(p);
288 p++;
289 }
bellardfd6ce8f2003-05-14 19:00:11 +0000290 }
291 }
292}
293
294/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000295/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000296void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000297{
bellard6a00d602005-11-21 23:25:50 +0000298 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000299#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000300 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
301 code_gen_ptr - code_gen_buffer,
302 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000303 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000304#endif
305 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000306
307 for(env = first_cpu; env != NULL; env = env->next_cpu) {
308 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
309 }
bellard9fa3e852004-01-04 18:06:42 +0000310
bellard8a8a6082004-10-03 13:36:49 +0000311 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000312 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000313
bellardfd6ce8f2003-05-14 19:00:11 +0000314 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000315 /* XXX: flush processor icache at this point if cache flush is
316 expensive */
bellarde3db7222005-01-26 22:00:47 +0000317 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000318}
319
320#ifdef DEBUG_TB_CHECK
321
322static void tb_invalidate_check(unsigned long address)
323{
324 TranslationBlock *tb;
325 int i;
326 address &= TARGET_PAGE_MASK;
327 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
328 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
329 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
330 address >= tb->pc + tb->size)) {
331 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
332 address, tb->pc, tb->size);
333 }
334 }
335 }
336}
337
338/* verify that all the pages have correct rights for code */
339static void tb_page_check(void)
340{
341 TranslationBlock *tb;
342 int i, flags1, flags2;
343
344 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
345 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
346 flags1 = page_get_flags(tb->pc);
347 flags2 = page_get_flags(tb->pc + tb->size - 1);
348 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
349 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
350 tb->pc, tb->size, flags1, flags2);
351 }
352 }
353 }
354}
355
bellardd4e81642003-05-25 16:46:15 +0000356void tb_jmp_check(TranslationBlock *tb)
357{
358 TranslationBlock *tb1;
359 unsigned int n1;
360
361 /* suppress any remaining jumps to this TB */
362 tb1 = tb->jmp_first;
363 for(;;) {
364 n1 = (long)tb1 & 3;
365 tb1 = (TranslationBlock *)((long)tb1 & ~3);
366 if (n1 == 2)
367 break;
368 tb1 = tb1->jmp_next[n1];
369 }
370 /* check end of list */
371 if (tb1 != tb) {
372 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
373 }
374}
375
bellardfd6ce8f2003-05-14 19:00:11 +0000376#endif
377
378/* invalidate one TB */
379static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
380 int next_offset)
381{
382 TranslationBlock *tb1;
383 for(;;) {
384 tb1 = *ptb;
385 if (tb1 == tb) {
386 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
387 break;
388 }
389 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
390 }
391}
392
bellard9fa3e852004-01-04 18:06:42 +0000393static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
394{
395 TranslationBlock *tb1;
396 unsigned int n1;
397
398 for(;;) {
399 tb1 = *ptb;
400 n1 = (long)tb1 & 3;
401 tb1 = (TranslationBlock *)((long)tb1 & ~3);
402 if (tb1 == tb) {
403 *ptb = tb1->page_next[n1];
404 break;
405 }
406 ptb = &tb1->page_next[n1];
407 }
408}
409
bellardd4e81642003-05-25 16:46:15 +0000410static inline void tb_jmp_remove(TranslationBlock *tb, int n)
411{
412 TranslationBlock *tb1, **ptb;
413 unsigned int n1;
414
415 ptb = &tb->jmp_next[n];
416 tb1 = *ptb;
417 if (tb1) {
418 /* find tb(n) in circular list */
419 for(;;) {
420 tb1 = *ptb;
421 n1 = (long)tb1 & 3;
422 tb1 = (TranslationBlock *)((long)tb1 & ~3);
423 if (n1 == n && tb1 == tb)
424 break;
425 if (n1 == 2) {
426 ptb = &tb1->jmp_first;
427 } else {
428 ptb = &tb1->jmp_next[n1];
429 }
430 }
431 /* now we can suppress tb(n) from the list */
432 *ptb = tb->jmp_next[n];
433
434 tb->jmp_next[n] = NULL;
435 }
436}
437
438/* reset the jump entry 'n' of a TB so that it is not chained to
439 another TB */
440static inline void tb_reset_jump(TranslationBlock *tb, int n)
441{
442 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
443}
444
bellard9fa3e852004-01-04 18:06:42 +0000445static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000446{
bellard6a00d602005-11-21 23:25:50 +0000447 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000448 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000449 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000450 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000451 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000452
453 /* remove the TB from the hash list */
454 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
455 h = tb_phys_hash_func(phys_pc);
456 tb_remove(&tb_phys_hash[h], tb,
457 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000458
bellard9fa3e852004-01-04 18:06:42 +0000459 /* remove the TB from the page list */
460 if (tb->page_addr[0] != page_addr) {
461 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
462 tb_page_remove(&p->first_tb, tb);
463 invalidate_page_bitmap(p);
464 }
465 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
466 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
467 tb_page_remove(&p->first_tb, tb);
468 invalidate_page_bitmap(p);
469 }
470
bellard8a40a182005-11-20 10:35:40 +0000471 tb_invalidated_flag = 1;
472
473 /* remove the TB from the hash list */
474 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000475 for(env = first_cpu; env != NULL; env = env->next_cpu) {
476 if (env->tb_jmp_cache[h] == tb)
477 env->tb_jmp_cache[h] = NULL;
478 }
bellard8a40a182005-11-20 10:35:40 +0000479
480 /* suppress this TB from the two jump lists */
481 tb_jmp_remove(tb, 0);
482 tb_jmp_remove(tb, 1);
483
484 /* suppress any remaining jumps to this TB */
485 tb1 = tb->jmp_first;
486 for(;;) {
487 n1 = (long)tb1 & 3;
488 if (n1 == 2)
489 break;
490 tb1 = (TranslationBlock *)((long)tb1 & ~3);
491 tb2 = tb1->jmp_next[n1];
492 tb_reset_jump(tb1, n1);
493 tb1->jmp_next[n1] = NULL;
494 tb1 = tb2;
495 }
496 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
497
bellarde3db7222005-01-26 22:00:47 +0000498 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000499}
500
501static inline void set_bits(uint8_t *tab, int start, int len)
502{
503 int end, mask, end1;
504
505 end = start + len;
506 tab += start >> 3;
507 mask = 0xff << (start & 7);
508 if ((start & ~7) == (end & ~7)) {
509 if (start < end) {
510 mask &= ~(0xff << (end & 7));
511 *tab |= mask;
512 }
513 } else {
514 *tab++ |= mask;
515 start = (start + 8) & ~7;
516 end1 = end & ~7;
517 while (start < end1) {
518 *tab++ = 0xff;
519 start += 8;
520 }
521 if (start < end) {
522 mask = ~(0xff << (end & 7));
523 *tab |= mask;
524 }
525 }
526}
527
528static void build_page_bitmap(PageDesc *p)
529{
530 int n, tb_start, tb_end;
531 TranslationBlock *tb;
532
bellard59817cc2004-02-16 22:01:13 +0000533 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000534 if (!p->code_bitmap)
535 return;
536 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
537
538 tb = p->first_tb;
539 while (tb != NULL) {
540 n = (long)tb & 3;
541 tb = (TranslationBlock *)((long)tb & ~3);
542 /* NOTE: this is subtle as a TB may span two physical pages */
543 if (n == 0) {
544 /* NOTE: tb_end may be after the end of the page, but
545 it is not a problem */
546 tb_start = tb->pc & ~TARGET_PAGE_MASK;
547 tb_end = tb_start + tb->size;
548 if (tb_end > TARGET_PAGE_SIZE)
549 tb_end = TARGET_PAGE_SIZE;
550 } else {
551 tb_start = 0;
552 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
553 }
554 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
555 tb = tb->page_next[n];
556 }
557}
558
bellardd720b932004-04-25 17:57:43 +0000559#ifdef TARGET_HAS_PRECISE_SMC
560
561static void tb_gen_code(CPUState *env,
562 target_ulong pc, target_ulong cs_base, int flags,
563 int cflags)
564{
565 TranslationBlock *tb;
566 uint8_t *tc_ptr;
567 target_ulong phys_pc, phys_page2, virt_page2;
568 int code_gen_size;
569
bellardc27004e2005-01-03 23:35:10 +0000570 phys_pc = get_phys_addr_code(env, pc);
571 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000572 if (!tb) {
573 /* flush must be done */
574 tb_flush(env);
575 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000576 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000577 }
578 tc_ptr = code_gen_ptr;
579 tb->tc_ptr = tc_ptr;
580 tb->cs_base = cs_base;
581 tb->flags = flags;
582 tb->cflags = cflags;
583 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
584 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
585
586 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000587 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000588 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000589 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000590 phys_page2 = get_phys_addr_code(env, virt_page2);
591 }
592 tb_link_phys(tb, phys_pc, phys_page2);
593}
594#endif
595
bellard9fa3e852004-01-04 18:06:42 +0000596/* invalidate all TBs which intersect with the target physical page
597 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000598 the same physical page. 'is_cpu_write_access' should be true if called
599 from a real cpu write access: the virtual CPU will exit the current
600 TB if code is modified inside this TB. */
601void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
602 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000603{
bellardd720b932004-04-25 17:57:43 +0000604 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000605 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000606 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000607 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000608 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000609 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000610
611 p = page_find(start >> TARGET_PAGE_BITS);
612 if (!p)
613 return;
614 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000615 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
616 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000617 /* build code bitmap */
618 build_page_bitmap(p);
619 }
620
621 /* we remove all the TBs in the range [start, end[ */
622 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000623 current_tb_not_found = is_cpu_write_access;
624 current_tb_modified = 0;
625 current_tb = NULL; /* avoid warning */
626 current_pc = 0; /* avoid warning */
627 current_cs_base = 0; /* avoid warning */
628 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000629 tb = p->first_tb;
630 while (tb != NULL) {
631 n = (long)tb & 3;
632 tb = (TranslationBlock *)((long)tb & ~3);
633 tb_next = tb->page_next[n];
634 /* NOTE: this is subtle as a TB may span two physical pages */
635 if (n == 0) {
636 /* NOTE: tb_end may be after the end of the page, but
637 it is not a problem */
638 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
639 tb_end = tb_start + tb->size;
640 } else {
641 tb_start = tb->page_addr[1];
642 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
643 }
644 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000645#ifdef TARGET_HAS_PRECISE_SMC
646 if (current_tb_not_found) {
647 current_tb_not_found = 0;
648 current_tb = NULL;
649 if (env->mem_write_pc) {
650 /* now we have a real cpu fault */
651 current_tb = tb_find_pc(env->mem_write_pc);
652 }
653 }
654 if (current_tb == tb &&
655 !(current_tb->cflags & CF_SINGLE_INSN)) {
656 /* If we are modifying the current TB, we must stop
657 its execution. We could be more precise by checking
658 that the modification is after the current PC, but it
659 would require a specialized function to partially
660 restore the CPU state */
661
662 current_tb_modified = 1;
663 cpu_restore_state(current_tb, env,
664 env->mem_write_pc, NULL);
665#if defined(TARGET_I386)
666 current_flags = env->hflags;
667 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
668 current_cs_base = (target_ulong)env->segs[R_CS].base;
669 current_pc = current_cs_base + env->eip;
670#else
671#error unsupported CPU
672#endif
673 }
674#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000675 /* we need to do that to handle the case where a signal
676 occurs while doing tb_phys_invalidate() */
677 saved_tb = NULL;
678 if (env) {
679 saved_tb = env->current_tb;
680 env->current_tb = NULL;
681 }
bellard9fa3e852004-01-04 18:06:42 +0000682 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000683 if (env) {
684 env->current_tb = saved_tb;
685 if (env->interrupt_request && env->current_tb)
686 cpu_interrupt(env, env->interrupt_request);
687 }
bellard9fa3e852004-01-04 18:06:42 +0000688 }
689 tb = tb_next;
690 }
691#if !defined(CONFIG_USER_ONLY)
692 /* if no code remaining, no need to continue to use slow writes */
693 if (!p->first_tb) {
694 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000695 if (is_cpu_write_access) {
696 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
697 }
698 }
699#endif
700#ifdef TARGET_HAS_PRECISE_SMC
701 if (current_tb_modified) {
702 /* we generate a block containing just the instruction
703 modifying the memory. It will ensure that it cannot modify
704 itself */
bellardea1c1802004-06-14 18:56:36 +0000705 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000706 tb_gen_code(env, current_pc, current_cs_base, current_flags,
707 CF_SINGLE_INSN);
708 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000709 }
710#endif
711}
712
713/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000714static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000715{
716 PageDesc *p;
717 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000718#if 0
bellarda4193c82004-06-03 14:01:43 +0000719 if (1) {
720 if (loglevel) {
721 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
722 cpu_single_env->mem_write_vaddr, len,
723 cpu_single_env->eip,
724 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
725 }
bellard59817cc2004-02-16 22:01:13 +0000726 }
727#endif
bellard9fa3e852004-01-04 18:06:42 +0000728 p = page_find(start >> TARGET_PAGE_BITS);
729 if (!p)
730 return;
731 if (p->code_bitmap) {
732 offset = start & ~TARGET_PAGE_MASK;
733 b = p->code_bitmap[offset >> 3] >> (offset & 7);
734 if (b & ((1 << len) - 1))
735 goto do_invalidate;
736 } else {
737 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000738 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000739 }
740}
741
bellard9fa3e852004-01-04 18:06:42 +0000742#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000743static void tb_invalidate_phys_page(target_ulong addr,
744 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000745{
bellardd720b932004-04-25 17:57:43 +0000746 int n, current_flags, current_tb_modified;
747 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000748 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000749 TranslationBlock *tb, *current_tb;
750#ifdef TARGET_HAS_PRECISE_SMC
751 CPUState *env = cpu_single_env;
752#endif
bellard9fa3e852004-01-04 18:06:42 +0000753
754 addr &= TARGET_PAGE_MASK;
755 p = page_find(addr >> TARGET_PAGE_BITS);
756 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000757 return;
758 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000759 current_tb_modified = 0;
760 current_tb = NULL;
761 current_pc = 0; /* avoid warning */
762 current_cs_base = 0; /* avoid warning */
763 current_flags = 0; /* avoid warning */
764#ifdef TARGET_HAS_PRECISE_SMC
765 if (tb && pc != 0) {
766 current_tb = tb_find_pc(pc);
767 }
768#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000769 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000770 n = (long)tb & 3;
771 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000772#ifdef TARGET_HAS_PRECISE_SMC
773 if (current_tb == tb &&
774 !(current_tb->cflags & CF_SINGLE_INSN)) {
775 /* If we are modifying the current TB, we must stop
776 its execution. We could be more precise by checking
777 that the modification is after the current PC, but it
778 would require a specialized function to partially
779 restore the CPU state */
780
781 current_tb_modified = 1;
782 cpu_restore_state(current_tb, env, pc, puc);
783#if defined(TARGET_I386)
784 current_flags = env->hflags;
785 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
786 current_cs_base = (target_ulong)env->segs[R_CS].base;
787 current_pc = current_cs_base + env->eip;
788#else
789#error unsupported CPU
790#endif
791 }
792#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000793 tb_phys_invalidate(tb, addr);
794 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000795 }
796 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000797#ifdef TARGET_HAS_PRECISE_SMC
798 if (current_tb_modified) {
799 /* we generate a block containing just the instruction
800 modifying the memory. It will ensure that it cannot modify
801 itself */
bellardea1c1802004-06-14 18:56:36 +0000802 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000803 tb_gen_code(env, current_pc, current_cs_base, current_flags,
804 CF_SINGLE_INSN);
805 cpu_resume_from_signal(env, puc);
806 }
807#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000808}
bellard9fa3e852004-01-04 18:06:42 +0000809#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000810
811/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000812static inline void tb_alloc_page(TranslationBlock *tb,
813 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000814{
815 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000816 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000817
bellard9fa3e852004-01-04 18:06:42 +0000818 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000819 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000820 tb->page_next[n] = p->first_tb;
821 last_first_tb = p->first_tb;
822 p->first_tb = (TranslationBlock *)((long)tb | n);
823 invalidate_page_bitmap(p);
824
bellard107db442004-06-22 18:48:46 +0000825#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000826
bellard9fa3e852004-01-04 18:06:42 +0000827#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000828 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000829 unsigned long host_start, host_end, addr;
830 int prot;
831
bellardfd6ce8f2003-05-14 19:00:11 +0000832 /* force the host page as non writable (writes will have a
833 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000834 host_start = page_addr & qemu_host_page_mask;
835 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000836 prot = 0;
837 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
838 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000839 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000840 (prot & PAGE_BITS) & ~PAGE_WRITE);
841#ifdef DEBUG_TB_INVALIDATE
842 printf("protecting code page: 0x%08lx\n",
843 host_start);
844#endif
845 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000846 }
bellard9fa3e852004-01-04 18:06:42 +0000847#else
848 /* if some code is already present, then the pages are already
849 protected. So we handle the case where only the first TB is
850 allocated in a physical page */
851 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000852 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000853 }
854#endif
bellardd720b932004-04-25 17:57:43 +0000855
856#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000857}
858
859/* Allocate a new translation block. Flush the translation buffer if
860 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000861TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000862{
863 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000864
865 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
866 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000867 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000868 tb = &tbs[nb_tbs++];
869 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000870 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000871 return tb;
872}
873
bellard9fa3e852004-01-04 18:06:42 +0000874/* add a new TB and link it to the physical page tables. phys_page2 is
875 (-1) to indicate that only one page contains the TB. */
876void tb_link_phys(TranslationBlock *tb,
877 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000878{
bellard9fa3e852004-01-04 18:06:42 +0000879 unsigned int h;
880 TranslationBlock **ptb;
881
882 /* add in the physical hash table */
883 h = tb_phys_hash_func(phys_pc);
884 ptb = &tb_phys_hash[h];
885 tb->phys_hash_next = *ptb;
886 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000887
888 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000889 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
890 if (phys_page2 != -1)
891 tb_alloc_page(tb, 1, phys_page2);
892 else
893 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000894
bellardd4e81642003-05-25 16:46:15 +0000895 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
896 tb->jmp_next[0] = NULL;
897 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000898#ifdef USE_CODE_COPY
899 tb->cflags &= ~CF_FP_USED;
900 if (tb->cflags & CF_TB_FP_USED)
901 tb->cflags |= CF_FP_USED;
902#endif
bellardd4e81642003-05-25 16:46:15 +0000903
904 /* init original jump addresses */
905 if (tb->tb_next_offset[0] != 0xffff)
906 tb_reset_jump(tb, 0);
907 if (tb->tb_next_offset[1] != 0xffff)
908 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000909
910#ifdef DEBUG_TB_CHECK
911 tb_page_check();
912#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000913}
914
bellarda513fe12003-05-27 23:29:48 +0000915/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
916 tb[1].tc_ptr. Return NULL if not found */
917TranslationBlock *tb_find_pc(unsigned long tc_ptr)
918{
919 int m_min, m_max, m;
920 unsigned long v;
921 TranslationBlock *tb;
922
923 if (nb_tbs <= 0)
924 return NULL;
925 if (tc_ptr < (unsigned long)code_gen_buffer ||
926 tc_ptr >= (unsigned long)code_gen_ptr)
927 return NULL;
928 /* binary search (cf Knuth) */
929 m_min = 0;
930 m_max = nb_tbs - 1;
931 while (m_min <= m_max) {
932 m = (m_min + m_max) >> 1;
933 tb = &tbs[m];
934 v = (unsigned long)tb->tc_ptr;
935 if (v == tc_ptr)
936 return tb;
937 else if (tc_ptr < v) {
938 m_max = m - 1;
939 } else {
940 m_min = m + 1;
941 }
942 }
943 return &tbs[m_max];
944}
bellard75012672003-06-21 13:11:07 +0000945
bellardea041c02003-06-25 16:16:50 +0000946static void tb_reset_jump_recursive(TranslationBlock *tb);
947
948static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
949{
950 TranslationBlock *tb1, *tb_next, **ptb;
951 unsigned int n1;
952
953 tb1 = tb->jmp_next[n];
954 if (tb1 != NULL) {
955 /* find head of list */
956 for(;;) {
957 n1 = (long)tb1 & 3;
958 tb1 = (TranslationBlock *)((long)tb1 & ~3);
959 if (n1 == 2)
960 break;
961 tb1 = tb1->jmp_next[n1];
962 }
963 /* we are now sure now that tb jumps to tb1 */
964 tb_next = tb1;
965
966 /* remove tb from the jmp_first list */
967 ptb = &tb_next->jmp_first;
968 for(;;) {
969 tb1 = *ptb;
970 n1 = (long)tb1 & 3;
971 tb1 = (TranslationBlock *)((long)tb1 & ~3);
972 if (n1 == n && tb1 == tb)
973 break;
974 ptb = &tb1->jmp_next[n1];
975 }
976 *ptb = tb->jmp_next[n];
977 tb->jmp_next[n] = NULL;
978
979 /* suppress the jump to next tb in generated code */
980 tb_reset_jump(tb, n);
981
bellard01243112004-01-04 15:48:17 +0000982 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +0000983 tb_reset_jump_recursive(tb_next);
984 }
985}
986
987static void tb_reset_jump_recursive(TranslationBlock *tb)
988{
989 tb_reset_jump_recursive2(tb, 0);
990 tb_reset_jump_recursive2(tb, 1);
991}
992
bellard1fddef42005-04-17 19:16:13 +0000993#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +0000994static void breakpoint_invalidate(CPUState *env, target_ulong pc)
995{
996 target_ulong phys_addr;
997
998 phys_addr = cpu_get_phys_page_debug(env, pc);
999 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1000}
bellardc27004e2005-01-03 23:35:10 +00001001#endif
bellardd720b932004-04-25 17:57:43 +00001002
bellardc33a3462003-07-29 20:50:33 +00001003/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1004 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001005int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001006{
bellard1fddef42005-04-17 19:16:13 +00001007#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001008 int i;
bellardd720b932004-04-25 17:57:43 +00001009
bellard4c3a88a2003-07-26 12:06:08 +00001010 for(i = 0; i < env->nb_breakpoints; i++) {
1011 if (env->breakpoints[i] == pc)
1012 return 0;
1013 }
1014
1015 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1016 return -1;
1017 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001018
1019 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001020 return 0;
1021#else
1022 return -1;
1023#endif
1024}
1025
1026/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001027int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001028{
bellard1fddef42005-04-17 19:16:13 +00001029#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001030 int i;
1031 for(i = 0; i < env->nb_breakpoints; i++) {
1032 if (env->breakpoints[i] == pc)
1033 goto found;
1034 }
1035 return -1;
1036 found:
bellard4c3a88a2003-07-26 12:06:08 +00001037 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001038 if (i < env->nb_breakpoints)
1039 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001040
1041 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001042 return 0;
1043#else
1044 return -1;
1045#endif
1046}
1047
bellardc33a3462003-07-29 20:50:33 +00001048/* enable or disable single step mode. EXCP_DEBUG is returned by the
1049 CPU loop after each instruction */
1050void cpu_single_step(CPUState *env, int enabled)
1051{
bellard1fddef42005-04-17 19:16:13 +00001052#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001053 if (env->singlestep_enabled != enabled) {
1054 env->singlestep_enabled = enabled;
1055 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001056 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001057 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001058 }
1059#endif
1060}
1061
bellard34865132003-10-05 14:28:56 +00001062/* enable or disable low levels log */
1063void cpu_set_log(int log_flags)
1064{
1065 loglevel = log_flags;
1066 if (loglevel && !logfile) {
1067 logfile = fopen(logfilename, "w");
1068 if (!logfile) {
1069 perror(logfilename);
1070 _exit(1);
1071 }
bellard9fa3e852004-01-04 18:06:42 +00001072#if !defined(CONFIG_SOFTMMU)
1073 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1074 {
1075 static uint8_t logfile_buf[4096];
1076 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1077 }
1078#else
bellard34865132003-10-05 14:28:56 +00001079 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001080#endif
bellard34865132003-10-05 14:28:56 +00001081 }
1082}
1083
1084void cpu_set_log_filename(const char *filename)
1085{
1086 logfilename = strdup(filename);
1087}
bellardc33a3462003-07-29 20:50:33 +00001088
bellard01243112004-01-04 15:48:17 +00001089/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001090void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001091{
1092 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001093 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001094
bellard68a79312003-06-30 13:12:32 +00001095 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001096 /* if the cpu is currently executing code, we must unlink it and
1097 all the potentially executing TB */
1098 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001099 if (tb && !testandset(&interrupt_lock)) {
1100 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001101 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001102 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001103 }
1104}
1105
bellardb54ad042004-05-20 13:42:52 +00001106void cpu_reset_interrupt(CPUState *env, int mask)
1107{
1108 env->interrupt_request &= ~mask;
1109}
1110
bellardf193c792004-03-21 17:06:25 +00001111CPULogItem cpu_log_items[] = {
1112 { CPU_LOG_TB_OUT_ASM, "out_asm",
1113 "show generated host assembly code for each compiled TB" },
1114 { CPU_LOG_TB_IN_ASM, "in_asm",
1115 "show target assembly code for each compiled TB" },
1116 { CPU_LOG_TB_OP, "op",
1117 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1118#ifdef TARGET_I386
1119 { CPU_LOG_TB_OP_OPT, "op_opt",
1120 "show micro ops after optimization for each compiled TB" },
1121#endif
1122 { CPU_LOG_INT, "int",
1123 "show interrupts/exceptions in short format" },
1124 { CPU_LOG_EXEC, "exec",
1125 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001126 { CPU_LOG_TB_CPU, "cpu",
1127 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001128#ifdef TARGET_I386
1129 { CPU_LOG_PCALL, "pcall",
1130 "show protected mode far calls/returns/exceptions" },
1131#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001132#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001133 { CPU_LOG_IOPORT, "ioport",
1134 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001135#endif
bellardf193c792004-03-21 17:06:25 +00001136 { 0, NULL, NULL },
1137};
1138
1139static int cmp1(const char *s1, int n, const char *s2)
1140{
1141 if (strlen(s2) != n)
1142 return 0;
1143 return memcmp(s1, s2, n) == 0;
1144}
1145
1146/* takes a comma separated list of log masks. Return 0 if error. */
1147int cpu_str_to_log_mask(const char *str)
1148{
1149 CPULogItem *item;
1150 int mask;
1151 const char *p, *p1;
1152
1153 p = str;
1154 mask = 0;
1155 for(;;) {
1156 p1 = strchr(p, ',');
1157 if (!p1)
1158 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001159 if(cmp1(p,p1-p,"all")) {
1160 for(item = cpu_log_items; item->mask != 0; item++) {
1161 mask |= item->mask;
1162 }
1163 } else {
bellardf193c792004-03-21 17:06:25 +00001164 for(item = cpu_log_items; item->mask != 0; item++) {
1165 if (cmp1(p, p1 - p, item->name))
1166 goto found;
1167 }
1168 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001169 }
bellardf193c792004-03-21 17:06:25 +00001170 found:
1171 mask |= item->mask;
1172 if (*p1 != ',')
1173 break;
1174 p = p1 + 1;
1175 }
1176 return mask;
1177}
bellardea041c02003-06-25 16:16:50 +00001178
bellard75012672003-06-21 13:11:07 +00001179void cpu_abort(CPUState *env, const char *fmt, ...)
1180{
1181 va_list ap;
1182
1183 va_start(ap, fmt);
1184 fprintf(stderr, "qemu: fatal: ");
1185 vfprintf(stderr, fmt, ap);
1186 fprintf(stderr, "\n");
1187#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001188 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1189#else
1190 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001191#endif
1192 va_end(ap);
1193 abort();
1194}
1195
bellard01243112004-01-04 15:48:17 +00001196#if !defined(CONFIG_USER_ONLY)
1197
bellardee8b7022004-02-03 23:35:10 +00001198/* NOTE: if flush_global is true, also flush global entries (not
1199 implemented yet) */
1200void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001201{
bellard33417e72003-08-10 21:47:01 +00001202 int i;
bellard01243112004-01-04 15:48:17 +00001203
bellard9fa3e852004-01-04 18:06:42 +00001204#if defined(DEBUG_TLB)
1205 printf("tlb_flush:\n");
1206#endif
bellard01243112004-01-04 15:48:17 +00001207 /* must reset current TB so that interrupts cannot modify the
1208 links while we are modifying them */
1209 env->current_tb = NULL;
1210
bellard33417e72003-08-10 21:47:01 +00001211 for(i = 0; i < CPU_TLB_SIZE; i++) {
1212 env->tlb_read[0][i].address = -1;
1213 env->tlb_write[0][i].address = -1;
1214 env->tlb_read[1][i].address = -1;
1215 env->tlb_write[1][i].address = -1;
1216 }
bellard9fa3e852004-01-04 18:06:42 +00001217
bellard8a40a182005-11-20 10:35:40 +00001218 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001219
1220#if !defined(CONFIG_SOFTMMU)
1221 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1222#endif
bellard0a962c02005-02-10 22:00:27 +00001223#ifdef USE_KQEMU
1224 if (env->kqemu_enabled) {
1225 kqemu_flush(env, flush_global);
1226 }
1227#endif
bellarde3db7222005-01-26 22:00:47 +00001228 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001229}
1230
bellard274da6b2004-05-20 21:56:27 +00001231static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001232{
1233 if (addr == (tlb_entry->address &
1234 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1235 tlb_entry->address = -1;
1236}
1237
bellard2e126692004-04-25 21:28:44 +00001238void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001239{
bellard8a40a182005-11-20 10:35:40 +00001240 int i;
bellard9fa3e852004-01-04 18:06:42 +00001241 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001242
bellard9fa3e852004-01-04 18:06:42 +00001243#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001244 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001245#endif
bellard01243112004-01-04 15:48:17 +00001246 /* must reset current TB so that interrupts cannot modify the
1247 links while we are modifying them */
1248 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001249
bellard61382a52003-10-27 21:22:23 +00001250 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001251 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001252 tlb_flush_entry(&env->tlb_read[0][i], addr);
1253 tlb_flush_entry(&env->tlb_write[0][i], addr);
1254 tlb_flush_entry(&env->tlb_read[1][i], addr);
1255 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001256
bellard8a40a182005-11-20 10:35:40 +00001257 for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
1258 tb = env->tb_jmp_cache[i];
1259 if (tb &&
1260 ((tb->pc & TARGET_PAGE_MASK) == addr ||
1261 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
1262 env->tb_jmp_cache[i] = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001263 }
1264 }
1265
bellard01243112004-01-04 15:48:17 +00001266#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001267 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001268 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001269#endif
bellard0a962c02005-02-10 22:00:27 +00001270#ifdef USE_KQEMU
1271 if (env->kqemu_enabled) {
1272 kqemu_flush_page(env, addr);
1273 }
1274#endif
bellard9fa3e852004-01-04 18:06:42 +00001275}
1276
bellard9fa3e852004-01-04 18:06:42 +00001277/* update the TLBs so that writes to code in the virtual page 'addr'
1278 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001279static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001280{
bellard6a00d602005-11-21 23:25:50 +00001281 cpu_physical_memory_reset_dirty(ram_addr,
1282 ram_addr + TARGET_PAGE_SIZE,
1283 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001284}
1285
bellard9fa3e852004-01-04 18:06:42 +00001286/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001287 tested for self modifying code */
1288static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1289 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001290{
bellard3a7d9292005-08-21 09:26:42 +00001291 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001292}
1293
1294static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1295 unsigned long start, unsigned long length)
1296{
1297 unsigned long addr;
1298 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1299 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1300 if ((addr - start) < length) {
1301 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1302 }
1303 }
1304}
1305
bellard3a7d9292005-08-21 09:26:42 +00001306void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001307 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001308{
1309 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001310 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001311 int i, mask, len;
1312 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001313
1314 start &= TARGET_PAGE_MASK;
1315 end = TARGET_PAGE_ALIGN(end);
1316
1317 length = end - start;
1318 if (length == 0)
1319 return;
bellard0a962c02005-02-10 22:00:27 +00001320 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001321#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001322 /* XXX: should not depend on cpu context */
1323 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001324 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001325 ram_addr_t addr;
1326 addr = start;
1327 for(i = 0; i < len; i++) {
1328 kqemu_set_notdirty(env, addr);
1329 addr += TARGET_PAGE_SIZE;
1330 }
bellard3a7d9292005-08-21 09:26:42 +00001331 }
1332#endif
bellardf23db162005-08-21 19:12:28 +00001333 mask = ~dirty_flags;
1334 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1335 for(i = 0; i < len; i++)
1336 p[i] &= mask;
1337
bellard1ccde1c2004-02-06 19:46:14 +00001338 /* we modify the TLB cache so that the dirty bit will be set again
1339 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001340 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001341 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1342 for(i = 0; i < CPU_TLB_SIZE; i++)
1343 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
1344 for(i = 0; i < CPU_TLB_SIZE; i++)
1345 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1346 }
bellard59817cc2004-02-16 22:01:13 +00001347
1348#if !defined(CONFIG_SOFTMMU)
1349 /* XXX: this is expensive */
1350 {
1351 VirtPageDesc *p;
1352 int j;
1353 target_ulong addr;
1354
1355 for(i = 0; i < L1_SIZE; i++) {
1356 p = l1_virt_map[i];
1357 if (p) {
1358 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1359 for(j = 0; j < L2_SIZE; j++) {
1360 if (p->valid_tag == virt_valid_tag &&
1361 p->phys_addr >= start && p->phys_addr < end &&
1362 (p->prot & PROT_WRITE)) {
1363 if (addr < MMAP_AREA_END) {
1364 mprotect((void *)addr, TARGET_PAGE_SIZE,
1365 p->prot & ~PROT_WRITE);
1366 }
1367 }
1368 addr += TARGET_PAGE_SIZE;
1369 p++;
1370 }
1371 }
1372 }
1373 }
1374#endif
bellard1ccde1c2004-02-06 19:46:14 +00001375}
1376
bellard3a7d9292005-08-21 09:26:42 +00001377static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1378{
1379 ram_addr_t ram_addr;
1380
1381 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1382 ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) +
1383 tlb_entry->addend - (unsigned long)phys_ram_base;
1384 if (!cpu_physical_memory_is_dirty(ram_addr)) {
1385 tlb_entry->address |= IO_MEM_NOTDIRTY;
1386 }
1387 }
1388}
1389
1390/* update the TLB according to the current state of the dirty bits */
1391void cpu_tlb_update_dirty(CPUState *env)
1392{
1393 int i;
1394 for(i = 0; i < CPU_TLB_SIZE; i++)
1395 tlb_update_dirty(&env->tlb_write[0][i]);
1396 for(i = 0; i < CPU_TLB_SIZE; i++)
1397 tlb_update_dirty(&env->tlb_write[1][i]);
1398}
1399
bellard1ccde1c2004-02-06 19:46:14 +00001400static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001401 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001402{
1403 unsigned long addr;
1404 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1405 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1406 if (addr == start) {
1407 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1408 }
1409 }
1410}
1411
1412/* update the TLB corresponding to virtual page vaddr and phys addr
1413 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001414static inline void tlb_set_dirty(CPUState *env,
1415 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001416{
bellard1ccde1c2004-02-06 19:46:14 +00001417 int i;
1418
bellard1ccde1c2004-02-06 19:46:14 +00001419 addr &= TARGET_PAGE_MASK;
1420 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1421 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1422 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001423}
1424
bellard59817cc2004-02-16 22:01:13 +00001425/* add a new TLB entry. At most one entry for a given virtual address
1426 is permitted. Return 0 if OK or 2 if the page could not be mapped
1427 (can only happen in non SOFTMMU mode for I/O pages or pages
1428 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001429int tlb_set_page(CPUState *env, target_ulong vaddr,
1430 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001431 int is_user, int is_softmmu)
1432{
bellard92e873b2004-05-21 14:52:29 +00001433 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001434 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001435 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001436 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001437 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001438 int ret;
1439
bellard92e873b2004-05-21 14:52:29 +00001440 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001441 if (!p) {
1442 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001443 } else {
1444 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001445 }
1446#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001447 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
1448 vaddr, paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001449#endif
1450
1451 ret = 0;
1452#if !defined(CONFIG_SOFTMMU)
1453 if (is_softmmu)
1454#endif
1455 {
1456 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1457 /* IO memory case */
1458 address = vaddr | pd;
1459 addend = paddr;
1460 } else {
1461 /* standard memory */
1462 address = vaddr;
1463 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1464 }
1465
bellard90f18422005-07-24 10:17:31 +00001466 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001467 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001468 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001469 env->tlb_read[is_user][index].address = address;
1470 env->tlb_read[is_user][index].addend = addend;
1471 } else {
1472 env->tlb_read[is_user][index].address = -1;
1473 env->tlb_read[is_user][index].addend = -1;
1474 }
bellard67b915a2004-03-31 23:37:16 +00001475 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001476 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1477 /* ROM: access is ignored (same as unassigned) */
1478 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001479 env->tlb_write[is_user][index].addend = addend;
bellard3a7d9292005-08-21 09:26:42 +00001480 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001481 !cpu_physical_memory_is_dirty(pd)) {
1482 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1483 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001484 } else {
1485 env->tlb_write[is_user][index].address = address;
1486 env->tlb_write[is_user][index].addend = addend;
1487 }
1488 } else {
1489 env->tlb_write[is_user][index].address = -1;
1490 env->tlb_write[is_user][index].addend = -1;
1491 }
1492 }
1493#if !defined(CONFIG_SOFTMMU)
1494 else {
1495 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1496 /* IO access: no mapping is done as it will be handled by the
1497 soft MMU */
1498 if (!(env->hflags & HF_SOFTMMU_MASK))
1499 ret = 2;
1500 } else {
1501 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001502
bellard59817cc2004-02-16 22:01:13 +00001503 if (vaddr >= MMAP_AREA_END) {
1504 ret = 2;
1505 } else {
1506 if (prot & PROT_WRITE) {
1507 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001508#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001509 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001510#endif
bellard59817cc2004-02-16 22:01:13 +00001511 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1512 !cpu_physical_memory_is_dirty(pd))) {
1513 /* ROM: we do as if code was inside */
1514 /* if code is present, we only map as read only and save the
1515 original mapping */
1516 VirtPageDesc *vp;
1517
bellard90f18422005-07-24 10:17:31 +00001518 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001519 vp->phys_addr = pd;
1520 vp->prot = prot;
1521 vp->valid_tag = virt_valid_tag;
1522 prot &= ~PAGE_WRITE;
1523 }
bellard9fa3e852004-01-04 18:06:42 +00001524 }
bellard59817cc2004-02-16 22:01:13 +00001525 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1526 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1527 if (map_addr == MAP_FAILED) {
1528 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1529 paddr, vaddr);
1530 }
bellard9fa3e852004-01-04 18:06:42 +00001531 }
1532 }
1533 }
1534#endif
1535 return ret;
1536}
1537
1538/* called from signal handler: invalidate the code and unprotect the
1539 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001540int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001541{
1542#if !defined(CONFIG_SOFTMMU)
1543 VirtPageDesc *vp;
1544
1545#if defined(DEBUG_TLB)
1546 printf("page_unprotect: addr=0x%08x\n", addr);
1547#endif
1548 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001549
1550 /* if it is not mapped, no need to worry here */
1551 if (addr >= MMAP_AREA_END)
1552 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001553 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1554 if (!vp)
1555 return 0;
1556 /* NOTE: in this case, validate_tag is _not_ tested as it
1557 validates only the code TLB */
1558 if (vp->valid_tag != virt_valid_tag)
1559 return 0;
1560 if (!(vp->prot & PAGE_WRITE))
1561 return 0;
1562#if defined(DEBUG_TLB)
1563 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1564 addr, vp->phys_addr, vp->prot);
1565#endif
bellard59817cc2004-02-16 22:01:13 +00001566 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1567 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1568 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001569 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001570 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001571 /* flush the code inside */
1572 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001573 return 1;
1574#else
1575 return 0;
1576#endif
bellard33417e72003-08-10 21:47:01 +00001577}
1578
bellard01243112004-01-04 15:48:17 +00001579#else
1580
bellardee8b7022004-02-03 23:35:10 +00001581void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001582{
1583}
1584
bellard2e126692004-04-25 21:28:44 +00001585void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001586{
1587}
1588
bellard2e126692004-04-25 21:28:44 +00001589int tlb_set_page(CPUState *env, target_ulong vaddr,
1590 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001591 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001592{
bellard9fa3e852004-01-04 18:06:42 +00001593 return 0;
1594}
bellard33417e72003-08-10 21:47:01 +00001595
bellard9fa3e852004-01-04 18:06:42 +00001596/* dump memory mappings */
1597void page_dump(FILE *f)
1598{
1599 unsigned long start, end;
1600 int i, j, prot, prot1;
1601 PageDesc *p;
1602
1603 fprintf(f, "%-8s %-8s %-8s %s\n",
1604 "start", "end", "size", "prot");
1605 start = -1;
1606 end = -1;
1607 prot = 0;
1608 for(i = 0; i <= L1_SIZE; i++) {
1609 if (i < L1_SIZE)
1610 p = l1_map[i];
1611 else
1612 p = NULL;
1613 for(j = 0;j < L2_SIZE; j++) {
1614 if (!p)
1615 prot1 = 0;
1616 else
1617 prot1 = p[j].flags;
1618 if (prot1 != prot) {
1619 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1620 if (start != -1) {
1621 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1622 start, end, end - start,
1623 prot & PAGE_READ ? 'r' : '-',
1624 prot & PAGE_WRITE ? 'w' : '-',
1625 prot & PAGE_EXEC ? 'x' : '-');
1626 }
1627 if (prot1 != 0)
1628 start = end;
1629 else
1630 start = -1;
1631 prot = prot1;
1632 }
1633 if (!p)
1634 break;
1635 }
bellard33417e72003-08-10 21:47:01 +00001636 }
bellard33417e72003-08-10 21:47:01 +00001637}
1638
bellard9fa3e852004-01-04 18:06:42 +00001639int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001640{
bellard9fa3e852004-01-04 18:06:42 +00001641 PageDesc *p;
1642
1643 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001644 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001645 return 0;
1646 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001647}
1648
bellard9fa3e852004-01-04 18:06:42 +00001649/* modify the flags of a page and invalidate the code if
1650 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1651 depending on PAGE_WRITE */
1652void page_set_flags(unsigned long start, unsigned long end, int flags)
1653{
1654 PageDesc *p;
1655 unsigned long addr;
1656
1657 start = start & TARGET_PAGE_MASK;
1658 end = TARGET_PAGE_ALIGN(end);
1659 if (flags & PAGE_WRITE)
1660 flags |= PAGE_WRITE_ORG;
1661 spin_lock(&tb_lock);
1662 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1663 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1664 /* if the write protection is set, then we invalidate the code
1665 inside */
1666 if (!(p->flags & PAGE_WRITE) &&
1667 (flags & PAGE_WRITE) &&
1668 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001669 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001670 }
1671 p->flags = flags;
1672 }
1673 spin_unlock(&tb_lock);
1674}
1675
1676/* called from signal handler: invalidate the code and unprotect the
1677 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001678int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001679{
1680 unsigned int page_index, prot, pindex;
1681 PageDesc *p, *p1;
1682 unsigned long host_start, host_end, addr;
1683
bellard83fb7ad2004-07-05 21:25:26 +00001684 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001685 page_index = host_start >> TARGET_PAGE_BITS;
1686 p1 = page_find(page_index);
1687 if (!p1)
1688 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001689 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001690 p = p1;
1691 prot = 0;
1692 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1693 prot |= p->flags;
1694 p++;
1695 }
1696 /* if the page was really writable, then we change its
1697 protection back to writable */
1698 if (prot & PAGE_WRITE_ORG) {
1699 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1700 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001701 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001702 (prot & PAGE_BITS) | PAGE_WRITE);
1703 p1[pindex].flags |= PAGE_WRITE;
1704 /* and since the content will be modified, we must invalidate
1705 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001706 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001707#ifdef DEBUG_TB_CHECK
1708 tb_invalidate_check(address);
1709#endif
1710 return 1;
1711 }
1712 }
1713 return 0;
1714}
1715
1716/* call this function when system calls directly modify a memory area */
1717void page_unprotect_range(uint8_t *data, unsigned long data_size)
1718{
1719 unsigned long start, end, addr;
1720
1721 start = (unsigned long)data;
1722 end = start + data_size;
1723 start &= TARGET_PAGE_MASK;
1724 end = TARGET_PAGE_ALIGN(end);
1725 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001726 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001727 }
1728}
1729
bellard6a00d602005-11-21 23:25:50 +00001730static inline void tlb_set_dirty(CPUState *env,
1731 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001732{
1733}
bellard9fa3e852004-01-04 18:06:42 +00001734#endif /* defined(CONFIG_USER_ONLY) */
1735
bellard33417e72003-08-10 21:47:01 +00001736/* register physical memory. 'size' must be a multiple of the target
1737 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1738 io memory page */
bellard2e126692004-04-25 21:28:44 +00001739void cpu_register_physical_memory(target_phys_addr_t start_addr,
1740 unsigned long size,
1741 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001742{
bellard108c49b2005-07-24 12:55:09 +00001743 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001744 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001745
bellard5fd386f2004-05-23 21:11:22 +00001746 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001747 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001748 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001749 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001750 p->phys_offset = phys_offset;
1751 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001752 phys_offset += TARGET_PAGE_SIZE;
1753 }
1754}
1755
bellarda4193c82004-06-03 14:01:43 +00001756static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001757{
1758 return 0;
1759}
1760
bellarda4193c82004-06-03 14:01:43 +00001761static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001762{
1763}
1764
1765static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1766 unassigned_mem_readb,
1767 unassigned_mem_readb,
1768 unassigned_mem_readb,
1769};
1770
1771static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1772 unassigned_mem_writeb,
1773 unassigned_mem_writeb,
1774 unassigned_mem_writeb,
1775};
1776
bellarda4193c82004-06-03 14:01:43 +00001777static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001778{
bellard3a7d9292005-08-21 09:26:42 +00001779 unsigned long ram_addr;
1780 int dirty_flags;
1781 ram_addr = addr - (unsigned long)phys_ram_base;
1782 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1783 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1784#if !defined(CONFIG_USER_ONLY)
1785 tb_invalidate_phys_page_fast(ram_addr, 1);
1786 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1787#endif
1788 }
bellardc27004e2005-01-03 23:35:10 +00001789 stb_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001790 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1791 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1792 /* we remove the notdirty callback only if the code has been
1793 flushed */
1794 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001795 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001796}
1797
bellarda4193c82004-06-03 14:01:43 +00001798static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001799{
bellard3a7d9292005-08-21 09:26:42 +00001800 unsigned long ram_addr;
1801 int dirty_flags;
1802 ram_addr = addr - (unsigned long)phys_ram_base;
1803 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1804 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1805#if !defined(CONFIG_USER_ONLY)
1806 tb_invalidate_phys_page_fast(ram_addr, 2);
1807 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1808#endif
1809 }
bellardc27004e2005-01-03 23:35:10 +00001810 stw_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001811 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1812 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1813 /* we remove the notdirty callback only if the code has been
1814 flushed */
1815 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001816 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001817}
1818
bellarda4193c82004-06-03 14:01:43 +00001819static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001820{
bellard3a7d9292005-08-21 09:26:42 +00001821 unsigned long ram_addr;
1822 int dirty_flags;
1823 ram_addr = addr - (unsigned long)phys_ram_base;
1824 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1825 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1826#if !defined(CONFIG_USER_ONLY)
1827 tb_invalidate_phys_page_fast(ram_addr, 4);
1828 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1829#endif
1830 }
bellardc27004e2005-01-03 23:35:10 +00001831 stl_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001832 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1833 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1834 /* we remove the notdirty callback only if the code has been
1835 flushed */
1836 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001837 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001838}
1839
bellard3a7d9292005-08-21 09:26:42 +00001840static CPUReadMemoryFunc *error_mem_read[3] = {
1841 NULL, /* never used */
1842 NULL, /* never used */
1843 NULL, /* never used */
1844};
1845
bellard1ccde1c2004-02-06 19:46:14 +00001846static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1847 notdirty_mem_writeb,
1848 notdirty_mem_writew,
1849 notdirty_mem_writel,
1850};
1851
bellard33417e72003-08-10 21:47:01 +00001852static void io_mem_init(void)
1853{
bellard3a7d9292005-08-21 09:26:42 +00001854 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001855 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001856 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001857 io_mem_nb = 5;
1858
1859 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001860 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001861 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001862}
1863
1864/* mem_read and mem_write are arrays of functions containing the
1865 function to access byte (index 0), word (index 1) and dword (index
1866 2). All functions must be supplied. If io_index is non zero, the
1867 corresponding io zone is modified. If it is zero, a new io zone is
1868 allocated. The return value can be used with
1869 cpu_register_physical_memory(). (-1) is returned if error. */
1870int cpu_register_io_memory(int io_index,
1871 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001872 CPUWriteMemoryFunc **mem_write,
1873 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001874{
1875 int i;
1876
1877 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00001878 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00001879 return -1;
1880 io_index = io_mem_nb++;
1881 } else {
1882 if (io_index >= IO_MEM_NB_ENTRIES)
1883 return -1;
1884 }
bellardb5ff1b32005-11-26 10:38:39 +00001885
bellard33417e72003-08-10 21:47:01 +00001886 for(i = 0;i < 3; i++) {
1887 io_mem_read[io_index][i] = mem_read[i];
1888 io_mem_write[io_index][i] = mem_write[i];
1889 }
bellarda4193c82004-06-03 14:01:43 +00001890 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001891 return io_index << IO_MEM_SHIFT;
1892}
bellard61382a52003-10-27 21:22:23 +00001893
bellard8926b512004-10-10 15:14:20 +00001894CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1895{
1896 return io_mem_write[io_index >> IO_MEM_SHIFT];
1897}
1898
1899CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
1900{
1901 return io_mem_read[io_index >> IO_MEM_SHIFT];
1902}
1903
bellard13eb76e2004-01-24 15:23:36 +00001904/* physical memory access (slow version, mainly for debug) */
1905#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001906void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001907 int len, int is_write)
1908{
1909 int l, flags;
1910 target_ulong page;
1911
1912 while (len > 0) {
1913 page = addr & TARGET_PAGE_MASK;
1914 l = (page + TARGET_PAGE_SIZE) - addr;
1915 if (l > len)
1916 l = len;
1917 flags = page_get_flags(page);
1918 if (!(flags & PAGE_VALID))
1919 return;
1920 if (is_write) {
1921 if (!(flags & PAGE_WRITE))
1922 return;
1923 memcpy((uint8_t *)addr, buf, len);
1924 } else {
1925 if (!(flags & PAGE_READ))
1926 return;
1927 memcpy(buf, (uint8_t *)addr, len);
1928 }
1929 len -= l;
1930 buf += l;
1931 addr += l;
1932 }
1933}
bellard8df1cd02005-01-28 22:37:22 +00001934
bellard13eb76e2004-01-24 15:23:36 +00001935#else
bellard2e126692004-04-25 21:28:44 +00001936void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001937 int len, int is_write)
1938{
1939 int l, io_index;
1940 uint8_t *ptr;
1941 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00001942 target_phys_addr_t page;
1943 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00001944 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00001945
1946 while (len > 0) {
1947 page = addr & TARGET_PAGE_MASK;
1948 l = (page + TARGET_PAGE_SIZE) - addr;
1949 if (l > len)
1950 l = len;
bellard92e873b2004-05-21 14:52:29 +00001951 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00001952 if (!p) {
1953 pd = IO_MEM_UNASSIGNED;
1954 } else {
1955 pd = p->phys_offset;
1956 }
1957
1958 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00001959 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00001960 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00001961 /* XXX: could force cpu_single_env to NULL to avoid
1962 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00001963 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00001964 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001965 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001966 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001967 l = 4;
1968 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00001969 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001970 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001971 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001972 l = 2;
1973 } else {
bellard1c213d12005-09-03 10:49:04 +00001974 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001975 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001976 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001977 l = 1;
1978 }
1979 } else {
bellardb448f2f2004-02-25 23:24:04 +00001980 unsigned long addr1;
1981 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00001982 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00001983 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00001984 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00001985 if (!cpu_physical_memory_is_dirty(addr1)) {
1986 /* invalidate code */
1987 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
1988 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00001989 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
1990 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00001991 }
bellard13eb76e2004-01-24 15:23:36 +00001992 }
1993 } else {
bellard3a7d9292005-08-21 09:26:42 +00001994 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard13eb76e2004-01-24 15:23:36 +00001995 /* I/O case */
1996 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
1997 if (l >= 4 && ((addr & 3) == 0)) {
1998 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00001999 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002000 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002001 l = 4;
2002 } else if (l >= 2 && ((addr & 1) == 0)) {
2003 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002004 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002005 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002006 l = 2;
2007 } else {
bellard1c213d12005-09-03 10:49:04 +00002008 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002009 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002010 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002011 l = 1;
2012 }
2013 } else {
2014 /* RAM case */
2015 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2016 (addr & ~TARGET_PAGE_MASK);
2017 memcpy(buf, ptr, l);
2018 }
2019 }
2020 len -= l;
2021 buf += l;
2022 addr += l;
2023 }
2024}
bellard8df1cd02005-01-28 22:37:22 +00002025
2026/* warning: addr must be aligned */
2027uint32_t ldl_phys(target_phys_addr_t addr)
2028{
2029 int io_index;
2030 uint8_t *ptr;
2031 uint32_t val;
2032 unsigned long pd;
2033 PhysPageDesc *p;
2034
2035 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2036 if (!p) {
2037 pd = IO_MEM_UNASSIGNED;
2038 } else {
2039 pd = p->phys_offset;
2040 }
2041
bellard3a7d9292005-08-21 09:26:42 +00002042 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard8df1cd02005-01-28 22:37:22 +00002043 /* I/O case */
2044 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2045 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2046 } else {
2047 /* RAM case */
2048 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2049 (addr & ~TARGET_PAGE_MASK);
2050 val = ldl_p(ptr);
2051 }
2052 return val;
2053}
2054
bellardaab33092005-10-30 20:48:42 +00002055/* XXX: optimize */
2056uint32_t ldub_phys(target_phys_addr_t addr)
2057{
2058 uint8_t val;
2059 cpu_physical_memory_read(addr, &val, 1);
2060 return val;
2061}
2062
2063/* XXX: optimize */
2064uint32_t lduw_phys(target_phys_addr_t addr)
2065{
2066 uint16_t val;
2067 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2068 return tswap16(val);
2069}
2070
2071/* XXX: optimize */
2072uint64_t ldq_phys(target_phys_addr_t addr)
2073{
2074 uint64_t val;
2075 cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
2076 return tswap64(val);
2077}
2078
bellard8df1cd02005-01-28 22:37:22 +00002079/* warning: addr must be aligned. The ram page is not masked as dirty
2080 and the code inside is not invalidated. It is useful if the dirty
2081 bits are used to track modified PTEs */
2082void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2083{
2084 int io_index;
2085 uint8_t *ptr;
2086 unsigned long pd;
2087 PhysPageDesc *p;
2088
2089 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2090 if (!p) {
2091 pd = IO_MEM_UNASSIGNED;
2092 } else {
2093 pd = p->phys_offset;
2094 }
2095
bellard3a7d9292005-08-21 09:26:42 +00002096 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002097 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2098 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2099 } else {
2100 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2101 (addr & ~TARGET_PAGE_MASK);
2102 stl_p(ptr, val);
2103 }
2104}
2105
2106/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002107void stl_phys(target_phys_addr_t addr, uint32_t val)
2108{
2109 int io_index;
2110 uint8_t *ptr;
2111 unsigned long pd;
2112 PhysPageDesc *p;
2113
2114 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2115 if (!p) {
2116 pd = IO_MEM_UNASSIGNED;
2117 } else {
2118 pd = p->phys_offset;
2119 }
2120
bellard3a7d9292005-08-21 09:26:42 +00002121 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002122 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2123 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2124 } else {
2125 unsigned long addr1;
2126 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2127 /* RAM case */
2128 ptr = phys_ram_base + addr1;
2129 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002130 if (!cpu_physical_memory_is_dirty(addr1)) {
2131 /* invalidate code */
2132 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2133 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002134 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2135 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002136 }
bellard8df1cd02005-01-28 22:37:22 +00002137 }
2138}
2139
bellardaab33092005-10-30 20:48:42 +00002140/* XXX: optimize */
2141void stb_phys(target_phys_addr_t addr, uint32_t val)
2142{
2143 uint8_t v = val;
2144 cpu_physical_memory_write(addr, &v, 1);
2145}
2146
2147/* XXX: optimize */
2148void stw_phys(target_phys_addr_t addr, uint32_t val)
2149{
2150 uint16_t v = tswap16(val);
2151 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2152}
2153
2154/* XXX: optimize */
2155void stq_phys(target_phys_addr_t addr, uint64_t val)
2156{
2157 val = tswap64(val);
2158 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2159}
2160
bellard13eb76e2004-01-24 15:23:36 +00002161#endif
2162
2163/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002164int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2165 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002166{
2167 int l;
2168 target_ulong page, phys_addr;
2169
2170 while (len > 0) {
2171 page = addr & TARGET_PAGE_MASK;
2172 phys_addr = cpu_get_phys_page_debug(env, page);
2173 /* if no physical page mapped, return an error */
2174 if (phys_addr == -1)
2175 return -1;
2176 l = (page + TARGET_PAGE_SIZE) - addr;
2177 if (l > len)
2178 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002179 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2180 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002181 len -= l;
2182 buf += l;
2183 addr += l;
2184 }
2185 return 0;
2186}
2187
bellarde3db7222005-01-26 22:00:47 +00002188void dump_exec_info(FILE *f,
2189 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2190{
2191 int i, target_code_size, max_target_code_size;
2192 int direct_jmp_count, direct_jmp2_count, cross_page;
2193 TranslationBlock *tb;
2194
2195 target_code_size = 0;
2196 max_target_code_size = 0;
2197 cross_page = 0;
2198 direct_jmp_count = 0;
2199 direct_jmp2_count = 0;
2200 for(i = 0; i < nb_tbs; i++) {
2201 tb = &tbs[i];
2202 target_code_size += tb->size;
2203 if (tb->size > max_target_code_size)
2204 max_target_code_size = tb->size;
2205 if (tb->page_addr[1] != -1)
2206 cross_page++;
2207 if (tb->tb_next_offset[0] != 0xffff) {
2208 direct_jmp_count++;
2209 if (tb->tb_next_offset[1] != 0xffff) {
2210 direct_jmp2_count++;
2211 }
2212 }
2213 }
2214 /* XXX: avoid using doubles ? */
2215 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2216 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2217 nb_tbs ? target_code_size / nb_tbs : 0,
2218 max_target_code_size);
2219 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2220 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2221 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2222 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2223 cross_page,
2224 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2225 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2226 direct_jmp_count,
2227 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2228 direct_jmp2_count,
2229 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2230 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2231 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2232 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2233}
2234
bellard61382a52003-10-27 21:22:23 +00002235#if !defined(CONFIG_USER_ONLY)
2236
2237#define MMUSUFFIX _cmmu
2238#define GETPC() NULL
2239#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002240#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002241
2242#define SHIFT 0
2243#include "softmmu_template.h"
2244
2245#define SHIFT 1
2246#include "softmmu_template.h"
2247
2248#define SHIFT 2
2249#include "softmmu_template.h"
2250
2251#define SHIFT 3
2252#include "softmmu_template.h"
2253
2254#undef env
2255
2256#endif