blob: 3466c9df7b6708005728eb122d387d39a80de78c [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];
64TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
bellard9fa3e852004-01-04 18:06:42 +000065TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000066int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000067/* any access to the tbs or the page table must use this lock */
68spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000069
bellardb8076a72005-04-07 22:20:31 +000070uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000071uint8_t *code_gen_ptr;
72
bellard9fa3e852004-01-04 18:06:42 +000073int phys_ram_size;
74int phys_ram_fd;
75uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000076uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000077
bellard54936002003-05-13 00:25:15 +000078typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000079 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000080 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000081 /* in order to optimize self modifying code, we count the number
82 of lookups we do to a given page to use a bitmap */
83 unsigned int code_write_count;
84 uint8_t *code_bitmap;
85#if defined(CONFIG_USER_ONLY)
86 unsigned long flags;
87#endif
bellard54936002003-05-13 00:25:15 +000088} PageDesc;
89
bellard92e873b2004-05-21 14:52:29 +000090typedef struct PhysPageDesc {
91 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +000092 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +000093} PhysPageDesc;
94
bellard90f18422005-07-24 10:17:31 +000095/* Note: the VirtPage handling is absolete and will be suppressed
96 ASAP */
bellard9fa3e852004-01-04 18:06:42 +000097typedef struct VirtPageDesc {
98 /* physical address of code page. It is valid only if 'valid_tag'
99 matches 'virt_valid_tag' */
100 target_ulong phys_addr;
101 unsigned int valid_tag;
102#if !defined(CONFIG_SOFTMMU)
103 /* original page access rights. It is valid only if 'valid_tag'
104 matches 'virt_valid_tag' */
105 unsigned int prot;
106#endif
107} VirtPageDesc;
108
bellard54936002003-05-13 00:25:15 +0000109#define L2_BITS 10
110#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
111
112#define L1_SIZE (1 << L1_BITS)
113#define L2_SIZE (1 << L2_BITS)
114
bellard33417e72003-08-10 21:47:01 +0000115static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000116
bellard83fb7ad2004-07-05 21:25:26 +0000117unsigned long qemu_real_host_page_size;
118unsigned long qemu_host_page_bits;
119unsigned long qemu_host_page_size;
120unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000121
bellard92e873b2004-05-21 14:52:29 +0000122/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000123static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000124PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000125
bellard9fa3e852004-01-04 18:06:42 +0000126#if !defined(CONFIG_USER_ONLY)
bellard90f18422005-07-24 10:17:31 +0000127#if TARGET_LONG_BITS > 32
128#define VIRT_L_BITS 9
129#define VIRT_L_SIZE (1 << VIRT_L_BITS)
130static void *l1_virt_map[VIRT_L_SIZE];
131#else
bellard9fa3e852004-01-04 18:06:42 +0000132static VirtPageDesc *l1_virt_map[L1_SIZE];
bellard90f18422005-07-24 10:17:31 +0000133#endif
bellard9fa3e852004-01-04 18:06:42 +0000134static unsigned int virt_valid_tag;
135#endif
136
bellard33417e72003-08-10 21:47:01 +0000137/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000138CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
139CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000140void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000141static int io_mem_nb;
142
bellard34865132003-10-05 14:28:56 +0000143/* log support */
144char *logfilename = "/tmp/qemu.log";
145FILE *logfile;
146int loglevel;
147
bellarde3db7222005-01-26 22:00:47 +0000148/* statistics */
149static int tlb_flush_count;
150static int tb_flush_count;
151static int tb_phys_invalidate_count;
152
bellardb346ff42003-06-15 20:05:50 +0000153static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000154{
bellard83fb7ad2004-07-05 21:25:26 +0000155 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000156 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000157#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000158 {
159 SYSTEM_INFO system_info;
160 DWORD old_protect;
161
162 GetSystemInfo(&system_info);
163 qemu_real_host_page_size = system_info.dwPageSize;
164
165 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
166 PAGE_EXECUTE_READWRITE, &old_protect);
167 }
bellard67b915a2004-03-31 23:37:16 +0000168#else
bellard83fb7ad2004-07-05 21:25:26 +0000169 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000170 {
171 unsigned long start, end;
172
173 start = (unsigned long)code_gen_buffer;
174 start &= ~(qemu_real_host_page_size - 1);
175
176 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
177 end += qemu_real_host_page_size - 1;
178 end &= ~(qemu_real_host_page_size - 1);
179
180 mprotect((void *)start, end - start,
181 PROT_READ | PROT_WRITE | PROT_EXEC);
182 }
bellard67b915a2004-03-31 23:37:16 +0000183#endif
bellardd5a8f072004-09-29 21:15:28 +0000184
bellard83fb7ad2004-07-05 21:25:26 +0000185 if (qemu_host_page_size == 0)
186 qemu_host_page_size = qemu_real_host_page_size;
187 if (qemu_host_page_size < TARGET_PAGE_SIZE)
188 qemu_host_page_size = TARGET_PAGE_SIZE;
189 qemu_host_page_bits = 0;
190 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
191 qemu_host_page_bits++;
192 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard9fa3e852004-01-04 18:06:42 +0000193#if !defined(CONFIG_USER_ONLY)
194 virt_valid_tag = 1;
195#endif
bellard108c49b2005-07-24 12:55:09 +0000196 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
197 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000198}
199
bellardfd6ce8f2003-05-14 19:00:11 +0000200static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000201{
bellard54936002003-05-13 00:25:15 +0000202 PageDesc **lp, *p;
203
bellard54936002003-05-13 00:25:15 +0000204 lp = &l1_map[index >> L2_BITS];
205 p = *lp;
206 if (!p) {
207 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000208 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000209 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000210 *lp = p;
211 }
212 return p + (index & (L2_SIZE - 1));
213}
214
bellardfd6ce8f2003-05-14 19:00:11 +0000215static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000216{
bellard54936002003-05-13 00:25:15 +0000217 PageDesc *p;
218
bellard54936002003-05-13 00:25:15 +0000219 p = l1_map[index >> L2_BITS];
220 if (!p)
221 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000222 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000223}
224
bellard108c49b2005-07-24 12:55:09 +0000225static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000226{
bellard108c49b2005-07-24 12:55:09 +0000227 void **lp, **p;
bellard92e873b2004-05-21 14:52:29 +0000228
bellard108c49b2005-07-24 12:55:09 +0000229 p = (void **)l1_phys_map;
230#if TARGET_PHYS_ADDR_SPACE_BITS > 32
231
232#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
233#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
234#endif
235 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000236 p = *lp;
237 if (!p) {
238 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000239 if (!alloc)
240 return NULL;
241 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
242 memset(p, 0, sizeof(void *) * L1_SIZE);
243 *lp = p;
244 }
245#endif
246 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
247 p = *lp;
248 if (!p) {
249 /* allocate if not found */
250 if (!alloc)
251 return NULL;
bellard0a962c02005-02-10 22:00:27 +0000252 p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
bellard92e873b2004-05-21 14:52:29 +0000253 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
254 *lp = p;
255 }
bellard108c49b2005-07-24 12:55:09 +0000256 return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000257}
258
bellard108c49b2005-07-24 12:55:09 +0000259static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000260{
bellard108c49b2005-07-24 12:55:09 +0000261 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000262}
263
bellard9fa3e852004-01-04 18:06:42 +0000264#if !defined(CONFIG_USER_ONLY)
bellard3a7d9292005-08-21 09:26:42 +0000265static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
266 target_ulong vaddr);
267static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
268 target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000269
bellard90f18422005-07-24 10:17:31 +0000270static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
bellard9fa3e852004-01-04 18:06:42 +0000271{
bellardc27004e2005-01-03 23:35:10 +0000272#if TARGET_LONG_BITS > 32
bellard90f18422005-07-24 10:17:31 +0000273 void **p, **lp;
274
275 p = l1_virt_map;
276 lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
277 p = *lp;
278 if (!p) {
279 if (!alloc)
280 return NULL;
281 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
282 *lp = p;
283 }
284 lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
285 p = *lp;
286 if (!p) {
287 if (!alloc)
288 return NULL;
289 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
290 *lp = p;
291 }
292 lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
293 p = *lp;
294 if (!p) {
295 if (!alloc)
296 return NULL;
297 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
298 *lp = p;
299 }
300 lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
301 p = *lp;
302 if (!p) {
303 if (!alloc)
304 return NULL;
305 p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
306 *lp = p;
307 }
308 lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
309 p = *lp;
310 if (!p) {
311 if (!alloc)
312 return NULL;
313 p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
314 *lp = p;
315 }
316 return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
317#else
318 VirtPageDesc *p, **lp;
319
bellard9fa3e852004-01-04 18:06:42 +0000320 lp = &l1_virt_map[index >> L2_BITS];
321 p = *lp;
322 if (!p) {
323 /* allocate if not found */
bellard90f18422005-07-24 10:17:31 +0000324 if (!alloc)
325 return NULL;
326 p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000327 *lp = p;
328 }
329 return p + (index & (L2_SIZE - 1));
bellard90f18422005-07-24 10:17:31 +0000330#endif
bellard9fa3e852004-01-04 18:06:42 +0000331}
332
bellard90f18422005-07-24 10:17:31 +0000333static inline VirtPageDesc *virt_page_find(target_ulong index)
bellard9fa3e852004-01-04 18:06:42 +0000334{
bellard90f18422005-07-24 10:17:31 +0000335 return virt_page_find_alloc(index, 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000336}
337
bellard90f18422005-07-24 10:17:31 +0000338#if TARGET_LONG_BITS > 32
339static void virt_page_flush_internal(void **p, int level)
340{
341 int i;
342 if (level == 0) {
343 VirtPageDesc *q = (VirtPageDesc *)p;
344 for(i = 0; i < VIRT_L_SIZE; i++)
345 q[i].valid_tag = 0;
346 } else {
347 level--;
348 for(i = 0; i < VIRT_L_SIZE; i++) {
349 if (p[i])
350 virt_page_flush_internal(p[i], level);
351 }
352 }
353}
354#endif
355
bellard9fa3e852004-01-04 18:06:42 +0000356static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000357{
bellard9fa3e852004-01-04 18:06:42 +0000358 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000359
bellard9fa3e852004-01-04 18:06:42 +0000360 if (virt_valid_tag == 0) {
361 virt_valid_tag = 1;
bellard90f18422005-07-24 10:17:31 +0000362#if TARGET_LONG_BITS > 32
363 virt_page_flush_internal(l1_virt_map, 5);
364#else
365 {
366 int i, j;
367 VirtPageDesc *p;
368 for(i = 0; i < L1_SIZE; i++) {
369 p = l1_virt_map[i];
370 if (p) {
371 for(j = 0; j < L2_SIZE; j++)
372 p[j].valid_tag = 0;
373 }
bellard9fa3e852004-01-04 18:06:42 +0000374 }
bellardfd6ce8f2003-05-14 19:00:11 +0000375 }
bellard90f18422005-07-24 10:17:31 +0000376#endif
bellard54936002003-05-13 00:25:15 +0000377 }
378}
bellard9fa3e852004-01-04 18:06:42 +0000379#else
380static void virt_page_flush(void)
381{
382}
383#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000384
bellardb346ff42003-06-15 20:05:50 +0000385void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000386{
387 if (!code_gen_ptr) {
388 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000389 page_init();
bellard33417e72003-08-10 21:47:01 +0000390 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000391 }
392}
393
bellard9fa3e852004-01-04 18:06:42 +0000394static inline void invalidate_page_bitmap(PageDesc *p)
395{
396 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000397 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000398 p->code_bitmap = NULL;
399 }
400 p->code_write_count = 0;
401}
402
bellardfd6ce8f2003-05-14 19:00:11 +0000403/* set to NULL all the 'first_tb' fields in all PageDescs */
404static void page_flush_tb(void)
405{
406 int i, j;
407 PageDesc *p;
408
409 for(i = 0; i < L1_SIZE; i++) {
410 p = l1_map[i];
411 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000412 for(j = 0; j < L2_SIZE; j++) {
413 p->first_tb = NULL;
414 invalidate_page_bitmap(p);
415 p++;
416 }
bellardfd6ce8f2003-05-14 19:00:11 +0000417 }
418 }
419}
420
421/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000422/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000423void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000424{
bellard01243112004-01-04 15:48:17 +0000425#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000426 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
427 code_gen_ptr - code_gen_buffer,
428 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000429 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000430#endif
431 nb_tbs = 0;
bellard8a8a6082004-10-03 13:36:49 +0000432 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000433 virt_page_flush();
434
bellard8a8a6082004-10-03 13:36:49 +0000435 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000436 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000437
bellardfd6ce8f2003-05-14 19:00:11 +0000438 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000439 /* XXX: flush processor icache at this point if cache flush is
440 expensive */
bellarde3db7222005-01-26 22:00:47 +0000441 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000442}
443
444#ifdef DEBUG_TB_CHECK
445
446static void tb_invalidate_check(unsigned long address)
447{
448 TranslationBlock *tb;
449 int i;
450 address &= TARGET_PAGE_MASK;
451 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
452 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
453 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
454 address >= tb->pc + tb->size)) {
455 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
456 address, tb->pc, tb->size);
457 }
458 }
459 }
460}
461
462/* verify that all the pages have correct rights for code */
463static void tb_page_check(void)
464{
465 TranslationBlock *tb;
466 int i, flags1, flags2;
467
468 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
469 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
470 flags1 = page_get_flags(tb->pc);
471 flags2 = page_get_flags(tb->pc + tb->size - 1);
472 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
473 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
474 tb->pc, tb->size, flags1, flags2);
475 }
476 }
477 }
478}
479
bellardd4e81642003-05-25 16:46:15 +0000480void tb_jmp_check(TranslationBlock *tb)
481{
482 TranslationBlock *tb1;
483 unsigned int n1;
484
485 /* suppress any remaining jumps to this TB */
486 tb1 = tb->jmp_first;
487 for(;;) {
488 n1 = (long)tb1 & 3;
489 tb1 = (TranslationBlock *)((long)tb1 & ~3);
490 if (n1 == 2)
491 break;
492 tb1 = tb1->jmp_next[n1];
493 }
494 /* check end of list */
495 if (tb1 != tb) {
496 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
497 }
498}
499
bellardfd6ce8f2003-05-14 19:00:11 +0000500#endif
501
502/* invalidate one TB */
503static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
504 int next_offset)
505{
506 TranslationBlock *tb1;
507 for(;;) {
508 tb1 = *ptb;
509 if (tb1 == tb) {
510 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
511 break;
512 }
513 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
514 }
515}
516
bellard9fa3e852004-01-04 18:06:42 +0000517static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
518{
519 TranslationBlock *tb1;
520 unsigned int n1;
521
522 for(;;) {
523 tb1 = *ptb;
524 n1 = (long)tb1 & 3;
525 tb1 = (TranslationBlock *)((long)tb1 & ~3);
526 if (tb1 == tb) {
527 *ptb = tb1->page_next[n1];
528 break;
529 }
530 ptb = &tb1->page_next[n1];
531 }
532}
533
bellardd4e81642003-05-25 16:46:15 +0000534static inline void tb_jmp_remove(TranslationBlock *tb, int n)
535{
536 TranslationBlock *tb1, **ptb;
537 unsigned int n1;
538
539 ptb = &tb->jmp_next[n];
540 tb1 = *ptb;
541 if (tb1) {
542 /* find tb(n) in circular list */
543 for(;;) {
544 tb1 = *ptb;
545 n1 = (long)tb1 & 3;
546 tb1 = (TranslationBlock *)((long)tb1 & ~3);
547 if (n1 == n && tb1 == tb)
548 break;
549 if (n1 == 2) {
550 ptb = &tb1->jmp_first;
551 } else {
552 ptb = &tb1->jmp_next[n1];
553 }
554 }
555 /* now we can suppress tb(n) from the list */
556 *ptb = tb->jmp_next[n];
557
558 tb->jmp_next[n] = NULL;
559 }
560}
561
562/* reset the jump entry 'n' of a TB so that it is not chained to
563 another TB */
564static inline void tb_reset_jump(TranslationBlock *tb, int n)
565{
566 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
567}
568
bellard9fa3e852004-01-04 18:06:42 +0000569static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000570{
bellardd4e81642003-05-25 16:46:15 +0000571 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000572 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000573
bellard36bdbe52003-11-19 22:12:02 +0000574 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000575
bellardfd6ce8f2003-05-14 19:00:11 +0000576 /* remove the TB from the hash list */
577 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000578 ptb = &tb_hash[h];
579 for(;;) {
580 tb1 = *ptb;
581 /* NOTE: the TB is not necessarily linked in the hash. It
582 indicates that it is not currently used */
583 if (tb1 == NULL)
584 return;
585 if (tb1 == tb) {
586 *ptb = tb1->hash_next;
587 break;
588 }
589 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000590 }
bellardd4e81642003-05-25 16:46:15 +0000591
592 /* suppress this TB from the two jump lists */
593 tb_jmp_remove(tb, 0);
594 tb_jmp_remove(tb, 1);
595
596 /* suppress any remaining jumps to this TB */
597 tb1 = tb->jmp_first;
598 for(;;) {
599 n1 = (long)tb1 & 3;
600 if (n1 == 2)
601 break;
602 tb1 = (TranslationBlock *)((long)tb1 & ~3);
603 tb2 = tb1->jmp_next[n1];
604 tb_reset_jump(tb1, n1);
605 tb1->jmp_next[n1] = NULL;
606 tb1 = tb2;
607 }
608 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000609}
610
bellard9fa3e852004-01-04 18:06:42 +0000611static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000612{
bellardfd6ce8f2003-05-14 19:00:11 +0000613 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000614 unsigned int h;
615 target_ulong phys_pc;
616
617 /* remove the TB from the hash list */
618 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
619 h = tb_phys_hash_func(phys_pc);
620 tb_remove(&tb_phys_hash[h], tb,
621 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000622
bellard9fa3e852004-01-04 18:06:42 +0000623 /* remove the TB from the page list */
624 if (tb->page_addr[0] != page_addr) {
625 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
626 tb_page_remove(&p->first_tb, tb);
627 invalidate_page_bitmap(p);
628 }
629 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
630 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
631 tb_page_remove(&p->first_tb, tb);
632 invalidate_page_bitmap(p);
633 }
634
635 tb_invalidate(tb);
bellarde3db7222005-01-26 22:00:47 +0000636 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000637}
638
639static inline void set_bits(uint8_t *tab, int start, int len)
640{
641 int end, mask, end1;
642
643 end = start + len;
644 tab += start >> 3;
645 mask = 0xff << (start & 7);
646 if ((start & ~7) == (end & ~7)) {
647 if (start < end) {
648 mask &= ~(0xff << (end & 7));
649 *tab |= mask;
650 }
651 } else {
652 *tab++ |= mask;
653 start = (start + 8) & ~7;
654 end1 = end & ~7;
655 while (start < end1) {
656 *tab++ = 0xff;
657 start += 8;
658 }
659 if (start < end) {
660 mask = ~(0xff << (end & 7));
661 *tab |= mask;
662 }
663 }
664}
665
666static void build_page_bitmap(PageDesc *p)
667{
668 int n, tb_start, tb_end;
669 TranslationBlock *tb;
670
bellard59817cc2004-02-16 22:01:13 +0000671 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000672 if (!p->code_bitmap)
673 return;
674 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
675
676 tb = p->first_tb;
677 while (tb != NULL) {
678 n = (long)tb & 3;
679 tb = (TranslationBlock *)((long)tb & ~3);
680 /* NOTE: this is subtle as a TB may span two physical pages */
681 if (n == 0) {
682 /* NOTE: tb_end may be after the end of the page, but
683 it is not a problem */
684 tb_start = tb->pc & ~TARGET_PAGE_MASK;
685 tb_end = tb_start + tb->size;
686 if (tb_end > TARGET_PAGE_SIZE)
687 tb_end = TARGET_PAGE_SIZE;
688 } else {
689 tb_start = 0;
690 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
691 }
692 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
693 tb = tb->page_next[n];
694 }
695}
696
bellardd720b932004-04-25 17:57:43 +0000697#ifdef TARGET_HAS_PRECISE_SMC
698
699static void tb_gen_code(CPUState *env,
700 target_ulong pc, target_ulong cs_base, int flags,
701 int cflags)
702{
703 TranslationBlock *tb;
704 uint8_t *tc_ptr;
705 target_ulong phys_pc, phys_page2, virt_page2;
706 int code_gen_size;
707
bellardc27004e2005-01-03 23:35:10 +0000708 phys_pc = get_phys_addr_code(env, pc);
709 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000710 if (!tb) {
711 /* flush must be done */
712 tb_flush(env);
713 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000714 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000715 }
716 tc_ptr = code_gen_ptr;
717 tb->tc_ptr = tc_ptr;
718 tb->cs_base = cs_base;
719 tb->flags = flags;
720 tb->cflags = cflags;
721 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
722 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
723
724 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000725 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000726 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000727 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000728 phys_page2 = get_phys_addr_code(env, virt_page2);
729 }
730 tb_link_phys(tb, phys_pc, phys_page2);
731}
732#endif
733
bellard9fa3e852004-01-04 18:06:42 +0000734/* invalidate all TBs which intersect with the target physical page
735 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000736 the same physical page. 'is_cpu_write_access' should be true if called
737 from a real cpu write access: the virtual CPU will exit the current
738 TB if code is modified inside this TB. */
739void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
740 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000741{
bellardd720b932004-04-25 17:57:43 +0000742 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000743 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000744 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000745 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000746 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000747 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000748
749 p = page_find(start >> TARGET_PAGE_BITS);
750 if (!p)
751 return;
752 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000753 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
754 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000755 /* build code bitmap */
756 build_page_bitmap(p);
757 }
758
759 /* we remove all the TBs in the range [start, end[ */
760 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000761 current_tb_not_found = is_cpu_write_access;
762 current_tb_modified = 0;
763 current_tb = NULL; /* avoid warning */
764 current_pc = 0; /* avoid warning */
765 current_cs_base = 0; /* avoid warning */
766 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000767 tb = p->first_tb;
768 while (tb != NULL) {
769 n = (long)tb & 3;
770 tb = (TranslationBlock *)((long)tb & ~3);
771 tb_next = tb->page_next[n];
772 /* NOTE: this is subtle as a TB may span two physical pages */
773 if (n == 0) {
774 /* NOTE: tb_end may be after the end of the page, but
775 it is not a problem */
776 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
777 tb_end = tb_start + tb->size;
778 } else {
779 tb_start = tb->page_addr[1];
780 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
781 }
782 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000783#ifdef TARGET_HAS_PRECISE_SMC
784 if (current_tb_not_found) {
785 current_tb_not_found = 0;
786 current_tb = NULL;
787 if (env->mem_write_pc) {
788 /* now we have a real cpu fault */
789 current_tb = tb_find_pc(env->mem_write_pc);
790 }
791 }
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,
802 env->mem_write_pc, NULL);
803#if defined(TARGET_I386)
804 current_flags = env->hflags;
805 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
806 current_cs_base = (target_ulong)env->segs[R_CS].base;
807 current_pc = current_cs_base + env->eip;
808#else
809#error unsupported CPU
810#endif
811 }
812#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000813 saved_tb = env->current_tb;
814 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000815 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000816 env->current_tb = saved_tb;
817 if (env->interrupt_request && env->current_tb)
818 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000819 }
820 tb = tb_next;
821 }
822#if !defined(CONFIG_USER_ONLY)
823 /* if no code remaining, no need to continue to use slow writes */
824 if (!p->first_tb) {
825 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000826 if (is_cpu_write_access) {
827 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
828 }
829 }
830#endif
831#ifdef TARGET_HAS_PRECISE_SMC
832 if (current_tb_modified) {
833 /* we generate a block containing just the instruction
834 modifying the memory. It will ensure that it cannot modify
835 itself */
bellardea1c1802004-06-14 18:56:36 +0000836 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000837 tb_gen_code(env, current_pc, current_cs_base, current_flags,
838 CF_SINGLE_INSN);
839 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000840 }
841#endif
842}
843
844/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000845static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000846{
847 PageDesc *p;
848 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000849#if 0
bellarda4193c82004-06-03 14:01:43 +0000850 if (1) {
851 if (loglevel) {
852 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
853 cpu_single_env->mem_write_vaddr, len,
854 cpu_single_env->eip,
855 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
856 }
bellard59817cc2004-02-16 22:01:13 +0000857 }
858#endif
bellard9fa3e852004-01-04 18:06:42 +0000859 p = page_find(start >> TARGET_PAGE_BITS);
860 if (!p)
861 return;
862 if (p->code_bitmap) {
863 offset = start & ~TARGET_PAGE_MASK;
864 b = p->code_bitmap[offset >> 3] >> (offset & 7);
865 if (b & ((1 << len) - 1))
866 goto do_invalidate;
867 } else {
868 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000869 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000870 }
871}
872
bellard9fa3e852004-01-04 18:06:42 +0000873#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000874static void tb_invalidate_phys_page(target_ulong addr,
875 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000876{
bellardd720b932004-04-25 17:57:43 +0000877 int n, current_flags, current_tb_modified;
878 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000879 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000880 TranslationBlock *tb, *current_tb;
881#ifdef TARGET_HAS_PRECISE_SMC
882 CPUState *env = cpu_single_env;
883#endif
bellard9fa3e852004-01-04 18:06:42 +0000884
885 addr &= TARGET_PAGE_MASK;
886 p = page_find(addr >> TARGET_PAGE_BITS);
887 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000888 return;
889 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000890 current_tb_modified = 0;
891 current_tb = NULL;
892 current_pc = 0; /* avoid warning */
893 current_cs_base = 0; /* avoid warning */
894 current_flags = 0; /* avoid warning */
895#ifdef TARGET_HAS_PRECISE_SMC
896 if (tb && pc != 0) {
897 current_tb = tb_find_pc(pc);
898 }
899#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000900 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000901 n = (long)tb & 3;
902 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000903#ifdef TARGET_HAS_PRECISE_SMC
904 if (current_tb == tb &&
905 !(current_tb->cflags & CF_SINGLE_INSN)) {
906 /* If we are modifying the current TB, we must stop
907 its execution. We could be more precise by checking
908 that the modification is after the current PC, but it
909 would require a specialized function to partially
910 restore the CPU state */
911
912 current_tb_modified = 1;
913 cpu_restore_state(current_tb, env, pc, puc);
914#if defined(TARGET_I386)
915 current_flags = env->hflags;
916 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
917 current_cs_base = (target_ulong)env->segs[R_CS].base;
918 current_pc = current_cs_base + env->eip;
919#else
920#error unsupported CPU
921#endif
922 }
923#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000924 tb_phys_invalidate(tb, addr);
925 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000926 }
927 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000928#ifdef TARGET_HAS_PRECISE_SMC
929 if (current_tb_modified) {
930 /* we generate a block containing just the instruction
931 modifying the memory. It will ensure that it cannot modify
932 itself */
bellardea1c1802004-06-14 18:56:36 +0000933 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000934 tb_gen_code(env, current_pc, current_cs_base, current_flags,
935 CF_SINGLE_INSN);
936 cpu_resume_from_signal(env, puc);
937 }
938#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000939}
bellard9fa3e852004-01-04 18:06:42 +0000940#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000941
942/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000943static inline void tb_alloc_page(TranslationBlock *tb,
944 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000945{
946 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000947 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000948
bellard9fa3e852004-01-04 18:06:42 +0000949 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000950 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000951 tb->page_next[n] = p->first_tb;
952 last_first_tb = p->first_tb;
953 p->first_tb = (TranslationBlock *)((long)tb | n);
954 invalidate_page_bitmap(p);
955
bellard107db442004-06-22 18:48:46 +0000956#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000957
bellard9fa3e852004-01-04 18:06:42 +0000958#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000959 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000960 unsigned long host_start, host_end, addr;
961 int prot;
962
bellardfd6ce8f2003-05-14 19:00:11 +0000963 /* force the host page as non writable (writes will have a
964 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000965 host_start = page_addr & qemu_host_page_mask;
966 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000967 prot = 0;
968 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
969 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000970 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000971 (prot & PAGE_BITS) & ~PAGE_WRITE);
972#ifdef DEBUG_TB_INVALIDATE
973 printf("protecting code page: 0x%08lx\n",
974 host_start);
975#endif
976 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000977 }
bellard9fa3e852004-01-04 18:06:42 +0000978#else
979 /* if some code is already present, then the pages are already
980 protected. So we handle the case where only the first TB is
981 allocated in a physical page */
982 if (!last_first_tb) {
983 target_ulong virt_addr;
984
985 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +0000986 tlb_protect_code(cpu_single_env, page_addr, virt_addr);
bellard9fa3e852004-01-04 18:06:42 +0000987 }
988#endif
bellardd720b932004-04-25 17:57:43 +0000989
990#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000991}
992
993/* Allocate a new translation block. Flush the translation buffer if
994 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000995TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000996{
997 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000998
999 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
1000 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +00001001 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001002 tb = &tbs[nb_tbs++];
1003 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001004 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001005 return tb;
1006}
1007
bellard9fa3e852004-01-04 18:06:42 +00001008/* add a new TB and link it to the physical page tables. phys_page2 is
1009 (-1) to indicate that only one page contains the TB. */
1010void tb_link_phys(TranslationBlock *tb,
1011 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001012{
bellard9fa3e852004-01-04 18:06:42 +00001013 unsigned int h;
1014 TranslationBlock **ptb;
1015
1016 /* add in the physical hash table */
1017 h = tb_phys_hash_func(phys_pc);
1018 ptb = &tb_phys_hash[h];
1019 tb->phys_hash_next = *ptb;
1020 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001021
1022 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001023 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1024 if (phys_page2 != -1)
1025 tb_alloc_page(tb, 1, phys_page2);
1026 else
1027 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +00001028#ifdef DEBUG_TB_CHECK
1029 tb_page_check();
1030#endif
bellard9fa3e852004-01-04 18:06:42 +00001031}
1032
1033/* link the tb with the other TBs */
1034void tb_link(TranslationBlock *tb)
1035{
1036#if !defined(CONFIG_USER_ONLY)
1037 {
1038 VirtPageDesc *vp;
1039 target_ulong addr;
1040
1041 /* save the code memory mappings (needed to invalidate the code) */
1042 addr = tb->pc & TARGET_PAGE_MASK;
bellard90f18422005-07-24 10:17:31 +00001043 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard98857882004-01-18 21:52:14 +00001044#ifdef DEBUG_TLB_CHECK
1045 if (vp->valid_tag == virt_valid_tag &&
1046 vp->phys_addr != tb->page_addr[0]) {
1047 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
1048 addr, tb->page_addr[0], vp->phys_addr);
1049 }
1050#endif
bellard9fa3e852004-01-04 18:06:42 +00001051 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +00001052 if (vp->valid_tag != virt_valid_tag) {
1053 vp->valid_tag = virt_valid_tag;
1054#if !defined(CONFIG_SOFTMMU)
1055 vp->prot = 0;
1056#endif
1057 }
bellard9fa3e852004-01-04 18:06:42 +00001058
1059 if (tb->page_addr[1] != -1) {
1060 addr += TARGET_PAGE_SIZE;
bellard90f18422005-07-24 10:17:31 +00001061 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard98857882004-01-18 21:52:14 +00001062#ifdef DEBUG_TLB_CHECK
1063 if (vp->valid_tag == virt_valid_tag &&
1064 vp->phys_addr != tb->page_addr[1]) {
1065 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
1066 addr, tb->page_addr[1], vp->phys_addr);
1067 }
1068#endif
bellard9fa3e852004-01-04 18:06:42 +00001069 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +00001070 if (vp->valid_tag != virt_valid_tag) {
1071 vp->valid_tag = virt_valid_tag;
1072#if !defined(CONFIG_SOFTMMU)
1073 vp->prot = 0;
1074#endif
1075 }
bellard9fa3e852004-01-04 18:06:42 +00001076 }
1077 }
1078#endif
1079
bellardd4e81642003-05-25 16:46:15 +00001080 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1081 tb->jmp_next[0] = NULL;
1082 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +00001083#ifdef USE_CODE_COPY
1084 tb->cflags &= ~CF_FP_USED;
1085 if (tb->cflags & CF_TB_FP_USED)
1086 tb->cflags |= CF_FP_USED;
1087#endif
bellardd4e81642003-05-25 16:46:15 +00001088
1089 /* init original jump addresses */
1090 if (tb->tb_next_offset[0] != 0xffff)
1091 tb_reset_jump(tb, 0);
1092 if (tb->tb_next_offset[1] != 0xffff)
1093 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +00001094}
1095
bellarda513fe12003-05-27 23:29:48 +00001096/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1097 tb[1].tc_ptr. Return NULL if not found */
1098TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1099{
1100 int m_min, m_max, m;
1101 unsigned long v;
1102 TranslationBlock *tb;
1103
1104 if (nb_tbs <= 0)
1105 return NULL;
1106 if (tc_ptr < (unsigned long)code_gen_buffer ||
1107 tc_ptr >= (unsigned long)code_gen_ptr)
1108 return NULL;
1109 /* binary search (cf Knuth) */
1110 m_min = 0;
1111 m_max = nb_tbs - 1;
1112 while (m_min <= m_max) {
1113 m = (m_min + m_max) >> 1;
1114 tb = &tbs[m];
1115 v = (unsigned long)tb->tc_ptr;
1116 if (v == tc_ptr)
1117 return tb;
1118 else if (tc_ptr < v) {
1119 m_max = m - 1;
1120 } else {
1121 m_min = m + 1;
1122 }
1123 }
1124 return &tbs[m_max];
1125}
bellard75012672003-06-21 13:11:07 +00001126
bellardea041c02003-06-25 16:16:50 +00001127static void tb_reset_jump_recursive(TranslationBlock *tb);
1128
1129static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1130{
1131 TranslationBlock *tb1, *tb_next, **ptb;
1132 unsigned int n1;
1133
1134 tb1 = tb->jmp_next[n];
1135 if (tb1 != NULL) {
1136 /* find head of list */
1137 for(;;) {
1138 n1 = (long)tb1 & 3;
1139 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1140 if (n1 == 2)
1141 break;
1142 tb1 = tb1->jmp_next[n1];
1143 }
1144 /* we are now sure now that tb jumps to tb1 */
1145 tb_next = tb1;
1146
1147 /* remove tb from the jmp_first list */
1148 ptb = &tb_next->jmp_first;
1149 for(;;) {
1150 tb1 = *ptb;
1151 n1 = (long)tb1 & 3;
1152 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1153 if (n1 == n && tb1 == tb)
1154 break;
1155 ptb = &tb1->jmp_next[n1];
1156 }
1157 *ptb = tb->jmp_next[n];
1158 tb->jmp_next[n] = NULL;
1159
1160 /* suppress the jump to next tb in generated code */
1161 tb_reset_jump(tb, n);
1162
bellard01243112004-01-04 15:48:17 +00001163 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001164 tb_reset_jump_recursive(tb_next);
1165 }
1166}
1167
1168static void tb_reset_jump_recursive(TranslationBlock *tb)
1169{
1170 tb_reset_jump_recursive2(tb, 0);
1171 tb_reset_jump_recursive2(tb, 1);
1172}
1173
bellard1fddef42005-04-17 19:16:13 +00001174#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001175static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1176{
1177 target_ulong phys_addr;
1178
1179 phys_addr = cpu_get_phys_page_debug(env, pc);
1180 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1181}
bellardc27004e2005-01-03 23:35:10 +00001182#endif
bellardd720b932004-04-25 17:57:43 +00001183
bellardc33a3462003-07-29 20:50:33 +00001184/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1185 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001186int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001187{
bellard1fddef42005-04-17 19:16:13 +00001188#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001189 int i;
bellardd720b932004-04-25 17:57:43 +00001190
bellard4c3a88a2003-07-26 12:06:08 +00001191 for(i = 0; i < env->nb_breakpoints; i++) {
1192 if (env->breakpoints[i] == pc)
1193 return 0;
1194 }
1195
1196 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1197 return -1;
1198 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001199
1200 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001201 return 0;
1202#else
1203 return -1;
1204#endif
1205}
1206
1207/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001208int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001209{
bellard1fddef42005-04-17 19:16:13 +00001210#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001211 int i;
1212 for(i = 0; i < env->nb_breakpoints; i++) {
1213 if (env->breakpoints[i] == pc)
1214 goto found;
1215 }
1216 return -1;
1217 found:
bellard4c3a88a2003-07-26 12:06:08 +00001218 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001219 if (i < env->nb_breakpoints)
1220 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001221
1222 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001223 return 0;
1224#else
1225 return -1;
1226#endif
1227}
1228
bellardc33a3462003-07-29 20:50:33 +00001229/* enable or disable single step mode. EXCP_DEBUG is returned by the
1230 CPU loop after each instruction */
1231void cpu_single_step(CPUState *env, int enabled)
1232{
bellard1fddef42005-04-17 19:16:13 +00001233#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001234 if (env->singlestep_enabled != enabled) {
1235 env->singlestep_enabled = enabled;
1236 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001237 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001238 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001239 }
1240#endif
1241}
1242
bellard34865132003-10-05 14:28:56 +00001243/* enable or disable low levels log */
1244void cpu_set_log(int log_flags)
1245{
1246 loglevel = log_flags;
1247 if (loglevel && !logfile) {
1248 logfile = fopen(logfilename, "w");
1249 if (!logfile) {
1250 perror(logfilename);
1251 _exit(1);
1252 }
bellard9fa3e852004-01-04 18:06:42 +00001253#if !defined(CONFIG_SOFTMMU)
1254 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1255 {
1256 static uint8_t logfile_buf[4096];
1257 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1258 }
1259#else
bellard34865132003-10-05 14:28:56 +00001260 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001261#endif
bellard34865132003-10-05 14:28:56 +00001262 }
1263}
1264
1265void cpu_set_log_filename(const char *filename)
1266{
1267 logfilename = strdup(filename);
1268}
bellardc33a3462003-07-29 20:50:33 +00001269
bellard01243112004-01-04 15:48:17 +00001270/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001271void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001272{
1273 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001274 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001275
bellard68a79312003-06-30 13:12:32 +00001276 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001277 /* if the cpu is currently executing code, we must unlink it and
1278 all the potentially executing TB */
1279 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001280 if (tb && !testandset(&interrupt_lock)) {
1281 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001282 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001283 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001284 }
1285}
1286
bellardb54ad042004-05-20 13:42:52 +00001287void cpu_reset_interrupt(CPUState *env, int mask)
1288{
1289 env->interrupt_request &= ~mask;
1290}
1291
bellardf193c792004-03-21 17:06:25 +00001292CPULogItem cpu_log_items[] = {
1293 { CPU_LOG_TB_OUT_ASM, "out_asm",
1294 "show generated host assembly code for each compiled TB" },
1295 { CPU_LOG_TB_IN_ASM, "in_asm",
1296 "show target assembly code for each compiled TB" },
1297 { CPU_LOG_TB_OP, "op",
1298 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1299#ifdef TARGET_I386
1300 { CPU_LOG_TB_OP_OPT, "op_opt",
1301 "show micro ops after optimization for each compiled TB" },
1302#endif
1303 { CPU_LOG_INT, "int",
1304 "show interrupts/exceptions in short format" },
1305 { CPU_LOG_EXEC, "exec",
1306 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001307 { CPU_LOG_TB_CPU, "cpu",
1308 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001309#ifdef TARGET_I386
1310 { CPU_LOG_PCALL, "pcall",
1311 "show protected mode far calls/returns/exceptions" },
1312#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001313#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001314 { CPU_LOG_IOPORT, "ioport",
1315 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001316#endif
bellardf193c792004-03-21 17:06:25 +00001317 { 0, NULL, NULL },
1318};
1319
1320static int cmp1(const char *s1, int n, const char *s2)
1321{
1322 if (strlen(s2) != n)
1323 return 0;
1324 return memcmp(s1, s2, n) == 0;
1325}
1326
1327/* takes a comma separated list of log masks. Return 0 if error. */
1328int cpu_str_to_log_mask(const char *str)
1329{
1330 CPULogItem *item;
1331 int mask;
1332 const char *p, *p1;
1333
1334 p = str;
1335 mask = 0;
1336 for(;;) {
1337 p1 = strchr(p, ',');
1338 if (!p1)
1339 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001340 if(cmp1(p,p1-p,"all")) {
1341 for(item = cpu_log_items; item->mask != 0; item++) {
1342 mask |= item->mask;
1343 }
1344 } else {
bellardf193c792004-03-21 17:06:25 +00001345 for(item = cpu_log_items; item->mask != 0; item++) {
1346 if (cmp1(p, p1 - p, item->name))
1347 goto found;
1348 }
1349 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001350 }
bellardf193c792004-03-21 17:06:25 +00001351 found:
1352 mask |= item->mask;
1353 if (*p1 != ',')
1354 break;
1355 p = p1 + 1;
1356 }
1357 return mask;
1358}
bellardea041c02003-06-25 16:16:50 +00001359
bellard75012672003-06-21 13:11:07 +00001360void cpu_abort(CPUState *env, const char *fmt, ...)
1361{
1362 va_list ap;
1363
1364 va_start(ap, fmt);
1365 fprintf(stderr, "qemu: fatal: ");
1366 vfprintf(stderr, fmt, ap);
1367 fprintf(stderr, "\n");
1368#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001369 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1370#else
1371 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001372#endif
1373 va_end(ap);
1374 abort();
1375}
1376
bellard01243112004-01-04 15:48:17 +00001377#if !defined(CONFIG_USER_ONLY)
1378
bellardee8b7022004-02-03 23:35:10 +00001379/* NOTE: if flush_global is true, also flush global entries (not
1380 implemented yet) */
1381void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001382{
bellard33417e72003-08-10 21:47:01 +00001383 int i;
bellard01243112004-01-04 15:48:17 +00001384
bellard9fa3e852004-01-04 18:06:42 +00001385#if defined(DEBUG_TLB)
1386 printf("tlb_flush:\n");
1387#endif
bellard01243112004-01-04 15:48:17 +00001388 /* must reset current TB so that interrupts cannot modify the
1389 links while we are modifying them */
1390 env->current_tb = NULL;
1391
bellard33417e72003-08-10 21:47:01 +00001392 for(i = 0; i < CPU_TLB_SIZE; i++) {
1393 env->tlb_read[0][i].address = -1;
1394 env->tlb_write[0][i].address = -1;
1395 env->tlb_read[1][i].address = -1;
1396 env->tlb_write[1][i].address = -1;
1397 }
bellard9fa3e852004-01-04 18:06:42 +00001398
1399 virt_page_flush();
bellard8a8a6082004-10-03 13:36:49 +00001400 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001401
1402#if !defined(CONFIG_SOFTMMU)
1403 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1404#endif
bellard0a962c02005-02-10 22:00:27 +00001405#ifdef USE_KQEMU
1406 if (env->kqemu_enabled) {
1407 kqemu_flush(env, flush_global);
1408 }
1409#endif
bellarde3db7222005-01-26 22:00:47 +00001410 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001411}
1412
bellard274da6b2004-05-20 21:56:27 +00001413static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001414{
1415 if (addr == (tlb_entry->address &
1416 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1417 tlb_entry->address = -1;
1418}
1419
bellard2e126692004-04-25 21:28:44 +00001420void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001421{
bellard9fa3e852004-01-04 18:06:42 +00001422 int i, n;
1423 VirtPageDesc *vp;
1424 PageDesc *p;
1425 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001426
bellard9fa3e852004-01-04 18:06:42 +00001427#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001428 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001429#endif
bellard01243112004-01-04 15:48:17 +00001430 /* must reset current TB so that interrupts cannot modify the
1431 links while we are modifying them */
1432 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001433
bellard61382a52003-10-27 21:22:23 +00001434 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001435 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001436 tlb_flush_entry(&env->tlb_read[0][i], addr);
1437 tlb_flush_entry(&env->tlb_write[0][i], addr);
1438 tlb_flush_entry(&env->tlb_read[1][i], addr);
1439 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001440
bellard9fa3e852004-01-04 18:06:42 +00001441 /* remove from the virtual pc hash table all the TB at this
1442 virtual address */
1443
1444 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1445 if (vp && vp->valid_tag == virt_valid_tag) {
1446 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1447 if (p) {
1448 /* we remove all the links to the TBs in this virtual page */
1449 tb = p->first_tb;
1450 while (tb != NULL) {
1451 n = (long)tb & 3;
1452 tb = (TranslationBlock *)((long)tb & ~3);
1453 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1454 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1455 tb_invalidate(tb);
1456 }
1457 tb = tb->page_next[n];
1458 }
1459 }
bellard98857882004-01-18 21:52:14 +00001460 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001461 }
1462
bellard01243112004-01-04 15:48:17 +00001463#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001464 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001465 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001466#endif
bellard0a962c02005-02-10 22:00:27 +00001467#ifdef USE_KQEMU
1468 if (env->kqemu_enabled) {
1469 kqemu_flush_page(env, addr);
1470 }
1471#endif
bellard9fa3e852004-01-04 18:06:42 +00001472}
1473
bellard4f2ac232004-04-26 19:44:02 +00001474static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001475{
1476 if (addr == (tlb_entry->address &
1477 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard3a7d9292005-08-21 09:26:42 +00001478 (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1479 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard01243112004-01-04 15:48:17 +00001480 }
bellard61382a52003-10-27 21:22:23 +00001481}
1482
bellard9fa3e852004-01-04 18:06:42 +00001483/* update the TLBs so that writes to code in the virtual page 'addr'
1484 can be detected */
bellard3a7d9292005-08-21 09:26:42 +00001485static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
1486 target_ulong vaddr)
bellard61382a52003-10-27 21:22:23 +00001487{
bellard61382a52003-10-27 21:22:23 +00001488 int i;
1489
bellard3a7d9292005-08-21 09:26:42 +00001490 vaddr &= TARGET_PAGE_MASK;
1491 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1492 tlb_protect_code1(&env->tlb_write[0][i], vaddr);
1493 tlb_protect_code1(&env->tlb_write[1][i], vaddr);
1494
bellard3a7d9292005-08-21 09:26:42 +00001495#ifdef USE_KQEMU
1496 if (env->kqemu_enabled) {
1497 kqemu_set_notdirty(env, ram_addr);
1498 }
1499#endif
bellardf23db162005-08-21 19:12:28 +00001500 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG;
bellard3a7d9292005-08-21 09:26:42 +00001501
bellard9fa3e852004-01-04 18:06:42 +00001502#if !defined(CONFIG_SOFTMMU)
1503 /* NOTE: as we generated the code for this page, it is already at
1504 least readable */
bellard3a7d9292005-08-21 09:26:42 +00001505 if (vaddr < MMAP_AREA_END)
1506 mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ);
bellard9fa3e852004-01-04 18:06:42 +00001507#endif
1508}
1509
bellard9fa3e852004-01-04 18:06:42 +00001510/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001511 tested for self modifying code */
1512static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1513 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001514{
bellard3a7d9292005-08-21 09:26:42 +00001515 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001516}
1517
1518static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1519 unsigned long start, unsigned long length)
1520{
1521 unsigned long addr;
1522 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1523 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1524 if ((addr - start) < length) {
1525 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1526 }
1527 }
1528}
1529
bellard3a7d9292005-08-21 09:26:42 +00001530void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001531 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001532{
1533 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001534 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001535 int i, mask, len;
1536 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001537
1538 start &= TARGET_PAGE_MASK;
1539 end = TARGET_PAGE_ALIGN(end);
1540
1541 length = end - start;
1542 if (length == 0)
1543 return;
bellard0a962c02005-02-10 22:00:27 +00001544 len = length >> TARGET_PAGE_BITS;
bellard1ccde1c2004-02-06 19:46:14 +00001545 env = cpu_single_env;
bellard3a7d9292005-08-21 09:26:42 +00001546#ifdef USE_KQEMU
1547 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001548 ram_addr_t addr;
1549 addr = start;
1550 for(i = 0; i < len; i++) {
1551 kqemu_set_notdirty(env, addr);
1552 addr += TARGET_PAGE_SIZE;
1553 }
bellard3a7d9292005-08-21 09:26:42 +00001554 }
1555#endif
bellardf23db162005-08-21 19:12:28 +00001556 mask = ~dirty_flags;
1557 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1558 for(i = 0; i < len; i++)
1559 p[i] &= mask;
1560
bellard1ccde1c2004-02-06 19:46:14 +00001561 /* we modify the TLB cache so that the dirty bit will be set again
1562 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001563 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001564 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001565 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001566 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001567 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1568
1569#if !defined(CONFIG_SOFTMMU)
1570 /* XXX: this is expensive */
1571 {
1572 VirtPageDesc *p;
1573 int j;
1574 target_ulong addr;
1575
1576 for(i = 0; i < L1_SIZE; i++) {
1577 p = l1_virt_map[i];
1578 if (p) {
1579 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1580 for(j = 0; j < L2_SIZE; j++) {
1581 if (p->valid_tag == virt_valid_tag &&
1582 p->phys_addr >= start && p->phys_addr < end &&
1583 (p->prot & PROT_WRITE)) {
1584 if (addr < MMAP_AREA_END) {
1585 mprotect((void *)addr, TARGET_PAGE_SIZE,
1586 p->prot & ~PROT_WRITE);
1587 }
1588 }
1589 addr += TARGET_PAGE_SIZE;
1590 p++;
1591 }
1592 }
1593 }
1594 }
1595#endif
bellard1ccde1c2004-02-06 19:46:14 +00001596}
1597
bellard3a7d9292005-08-21 09:26:42 +00001598static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1599{
1600 ram_addr_t ram_addr;
1601
1602 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1603 ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) +
1604 tlb_entry->addend - (unsigned long)phys_ram_base;
1605 if (!cpu_physical_memory_is_dirty(ram_addr)) {
1606 tlb_entry->address |= IO_MEM_NOTDIRTY;
1607 }
1608 }
1609}
1610
1611/* update the TLB according to the current state of the dirty bits */
1612void cpu_tlb_update_dirty(CPUState *env)
1613{
1614 int i;
1615 for(i = 0; i < CPU_TLB_SIZE; i++)
1616 tlb_update_dirty(&env->tlb_write[0][i]);
1617 for(i = 0; i < CPU_TLB_SIZE; i++)
1618 tlb_update_dirty(&env->tlb_write[1][i]);
1619}
1620
bellard1ccde1c2004-02-06 19:46:14 +00001621static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001622 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001623{
1624 unsigned long addr;
1625 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1626 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1627 if (addr == start) {
1628 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1629 }
1630 }
1631}
1632
1633/* update the TLB corresponding to virtual page vaddr and phys addr
1634 addr so that it is no longer dirty */
1635static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1636{
1637 CPUState *env = cpu_single_env;
1638 int i;
1639
bellard1ccde1c2004-02-06 19:46:14 +00001640 addr &= TARGET_PAGE_MASK;
1641 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1642 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1643 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001644}
1645
bellard59817cc2004-02-16 22:01:13 +00001646/* add a new TLB entry. At most one entry for a given virtual address
1647 is permitted. Return 0 if OK or 2 if the page could not be mapped
1648 (can only happen in non SOFTMMU mode for I/O pages or pages
1649 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001650int tlb_set_page(CPUState *env, target_ulong vaddr,
1651 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001652 int is_user, int is_softmmu)
1653{
bellard92e873b2004-05-21 14:52:29 +00001654 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001655 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001656 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001657 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001658 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001659 int ret;
1660
bellard92e873b2004-05-21 14:52:29 +00001661 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001662 if (!p) {
1663 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001664 } else {
1665 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001666 }
1667#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001668 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
1669 vaddr, paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001670#endif
1671
1672 ret = 0;
1673#if !defined(CONFIG_SOFTMMU)
1674 if (is_softmmu)
1675#endif
1676 {
1677 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1678 /* IO memory case */
1679 address = vaddr | pd;
1680 addend = paddr;
1681 } else {
1682 /* standard memory */
1683 address = vaddr;
1684 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1685 }
1686
bellard90f18422005-07-24 10:17:31 +00001687 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001688 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001689 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001690 env->tlb_read[is_user][index].address = address;
1691 env->tlb_read[is_user][index].addend = addend;
1692 } else {
1693 env->tlb_read[is_user][index].address = -1;
1694 env->tlb_read[is_user][index].addend = -1;
1695 }
bellard67b915a2004-03-31 23:37:16 +00001696 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001697 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1698 /* ROM: access is ignored (same as unassigned) */
1699 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001700 env->tlb_write[is_user][index].addend = addend;
bellard3a7d9292005-08-21 09:26:42 +00001701 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001702 !cpu_physical_memory_is_dirty(pd)) {
1703 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1704 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001705 } else {
1706 env->tlb_write[is_user][index].address = address;
1707 env->tlb_write[is_user][index].addend = addend;
1708 }
1709 } else {
1710 env->tlb_write[is_user][index].address = -1;
1711 env->tlb_write[is_user][index].addend = -1;
1712 }
1713 }
1714#if !defined(CONFIG_SOFTMMU)
1715 else {
1716 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1717 /* IO access: no mapping is done as it will be handled by the
1718 soft MMU */
1719 if (!(env->hflags & HF_SOFTMMU_MASK))
1720 ret = 2;
1721 } else {
1722 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001723
bellard59817cc2004-02-16 22:01:13 +00001724 if (vaddr >= MMAP_AREA_END) {
1725 ret = 2;
1726 } else {
1727 if (prot & PROT_WRITE) {
1728 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001729#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001730 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001731#endif
bellard59817cc2004-02-16 22:01:13 +00001732 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1733 !cpu_physical_memory_is_dirty(pd))) {
1734 /* ROM: we do as if code was inside */
1735 /* if code is present, we only map as read only and save the
1736 original mapping */
1737 VirtPageDesc *vp;
1738
bellard90f18422005-07-24 10:17:31 +00001739 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001740 vp->phys_addr = pd;
1741 vp->prot = prot;
1742 vp->valid_tag = virt_valid_tag;
1743 prot &= ~PAGE_WRITE;
1744 }
bellard9fa3e852004-01-04 18:06:42 +00001745 }
bellard59817cc2004-02-16 22:01:13 +00001746 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1747 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1748 if (map_addr == MAP_FAILED) {
1749 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1750 paddr, vaddr);
1751 }
bellard9fa3e852004-01-04 18:06:42 +00001752 }
1753 }
1754 }
1755#endif
1756 return ret;
1757}
1758
1759/* called from signal handler: invalidate the code and unprotect the
1760 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001761int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001762{
1763#if !defined(CONFIG_SOFTMMU)
1764 VirtPageDesc *vp;
1765
1766#if defined(DEBUG_TLB)
1767 printf("page_unprotect: addr=0x%08x\n", addr);
1768#endif
1769 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001770
1771 /* if it is not mapped, no need to worry here */
1772 if (addr >= MMAP_AREA_END)
1773 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001774 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1775 if (!vp)
1776 return 0;
1777 /* NOTE: in this case, validate_tag is _not_ tested as it
1778 validates only the code TLB */
1779 if (vp->valid_tag != virt_valid_tag)
1780 return 0;
1781 if (!(vp->prot & PAGE_WRITE))
1782 return 0;
1783#if defined(DEBUG_TLB)
1784 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1785 addr, vp->phys_addr, vp->prot);
1786#endif
bellard59817cc2004-02-16 22:01:13 +00001787 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1788 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1789 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001790 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001791 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001792 /* flush the code inside */
1793 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001794 return 1;
1795#else
1796 return 0;
1797#endif
bellard33417e72003-08-10 21:47:01 +00001798}
1799
bellard01243112004-01-04 15:48:17 +00001800#else
1801
bellardee8b7022004-02-03 23:35:10 +00001802void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001803{
1804}
1805
bellard2e126692004-04-25 21:28:44 +00001806void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001807{
1808}
1809
bellard2e126692004-04-25 21:28:44 +00001810int tlb_set_page(CPUState *env, target_ulong vaddr,
1811 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001812 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001813{
bellard9fa3e852004-01-04 18:06:42 +00001814 return 0;
1815}
bellard33417e72003-08-10 21:47:01 +00001816
bellard9fa3e852004-01-04 18:06:42 +00001817/* dump memory mappings */
1818void page_dump(FILE *f)
1819{
1820 unsigned long start, end;
1821 int i, j, prot, prot1;
1822 PageDesc *p;
1823
1824 fprintf(f, "%-8s %-8s %-8s %s\n",
1825 "start", "end", "size", "prot");
1826 start = -1;
1827 end = -1;
1828 prot = 0;
1829 for(i = 0; i <= L1_SIZE; i++) {
1830 if (i < L1_SIZE)
1831 p = l1_map[i];
1832 else
1833 p = NULL;
1834 for(j = 0;j < L2_SIZE; j++) {
1835 if (!p)
1836 prot1 = 0;
1837 else
1838 prot1 = p[j].flags;
1839 if (prot1 != prot) {
1840 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1841 if (start != -1) {
1842 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1843 start, end, end - start,
1844 prot & PAGE_READ ? 'r' : '-',
1845 prot & PAGE_WRITE ? 'w' : '-',
1846 prot & PAGE_EXEC ? 'x' : '-');
1847 }
1848 if (prot1 != 0)
1849 start = end;
1850 else
1851 start = -1;
1852 prot = prot1;
1853 }
1854 if (!p)
1855 break;
1856 }
bellard33417e72003-08-10 21:47:01 +00001857 }
bellard33417e72003-08-10 21:47:01 +00001858}
1859
bellard9fa3e852004-01-04 18:06:42 +00001860int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001861{
bellard9fa3e852004-01-04 18:06:42 +00001862 PageDesc *p;
1863
1864 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001865 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001866 return 0;
1867 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001868}
1869
bellard9fa3e852004-01-04 18:06:42 +00001870/* modify the flags of a page and invalidate the code if
1871 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1872 depending on PAGE_WRITE */
1873void page_set_flags(unsigned long start, unsigned long end, int flags)
1874{
1875 PageDesc *p;
1876 unsigned long addr;
1877
1878 start = start & TARGET_PAGE_MASK;
1879 end = TARGET_PAGE_ALIGN(end);
1880 if (flags & PAGE_WRITE)
1881 flags |= PAGE_WRITE_ORG;
1882 spin_lock(&tb_lock);
1883 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1884 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1885 /* if the write protection is set, then we invalidate the code
1886 inside */
1887 if (!(p->flags & PAGE_WRITE) &&
1888 (flags & PAGE_WRITE) &&
1889 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001890 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001891 }
1892 p->flags = flags;
1893 }
1894 spin_unlock(&tb_lock);
1895}
1896
1897/* called from signal handler: invalidate the code and unprotect the
1898 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001899int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001900{
1901 unsigned int page_index, prot, pindex;
1902 PageDesc *p, *p1;
1903 unsigned long host_start, host_end, addr;
1904
bellard83fb7ad2004-07-05 21:25:26 +00001905 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001906 page_index = host_start >> TARGET_PAGE_BITS;
1907 p1 = page_find(page_index);
1908 if (!p1)
1909 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001910 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001911 p = p1;
1912 prot = 0;
1913 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1914 prot |= p->flags;
1915 p++;
1916 }
1917 /* if the page was really writable, then we change its
1918 protection back to writable */
1919 if (prot & PAGE_WRITE_ORG) {
1920 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1921 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001922 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001923 (prot & PAGE_BITS) | PAGE_WRITE);
1924 p1[pindex].flags |= PAGE_WRITE;
1925 /* and since the content will be modified, we must invalidate
1926 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001927 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001928#ifdef DEBUG_TB_CHECK
1929 tb_invalidate_check(address);
1930#endif
1931 return 1;
1932 }
1933 }
1934 return 0;
1935}
1936
1937/* call this function when system calls directly modify a memory area */
1938void page_unprotect_range(uint8_t *data, unsigned long data_size)
1939{
1940 unsigned long start, end, addr;
1941
1942 start = (unsigned long)data;
1943 end = start + data_size;
1944 start &= TARGET_PAGE_MASK;
1945 end = TARGET_PAGE_ALIGN(end);
1946 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001947 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001948 }
1949}
1950
bellard1ccde1c2004-02-06 19:46:14 +00001951static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1952{
1953}
bellard9fa3e852004-01-04 18:06:42 +00001954#endif /* defined(CONFIG_USER_ONLY) */
1955
bellard33417e72003-08-10 21:47:01 +00001956/* register physical memory. 'size' must be a multiple of the target
1957 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1958 io memory page */
bellard2e126692004-04-25 21:28:44 +00001959void cpu_register_physical_memory(target_phys_addr_t start_addr,
1960 unsigned long size,
1961 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001962{
bellard108c49b2005-07-24 12:55:09 +00001963 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001964 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001965
bellard5fd386f2004-05-23 21:11:22 +00001966 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001967 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001968 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001969 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001970 p->phys_offset = phys_offset;
1971 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001972 phys_offset += TARGET_PAGE_SIZE;
1973 }
1974}
1975
bellarda4193c82004-06-03 14:01:43 +00001976static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001977{
1978 return 0;
1979}
1980
bellarda4193c82004-06-03 14:01:43 +00001981static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001982{
1983}
1984
1985static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1986 unassigned_mem_readb,
1987 unassigned_mem_readb,
1988 unassigned_mem_readb,
1989};
1990
1991static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1992 unassigned_mem_writeb,
1993 unassigned_mem_writeb,
1994 unassigned_mem_writeb,
1995};
1996
bellarda4193c82004-06-03 14:01:43 +00001997static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001998{
bellard3a7d9292005-08-21 09:26:42 +00001999 unsigned long ram_addr;
2000 int dirty_flags;
2001 ram_addr = addr - (unsigned long)phys_ram_base;
2002 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2003 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2004#if !defined(CONFIG_USER_ONLY)
2005 tb_invalidate_phys_page_fast(ram_addr, 1);
2006 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2007#endif
2008 }
bellardc27004e2005-01-03 23:35:10 +00002009 stb_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00002010 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2011 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2012 /* we remove the notdirty callback only if the code has been
2013 flushed */
2014 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00002015 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002016}
2017
bellarda4193c82004-06-03 14:01:43 +00002018static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002019{
bellard3a7d9292005-08-21 09:26:42 +00002020 unsigned long ram_addr;
2021 int dirty_flags;
2022 ram_addr = addr - (unsigned long)phys_ram_base;
2023 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2024 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2025#if !defined(CONFIG_USER_ONLY)
2026 tb_invalidate_phys_page_fast(ram_addr, 2);
2027 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2028#endif
2029 }
bellardc27004e2005-01-03 23:35:10 +00002030 stw_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00002031 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2032 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2033 /* we remove the notdirty callback only if the code has been
2034 flushed */
2035 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00002036 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002037}
2038
bellarda4193c82004-06-03 14:01:43 +00002039static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002040{
bellard3a7d9292005-08-21 09:26:42 +00002041 unsigned long ram_addr;
2042 int dirty_flags;
2043 ram_addr = addr - (unsigned long)phys_ram_base;
2044 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2045 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2046#if !defined(CONFIG_USER_ONLY)
2047 tb_invalidate_phys_page_fast(ram_addr, 4);
2048 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2049#endif
2050 }
bellardc27004e2005-01-03 23:35:10 +00002051 stl_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00002052 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2053 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2054 /* we remove the notdirty callback only if the code has been
2055 flushed */
2056 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00002057 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002058}
2059
bellard3a7d9292005-08-21 09:26:42 +00002060static CPUReadMemoryFunc *error_mem_read[3] = {
2061 NULL, /* never used */
2062 NULL, /* never used */
2063 NULL, /* never used */
2064};
2065
bellard1ccde1c2004-02-06 19:46:14 +00002066static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2067 notdirty_mem_writeb,
2068 notdirty_mem_writew,
2069 notdirty_mem_writel,
2070};
2071
bellard33417e72003-08-10 21:47:01 +00002072static void io_mem_init(void)
2073{
bellard3a7d9292005-08-21 09:26:42 +00002074 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002075 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002076 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002077 io_mem_nb = 5;
2078
2079 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002080 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002081 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002082}
2083
2084/* mem_read and mem_write are arrays of functions containing the
2085 function to access byte (index 0), word (index 1) and dword (index
2086 2). All functions must be supplied. If io_index is non zero, the
2087 corresponding io zone is modified. If it is zero, a new io zone is
2088 allocated. The return value can be used with
2089 cpu_register_physical_memory(). (-1) is returned if error. */
2090int cpu_register_io_memory(int io_index,
2091 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002092 CPUWriteMemoryFunc **mem_write,
2093 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002094{
2095 int i;
2096
2097 if (io_index <= 0) {
2098 if (io_index >= IO_MEM_NB_ENTRIES)
2099 return -1;
2100 io_index = io_mem_nb++;
2101 } else {
2102 if (io_index >= IO_MEM_NB_ENTRIES)
2103 return -1;
2104 }
2105
2106 for(i = 0;i < 3; i++) {
2107 io_mem_read[io_index][i] = mem_read[i];
2108 io_mem_write[io_index][i] = mem_write[i];
2109 }
bellarda4193c82004-06-03 14:01:43 +00002110 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002111 return io_index << IO_MEM_SHIFT;
2112}
bellard61382a52003-10-27 21:22:23 +00002113
bellard8926b512004-10-10 15:14:20 +00002114CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2115{
2116 return io_mem_write[io_index >> IO_MEM_SHIFT];
2117}
2118
2119CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2120{
2121 return io_mem_read[io_index >> IO_MEM_SHIFT];
2122}
2123
bellard13eb76e2004-01-24 15:23:36 +00002124/* physical memory access (slow version, mainly for debug) */
2125#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002126void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002127 int len, int is_write)
2128{
2129 int l, flags;
2130 target_ulong page;
2131
2132 while (len > 0) {
2133 page = addr & TARGET_PAGE_MASK;
2134 l = (page + TARGET_PAGE_SIZE) - addr;
2135 if (l > len)
2136 l = len;
2137 flags = page_get_flags(page);
2138 if (!(flags & PAGE_VALID))
2139 return;
2140 if (is_write) {
2141 if (!(flags & PAGE_WRITE))
2142 return;
2143 memcpy((uint8_t *)addr, buf, len);
2144 } else {
2145 if (!(flags & PAGE_READ))
2146 return;
2147 memcpy(buf, (uint8_t *)addr, len);
2148 }
2149 len -= l;
2150 buf += l;
2151 addr += l;
2152 }
2153}
bellard8df1cd02005-01-28 22:37:22 +00002154
2155/* never used */
2156uint32_t ldl_phys(target_phys_addr_t addr)
2157{
2158 return 0;
2159}
2160
2161void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2162{
2163}
2164
2165void stl_phys(target_phys_addr_t addr, uint32_t val)
2166{
2167}
2168
bellard13eb76e2004-01-24 15:23:36 +00002169#else
bellard2e126692004-04-25 21:28:44 +00002170void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002171 int len, int is_write)
2172{
2173 int l, io_index;
2174 uint8_t *ptr;
2175 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002176 target_phys_addr_t page;
2177 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002178 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002179
2180 while (len > 0) {
2181 page = addr & TARGET_PAGE_MASK;
2182 l = (page + TARGET_PAGE_SIZE) - addr;
2183 if (l > len)
2184 l = len;
bellard92e873b2004-05-21 14:52:29 +00002185 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002186 if (!p) {
2187 pd = IO_MEM_UNASSIGNED;
2188 } else {
2189 pd = p->phys_offset;
2190 }
2191
2192 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002193 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002194 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2195 if (l >= 4 && ((addr & 3) == 0)) {
2196 /* 32 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002197 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002198 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002199 l = 4;
2200 } else if (l >= 2 && ((addr & 1) == 0)) {
2201 /* 16 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002202 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002203 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002204 l = 2;
2205 } else {
2206 /* 8 bit access */
bellardc27004e2005-01-03 23:35:10 +00002207 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002208 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002209 l = 1;
2210 }
2211 } else {
bellardb448f2f2004-02-25 23:24:04 +00002212 unsigned long addr1;
2213 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002214 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002215 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002216 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002217 if (!cpu_physical_memory_is_dirty(addr1)) {
2218 /* invalidate code */
2219 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2220 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002221 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2222 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002223 }
bellard13eb76e2004-01-24 15:23:36 +00002224 }
2225 } else {
bellard3a7d9292005-08-21 09:26:42 +00002226 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard13eb76e2004-01-24 15:23:36 +00002227 /* I/O case */
2228 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2229 if (l >= 4 && ((addr & 3) == 0)) {
2230 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002231 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002232 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002233 l = 4;
2234 } else if (l >= 2 && ((addr & 1) == 0)) {
2235 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002236 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002237 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002238 l = 2;
2239 } else {
2240 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002241 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002242 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002243 l = 1;
2244 }
2245 } else {
2246 /* RAM case */
2247 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2248 (addr & ~TARGET_PAGE_MASK);
2249 memcpy(buf, ptr, l);
2250 }
2251 }
2252 len -= l;
2253 buf += l;
2254 addr += l;
2255 }
2256}
bellard8df1cd02005-01-28 22:37:22 +00002257
2258/* warning: addr must be aligned */
2259uint32_t ldl_phys(target_phys_addr_t addr)
2260{
2261 int io_index;
2262 uint8_t *ptr;
2263 uint32_t val;
2264 unsigned long pd;
2265 PhysPageDesc *p;
2266
2267 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2268 if (!p) {
2269 pd = IO_MEM_UNASSIGNED;
2270 } else {
2271 pd = p->phys_offset;
2272 }
2273
bellard3a7d9292005-08-21 09:26:42 +00002274 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard8df1cd02005-01-28 22:37:22 +00002275 /* I/O case */
2276 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2277 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2278 } else {
2279 /* RAM case */
2280 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2281 (addr & ~TARGET_PAGE_MASK);
2282 val = ldl_p(ptr);
2283 }
2284 return val;
2285}
2286
2287/* warning: addr must be aligned. The ram page is not masked as dirty
2288 and the code inside is not invalidated. It is useful if the dirty
2289 bits are used to track modified PTEs */
2290void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2291{
2292 int io_index;
2293 uint8_t *ptr;
2294 unsigned long pd;
2295 PhysPageDesc *p;
2296
2297 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2298 if (!p) {
2299 pd = IO_MEM_UNASSIGNED;
2300 } else {
2301 pd = p->phys_offset;
2302 }
2303
bellard3a7d9292005-08-21 09:26:42 +00002304 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002305 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2306 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2307 } else {
2308 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2309 (addr & ~TARGET_PAGE_MASK);
2310 stl_p(ptr, val);
2311 }
2312}
2313
2314/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002315void stl_phys(target_phys_addr_t addr, uint32_t val)
2316{
2317 int io_index;
2318 uint8_t *ptr;
2319 unsigned long pd;
2320 PhysPageDesc *p;
2321
2322 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2323 if (!p) {
2324 pd = IO_MEM_UNASSIGNED;
2325 } else {
2326 pd = p->phys_offset;
2327 }
2328
bellard3a7d9292005-08-21 09:26:42 +00002329 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002330 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2331 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2332 } else {
2333 unsigned long addr1;
2334 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2335 /* RAM case */
2336 ptr = phys_ram_base + addr1;
2337 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002338 if (!cpu_physical_memory_is_dirty(addr1)) {
2339 /* invalidate code */
2340 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2341 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002342 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2343 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002344 }
bellard8df1cd02005-01-28 22:37:22 +00002345 }
2346}
2347
bellard13eb76e2004-01-24 15:23:36 +00002348#endif
2349
2350/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002351int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2352 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002353{
2354 int l;
2355 target_ulong page, phys_addr;
2356
2357 while (len > 0) {
2358 page = addr & TARGET_PAGE_MASK;
2359 phys_addr = cpu_get_phys_page_debug(env, page);
2360 /* if no physical page mapped, return an error */
2361 if (phys_addr == -1)
2362 return -1;
2363 l = (page + TARGET_PAGE_SIZE) - addr;
2364 if (l > len)
2365 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002366 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2367 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002368 len -= l;
2369 buf += l;
2370 addr += l;
2371 }
2372 return 0;
2373}
2374
bellarde3db7222005-01-26 22:00:47 +00002375void dump_exec_info(FILE *f,
2376 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2377{
2378 int i, target_code_size, max_target_code_size;
2379 int direct_jmp_count, direct_jmp2_count, cross_page;
2380 TranslationBlock *tb;
2381
2382 target_code_size = 0;
2383 max_target_code_size = 0;
2384 cross_page = 0;
2385 direct_jmp_count = 0;
2386 direct_jmp2_count = 0;
2387 for(i = 0; i < nb_tbs; i++) {
2388 tb = &tbs[i];
2389 target_code_size += tb->size;
2390 if (tb->size > max_target_code_size)
2391 max_target_code_size = tb->size;
2392 if (tb->page_addr[1] != -1)
2393 cross_page++;
2394 if (tb->tb_next_offset[0] != 0xffff) {
2395 direct_jmp_count++;
2396 if (tb->tb_next_offset[1] != 0xffff) {
2397 direct_jmp2_count++;
2398 }
2399 }
2400 }
2401 /* XXX: avoid using doubles ? */
2402 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2403 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2404 nb_tbs ? target_code_size / nb_tbs : 0,
2405 max_target_code_size);
2406 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2407 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2408 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2409 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2410 cross_page,
2411 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2412 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2413 direct_jmp_count,
2414 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2415 direct_jmp2_count,
2416 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2417 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2418 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2419 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2420}
2421
bellard61382a52003-10-27 21:22:23 +00002422#if !defined(CONFIG_USER_ONLY)
2423
2424#define MMUSUFFIX _cmmu
2425#define GETPC() NULL
2426#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002427#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002428
2429#define SHIFT 0
2430#include "softmmu_template.h"
2431
2432#define SHIFT 1
2433#include "softmmu_template.h"
2434
2435#define SHIFT 2
2436#include "softmmu_template.h"
2437
2438#define SHIFT 3
2439#include "softmmu_template.h"
2440
2441#undef env
2442
2443#endif