blob: ae2d825da34f44036eec24378c2e114ab9964996 [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
pbrook53a59602006-03-25 19:31:22 +000037#if defined(CONFIG_USER_ONLY)
38#include <qemu.h>
39#endif
bellard54936002003-05-13 00:25:15 +000040
bellardfd6ce8f2003-05-14 19:00:11 +000041//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000042//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000043//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000044//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* make various TB consistency checks */
47//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000048//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000049
pbrook99773bd2006-04-16 15:14:59 +000050#if !defined(CONFIG_USER_ONLY)
51/* TB consistency checks only implemented for usermode emulation. */
52#undef DEBUG_TB_CHECK
53#endif
54
bellardfd6ce8f2003-05-14 19:00:11 +000055/* threshold to flush the translated code buffer */
56#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
57
bellard9fa3e852004-01-04 18:06:42 +000058#define SMC_BITMAP_USE_THRESHOLD 10
59
60#define MMAP_AREA_START 0x00000000
61#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000062
bellard108c49b2005-07-24 12:55:09 +000063#if defined(TARGET_SPARC64)
64#define TARGET_PHYS_ADDR_SPACE_BITS 41
65#elif defined(TARGET_PPC64)
66#define TARGET_PHYS_ADDR_SPACE_BITS 42
67#else
68/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
69#define TARGET_PHYS_ADDR_SPACE_BITS 32
70#endif
71
bellardfd6ce8f2003-05-14 19:00:11 +000072TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000073TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000074int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000075/* any access to the tbs or the page table must use this lock */
76spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000077
bellardb8076a72005-04-07 22:20:31 +000078uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000079uint8_t *code_gen_ptr;
80
bellard9fa3e852004-01-04 18:06:42 +000081int phys_ram_size;
82int phys_ram_fd;
83uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000084uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000085
bellard6a00d602005-11-21 23:25:50 +000086CPUState *first_cpu;
87/* current CPU in the current thread. It is only valid inside
88 cpu_exec() */
89CPUState *cpu_single_env;
90
bellard54936002003-05-13 00:25:15 +000091typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000092 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000093 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000094 /* in order to optimize self modifying code, we count the number
95 of lookups we do to a given page to use a bitmap */
96 unsigned int code_write_count;
97 uint8_t *code_bitmap;
98#if defined(CONFIG_USER_ONLY)
99 unsigned long flags;
100#endif
bellard54936002003-05-13 00:25:15 +0000101} PageDesc;
102
bellard92e873b2004-05-21 14:52:29 +0000103typedef struct PhysPageDesc {
104 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000105 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000106} PhysPageDesc;
107
bellard54936002003-05-13 00:25:15 +0000108#define L2_BITS 10
109#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
110
111#define L1_SIZE (1 << L1_BITS)
112#define L2_SIZE (1 << L2_BITS)
113
bellard33417e72003-08-10 21:47:01 +0000114static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000115
bellard83fb7ad2004-07-05 21:25:26 +0000116unsigned long qemu_real_host_page_size;
117unsigned long qemu_host_page_bits;
118unsigned long qemu_host_page_size;
119unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000120
bellard92e873b2004-05-21 14:52:29 +0000121/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000122static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000123PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000124
bellard33417e72003-08-10 21:47:01 +0000125/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000126CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
127CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000128void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000129static int io_mem_nb;
130
bellard34865132003-10-05 14:28:56 +0000131/* log support */
132char *logfilename = "/tmp/qemu.log";
133FILE *logfile;
134int loglevel;
135
bellarde3db7222005-01-26 22:00:47 +0000136/* statistics */
137static int tlb_flush_count;
138static int tb_flush_count;
139static int tb_phys_invalidate_count;
140
bellardb346ff42003-06-15 20:05:50 +0000141static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000142{
bellard83fb7ad2004-07-05 21:25:26 +0000143 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000144 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000145#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000146 {
147 SYSTEM_INFO system_info;
148 DWORD old_protect;
149
150 GetSystemInfo(&system_info);
151 qemu_real_host_page_size = system_info.dwPageSize;
152
153 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
154 PAGE_EXECUTE_READWRITE, &old_protect);
155 }
bellard67b915a2004-03-31 23:37:16 +0000156#else
bellard83fb7ad2004-07-05 21:25:26 +0000157 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000158 {
159 unsigned long start, end;
160
161 start = (unsigned long)code_gen_buffer;
162 start &= ~(qemu_real_host_page_size - 1);
163
164 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
165 end += qemu_real_host_page_size - 1;
166 end &= ~(qemu_real_host_page_size - 1);
167
168 mprotect((void *)start, end - start,
169 PROT_READ | PROT_WRITE | PROT_EXEC);
170 }
bellard67b915a2004-03-31 23:37:16 +0000171#endif
bellardd5a8f072004-09-29 21:15:28 +0000172
bellard83fb7ad2004-07-05 21:25:26 +0000173 if (qemu_host_page_size == 0)
174 qemu_host_page_size = qemu_real_host_page_size;
175 if (qemu_host_page_size < TARGET_PAGE_SIZE)
176 qemu_host_page_size = TARGET_PAGE_SIZE;
177 qemu_host_page_bits = 0;
178 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
179 qemu_host_page_bits++;
180 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000181 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
182 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000183}
184
bellardfd6ce8f2003-05-14 19:00:11 +0000185static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000186{
bellard54936002003-05-13 00:25:15 +0000187 PageDesc **lp, *p;
188
bellard54936002003-05-13 00:25:15 +0000189 lp = &l1_map[index >> L2_BITS];
190 p = *lp;
191 if (!p) {
192 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000193 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000194 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000195 *lp = p;
196 }
197 return p + (index & (L2_SIZE - 1));
198}
199
bellardfd6ce8f2003-05-14 19:00:11 +0000200static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000201{
bellard54936002003-05-13 00:25:15 +0000202 PageDesc *p;
203
bellard54936002003-05-13 00:25:15 +0000204 p = l1_map[index >> L2_BITS];
205 if (!p)
206 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000207 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000208}
209
bellard108c49b2005-07-24 12:55:09 +0000210static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000211{
bellard108c49b2005-07-24 12:55:09 +0000212 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000213 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000214
bellard108c49b2005-07-24 12:55:09 +0000215 p = (void **)l1_phys_map;
216#if TARGET_PHYS_ADDR_SPACE_BITS > 32
217
218#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
219#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
220#endif
221 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000222 p = *lp;
223 if (!p) {
224 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000225 if (!alloc)
226 return NULL;
227 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
228 memset(p, 0, sizeof(void *) * L1_SIZE);
229 *lp = p;
230 }
231#endif
232 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000233 pd = *lp;
234 if (!pd) {
235 int i;
bellard108c49b2005-07-24 12:55:09 +0000236 /* allocate if not found */
237 if (!alloc)
238 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000239 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
240 *lp = pd;
241 for (i = 0; i < L2_SIZE; i++)
242 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000243 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000244 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000245}
246
bellard108c49b2005-07-24 12:55:09 +0000247static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000248{
bellard108c49b2005-07-24 12:55:09 +0000249 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000250}
251
bellard9fa3e852004-01-04 18:06:42 +0000252#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000253static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000254static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
255 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000256#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000257
bellard6a00d602005-11-21 23:25:50 +0000258void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000259{
bellard6a00d602005-11-21 23:25:50 +0000260 CPUState **penv;
261 int cpu_index;
262
bellardfd6ce8f2003-05-14 19:00:11 +0000263 if (!code_gen_ptr) {
264 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000265 page_init();
bellard33417e72003-08-10 21:47:01 +0000266 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000267 }
bellard6a00d602005-11-21 23:25:50 +0000268 env->next_cpu = NULL;
269 penv = &first_cpu;
270 cpu_index = 0;
271 while (*penv != NULL) {
272 penv = (CPUState **)&(*penv)->next_cpu;
273 cpu_index++;
274 }
275 env->cpu_index = cpu_index;
276 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000277}
278
bellard9fa3e852004-01-04 18:06:42 +0000279static inline void invalidate_page_bitmap(PageDesc *p)
280{
281 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000282 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000283 p->code_bitmap = NULL;
284 }
285 p->code_write_count = 0;
286}
287
bellardfd6ce8f2003-05-14 19:00:11 +0000288/* set to NULL all the 'first_tb' fields in all PageDescs */
289static void page_flush_tb(void)
290{
291 int i, j;
292 PageDesc *p;
293
294 for(i = 0; i < L1_SIZE; i++) {
295 p = l1_map[i];
296 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000297 for(j = 0; j < L2_SIZE; j++) {
298 p->first_tb = NULL;
299 invalidate_page_bitmap(p);
300 p++;
301 }
bellardfd6ce8f2003-05-14 19:00:11 +0000302 }
303 }
304}
305
306/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000307/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000308void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000309{
bellard6a00d602005-11-21 23:25:50 +0000310 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000311#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000312 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
313 code_gen_ptr - code_gen_buffer,
314 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000315 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000316#endif
317 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000318
319 for(env = first_cpu; env != NULL; env = env->next_cpu) {
320 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
321 }
bellard9fa3e852004-01-04 18:06:42 +0000322
bellard8a8a6082004-10-03 13:36:49 +0000323 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000324 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000325
bellardfd6ce8f2003-05-14 19:00:11 +0000326 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000327 /* XXX: flush processor icache at this point if cache flush is
328 expensive */
bellarde3db7222005-01-26 22:00:47 +0000329 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000330}
331
332#ifdef DEBUG_TB_CHECK
333
334static void tb_invalidate_check(unsigned long address)
335{
336 TranslationBlock *tb;
337 int i;
338 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000339 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
340 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000341 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
342 address >= tb->pc + tb->size)) {
343 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000344 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000345 }
346 }
347 }
348}
349
350/* verify that all the pages have correct rights for code */
351static void tb_page_check(void)
352{
353 TranslationBlock *tb;
354 int i, flags1, flags2;
355
pbrook99773bd2006-04-16 15:14:59 +0000356 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
357 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000358 flags1 = page_get_flags(tb->pc);
359 flags2 = page_get_flags(tb->pc + tb->size - 1);
360 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
361 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000362 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000363 }
364 }
365 }
366}
367
bellardd4e81642003-05-25 16:46:15 +0000368void tb_jmp_check(TranslationBlock *tb)
369{
370 TranslationBlock *tb1;
371 unsigned int n1;
372
373 /* suppress any remaining jumps to this TB */
374 tb1 = tb->jmp_first;
375 for(;;) {
376 n1 = (long)tb1 & 3;
377 tb1 = (TranslationBlock *)((long)tb1 & ~3);
378 if (n1 == 2)
379 break;
380 tb1 = tb1->jmp_next[n1];
381 }
382 /* check end of list */
383 if (tb1 != tb) {
384 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
385 }
386}
387
bellardfd6ce8f2003-05-14 19:00:11 +0000388#endif
389
390/* invalidate one TB */
391static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
392 int next_offset)
393{
394 TranslationBlock *tb1;
395 for(;;) {
396 tb1 = *ptb;
397 if (tb1 == tb) {
398 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
399 break;
400 }
401 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
402 }
403}
404
bellard9fa3e852004-01-04 18:06:42 +0000405static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
406{
407 TranslationBlock *tb1;
408 unsigned int n1;
409
410 for(;;) {
411 tb1 = *ptb;
412 n1 = (long)tb1 & 3;
413 tb1 = (TranslationBlock *)((long)tb1 & ~3);
414 if (tb1 == tb) {
415 *ptb = tb1->page_next[n1];
416 break;
417 }
418 ptb = &tb1->page_next[n1];
419 }
420}
421
bellardd4e81642003-05-25 16:46:15 +0000422static inline void tb_jmp_remove(TranslationBlock *tb, int n)
423{
424 TranslationBlock *tb1, **ptb;
425 unsigned int n1;
426
427 ptb = &tb->jmp_next[n];
428 tb1 = *ptb;
429 if (tb1) {
430 /* find tb(n) in circular list */
431 for(;;) {
432 tb1 = *ptb;
433 n1 = (long)tb1 & 3;
434 tb1 = (TranslationBlock *)((long)tb1 & ~3);
435 if (n1 == n && tb1 == tb)
436 break;
437 if (n1 == 2) {
438 ptb = &tb1->jmp_first;
439 } else {
440 ptb = &tb1->jmp_next[n1];
441 }
442 }
443 /* now we can suppress tb(n) from the list */
444 *ptb = tb->jmp_next[n];
445
446 tb->jmp_next[n] = NULL;
447 }
448}
449
450/* reset the jump entry 'n' of a TB so that it is not chained to
451 another TB */
452static inline void tb_reset_jump(TranslationBlock *tb, int n)
453{
454 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
455}
456
bellard9fa3e852004-01-04 18:06:42 +0000457static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000458{
bellard6a00d602005-11-21 23:25:50 +0000459 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000460 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000461 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000462 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000463 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000464
465 /* remove the TB from the hash list */
466 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
467 h = tb_phys_hash_func(phys_pc);
468 tb_remove(&tb_phys_hash[h], tb,
469 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000470
bellard9fa3e852004-01-04 18:06:42 +0000471 /* remove the TB from the page list */
472 if (tb->page_addr[0] != page_addr) {
473 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
474 tb_page_remove(&p->first_tb, tb);
475 invalidate_page_bitmap(p);
476 }
477 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
478 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
479 tb_page_remove(&p->first_tb, tb);
480 invalidate_page_bitmap(p);
481 }
482
bellard8a40a182005-11-20 10:35:40 +0000483 tb_invalidated_flag = 1;
484
485 /* remove the TB from the hash list */
486 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000487 for(env = first_cpu; env != NULL; env = env->next_cpu) {
488 if (env->tb_jmp_cache[h] == tb)
489 env->tb_jmp_cache[h] = NULL;
490 }
bellard8a40a182005-11-20 10:35:40 +0000491
492 /* suppress this TB from the two jump lists */
493 tb_jmp_remove(tb, 0);
494 tb_jmp_remove(tb, 1);
495
496 /* suppress any remaining jumps to this TB */
497 tb1 = tb->jmp_first;
498 for(;;) {
499 n1 = (long)tb1 & 3;
500 if (n1 == 2)
501 break;
502 tb1 = (TranslationBlock *)((long)tb1 & ~3);
503 tb2 = tb1->jmp_next[n1];
504 tb_reset_jump(tb1, n1);
505 tb1->jmp_next[n1] = NULL;
506 tb1 = tb2;
507 }
508 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
509
bellarde3db7222005-01-26 22:00:47 +0000510 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000511}
512
513static inline void set_bits(uint8_t *tab, int start, int len)
514{
515 int end, mask, end1;
516
517 end = start + len;
518 tab += start >> 3;
519 mask = 0xff << (start & 7);
520 if ((start & ~7) == (end & ~7)) {
521 if (start < end) {
522 mask &= ~(0xff << (end & 7));
523 *tab |= mask;
524 }
525 } else {
526 *tab++ |= mask;
527 start = (start + 8) & ~7;
528 end1 = end & ~7;
529 while (start < end1) {
530 *tab++ = 0xff;
531 start += 8;
532 }
533 if (start < end) {
534 mask = ~(0xff << (end & 7));
535 *tab |= mask;
536 }
537 }
538}
539
540static void build_page_bitmap(PageDesc *p)
541{
542 int n, tb_start, tb_end;
543 TranslationBlock *tb;
544
bellard59817cc2004-02-16 22:01:13 +0000545 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000546 if (!p->code_bitmap)
547 return;
548 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
549
550 tb = p->first_tb;
551 while (tb != NULL) {
552 n = (long)tb & 3;
553 tb = (TranslationBlock *)((long)tb & ~3);
554 /* NOTE: this is subtle as a TB may span two physical pages */
555 if (n == 0) {
556 /* NOTE: tb_end may be after the end of the page, but
557 it is not a problem */
558 tb_start = tb->pc & ~TARGET_PAGE_MASK;
559 tb_end = tb_start + tb->size;
560 if (tb_end > TARGET_PAGE_SIZE)
561 tb_end = TARGET_PAGE_SIZE;
562 } else {
563 tb_start = 0;
564 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
565 }
566 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
567 tb = tb->page_next[n];
568 }
569}
570
bellardd720b932004-04-25 17:57:43 +0000571#ifdef TARGET_HAS_PRECISE_SMC
572
573static void tb_gen_code(CPUState *env,
574 target_ulong pc, target_ulong cs_base, int flags,
575 int cflags)
576{
577 TranslationBlock *tb;
578 uint8_t *tc_ptr;
579 target_ulong phys_pc, phys_page2, virt_page2;
580 int code_gen_size;
581
bellardc27004e2005-01-03 23:35:10 +0000582 phys_pc = get_phys_addr_code(env, pc);
583 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000584 if (!tb) {
585 /* flush must be done */
586 tb_flush(env);
587 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000588 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000589 }
590 tc_ptr = code_gen_ptr;
591 tb->tc_ptr = tc_ptr;
592 tb->cs_base = cs_base;
593 tb->flags = flags;
594 tb->cflags = cflags;
595 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
596 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
597
598 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000599 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000600 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000601 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000602 phys_page2 = get_phys_addr_code(env, virt_page2);
603 }
604 tb_link_phys(tb, phys_pc, phys_page2);
605}
606#endif
607
bellard9fa3e852004-01-04 18:06:42 +0000608/* invalidate all TBs which intersect with the target physical page
609 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000610 the same physical page. 'is_cpu_write_access' should be true if called
611 from a real cpu write access: the virtual CPU will exit the current
612 TB if code is modified inside this TB. */
613void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
614 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000615{
bellardd720b932004-04-25 17:57:43 +0000616 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000617 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000618 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000619 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000620 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000621 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000622
623 p = page_find(start >> TARGET_PAGE_BITS);
624 if (!p)
625 return;
626 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000627 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
628 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000629 /* build code bitmap */
630 build_page_bitmap(p);
631 }
632
633 /* we remove all the TBs in the range [start, end[ */
634 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000635 current_tb_not_found = is_cpu_write_access;
636 current_tb_modified = 0;
637 current_tb = NULL; /* avoid warning */
638 current_pc = 0; /* avoid warning */
639 current_cs_base = 0; /* avoid warning */
640 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000641 tb = p->first_tb;
642 while (tb != NULL) {
643 n = (long)tb & 3;
644 tb = (TranslationBlock *)((long)tb & ~3);
645 tb_next = tb->page_next[n];
646 /* NOTE: this is subtle as a TB may span two physical pages */
647 if (n == 0) {
648 /* NOTE: tb_end may be after the end of the page, but
649 it is not a problem */
650 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
651 tb_end = tb_start + tb->size;
652 } else {
653 tb_start = tb->page_addr[1];
654 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
655 }
656 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000657#ifdef TARGET_HAS_PRECISE_SMC
658 if (current_tb_not_found) {
659 current_tb_not_found = 0;
660 current_tb = NULL;
661 if (env->mem_write_pc) {
662 /* now we have a real cpu fault */
663 current_tb = tb_find_pc(env->mem_write_pc);
664 }
665 }
666 if (current_tb == tb &&
667 !(current_tb->cflags & CF_SINGLE_INSN)) {
668 /* If we are modifying the current TB, we must stop
669 its execution. We could be more precise by checking
670 that the modification is after the current PC, but it
671 would require a specialized function to partially
672 restore the CPU state */
673
674 current_tb_modified = 1;
675 cpu_restore_state(current_tb, env,
676 env->mem_write_pc, NULL);
677#if defined(TARGET_I386)
678 current_flags = env->hflags;
679 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
680 current_cs_base = (target_ulong)env->segs[R_CS].base;
681 current_pc = current_cs_base + env->eip;
682#else
683#error unsupported CPU
684#endif
685 }
686#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000687 /* we need to do that to handle the case where a signal
688 occurs while doing tb_phys_invalidate() */
689 saved_tb = NULL;
690 if (env) {
691 saved_tb = env->current_tb;
692 env->current_tb = NULL;
693 }
bellard9fa3e852004-01-04 18:06:42 +0000694 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000695 if (env) {
696 env->current_tb = saved_tb;
697 if (env->interrupt_request && env->current_tb)
698 cpu_interrupt(env, env->interrupt_request);
699 }
bellard9fa3e852004-01-04 18:06:42 +0000700 }
701 tb = tb_next;
702 }
703#if !defined(CONFIG_USER_ONLY)
704 /* if no code remaining, no need to continue to use slow writes */
705 if (!p->first_tb) {
706 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000707 if (is_cpu_write_access) {
708 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
709 }
710 }
711#endif
712#ifdef TARGET_HAS_PRECISE_SMC
713 if (current_tb_modified) {
714 /* we generate a block containing just the instruction
715 modifying the memory. It will ensure that it cannot modify
716 itself */
bellardea1c1802004-06-14 18:56:36 +0000717 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000718 tb_gen_code(env, current_pc, current_cs_base, current_flags,
719 CF_SINGLE_INSN);
720 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000721 }
722#endif
723}
724
725/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000726static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000727{
728 PageDesc *p;
729 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000730#if 0
bellarda4193c82004-06-03 14:01:43 +0000731 if (1) {
732 if (loglevel) {
733 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
734 cpu_single_env->mem_write_vaddr, len,
735 cpu_single_env->eip,
736 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
737 }
bellard59817cc2004-02-16 22:01:13 +0000738 }
739#endif
bellard9fa3e852004-01-04 18:06:42 +0000740 p = page_find(start >> TARGET_PAGE_BITS);
741 if (!p)
742 return;
743 if (p->code_bitmap) {
744 offset = start & ~TARGET_PAGE_MASK;
745 b = p->code_bitmap[offset >> 3] >> (offset & 7);
746 if (b & ((1 << len) - 1))
747 goto do_invalidate;
748 } else {
749 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000750 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000751 }
752}
753
bellard9fa3e852004-01-04 18:06:42 +0000754#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000755static void tb_invalidate_phys_page(target_ulong addr,
756 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000757{
bellardd720b932004-04-25 17:57:43 +0000758 int n, current_flags, current_tb_modified;
759 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000760 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000761 TranslationBlock *tb, *current_tb;
762#ifdef TARGET_HAS_PRECISE_SMC
763 CPUState *env = cpu_single_env;
764#endif
bellard9fa3e852004-01-04 18:06:42 +0000765
766 addr &= TARGET_PAGE_MASK;
767 p = page_find(addr >> TARGET_PAGE_BITS);
768 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000769 return;
770 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000771 current_tb_modified = 0;
772 current_tb = NULL;
773 current_pc = 0; /* avoid warning */
774 current_cs_base = 0; /* avoid warning */
775 current_flags = 0; /* avoid warning */
776#ifdef TARGET_HAS_PRECISE_SMC
777 if (tb && pc != 0) {
778 current_tb = tb_find_pc(pc);
779 }
780#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000781 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000782 n = (long)tb & 3;
783 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000784#ifdef TARGET_HAS_PRECISE_SMC
785 if (current_tb == tb &&
786 !(current_tb->cflags & CF_SINGLE_INSN)) {
787 /* If we are modifying the current TB, we must stop
788 its execution. We could be more precise by checking
789 that the modification is after the current PC, but it
790 would require a specialized function to partially
791 restore the CPU state */
792
793 current_tb_modified = 1;
794 cpu_restore_state(current_tb, env, pc, puc);
795#if defined(TARGET_I386)
796 current_flags = env->hflags;
797 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
798 current_cs_base = (target_ulong)env->segs[R_CS].base;
799 current_pc = current_cs_base + env->eip;
800#else
801#error unsupported CPU
802#endif
803 }
804#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000805 tb_phys_invalidate(tb, addr);
806 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000807 }
808 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000809#ifdef TARGET_HAS_PRECISE_SMC
810 if (current_tb_modified) {
811 /* we generate a block containing just the instruction
812 modifying the memory. It will ensure that it cannot modify
813 itself */
bellardea1c1802004-06-14 18:56:36 +0000814 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000815 tb_gen_code(env, current_pc, current_cs_base, current_flags,
816 CF_SINGLE_INSN);
817 cpu_resume_from_signal(env, puc);
818 }
819#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000820}
bellard9fa3e852004-01-04 18:06:42 +0000821#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000822
823/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000824static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000825 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000826{
827 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000828 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000829
bellard9fa3e852004-01-04 18:06:42 +0000830 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000831 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000832 tb->page_next[n] = p->first_tb;
833 last_first_tb = p->first_tb;
834 p->first_tb = (TranslationBlock *)((long)tb | n);
835 invalidate_page_bitmap(p);
836
bellard107db442004-06-22 18:48:46 +0000837#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000838
bellard9fa3e852004-01-04 18:06:42 +0000839#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000840 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000841 target_ulong addr;
842 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000843 int prot;
844
bellardfd6ce8f2003-05-14 19:00:11 +0000845 /* force the host page as non writable (writes will have a
846 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000847 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000848 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000849 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
850 addr += TARGET_PAGE_SIZE) {
851
852 p2 = page_find (addr >> TARGET_PAGE_BITS);
853 if (!p2)
854 continue;
855 prot |= p2->flags;
856 p2->flags &= ~PAGE_WRITE;
857 page_get_flags(addr);
858 }
859 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000860 (prot & PAGE_BITS) & ~PAGE_WRITE);
861#ifdef DEBUG_TB_INVALIDATE
862 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000863 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000864#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000865 }
bellard9fa3e852004-01-04 18:06:42 +0000866#else
867 /* if some code is already present, then the pages are already
868 protected. So we handle the case where only the first TB is
869 allocated in a physical page */
870 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000871 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000872 }
873#endif
bellardd720b932004-04-25 17:57:43 +0000874
875#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000876}
877
878/* Allocate a new translation block. Flush the translation buffer if
879 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000880TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000881{
882 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000883
884 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
885 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000886 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000887 tb = &tbs[nb_tbs++];
888 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000889 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000890 return tb;
891}
892
bellard9fa3e852004-01-04 18:06:42 +0000893/* add a new TB and link it to the physical page tables. phys_page2 is
894 (-1) to indicate that only one page contains the TB. */
895void tb_link_phys(TranslationBlock *tb,
896 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000897{
bellard9fa3e852004-01-04 18:06:42 +0000898 unsigned int h;
899 TranslationBlock **ptb;
900
901 /* add in the physical hash table */
902 h = tb_phys_hash_func(phys_pc);
903 ptb = &tb_phys_hash[h];
904 tb->phys_hash_next = *ptb;
905 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000906
907 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000908 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
909 if (phys_page2 != -1)
910 tb_alloc_page(tb, 1, phys_page2);
911 else
912 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000913
bellardd4e81642003-05-25 16:46:15 +0000914 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
915 tb->jmp_next[0] = NULL;
916 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000917#ifdef USE_CODE_COPY
918 tb->cflags &= ~CF_FP_USED;
919 if (tb->cflags & CF_TB_FP_USED)
920 tb->cflags |= CF_FP_USED;
921#endif
bellardd4e81642003-05-25 16:46:15 +0000922
923 /* init original jump addresses */
924 if (tb->tb_next_offset[0] != 0xffff)
925 tb_reset_jump(tb, 0);
926 if (tb->tb_next_offset[1] != 0xffff)
927 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000928
929#ifdef DEBUG_TB_CHECK
930 tb_page_check();
931#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000932}
933
bellarda513fe12003-05-27 23:29:48 +0000934/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
935 tb[1].tc_ptr. Return NULL if not found */
936TranslationBlock *tb_find_pc(unsigned long tc_ptr)
937{
938 int m_min, m_max, m;
939 unsigned long v;
940 TranslationBlock *tb;
941
942 if (nb_tbs <= 0)
943 return NULL;
944 if (tc_ptr < (unsigned long)code_gen_buffer ||
945 tc_ptr >= (unsigned long)code_gen_ptr)
946 return NULL;
947 /* binary search (cf Knuth) */
948 m_min = 0;
949 m_max = nb_tbs - 1;
950 while (m_min <= m_max) {
951 m = (m_min + m_max) >> 1;
952 tb = &tbs[m];
953 v = (unsigned long)tb->tc_ptr;
954 if (v == tc_ptr)
955 return tb;
956 else if (tc_ptr < v) {
957 m_max = m - 1;
958 } else {
959 m_min = m + 1;
960 }
961 }
962 return &tbs[m_max];
963}
bellard75012672003-06-21 13:11:07 +0000964
bellardea041c02003-06-25 16:16:50 +0000965static void tb_reset_jump_recursive(TranslationBlock *tb);
966
967static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
968{
969 TranslationBlock *tb1, *tb_next, **ptb;
970 unsigned int n1;
971
972 tb1 = tb->jmp_next[n];
973 if (tb1 != NULL) {
974 /* find head of list */
975 for(;;) {
976 n1 = (long)tb1 & 3;
977 tb1 = (TranslationBlock *)((long)tb1 & ~3);
978 if (n1 == 2)
979 break;
980 tb1 = tb1->jmp_next[n1];
981 }
982 /* we are now sure now that tb jumps to tb1 */
983 tb_next = tb1;
984
985 /* remove tb from the jmp_first list */
986 ptb = &tb_next->jmp_first;
987 for(;;) {
988 tb1 = *ptb;
989 n1 = (long)tb1 & 3;
990 tb1 = (TranslationBlock *)((long)tb1 & ~3);
991 if (n1 == n && tb1 == tb)
992 break;
993 ptb = &tb1->jmp_next[n1];
994 }
995 *ptb = tb->jmp_next[n];
996 tb->jmp_next[n] = NULL;
997
998 /* suppress the jump to next tb in generated code */
999 tb_reset_jump(tb, n);
1000
bellard01243112004-01-04 15:48:17 +00001001 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001002 tb_reset_jump_recursive(tb_next);
1003 }
1004}
1005
1006static void tb_reset_jump_recursive(TranslationBlock *tb)
1007{
1008 tb_reset_jump_recursive2(tb, 0);
1009 tb_reset_jump_recursive2(tb, 1);
1010}
1011
bellard1fddef42005-04-17 19:16:13 +00001012#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001013static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1014{
pbrookc2f07f82006-04-08 17:14:56 +00001015 target_ulong addr, pd;
1016 ram_addr_t ram_addr;
1017 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001018
pbrookc2f07f82006-04-08 17:14:56 +00001019 addr = cpu_get_phys_page_debug(env, pc);
1020 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1021 if (!p) {
1022 pd = IO_MEM_UNASSIGNED;
1023 } else {
1024 pd = p->phys_offset;
1025 }
1026 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001027 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001028}
bellardc27004e2005-01-03 23:35:10 +00001029#endif
bellardd720b932004-04-25 17:57:43 +00001030
bellardc33a3462003-07-29 20:50:33 +00001031/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1032 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001033int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001034{
bellard1fddef42005-04-17 19:16:13 +00001035#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001036 int i;
bellardd720b932004-04-25 17:57:43 +00001037
bellard4c3a88a2003-07-26 12:06:08 +00001038 for(i = 0; i < env->nb_breakpoints; i++) {
1039 if (env->breakpoints[i] == pc)
1040 return 0;
1041 }
1042
1043 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1044 return -1;
1045 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001046
1047 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001048 return 0;
1049#else
1050 return -1;
1051#endif
1052}
1053
1054/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001055int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001056{
bellard1fddef42005-04-17 19:16:13 +00001057#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001058 int i;
1059 for(i = 0; i < env->nb_breakpoints; i++) {
1060 if (env->breakpoints[i] == pc)
1061 goto found;
1062 }
1063 return -1;
1064 found:
bellard4c3a88a2003-07-26 12:06:08 +00001065 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001066 if (i < env->nb_breakpoints)
1067 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001068
1069 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001070 return 0;
1071#else
1072 return -1;
1073#endif
1074}
1075
bellardc33a3462003-07-29 20:50:33 +00001076/* enable or disable single step mode. EXCP_DEBUG is returned by the
1077 CPU loop after each instruction */
1078void cpu_single_step(CPUState *env, int enabled)
1079{
bellard1fddef42005-04-17 19:16:13 +00001080#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001081 if (env->singlestep_enabled != enabled) {
1082 env->singlestep_enabled = enabled;
1083 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001084 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001085 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001086 }
1087#endif
1088}
1089
bellard34865132003-10-05 14:28:56 +00001090/* enable or disable low levels log */
1091void cpu_set_log(int log_flags)
1092{
1093 loglevel = log_flags;
1094 if (loglevel && !logfile) {
1095 logfile = fopen(logfilename, "w");
1096 if (!logfile) {
1097 perror(logfilename);
1098 _exit(1);
1099 }
bellard9fa3e852004-01-04 18:06:42 +00001100#if !defined(CONFIG_SOFTMMU)
1101 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1102 {
1103 static uint8_t logfile_buf[4096];
1104 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1105 }
1106#else
bellard34865132003-10-05 14:28:56 +00001107 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001108#endif
bellard34865132003-10-05 14:28:56 +00001109 }
1110}
1111
1112void cpu_set_log_filename(const char *filename)
1113{
1114 logfilename = strdup(filename);
1115}
bellardc33a3462003-07-29 20:50:33 +00001116
bellard01243112004-01-04 15:48:17 +00001117/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001118void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001119{
1120 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001121 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001122
bellard68a79312003-06-30 13:12:32 +00001123 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001124 /* if the cpu is currently executing code, we must unlink it and
1125 all the potentially executing TB */
1126 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001127 if (tb && !testandset(&interrupt_lock)) {
1128 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001129 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001130 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001131 }
1132}
1133
bellardb54ad042004-05-20 13:42:52 +00001134void cpu_reset_interrupt(CPUState *env, int mask)
1135{
1136 env->interrupt_request &= ~mask;
1137}
1138
bellardf193c792004-03-21 17:06:25 +00001139CPULogItem cpu_log_items[] = {
1140 { CPU_LOG_TB_OUT_ASM, "out_asm",
1141 "show generated host assembly code for each compiled TB" },
1142 { CPU_LOG_TB_IN_ASM, "in_asm",
1143 "show target assembly code for each compiled TB" },
1144 { CPU_LOG_TB_OP, "op",
1145 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1146#ifdef TARGET_I386
1147 { CPU_LOG_TB_OP_OPT, "op_opt",
1148 "show micro ops after optimization for each compiled TB" },
1149#endif
1150 { CPU_LOG_INT, "int",
1151 "show interrupts/exceptions in short format" },
1152 { CPU_LOG_EXEC, "exec",
1153 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001154 { CPU_LOG_TB_CPU, "cpu",
1155 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001156#ifdef TARGET_I386
1157 { CPU_LOG_PCALL, "pcall",
1158 "show protected mode far calls/returns/exceptions" },
1159#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001160#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001161 { CPU_LOG_IOPORT, "ioport",
1162 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001163#endif
bellardf193c792004-03-21 17:06:25 +00001164 { 0, NULL, NULL },
1165};
1166
1167static int cmp1(const char *s1, int n, const char *s2)
1168{
1169 if (strlen(s2) != n)
1170 return 0;
1171 return memcmp(s1, s2, n) == 0;
1172}
1173
1174/* takes a comma separated list of log masks. Return 0 if error. */
1175int cpu_str_to_log_mask(const char *str)
1176{
1177 CPULogItem *item;
1178 int mask;
1179 const char *p, *p1;
1180
1181 p = str;
1182 mask = 0;
1183 for(;;) {
1184 p1 = strchr(p, ',');
1185 if (!p1)
1186 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001187 if(cmp1(p,p1-p,"all")) {
1188 for(item = cpu_log_items; item->mask != 0; item++) {
1189 mask |= item->mask;
1190 }
1191 } else {
bellardf193c792004-03-21 17:06:25 +00001192 for(item = cpu_log_items; item->mask != 0; item++) {
1193 if (cmp1(p, p1 - p, item->name))
1194 goto found;
1195 }
1196 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001197 }
bellardf193c792004-03-21 17:06:25 +00001198 found:
1199 mask |= item->mask;
1200 if (*p1 != ',')
1201 break;
1202 p = p1 + 1;
1203 }
1204 return mask;
1205}
bellardea041c02003-06-25 16:16:50 +00001206
bellard75012672003-06-21 13:11:07 +00001207void cpu_abort(CPUState *env, const char *fmt, ...)
1208{
1209 va_list ap;
1210
1211 va_start(ap, fmt);
1212 fprintf(stderr, "qemu: fatal: ");
1213 vfprintf(stderr, fmt, ap);
1214 fprintf(stderr, "\n");
1215#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001216 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1217#else
1218 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001219#endif
1220 va_end(ap);
1221 abort();
1222}
1223
bellard01243112004-01-04 15:48:17 +00001224#if !defined(CONFIG_USER_ONLY)
1225
bellardee8b7022004-02-03 23:35:10 +00001226/* NOTE: if flush_global is true, also flush global entries (not
1227 implemented yet) */
1228void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001229{
bellard33417e72003-08-10 21:47:01 +00001230 int i;
bellard01243112004-01-04 15:48:17 +00001231
bellard9fa3e852004-01-04 18:06:42 +00001232#if defined(DEBUG_TLB)
1233 printf("tlb_flush:\n");
1234#endif
bellard01243112004-01-04 15:48:17 +00001235 /* must reset current TB so that interrupts cannot modify the
1236 links while we are modifying them */
1237 env->current_tb = NULL;
1238
bellard33417e72003-08-10 21:47:01 +00001239 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001240 env->tlb_table[0][i].addr_read = -1;
1241 env->tlb_table[0][i].addr_write = -1;
1242 env->tlb_table[0][i].addr_code = -1;
1243 env->tlb_table[1][i].addr_read = -1;
1244 env->tlb_table[1][i].addr_write = -1;
1245 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001246 }
bellard9fa3e852004-01-04 18:06:42 +00001247
bellard8a40a182005-11-20 10:35:40 +00001248 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001249
1250#if !defined(CONFIG_SOFTMMU)
1251 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1252#endif
bellard0a962c02005-02-10 22:00:27 +00001253#ifdef USE_KQEMU
1254 if (env->kqemu_enabled) {
1255 kqemu_flush(env, flush_global);
1256 }
1257#endif
bellarde3db7222005-01-26 22:00:47 +00001258 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001259}
1260
bellard274da6b2004-05-20 21:56:27 +00001261static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001262{
bellard84b7b8e2005-11-28 21:19:04 +00001263 if (addr == (tlb_entry->addr_read &
1264 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1265 addr == (tlb_entry->addr_write &
1266 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1267 addr == (tlb_entry->addr_code &
1268 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1269 tlb_entry->addr_read = -1;
1270 tlb_entry->addr_write = -1;
1271 tlb_entry->addr_code = -1;
1272 }
bellard61382a52003-10-27 21:22:23 +00001273}
1274
bellard2e126692004-04-25 21:28:44 +00001275void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001276{
bellard8a40a182005-11-20 10:35:40 +00001277 int i;
bellard9fa3e852004-01-04 18:06:42 +00001278 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001279
bellard9fa3e852004-01-04 18:06:42 +00001280#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001281 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001282#endif
bellard01243112004-01-04 15:48:17 +00001283 /* must reset current TB so that interrupts cannot modify the
1284 links while we are modifying them */
1285 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001286
bellard61382a52003-10-27 21:22:23 +00001287 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001288 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001289 tlb_flush_entry(&env->tlb_table[0][i], addr);
1290 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001291
pbrookb362e5e2006-11-12 20:40:55 +00001292 /* Discard jump cache entries for any tb which might potentially
1293 overlap the flushed page. */
1294 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1295 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1296
1297 i = tb_jmp_cache_hash_page(addr);
1298 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001299
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{
pbrook67d3b952006-12-18 05:03:52 +00001817#ifdef DEBUG_UNASSIGNED
1818 printf("Unassigned mem read 0x%08x\n", (int)addr);
1819#endif
bellard33417e72003-08-10 21:47:01 +00001820 return 0;
1821}
1822
bellarda4193c82004-06-03 14:01:43 +00001823static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001824{
pbrook67d3b952006-12-18 05:03:52 +00001825#ifdef DEBUG_UNASSIGNED
1826 printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
1827#endif
bellard33417e72003-08-10 21:47:01 +00001828}
1829
1830static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1831 unassigned_mem_readb,
1832 unassigned_mem_readb,
1833 unassigned_mem_readb,
1834};
1835
1836static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1837 unassigned_mem_writeb,
1838 unassigned_mem_writeb,
1839 unassigned_mem_writeb,
1840};
1841
bellarda4193c82004-06-03 14:01:43 +00001842static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001843{
bellard3a7d9292005-08-21 09:26:42 +00001844 unsigned long ram_addr;
1845 int dirty_flags;
1846 ram_addr = addr - (unsigned long)phys_ram_base;
1847 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1848 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1849#if !defined(CONFIG_USER_ONLY)
1850 tb_invalidate_phys_page_fast(ram_addr, 1);
1851 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1852#endif
1853 }
bellardc27004e2005-01-03 23:35:10 +00001854 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001855#ifdef USE_KQEMU
1856 if (cpu_single_env->kqemu_enabled &&
1857 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1858 kqemu_modify_page(cpu_single_env, ram_addr);
1859#endif
bellardf23db162005-08-21 19:12:28 +00001860 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1861 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1862 /* we remove the notdirty callback only if the code has been
1863 flushed */
1864 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001865 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001866}
1867
bellarda4193c82004-06-03 14:01:43 +00001868static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001869{
bellard3a7d9292005-08-21 09:26:42 +00001870 unsigned long ram_addr;
1871 int dirty_flags;
1872 ram_addr = addr - (unsigned long)phys_ram_base;
1873 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1874 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1875#if !defined(CONFIG_USER_ONLY)
1876 tb_invalidate_phys_page_fast(ram_addr, 2);
1877 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1878#endif
1879 }
bellardc27004e2005-01-03 23:35:10 +00001880 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001881#ifdef USE_KQEMU
1882 if (cpu_single_env->kqemu_enabled &&
1883 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1884 kqemu_modify_page(cpu_single_env, ram_addr);
1885#endif
bellardf23db162005-08-21 19:12:28 +00001886 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1887 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1888 /* we remove the notdirty callback only if the code has been
1889 flushed */
1890 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001891 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001892}
1893
bellarda4193c82004-06-03 14:01:43 +00001894static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001895{
bellard3a7d9292005-08-21 09:26:42 +00001896 unsigned long ram_addr;
1897 int dirty_flags;
1898 ram_addr = addr - (unsigned long)phys_ram_base;
1899 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1900 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1901#if !defined(CONFIG_USER_ONLY)
1902 tb_invalidate_phys_page_fast(ram_addr, 4);
1903 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1904#endif
1905 }
bellardc27004e2005-01-03 23:35:10 +00001906 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001907#ifdef USE_KQEMU
1908 if (cpu_single_env->kqemu_enabled &&
1909 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1910 kqemu_modify_page(cpu_single_env, ram_addr);
1911#endif
bellardf23db162005-08-21 19:12:28 +00001912 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1913 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1914 /* we remove the notdirty callback only if the code has been
1915 flushed */
1916 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001917 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001918}
1919
bellard3a7d9292005-08-21 09:26:42 +00001920static CPUReadMemoryFunc *error_mem_read[3] = {
1921 NULL, /* never used */
1922 NULL, /* never used */
1923 NULL, /* never used */
1924};
1925
bellard1ccde1c2004-02-06 19:46:14 +00001926static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1927 notdirty_mem_writeb,
1928 notdirty_mem_writew,
1929 notdirty_mem_writel,
1930};
1931
bellard33417e72003-08-10 21:47:01 +00001932static void io_mem_init(void)
1933{
bellard3a7d9292005-08-21 09:26:42 +00001934 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001935 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001936 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001937 io_mem_nb = 5;
1938
1939 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001940 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001941 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001942}
1943
1944/* mem_read and mem_write are arrays of functions containing the
1945 function to access byte (index 0), word (index 1) and dword (index
1946 2). All functions must be supplied. If io_index is non zero, the
1947 corresponding io zone is modified. If it is zero, a new io zone is
1948 allocated. The return value can be used with
1949 cpu_register_physical_memory(). (-1) is returned if error. */
1950int cpu_register_io_memory(int io_index,
1951 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001952 CPUWriteMemoryFunc **mem_write,
1953 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001954{
1955 int i;
1956
1957 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00001958 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00001959 return -1;
1960 io_index = io_mem_nb++;
1961 } else {
1962 if (io_index >= IO_MEM_NB_ENTRIES)
1963 return -1;
1964 }
bellardb5ff1b32005-11-26 10:38:39 +00001965
bellard33417e72003-08-10 21:47:01 +00001966 for(i = 0;i < 3; i++) {
1967 io_mem_read[io_index][i] = mem_read[i];
1968 io_mem_write[io_index][i] = mem_write[i];
1969 }
bellarda4193c82004-06-03 14:01:43 +00001970 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001971 return io_index << IO_MEM_SHIFT;
1972}
bellard61382a52003-10-27 21:22:23 +00001973
bellard8926b512004-10-10 15:14:20 +00001974CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1975{
1976 return io_mem_write[io_index >> IO_MEM_SHIFT];
1977}
1978
1979CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
1980{
1981 return io_mem_read[io_index >> IO_MEM_SHIFT];
1982}
1983
bellard13eb76e2004-01-24 15:23:36 +00001984/* physical memory access (slow version, mainly for debug) */
1985#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001986void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001987 int len, int is_write)
1988{
1989 int l, flags;
1990 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00001991 void * p;
bellard13eb76e2004-01-24 15:23:36 +00001992
1993 while (len > 0) {
1994 page = addr & TARGET_PAGE_MASK;
1995 l = (page + TARGET_PAGE_SIZE) - addr;
1996 if (l > len)
1997 l = len;
1998 flags = page_get_flags(page);
1999 if (!(flags & PAGE_VALID))
2000 return;
2001 if (is_write) {
2002 if (!(flags & PAGE_WRITE))
2003 return;
pbrook53a59602006-03-25 19:31:22 +00002004 p = lock_user(addr, len, 0);
2005 memcpy(p, buf, len);
2006 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002007 } else {
2008 if (!(flags & PAGE_READ))
2009 return;
pbrook53a59602006-03-25 19:31:22 +00002010 p = lock_user(addr, len, 1);
2011 memcpy(buf, p, len);
2012 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002013 }
2014 len -= l;
2015 buf += l;
2016 addr += l;
2017 }
2018}
bellard8df1cd02005-01-28 22:37:22 +00002019
bellard13eb76e2004-01-24 15:23:36 +00002020#else
bellard2e126692004-04-25 21:28:44 +00002021void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002022 int len, int is_write)
2023{
2024 int l, io_index;
2025 uint8_t *ptr;
2026 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002027 target_phys_addr_t page;
2028 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002029 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002030
2031 while (len > 0) {
2032 page = addr & TARGET_PAGE_MASK;
2033 l = (page + TARGET_PAGE_SIZE) - addr;
2034 if (l > len)
2035 l = len;
bellard92e873b2004-05-21 14:52:29 +00002036 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002037 if (!p) {
2038 pd = IO_MEM_UNASSIGNED;
2039 } else {
2040 pd = p->phys_offset;
2041 }
2042
2043 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002044 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002045 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002046 /* XXX: could force cpu_single_env to NULL to avoid
2047 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002048 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002049 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002050 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002051 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002052 l = 4;
2053 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002054 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002055 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002056 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002057 l = 2;
2058 } else {
bellard1c213d12005-09-03 10:49:04 +00002059 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002060 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002061 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002062 l = 1;
2063 }
2064 } else {
bellardb448f2f2004-02-25 23:24:04 +00002065 unsigned long addr1;
2066 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002067 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002068 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002069 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002070 if (!cpu_physical_memory_is_dirty(addr1)) {
2071 /* invalidate code */
2072 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2073 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002074 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2075 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002076 }
bellard13eb76e2004-01-24 15:23:36 +00002077 }
2078 } else {
bellard2a4188a2006-06-25 21:54:59 +00002079 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2080 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002081 /* I/O case */
2082 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2083 if (l >= 4 && ((addr & 3) == 0)) {
2084 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002085 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002086 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002087 l = 4;
2088 } else if (l >= 2 && ((addr & 1) == 0)) {
2089 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002090 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002091 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002092 l = 2;
2093 } else {
bellard1c213d12005-09-03 10:49:04 +00002094 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002095 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002096 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002097 l = 1;
2098 }
2099 } else {
2100 /* RAM case */
2101 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2102 (addr & ~TARGET_PAGE_MASK);
2103 memcpy(buf, ptr, l);
2104 }
2105 }
2106 len -= l;
2107 buf += l;
2108 addr += l;
2109 }
2110}
bellard8df1cd02005-01-28 22:37:22 +00002111
bellardd0ecd2a2006-04-23 17:14:48 +00002112/* used for ROM loading : can write in RAM and ROM */
2113void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2114 const uint8_t *buf, int len)
2115{
2116 int l;
2117 uint8_t *ptr;
2118 target_phys_addr_t page;
2119 unsigned long pd;
2120 PhysPageDesc *p;
2121
2122 while (len > 0) {
2123 page = addr & TARGET_PAGE_MASK;
2124 l = (page + TARGET_PAGE_SIZE) - addr;
2125 if (l > len)
2126 l = len;
2127 p = phys_page_find(page >> TARGET_PAGE_BITS);
2128 if (!p) {
2129 pd = IO_MEM_UNASSIGNED;
2130 } else {
2131 pd = p->phys_offset;
2132 }
2133
2134 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002135 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2136 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002137 /* do nothing */
2138 } else {
2139 unsigned long addr1;
2140 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2141 /* ROM/RAM case */
2142 ptr = phys_ram_base + addr1;
2143 memcpy(ptr, buf, l);
2144 }
2145 len -= l;
2146 buf += l;
2147 addr += l;
2148 }
2149}
2150
2151
bellard8df1cd02005-01-28 22:37:22 +00002152/* warning: addr must be aligned */
2153uint32_t ldl_phys(target_phys_addr_t addr)
2154{
2155 int io_index;
2156 uint8_t *ptr;
2157 uint32_t val;
2158 unsigned long pd;
2159 PhysPageDesc *p;
2160
2161 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2162 if (!p) {
2163 pd = IO_MEM_UNASSIGNED;
2164 } else {
2165 pd = p->phys_offset;
2166 }
2167
bellard2a4188a2006-06-25 21:54:59 +00002168 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2169 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002170 /* I/O case */
2171 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2172 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2173 } else {
2174 /* RAM case */
2175 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2176 (addr & ~TARGET_PAGE_MASK);
2177 val = ldl_p(ptr);
2178 }
2179 return val;
2180}
2181
bellard84b7b8e2005-11-28 21:19:04 +00002182/* warning: addr must be aligned */
2183uint64_t ldq_phys(target_phys_addr_t addr)
2184{
2185 int io_index;
2186 uint8_t *ptr;
2187 uint64_t val;
2188 unsigned long pd;
2189 PhysPageDesc *p;
2190
2191 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2192 if (!p) {
2193 pd = IO_MEM_UNASSIGNED;
2194 } else {
2195 pd = p->phys_offset;
2196 }
2197
bellard2a4188a2006-06-25 21:54:59 +00002198 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2199 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002200 /* I/O case */
2201 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2202#ifdef TARGET_WORDS_BIGENDIAN
2203 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2204 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2205#else
2206 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2207 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2208#endif
2209 } else {
2210 /* RAM case */
2211 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2212 (addr & ~TARGET_PAGE_MASK);
2213 val = ldq_p(ptr);
2214 }
2215 return val;
2216}
2217
bellardaab33092005-10-30 20:48:42 +00002218/* XXX: optimize */
2219uint32_t ldub_phys(target_phys_addr_t addr)
2220{
2221 uint8_t val;
2222 cpu_physical_memory_read(addr, &val, 1);
2223 return val;
2224}
2225
2226/* XXX: optimize */
2227uint32_t lduw_phys(target_phys_addr_t addr)
2228{
2229 uint16_t val;
2230 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2231 return tswap16(val);
2232}
2233
bellard8df1cd02005-01-28 22:37:22 +00002234/* warning: addr must be aligned. The ram page is not masked as dirty
2235 and the code inside is not invalidated. It is useful if the dirty
2236 bits are used to track modified PTEs */
2237void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2238{
2239 int io_index;
2240 uint8_t *ptr;
2241 unsigned long pd;
2242 PhysPageDesc *p;
2243
2244 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2245 if (!p) {
2246 pd = IO_MEM_UNASSIGNED;
2247 } else {
2248 pd = p->phys_offset;
2249 }
2250
bellard3a7d9292005-08-21 09:26:42 +00002251 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002252 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2253 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2254 } else {
2255 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2256 (addr & ~TARGET_PAGE_MASK);
2257 stl_p(ptr, val);
2258 }
2259}
2260
2261/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002262void stl_phys(target_phys_addr_t addr, uint32_t val)
2263{
2264 int io_index;
2265 uint8_t *ptr;
2266 unsigned long pd;
2267 PhysPageDesc *p;
2268
2269 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2270 if (!p) {
2271 pd = IO_MEM_UNASSIGNED;
2272 } else {
2273 pd = p->phys_offset;
2274 }
2275
bellard3a7d9292005-08-21 09:26:42 +00002276 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002277 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2278 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2279 } else {
2280 unsigned long addr1;
2281 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2282 /* RAM case */
2283 ptr = phys_ram_base + addr1;
2284 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002285 if (!cpu_physical_memory_is_dirty(addr1)) {
2286 /* invalidate code */
2287 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2288 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002289 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2290 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002291 }
bellard8df1cd02005-01-28 22:37:22 +00002292 }
2293}
2294
bellardaab33092005-10-30 20:48:42 +00002295/* XXX: optimize */
2296void stb_phys(target_phys_addr_t addr, uint32_t val)
2297{
2298 uint8_t v = val;
2299 cpu_physical_memory_write(addr, &v, 1);
2300}
2301
2302/* XXX: optimize */
2303void stw_phys(target_phys_addr_t addr, uint32_t val)
2304{
2305 uint16_t v = tswap16(val);
2306 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2307}
2308
2309/* XXX: optimize */
2310void stq_phys(target_phys_addr_t addr, uint64_t val)
2311{
2312 val = tswap64(val);
2313 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2314}
2315
bellard13eb76e2004-01-24 15:23:36 +00002316#endif
2317
2318/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002319int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2320 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002321{
2322 int l;
2323 target_ulong page, phys_addr;
2324
2325 while (len > 0) {
2326 page = addr & TARGET_PAGE_MASK;
2327 phys_addr = cpu_get_phys_page_debug(env, page);
2328 /* if no physical page mapped, return an error */
2329 if (phys_addr == -1)
2330 return -1;
2331 l = (page + TARGET_PAGE_SIZE) - addr;
2332 if (l > len)
2333 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002334 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2335 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002336 len -= l;
2337 buf += l;
2338 addr += l;
2339 }
2340 return 0;
2341}
2342
bellarde3db7222005-01-26 22:00:47 +00002343void dump_exec_info(FILE *f,
2344 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2345{
2346 int i, target_code_size, max_target_code_size;
2347 int direct_jmp_count, direct_jmp2_count, cross_page;
2348 TranslationBlock *tb;
2349
2350 target_code_size = 0;
2351 max_target_code_size = 0;
2352 cross_page = 0;
2353 direct_jmp_count = 0;
2354 direct_jmp2_count = 0;
2355 for(i = 0; i < nb_tbs; i++) {
2356 tb = &tbs[i];
2357 target_code_size += tb->size;
2358 if (tb->size > max_target_code_size)
2359 max_target_code_size = tb->size;
2360 if (tb->page_addr[1] != -1)
2361 cross_page++;
2362 if (tb->tb_next_offset[0] != 0xffff) {
2363 direct_jmp_count++;
2364 if (tb->tb_next_offset[1] != 0xffff) {
2365 direct_jmp2_count++;
2366 }
2367 }
2368 }
2369 /* XXX: avoid using doubles ? */
2370 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2371 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2372 nb_tbs ? target_code_size / nb_tbs : 0,
2373 max_target_code_size);
2374 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2375 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2376 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2377 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2378 cross_page,
2379 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2380 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2381 direct_jmp_count,
2382 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2383 direct_jmp2_count,
2384 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2385 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2386 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2387 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2388}
2389
bellard61382a52003-10-27 21:22:23 +00002390#if !defined(CONFIG_USER_ONLY)
2391
2392#define MMUSUFFIX _cmmu
2393#define GETPC() NULL
2394#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002395#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002396
2397#define SHIFT 0
2398#include "softmmu_template.h"
2399
2400#define SHIFT 1
2401#include "softmmu_template.h"
2402
2403#define SHIFT 2
2404#include "softmmu_template.h"
2405
2406#define SHIFT 3
2407#include "softmmu_template.h"
2408
2409#undef env
2410
2411#endif