blob: 20870ad0243b5d512b801b1ffa2d9dce21abe84e [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
pbrook53a59602006-03-25 19:31:22 +000037#if defined(CONFIG_USER_ONLY)
38#include <qemu.h>
39#endif
bellard54936002003-05-13 00:25:15 +000040
bellardfd6ce8f2003-05-14 19:00:11 +000041//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000042//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000043//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000044
45/* make various TB consistency checks */
46//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000047//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000048
pbrook99773bd2006-04-16 15:14:59 +000049#if !defined(CONFIG_USER_ONLY)
50/* TB consistency checks only implemented for usermode emulation. */
51#undef DEBUG_TB_CHECK
52#endif
53
bellardfd6ce8f2003-05-14 19:00:11 +000054/* threshold to flush the translated code buffer */
55#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
56
bellard9fa3e852004-01-04 18:06:42 +000057#define SMC_BITMAP_USE_THRESHOLD 10
58
59#define MMAP_AREA_START 0x00000000
60#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000061
bellard108c49b2005-07-24 12:55:09 +000062#if defined(TARGET_SPARC64)
63#define TARGET_PHYS_ADDR_SPACE_BITS 41
64#elif defined(TARGET_PPC64)
65#define TARGET_PHYS_ADDR_SPACE_BITS 42
66#else
67/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
68#define TARGET_PHYS_ADDR_SPACE_BITS 32
69#endif
70
bellardfd6ce8f2003-05-14 19:00:11 +000071TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000072TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000073int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000074/* any access to the tbs or the page table must use this lock */
75spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000076
bellardb8076a72005-04-07 22:20:31 +000077uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000078uint8_t *code_gen_ptr;
79
bellard9fa3e852004-01-04 18:06:42 +000080int phys_ram_size;
81int phys_ram_fd;
82uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000083uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000084
bellard6a00d602005-11-21 23:25:50 +000085CPUState *first_cpu;
86/* current CPU in the current thread. It is only valid inside
87 cpu_exec() */
88CPUState *cpu_single_env;
89
bellard54936002003-05-13 00:25:15 +000090typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000091 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000092 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000093 /* in order to optimize self modifying code, we count the number
94 of lookups we do to a given page to use a bitmap */
95 unsigned int code_write_count;
96 uint8_t *code_bitmap;
97#if defined(CONFIG_USER_ONLY)
98 unsigned long flags;
99#endif
bellard54936002003-05-13 00:25:15 +0000100} PageDesc;
101
bellard92e873b2004-05-21 14:52:29 +0000102typedef struct PhysPageDesc {
103 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000104 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000105} PhysPageDesc;
106
bellard54936002003-05-13 00:25:15 +0000107#define L2_BITS 10
108#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
109
110#define L1_SIZE (1 << L1_BITS)
111#define L2_SIZE (1 << L2_BITS)
112
bellard33417e72003-08-10 21:47:01 +0000113static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000114
bellard83fb7ad2004-07-05 21:25:26 +0000115unsigned long qemu_real_host_page_size;
116unsigned long qemu_host_page_bits;
117unsigned long qemu_host_page_size;
118unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000119
bellard92e873b2004-05-21 14:52:29 +0000120/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000121static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000122PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000123
bellard33417e72003-08-10 21:47:01 +0000124/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000125CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
126CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000127void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000128static int io_mem_nb;
129
bellard34865132003-10-05 14:28:56 +0000130/* log support */
131char *logfilename = "/tmp/qemu.log";
132FILE *logfile;
133int loglevel;
134
bellarde3db7222005-01-26 22:00:47 +0000135/* statistics */
136static int tlb_flush_count;
137static int tb_flush_count;
138static int tb_phys_invalidate_count;
139
bellardb346ff42003-06-15 20:05:50 +0000140static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000141{
bellard83fb7ad2004-07-05 21:25:26 +0000142 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000143 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000144#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000145 {
146 SYSTEM_INFO system_info;
147 DWORD old_protect;
148
149 GetSystemInfo(&system_info);
150 qemu_real_host_page_size = system_info.dwPageSize;
151
152 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
153 PAGE_EXECUTE_READWRITE, &old_protect);
154 }
bellard67b915a2004-03-31 23:37:16 +0000155#else
bellard83fb7ad2004-07-05 21:25:26 +0000156 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000157 {
158 unsigned long start, end;
159
160 start = (unsigned long)code_gen_buffer;
161 start &= ~(qemu_real_host_page_size - 1);
162
163 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
164 end += qemu_real_host_page_size - 1;
165 end &= ~(qemu_real_host_page_size - 1);
166
167 mprotect((void *)start, end - start,
168 PROT_READ | PROT_WRITE | PROT_EXEC);
169 }
bellard67b915a2004-03-31 23:37:16 +0000170#endif
bellardd5a8f072004-09-29 21:15:28 +0000171
bellard83fb7ad2004-07-05 21:25:26 +0000172 if (qemu_host_page_size == 0)
173 qemu_host_page_size = qemu_real_host_page_size;
174 if (qemu_host_page_size < TARGET_PAGE_SIZE)
175 qemu_host_page_size = TARGET_PAGE_SIZE;
176 qemu_host_page_bits = 0;
177 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
178 qemu_host_page_bits++;
179 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000180 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
181 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000182}
183
bellardfd6ce8f2003-05-14 19:00:11 +0000184static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000185{
bellard54936002003-05-13 00:25:15 +0000186 PageDesc **lp, *p;
187
bellard54936002003-05-13 00:25:15 +0000188 lp = &l1_map[index >> L2_BITS];
189 p = *lp;
190 if (!p) {
191 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000192 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000193 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000194 *lp = p;
195 }
196 return p + (index & (L2_SIZE - 1));
197}
198
bellardfd6ce8f2003-05-14 19:00:11 +0000199static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000200{
bellard54936002003-05-13 00:25:15 +0000201 PageDesc *p;
202
bellard54936002003-05-13 00:25:15 +0000203 p = l1_map[index >> L2_BITS];
204 if (!p)
205 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000206 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000207}
208
bellard108c49b2005-07-24 12:55:09 +0000209static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000210{
bellard108c49b2005-07-24 12:55:09 +0000211 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000212 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000213
bellard108c49b2005-07-24 12:55:09 +0000214 p = (void **)l1_phys_map;
215#if TARGET_PHYS_ADDR_SPACE_BITS > 32
216
217#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
218#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
219#endif
220 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000221 p = *lp;
222 if (!p) {
223 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000224 if (!alloc)
225 return NULL;
226 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
227 memset(p, 0, sizeof(void *) * L1_SIZE);
228 *lp = p;
229 }
230#endif
231 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000232 pd = *lp;
233 if (!pd) {
234 int i;
bellard108c49b2005-07-24 12:55:09 +0000235 /* allocate if not found */
236 if (!alloc)
237 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000238 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
239 *lp = pd;
240 for (i = 0; i < L2_SIZE; i++)
241 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000242 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000243 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000244}
245
bellard108c49b2005-07-24 12:55:09 +0000246static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000247{
bellard108c49b2005-07-24 12:55:09 +0000248 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000249}
250
bellard9fa3e852004-01-04 18:06:42 +0000251#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000252static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000253static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
254 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000255#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000256
bellard6a00d602005-11-21 23:25:50 +0000257void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000258{
bellard6a00d602005-11-21 23:25:50 +0000259 CPUState **penv;
260 int cpu_index;
261
bellardfd6ce8f2003-05-14 19:00:11 +0000262 if (!code_gen_ptr) {
263 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000264 page_init();
bellard33417e72003-08-10 21:47:01 +0000265 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000266 }
bellard6a00d602005-11-21 23:25:50 +0000267 env->next_cpu = NULL;
268 penv = &first_cpu;
269 cpu_index = 0;
270 while (*penv != NULL) {
271 penv = (CPUState **)&(*penv)->next_cpu;
272 cpu_index++;
273 }
274 env->cpu_index = cpu_index;
275 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000276}
277
bellard9fa3e852004-01-04 18:06:42 +0000278static inline void invalidate_page_bitmap(PageDesc *p)
279{
280 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000281 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000282 p->code_bitmap = NULL;
283 }
284 p->code_write_count = 0;
285}
286
bellardfd6ce8f2003-05-14 19:00:11 +0000287/* set to NULL all the 'first_tb' fields in all PageDescs */
288static void page_flush_tb(void)
289{
290 int i, j;
291 PageDesc *p;
292
293 for(i = 0; i < L1_SIZE; i++) {
294 p = l1_map[i];
295 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000296 for(j = 0; j < L2_SIZE; j++) {
297 p->first_tb = NULL;
298 invalidate_page_bitmap(p);
299 p++;
300 }
bellardfd6ce8f2003-05-14 19:00:11 +0000301 }
302 }
303}
304
305/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000306/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000307void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000308{
bellard6a00d602005-11-21 23:25:50 +0000309 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000310#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000311 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
312 code_gen_ptr - code_gen_buffer,
313 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000314 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000315#endif
316 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000317
318 for(env = first_cpu; env != NULL; env = env->next_cpu) {
319 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
320 }
bellard9fa3e852004-01-04 18:06:42 +0000321
bellard8a8a6082004-10-03 13:36:49 +0000322 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000323 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000324
bellardfd6ce8f2003-05-14 19:00:11 +0000325 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000326 /* XXX: flush processor icache at this point if cache flush is
327 expensive */
bellarde3db7222005-01-26 22:00:47 +0000328 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000329}
330
331#ifdef DEBUG_TB_CHECK
332
333static void tb_invalidate_check(unsigned long address)
334{
335 TranslationBlock *tb;
336 int i;
337 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000338 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
339 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000340 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
341 address >= tb->pc + tb->size)) {
342 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000343 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000344 }
345 }
346 }
347}
348
349/* verify that all the pages have correct rights for code */
350static void tb_page_check(void)
351{
352 TranslationBlock *tb;
353 int i, flags1, flags2;
354
pbrook99773bd2006-04-16 15:14:59 +0000355 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
356 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000357 flags1 = page_get_flags(tb->pc);
358 flags2 = page_get_flags(tb->pc + tb->size - 1);
359 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
360 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000361 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000362 }
363 }
364 }
365}
366
bellardd4e81642003-05-25 16:46:15 +0000367void tb_jmp_check(TranslationBlock *tb)
368{
369 TranslationBlock *tb1;
370 unsigned int n1;
371
372 /* suppress any remaining jumps to this TB */
373 tb1 = tb->jmp_first;
374 for(;;) {
375 n1 = (long)tb1 & 3;
376 tb1 = (TranslationBlock *)((long)tb1 & ~3);
377 if (n1 == 2)
378 break;
379 tb1 = tb1->jmp_next[n1];
380 }
381 /* check end of list */
382 if (tb1 != tb) {
383 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
384 }
385}
386
bellardfd6ce8f2003-05-14 19:00:11 +0000387#endif
388
389/* invalidate one TB */
390static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
391 int next_offset)
392{
393 TranslationBlock *tb1;
394 for(;;) {
395 tb1 = *ptb;
396 if (tb1 == tb) {
397 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
398 break;
399 }
400 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
401 }
402}
403
bellard9fa3e852004-01-04 18:06:42 +0000404static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
405{
406 TranslationBlock *tb1;
407 unsigned int n1;
408
409 for(;;) {
410 tb1 = *ptb;
411 n1 = (long)tb1 & 3;
412 tb1 = (TranslationBlock *)((long)tb1 & ~3);
413 if (tb1 == tb) {
414 *ptb = tb1->page_next[n1];
415 break;
416 }
417 ptb = &tb1->page_next[n1];
418 }
419}
420
bellardd4e81642003-05-25 16:46:15 +0000421static inline void tb_jmp_remove(TranslationBlock *tb, int n)
422{
423 TranslationBlock *tb1, **ptb;
424 unsigned int n1;
425
426 ptb = &tb->jmp_next[n];
427 tb1 = *ptb;
428 if (tb1) {
429 /* find tb(n) in circular list */
430 for(;;) {
431 tb1 = *ptb;
432 n1 = (long)tb1 & 3;
433 tb1 = (TranslationBlock *)((long)tb1 & ~3);
434 if (n1 == n && tb1 == tb)
435 break;
436 if (n1 == 2) {
437 ptb = &tb1->jmp_first;
438 } else {
439 ptb = &tb1->jmp_next[n1];
440 }
441 }
442 /* now we can suppress tb(n) from the list */
443 *ptb = tb->jmp_next[n];
444
445 tb->jmp_next[n] = NULL;
446 }
447}
448
449/* reset the jump entry 'n' of a TB so that it is not chained to
450 another TB */
451static inline void tb_reset_jump(TranslationBlock *tb, int n)
452{
453 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
454}
455
bellard9fa3e852004-01-04 18:06:42 +0000456static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000457{
bellard6a00d602005-11-21 23:25:50 +0000458 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000459 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000460 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000461 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000462 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000463
464 /* remove the TB from the hash list */
465 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
466 h = tb_phys_hash_func(phys_pc);
467 tb_remove(&tb_phys_hash[h], tb,
468 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000469
bellard9fa3e852004-01-04 18:06:42 +0000470 /* remove the TB from the page list */
471 if (tb->page_addr[0] != page_addr) {
472 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
473 tb_page_remove(&p->first_tb, tb);
474 invalidate_page_bitmap(p);
475 }
476 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
477 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
478 tb_page_remove(&p->first_tb, tb);
479 invalidate_page_bitmap(p);
480 }
481
bellard8a40a182005-11-20 10:35:40 +0000482 tb_invalidated_flag = 1;
483
484 /* remove the TB from the hash list */
485 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000486 for(env = first_cpu; env != NULL; env = env->next_cpu) {
487 if (env->tb_jmp_cache[h] == tb)
488 env->tb_jmp_cache[h] = NULL;
489 }
bellard8a40a182005-11-20 10:35:40 +0000490
491 /* suppress this TB from the two jump lists */
492 tb_jmp_remove(tb, 0);
493 tb_jmp_remove(tb, 1);
494
495 /* suppress any remaining jumps to this TB */
496 tb1 = tb->jmp_first;
497 for(;;) {
498 n1 = (long)tb1 & 3;
499 if (n1 == 2)
500 break;
501 tb1 = (TranslationBlock *)((long)tb1 & ~3);
502 tb2 = tb1->jmp_next[n1];
503 tb_reset_jump(tb1, n1);
504 tb1->jmp_next[n1] = NULL;
505 tb1 = tb2;
506 }
507 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
508
bellarde3db7222005-01-26 22:00:47 +0000509 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000510}
511
512static inline void set_bits(uint8_t *tab, int start, int len)
513{
514 int end, mask, end1;
515
516 end = start + len;
517 tab += start >> 3;
518 mask = 0xff << (start & 7);
519 if ((start & ~7) == (end & ~7)) {
520 if (start < end) {
521 mask &= ~(0xff << (end & 7));
522 *tab |= mask;
523 }
524 } else {
525 *tab++ |= mask;
526 start = (start + 8) & ~7;
527 end1 = end & ~7;
528 while (start < end1) {
529 *tab++ = 0xff;
530 start += 8;
531 }
532 if (start < end) {
533 mask = ~(0xff << (end & 7));
534 *tab |= mask;
535 }
536 }
537}
538
539static void build_page_bitmap(PageDesc *p)
540{
541 int n, tb_start, tb_end;
542 TranslationBlock *tb;
543
bellard59817cc2004-02-16 22:01:13 +0000544 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000545 if (!p->code_bitmap)
546 return;
547 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
548
549 tb = p->first_tb;
550 while (tb != NULL) {
551 n = (long)tb & 3;
552 tb = (TranslationBlock *)((long)tb & ~3);
553 /* NOTE: this is subtle as a TB may span two physical pages */
554 if (n == 0) {
555 /* NOTE: tb_end may be after the end of the page, but
556 it is not a problem */
557 tb_start = tb->pc & ~TARGET_PAGE_MASK;
558 tb_end = tb_start + tb->size;
559 if (tb_end > TARGET_PAGE_SIZE)
560 tb_end = TARGET_PAGE_SIZE;
561 } else {
562 tb_start = 0;
563 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
564 }
565 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
566 tb = tb->page_next[n];
567 }
568}
569
bellardd720b932004-04-25 17:57:43 +0000570#ifdef TARGET_HAS_PRECISE_SMC
571
572static void tb_gen_code(CPUState *env,
573 target_ulong pc, target_ulong cs_base, int flags,
574 int cflags)
575{
576 TranslationBlock *tb;
577 uint8_t *tc_ptr;
578 target_ulong phys_pc, phys_page2, virt_page2;
579 int code_gen_size;
580
bellardc27004e2005-01-03 23:35:10 +0000581 phys_pc = get_phys_addr_code(env, pc);
582 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000583 if (!tb) {
584 /* flush must be done */
585 tb_flush(env);
586 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000587 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000588 }
589 tc_ptr = code_gen_ptr;
590 tb->tc_ptr = tc_ptr;
591 tb->cs_base = cs_base;
592 tb->flags = flags;
593 tb->cflags = cflags;
594 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
595 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
596
597 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000598 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000599 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000600 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000601 phys_page2 = get_phys_addr_code(env, virt_page2);
602 }
603 tb_link_phys(tb, phys_pc, phys_page2);
604}
605#endif
606
bellard9fa3e852004-01-04 18:06:42 +0000607/* invalidate all TBs which intersect with the target physical page
608 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000609 the same physical page. 'is_cpu_write_access' should be true if called
610 from a real cpu write access: the virtual CPU will exit the current
611 TB if code is modified inside this TB. */
612void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
613 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000614{
bellardd720b932004-04-25 17:57:43 +0000615 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000616 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000617 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000618 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000619 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000620 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000621
622 p = page_find(start >> TARGET_PAGE_BITS);
623 if (!p)
624 return;
625 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000626 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
627 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000628 /* build code bitmap */
629 build_page_bitmap(p);
630 }
631
632 /* we remove all the TBs in the range [start, end[ */
633 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000634 current_tb_not_found = is_cpu_write_access;
635 current_tb_modified = 0;
636 current_tb = NULL; /* avoid warning */
637 current_pc = 0; /* avoid warning */
638 current_cs_base = 0; /* avoid warning */
639 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000640 tb = p->first_tb;
641 while (tb != NULL) {
642 n = (long)tb & 3;
643 tb = (TranslationBlock *)((long)tb & ~3);
644 tb_next = tb->page_next[n];
645 /* NOTE: this is subtle as a TB may span two physical pages */
646 if (n == 0) {
647 /* NOTE: tb_end may be after the end of the page, but
648 it is not a problem */
649 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
650 tb_end = tb_start + tb->size;
651 } else {
652 tb_start = tb->page_addr[1];
653 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
654 }
655 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000656#ifdef TARGET_HAS_PRECISE_SMC
657 if (current_tb_not_found) {
658 current_tb_not_found = 0;
659 current_tb = NULL;
660 if (env->mem_write_pc) {
661 /* now we have a real cpu fault */
662 current_tb = tb_find_pc(env->mem_write_pc);
663 }
664 }
665 if (current_tb == tb &&
666 !(current_tb->cflags & CF_SINGLE_INSN)) {
667 /* If we are modifying the current TB, we must stop
668 its execution. We could be more precise by checking
669 that the modification is after the current PC, but it
670 would require a specialized function to partially
671 restore the CPU state */
672
673 current_tb_modified = 1;
674 cpu_restore_state(current_tb, env,
675 env->mem_write_pc, NULL);
676#if defined(TARGET_I386)
677 current_flags = env->hflags;
678 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
679 current_cs_base = (target_ulong)env->segs[R_CS].base;
680 current_pc = current_cs_base + env->eip;
681#else
682#error unsupported CPU
683#endif
684 }
685#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000686 /* we need to do that to handle the case where a signal
687 occurs while doing tb_phys_invalidate() */
688 saved_tb = NULL;
689 if (env) {
690 saved_tb = env->current_tb;
691 env->current_tb = NULL;
692 }
bellard9fa3e852004-01-04 18:06:42 +0000693 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000694 if (env) {
695 env->current_tb = saved_tb;
696 if (env->interrupt_request && env->current_tb)
697 cpu_interrupt(env, env->interrupt_request);
698 }
bellard9fa3e852004-01-04 18:06:42 +0000699 }
700 tb = tb_next;
701 }
702#if !defined(CONFIG_USER_ONLY)
703 /* if no code remaining, no need to continue to use slow writes */
704 if (!p->first_tb) {
705 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000706 if (is_cpu_write_access) {
707 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
708 }
709 }
710#endif
711#ifdef TARGET_HAS_PRECISE_SMC
712 if (current_tb_modified) {
713 /* we generate a block containing just the instruction
714 modifying the memory. It will ensure that it cannot modify
715 itself */
bellardea1c1802004-06-14 18:56:36 +0000716 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000717 tb_gen_code(env, current_pc, current_cs_base, current_flags,
718 CF_SINGLE_INSN);
719 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000720 }
721#endif
722}
723
724/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000725static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000726{
727 PageDesc *p;
728 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000729#if 0
bellarda4193c82004-06-03 14:01:43 +0000730 if (1) {
731 if (loglevel) {
732 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
733 cpu_single_env->mem_write_vaddr, len,
734 cpu_single_env->eip,
735 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
736 }
bellard59817cc2004-02-16 22:01:13 +0000737 }
738#endif
bellard9fa3e852004-01-04 18:06:42 +0000739 p = page_find(start >> TARGET_PAGE_BITS);
740 if (!p)
741 return;
742 if (p->code_bitmap) {
743 offset = start & ~TARGET_PAGE_MASK;
744 b = p->code_bitmap[offset >> 3] >> (offset & 7);
745 if (b & ((1 << len) - 1))
746 goto do_invalidate;
747 } else {
748 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000749 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000750 }
751}
752
bellard9fa3e852004-01-04 18:06:42 +0000753#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000754static void tb_invalidate_phys_page(target_ulong addr,
755 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000756{
bellardd720b932004-04-25 17:57:43 +0000757 int n, current_flags, current_tb_modified;
758 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000759 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000760 TranslationBlock *tb, *current_tb;
761#ifdef TARGET_HAS_PRECISE_SMC
762 CPUState *env = cpu_single_env;
763#endif
bellard9fa3e852004-01-04 18:06:42 +0000764
765 addr &= TARGET_PAGE_MASK;
766 p = page_find(addr >> TARGET_PAGE_BITS);
767 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000768 return;
769 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000770 current_tb_modified = 0;
771 current_tb = NULL;
772 current_pc = 0; /* avoid warning */
773 current_cs_base = 0; /* avoid warning */
774 current_flags = 0; /* avoid warning */
775#ifdef TARGET_HAS_PRECISE_SMC
776 if (tb && pc != 0) {
777 current_tb = tb_find_pc(pc);
778 }
779#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000780 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000781 n = (long)tb & 3;
782 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000783#ifdef TARGET_HAS_PRECISE_SMC
784 if (current_tb == tb &&
785 !(current_tb->cflags & CF_SINGLE_INSN)) {
786 /* If we are modifying the current TB, we must stop
787 its execution. We could be more precise by checking
788 that the modification is after the current PC, but it
789 would require a specialized function to partially
790 restore the CPU state */
791
792 current_tb_modified = 1;
793 cpu_restore_state(current_tb, env, pc, puc);
794#if defined(TARGET_I386)
795 current_flags = env->hflags;
796 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
797 current_cs_base = (target_ulong)env->segs[R_CS].base;
798 current_pc = current_cs_base + env->eip;
799#else
800#error unsupported CPU
801#endif
802 }
803#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000804 tb_phys_invalidate(tb, addr);
805 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000806 }
807 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000808#ifdef TARGET_HAS_PRECISE_SMC
809 if (current_tb_modified) {
810 /* we generate a block containing just the instruction
811 modifying the memory. It will ensure that it cannot modify
812 itself */
bellardea1c1802004-06-14 18:56:36 +0000813 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000814 tb_gen_code(env, current_pc, current_cs_base, current_flags,
815 CF_SINGLE_INSN);
816 cpu_resume_from_signal(env, puc);
817 }
818#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000819}
bellard9fa3e852004-01-04 18:06:42 +0000820#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000821
822/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000823static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000824 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000825{
826 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000827 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000828
bellard9fa3e852004-01-04 18:06:42 +0000829 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000830 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000831 tb->page_next[n] = p->first_tb;
832 last_first_tb = p->first_tb;
833 p->first_tb = (TranslationBlock *)((long)tb | n);
834 invalidate_page_bitmap(p);
835
bellard107db442004-06-22 18:48:46 +0000836#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000837
bellard9fa3e852004-01-04 18:06:42 +0000838#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000839 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000840 target_ulong addr;
841 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000842 int prot;
843
bellardfd6ce8f2003-05-14 19:00:11 +0000844 /* force the host page as non writable (writes will have a
845 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000846 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000847 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000848 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
849 addr += TARGET_PAGE_SIZE) {
850
851 p2 = page_find (addr >> TARGET_PAGE_BITS);
852 if (!p2)
853 continue;
854 prot |= p2->flags;
855 p2->flags &= ~PAGE_WRITE;
856 page_get_flags(addr);
857 }
858 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000859 (prot & PAGE_BITS) & ~PAGE_WRITE);
860#ifdef DEBUG_TB_INVALIDATE
861 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000862 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000863#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000864 }
bellard9fa3e852004-01-04 18:06:42 +0000865#else
866 /* if some code is already present, then the pages are already
867 protected. So we handle the case where only the first TB is
868 allocated in a physical page */
869 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000870 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000871 }
872#endif
bellardd720b932004-04-25 17:57:43 +0000873
874#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000875}
876
877/* Allocate a new translation block. Flush the translation buffer if
878 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000879TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000880{
881 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000882
883 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
884 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000885 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000886 tb = &tbs[nb_tbs++];
887 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000888 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000889 return tb;
890}
891
bellard9fa3e852004-01-04 18:06:42 +0000892/* add a new TB and link it to the physical page tables. phys_page2 is
893 (-1) to indicate that only one page contains the TB. */
894void tb_link_phys(TranslationBlock *tb,
895 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000896{
bellard9fa3e852004-01-04 18:06:42 +0000897 unsigned int h;
898 TranslationBlock **ptb;
899
900 /* add in the physical hash table */
901 h = tb_phys_hash_func(phys_pc);
902 ptb = &tb_phys_hash[h];
903 tb->phys_hash_next = *ptb;
904 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000905
906 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000907 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
908 if (phys_page2 != -1)
909 tb_alloc_page(tb, 1, phys_page2);
910 else
911 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000912
bellardd4e81642003-05-25 16:46:15 +0000913 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
914 tb->jmp_next[0] = NULL;
915 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000916#ifdef USE_CODE_COPY
917 tb->cflags &= ~CF_FP_USED;
918 if (tb->cflags & CF_TB_FP_USED)
919 tb->cflags |= CF_FP_USED;
920#endif
bellardd4e81642003-05-25 16:46:15 +0000921
922 /* init original jump addresses */
923 if (tb->tb_next_offset[0] != 0xffff)
924 tb_reset_jump(tb, 0);
925 if (tb->tb_next_offset[1] != 0xffff)
926 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000927
928#ifdef DEBUG_TB_CHECK
929 tb_page_check();
930#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000931}
932
bellarda513fe12003-05-27 23:29:48 +0000933/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
934 tb[1].tc_ptr. Return NULL if not found */
935TranslationBlock *tb_find_pc(unsigned long tc_ptr)
936{
937 int m_min, m_max, m;
938 unsigned long v;
939 TranslationBlock *tb;
940
941 if (nb_tbs <= 0)
942 return NULL;
943 if (tc_ptr < (unsigned long)code_gen_buffer ||
944 tc_ptr >= (unsigned long)code_gen_ptr)
945 return NULL;
946 /* binary search (cf Knuth) */
947 m_min = 0;
948 m_max = nb_tbs - 1;
949 while (m_min <= m_max) {
950 m = (m_min + m_max) >> 1;
951 tb = &tbs[m];
952 v = (unsigned long)tb->tc_ptr;
953 if (v == tc_ptr)
954 return tb;
955 else if (tc_ptr < v) {
956 m_max = m - 1;
957 } else {
958 m_min = m + 1;
959 }
960 }
961 return &tbs[m_max];
962}
bellard75012672003-06-21 13:11:07 +0000963
bellardea041c02003-06-25 16:16:50 +0000964static void tb_reset_jump_recursive(TranslationBlock *tb);
965
966static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
967{
968 TranslationBlock *tb1, *tb_next, **ptb;
969 unsigned int n1;
970
971 tb1 = tb->jmp_next[n];
972 if (tb1 != NULL) {
973 /* find head of list */
974 for(;;) {
975 n1 = (long)tb1 & 3;
976 tb1 = (TranslationBlock *)((long)tb1 & ~3);
977 if (n1 == 2)
978 break;
979 tb1 = tb1->jmp_next[n1];
980 }
981 /* we are now sure now that tb jumps to tb1 */
982 tb_next = tb1;
983
984 /* remove tb from the jmp_first list */
985 ptb = &tb_next->jmp_first;
986 for(;;) {
987 tb1 = *ptb;
988 n1 = (long)tb1 & 3;
989 tb1 = (TranslationBlock *)((long)tb1 & ~3);
990 if (n1 == n && tb1 == tb)
991 break;
992 ptb = &tb1->jmp_next[n1];
993 }
994 *ptb = tb->jmp_next[n];
995 tb->jmp_next[n] = NULL;
996
997 /* suppress the jump to next tb in generated code */
998 tb_reset_jump(tb, n);
999
bellard01243112004-01-04 15:48:17 +00001000 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001001 tb_reset_jump_recursive(tb_next);
1002 }
1003}
1004
1005static void tb_reset_jump_recursive(TranslationBlock *tb)
1006{
1007 tb_reset_jump_recursive2(tb, 0);
1008 tb_reset_jump_recursive2(tb, 1);
1009}
1010
bellard1fddef42005-04-17 19:16:13 +00001011#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001012static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1013{
pbrookc2f07f82006-04-08 17:14:56 +00001014 target_ulong addr, pd;
1015 ram_addr_t ram_addr;
1016 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001017
pbrookc2f07f82006-04-08 17:14:56 +00001018 addr = cpu_get_phys_page_debug(env, pc);
1019 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1020 if (!p) {
1021 pd = IO_MEM_UNASSIGNED;
1022 } else {
1023 pd = p->phys_offset;
1024 }
1025 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001026 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001027}
bellardc27004e2005-01-03 23:35:10 +00001028#endif
bellardd720b932004-04-25 17:57:43 +00001029
bellardc33a3462003-07-29 20:50:33 +00001030/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1031 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001032int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001033{
bellard1fddef42005-04-17 19:16:13 +00001034#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001035 int i;
bellardd720b932004-04-25 17:57:43 +00001036
bellard4c3a88a2003-07-26 12:06:08 +00001037 for(i = 0; i < env->nb_breakpoints; i++) {
1038 if (env->breakpoints[i] == pc)
1039 return 0;
1040 }
1041
1042 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1043 return -1;
1044 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001045
1046 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001047 return 0;
1048#else
1049 return -1;
1050#endif
1051}
1052
1053/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001054int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001055{
bellard1fddef42005-04-17 19:16:13 +00001056#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001057 int i;
1058 for(i = 0; i < env->nb_breakpoints; i++) {
1059 if (env->breakpoints[i] == pc)
1060 goto found;
1061 }
1062 return -1;
1063 found:
bellard4c3a88a2003-07-26 12:06:08 +00001064 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001065 if (i < env->nb_breakpoints)
1066 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001067
1068 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001069 return 0;
1070#else
1071 return -1;
1072#endif
1073}
1074
bellardc33a3462003-07-29 20:50:33 +00001075/* enable or disable single step mode. EXCP_DEBUG is returned by the
1076 CPU loop after each instruction */
1077void cpu_single_step(CPUState *env, int enabled)
1078{
bellard1fddef42005-04-17 19:16:13 +00001079#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001080 if (env->singlestep_enabled != enabled) {
1081 env->singlestep_enabled = enabled;
1082 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001083 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001084 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001085 }
1086#endif
1087}
1088
bellard34865132003-10-05 14:28:56 +00001089/* enable or disable low levels log */
1090void cpu_set_log(int log_flags)
1091{
1092 loglevel = log_flags;
1093 if (loglevel && !logfile) {
1094 logfile = fopen(logfilename, "w");
1095 if (!logfile) {
1096 perror(logfilename);
1097 _exit(1);
1098 }
bellard9fa3e852004-01-04 18:06:42 +00001099#if !defined(CONFIG_SOFTMMU)
1100 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1101 {
1102 static uint8_t logfile_buf[4096];
1103 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1104 }
1105#else
bellard34865132003-10-05 14:28:56 +00001106 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001107#endif
bellard34865132003-10-05 14:28:56 +00001108 }
1109}
1110
1111void cpu_set_log_filename(const char *filename)
1112{
1113 logfilename = strdup(filename);
1114}
bellardc33a3462003-07-29 20:50:33 +00001115
bellard01243112004-01-04 15:48:17 +00001116/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001117void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001118{
1119 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001120 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001121
bellard68a79312003-06-30 13:12:32 +00001122 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001123 /* if the cpu is currently executing code, we must unlink it and
1124 all the potentially executing TB */
1125 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001126 if (tb && !testandset(&interrupt_lock)) {
1127 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001128 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001129 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001130 }
1131}
1132
bellardb54ad042004-05-20 13:42:52 +00001133void cpu_reset_interrupt(CPUState *env, int mask)
1134{
1135 env->interrupt_request &= ~mask;
1136}
1137
bellardf193c792004-03-21 17:06:25 +00001138CPULogItem cpu_log_items[] = {
1139 { CPU_LOG_TB_OUT_ASM, "out_asm",
1140 "show generated host assembly code for each compiled TB" },
1141 { CPU_LOG_TB_IN_ASM, "in_asm",
1142 "show target assembly code for each compiled TB" },
1143 { CPU_LOG_TB_OP, "op",
1144 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1145#ifdef TARGET_I386
1146 { CPU_LOG_TB_OP_OPT, "op_opt",
1147 "show micro ops after optimization for each compiled TB" },
1148#endif
1149 { CPU_LOG_INT, "int",
1150 "show interrupts/exceptions in short format" },
1151 { CPU_LOG_EXEC, "exec",
1152 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001153 { CPU_LOG_TB_CPU, "cpu",
1154 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001155#ifdef TARGET_I386
1156 { CPU_LOG_PCALL, "pcall",
1157 "show protected mode far calls/returns/exceptions" },
1158#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001159#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001160 { CPU_LOG_IOPORT, "ioport",
1161 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001162#endif
bellardf193c792004-03-21 17:06:25 +00001163 { 0, NULL, NULL },
1164};
1165
1166static int cmp1(const char *s1, int n, const char *s2)
1167{
1168 if (strlen(s2) != n)
1169 return 0;
1170 return memcmp(s1, s2, n) == 0;
1171}
1172
1173/* takes a comma separated list of log masks. Return 0 if error. */
1174int cpu_str_to_log_mask(const char *str)
1175{
1176 CPULogItem *item;
1177 int mask;
1178 const char *p, *p1;
1179
1180 p = str;
1181 mask = 0;
1182 for(;;) {
1183 p1 = strchr(p, ',');
1184 if (!p1)
1185 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001186 if(cmp1(p,p1-p,"all")) {
1187 for(item = cpu_log_items; item->mask != 0; item++) {
1188 mask |= item->mask;
1189 }
1190 } else {
bellardf193c792004-03-21 17:06:25 +00001191 for(item = cpu_log_items; item->mask != 0; item++) {
1192 if (cmp1(p, p1 - p, item->name))
1193 goto found;
1194 }
1195 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001196 }
bellardf193c792004-03-21 17:06:25 +00001197 found:
1198 mask |= item->mask;
1199 if (*p1 != ',')
1200 break;
1201 p = p1 + 1;
1202 }
1203 return mask;
1204}
bellardea041c02003-06-25 16:16:50 +00001205
bellard75012672003-06-21 13:11:07 +00001206void cpu_abort(CPUState *env, const char *fmt, ...)
1207{
1208 va_list ap;
1209
1210 va_start(ap, fmt);
1211 fprintf(stderr, "qemu: fatal: ");
1212 vfprintf(stderr, fmt, ap);
1213 fprintf(stderr, "\n");
1214#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001215 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1216#else
1217 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001218#endif
1219 va_end(ap);
1220 abort();
1221}
1222
bellard01243112004-01-04 15:48:17 +00001223#if !defined(CONFIG_USER_ONLY)
1224
bellardee8b7022004-02-03 23:35:10 +00001225/* NOTE: if flush_global is true, also flush global entries (not
1226 implemented yet) */
1227void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001228{
bellard33417e72003-08-10 21:47:01 +00001229 int i;
bellard01243112004-01-04 15:48:17 +00001230
bellard9fa3e852004-01-04 18:06:42 +00001231#if defined(DEBUG_TLB)
1232 printf("tlb_flush:\n");
1233#endif
bellard01243112004-01-04 15:48:17 +00001234 /* must reset current TB so that interrupts cannot modify the
1235 links while we are modifying them */
1236 env->current_tb = NULL;
1237
bellard33417e72003-08-10 21:47:01 +00001238 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001239 env->tlb_table[0][i].addr_read = -1;
1240 env->tlb_table[0][i].addr_write = -1;
1241 env->tlb_table[0][i].addr_code = -1;
1242 env->tlb_table[1][i].addr_read = -1;
1243 env->tlb_table[1][i].addr_write = -1;
1244 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001245 }
bellard9fa3e852004-01-04 18:06:42 +00001246
bellard8a40a182005-11-20 10:35:40 +00001247 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001248
1249#if !defined(CONFIG_SOFTMMU)
1250 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1251#endif
bellard0a962c02005-02-10 22:00:27 +00001252#ifdef USE_KQEMU
1253 if (env->kqemu_enabled) {
1254 kqemu_flush(env, flush_global);
1255 }
1256#endif
bellarde3db7222005-01-26 22:00:47 +00001257 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001258}
1259
bellard274da6b2004-05-20 21:56:27 +00001260static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001261{
bellard84b7b8e2005-11-28 21:19:04 +00001262 if (addr == (tlb_entry->addr_read &
1263 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1264 addr == (tlb_entry->addr_write &
1265 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1266 addr == (tlb_entry->addr_code &
1267 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1268 tlb_entry->addr_read = -1;
1269 tlb_entry->addr_write = -1;
1270 tlb_entry->addr_code = -1;
1271 }
bellard61382a52003-10-27 21:22:23 +00001272}
1273
bellard2e126692004-04-25 21:28:44 +00001274void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001275{
bellard8a40a182005-11-20 10:35:40 +00001276 int i;
bellard9fa3e852004-01-04 18:06:42 +00001277 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001278
bellard9fa3e852004-01-04 18:06:42 +00001279#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001280 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001281#endif
bellard01243112004-01-04 15:48:17 +00001282 /* must reset current TB so that interrupts cannot modify the
1283 links while we are modifying them */
1284 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001285
bellard61382a52003-10-27 21:22:23 +00001286 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001287 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001288 tlb_flush_entry(&env->tlb_table[0][i], addr);
1289 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001290
bellard8a40a182005-11-20 10:35:40 +00001291 for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
1292 tb = env->tb_jmp_cache[i];
1293 if (tb &&
1294 ((tb->pc & TARGET_PAGE_MASK) == addr ||
1295 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
1296 env->tb_jmp_cache[i] = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001297 }
1298 }
1299
bellard01243112004-01-04 15:48:17 +00001300#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001301 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001302 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001303#endif
bellard0a962c02005-02-10 22:00:27 +00001304#ifdef USE_KQEMU
1305 if (env->kqemu_enabled) {
1306 kqemu_flush_page(env, addr);
1307 }
1308#endif
bellard9fa3e852004-01-04 18:06:42 +00001309}
1310
bellard9fa3e852004-01-04 18:06:42 +00001311/* update the TLBs so that writes to code in the virtual page 'addr'
1312 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001313static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001314{
bellard6a00d602005-11-21 23:25:50 +00001315 cpu_physical_memory_reset_dirty(ram_addr,
1316 ram_addr + TARGET_PAGE_SIZE,
1317 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001318}
1319
bellard9fa3e852004-01-04 18:06:42 +00001320/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001321 tested for self modifying code */
1322static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1323 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001324{
bellard3a7d9292005-08-21 09:26:42 +00001325 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001326}
1327
1328static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1329 unsigned long start, unsigned long length)
1330{
1331 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001332 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1333 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001334 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001335 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001336 }
1337 }
1338}
1339
bellard3a7d9292005-08-21 09:26:42 +00001340void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001341 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001342{
1343 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001344 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001345 int i, mask, len;
1346 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001347
1348 start &= TARGET_PAGE_MASK;
1349 end = TARGET_PAGE_ALIGN(end);
1350
1351 length = end - start;
1352 if (length == 0)
1353 return;
bellard0a962c02005-02-10 22:00:27 +00001354 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001355#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001356 /* XXX: should not depend on cpu context */
1357 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001358 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001359 ram_addr_t addr;
1360 addr = start;
1361 for(i = 0; i < len; i++) {
1362 kqemu_set_notdirty(env, addr);
1363 addr += TARGET_PAGE_SIZE;
1364 }
bellard3a7d9292005-08-21 09:26:42 +00001365 }
1366#endif
bellardf23db162005-08-21 19:12:28 +00001367 mask = ~dirty_flags;
1368 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1369 for(i = 0; i < len; i++)
1370 p[i] &= mask;
1371
bellard1ccde1c2004-02-06 19:46:14 +00001372 /* we modify the TLB cache so that the dirty bit will be set again
1373 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001374 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001375 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1376 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001377 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001378 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001379 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001380 }
bellard59817cc2004-02-16 22:01:13 +00001381
1382#if !defined(CONFIG_SOFTMMU)
1383 /* XXX: this is expensive */
1384 {
1385 VirtPageDesc *p;
1386 int j;
1387 target_ulong addr;
1388
1389 for(i = 0; i < L1_SIZE; i++) {
1390 p = l1_virt_map[i];
1391 if (p) {
1392 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1393 for(j = 0; j < L2_SIZE; j++) {
1394 if (p->valid_tag == virt_valid_tag &&
1395 p->phys_addr >= start && p->phys_addr < end &&
1396 (p->prot & PROT_WRITE)) {
1397 if (addr < MMAP_AREA_END) {
1398 mprotect((void *)addr, TARGET_PAGE_SIZE,
1399 p->prot & ~PROT_WRITE);
1400 }
1401 }
1402 addr += TARGET_PAGE_SIZE;
1403 p++;
1404 }
1405 }
1406 }
1407 }
1408#endif
bellard1ccde1c2004-02-06 19:46:14 +00001409}
1410
bellard3a7d9292005-08-21 09:26:42 +00001411static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1412{
1413 ram_addr_t ram_addr;
1414
bellard84b7b8e2005-11-28 21:19:04 +00001415 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1416 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001417 tlb_entry->addend - (unsigned long)phys_ram_base;
1418 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001419 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001420 }
1421 }
1422}
1423
1424/* update the TLB according to the current state of the dirty bits */
1425void cpu_tlb_update_dirty(CPUState *env)
1426{
1427 int i;
1428 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001429 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001430 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001431 tlb_update_dirty(&env->tlb_table[1][i]);
bellard3a7d9292005-08-21 09:26:42 +00001432}
1433
bellard1ccde1c2004-02-06 19:46:14 +00001434static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001435 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001436{
1437 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001438 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1439 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001440 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001441 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001442 }
1443 }
1444}
1445
1446/* update the TLB corresponding to virtual page vaddr and phys addr
1447 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001448static inline void tlb_set_dirty(CPUState *env,
1449 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001450{
bellard1ccde1c2004-02-06 19:46:14 +00001451 int i;
1452
bellard1ccde1c2004-02-06 19:46:14 +00001453 addr &= TARGET_PAGE_MASK;
1454 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001455 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1456 tlb_set_dirty1(&env->tlb_table[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001457}
1458
bellard59817cc2004-02-16 22:01:13 +00001459/* add a new TLB entry. At most one entry for a given virtual address
1460 is permitted. Return 0 if OK or 2 if the page could not be mapped
1461 (can only happen in non SOFTMMU mode for I/O pages or pages
1462 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001463int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1464 target_phys_addr_t paddr, int prot,
1465 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001466{
bellard92e873b2004-05-21 14:52:29 +00001467 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001468 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001469 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001470 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001471 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001472 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001473 CPUTLBEntry *te;
bellard9fa3e852004-01-04 18:06:42 +00001474
bellard92e873b2004-05-21 14:52:29 +00001475 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001476 if (!p) {
1477 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001478 } else {
1479 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001480 }
1481#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001482 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
bellard84b7b8e2005-11-28 21:19:04 +00001483 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001484#endif
1485
1486 ret = 0;
1487#if !defined(CONFIG_SOFTMMU)
1488 if (is_softmmu)
1489#endif
1490 {
bellard2a4188a2006-06-25 21:54:59 +00001491 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001492 /* IO memory case */
1493 address = vaddr | pd;
1494 addend = paddr;
1495 } else {
1496 /* standard memory */
1497 address = vaddr;
1498 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1499 }
1500
bellard90f18422005-07-24 10:17:31 +00001501 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001502 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001503 te = &env->tlb_table[is_user][index];
1504 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001505 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001506 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001507 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001508 te->addr_read = -1;
1509 }
1510 if (prot & PAGE_EXEC) {
1511 te->addr_code = address;
1512 } else {
1513 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001514 }
bellard67b915a2004-03-31 23:37:16 +00001515 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001516 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1517 (pd & IO_MEM_ROMD)) {
1518 /* write access calls the I/O callback */
1519 te->addr_write = vaddr |
1520 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001521 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001522 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001523 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001524 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001525 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001526 }
1527 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001528 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001529 }
1530 }
1531#if !defined(CONFIG_SOFTMMU)
1532 else {
1533 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1534 /* IO access: no mapping is done as it will be handled by the
1535 soft MMU */
1536 if (!(env->hflags & HF_SOFTMMU_MASK))
1537 ret = 2;
1538 } else {
1539 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001540
bellard59817cc2004-02-16 22:01:13 +00001541 if (vaddr >= MMAP_AREA_END) {
1542 ret = 2;
1543 } else {
1544 if (prot & PROT_WRITE) {
1545 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001546#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001547 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001548#endif
bellard59817cc2004-02-16 22:01:13 +00001549 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1550 !cpu_physical_memory_is_dirty(pd))) {
1551 /* ROM: we do as if code was inside */
1552 /* if code is present, we only map as read only and save the
1553 original mapping */
1554 VirtPageDesc *vp;
1555
bellard90f18422005-07-24 10:17:31 +00001556 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001557 vp->phys_addr = pd;
1558 vp->prot = prot;
1559 vp->valid_tag = virt_valid_tag;
1560 prot &= ~PAGE_WRITE;
1561 }
bellard9fa3e852004-01-04 18:06:42 +00001562 }
bellard59817cc2004-02-16 22:01:13 +00001563 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1564 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1565 if (map_addr == MAP_FAILED) {
1566 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1567 paddr, vaddr);
1568 }
bellard9fa3e852004-01-04 18:06:42 +00001569 }
1570 }
1571 }
1572#endif
1573 return ret;
1574}
1575
1576/* called from signal handler: invalidate the code and unprotect the
1577 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001578int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001579{
1580#if !defined(CONFIG_SOFTMMU)
1581 VirtPageDesc *vp;
1582
1583#if defined(DEBUG_TLB)
1584 printf("page_unprotect: addr=0x%08x\n", addr);
1585#endif
1586 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001587
1588 /* if it is not mapped, no need to worry here */
1589 if (addr >= MMAP_AREA_END)
1590 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001591 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1592 if (!vp)
1593 return 0;
1594 /* NOTE: in this case, validate_tag is _not_ tested as it
1595 validates only the code TLB */
1596 if (vp->valid_tag != virt_valid_tag)
1597 return 0;
1598 if (!(vp->prot & PAGE_WRITE))
1599 return 0;
1600#if defined(DEBUG_TLB)
1601 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1602 addr, vp->phys_addr, vp->prot);
1603#endif
bellard59817cc2004-02-16 22:01:13 +00001604 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1605 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1606 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001607 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001608 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001609 /* flush the code inside */
1610 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001611 return 1;
1612#else
1613 return 0;
1614#endif
bellard33417e72003-08-10 21:47:01 +00001615}
1616
bellard01243112004-01-04 15:48:17 +00001617#else
1618
bellardee8b7022004-02-03 23:35:10 +00001619void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001620{
1621}
1622
bellard2e126692004-04-25 21:28:44 +00001623void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001624{
1625}
1626
bellard84b7b8e2005-11-28 21:19:04 +00001627int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1628 target_phys_addr_t paddr, int prot,
1629 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001630{
bellard9fa3e852004-01-04 18:06:42 +00001631 return 0;
1632}
bellard33417e72003-08-10 21:47:01 +00001633
bellard9fa3e852004-01-04 18:06:42 +00001634/* dump memory mappings */
1635void page_dump(FILE *f)
1636{
1637 unsigned long start, end;
1638 int i, j, prot, prot1;
1639 PageDesc *p;
1640
1641 fprintf(f, "%-8s %-8s %-8s %s\n",
1642 "start", "end", "size", "prot");
1643 start = -1;
1644 end = -1;
1645 prot = 0;
1646 for(i = 0; i <= L1_SIZE; i++) {
1647 if (i < L1_SIZE)
1648 p = l1_map[i];
1649 else
1650 p = NULL;
1651 for(j = 0;j < L2_SIZE; j++) {
1652 if (!p)
1653 prot1 = 0;
1654 else
1655 prot1 = p[j].flags;
1656 if (prot1 != prot) {
1657 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1658 if (start != -1) {
1659 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1660 start, end, end - start,
1661 prot & PAGE_READ ? 'r' : '-',
1662 prot & PAGE_WRITE ? 'w' : '-',
1663 prot & PAGE_EXEC ? 'x' : '-');
1664 }
1665 if (prot1 != 0)
1666 start = end;
1667 else
1668 start = -1;
1669 prot = prot1;
1670 }
1671 if (!p)
1672 break;
1673 }
bellard33417e72003-08-10 21:47:01 +00001674 }
bellard33417e72003-08-10 21:47:01 +00001675}
1676
pbrook53a59602006-03-25 19:31:22 +00001677int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001678{
bellard9fa3e852004-01-04 18:06:42 +00001679 PageDesc *p;
1680
1681 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001682 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001683 return 0;
1684 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001685}
1686
bellard9fa3e852004-01-04 18:06:42 +00001687/* modify the flags of a page and invalidate the code if
1688 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1689 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001690void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001691{
1692 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001693 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001694
1695 start = start & TARGET_PAGE_MASK;
1696 end = TARGET_PAGE_ALIGN(end);
1697 if (flags & PAGE_WRITE)
1698 flags |= PAGE_WRITE_ORG;
1699 spin_lock(&tb_lock);
1700 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1701 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1702 /* if the write protection is set, then we invalidate the code
1703 inside */
1704 if (!(p->flags & PAGE_WRITE) &&
1705 (flags & PAGE_WRITE) &&
1706 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001707 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001708 }
1709 p->flags = flags;
1710 }
1711 spin_unlock(&tb_lock);
1712}
1713
1714/* called from signal handler: invalidate the code and unprotect the
1715 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001716int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001717{
1718 unsigned int page_index, prot, pindex;
1719 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001720 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001721
bellard83fb7ad2004-07-05 21:25:26 +00001722 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001723 page_index = host_start >> TARGET_PAGE_BITS;
1724 p1 = page_find(page_index);
1725 if (!p1)
1726 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001727 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001728 p = p1;
1729 prot = 0;
1730 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1731 prot |= p->flags;
1732 p++;
1733 }
1734 /* if the page was really writable, then we change its
1735 protection back to writable */
1736 if (prot & PAGE_WRITE_ORG) {
1737 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1738 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001739 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001740 (prot & PAGE_BITS) | PAGE_WRITE);
1741 p1[pindex].flags |= PAGE_WRITE;
1742 /* and since the content will be modified, we must invalidate
1743 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001744 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001745#ifdef DEBUG_TB_CHECK
1746 tb_invalidate_check(address);
1747#endif
1748 return 1;
1749 }
1750 }
1751 return 0;
1752}
1753
1754/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001755/* ??? This should be redundant now we have lock_user. */
1756void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001757{
pbrook53a59602006-03-25 19:31:22 +00001758 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001759
pbrook53a59602006-03-25 19:31:22 +00001760 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001761 end = start + data_size;
1762 start &= TARGET_PAGE_MASK;
1763 end = TARGET_PAGE_ALIGN(end);
1764 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001765 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001766 }
1767}
1768
bellard6a00d602005-11-21 23:25:50 +00001769static inline void tlb_set_dirty(CPUState *env,
1770 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001771{
1772}
bellard9fa3e852004-01-04 18:06:42 +00001773#endif /* defined(CONFIG_USER_ONLY) */
1774
bellard33417e72003-08-10 21:47:01 +00001775/* register physical memory. 'size' must be a multiple of the target
1776 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1777 io memory page */
bellard2e126692004-04-25 21:28:44 +00001778void cpu_register_physical_memory(target_phys_addr_t start_addr,
1779 unsigned long size,
1780 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001781{
bellard108c49b2005-07-24 12:55:09 +00001782 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001783 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001784 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001785
bellard5fd386f2004-05-23 21:11:22 +00001786 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001787 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001788 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001789 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001790 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001791 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1792 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001793 phys_offset += TARGET_PAGE_SIZE;
1794 }
bellard9d420372006-06-25 22:25:22 +00001795
1796 /* since each CPU stores ram addresses in its TLB cache, we must
1797 reset the modified entries */
1798 /* XXX: slow ! */
1799 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1800 tlb_flush(env, 1);
1801 }
bellard33417e72003-08-10 21:47:01 +00001802}
1803
bellardba863452006-09-24 18:41:10 +00001804/* XXX: temporary until new memory mapping API */
1805uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1806{
1807 PhysPageDesc *p;
1808
1809 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1810 if (!p)
1811 return IO_MEM_UNASSIGNED;
1812 return p->phys_offset;
1813}
1814
bellarda4193c82004-06-03 14:01:43 +00001815static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001816{
1817 return 0;
1818}
1819
bellarda4193c82004-06-03 14:01:43 +00001820static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001821{
1822}
1823
1824static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1825 unassigned_mem_readb,
1826 unassigned_mem_readb,
1827 unassigned_mem_readb,
1828};
1829
1830static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1831 unassigned_mem_writeb,
1832 unassigned_mem_writeb,
1833 unassigned_mem_writeb,
1834};
1835
bellarda4193c82004-06-03 14:01:43 +00001836static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001837{
bellard3a7d9292005-08-21 09:26:42 +00001838 unsigned long ram_addr;
1839 int dirty_flags;
1840 ram_addr = addr - (unsigned long)phys_ram_base;
1841 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1842 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1843#if !defined(CONFIG_USER_ONLY)
1844 tb_invalidate_phys_page_fast(ram_addr, 1);
1845 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1846#endif
1847 }
bellardc27004e2005-01-03 23:35:10 +00001848 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001849#ifdef USE_KQEMU
1850 if (cpu_single_env->kqemu_enabled &&
1851 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1852 kqemu_modify_page(cpu_single_env, ram_addr);
1853#endif
bellardf23db162005-08-21 19:12:28 +00001854 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1855 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1856 /* we remove the notdirty callback only if the code has been
1857 flushed */
1858 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001859 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001860}
1861
bellarda4193c82004-06-03 14:01:43 +00001862static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001863{
bellard3a7d9292005-08-21 09:26:42 +00001864 unsigned long ram_addr;
1865 int dirty_flags;
1866 ram_addr = addr - (unsigned long)phys_ram_base;
1867 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1868 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1869#if !defined(CONFIG_USER_ONLY)
1870 tb_invalidate_phys_page_fast(ram_addr, 2);
1871 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1872#endif
1873 }
bellardc27004e2005-01-03 23:35:10 +00001874 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001875#ifdef USE_KQEMU
1876 if (cpu_single_env->kqemu_enabled &&
1877 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1878 kqemu_modify_page(cpu_single_env, ram_addr);
1879#endif
bellardf23db162005-08-21 19:12:28 +00001880 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1881 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1882 /* we remove the notdirty callback only if the code has been
1883 flushed */
1884 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001885 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001886}
1887
bellarda4193c82004-06-03 14:01:43 +00001888static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001889{
bellard3a7d9292005-08-21 09:26:42 +00001890 unsigned long ram_addr;
1891 int dirty_flags;
1892 ram_addr = addr - (unsigned long)phys_ram_base;
1893 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1894 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1895#if !defined(CONFIG_USER_ONLY)
1896 tb_invalidate_phys_page_fast(ram_addr, 4);
1897 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1898#endif
1899 }
bellardc27004e2005-01-03 23:35:10 +00001900 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001901#ifdef USE_KQEMU
1902 if (cpu_single_env->kqemu_enabled &&
1903 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1904 kqemu_modify_page(cpu_single_env, ram_addr);
1905#endif
bellardf23db162005-08-21 19:12:28 +00001906 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1907 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1908 /* we remove the notdirty callback only if the code has been
1909 flushed */
1910 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001911 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001912}
1913
bellard3a7d9292005-08-21 09:26:42 +00001914static CPUReadMemoryFunc *error_mem_read[3] = {
1915 NULL, /* never used */
1916 NULL, /* never used */
1917 NULL, /* never used */
1918};
1919
bellard1ccde1c2004-02-06 19:46:14 +00001920static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1921 notdirty_mem_writeb,
1922 notdirty_mem_writew,
1923 notdirty_mem_writel,
1924};
1925
bellard33417e72003-08-10 21:47:01 +00001926static void io_mem_init(void)
1927{
bellard3a7d9292005-08-21 09:26:42 +00001928 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001929 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001930 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001931 io_mem_nb = 5;
1932
1933 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001934 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001935 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001936}
1937
1938/* mem_read and mem_write are arrays of functions containing the
1939 function to access byte (index 0), word (index 1) and dword (index
1940 2). All functions must be supplied. If io_index is non zero, the
1941 corresponding io zone is modified. If it is zero, a new io zone is
1942 allocated. The return value can be used with
1943 cpu_register_physical_memory(). (-1) is returned if error. */
1944int cpu_register_io_memory(int io_index,
1945 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001946 CPUWriteMemoryFunc **mem_write,
1947 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001948{
1949 int i;
1950
1951 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00001952 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00001953 return -1;
1954 io_index = io_mem_nb++;
1955 } else {
1956 if (io_index >= IO_MEM_NB_ENTRIES)
1957 return -1;
1958 }
bellardb5ff1b32005-11-26 10:38:39 +00001959
bellard33417e72003-08-10 21:47:01 +00001960 for(i = 0;i < 3; i++) {
1961 io_mem_read[io_index][i] = mem_read[i];
1962 io_mem_write[io_index][i] = mem_write[i];
1963 }
bellarda4193c82004-06-03 14:01:43 +00001964 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001965 return io_index << IO_MEM_SHIFT;
1966}
bellard61382a52003-10-27 21:22:23 +00001967
bellard8926b512004-10-10 15:14:20 +00001968CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1969{
1970 return io_mem_write[io_index >> IO_MEM_SHIFT];
1971}
1972
1973CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
1974{
1975 return io_mem_read[io_index >> IO_MEM_SHIFT];
1976}
1977
bellard13eb76e2004-01-24 15:23:36 +00001978/* physical memory access (slow version, mainly for debug) */
1979#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001980void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001981 int len, int is_write)
1982{
1983 int l, flags;
1984 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00001985 void * p;
bellard13eb76e2004-01-24 15:23:36 +00001986
1987 while (len > 0) {
1988 page = addr & TARGET_PAGE_MASK;
1989 l = (page + TARGET_PAGE_SIZE) - addr;
1990 if (l > len)
1991 l = len;
1992 flags = page_get_flags(page);
1993 if (!(flags & PAGE_VALID))
1994 return;
1995 if (is_write) {
1996 if (!(flags & PAGE_WRITE))
1997 return;
pbrook53a59602006-03-25 19:31:22 +00001998 p = lock_user(addr, len, 0);
1999 memcpy(p, buf, len);
2000 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002001 } else {
2002 if (!(flags & PAGE_READ))
2003 return;
pbrook53a59602006-03-25 19:31:22 +00002004 p = lock_user(addr, len, 1);
2005 memcpy(buf, p, len);
2006 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002007 }
2008 len -= l;
2009 buf += l;
2010 addr += l;
2011 }
2012}
bellard8df1cd02005-01-28 22:37:22 +00002013
bellard13eb76e2004-01-24 15:23:36 +00002014#else
bellard2e126692004-04-25 21:28:44 +00002015void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002016 int len, int is_write)
2017{
2018 int l, io_index;
2019 uint8_t *ptr;
2020 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002021 target_phys_addr_t page;
2022 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002023 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002024
2025 while (len > 0) {
2026 page = addr & TARGET_PAGE_MASK;
2027 l = (page + TARGET_PAGE_SIZE) - addr;
2028 if (l > len)
2029 l = len;
bellard92e873b2004-05-21 14:52:29 +00002030 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002031 if (!p) {
2032 pd = IO_MEM_UNASSIGNED;
2033 } else {
2034 pd = p->phys_offset;
2035 }
2036
2037 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002038 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002039 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002040 /* XXX: could force cpu_single_env to NULL to avoid
2041 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002042 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002043 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002044 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002045 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002046 l = 4;
2047 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002048 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002049 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002050 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002051 l = 2;
2052 } else {
bellard1c213d12005-09-03 10:49:04 +00002053 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002054 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002055 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002056 l = 1;
2057 }
2058 } else {
bellardb448f2f2004-02-25 23:24:04 +00002059 unsigned long addr1;
2060 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002061 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002062 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002063 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002064 if (!cpu_physical_memory_is_dirty(addr1)) {
2065 /* invalidate code */
2066 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2067 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002068 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2069 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002070 }
bellard13eb76e2004-01-24 15:23:36 +00002071 }
2072 } else {
bellard2a4188a2006-06-25 21:54:59 +00002073 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2074 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002075 /* I/O case */
2076 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2077 if (l >= 4 && ((addr & 3) == 0)) {
2078 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002079 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002080 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002081 l = 4;
2082 } else if (l >= 2 && ((addr & 1) == 0)) {
2083 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002084 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002085 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002086 l = 2;
2087 } else {
bellard1c213d12005-09-03 10:49:04 +00002088 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002089 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002090 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002091 l = 1;
2092 }
2093 } else {
2094 /* RAM case */
2095 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2096 (addr & ~TARGET_PAGE_MASK);
2097 memcpy(buf, ptr, l);
2098 }
2099 }
2100 len -= l;
2101 buf += l;
2102 addr += l;
2103 }
2104}
bellard8df1cd02005-01-28 22:37:22 +00002105
bellardd0ecd2a2006-04-23 17:14:48 +00002106/* used for ROM loading : can write in RAM and ROM */
2107void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2108 const uint8_t *buf, int len)
2109{
2110 int l;
2111 uint8_t *ptr;
2112 target_phys_addr_t page;
2113 unsigned long pd;
2114 PhysPageDesc *p;
2115
2116 while (len > 0) {
2117 page = addr & TARGET_PAGE_MASK;
2118 l = (page + TARGET_PAGE_SIZE) - addr;
2119 if (l > len)
2120 l = len;
2121 p = phys_page_find(page >> TARGET_PAGE_BITS);
2122 if (!p) {
2123 pd = IO_MEM_UNASSIGNED;
2124 } else {
2125 pd = p->phys_offset;
2126 }
2127
2128 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002129 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2130 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002131 /* do nothing */
2132 } else {
2133 unsigned long addr1;
2134 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2135 /* ROM/RAM case */
2136 ptr = phys_ram_base + addr1;
2137 memcpy(ptr, buf, l);
2138 }
2139 len -= l;
2140 buf += l;
2141 addr += l;
2142 }
2143}
2144
2145
bellard8df1cd02005-01-28 22:37:22 +00002146/* warning: addr must be aligned */
2147uint32_t ldl_phys(target_phys_addr_t addr)
2148{
2149 int io_index;
2150 uint8_t *ptr;
2151 uint32_t val;
2152 unsigned long pd;
2153 PhysPageDesc *p;
2154
2155 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2156 if (!p) {
2157 pd = IO_MEM_UNASSIGNED;
2158 } else {
2159 pd = p->phys_offset;
2160 }
2161
bellard2a4188a2006-06-25 21:54:59 +00002162 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2163 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002164 /* I/O case */
2165 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2166 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2167 } else {
2168 /* RAM case */
2169 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2170 (addr & ~TARGET_PAGE_MASK);
2171 val = ldl_p(ptr);
2172 }
2173 return val;
2174}
2175
bellard84b7b8e2005-11-28 21:19:04 +00002176/* warning: addr must be aligned */
2177uint64_t ldq_phys(target_phys_addr_t addr)
2178{
2179 int io_index;
2180 uint8_t *ptr;
2181 uint64_t val;
2182 unsigned long pd;
2183 PhysPageDesc *p;
2184
2185 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2186 if (!p) {
2187 pd = IO_MEM_UNASSIGNED;
2188 } else {
2189 pd = p->phys_offset;
2190 }
2191
bellard2a4188a2006-06-25 21:54:59 +00002192 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2193 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002194 /* I/O case */
2195 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2196#ifdef TARGET_WORDS_BIGENDIAN
2197 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2198 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2199#else
2200 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2201 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2202#endif
2203 } else {
2204 /* RAM case */
2205 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2206 (addr & ~TARGET_PAGE_MASK);
2207 val = ldq_p(ptr);
2208 }
2209 return val;
2210}
2211
bellardaab33092005-10-30 20:48:42 +00002212/* XXX: optimize */
2213uint32_t ldub_phys(target_phys_addr_t addr)
2214{
2215 uint8_t val;
2216 cpu_physical_memory_read(addr, &val, 1);
2217 return val;
2218}
2219
2220/* XXX: optimize */
2221uint32_t lduw_phys(target_phys_addr_t addr)
2222{
2223 uint16_t val;
2224 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2225 return tswap16(val);
2226}
2227
bellard8df1cd02005-01-28 22:37:22 +00002228/* warning: addr must be aligned. The ram page is not masked as dirty
2229 and the code inside is not invalidated. It is useful if the dirty
2230 bits are used to track modified PTEs */
2231void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2232{
2233 int io_index;
2234 uint8_t *ptr;
2235 unsigned long pd;
2236 PhysPageDesc *p;
2237
2238 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2239 if (!p) {
2240 pd = IO_MEM_UNASSIGNED;
2241 } else {
2242 pd = p->phys_offset;
2243 }
2244
bellard3a7d9292005-08-21 09:26:42 +00002245 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002246 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2247 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2248 } else {
2249 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2250 (addr & ~TARGET_PAGE_MASK);
2251 stl_p(ptr, val);
2252 }
2253}
2254
2255/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002256void stl_phys(target_phys_addr_t addr, uint32_t val)
2257{
2258 int io_index;
2259 uint8_t *ptr;
2260 unsigned long pd;
2261 PhysPageDesc *p;
2262
2263 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2264 if (!p) {
2265 pd = IO_MEM_UNASSIGNED;
2266 } else {
2267 pd = p->phys_offset;
2268 }
2269
bellard3a7d9292005-08-21 09:26:42 +00002270 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002271 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2272 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2273 } else {
2274 unsigned long addr1;
2275 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2276 /* RAM case */
2277 ptr = phys_ram_base + addr1;
2278 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002279 if (!cpu_physical_memory_is_dirty(addr1)) {
2280 /* invalidate code */
2281 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2282 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002283 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2284 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002285 }
bellard8df1cd02005-01-28 22:37:22 +00002286 }
2287}
2288
bellardaab33092005-10-30 20:48:42 +00002289/* XXX: optimize */
2290void stb_phys(target_phys_addr_t addr, uint32_t val)
2291{
2292 uint8_t v = val;
2293 cpu_physical_memory_write(addr, &v, 1);
2294}
2295
2296/* XXX: optimize */
2297void stw_phys(target_phys_addr_t addr, uint32_t val)
2298{
2299 uint16_t v = tswap16(val);
2300 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2301}
2302
2303/* XXX: optimize */
2304void stq_phys(target_phys_addr_t addr, uint64_t val)
2305{
2306 val = tswap64(val);
2307 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2308}
2309
bellard13eb76e2004-01-24 15:23:36 +00002310#endif
2311
2312/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002313int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2314 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002315{
2316 int l;
2317 target_ulong page, phys_addr;
2318
2319 while (len > 0) {
2320 page = addr & TARGET_PAGE_MASK;
2321 phys_addr = cpu_get_phys_page_debug(env, page);
2322 /* if no physical page mapped, return an error */
2323 if (phys_addr == -1)
2324 return -1;
2325 l = (page + TARGET_PAGE_SIZE) - addr;
2326 if (l > len)
2327 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002328 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2329 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002330 len -= l;
2331 buf += l;
2332 addr += l;
2333 }
2334 return 0;
2335}
2336
bellarde3db7222005-01-26 22:00:47 +00002337void dump_exec_info(FILE *f,
2338 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2339{
2340 int i, target_code_size, max_target_code_size;
2341 int direct_jmp_count, direct_jmp2_count, cross_page;
2342 TranslationBlock *tb;
2343
2344 target_code_size = 0;
2345 max_target_code_size = 0;
2346 cross_page = 0;
2347 direct_jmp_count = 0;
2348 direct_jmp2_count = 0;
2349 for(i = 0; i < nb_tbs; i++) {
2350 tb = &tbs[i];
2351 target_code_size += tb->size;
2352 if (tb->size > max_target_code_size)
2353 max_target_code_size = tb->size;
2354 if (tb->page_addr[1] != -1)
2355 cross_page++;
2356 if (tb->tb_next_offset[0] != 0xffff) {
2357 direct_jmp_count++;
2358 if (tb->tb_next_offset[1] != 0xffff) {
2359 direct_jmp2_count++;
2360 }
2361 }
2362 }
2363 /* XXX: avoid using doubles ? */
2364 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2365 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2366 nb_tbs ? target_code_size / nb_tbs : 0,
2367 max_target_code_size);
2368 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2369 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2370 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2371 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2372 cross_page,
2373 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2374 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2375 direct_jmp_count,
2376 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2377 direct_jmp2_count,
2378 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2379 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2380 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2381 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2382}
2383
bellard61382a52003-10-27 21:22:23 +00002384#if !defined(CONFIG_USER_ONLY)
2385
2386#define MMUSUFFIX _cmmu
2387#define GETPC() NULL
2388#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002389#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002390
2391#define SHIFT 0
2392#include "softmmu_template.h"
2393
2394#define SHIFT 1
2395#include "softmmu_template.h"
2396
2397#define SHIFT 2
2398#include "softmmu_template.h"
2399
2400#define SHIFT 3
2401#include "softmmu_template.h"
2402
2403#undef env
2404
2405#endif