blob: 8aed3d00c0a0761532406782510bf782834a2934 [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000037
bellardfd6ce8f2003-05-14 19:00:11 +000038//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000039//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000040//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000041
42/* make various TB consistency checks */
43//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000044//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* threshold to flush the translated code buffer */
47#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
48
bellard9fa3e852004-01-04 18:06:42 +000049#define SMC_BITMAP_USE_THRESHOLD 10
50
51#define MMAP_AREA_START 0x00000000
52#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000053
bellard108c49b2005-07-24 12:55:09 +000054#if defined(TARGET_SPARC64)
55#define TARGET_PHYS_ADDR_SPACE_BITS 41
56#elif defined(TARGET_PPC64)
57#define TARGET_PHYS_ADDR_SPACE_BITS 42
58#else
59/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
60#define TARGET_PHYS_ADDR_SPACE_BITS 32
61#endif
62
bellardfd6ce8f2003-05-14 19:00:11 +000063TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000064TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000065int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000066/* any access to the tbs or the page table must use this lock */
67spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000068
bellardb8076a72005-04-07 22:20:31 +000069uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000070uint8_t *code_gen_ptr;
71
bellard9fa3e852004-01-04 18:06:42 +000072int phys_ram_size;
73int phys_ram_fd;
74uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000075uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000076
bellard54936002003-05-13 00:25:15 +000077typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000078 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000079 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000080 /* in order to optimize self modifying code, we count the number
81 of lookups we do to a given page to use a bitmap */
82 unsigned int code_write_count;
83 uint8_t *code_bitmap;
84#if defined(CONFIG_USER_ONLY)
85 unsigned long flags;
86#endif
bellard54936002003-05-13 00:25:15 +000087} PageDesc;
88
bellard92e873b2004-05-21 14:52:29 +000089typedef struct PhysPageDesc {
90 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +000091 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +000092} PhysPageDesc;
93
bellard54936002003-05-13 00:25:15 +000094#define L2_BITS 10
95#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
96
97#define L1_SIZE (1 << L1_BITS)
98#define L2_SIZE (1 << L2_BITS)
99
bellard33417e72003-08-10 21:47:01 +0000100static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000101
bellard83fb7ad2004-07-05 21:25:26 +0000102unsigned long qemu_real_host_page_size;
103unsigned long qemu_host_page_bits;
104unsigned long qemu_host_page_size;
105unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000106
bellard92e873b2004-05-21 14:52:29 +0000107/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000108static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000109PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000110
bellard33417e72003-08-10 21:47:01 +0000111/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000112CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
113CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000114void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000115static int io_mem_nb;
116
bellard34865132003-10-05 14:28:56 +0000117/* log support */
118char *logfilename = "/tmp/qemu.log";
119FILE *logfile;
120int loglevel;
121
bellarde3db7222005-01-26 22:00:47 +0000122/* statistics */
123static int tlb_flush_count;
124static int tb_flush_count;
125static int tb_phys_invalidate_count;
126
bellardb346ff42003-06-15 20:05:50 +0000127static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000128{
bellard83fb7ad2004-07-05 21:25:26 +0000129 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000130 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000131#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000132 {
133 SYSTEM_INFO system_info;
134 DWORD old_protect;
135
136 GetSystemInfo(&system_info);
137 qemu_real_host_page_size = system_info.dwPageSize;
138
139 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
140 PAGE_EXECUTE_READWRITE, &old_protect);
141 }
bellard67b915a2004-03-31 23:37:16 +0000142#else
bellard83fb7ad2004-07-05 21:25:26 +0000143 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000144 {
145 unsigned long start, end;
146
147 start = (unsigned long)code_gen_buffer;
148 start &= ~(qemu_real_host_page_size - 1);
149
150 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
151 end += qemu_real_host_page_size - 1;
152 end &= ~(qemu_real_host_page_size - 1);
153
154 mprotect((void *)start, end - start,
155 PROT_READ | PROT_WRITE | PROT_EXEC);
156 }
bellard67b915a2004-03-31 23:37:16 +0000157#endif
bellardd5a8f072004-09-29 21:15:28 +0000158
bellard83fb7ad2004-07-05 21:25:26 +0000159 if (qemu_host_page_size == 0)
160 qemu_host_page_size = qemu_real_host_page_size;
161 if (qemu_host_page_size < TARGET_PAGE_SIZE)
162 qemu_host_page_size = TARGET_PAGE_SIZE;
163 qemu_host_page_bits = 0;
164 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
165 qemu_host_page_bits++;
166 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000167 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
168 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000169}
170
bellardfd6ce8f2003-05-14 19:00:11 +0000171static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000172{
bellard54936002003-05-13 00:25:15 +0000173 PageDesc **lp, *p;
174
bellard54936002003-05-13 00:25:15 +0000175 lp = &l1_map[index >> L2_BITS];
176 p = *lp;
177 if (!p) {
178 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000179 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000180 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000181 *lp = p;
182 }
183 return p + (index & (L2_SIZE - 1));
184}
185
bellardfd6ce8f2003-05-14 19:00:11 +0000186static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000187{
bellard54936002003-05-13 00:25:15 +0000188 PageDesc *p;
189
bellard54936002003-05-13 00:25:15 +0000190 p = l1_map[index >> L2_BITS];
191 if (!p)
192 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000193 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000194}
195
bellard108c49b2005-07-24 12:55:09 +0000196static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000197{
bellard108c49b2005-07-24 12:55:09 +0000198 void **lp, **p;
bellard92e873b2004-05-21 14:52:29 +0000199
bellard108c49b2005-07-24 12:55:09 +0000200 p = (void **)l1_phys_map;
201#if TARGET_PHYS_ADDR_SPACE_BITS > 32
202
203#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
204#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
205#endif
206 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000207 p = *lp;
208 if (!p) {
209 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000210 if (!alloc)
211 return NULL;
212 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
213 memset(p, 0, sizeof(void *) * L1_SIZE);
214 *lp = p;
215 }
216#endif
217 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
218 p = *lp;
219 if (!p) {
220 /* allocate if not found */
221 if (!alloc)
222 return NULL;
bellard0a962c02005-02-10 22:00:27 +0000223 p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
bellard92e873b2004-05-21 14:52:29 +0000224 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
225 *lp = p;
226 }
bellard108c49b2005-07-24 12:55:09 +0000227 return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000228}
229
bellard108c49b2005-07-24 12:55:09 +0000230static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000231{
bellard108c49b2005-07-24 12:55:09 +0000232 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000233}
234
bellard9fa3e852004-01-04 18:06:42 +0000235#if !defined(CONFIG_USER_ONLY)
bellard3a7d9292005-08-21 09:26:42 +0000236static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
237 target_ulong vaddr);
238static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
239 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000240#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000241
bellardb346ff42003-06-15 20:05:50 +0000242void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000243{
244 if (!code_gen_ptr) {
245 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000246 page_init();
bellard33417e72003-08-10 21:47:01 +0000247 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000248 }
249}
250
bellard9fa3e852004-01-04 18:06:42 +0000251static inline void invalidate_page_bitmap(PageDesc *p)
252{
253 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000254 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000255 p->code_bitmap = NULL;
256 }
257 p->code_write_count = 0;
258}
259
bellardfd6ce8f2003-05-14 19:00:11 +0000260/* set to NULL all the 'first_tb' fields in all PageDescs */
261static void page_flush_tb(void)
262{
263 int i, j;
264 PageDesc *p;
265
266 for(i = 0; i < L1_SIZE; i++) {
267 p = l1_map[i];
268 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000269 for(j = 0; j < L2_SIZE; j++) {
270 p->first_tb = NULL;
271 invalidate_page_bitmap(p);
272 p++;
273 }
bellardfd6ce8f2003-05-14 19:00:11 +0000274 }
275 }
276}
277
278/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000279/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000280void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000281{
bellard01243112004-01-04 15:48:17 +0000282#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000283 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
284 code_gen_ptr - code_gen_buffer,
285 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000286 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000287#endif
288 nb_tbs = 0;
bellard8a40a182005-11-20 10:35:40 +0000289 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000290
bellard8a8a6082004-10-03 13:36:49 +0000291 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000292 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000293
bellardfd6ce8f2003-05-14 19:00:11 +0000294 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000295 /* XXX: flush processor icache at this point if cache flush is
296 expensive */
bellarde3db7222005-01-26 22:00:47 +0000297 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000298}
299
300#ifdef DEBUG_TB_CHECK
301
302static void tb_invalidate_check(unsigned long address)
303{
304 TranslationBlock *tb;
305 int i;
306 address &= TARGET_PAGE_MASK;
307 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
308 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
309 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
310 address >= tb->pc + tb->size)) {
311 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
312 address, tb->pc, tb->size);
313 }
314 }
315 }
316}
317
318/* verify that all the pages have correct rights for code */
319static void tb_page_check(void)
320{
321 TranslationBlock *tb;
322 int i, flags1, flags2;
323
324 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
325 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
326 flags1 = page_get_flags(tb->pc);
327 flags2 = page_get_flags(tb->pc + tb->size - 1);
328 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
329 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
330 tb->pc, tb->size, flags1, flags2);
331 }
332 }
333 }
334}
335
bellardd4e81642003-05-25 16:46:15 +0000336void tb_jmp_check(TranslationBlock *tb)
337{
338 TranslationBlock *tb1;
339 unsigned int n1;
340
341 /* suppress any remaining jumps to this TB */
342 tb1 = tb->jmp_first;
343 for(;;) {
344 n1 = (long)tb1 & 3;
345 tb1 = (TranslationBlock *)((long)tb1 & ~3);
346 if (n1 == 2)
347 break;
348 tb1 = tb1->jmp_next[n1];
349 }
350 /* check end of list */
351 if (tb1 != tb) {
352 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
353 }
354}
355
bellardfd6ce8f2003-05-14 19:00:11 +0000356#endif
357
358/* invalidate one TB */
359static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
360 int next_offset)
361{
362 TranslationBlock *tb1;
363 for(;;) {
364 tb1 = *ptb;
365 if (tb1 == tb) {
366 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
367 break;
368 }
369 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
370 }
371}
372
bellard9fa3e852004-01-04 18:06:42 +0000373static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
374{
375 TranslationBlock *tb1;
376 unsigned int n1;
377
378 for(;;) {
379 tb1 = *ptb;
380 n1 = (long)tb1 & 3;
381 tb1 = (TranslationBlock *)((long)tb1 & ~3);
382 if (tb1 == tb) {
383 *ptb = tb1->page_next[n1];
384 break;
385 }
386 ptb = &tb1->page_next[n1];
387 }
388}
389
bellardd4e81642003-05-25 16:46:15 +0000390static inline void tb_jmp_remove(TranslationBlock *tb, int n)
391{
392 TranslationBlock *tb1, **ptb;
393 unsigned int n1;
394
395 ptb = &tb->jmp_next[n];
396 tb1 = *ptb;
397 if (tb1) {
398 /* find tb(n) in circular list */
399 for(;;) {
400 tb1 = *ptb;
401 n1 = (long)tb1 & 3;
402 tb1 = (TranslationBlock *)((long)tb1 & ~3);
403 if (n1 == n && tb1 == tb)
404 break;
405 if (n1 == 2) {
406 ptb = &tb1->jmp_first;
407 } else {
408 ptb = &tb1->jmp_next[n1];
409 }
410 }
411 /* now we can suppress tb(n) from the list */
412 *ptb = tb->jmp_next[n];
413
414 tb->jmp_next[n] = NULL;
415 }
416}
417
418/* reset the jump entry 'n' of a TB so that it is not chained to
419 another TB */
420static inline void tb_reset_jump(TranslationBlock *tb, int n)
421{
422 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
423}
424
bellard9fa3e852004-01-04 18:06:42 +0000425static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000426{
bellardfd6ce8f2003-05-14 19:00:11 +0000427 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000428 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000429 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000430 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000431
432 /* remove the TB from the hash list */
433 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
434 h = tb_phys_hash_func(phys_pc);
435 tb_remove(&tb_phys_hash[h], tb,
436 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000437
bellard9fa3e852004-01-04 18:06:42 +0000438 /* remove the TB from the page list */
439 if (tb->page_addr[0] != page_addr) {
440 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
441 tb_page_remove(&p->first_tb, tb);
442 invalidate_page_bitmap(p);
443 }
444 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
445 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
446 tb_page_remove(&p->first_tb, tb);
447 invalidate_page_bitmap(p);
448 }
449
bellard8a40a182005-11-20 10:35:40 +0000450 tb_invalidated_flag = 1;
451
452 /* remove the TB from the hash list */
453 h = tb_jmp_cache_hash_func(tb->pc);
454 cpu_single_env->tb_jmp_cache[h] = NULL;
455
456 /* suppress this TB from the two jump lists */
457 tb_jmp_remove(tb, 0);
458 tb_jmp_remove(tb, 1);
459
460 /* suppress any remaining jumps to this TB */
461 tb1 = tb->jmp_first;
462 for(;;) {
463 n1 = (long)tb1 & 3;
464 if (n1 == 2)
465 break;
466 tb1 = (TranslationBlock *)((long)tb1 & ~3);
467 tb2 = tb1->jmp_next[n1];
468 tb_reset_jump(tb1, n1);
469 tb1->jmp_next[n1] = NULL;
470 tb1 = tb2;
471 }
472 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
473
bellarde3db7222005-01-26 22:00:47 +0000474 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000475}
476
477static inline void set_bits(uint8_t *tab, int start, int len)
478{
479 int end, mask, end1;
480
481 end = start + len;
482 tab += start >> 3;
483 mask = 0xff << (start & 7);
484 if ((start & ~7) == (end & ~7)) {
485 if (start < end) {
486 mask &= ~(0xff << (end & 7));
487 *tab |= mask;
488 }
489 } else {
490 *tab++ |= mask;
491 start = (start + 8) & ~7;
492 end1 = end & ~7;
493 while (start < end1) {
494 *tab++ = 0xff;
495 start += 8;
496 }
497 if (start < end) {
498 mask = ~(0xff << (end & 7));
499 *tab |= mask;
500 }
501 }
502}
503
504static void build_page_bitmap(PageDesc *p)
505{
506 int n, tb_start, tb_end;
507 TranslationBlock *tb;
508
bellard59817cc2004-02-16 22:01:13 +0000509 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000510 if (!p->code_bitmap)
511 return;
512 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
513
514 tb = p->first_tb;
515 while (tb != NULL) {
516 n = (long)tb & 3;
517 tb = (TranslationBlock *)((long)tb & ~3);
518 /* NOTE: this is subtle as a TB may span two physical pages */
519 if (n == 0) {
520 /* NOTE: tb_end may be after the end of the page, but
521 it is not a problem */
522 tb_start = tb->pc & ~TARGET_PAGE_MASK;
523 tb_end = tb_start + tb->size;
524 if (tb_end > TARGET_PAGE_SIZE)
525 tb_end = TARGET_PAGE_SIZE;
526 } else {
527 tb_start = 0;
528 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
529 }
530 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
531 tb = tb->page_next[n];
532 }
533}
534
bellardd720b932004-04-25 17:57:43 +0000535#ifdef TARGET_HAS_PRECISE_SMC
536
537static void tb_gen_code(CPUState *env,
538 target_ulong pc, target_ulong cs_base, int flags,
539 int cflags)
540{
541 TranslationBlock *tb;
542 uint8_t *tc_ptr;
543 target_ulong phys_pc, phys_page2, virt_page2;
544 int code_gen_size;
545
bellardc27004e2005-01-03 23:35:10 +0000546 phys_pc = get_phys_addr_code(env, pc);
547 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000548 if (!tb) {
549 /* flush must be done */
550 tb_flush(env);
551 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000552 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000553 }
554 tc_ptr = code_gen_ptr;
555 tb->tc_ptr = tc_ptr;
556 tb->cs_base = cs_base;
557 tb->flags = flags;
558 tb->cflags = cflags;
559 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
560 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
561
562 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000563 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000564 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000565 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000566 phys_page2 = get_phys_addr_code(env, virt_page2);
567 }
568 tb_link_phys(tb, phys_pc, phys_page2);
569}
570#endif
571
bellard9fa3e852004-01-04 18:06:42 +0000572/* invalidate all TBs which intersect with the target physical page
573 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000574 the same physical page. 'is_cpu_write_access' should be true if called
575 from a real cpu write access: the virtual CPU will exit the current
576 TB if code is modified inside this TB. */
577void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
578 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000579{
bellardd720b932004-04-25 17:57:43 +0000580 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000581 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000582 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000583 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000584 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000585 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000586
587 p = page_find(start >> TARGET_PAGE_BITS);
588 if (!p)
589 return;
590 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000591 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
592 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000593 /* build code bitmap */
594 build_page_bitmap(p);
595 }
596
597 /* we remove all the TBs in the range [start, end[ */
598 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000599 current_tb_not_found = is_cpu_write_access;
600 current_tb_modified = 0;
601 current_tb = NULL; /* avoid warning */
602 current_pc = 0; /* avoid warning */
603 current_cs_base = 0; /* avoid warning */
604 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000605 tb = p->first_tb;
606 while (tb != NULL) {
607 n = (long)tb & 3;
608 tb = (TranslationBlock *)((long)tb & ~3);
609 tb_next = tb->page_next[n];
610 /* NOTE: this is subtle as a TB may span two physical pages */
611 if (n == 0) {
612 /* NOTE: tb_end may be after the end of the page, but
613 it is not a problem */
614 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
615 tb_end = tb_start + tb->size;
616 } else {
617 tb_start = tb->page_addr[1];
618 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
619 }
620 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000621#ifdef TARGET_HAS_PRECISE_SMC
622 if (current_tb_not_found) {
623 current_tb_not_found = 0;
624 current_tb = NULL;
625 if (env->mem_write_pc) {
626 /* now we have a real cpu fault */
627 current_tb = tb_find_pc(env->mem_write_pc);
628 }
629 }
630 if (current_tb == tb &&
631 !(current_tb->cflags & CF_SINGLE_INSN)) {
632 /* If we are modifying the current TB, we must stop
633 its execution. We could be more precise by checking
634 that the modification is after the current PC, but it
635 would require a specialized function to partially
636 restore the CPU state */
637
638 current_tb_modified = 1;
639 cpu_restore_state(current_tb, env,
640 env->mem_write_pc, NULL);
641#if defined(TARGET_I386)
642 current_flags = env->hflags;
643 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
644 current_cs_base = (target_ulong)env->segs[R_CS].base;
645 current_pc = current_cs_base + env->eip;
646#else
647#error unsupported CPU
648#endif
649 }
650#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000651 saved_tb = env->current_tb;
652 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000653 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000654 env->current_tb = saved_tb;
655 if (env->interrupt_request && env->current_tb)
656 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000657 }
658 tb = tb_next;
659 }
660#if !defined(CONFIG_USER_ONLY)
661 /* if no code remaining, no need to continue to use slow writes */
662 if (!p->first_tb) {
663 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000664 if (is_cpu_write_access) {
665 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
666 }
667 }
668#endif
669#ifdef TARGET_HAS_PRECISE_SMC
670 if (current_tb_modified) {
671 /* we generate a block containing just the instruction
672 modifying the memory. It will ensure that it cannot modify
673 itself */
bellardea1c1802004-06-14 18:56:36 +0000674 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000675 tb_gen_code(env, current_pc, current_cs_base, current_flags,
676 CF_SINGLE_INSN);
677 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000678 }
679#endif
680}
681
682/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000683static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000684{
685 PageDesc *p;
686 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000687#if 0
bellarda4193c82004-06-03 14:01:43 +0000688 if (1) {
689 if (loglevel) {
690 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
691 cpu_single_env->mem_write_vaddr, len,
692 cpu_single_env->eip,
693 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
694 }
bellard59817cc2004-02-16 22:01:13 +0000695 }
696#endif
bellard9fa3e852004-01-04 18:06:42 +0000697 p = page_find(start >> TARGET_PAGE_BITS);
698 if (!p)
699 return;
700 if (p->code_bitmap) {
701 offset = start & ~TARGET_PAGE_MASK;
702 b = p->code_bitmap[offset >> 3] >> (offset & 7);
703 if (b & ((1 << len) - 1))
704 goto do_invalidate;
705 } else {
706 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000707 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000708 }
709}
710
bellard9fa3e852004-01-04 18:06:42 +0000711#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000712static void tb_invalidate_phys_page(target_ulong addr,
713 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000714{
bellardd720b932004-04-25 17:57:43 +0000715 int n, current_flags, current_tb_modified;
716 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000717 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000718 TranslationBlock *tb, *current_tb;
719#ifdef TARGET_HAS_PRECISE_SMC
720 CPUState *env = cpu_single_env;
721#endif
bellard9fa3e852004-01-04 18:06:42 +0000722
723 addr &= TARGET_PAGE_MASK;
724 p = page_find(addr >> TARGET_PAGE_BITS);
725 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000726 return;
727 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000728 current_tb_modified = 0;
729 current_tb = NULL;
730 current_pc = 0; /* avoid warning */
731 current_cs_base = 0; /* avoid warning */
732 current_flags = 0; /* avoid warning */
733#ifdef TARGET_HAS_PRECISE_SMC
734 if (tb && pc != 0) {
735 current_tb = tb_find_pc(pc);
736 }
737#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000738 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000739 n = (long)tb & 3;
740 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000741#ifdef TARGET_HAS_PRECISE_SMC
742 if (current_tb == tb &&
743 !(current_tb->cflags & CF_SINGLE_INSN)) {
744 /* If we are modifying the current TB, we must stop
745 its execution. We could be more precise by checking
746 that the modification is after the current PC, but it
747 would require a specialized function to partially
748 restore the CPU state */
749
750 current_tb_modified = 1;
751 cpu_restore_state(current_tb, env, pc, puc);
752#if defined(TARGET_I386)
753 current_flags = env->hflags;
754 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
755 current_cs_base = (target_ulong)env->segs[R_CS].base;
756 current_pc = current_cs_base + env->eip;
757#else
758#error unsupported CPU
759#endif
760 }
761#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000762 tb_phys_invalidate(tb, addr);
763 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000764 }
765 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000766#ifdef TARGET_HAS_PRECISE_SMC
767 if (current_tb_modified) {
768 /* we generate a block containing just the instruction
769 modifying the memory. It will ensure that it cannot modify
770 itself */
bellardea1c1802004-06-14 18:56:36 +0000771 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000772 tb_gen_code(env, current_pc, current_cs_base, current_flags,
773 CF_SINGLE_INSN);
774 cpu_resume_from_signal(env, puc);
775 }
776#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000777}
bellard9fa3e852004-01-04 18:06:42 +0000778#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000779
780/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000781static inline void tb_alloc_page(TranslationBlock *tb,
782 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000783{
784 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000785 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000786
bellard9fa3e852004-01-04 18:06:42 +0000787 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000788 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000789 tb->page_next[n] = p->first_tb;
790 last_first_tb = p->first_tb;
791 p->first_tb = (TranslationBlock *)((long)tb | n);
792 invalidate_page_bitmap(p);
793
bellard107db442004-06-22 18:48:46 +0000794#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000795
bellard9fa3e852004-01-04 18:06:42 +0000796#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000797 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000798 unsigned long host_start, host_end, addr;
799 int prot;
800
bellardfd6ce8f2003-05-14 19:00:11 +0000801 /* force the host page as non writable (writes will have a
802 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000803 host_start = page_addr & qemu_host_page_mask;
804 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000805 prot = 0;
806 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
807 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000808 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000809 (prot & PAGE_BITS) & ~PAGE_WRITE);
810#ifdef DEBUG_TB_INVALIDATE
811 printf("protecting code page: 0x%08lx\n",
812 host_start);
813#endif
814 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000815 }
bellard9fa3e852004-01-04 18:06:42 +0000816#else
817 /* if some code is already present, then the pages are already
818 protected. So we handle the case where only the first TB is
819 allocated in a physical page */
820 if (!last_first_tb) {
821 target_ulong virt_addr;
822
823 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +0000824 tlb_protect_code(cpu_single_env, page_addr, virt_addr);
bellard9fa3e852004-01-04 18:06:42 +0000825 }
826#endif
bellardd720b932004-04-25 17:57:43 +0000827
828#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000829}
830
831/* Allocate a new translation block. Flush the translation buffer if
832 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000833TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000834{
835 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000836
837 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
838 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000839 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000840 tb = &tbs[nb_tbs++];
841 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000842 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000843 return tb;
844}
845
bellard9fa3e852004-01-04 18:06:42 +0000846/* add a new TB and link it to the physical page tables. phys_page2 is
847 (-1) to indicate that only one page contains the TB. */
848void tb_link_phys(TranslationBlock *tb,
849 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000850{
bellard9fa3e852004-01-04 18:06:42 +0000851 unsigned int h;
852 TranslationBlock **ptb;
853
854 /* add in the physical hash table */
855 h = tb_phys_hash_func(phys_pc);
856 ptb = &tb_phys_hash[h];
857 tb->phys_hash_next = *ptb;
858 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000859
860 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000861 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
862 if (phys_page2 != -1)
863 tb_alloc_page(tb, 1, phys_page2);
864 else
865 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000866
bellardd4e81642003-05-25 16:46:15 +0000867 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
868 tb->jmp_next[0] = NULL;
869 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000870#ifdef USE_CODE_COPY
871 tb->cflags &= ~CF_FP_USED;
872 if (tb->cflags & CF_TB_FP_USED)
873 tb->cflags |= CF_FP_USED;
874#endif
bellardd4e81642003-05-25 16:46:15 +0000875
876 /* init original jump addresses */
877 if (tb->tb_next_offset[0] != 0xffff)
878 tb_reset_jump(tb, 0);
879 if (tb->tb_next_offset[1] != 0xffff)
880 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000881
882#ifdef DEBUG_TB_CHECK
883 tb_page_check();
884#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000885}
886
bellarda513fe12003-05-27 23:29:48 +0000887/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
888 tb[1].tc_ptr. Return NULL if not found */
889TranslationBlock *tb_find_pc(unsigned long tc_ptr)
890{
891 int m_min, m_max, m;
892 unsigned long v;
893 TranslationBlock *tb;
894
895 if (nb_tbs <= 0)
896 return NULL;
897 if (tc_ptr < (unsigned long)code_gen_buffer ||
898 tc_ptr >= (unsigned long)code_gen_ptr)
899 return NULL;
900 /* binary search (cf Knuth) */
901 m_min = 0;
902 m_max = nb_tbs - 1;
903 while (m_min <= m_max) {
904 m = (m_min + m_max) >> 1;
905 tb = &tbs[m];
906 v = (unsigned long)tb->tc_ptr;
907 if (v == tc_ptr)
908 return tb;
909 else if (tc_ptr < v) {
910 m_max = m - 1;
911 } else {
912 m_min = m + 1;
913 }
914 }
915 return &tbs[m_max];
916}
bellard75012672003-06-21 13:11:07 +0000917
bellardea041c02003-06-25 16:16:50 +0000918static void tb_reset_jump_recursive(TranslationBlock *tb);
919
920static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
921{
922 TranslationBlock *tb1, *tb_next, **ptb;
923 unsigned int n1;
924
925 tb1 = tb->jmp_next[n];
926 if (tb1 != NULL) {
927 /* find head of list */
928 for(;;) {
929 n1 = (long)tb1 & 3;
930 tb1 = (TranslationBlock *)((long)tb1 & ~3);
931 if (n1 == 2)
932 break;
933 tb1 = tb1->jmp_next[n1];
934 }
935 /* we are now sure now that tb jumps to tb1 */
936 tb_next = tb1;
937
938 /* remove tb from the jmp_first list */
939 ptb = &tb_next->jmp_first;
940 for(;;) {
941 tb1 = *ptb;
942 n1 = (long)tb1 & 3;
943 tb1 = (TranslationBlock *)((long)tb1 & ~3);
944 if (n1 == n && tb1 == tb)
945 break;
946 ptb = &tb1->jmp_next[n1];
947 }
948 *ptb = tb->jmp_next[n];
949 tb->jmp_next[n] = NULL;
950
951 /* suppress the jump to next tb in generated code */
952 tb_reset_jump(tb, n);
953
bellard01243112004-01-04 15:48:17 +0000954 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +0000955 tb_reset_jump_recursive(tb_next);
956 }
957}
958
959static void tb_reset_jump_recursive(TranslationBlock *tb)
960{
961 tb_reset_jump_recursive2(tb, 0);
962 tb_reset_jump_recursive2(tb, 1);
963}
964
bellard1fddef42005-04-17 19:16:13 +0000965#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +0000966static void breakpoint_invalidate(CPUState *env, target_ulong pc)
967{
968 target_ulong phys_addr;
969
970 phys_addr = cpu_get_phys_page_debug(env, pc);
971 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
972}
bellardc27004e2005-01-03 23:35:10 +0000973#endif
bellardd720b932004-04-25 17:57:43 +0000974
bellardc33a3462003-07-29 20:50:33 +0000975/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
976 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +0000977int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +0000978{
bellard1fddef42005-04-17 19:16:13 +0000979#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +0000980 int i;
bellardd720b932004-04-25 17:57:43 +0000981
bellard4c3a88a2003-07-26 12:06:08 +0000982 for(i = 0; i < env->nb_breakpoints; i++) {
983 if (env->breakpoints[i] == pc)
984 return 0;
985 }
986
987 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
988 return -1;
989 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +0000990
991 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +0000992 return 0;
993#else
994 return -1;
995#endif
996}
997
998/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +0000999int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001000{
bellard1fddef42005-04-17 19:16:13 +00001001#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001002 int i;
1003 for(i = 0; i < env->nb_breakpoints; i++) {
1004 if (env->breakpoints[i] == pc)
1005 goto found;
1006 }
1007 return -1;
1008 found:
bellard4c3a88a2003-07-26 12:06:08 +00001009 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001010 if (i < env->nb_breakpoints)
1011 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001012
1013 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001014 return 0;
1015#else
1016 return -1;
1017#endif
1018}
1019
bellardc33a3462003-07-29 20:50:33 +00001020/* enable or disable single step mode. EXCP_DEBUG is returned by the
1021 CPU loop after each instruction */
1022void cpu_single_step(CPUState *env, int enabled)
1023{
bellard1fddef42005-04-17 19:16:13 +00001024#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001025 if (env->singlestep_enabled != enabled) {
1026 env->singlestep_enabled = enabled;
1027 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001028 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001029 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001030 }
1031#endif
1032}
1033
bellard34865132003-10-05 14:28:56 +00001034/* enable or disable low levels log */
1035void cpu_set_log(int log_flags)
1036{
1037 loglevel = log_flags;
1038 if (loglevel && !logfile) {
1039 logfile = fopen(logfilename, "w");
1040 if (!logfile) {
1041 perror(logfilename);
1042 _exit(1);
1043 }
bellard9fa3e852004-01-04 18:06:42 +00001044#if !defined(CONFIG_SOFTMMU)
1045 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1046 {
1047 static uint8_t logfile_buf[4096];
1048 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1049 }
1050#else
bellard34865132003-10-05 14:28:56 +00001051 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001052#endif
bellard34865132003-10-05 14:28:56 +00001053 }
1054}
1055
1056void cpu_set_log_filename(const char *filename)
1057{
1058 logfilename = strdup(filename);
1059}
bellardc33a3462003-07-29 20:50:33 +00001060
bellard01243112004-01-04 15:48:17 +00001061/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001062void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001063{
1064 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001065 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001066
bellard68a79312003-06-30 13:12:32 +00001067 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001068 /* if the cpu is currently executing code, we must unlink it and
1069 all the potentially executing TB */
1070 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001071 if (tb && !testandset(&interrupt_lock)) {
1072 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001073 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001074 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001075 }
1076}
1077
bellardb54ad042004-05-20 13:42:52 +00001078void cpu_reset_interrupt(CPUState *env, int mask)
1079{
1080 env->interrupt_request &= ~mask;
1081}
1082
bellardf193c792004-03-21 17:06:25 +00001083CPULogItem cpu_log_items[] = {
1084 { CPU_LOG_TB_OUT_ASM, "out_asm",
1085 "show generated host assembly code for each compiled TB" },
1086 { CPU_LOG_TB_IN_ASM, "in_asm",
1087 "show target assembly code for each compiled TB" },
1088 { CPU_LOG_TB_OP, "op",
1089 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1090#ifdef TARGET_I386
1091 { CPU_LOG_TB_OP_OPT, "op_opt",
1092 "show micro ops after optimization for each compiled TB" },
1093#endif
1094 { CPU_LOG_INT, "int",
1095 "show interrupts/exceptions in short format" },
1096 { CPU_LOG_EXEC, "exec",
1097 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001098 { CPU_LOG_TB_CPU, "cpu",
1099 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001100#ifdef TARGET_I386
1101 { CPU_LOG_PCALL, "pcall",
1102 "show protected mode far calls/returns/exceptions" },
1103#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001104#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001105 { CPU_LOG_IOPORT, "ioport",
1106 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001107#endif
bellardf193c792004-03-21 17:06:25 +00001108 { 0, NULL, NULL },
1109};
1110
1111static int cmp1(const char *s1, int n, const char *s2)
1112{
1113 if (strlen(s2) != n)
1114 return 0;
1115 return memcmp(s1, s2, n) == 0;
1116}
1117
1118/* takes a comma separated list of log masks. Return 0 if error. */
1119int cpu_str_to_log_mask(const char *str)
1120{
1121 CPULogItem *item;
1122 int mask;
1123 const char *p, *p1;
1124
1125 p = str;
1126 mask = 0;
1127 for(;;) {
1128 p1 = strchr(p, ',');
1129 if (!p1)
1130 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001131 if(cmp1(p,p1-p,"all")) {
1132 for(item = cpu_log_items; item->mask != 0; item++) {
1133 mask |= item->mask;
1134 }
1135 } else {
bellardf193c792004-03-21 17:06:25 +00001136 for(item = cpu_log_items; item->mask != 0; item++) {
1137 if (cmp1(p, p1 - p, item->name))
1138 goto found;
1139 }
1140 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001141 }
bellardf193c792004-03-21 17:06:25 +00001142 found:
1143 mask |= item->mask;
1144 if (*p1 != ',')
1145 break;
1146 p = p1 + 1;
1147 }
1148 return mask;
1149}
bellardea041c02003-06-25 16:16:50 +00001150
bellard75012672003-06-21 13:11:07 +00001151void cpu_abort(CPUState *env, const char *fmt, ...)
1152{
1153 va_list ap;
1154
1155 va_start(ap, fmt);
1156 fprintf(stderr, "qemu: fatal: ");
1157 vfprintf(stderr, fmt, ap);
1158 fprintf(stderr, "\n");
1159#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001160 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1161#else
1162 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001163#endif
1164 va_end(ap);
1165 abort();
1166}
1167
bellard01243112004-01-04 15:48:17 +00001168#if !defined(CONFIG_USER_ONLY)
1169
bellardee8b7022004-02-03 23:35:10 +00001170/* NOTE: if flush_global is true, also flush global entries (not
1171 implemented yet) */
1172void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001173{
bellard33417e72003-08-10 21:47:01 +00001174 int i;
bellard01243112004-01-04 15:48:17 +00001175
bellard9fa3e852004-01-04 18:06:42 +00001176#if defined(DEBUG_TLB)
1177 printf("tlb_flush:\n");
1178#endif
bellard01243112004-01-04 15:48:17 +00001179 /* must reset current TB so that interrupts cannot modify the
1180 links while we are modifying them */
1181 env->current_tb = NULL;
1182
bellard33417e72003-08-10 21:47:01 +00001183 for(i = 0; i < CPU_TLB_SIZE; i++) {
1184 env->tlb_read[0][i].address = -1;
1185 env->tlb_write[0][i].address = -1;
1186 env->tlb_read[1][i].address = -1;
1187 env->tlb_write[1][i].address = -1;
1188 }
bellard9fa3e852004-01-04 18:06:42 +00001189
bellard8a40a182005-11-20 10:35:40 +00001190 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001191
1192#if !defined(CONFIG_SOFTMMU)
1193 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1194#endif
bellard0a962c02005-02-10 22:00:27 +00001195#ifdef USE_KQEMU
1196 if (env->kqemu_enabled) {
1197 kqemu_flush(env, flush_global);
1198 }
1199#endif
bellarde3db7222005-01-26 22:00:47 +00001200 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001201}
1202
bellard274da6b2004-05-20 21:56:27 +00001203static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001204{
1205 if (addr == (tlb_entry->address &
1206 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1207 tlb_entry->address = -1;
1208}
1209
bellard2e126692004-04-25 21:28:44 +00001210void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001211{
bellard8a40a182005-11-20 10:35:40 +00001212 int i;
bellard9fa3e852004-01-04 18:06:42 +00001213 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001214
bellard9fa3e852004-01-04 18:06:42 +00001215#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001216 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001217#endif
bellard01243112004-01-04 15:48:17 +00001218 /* must reset current TB so that interrupts cannot modify the
1219 links while we are modifying them */
1220 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001221
bellard61382a52003-10-27 21:22:23 +00001222 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001223 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001224 tlb_flush_entry(&env->tlb_read[0][i], addr);
1225 tlb_flush_entry(&env->tlb_write[0][i], addr);
1226 tlb_flush_entry(&env->tlb_read[1][i], addr);
1227 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001228
bellard8a40a182005-11-20 10:35:40 +00001229 for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
1230 tb = env->tb_jmp_cache[i];
1231 if (tb &&
1232 ((tb->pc & TARGET_PAGE_MASK) == addr ||
1233 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
1234 env->tb_jmp_cache[i] = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001235 }
1236 }
1237
bellard01243112004-01-04 15:48:17 +00001238#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001239 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001240 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001241#endif
bellard0a962c02005-02-10 22:00:27 +00001242#ifdef USE_KQEMU
1243 if (env->kqemu_enabled) {
1244 kqemu_flush_page(env, addr);
1245 }
1246#endif
bellard9fa3e852004-01-04 18:06:42 +00001247}
1248
bellard4f2ac232004-04-26 19:44:02 +00001249static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001250{
1251 if (addr == (tlb_entry->address &
1252 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard3a7d9292005-08-21 09:26:42 +00001253 (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1254 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard01243112004-01-04 15:48:17 +00001255 }
bellard61382a52003-10-27 21:22:23 +00001256}
1257
bellard9fa3e852004-01-04 18:06:42 +00001258/* update the TLBs so that writes to code in the virtual page 'addr'
1259 can be detected */
bellard3a7d9292005-08-21 09:26:42 +00001260static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
1261 target_ulong vaddr)
bellard61382a52003-10-27 21:22:23 +00001262{
bellard61382a52003-10-27 21:22:23 +00001263 int i;
1264
bellard3a7d9292005-08-21 09:26:42 +00001265 vaddr &= TARGET_PAGE_MASK;
1266 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1267 tlb_protect_code1(&env->tlb_write[0][i], vaddr);
1268 tlb_protect_code1(&env->tlb_write[1][i], vaddr);
1269
bellard3a7d9292005-08-21 09:26:42 +00001270#ifdef USE_KQEMU
1271 if (env->kqemu_enabled) {
1272 kqemu_set_notdirty(env, ram_addr);
1273 }
1274#endif
bellardf23db162005-08-21 19:12:28 +00001275 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG;
bellard3a7d9292005-08-21 09:26:42 +00001276
bellard9fa3e852004-01-04 18:06:42 +00001277#if !defined(CONFIG_SOFTMMU)
1278 /* NOTE: as we generated the code for this page, it is already at
1279 least readable */
bellard3a7d9292005-08-21 09:26:42 +00001280 if (vaddr < MMAP_AREA_END)
1281 mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ);
bellard9fa3e852004-01-04 18:06:42 +00001282#endif
1283}
1284
bellard9fa3e852004-01-04 18:06:42 +00001285/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001286 tested for self modifying code */
1287static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1288 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001289{
bellard3a7d9292005-08-21 09:26:42 +00001290 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001291}
1292
1293static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1294 unsigned long start, unsigned long length)
1295{
1296 unsigned long addr;
1297 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1298 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1299 if ((addr - start) < length) {
1300 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1301 }
1302 }
1303}
1304
bellard3a7d9292005-08-21 09:26:42 +00001305void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001306 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001307{
1308 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001309 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001310 int i, mask, len;
1311 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001312
1313 start &= TARGET_PAGE_MASK;
1314 end = TARGET_PAGE_ALIGN(end);
1315
1316 length = end - start;
1317 if (length == 0)
1318 return;
bellard0a962c02005-02-10 22:00:27 +00001319 len = length >> TARGET_PAGE_BITS;
bellard1ccde1c2004-02-06 19:46:14 +00001320 env = cpu_single_env;
bellard3a7d9292005-08-21 09:26:42 +00001321#ifdef USE_KQEMU
1322 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001323 ram_addr_t addr;
1324 addr = start;
1325 for(i = 0; i < len; i++) {
1326 kqemu_set_notdirty(env, addr);
1327 addr += TARGET_PAGE_SIZE;
1328 }
bellard3a7d9292005-08-21 09:26:42 +00001329 }
1330#endif
bellardf23db162005-08-21 19:12:28 +00001331 mask = ~dirty_flags;
1332 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1333 for(i = 0; i < len; i++)
1334 p[i] &= mask;
1335
bellard1ccde1c2004-02-06 19:46:14 +00001336 /* we modify the TLB cache so that the dirty bit will be set again
1337 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001338 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001339 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001340 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001341 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001342 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1343
1344#if !defined(CONFIG_SOFTMMU)
1345 /* XXX: this is expensive */
1346 {
1347 VirtPageDesc *p;
1348 int j;
1349 target_ulong addr;
1350
1351 for(i = 0; i < L1_SIZE; i++) {
1352 p = l1_virt_map[i];
1353 if (p) {
1354 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1355 for(j = 0; j < L2_SIZE; j++) {
1356 if (p->valid_tag == virt_valid_tag &&
1357 p->phys_addr >= start && p->phys_addr < end &&
1358 (p->prot & PROT_WRITE)) {
1359 if (addr < MMAP_AREA_END) {
1360 mprotect((void *)addr, TARGET_PAGE_SIZE,
1361 p->prot & ~PROT_WRITE);
1362 }
1363 }
1364 addr += TARGET_PAGE_SIZE;
1365 p++;
1366 }
1367 }
1368 }
1369 }
1370#endif
bellard1ccde1c2004-02-06 19:46:14 +00001371}
1372
bellard3a7d9292005-08-21 09:26:42 +00001373static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1374{
1375 ram_addr_t ram_addr;
1376
1377 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1378 ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) +
1379 tlb_entry->addend - (unsigned long)phys_ram_base;
1380 if (!cpu_physical_memory_is_dirty(ram_addr)) {
1381 tlb_entry->address |= IO_MEM_NOTDIRTY;
1382 }
1383 }
1384}
1385
1386/* update the TLB according to the current state of the dirty bits */
1387void cpu_tlb_update_dirty(CPUState *env)
1388{
1389 int i;
1390 for(i = 0; i < CPU_TLB_SIZE; i++)
1391 tlb_update_dirty(&env->tlb_write[0][i]);
1392 for(i = 0; i < CPU_TLB_SIZE; i++)
1393 tlb_update_dirty(&env->tlb_write[1][i]);
1394}
1395
bellard1ccde1c2004-02-06 19:46:14 +00001396static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001397 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001398{
1399 unsigned long addr;
1400 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1401 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1402 if (addr == start) {
1403 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1404 }
1405 }
1406}
1407
1408/* update the TLB corresponding to virtual page vaddr and phys addr
1409 addr so that it is no longer dirty */
1410static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1411{
1412 CPUState *env = cpu_single_env;
1413 int i;
1414
bellard1ccde1c2004-02-06 19:46:14 +00001415 addr &= TARGET_PAGE_MASK;
1416 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1417 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1418 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001419}
1420
bellard59817cc2004-02-16 22:01:13 +00001421/* add a new TLB entry. At most one entry for a given virtual address
1422 is permitted. Return 0 if OK or 2 if the page could not be mapped
1423 (can only happen in non SOFTMMU mode for I/O pages or pages
1424 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001425int tlb_set_page(CPUState *env, target_ulong vaddr,
1426 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001427 int is_user, int is_softmmu)
1428{
bellard92e873b2004-05-21 14:52:29 +00001429 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001430 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001431 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001432 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001433 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001434 int ret;
1435
bellard92e873b2004-05-21 14:52:29 +00001436 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001437 if (!p) {
1438 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001439 } else {
1440 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001441 }
1442#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001443 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
1444 vaddr, paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001445#endif
1446
1447 ret = 0;
1448#if !defined(CONFIG_SOFTMMU)
1449 if (is_softmmu)
1450#endif
1451 {
1452 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1453 /* IO memory case */
1454 address = vaddr | pd;
1455 addend = paddr;
1456 } else {
1457 /* standard memory */
1458 address = vaddr;
1459 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1460 }
1461
bellard90f18422005-07-24 10:17:31 +00001462 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001463 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001464 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001465 env->tlb_read[is_user][index].address = address;
1466 env->tlb_read[is_user][index].addend = addend;
1467 } else {
1468 env->tlb_read[is_user][index].address = -1;
1469 env->tlb_read[is_user][index].addend = -1;
1470 }
bellard67b915a2004-03-31 23:37:16 +00001471 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001472 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1473 /* ROM: access is ignored (same as unassigned) */
1474 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001475 env->tlb_write[is_user][index].addend = addend;
bellard3a7d9292005-08-21 09:26:42 +00001476 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001477 !cpu_physical_memory_is_dirty(pd)) {
1478 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1479 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001480 } else {
1481 env->tlb_write[is_user][index].address = address;
1482 env->tlb_write[is_user][index].addend = addend;
1483 }
1484 } else {
1485 env->tlb_write[is_user][index].address = -1;
1486 env->tlb_write[is_user][index].addend = -1;
1487 }
1488 }
1489#if !defined(CONFIG_SOFTMMU)
1490 else {
1491 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1492 /* IO access: no mapping is done as it will be handled by the
1493 soft MMU */
1494 if (!(env->hflags & HF_SOFTMMU_MASK))
1495 ret = 2;
1496 } else {
1497 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001498
bellard59817cc2004-02-16 22:01:13 +00001499 if (vaddr >= MMAP_AREA_END) {
1500 ret = 2;
1501 } else {
1502 if (prot & PROT_WRITE) {
1503 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001504#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001505 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001506#endif
bellard59817cc2004-02-16 22:01:13 +00001507 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1508 !cpu_physical_memory_is_dirty(pd))) {
1509 /* ROM: we do as if code was inside */
1510 /* if code is present, we only map as read only and save the
1511 original mapping */
1512 VirtPageDesc *vp;
1513
bellard90f18422005-07-24 10:17:31 +00001514 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001515 vp->phys_addr = pd;
1516 vp->prot = prot;
1517 vp->valid_tag = virt_valid_tag;
1518 prot &= ~PAGE_WRITE;
1519 }
bellard9fa3e852004-01-04 18:06:42 +00001520 }
bellard59817cc2004-02-16 22:01:13 +00001521 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1522 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1523 if (map_addr == MAP_FAILED) {
1524 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1525 paddr, vaddr);
1526 }
bellard9fa3e852004-01-04 18:06:42 +00001527 }
1528 }
1529 }
1530#endif
1531 return ret;
1532}
1533
1534/* called from signal handler: invalidate the code and unprotect the
1535 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001536int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001537{
1538#if !defined(CONFIG_SOFTMMU)
1539 VirtPageDesc *vp;
1540
1541#if defined(DEBUG_TLB)
1542 printf("page_unprotect: addr=0x%08x\n", addr);
1543#endif
1544 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001545
1546 /* if it is not mapped, no need to worry here */
1547 if (addr >= MMAP_AREA_END)
1548 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001549 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1550 if (!vp)
1551 return 0;
1552 /* NOTE: in this case, validate_tag is _not_ tested as it
1553 validates only the code TLB */
1554 if (vp->valid_tag != virt_valid_tag)
1555 return 0;
1556 if (!(vp->prot & PAGE_WRITE))
1557 return 0;
1558#if defined(DEBUG_TLB)
1559 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1560 addr, vp->phys_addr, vp->prot);
1561#endif
bellard59817cc2004-02-16 22:01:13 +00001562 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1563 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1564 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001565 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001566 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001567 /* flush the code inside */
1568 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001569 return 1;
1570#else
1571 return 0;
1572#endif
bellard33417e72003-08-10 21:47:01 +00001573}
1574
bellard01243112004-01-04 15:48:17 +00001575#else
1576
bellardee8b7022004-02-03 23:35:10 +00001577void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001578{
1579}
1580
bellard2e126692004-04-25 21:28:44 +00001581void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001582{
1583}
1584
bellard2e126692004-04-25 21:28:44 +00001585int tlb_set_page(CPUState *env, target_ulong vaddr,
1586 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001587 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001588{
bellard9fa3e852004-01-04 18:06:42 +00001589 return 0;
1590}
bellard33417e72003-08-10 21:47:01 +00001591
bellard9fa3e852004-01-04 18:06:42 +00001592/* dump memory mappings */
1593void page_dump(FILE *f)
1594{
1595 unsigned long start, end;
1596 int i, j, prot, prot1;
1597 PageDesc *p;
1598
1599 fprintf(f, "%-8s %-8s %-8s %s\n",
1600 "start", "end", "size", "prot");
1601 start = -1;
1602 end = -1;
1603 prot = 0;
1604 for(i = 0; i <= L1_SIZE; i++) {
1605 if (i < L1_SIZE)
1606 p = l1_map[i];
1607 else
1608 p = NULL;
1609 for(j = 0;j < L2_SIZE; j++) {
1610 if (!p)
1611 prot1 = 0;
1612 else
1613 prot1 = p[j].flags;
1614 if (prot1 != prot) {
1615 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1616 if (start != -1) {
1617 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1618 start, end, end - start,
1619 prot & PAGE_READ ? 'r' : '-',
1620 prot & PAGE_WRITE ? 'w' : '-',
1621 prot & PAGE_EXEC ? 'x' : '-');
1622 }
1623 if (prot1 != 0)
1624 start = end;
1625 else
1626 start = -1;
1627 prot = prot1;
1628 }
1629 if (!p)
1630 break;
1631 }
bellard33417e72003-08-10 21:47:01 +00001632 }
bellard33417e72003-08-10 21:47:01 +00001633}
1634
bellard9fa3e852004-01-04 18:06:42 +00001635int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001636{
bellard9fa3e852004-01-04 18:06:42 +00001637 PageDesc *p;
1638
1639 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001640 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001641 return 0;
1642 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001643}
1644
bellard9fa3e852004-01-04 18:06:42 +00001645/* modify the flags of a page and invalidate the code if
1646 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1647 depending on PAGE_WRITE */
1648void page_set_flags(unsigned long start, unsigned long end, int flags)
1649{
1650 PageDesc *p;
1651 unsigned long addr;
1652
1653 start = start & TARGET_PAGE_MASK;
1654 end = TARGET_PAGE_ALIGN(end);
1655 if (flags & PAGE_WRITE)
1656 flags |= PAGE_WRITE_ORG;
1657 spin_lock(&tb_lock);
1658 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1659 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1660 /* if the write protection is set, then we invalidate the code
1661 inside */
1662 if (!(p->flags & PAGE_WRITE) &&
1663 (flags & PAGE_WRITE) &&
1664 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001665 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001666 }
1667 p->flags = flags;
1668 }
1669 spin_unlock(&tb_lock);
1670}
1671
1672/* called from signal handler: invalidate the code and unprotect the
1673 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001674int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001675{
1676 unsigned int page_index, prot, pindex;
1677 PageDesc *p, *p1;
1678 unsigned long host_start, host_end, addr;
1679
bellard83fb7ad2004-07-05 21:25:26 +00001680 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001681 page_index = host_start >> TARGET_PAGE_BITS;
1682 p1 = page_find(page_index);
1683 if (!p1)
1684 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001685 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001686 p = p1;
1687 prot = 0;
1688 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1689 prot |= p->flags;
1690 p++;
1691 }
1692 /* if the page was really writable, then we change its
1693 protection back to writable */
1694 if (prot & PAGE_WRITE_ORG) {
1695 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1696 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001697 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001698 (prot & PAGE_BITS) | PAGE_WRITE);
1699 p1[pindex].flags |= PAGE_WRITE;
1700 /* and since the content will be modified, we must invalidate
1701 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001702 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001703#ifdef DEBUG_TB_CHECK
1704 tb_invalidate_check(address);
1705#endif
1706 return 1;
1707 }
1708 }
1709 return 0;
1710}
1711
1712/* call this function when system calls directly modify a memory area */
1713void page_unprotect_range(uint8_t *data, unsigned long data_size)
1714{
1715 unsigned long start, end, addr;
1716
1717 start = (unsigned long)data;
1718 end = start + data_size;
1719 start &= TARGET_PAGE_MASK;
1720 end = TARGET_PAGE_ALIGN(end);
1721 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001722 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001723 }
1724}
1725
bellard1ccde1c2004-02-06 19:46:14 +00001726static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1727{
1728}
bellard9fa3e852004-01-04 18:06:42 +00001729#endif /* defined(CONFIG_USER_ONLY) */
1730
bellard33417e72003-08-10 21:47:01 +00001731/* register physical memory. 'size' must be a multiple of the target
1732 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1733 io memory page */
bellard2e126692004-04-25 21:28:44 +00001734void cpu_register_physical_memory(target_phys_addr_t start_addr,
1735 unsigned long size,
1736 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001737{
bellard108c49b2005-07-24 12:55:09 +00001738 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001739 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001740
bellard5fd386f2004-05-23 21:11:22 +00001741 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001742 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001743 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001744 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001745 p->phys_offset = phys_offset;
1746 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001747 phys_offset += TARGET_PAGE_SIZE;
1748 }
1749}
1750
bellarda4193c82004-06-03 14:01:43 +00001751static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001752{
1753 return 0;
1754}
1755
bellarda4193c82004-06-03 14:01:43 +00001756static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001757{
1758}
1759
1760static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1761 unassigned_mem_readb,
1762 unassigned_mem_readb,
1763 unassigned_mem_readb,
1764};
1765
1766static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1767 unassigned_mem_writeb,
1768 unassigned_mem_writeb,
1769 unassigned_mem_writeb,
1770};
1771
bellarda4193c82004-06-03 14:01:43 +00001772static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001773{
bellard3a7d9292005-08-21 09:26:42 +00001774 unsigned long ram_addr;
1775 int dirty_flags;
1776 ram_addr = addr - (unsigned long)phys_ram_base;
1777 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1778 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1779#if !defined(CONFIG_USER_ONLY)
1780 tb_invalidate_phys_page_fast(ram_addr, 1);
1781 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1782#endif
1783 }
bellardc27004e2005-01-03 23:35:10 +00001784 stb_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001785 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1786 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1787 /* we remove the notdirty callback only if the code has been
1788 flushed */
1789 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00001790 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001791}
1792
bellarda4193c82004-06-03 14:01:43 +00001793static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001794{
bellard3a7d9292005-08-21 09:26:42 +00001795 unsigned long ram_addr;
1796 int dirty_flags;
1797 ram_addr = addr - (unsigned long)phys_ram_base;
1798 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1799 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1800#if !defined(CONFIG_USER_ONLY)
1801 tb_invalidate_phys_page_fast(ram_addr, 2);
1802 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1803#endif
1804 }
bellardc27004e2005-01-03 23:35:10 +00001805 stw_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001806 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1807 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1808 /* we remove the notdirty callback only if the code has been
1809 flushed */
1810 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00001811 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001812}
1813
bellarda4193c82004-06-03 14:01:43 +00001814static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001815{
bellard3a7d9292005-08-21 09:26:42 +00001816 unsigned long ram_addr;
1817 int dirty_flags;
1818 ram_addr = addr - (unsigned long)phys_ram_base;
1819 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1820 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1821#if !defined(CONFIG_USER_ONLY)
1822 tb_invalidate_phys_page_fast(ram_addr, 4);
1823 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1824#endif
1825 }
bellardc27004e2005-01-03 23:35:10 +00001826 stl_p((uint8_t *)(long)addr, val);
bellardf23db162005-08-21 19:12:28 +00001827 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1828 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1829 /* we remove the notdirty callback only if the code has been
1830 flushed */
1831 if (dirty_flags == 0xff)
bellard3a7d9292005-08-21 09:26:42 +00001832 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001833}
1834
bellard3a7d9292005-08-21 09:26:42 +00001835static CPUReadMemoryFunc *error_mem_read[3] = {
1836 NULL, /* never used */
1837 NULL, /* never used */
1838 NULL, /* never used */
1839};
1840
bellard1ccde1c2004-02-06 19:46:14 +00001841static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1842 notdirty_mem_writeb,
1843 notdirty_mem_writew,
1844 notdirty_mem_writel,
1845};
1846
bellard33417e72003-08-10 21:47:01 +00001847static void io_mem_init(void)
1848{
bellard3a7d9292005-08-21 09:26:42 +00001849 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001850 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001851 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001852 io_mem_nb = 5;
1853
1854 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001855 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001856 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001857}
1858
1859/* mem_read and mem_write are arrays of functions containing the
1860 function to access byte (index 0), word (index 1) and dword (index
1861 2). All functions must be supplied. If io_index is non zero, the
1862 corresponding io zone is modified. If it is zero, a new io zone is
1863 allocated. The return value can be used with
1864 cpu_register_physical_memory(). (-1) is returned if error. */
1865int cpu_register_io_memory(int io_index,
1866 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001867 CPUWriteMemoryFunc **mem_write,
1868 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001869{
1870 int i;
1871
1872 if (io_index <= 0) {
1873 if (io_index >= IO_MEM_NB_ENTRIES)
1874 return -1;
1875 io_index = io_mem_nb++;
1876 } else {
1877 if (io_index >= IO_MEM_NB_ENTRIES)
1878 return -1;
1879 }
1880
1881 for(i = 0;i < 3; i++) {
1882 io_mem_read[io_index][i] = mem_read[i];
1883 io_mem_write[io_index][i] = mem_write[i];
1884 }
bellarda4193c82004-06-03 14:01:43 +00001885 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001886 return io_index << IO_MEM_SHIFT;
1887}
bellard61382a52003-10-27 21:22:23 +00001888
bellard8926b512004-10-10 15:14:20 +00001889CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1890{
1891 return io_mem_write[io_index >> IO_MEM_SHIFT];
1892}
1893
1894CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
1895{
1896 return io_mem_read[io_index >> IO_MEM_SHIFT];
1897}
1898
bellard13eb76e2004-01-24 15:23:36 +00001899/* physical memory access (slow version, mainly for debug) */
1900#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001901void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001902 int len, int is_write)
1903{
1904 int l, flags;
1905 target_ulong page;
1906
1907 while (len > 0) {
1908 page = addr & TARGET_PAGE_MASK;
1909 l = (page + TARGET_PAGE_SIZE) - addr;
1910 if (l > len)
1911 l = len;
1912 flags = page_get_flags(page);
1913 if (!(flags & PAGE_VALID))
1914 return;
1915 if (is_write) {
1916 if (!(flags & PAGE_WRITE))
1917 return;
1918 memcpy((uint8_t *)addr, buf, len);
1919 } else {
1920 if (!(flags & PAGE_READ))
1921 return;
1922 memcpy(buf, (uint8_t *)addr, len);
1923 }
1924 len -= l;
1925 buf += l;
1926 addr += l;
1927 }
1928}
bellard8df1cd02005-01-28 22:37:22 +00001929
bellard13eb76e2004-01-24 15:23:36 +00001930#else
bellard2e126692004-04-25 21:28:44 +00001931void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001932 int len, int is_write)
1933{
1934 int l, io_index;
1935 uint8_t *ptr;
1936 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00001937 target_phys_addr_t page;
1938 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00001939 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00001940
1941 while (len > 0) {
1942 page = addr & TARGET_PAGE_MASK;
1943 l = (page + TARGET_PAGE_SIZE) - addr;
1944 if (l > len)
1945 l = len;
bellard92e873b2004-05-21 14:52:29 +00001946 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00001947 if (!p) {
1948 pd = IO_MEM_UNASSIGNED;
1949 } else {
1950 pd = p->phys_offset;
1951 }
1952
1953 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00001954 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00001955 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
1956 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00001957 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001958 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001959 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001960 l = 4;
1961 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00001962 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001963 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001964 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001965 l = 2;
1966 } else {
bellard1c213d12005-09-03 10:49:04 +00001967 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00001968 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00001969 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00001970 l = 1;
1971 }
1972 } else {
bellardb448f2f2004-02-25 23:24:04 +00001973 unsigned long addr1;
1974 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00001975 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00001976 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00001977 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00001978 if (!cpu_physical_memory_is_dirty(addr1)) {
1979 /* invalidate code */
1980 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
1981 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00001982 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
1983 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00001984 }
bellard13eb76e2004-01-24 15:23:36 +00001985 }
1986 } else {
bellard3a7d9292005-08-21 09:26:42 +00001987 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard13eb76e2004-01-24 15:23:36 +00001988 /* I/O case */
1989 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
1990 if (l >= 4 && ((addr & 3) == 0)) {
1991 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00001992 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00001993 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00001994 l = 4;
1995 } else if (l >= 2 && ((addr & 1) == 0)) {
1996 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00001997 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00001998 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00001999 l = 2;
2000 } else {
bellard1c213d12005-09-03 10:49:04 +00002001 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002002 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002003 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002004 l = 1;
2005 }
2006 } else {
2007 /* RAM case */
2008 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2009 (addr & ~TARGET_PAGE_MASK);
2010 memcpy(buf, ptr, l);
2011 }
2012 }
2013 len -= l;
2014 buf += l;
2015 addr += l;
2016 }
2017}
bellard8df1cd02005-01-28 22:37:22 +00002018
2019/* warning: addr must be aligned */
2020uint32_t ldl_phys(target_phys_addr_t addr)
2021{
2022 int io_index;
2023 uint8_t *ptr;
2024 uint32_t val;
2025 unsigned long pd;
2026 PhysPageDesc *p;
2027
2028 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2029 if (!p) {
2030 pd = IO_MEM_UNASSIGNED;
2031 } else {
2032 pd = p->phys_offset;
2033 }
2034
bellard3a7d9292005-08-21 09:26:42 +00002035 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
bellard8df1cd02005-01-28 22:37:22 +00002036 /* I/O case */
2037 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2038 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2039 } else {
2040 /* RAM case */
2041 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2042 (addr & ~TARGET_PAGE_MASK);
2043 val = ldl_p(ptr);
2044 }
2045 return val;
2046}
2047
bellardaab33092005-10-30 20:48:42 +00002048/* XXX: optimize */
2049uint32_t ldub_phys(target_phys_addr_t addr)
2050{
2051 uint8_t val;
2052 cpu_physical_memory_read(addr, &val, 1);
2053 return val;
2054}
2055
2056/* XXX: optimize */
2057uint32_t lduw_phys(target_phys_addr_t addr)
2058{
2059 uint16_t val;
2060 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2061 return tswap16(val);
2062}
2063
2064/* XXX: optimize */
2065uint64_t ldq_phys(target_phys_addr_t addr)
2066{
2067 uint64_t val;
2068 cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
2069 return tswap64(val);
2070}
2071
bellard8df1cd02005-01-28 22:37:22 +00002072/* warning: addr must be aligned. The ram page is not masked as dirty
2073 and the code inside is not invalidated. It is useful if the dirty
2074 bits are used to track modified PTEs */
2075void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2076{
2077 int io_index;
2078 uint8_t *ptr;
2079 unsigned long pd;
2080 PhysPageDesc *p;
2081
2082 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2083 if (!p) {
2084 pd = IO_MEM_UNASSIGNED;
2085 } else {
2086 pd = p->phys_offset;
2087 }
2088
bellard3a7d9292005-08-21 09:26:42 +00002089 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002090 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2091 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2092 } else {
2093 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2094 (addr & ~TARGET_PAGE_MASK);
2095 stl_p(ptr, val);
2096 }
2097}
2098
2099/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002100void stl_phys(target_phys_addr_t addr, uint32_t val)
2101{
2102 int io_index;
2103 uint8_t *ptr;
2104 unsigned long pd;
2105 PhysPageDesc *p;
2106
2107 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2108 if (!p) {
2109 pd = IO_MEM_UNASSIGNED;
2110 } else {
2111 pd = p->phys_offset;
2112 }
2113
bellard3a7d9292005-08-21 09:26:42 +00002114 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002115 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2116 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2117 } else {
2118 unsigned long addr1;
2119 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2120 /* RAM case */
2121 ptr = phys_ram_base + addr1;
2122 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002123 if (!cpu_physical_memory_is_dirty(addr1)) {
2124 /* invalidate code */
2125 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2126 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002127 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2128 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002129 }
bellard8df1cd02005-01-28 22:37:22 +00002130 }
2131}
2132
bellardaab33092005-10-30 20:48:42 +00002133/* XXX: optimize */
2134void stb_phys(target_phys_addr_t addr, uint32_t val)
2135{
2136 uint8_t v = val;
2137 cpu_physical_memory_write(addr, &v, 1);
2138}
2139
2140/* XXX: optimize */
2141void stw_phys(target_phys_addr_t addr, uint32_t val)
2142{
2143 uint16_t v = tswap16(val);
2144 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2145}
2146
2147/* XXX: optimize */
2148void stq_phys(target_phys_addr_t addr, uint64_t val)
2149{
2150 val = tswap64(val);
2151 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2152}
2153
bellard13eb76e2004-01-24 15:23:36 +00002154#endif
2155
2156/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002157int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2158 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002159{
2160 int l;
2161 target_ulong page, phys_addr;
2162
2163 while (len > 0) {
2164 page = addr & TARGET_PAGE_MASK;
2165 phys_addr = cpu_get_phys_page_debug(env, page);
2166 /* if no physical page mapped, return an error */
2167 if (phys_addr == -1)
2168 return -1;
2169 l = (page + TARGET_PAGE_SIZE) - addr;
2170 if (l > len)
2171 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002172 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2173 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002174 len -= l;
2175 buf += l;
2176 addr += l;
2177 }
2178 return 0;
2179}
2180
bellarde3db7222005-01-26 22:00:47 +00002181void dump_exec_info(FILE *f,
2182 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2183{
2184 int i, target_code_size, max_target_code_size;
2185 int direct_jmp_count, direct_jmp2_count, cross_page;
2186 TranslationBlock *tb;
2187
2188 target_code_size = 0;
2189 max_target_code_size = 0;
2190 cross_page = 0;
2191 direct_jmp_count = 0;
2192 direct_jmp2_count = 0;
2193 for(i = 0; i < nb_tbs; i++) {
2194 tb = &tbs[i];
2195 target_code_size += tb->size;
2196 if (tb->size > max_target_code_size)
2197 max_target_code_size = tb->size;
2198 if (tb->page_addr[1] != -1)
2199 cross_page++;
2200 if (tb->tb_next_offset[0] != 0xffff) {
2201 direct_jmp_count++;
2202 if (tb->tb_next_offset[1] != 0xffff) {
2203 direct_jmp2_count++;
2204 }
2205 }
2206 }
2207 /* XXX: avoid using doubles ? */
2208 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2209 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2210 nb_tbs ? target_code_size / nb_tbs : 0,
2211 max_target_code_size);
2212 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2213 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2214 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2215 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2216 cross_page,
2217 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2218 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2219 direct_jmp_count,
2220 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2221 direct_jmp2_count,
2222 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2223 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2224 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2225 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2226}
2227
bellard61382a52003-10-27 21:22:23 +00002228#if !defined(CONFIG_USER_ONLY)
2229
2230#define MMUSUFFIX _cmmu
2231#define GETPC() NULL
2232#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002233#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002234
2235#define SHIFT 0
2236#include "softmmu_template.h"
2237
2238#define SHIFT 1
2239#include "softmmu_template.h"
2240
2241#define SHIFT 2
2242#include "softmmu_template.h"
2243
2244#define SHIFT 3
2245#include "softmmu_template.h"
2246
2247#undef env
2248
2249#endif