blob: 6deaf49279ad347a0454a9f379b92d269e04dea0 [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;
bellarde9a1ab12007-02-08 23:08:38 +000085static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000086
bellard6a00d602005-11-21 23:25:50 +000087CPUState *first_cpu;
88/* current CPU in the current thread. It is only valid inside
89 cpu_exec() */
90CPUState *cpu_single_env;
91
bellard54936002003-05-13 00:25:15 +000092typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000093 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000094 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000095 /* in order to optimize self modifying code, we count the number
96 of lookups we do to a given page to use a bitmap */
97 unsigned int code_write_count;
98 uint8_t *code_bitmap;
99#if defined(CONFIG_USER_ONLY)
100 unsigned long flags;
101#endif
bellard54936002003-05-13 00:25:15 +0000102} PageDesc;
103
bellard92e873b2004-05-21 14:52:29 +0000104typedef struct PhysPageDesc {
105 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000106 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000107} PhysPageDesc;
108
bellard54936002003-05-13 00:25:15 +0000109#define L2_BITS 10
110#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
111
112#define L1_SIZE (1 << L1_BITS)
113#define L2_SIZE (1 << L2_BITS)
114
bellard33417e72003-08-10 21:47:01 +0000115static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000116
bellard83fb7ad2004-07-05 21:25:26 +0000117unsigned long qemu_real_host_page_size;
118unsigned long qemu_host_page_bits;
119unsigned long qemu_host_page_size;
120unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000121
bellard92e873b2004-05-21 14:52:29 +0000122/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000123static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000124PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000125
bellard33417e72003-08-10 21:47:01 +0000126/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000127CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
128CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000129void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000130static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000131#if defined(CONFIG_SOFTMMU)
132static int io_mem_watch;
133#endif
bellard33417e72003-08-10 21:47:01 +0000134
bellard34865132003-10-05 14:28:56 +0000135/* log support */
136char *logfilename = "/tmp/qemu.log";
137FILE *logfile;
138int loglevel;
139
bellarde3db7222005-01-26 22:00:47 +0000140/* statistics */
141static int tlb_flush_count;
142static int tb_flush_count;
143static int tb_phys_invalidate_count;
144
bellardb346ff42003-06-15 20:05:50 +0000145static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000146{
bellard83fb7ad2004-07-05 21:25:26 +0000147 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000148 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000149#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000150 {
151 SYSTEM_INFO system_info;
152 DWORD old_protect;
153
154 GetSystemInfo(&system_info);
155 qemu_real_host_page_size = system_info.dwPageSize;
156
157 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
158 PAGE_EXECUTE_READWRITE, &old_protect);
159 }
bellard67b915a2004-03-31 23:37:16 +0000160#else
bellard83fb7ad2004-07-05 21:25:26 +0000161 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000162 {
163 unsigned long start, end;
164
165 start = (unsigned long)code_gen_buffer;
166 start &= ~(qemu_real_host_page_size - 1);
167
168 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
169 end += qemu_real_host_page_size - 1;
170 end &= ~(qemu_real_host_page_size - 1);
171
172 mprotect((void *)start, end - start,
173 PROT_READ | PROT_WRITE | PROT_EXEC);
174 }
bellard67b915a2004-03-31 23:37:16 +0000175#endif
bellardd5a8f072004-09-29 21:15:28 +0000176
bellard83fb7ad2004-07-05 21:25:26 +0000177 if (qemu_host_page_size == 0)
178 qemu_host_page_size = qemu_real_host_page_size;
179 if (qemu_host_page_size < TARGET_PAGE_SIZE)
180 qemu_host_page_size = TARGET_PAGE_SIZE;
181 qemu_host_page_bits = 0;
182 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
183 qemu_host_page_bits++;
184 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000185 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
186 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000187}
188
bellardfd6ce8f2003-05-14 19:00:11 +0000189static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000190{
bellard54936002003-05-13 00:25:15 +0000191 PageDesc **lp, *p;
192
bellard54936002003-05-13 00:25:15 +0000193 lp = &l1_map[index >> L2_BITS];
194 p = *lp;
195 if (!p) {
196 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000197 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000198 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000199 *lp = p;
200 }
201 return p + (index & (L2_SIZE - 1));
202}
203
bellardfd6ce8f2003-05-14 19:00:11 +0000204static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000205{
bellard54936002003-05-13 00:25:15 +0000206 PageDesc *p;
207
bellard54936002003-05-13 00:25:15 +0000208 p = l1_map[index >> L2_BITS];
209 if (!p)
210 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000211 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000212}
213
bellard108c49b2005-07-24 12:55:09 +0000214static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000215{
bellard108c49b2005-07-24 12:55:09 +0000216 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000217 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000218
bellard108c49b2005-07-24 12:55:09 +0000219 p = (void **)l1_phys_map;
220#if TARGET_PHYS_ADDR_SPACE_BITS > 32
221
222#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
223#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
224#endif
225 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000226 p = *lp;
227 if (!p) {
228 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000229 if (!alloc)
230 return NULL;
231 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
232 memset(p, 0, sizeof(void *) * L1_SIZE);
233 *lp = p;
234 }
235#endif
236 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000237 pd = *lp;
238 if (!pd) {
239 int i;
bellard108c49b2005-07-24 12:55:09 +0000240 /* allocate if not found */
241 if (!alloc)
242 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000243 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
244 *lp = pd;
245 for (i = 0; i < L2_SIZE; i++)
246 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000247 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000248 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000249}
250
bellard108c49b2005-07-24 12:55:09 +0000251static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000252{
bellard108c49b2005-07-24 12:55:09 +0000253 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000254}
255
bellard9fa3e852004-01-04 18:06:42 +0000256#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000257static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000258static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
259 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000260#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000261
bellard6a00d602005-11-21 23:25:50 +0000262void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000263{
bellard6a00d602005-11-21 23:25:50 +0000264 CPUState **penv;
265 int cpu_index;
266
bellardfd6ce8f2003-05-14 19:00:11 +0000267 if (!code_gen_ptr) {
268 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000269 page_init();
bellard33417e72003-08-10 21:47:01 +0000270 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000271 }
bellard6a00d602005-11-21 23:25:50 +0000272 env->next_cpu = NULL;
273 penv = &first_cpu;
274 cpu_index = 0;
275 while (*penv != NULL) {
276 penv = (CPUState **)&(*penv)->next_cpu;
277 cpu_index++;
278 }
279 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000280 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000281 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000282}
283
bellard9fa3e852004-01-04 18:06:42 +0000284static inline void invalidate_page_bitmap(PageDesc *p)
285{
286 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000287 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000288 p->code_bitmap = NULL;
289 }
290 p->code_write_count = 0;
291}
292
bellardfd6ce8f2003-05-14 19:00:11 +0000293/* set to NULL all the 'first_tb' fields in all PageDescs */
294static void page_flush_tb(void)
295{
296 int i, j;
297 PageDesc *p;
298
299 for(i = 0; i < L1_SIZE; i++) {
300 p = l1_map[i];
301 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000302 for(j = 0; j < L2_SIZE; j++) {
303 p->first_tb = NULL;
304 invalidate_page_bitmap(p);
305 p++;
306 }
bellardfd6ce8f2003-05-14 19:00:11 +0000307 }
308 }
309}
310
311/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000312/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000313void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000314{
bellard6a00d602005-11-21 23:25:50 +0000315 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000316#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000317 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
318 code_gen_ptr - code_gen_buffer,
319 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000320 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000321#endif
322 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000323
324 for(env = first_cpu; env != NULL; env = env->next_cpu) {
325 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
326 }
bellard9fa3e852004-01-04 18:06:42 +0000327
bellard8a8a6082004-10-03 13:36:49 +0000328 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000329 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000330
bellardfd6ce8f2003-05-14 19:00:11 +0000331 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000332 /* XXX: flush processor icache at this point if cache flush is
333 expensive */
bellarde3db7222005-01-26 22:00:47 +0000334 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000335}
336
337#ifdef DEBUG_TB_CHECK
338
339static void tb_invalidate_check(unsigned long address)
340{
341 TranslationBlock *tb;
342 int i;
343 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000344 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
345 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000346 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
347 address >= tb->pc + tb->size)) {
348 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000349 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000350 }
351 }
352 }
353}
354
355/* verify that all the pages have correct rights for code */
356static void tb_page_check(void)
357{
358 TranslationBlock *tb;
359 int i, flags1, flags2;
360
pbrook99773bd2006-04-16 15:14:59 +0000361 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
362 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000363 flags1 = page_get_flags(tb->pc);
364 flags2 = page_get_flags(tb->pc + tb->size - 1);
365 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
366 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000367 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000368 }
369 }
370 }
371}
372
bellardd4e81642003-05-25 16:46:15 +0000373void tb_jmp_check(TranslationBlock *tb)
374{
375 TranslationBlock *tb1;
376 unsigned int n1;
377
378 /* suppress any remaining jumps to this TB */
379 tb1 = tb->jmp_first;
380 for(;;) {
381 n1 = (long)tb1 & 3;
382 tb1 = (TranslationBlock *)((long)tb1 & ~3);
383 if (n1 == 2)
384 break;
385 tb1 = tb1->jmp_next[n1];
386 }
387 /* check end of list */
388 if (tb1 != tb) {
389 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
390 }
391}
392
bellardfd6ce8f2003-05-14 19:00:11 +0000393#endif
394
395/* invalidate one TB */
396static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
397 int next_offset)
398{
399 TranslationBlock *tb1;
400 for(;;) {
401 tb1 = *ptb;
402 if (tb1 == tb) {
403 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
404 break;
405 }
406 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
407 }
408}
409
bellard9fa3e852004-01-04 18:06:42 +0000410static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
411{
412 TranslationBlock *tb1;
413 unsigned int n1;
414
415 for(;;) {
416 tb1 = *ptb;
417 n1 = (long)tb1 & 3;
418 tb1 = (TranslationBlock *)((long)tb1 & ~3);
419 if (tb1 == tb) {
420 *ptb = tb1->page_next[n1];
421 break;
422 }
423 ptb = &tb1->page_next[n1];
424 }
425}
426
bellardd4e81642003-05-25 16:46:15 +0000427static inline void tb_jmp_remove(TranslationBlock *tb, int n)
428{
429 TranslationBlock *tb1, **ptb;
430 unsigned int n1;
431
432 ptb = &tb->jmp_next[n];
433 tb1 = *ptb;
434 if (tb1) {
435 /* find tb(n) in circular list */
436 for(;;) {
437 tb1 = *ptb;
438 n1 = (long)tb1 & 3;
439 tb1 = (TranslationBlock *)((long)tb1 & ~3);
440 if (n1 == n && tb1 == tb)
441 break;
442 if (n1 == 2) {
443 ptb = &tb1->jmp_first;
444 } else {
445 ptb = &tb1->jmp_next[n1];
446 }
447 }
448 /* now we can suppress tb(n) from the list */
449 *ptb = tb->jmp_next[n];
450
451 tb->jmp_next[n] = NULL;
452 }
453}
454
455/* reset the jump entry 'n' of a TB so that it is not chained to
456 another TB */
457static inline void tb_reset_jump(TranslationBlock *tb, int n)
458{
459 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
460}
461
bellard9fa3e852004-01-04 18:06:42 +0000462static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000463{
bellard6a00d602005-11-21 23:25:50 +0000464 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000465 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000466 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000467 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000468 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000469
470 /* remove the TB from the hash list */
471 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
472 h = tb_phys_hash_func(phys_pc);
473 tb_remove(&tb_phys_hash[h], tb,
474 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000475
bellard9fa3e852004-01-04 18:06:42 +0000476 /* remove the TB from the page list */
477 if (tb->page_addr[0] != page_addr) {
478 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
479 tb_page_remove(&p->first_tb, tb);
480 invalidate_page_bitmap(p);
481 }
482 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
483 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
484 tb_page_remove(&p->first_tb, tb);
485 invalidate_page_bitmap(p);
486 }
487
bellard8a40a182005-11-20 10:35:40 +0000488 tb_invalidated_flag = 1;
489
490 /* remove the TB from the hash list */
491 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000492 for(env = first_cpu; env != NULL; env = env->next_cpu) {
493 if (env->tb_jmp_cache[h] == tb)
494 env->tb_jmp_cache[h] = NULL;
495 }
bellard8a40a182005-11-20 10:35:40 +0000496
497 /* suppress this TB from the two jump lists */
498 tb_jmp_remove(tb, 0);
499 tb_jmp_remove(tb, 1);
500
501 /* suppress any remaining jumps to this TB */
502 tb1 = tb->jmp_first;
503 for(;;) {
504 n1 = (long)tb1 & 3;
505 if (n1 == 2)
506 break;
507 tb1 = (TranslationBlock *)((long)tb1 & ~3);
508 tb2 = tb1->jmp_next[n1];
509 tb_reset_jump(tb1, n1);
510 tb1->jmp_next[n1] = NULL;
511 tb1 = tb2;
512 }
513 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
514
bellarde3db7222005-01-26 22:00:47 +0000515 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000516}
517
518static inline void set_bits(uint8_t *tab, int start, int len)
519{
520 int end, mask, end1;
521
522 end = start + len;
523 tab += start >> 3;
524 mask = 0xff << (start & 7);
525 if ((start & ~7) == (end & ~7)) {
526 if (start < end) {
527 mask &= ~(0xff << (end & 7));
528 *tab |= mask;
529 }
530 } else {
531 *tab++ |= mask;
532 start = (start + 8) & ~7;
533 end1 = end & ~7;
534 while (start < end1) {
535 *tab++ = 0xff;
536 start += 8;
537 }
538 if (start < end) {
539 mask = ~(0xff << (end & 7));
540 *tab |= mask;
541 }
542 }
543}
544
545static void build_page_bitmap(PageDesc *p)
546{
547 int n, tb_start, tb_end;
548 TranslationBlock *tb;
549
bellard59817cc2004-02-16 22:01:13 +0000550 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000551 if (!p->code_bitmap)
552 return;
553 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
554
555 tb = p->first_tb;
556 while (tb != NULL) {
557 n = (long)tb & 3;
558 tb = (TranslationBlock *)((long)tb & ~3);
559 /* NOTE: this is subtle as a TB may span two physical pages */
560 if (n == 0) {
561 /* NOTE: tb_end may be after the end of the page, but
562 it is not a problem */
563 tb_start = tb->pc & ~TARGET_PAGE_MASK;
564 tb_end = tb_start + tb->size;
565 if (tb_end > TARGET_PAGE_SIZE)
566 tb_end = TARGET_PAGE_SIZE;
567 } else {
568 tb_start = 0;
569 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
570 }
571 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
572 tb = tb->page_next[n];
573 }
574}
575
bellardd720b932004-04-25 17:57:43 +0000576#ifdef TARGET_HAS_PRECISE_SMC
577
578static void tb_gen_code(CPUState *env,
579 target_ulong pc, target_ulong cs_base, int flags,
580 int cflags)
581{
582 TranslationBlock *tb;
583 uint8_t *tc_ptr;
584 target_ulong phys_pc, phys_page2, virt_page2;
585 int code_gen_size;
586
bellardc27004e2005-01-03 23:35:10 +0000587 phys_pc = get_phys_addr_code(env, pc);
588 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000589 if (!tb) {
590 /* flush must be done */
591 tb_flush(env);
592 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000593 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000594 }
595 tc_ptr = code_gen_ptr;
596 tb->tc_ptr = tc_ptr;
597 tb->cs_base = cs_base;
598 tb->flags = flags;
599 tb->cflags = cflags;
600 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
601 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
602
603 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000604 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000605 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000606 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000607 phys_page2 = get_phys_addr_code(env, virt_page2);
608 }
609 tb_link_phys(tb, phys_pc, phys_page2);
610}
611#endif
612
bellard9fa3e852004-01-04 18:06:42 +0000613/* invalidate all TBs which intersect with the target physical page
614 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000615 the same physical page. 'is_cpu_write_access' should be true if called
616 from a real cpu write access: the virtual CPU will exit the current
617 TB if code is modified inside this TB. */
618void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
619 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000620{
bellardd720b932004-04-25 17:57:43 +0000621 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000622 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000623 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000624 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000625 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000626 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000627
628 p = page_find(start >> TARGET_PAGE_BITS);
629 if (!p)
630 return;
631 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000632 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
633 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000634 /* build code bitmap */
635 build_page_bitmap(p);
636 }
637
638 /* we remove all the TBs in the range [start, end[ */
639 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000640 current_tb_not_found = is_cpu_write_access;
641 current_tb_modified = 0;
642 current_tb = NULL; /* avoid warning */
643 current_pc = 0; /* avoid warning */
644 current_cs_base = 0; /* avoid warning */
645 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000646 tb = p->first_tb;
647 while (tb != NULL) {
648 n = (long)tb & 3;
649 tb = (TranslationBlock *)((long)tb & ~3);
650 tb_next = tb->page_next[n];
651 /* NOTE: this is subtle as a TB may span two physical pages */
652 if (n == 0) {
653 /* NOTE: tb_end may be after the end of the page, but
654 it is not a problem */
655 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
656 tb_end = tb_start + tb->size;
657 } else {
658 tb_start = tb->page_addr[1];
659 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
660 }
661 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000662#ifdef TARGET_HAS_PRECISE_SMC
663 if (current_tb_not_found) {
664 current_tb_not_found = 0;
665 current_tb = NULL;
666 if (env->mem_write_pc) {
667 /* now we have a real cpu fault */
668 current_tb = tb_find_pc(env->mem_write_pc);
669 }
670 }
671 if (current_tb == tb &&
672 !(current_tb->cflags & CF_SINGLE_INSN)) {
673 /* If we are modifying the current TB, we must stop
674 its execution. We could be more precise by checking
675 that the modification is after the current PC, but it
676 would require a specialized function to partially
677 restore the CPU state */
678
679 current_tb_modified = 1;
680 cpu_restore_state(current_tb, env,
681 env->mem_write_pc, NULL);
682#if defined(TARGET_I386)
683 current_flags = env->hflags;
684 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
685 current_cs_base = (target_ulong)env->segs[R_CS].base;
686 current_pc = current_cs_base + env->eip;
687#else
688#error unsupported CPU
689#endif
690 }
691#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000692 /* we need to do that to handle the case where a signal
693 occurs while doing tb_phys_invalidate() */
694 saved_tb = NULL;
695 if (env) {
696 saved_tb = env->current_tb;
697 env->current_tb = NULL;
698 }
bellard9fa3e852004-01-04 18:06:42 +0000699 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000700 if (env) {
701 env->current_tb = saved_tb;
702 if (env->interrupt_request && env->current_tb)
703 cpu_interrupt(env, env->interrupt_request);
704 }
bellard9fa3e852004-01-04 18:06:42 +0000705 }
706 tb = tb_next;
707 }
708#if !defined(CONFIG_USER_ONLY)
709 /* if no code remaining, no need to continue to use slow writes */
710 if (!p->first_tb) {
711 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000712 if (is_cpu_write_access) {
713 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
714 }
715 }
716#endif
717#ifdef TARGET_HAS_PRECISE_SMC
718 if (current_tb_modified) {
719 /* we generate a block containing just the instruction
720 modifying the memory. It will ensure that it cannot modify
721 itself */
bellardea1c1802004-06-14 18:56:36 +0000722 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000723 tb_gen_code(env, current_pc, current_cs_base, current_flags,
724 CF_SINGLE_INSN);
725 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000726 }
727#endif
728}
729
730/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000731static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000732{
733 PageDesc *p;
734 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000735#if 0
bellarda4193c82004-06-03 14:01:43 +0000736 if (1) {
737 if (loglevel) {
738 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
739 cpu_single_env->mem_write_vaddr, len,
740 cpu_single_env->eip,
741 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
742 }
bellard59817cc2004-02-16 22:01:13 +0000743 }
744#endif
bellard9fa3e852004-01-04 18:06:42 +0000745 p = page_find(start >> TARGET_PAGE_BITS);
746 if (!p)
747 return;
748 if (p->code_bitmap) {
749 offset = start & ~TARGET_PAGE_MASK;
750 b = p->code_bitmap[offset >> 3] >> (offset & 7);
751 if (b & ((1 << len) - 1))
752 goto do_invalidate;
753 } else {
754 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000755 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000756 }
757}
758
bellard9fa3e852004-01-04 18:06:42 +0000759#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000760static void tb_invalidate_phys_page(target_ulong addr,
761 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000762{
bellardd720b932004-04-25 17:57:43 +0000763 int n, current_flags, current_tb_modified;
764 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000765 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000766 TranslationBlock *tb, *current_tb;
767#ifdef TARGET_HAS_PRECISE_SMC
768 CPUState *env = cpu_single_env;
769#endif
bellard9fa3e852004-01-04 18:06:42 +0000770
771 addr &= TARGET_PAGE_MASK;
772 p = page_find(addr >> TARGET_PAGE_BITS);
773 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000774 return;
775 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000776 current_tb_modified = 0;
777 current_tb = NULL;
778 current_pc = 0; /* avoid warning */
779 current_cs_base = 0; /* avoid warning */
780 current_flags = 0; /* avoid warning */
781#ifdef TARGET_HAS_PRECISE_SMC
782 if (tb && pc != 0) {
783 current_tb = tb_find_pc(pc);
784 }
785#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000786 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000787 n = (long)tb & 3;
788 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000789#ifdef TARGET_HAS_PRECISE_SMC
790 if (current_tb == tb &&
791 !(current_tb->cflags & CF_SINGLE_INSN)) {
792 /* If we are modifying the current TB, we must stop
793 its execution. We could be more precise by checking
794 that the modification is after the current PC, but it
795 would require a specialized function to partially
796 restore the CPU state */
797
798 current_tb_modified = 1;
799 cpu_restore_state(current_tb, env, pc, puc);
800#if defined(TARGET_I386)
801 current_flags = env->hflags;
802 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
803 current_cs_base = (target_ulong)env->segs[R_CS].base;
804 current_pc = current_cs_base + env->eip;
805#else
806#error unsupported CPU
807#endif
808 }
809#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000810 tb_phys_invalidate(tb, addr);
811 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000812 }
813 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000814#ifdef TARGET_HAS_PRECISE_SMC
815 if (current_tb_modified) {
816 /* we generate a block containing just the instruction
817 modifying the memory. It will ensure that it cannot modify
818 itself */
bellardea1c1802004-06-14 18:56:36 +0000819 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000820 tb_gen_code(env, current_pc, current_cs_base, current_flags,
821 CF_SINGLE_INSN);
822 cpu_resume_from_signal(env, puc);
823 }
824#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000825}
bellard9fa3e852004-01-04 18:06:42 +0000826#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000827
828/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000829static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000830 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000831{
832 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000833 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000834
bellard9fa3e852004-01-04 18:06:42 +0000835 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000836 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000837 tb->page_next[n] = p->first_tb;
838 last_first_tb = p->first_tb;
839 p->first_tb = (TranslationBlock *)((long)tb | n);
840 invalidate_page_bitmap(p);
841
bellard107db442004-06-22 18:48:46 +0000842#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000843
bellard9fa3e852004-01-04 18:06:42 +0000844#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000845 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000846 target_ulong addr;
847 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000848 int prot;
849
bellardfd6ce8f2003-05-14 19:00:11 +0000850 /* force the host page as non writable (writes will have a
851 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000852 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000853 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000854 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
855 addr += TARGET_PAGE_SIZE) {
856
857 p2 = page_find (addr >> TARGET_PAGE_BITS);
858 if (!p2)
859 continue;
860 prot |= p2->flags;
861 p2->flags &= ~PAGE_WRITE;
862 page_get_flags(addr);
863 }
864 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000865 (prot & PAGE_BITS) & ~PAGE_WRITE);
866#ifdef DEBUG_TB_INVALIDATE
867 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000868 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000869#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000870 }
bellard9fa3e852004-01-04 18:06:42 +0000871#else
872 /* if some code is already present, then the pages are already
873 protected. So we handle the case where only the first TB is
874 allocated in a physical page */
875 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000876 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000877 }
878#endif
bellardd720b932004-04-25 17:57:43 +0000879
880#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000881}
882
883/* Allocate a new translation block. Flush the translation buffer if
884 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000885TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000886{
887 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000888
889 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
890 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000891 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000892 tb = &tbs[nb_tbs++];
893 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000894 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000895 return tb;
896}
897
bellard9fa3e852004-01-04 18:06:42 +0000898/* add a new TB and link it to the physical page tables. phys_page2 is
899 (-1) to indicate that only one page contains the TB. */
900void tb_link_phys(TranslationBlock *tb,
901 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000902{
bellard9fa3e852004-01-04 18:06:42 +0000903 unsigned int h;
904 TranslationBlock **ptb;
905
906 /* add in the physical hash table */
907 h = tb_phys_hash_func(phys_pc);
908 ptb = &tb_phys_hash[h];
909 tb->phys_hash_next = *ptb;
910 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000911
912 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000913 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
914 if (phys_page2 != -1)
915 tb_alloc_page(tb, 1, phys_page2);
916 else
917 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000918
bellardd4e81642003-05-25 16:46:15 +0000919 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
920 tb->jmp_next[0] = NULL;
921 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000922#ifdef USE_CODE_COPY
923 tb->cflags &= ~CF_FP_USED;
924 if (tb->cflags & CF_TB_FP_USED)
925 tb->cflags |= CF_FP_USED;
926#endif
bellardd4e81642003-05-25 16:46:15 +0000927
928 /* init original jump addresses */
929 if (tb->tb_next_offset[0] != 0xffff)
930 tb_reset_jump(tb, 0);
931 if (tb->tb_next_offset[1] != 0xffff)
932 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000933
934#ifdef DEBUG_TB_CHECK
935 tb_page_check();
936#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000937}
938
bellarda513fe12003-05-27 23:29:48 +0000939/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
940 tb[1].tc_ptr. Return NULL if not found */
941TranslationBlock *tb_find_pc(unsigned long tc_ptr)
942{
943 int m_min, m_max, m;
944 unsigned long v;
945 TranslationBlock *tb;
946
947 if (nb_tbs <= 0)
948 return NULL;
949 if (tc_ptr < (unsigned long)code_gen_buffer ||
950 tc_ptr >= (unsigned long)code_gen_ptr)
951 return NULL;
952 /* binary search (cf Knuth) */
953 m_min = 0;
954 m_max = nb_tbs - 1;
955 while (m_min <= m_max) {
956 m = (m_min + m_max) >> 1;
957 tb = &tbs[m];
958 v = (unsigned long)tb->tc_ptr;
959 if (v == tc_ptr)
960 return tb;
961 else if (tc_ptr < v) {
962 m_max = m - 1;
963 } else {
964 m_min = m + 1;
965 }
966 }
967 return &tbs[m_max];
968}
bellard75012672003-06-21 13:11:07 +0000969
bellardea041c02003-06-25 16:16:50 +0000970static void tb_reset_jump_recursive(TranslationBlock *tb);
971
972static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
973{
974 TranslationBlock *tb1, *tb_next, **ptb;
975 unsigned int n1;
976
977 tb1 = tb->jmp_next[n];
978 if (tb1 != NULL) {
979 /* find head of list */
980 for(;;) {
981 n1 = (long)tb1 & 3;
982 tb1 = (TranslationBlock *)((long)tb1 & ~3);
983 if (n1 == 2)
984 break;
985 tb1 = tb1->jmp_next[n1];
986 }
987 /* we are now sure now that tb jumps to tb1 */
988 tb_next = tb1;
989
990 /* remove tb from the jmp_first list */
991 ptb = &tb_next->jmp_first;
992 for(;;) {
993 tb1 = *ptb;
994 n1 = (long)tb1 & 3;
995 tb1 = (TranslationBlock *)((long)tb1 & ~3);
996 if (n1 == n && tb1 == tb)
997 break;
998 ptb = &tb1->jmp_next[n1];
999 }
1000 *ptb = tb->jmp_next[n];
1001 tb->jmp_next[n] = NULL;
1002
1003 /* suppress the jump to next tb in generated code */
1004 tb_reset_jump(tb, n);
1005
bellard01243112004-01-04 15:48:17 +00001006 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001007 tb_reset_jump_recursive(tb_next);
1008 }
1009}
1010
1011static void tb_reset_jump_recursive(TranslationBlock *tb)
1012{
1013 tb_reset_jump_recursive2(tb, 0);
1014 tb_reset_jump_recursive2(tb, 1);
1015}
1016
bellard1fddef42005-04-17 19:16:13 +00001017#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001018static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1019{
pbrookc2f07f82006-04-08 17:14:56 +00001020 target_ulong addr, pd;
1021 ram_addr_t ram_addr;
1022 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001023
pbrookc2f07f82006-04-08 17:14:56 +00001024 addr = cpu_get_phys_page_debug(env, pc);
1025 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1026 if (!p) {
1027 pd = IO_MEM_UNASSIGNED;
1028 } else {
1029 pd = p->phys_offset;
1030 }
1031 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001032 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001033}
bellardc27004e2005-01-03 23:35:10 +00001034#endif
bellardd720b932004-04-25 17:57:43 +00001035
pbrook6658ffb2007-03-16 23:58:11 +00001036/* Add a watchpoint. */
1037int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1038{
1039 int i;
1040
1041 for (i = 0; i < env->nb_watchpoints; i++) {
1042 if (addr == env->watchpoint[i].vaddr)
1043 return 0;
1044 }
1045 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1046 return -1;
1047
1048 i = env->nb_watchpoints++;
1049 env->watchpoint[i].vaddr = addr;
1050 tlb_flush_page(env, addr);
1051 /* FIXME: This flush is needed because of the hack to make memory ops
1052 terminate the TB. It can be removed once the proper IO trap and
1053 re-execute bits are in. */
1054 tb_flush(env);
1055 return i;
1056}
1057
1058/* Remove a watchpoint. */
1059int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1060{
1061 int i;
1062
1063 for (i = 0; i < env->nb_watchpoints; i++) {
1064 if (addr == env->watchpoint[i].vaddr) {
1065 env->nb_watchpoints--;
1066 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1067 tlb_flush_page(env, addr);
1068 return 0;
1069 }
1070 }
1071 return -1;
1072}
1073
bellardc33a3462003-07-29 20:50:33 +00001074/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1075 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001076int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001077{
bellard1fddef42005-04-17 19:16:13 +00001078#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001079 int i;
bellardd720b932004-04-25 17:57:43 +00001080
bellard4c3a88a2003-07-26 12:06:08 +00001081 for(i = 0; i < env->nb_breakpoints; i++) {
1082 if (env->breakpoints[i] == pc)
1083 return 0;
1084 }
1085
1086 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1087 return -1;
1088 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001089
1090 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001091 return 0;
1092#else
1093 return -1;
1094#endif
1095}
1096
1097/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001098int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001099{
bellard1fddef42005-04-17 19:16:13 +00001100#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001101 int i;
1102 for(i = 0; i < env->nb_breakpoints; i++) {
1103 if (env->breakpoints[i] == pc)
1104 goto found;
1105 }
1106 return -1;
1107 found:
bellard4c3a88a2003-07-26 12:06:08 +00001108 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001109 if (i < env->nb_breakpoints)
1110 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001111
1112 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001113 return 0;
1114#else
1115 return -1;
1116#endif
1117}
1118
bellardc33a3462003-07-29 20:50:33 +00001119/* enable or disable single step mode. EXCP_DEBUG is returned by the
1120 CPU loop after each instruction */
1121void cpu_single_step(CPUState *env, int enabled)
1122{
bellard1fddef42005-04-17 19:16:13 +00001123#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001124 if (env->singlestep_enabled != enabled) {
1125 env->singlestep_enabled = enabled;
1126 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001127 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001128 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001129 }
1130#endif
1131}
1132
bellard34865132003-10-05 14:28:56 +00001133/* enable or disable low levels log */
1134void cpu_set_log(int log_flags)
1135{
1136 loglevel = log_flags;
1137 if (loglevel && !logfile) {
1138 logfile = fopen(logfilename, "w");
1139 if (!logfile) {
1140 perror(logfilename);
1141 _exit(1);
1142 }
bellard9fa3e852004-01-04 18:06:42 +00001143#if !defined(CONFIG_SOFTMMU)
1144 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1145 {
1146 static uint8_t logfile_buf[4096];
1147 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1148 }
1149#else
bellard34865132003-10-05 14:28:56 +00001150 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001151#endif
bellard34865132003-10-05 14:28:56 +00001152 }
1153}
1154
1155void cpu_set_log_filename(const char *filename)
1156{
1157 logfilename = strdup(filename);
1158}
bellardc33a3462003-07-29 20:50:33 +00001159
bellard01243112004-01-04 15:48:17 +00001160/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001161void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001162{
1163 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001164 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001165
bellard68a79312003-06-30 13:12:32 +00001166 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001167 /* if the cpu is currently executing code, we must unlink it and
1168 all the potentially executing TB */
1169 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001170 if (tb && !testandset(&interrupt_lock)) {
1171 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001172 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001173 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001174 }
1175}
1176
bellardb54ad042004-05-20 13:42:52 +00001177void cpu_reset_interrupt(CPUState *env, int mask)
1178{
1179 env->interrupt_request &= ~mask;
1180}
1181
bellardf193c792004-03-21 17:06:25 +00001182CPULogItem cpu_log_items[] = {
1183 { CPU_LOG_TB_OUT_ASM, "out_asm",
1184 "show generated host assembly code for each compiled TB" },
1185 { CPU_LOG_TB_IN_ASM, "in_asm",
1186 "show target assembly code for each compiled TB" },
1187 { CPU_LOG_TB_OP, "op",
1188 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1189#ifdef TARGET_I386
1190 { CPU_LOG_TB_OP_OPT, "op_opt",
1191 "show micro ops after optimization for each compiled TB" },
1192#endif
1193 { CPU_LOG_INT, "int",
1194 "show interrupts/exceptions in short format" },
1195 { CPU_LOG_EXEC, "exec",
1196 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001197 { CPU_LOG_TB_CPU, "cpu",
1198 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001199#ifdef TARGET_I386
1200 { CPU_LOG_PCALL, "pcall",
1201 "show protected mode far calls/returns/exceptions" },
1202#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001203#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001204 { CPU_LOG_IOPORT, "ioport",
1205 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001206#endif
bellardf193c792004-03-21 17:06:25 +00001207 { 0, NULL, NULL },
1208};
1209
1210static int cmp1(const char *s1, int n, const char *s2)
1211{
1212 if (strlen(s2) != n)
1213 return 0;
1214 return memcmp(s1, s2, n) == 0;
1215}
1216
1217/* takes a comma separated list of log masks. Return 0 if error. */
1218int cpu_str_to_log_mask(const char *str)
1219{
1220 CPULogItem *item;
1221 int mask;
1222 const char *p, *p1;
1223
1224 p = str;
1225 mask = 0;
1226 for(;;) {
1227 p1 = strchr(p, ',');
1228 if (!p1)
1229 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001230 if(cmp1(p,p1-p,"all")) {
1231 for(item = cpu_log_items; item->mask != 0; item++) {
1232 mask |= item->mask;
1233 }
1234 } else {
bellardf193c792004-03-21 17:06:25 +00001235 for(item = cpu_log_items; item->mask != 0; item++) {
1236 if (cmp1(p, p1 - p, item->name))
1237 goto found;
1238 }
1239 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001240 }
bellardf193c792004-03-21 17:06:25 +00001241 found:
1242 mask |= item->mask;
1243 if (*p1 != ',')
1244 break;
1245 p = p1 + 1;
1246 }
1247 return mask;
1248}
bellardea041c02003-06-25 16:16:50 +00001249
bellard75012672003-06-21 13:11:07 +00001250void cpu_abort(CPUState *env, const char *fmt, ...)
1251{
1252 va_list ap;
1253
1254 va_start(ap, fmt);
1255 fprintf(stderr, "qemu: fatal: ");
1256 vfprintf(stderr, fmt, ap);
1257 fprintf(stderr, "\n");
1258#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001259 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1260#else
1261 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001262#endif
1263 va_end(ap);
1264 abort();
1265}
1266
thsc5be9f02007-02-28 20:20:53 +00001267CPUState *cpu_copy(CPUState *env)
1268{
1269 CPUState *new_env = cpu_init();
1270 /* preserve chaining and index */
1271 CPUState *next_cpu = new_env->next_cpu;
1272 int cpu_index = new_env->cpu_index;
1273 memcpy(new_env, env, sizeof(CPUState));
1274 new_env->next_cpu = next_cpu;
1275 new_env->cpu_index = cpu_index;
1276 return new_env;
1277}
1278
bellard01243112004-01-04 15:48:17 +00001279#if !defined(CONFIG_USER_ONLY)
1280
bellardee8b7022004-02-03 23:35:10 +00001281/* NOTE: if flush_global is true, also flush global entries (not
1282 implemented yet) */
1283void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001284{
bellard33417e72003-08-10 21:47:01 +00001285 int i;
bellard01243112004-01-04 15:48:17 +00001286
bellard9fa3e852004-01-04 18:06:42 +00001287#if defined(DEBUG_TLB)
1288 printf("tlb_flush:\n");
1289#endif
bellard01243112004-01-04 15:48:17 +00001290 /* must reset current TB so that interrupts cannot modify the
1291 links while we are modifying them */
1292 env->current_tb = NULL;
1293
bellard33417e72003-08-10 21:47:01 +00001294 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001295 env->tlb_table[0][i].addr_read = -1;
1296 env->tlb_table[0][i].addr_write = -1;
1297 env->tlb_table[0][i].addr_code = -1;
1298 env->tlb_table[1][i].addr_read = -1;
1299 env->tlb_table[1][i].addr_write = -1;
1300 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001301 }
bellard9fa3e852004-01-04 18:06:42 +00001302
bellard8a40a182005-11-20 10:35:40 +00001303 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001304
1305#if !defined(CONFIG_SOFTMMU)
1306 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1307#endif
bellard0a962c02005-02-10 22:00:27 +00001308#ifdef USE_KQEMU
1309 if (env->kqemu_enabled) {
1310 kqemu_flush(env, flush_global);
1311 }
1312#endif
bellarde3db7222005-01-26 22:00:47 +00001313 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001314}
1315
bellard274da6b2004-05-20 21:56:27 +00001316static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001317{
bellard84b7b8e2005-11-28 21:19:04 +00001318 if (addr == (tlb_entry->addr_read &
1319 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1320 addr == (tlb_entry->addr_write &
1321 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1322 addr == (tlb_entry->addr_code &
1323 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1324 tlb_entry->addr_read = -1;
1325 tlb_entry->addr_write = -1;
1326 tlb_entry->addr_code = -1;
1327 }
bellard61382a52003-10-27 21:22:23 +00001328}
1329
bellard2e126692004-04-25 21:28:44 +00001330void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001331{
bellard8a40a182005-11-20 10:35:40 +00001332 int i;
bellard9fa3e852004-01-04 18:06:42 +00001333 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001334
bellard9fa3e852004-01-04 18:06:42 +00001335#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001336 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001337#endif
bellard01243112004-01-04 15:48:17 +00001338 /* must reset current TB so that interrupts cannot modify the
1339 links while we are modifying them */
1340 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001341
bellard61382a52003-10-27 21:22:23 +00001342 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001343 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001344 tlb_flush_entry(&env->tlb_table[0][i], addr);
1345 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001346
pbrookb362e5e2006-11-12 20:40:55 +00001347 /* Discard jump cache entries for any tb which might potentially
1348 overlap the flushed page. */
1349 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1350 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1351
1352 i = tb_jmp_cache_hash_page(addr);
1353 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001354
bellard01243112004-01-04 15:48:17 +00001355#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001356 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001357 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001358#endif
bellard0a962c02005-02-10 22:00:27 +00001359#ifdef USE_KQEMU
1360 if (env->kqemu_enabled) {
1361 kqemu_flush_page(env, addr);
1362 }
1363#endif
bellard9fa3e852004-01-04 18:06:42 +00001364}
1365
bellard9fa3e852004-01-04 18:06:42 +00001366/* update the TLBs so that writes to code in the virtual page 'addr'
1367 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001368static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001369{
bellard6a00d602005-11-21 23:25:50 +00001370 cpu_physical_memory_reset_dirty(ram_addr,
1371 ram_addr + TARGET_PAGE_SIZE,
1372 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001373}
1374
bellard9fa3e852004-01-04 18:06:42 +00001375/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001376 tested for self modifying code */
1377static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1378 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001379{
bellard3a7d9292005-08-21 09:26:42 +00001380 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001381}
1382
1383static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1384 unsigned long start, unsigned long length)
1385{
1386 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001387 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1388 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001389 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001390 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001391 }
1392 }
1393}
1394
bellard3a7d9292005-08-21 09:26:42 +00001395void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001396 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001397{
1398 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001399 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001400 int i, mask, len;
1401 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001402
1403 start &= TARGET_PAGE_MASK;
1404 end = TARGET_PAGE_ALIGN(end);
1405
1406 length = end - start;
1407 if (length == 0)
1408 return;
bellard0a962c02005-02-10 22:00:27 +00001409 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001410#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001411 /* XXX: should not depend on cpu context */
1412 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001413 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001414 ram_addr_t addr;
1415 addr = start;
1416 for(i = 0; i < len; i++) {
1417 kqemu_set_notdirty(env, addr);
1418 addr += TARGET_PAGE_SIZE;
1419 }
bellard3a7d9292005-08-21 09:26:42 +00001420 }
1421#endif
bellardf23db162005-08-21 19:12:28 +00001422 mask = ~dirty_flags;
1423 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1424 for(i = 0; i < len; i++)
1425 p[i] &= mask;
1426
bellard1ccde1c2004-02-06 19:46:14 +00001427 /* we modify the TLB cache so that the dirty bit will be set again
1428 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001429 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001430 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1431 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001432 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001433 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001434 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001435 }
bellard59817cc2004-02-16 22:01:13 +00001436
1437#if !defined(CONFIG_SOFTMMU)
1438 /* XXX: this is expensive */
1439 {
1440 VirtPageDesc *p;
1441 int j;
1442 target_ulong addr;
1443
1444 for(i = 0; i < L1_SIZE; i++) {
1445 p = l1_virt_map[i];
1446 if (p) {
1447 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1448 for(j = 0; j < L2_SIZE; j++) {
1449 if (p->valid_tag == virt_valid_tag &&
1450 p->phys_addr >= start && p->phys_addr < end &&
1451 (p->prot & PROT_WRITE)) {
1452 if (addr < MMAP_AREA_END) {
1453 mprotect((void *)addr, TARGET_PAGE_SIZE,
1454 p->prot & ~PROT_WRITE);
1455 }
1456 }
1457 addr += TARGET_PAGE_SIZE;
1458 p++;
1459 }
1460 }
1461 }
1462 }
1463#endif
bellard1ccde1c2004-02-06 19:46:14 +00001464}
1465
bellard3a7d9292005-08-21 09:26:42 +00001466static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1467{
1468 ram_addr_t ram_addr;
1469
bellard84b7b8e2005-11-28 21:19:04 +00001470 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1471 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001472 tlb_entry->addend - (unsigned long)phys_ram_base;
1473 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001474 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001475 }
1476 }
1477}
1478
1479/* update the TLB according to the current state of the dirty bits */
1480void cpu_tlb_update_dirty(CPUState *env)
1481{
1482 int i;
1483 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001484 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001485 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001486 tlb_update_dirty(&env->tlb_table[1][i]);
bellard3a7d9292005-08-21 09:26:42 +00001487}
1488
bellard1ccde1c2004-02-06 19:46:14 +00001489static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001490 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001491{
1492 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001493 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1494 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001495 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001496 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001497 }
1498 }
1499}
1500
1501/* update the TLB corresponding to virtual page vaddr and phys addr
1502 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001503static inline void tlb_set_dirty(CPUState *env,
1504 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001505{
bellard1ccde1c2004-02-06 19:46:14 +00001506 int i;
1507
bellard1ccde1c2004-02-06 19:46:14 +00001508 addr &= TARGET_PAGE_MASK;
1509 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001510 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1511 tlb_set_dirty1(&env->tlb_table[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001512}
1513
bellard59817cc2004-02-16 22:01:13 +00001514/* add a new TLB entry. At most one entry for a given virtual address
1515 is permitted. Return 0 if OK or 2 if the page could not be mapped
1516 (can only happen in non SOFTMMU mode for I/O pages or pages
1517 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001518int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1519 target_phys_addr_t paddr, int prot,
1520 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001521{
bellard92e873b2004-05-21 14:52:29 +00001522 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001523 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001524 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001525 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001526 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001527 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001528 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001529 int i;
bellard9fa3e852004-01-04 18:06:42 +00001530
bellard92e873b2004-05-21 14:52:29 +00001531 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001532 if (!p) {
1533 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001534 } else {
1535 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001536 }
1537#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001538 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 +00001539 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001540#endif
1541
1542 ret = 0;
1543#if !defined(CONFIG_SOFTMMU)
1544 if (is_softmmu)
1545#endif
1546 {
bellard2a4188a2006-06-25 21:54:59 +00001547 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001548 /* IO memory case */
1549 address = vaddr | pd;
1550 addend = paddr;
1551 } else {
1552 /* standard memory */
1553 address = vaddr;
1554 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1555 }
pbrook6658ffb2007-03-16 23:58:11 +00001556
1557 /* Make accesses to pages with watchpoints go via the
1558 watchpoint trap routines. */
1559 for (i = 0; i < env->nb_watchpoints; i++) {
1560 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1561 if (address & ~TARGET_PAGE_MASK) {
1562 env->watchpoint[i].is_ram = 0;
1563 address = vaddr | io_mem_watch;
1564 } else {
1565 env->watchpoint[i].is_ram = 1;
1566 /* TODO: Figure out how to make read watchpoints coexist
1567 with code. */
1568 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1569 }
1570 }
1571 }
bellard9fa3e852004-01-04 18:06:42 +00001572
bellard90f18422005-07-24 10:17:31 +00001573 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001574 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001575 te = &env->tlb_table[is_user][index];
1576 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001577 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001578 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001579 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001580 te->addr_read = -1;
1581 }
1582 if (prot & PAGE_EXEC) {
1583 te->addr_code = address;
1584 } else {
1585 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001586 }
bellard67b915a2004-03-31 23:37:16 +00001587 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001588 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1589 (pd & IO_MEM_ROMD)) {
1590 /* write access calls the I/O callback */
1591 te->addr_write = vaddr |
1592 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001593 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001594 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001595 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001596 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001597 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001598 }
1599 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001600 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001601 }
1602 }
1603#if !defined(CONFIG_SOFTMMU)
1604 else {
1605 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1606 /* IO access: no mapping is done as it will be handled by the
1607 soft MMU */
1608 if (!(env->hflags & HF_SOFTMMU_MASK))
1609 ret = 2;
1610 } else {
1611 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001612
bellard59817cc2004-02-16 22:01:13 +00001613 if (vaddr >= MMAP_AREA_END) {
1614 ret = 2;
1615 } else {
1616 if (prot & PROT_WRITE) {
1617 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001618#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001619 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001620#endif
bellard59817cc2004-02-16 22:01:13 +00001621 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1622 !cpu_physical_memory_is_dirty(pd))) {
1623 /* ROM: we do as if code was inside */
1624 /* if code is present, we only map as read only and save the
1625 original mapping */
1626 VirtPageDesc *vp;
1627
bellard90f18422005-07-24 10:17:31 +00001628 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001629 vp->phys_addr = pd;
1630 vp->prot = prot;
1631 vp->valid_tag = virt_valid_tag;
1632 prot &= ~PAGE_WRITE;
1633 }
bellard9fa3e852004-01-04 18:06:42 +00001634 }
bellard59817cc2004-02-16 22:01:13 +00001635 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1636 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1637 if (map_addr == MAP_FAILED) {
1638 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1639 paddr, vaddr);
1640 }
bellard9fa3e852004-01-04 18:06:42 +00001641 }
1642 }
1643 }
1644#endif
1645 return ret;
1646}
1647
1648/* called from signal handler: invalidate the code and unprotect the
1649 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001650int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001651{
1652#if !defined(CONFIG_SOFTMMU)
1653 VirtPageDesc *vp;
1654
1655#if defined(DEBUG_TLB)
1656 printf("page_unprotect: addr=0x%08x\n", addr);
1657#endif
1658 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001659
1660 /* if it is not mapped, no need to worry here */
1661 if (addr >= MMAP_AREA_END)
1662 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001663 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1664 if (!vp)
1665 return 0;
1666 /* NOTE: in this case, validate_tag is _not_ tested as it
1667 validates only the code TLB */
1668 if (vp->valid_tag != virt_valid_tag)
1669 return 0;
1670 if (!(vp->prot & PAGE_WRITE))
1671 return 0;
1672#if defined(DEBUG_TLB)
1673 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1674 addr, vp->phys_addr, vp->prot);
1675#endif
bellard59817cc2004-02-16 22:01:13 +00001676 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1677 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1678 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001679 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001680 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001681 /* flush the code inside */
1682 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001683 return 1;
1684#else
1685 return 0;
1686#endif
bellard33417e72003-08-10 21:47:01 +00001687}
1688
bellard01243112004-01-04 15:48:17 +00001689#else
1690
bellardee8b7022004-02-03 23:35:10 +00001691void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001692{
1693}
1694
bellard2e126692004-04-25 21:28:44 +00001695void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001696{
1697}
1698
bellard84b7b8e2005-11-28 21:19:04 +00001699int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1700 target_phys_addr_t paddr, int prot,
1701 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001702{
bellard9fa3e852004-01-04 18:06:42 +00001703 return 0;
1704}
bellard33417e72003-08-10 21:47:01 +00001705
bellard9fa3e852004-01-04 18:06:42 +00001706/* dump memory mappings */
1707void page_dump(FILE *f)
1708{
1709 unsigned long start, end;
1710 int i, j, prot, prot1;
1711 PageDesc *p;
1712
1713 fprintf(f, "%-8s %-8s %-8s %s\n",
1714 "start", "end", "size", "prot");
1715 start = -1;
1716 end = -1;
1717 prot = 0;
1718 for(i = 0; i <= L1_SIZE; i++) {
1719 if (i < L1_SIZE)
1720 p = l1_map[i];
1721 else
1722 p = NULL;
1723 for(j = 0;j < L2_SIZE; j++) {
1724 if (!p)
1725 prot1 = 0;
1726 else
1727 prot1 = p[j].flags;
1728 if (prot1 != prot) {
1729 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1730 if (start != -1) {
1731 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1732 start, end, end - start,
1733 prot & PAGE_READ ? 'r' : '-',
1734 prot & PAGE_WRITE ? 'w' : '-',
1735 prot & PAGE_EXEC ? 'x' : '-');
1736 }
1737 if (prot1 != 0)
1738 start = end;
1739 else
1740 start = -1;
1741 prot = prot1;
1742 }
1743 if (!p)
1744 break;
1745 }
bellard33417e72003-08-10 21:47:01 +00001746 }
bellard33417e72003-08-10 21:47:01 +00001747}
1748
pbrook53a59602006-03-25 19:31:22 +00001749int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001750{
bellard9fa3e852004-01-04 18:06:42 +00001751 PageDesc *p;
1752
1753 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001754 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001755 return 0;
1756 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001757}
1758
bellard9fa3e852004-01-04 18:06:42 +00001759/* modify the flags of a page and invalidate the code if
1760 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1761 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001762void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001763{
1764 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001765 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001766
1767 start = start & TARGET_PAGE_MASK;
1768 end = TARGET_PAGE_ALIGN(end);
1769 if (flags & PAGE_WRITE)
1770 flags |= PAGE_WRITE_ORG;
1771 spin_lock(&tb_lock);
1772 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1773 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1774 /* if the write protection is set, then we invalidate the code
1775 inside */
1776 if (!(p->flags & PAGE_WRITE) &&
1777 (flags & PAGE_WRITE) &&
1778 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001779 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001780 }
1781 p->flags = flags;
1782 }
1783 spin_unlock(&tb_lock);
1784}
1785
1786/* called from signal handler: invalidate the code and unprotect the
1787 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001788int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001789{
1790 unsigned int page_index, prot, pindex;
1791 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001792 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001793
bellard83fb7ad2004-07-05 21:25:26 +00001794 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001795 page_index = host_start >> TARGET_PAGE_BITS;
1796 p1 = page_find(page_index);
1797 if (!p1)
1798 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001799 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001800 p = p1;
1801 prot = 0;
1802 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1803 prot |= p->flags;
1804 p++;
1805 }
1806 /* if the page was really writable, then we change its
1807 protection back to writable */
1808 if (prot & PAGE_WRITE_ORG) {
1809 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1810 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001811 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001812 (prot & PAGE_BITS) | PAGE_WRITE);
1813 p1[pindex].flags |= PAGE_WRITE;
1814 /* and since the content will be modified, we must invalidate
1815 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001816 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001817#ifdef DEBUG_TB_CHECK
1818 tb_invalidate_check(address);
1819#endif
1820 return 1;
1821 }
1822 }
1823 return 0;
1824}
1825
1826/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001827/* ??? This should be redundant now we have lock_user. */
1828void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001829{
pbrook53a59602006-03-25 19:31:22 +00001830 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001831
pbrook53a59602006-03-25 19:31:22 +00001832 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001833 end = start + data_size;
1834 start &= TARGET_PAGE_MASK;
1835 end = TARGET_PAGE_ALIGN(end);
1836 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001837 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001838 }
1839}
1840
bellard6a00d602005-11-21 23:25:50 +00001841static inline void tlb_set_dirty(CPUState *env,
1842 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001843{
1844}
bellard9fa3e852004-01-04 18:06:42 +00001845#endif /* defined(CONFIG_USER_ONLY) */
1846
bellard33417e72003-08-10 21:47:01 +00001847/* register physical memory. 'size' must be a multiple of the target
1848 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1849 io memory page */
bellard2e126692004-04-25 21:28:44 +00001850void cpu_register_physical_memory(target_phys_addr_t start_addr,
1851 unsigned long size,
1852 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001853{
bellard108c49b2005-07-24 12:55:09 +00001854 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001855 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001856 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001857
bellard5fd386f2004-05-23 21:11:22 +00001858 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001859 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001860 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001861 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001862 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001863 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1864 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001865 phys_offset += TARGET_PAGE_SIZE;
1866 }
bellard9d420372006-06-25 22:25:22 +00001867
1868 /* since each CPU stores ram addresses in its TLB cache, we must
1869 reset the modified entries */
1870 /* XXX: slow ! */
1871 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1872 tlb_flush(env, 1);
1873 }
bellard33417e72003-08-10 21:47:01 +00001874}
1875
bellardba863452006-09-24 18:41:10 +00001876/* XXX: temporary until new memory mapping API */
1877uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1878{
1879 PhysPageDesc *p;
1880
1881 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1882 if (!p)
1883 return IO_MEM_UNASSIGNED;
1884 return p->phys_offset;
1885}
1886
bellarde9a1ab12007-02-08 23:08:38 +00001887/* XXX: better than nothing */
1888ram_addr_t qemu_ram_alloc(unsigned int size)
1889{
1890 ram_addr_t addr;
1891 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1892 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
1893 size, phys_ram_size);
1894 abort();
1895 }
1896 addr = phys_ram_alloc_offset;
1897 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1898 return addr;
1899}
1900
1901void qemu_ram_free(ram_addr_t addr)
1902{
1903}
1904
bellarda4193c82004-06-03 14:01:43 +00001905static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001906{
pbrook67d3b952006-12-18 05:03:52 +00001907#ifdef DEBUG_UNASSIGNED
1908 printf("Unassigned mem read 0x%08x\n", (int)addr);
1909#endif
bellard33417e72003-08-10 21:47:01 +00001910 return 0;
1911}
1912
bellarda4193c82004-06-03 14:01:43 +00001913static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001914{
pbrook67d3b952006-12-18 05:03:52 +00001915#ifdef DEBUG_UNASSIGNED
1916 printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
1917#endif
bellard33417e72003-08-10 21:47:01 +00001918}
1919
1920static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1921 unassigned_mem_readb,
1922 unassigned_mem_readb,
1923 unassigned_mem_readb,
1924};
1925
1926static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1927 unassigned_mem_writeb,
1928 unassigned_mem_writeb,
1929 unassigned_mem_writeb,
1930};
1931
bellarda4193c82004-06-03 14:01:43 +00001932static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001933{
bellard3a7d9292005-08-21 09:26:42 +00001934 unsigned long ram_addr;
1935 int dirty_flags;
1936 ram_addr = addr - (unsigned long)phys_ram_base;
1937 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1938 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1939#if !defined(CONFIG_USER_ONLY)
1940 tb_invalidate_phys_page_fast(ram_addr, 1);
1941 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1942#endif
1943 }
bellardc27004e2005-01-03 23:35:10 +00001944 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001945#ifdef USE_KQEMU
1946 if (cpu_single_env->kqemu_enabled &&
1947 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1948 kqemu_modify_page(cpu_single_env, ram_addr);
1949#endif
bellardf23db162005-08-21 19:12:28 +00001950 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1951 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1952 /* we remove the notdirty callback only if the code has been
1953 flushed */
1954 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001955 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001956}
1957
bellarda4193c82004-06-03 14:01:43 +00001958static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001959{
bellard3a7d9292005-08-21 09:26:42 +00001960 unsigned long ram_addr;
1961 int dirty_flags;
1962 ram_addr = addr - (unsigned long)phys_ram_base;
1963 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1964 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1965#if !defined(CONFIG_USER_ONLY)
1966 tb_invalidate_phys_page_fast(ram_addr, 2);
1967 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1968#endif
1969 }
bellardc27004e2005-01-03 23:35:10 +00001970 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001971#ifdef USE_KQEMU
1972 if (cpu_single_env->kqemu_enabled &&
1973 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1974 kqemu_modify_page(cpu_single_env, ram_addr);
1975#endif
bellardf23db162005-08-21 19:12:28 +00001976 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1977 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1978 /* we remove the notdirty callback only if the code has been
1979 flushed */
1980 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001981 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001982}
1983
bellarda4193c82004-06-03 14:01:43 +00001984static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001985{
bellard3a7d9292005-08-21 09:26:42 +00001986 unsigned long ram_addr;
1987 int dirty_flags;
1988 ram_addr = addr - (unsigned long)phys_ram_base;
1989 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1990 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1991#if !defined(CONFIG_USER_ONLY)
1992 tb_invalidate_phys_page_fast(ram_addr, 4);
1993 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1994#endif
1995 }
bellardc27004e2005-01-03 23:35:10 +00001996 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001997#ifdef USE_KQEMU
1998 if (cpu_single_env->kqemu_enabled &&
1999 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2000 kqemu_modify_page(cpu_single_env, ram_addr);
2001#endif
bellardf23db162005-08-21 19:12:28 +00002002 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2003 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2004 /* we remove the notdirty callback only if the code has been
2005 flushed */
2006 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002007 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002008}
2009
bellard3a7d9292005-08-21 09:26:42 +00002010static CPUReadMemoryFunc *error_mem_read[3] = {
2011 NULL, /* never used */
2012 NULL, /* never used */
2013 NULL, /* never used */
2014};
2015
bellard1ccde1c2004-02-06 19:46:14 +00002016static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2017 notdirty_mem_writeb,
2018 notdirty_mem_writew,
2019 notdirty_mem_writel,
2020};
2021
pbrook6658ffb2007-03-16 23:58:11 +00002022#if defined(CONFIG_SOFTMMU)
2023/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2024 so these check for a hit then pass through to the normal out-of-line
2025 phys routines. */
2026static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2027{
2028 return ldub_phys(addr);
2029}
2030
2031static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2032{
2033 return lduw_phys(addr);
2034}
2035
2036static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2037{
2038 return ldl_phys(addr);
2039}
2040
2041/* Generate a debug exception if a watchpoint has been hit.
2042 Returns the real physical address of the access. addr will be a host
2043 address in the is_ram case. */
2044static target_ulong check_watchpoint(target_phys_addr_t addr)
2045{
2046 CPUState *env = cpu_single_env;
2047 target_ulong watch;
2048 target_ulong retaddr;
2049 int i;
2050
2051 retaddr = addr;
2052 for (i = 0; i < env->nb_watchpoints; i++) {
2053 watch = env->watchpoint[i].vaddr;
2054 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
2055 if (env->watchpoint[i].is_ram)
2056 retaddr = addr - (unsigned long)phys_ram_base;
2057 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2058 cpu_single_env->watchpoint_hit = i + 1;
2059 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2060 break;
2061 }
2062 }
2063 }
2064 return retaddr;
2065}
2066
2067static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2068 uint32_t val)
2069{
2070 addr = check_watchpoint(addr);
2071 stb_phys(addr, val);
2072}
2073
2074static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2075 uint32_t val)
2076{
2077 addr = check_watchpoint(addr);
2078 stw_phys(addr, val);
2079}
2080
2081static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2082 uint32_t val)
2083{
2084 addr = check_watchpoint(addr);
2085 stl_phys(addr, val);
2086}
2087
2088static CPUReadMemoryFunc *watch_mem_read[3] = {
2089 watch_mem_readb,
2090 watch_mem_readw,
2091 watch_mem_readl,
2092};
2093
2094static CPUWriteMemoryFunc *watch_mem_write[3] = {
2095 watch_mem_writeb,
2096 watch_mem_writew,
2097 watch_mem_writel,
2098};
2099#endif
2100
bellard33417e72003-08-10 21:47:01 +00002101static void io_mem_init(void)
2102{
bellard3a7d9292005-08-21 09:26:42 +00002103 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002104 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002105 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002106 io_mem_nb = 5;
2107
pbrook6658ffb2007-03-16 23:58:11 +00002108#if defined(CONFIG_SOFTMMU)
2109 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2110 watch_mem_write, NULL);
2111#endif
bellard1ccde1c2004-02-06 19:46:14 +00002112 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002113 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002114 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002115}
2116
2117/* mem_read and mem_write are arrays of functions containing the
2118 function to access byte (index 0), word (index 1) and dword (index
2119 2). All functions must be supplied. If io_index is non zero, the
2120 corresponding io zone is modified. If it is zero, a new io zone is
2121 allocated. The return value can be used with
2122 cpu_register_physical_memory(). (-1) is returned if error. */
2123int cpu_register_io_memory(int io_index,
2124 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002125 CPUWriteMemoryFunc **mem_write,
2126 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002127{
2128 int i;
2129
2130 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002131 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002132 return -1;
2133 io_index = io_mem_nb++;
2134 } else {
2135 if (io_index >= IO_MEM_NB_ENTRIES)
2136 return -1;
2137 }
bellardb5ff1b32005-11-26 10:38:39 +00002138
bellard33417e72003-08-10 21:47:01 +00002139 for(i = 0;i < 3; i++) {
2140 io_mem_read[io_index][i] = mem_read[i];
2141 io_mem_write[io_index][i] = mem_write[i];
2142 }
bellarda4193c82004-06-03 14:01:43 +00002143 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002144 return io_index << IO_MEM_SHIFT;
2145}
bellard61382a52003-10-27 21:22:23 +00002146
bellard8926b512004-10-10 15:14:20 +00002147CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2148{
2149 return io_mem_write[io_index >> IO_MEM_SHIFT];
2150}
2151
2152CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2153{
2154 return io_mem_read[io_index >> IO_MEM_SHIFT];
2155}
2156
bellard13eb76e2004-01-24 15:23:36 +00002157/* physical memory access (slow version, mainly for debug) */
2158#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002159void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002160 int len, int is_write)
2161{
2162 int l, flags;
2163 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002164 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002165
2166 while (len > 0) {
2167 page = addr & TARGET_PAGE_MASK;
2168 l = (page + TARGET_PAGE_SIZE) - addr;
2169 if (l > len)
2170 l = len;
2171 flags = page_get_flags(page);
2172 if (!(flags & PAGE_VALID))
2173 return;
2174 if (is_write) {
2175 if (!(flags & PAGE_WRITE))
2176 return;
pbrook53a59602006-03-25 19:31:22 +00002177 p = lock_user(addr, len, 0);
2178 memcpy(p, buf, len);
2179 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002180 } else {
2181 if (!(flags & PAGE_READ))
2182 return;
pbrook53a59602006-03-25 19:31:22 +00002183 p = lock_user(addr, len, 1);
2184 memcpy(buf, p, len);
2185 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002186 }
2187 len -= l;
2188 buf += l;
2189 addr += l;
2190 }
2191}
bellard8df1cd02005-01-28 22:37:22 +00002192
bellard13eb76e2004-01-24 15:23:36 +00002193#else
bellard2e126692004-04-25 21:28:44 +00002194void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002195 int len, int is_write)
2196{
2197 int l, io_index;
2198 uint8_t *ptr;
2199 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002200 target_phys_addr_t page;
2201 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002202 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002203
2204 while (len > 0) {
2205 page = addr & TARGET_PAGE_MASK;
2206 l = (page + TARGET_PAGE_SIZE) - addr;
2207 if (l > len)
2208 l = len;
bellard92e873b2004-05-21 14:52:29 +00002209 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002210 if (!p) {
2211 pd = IO_MEM_UNASSIGNED;
2212 } else {
2213 pd = p->phys_offset;
2214 }
2215
2216 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002217 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002218 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002219 /* XXX: could force cpu_single_env to NULL to avoid
2220 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002221 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002222 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002223 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002224 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002225 l = 4;
2226 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002227 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002228 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002229 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002230 l = 2;
2231 } else {
bellard1c213d12005-09-03 10:49:04 +00002232 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002233 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002234 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002235 l = 1;
2236 }
2237 } else {
bellardb448f2f2004-02-25 23:24:04 +00002238 unsigned long addr1;
2239 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002240 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002241 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002242 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002243 if (!cpu_physical_memory_is_dirty(addr1)) {
2244 /* invalidate code */
2245 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2246 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002247 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2248 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002249 }
bellard13eb76e2004-01-24 15:23:36 +00002250 }
2251 } else {
bellard2a4188a2006-06-25 21:54:59 +00002252 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2253 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002254 /* I/O case */
2255 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2256 if (l >= 4 && ((addr & 3) == 0)) {
2257 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002258 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002259 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002260 l = 4;
2261 } else if (l >= 2 && ((addr & 1) == 0)) {
2262 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002263 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002264 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002265 l = 2;
2266 } else {
bellard1c213d12005-09-03 10:49:04 +00002267 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002268 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002269 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002270 l = 1;
2271 }
2272 } else {
2273 /* RAM case */
2274 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2275 (addr & ~TARGET_PAGE_MASK);
2276 memcpy(buf, ptr, l);
2277 }
2278 }
2279 len -= l;
2280 buf += l;
2281 addr += l;
2282 }
2283}
bellard8df1cd02005-01-28 22:37:22 +00002284
bellardd0ecd2a2006-04-23 17:14:48 +00002285/* used for ROM loading : can write in RAM and ROM */
2286void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2287 const uint8_t *buf, int len)
2288{
2289 int l;
2290 uint8_t *ptr;
2291 target_phys_addr_t page;
2292 unsigned long pd;
2293 PhysPageDesc *p;
2294
2295 while (len > 0) {
2296 page = addr & TARGET_PAGE_MASK;
2297 l = (page + TARGET_PAGE_SIZE) - addr;
2298 if (l > len)
2299 l = len;
2300 p = phys_page_find(page >> TARGET_PAGE_BITS);
2301 if (!p) {
2302 pd = IO_MEM_UNASSIGNED;
2303 } else {
2304 pd = p->phys_offset;
2305 }
2306
2307 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002308 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2309 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002310 /* do nothing */
2311 } else {
2312 unsigned long addr1;
2313 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2314 /* ROM/RAM case */
2315 ptr = phys_ram_base + addr1;
2316 memcpy(ptr, buf, l);
2317 }
2318 len -= l;
2319 buf += l;
2320 addr += l;
2321 }
2322}
2323
2324
bellard8df1cd02005-01-28 22:37:22 +00002325/* warning: addr must be aligned */
2326uint32_t ldl_phys(target_phys_addr_t addr)
2327{
2328 int io_index;
2329 uint8_t *ptr;
2330 uint32_t val;
2331 unsigned long pd;
2332 PhysPageDesc *p;
2333
2334 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2335 if (!p) {
2336 pd = IO_MEM_UNASSIGNED;
2337 } else {
2338 pd = p->phys_offset;
2339 }
2340
bellard2a4188a2006-06-25 21:54:59 +00002341 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2342 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002343 /* I/O case */
2344 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2345 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2346 } else {
2347 /* RAM case */
2348 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2349 (addr & ~TARGET_PAGE_MASK);
2350 val = ldl_p(ptr);
2351 }
2352 return val;
2353}
2354
bellard84b7b8e2005-11-28 21:19:04 +00002355/* warning: addr must be aligned */
2356uint64_t ldq_phys(target_phys_addr_t addr)
2357{
2358 int io_index;
2359 uint8_t *ptr;
2360 uint64_t val;
2361 unsigned long pd;
2362 PhysPageDesc *p;
2363
2364 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2365 if (!p) {
2366 pd = IO_MEM_UNASSIGNED;
2367 } else {
2368 pd = p->phys_offset;
2369 }
2370
bellard2a4188a2006-06-25 21:54:59 +00002371 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2372 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002373 /* I/O case */
2374 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2375#ifdef TARGET_WORDS_BIGENDIAN
2376 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2377 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2378#else
2379 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2380 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2381#endif
2382 } else {
2383 /* RAM case */
2384 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2385 (addr & ~TARGET_PAGE_MASK);
2386 val = ldq_p(ptr);
2387 }
2388 return val;
2389}
2390
bellardaab33092005-10-30 20:48:42 +00002391/* XXX: optimize */
2392uint32_t ldub_phys(target_phys_addr_t addr)
2393{
2394 uint8_t val;
2395 cpu_physical_memory_read(addr, &val, 1);
2396 return val;
2397}
2398
2399/* XXX: optimize */
2400uint32_t lduw_phys(target_phys_addr_t addr)
2401{
2402 uint16_t val;
2403 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2404 return tswap16(val);
2405}
2406
bellard8df1cd02005-01-28 22:37:22 +00002407/* warning: addr must be aligned. The ram page is not masked as dirty
2408 and the code inside is not invalidated. It is useful if the dirty
2409 bits are used to track modified PTEs */
2410void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2411{
2412 int io_index;
2413 uint8_t *ptr;
2414 unsigned long pd;
2415 PhysPageDesc *p;
2416
2417 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2418 if (!p) {
2419 pd = IO_MEM_UNASSIGNED;
2420 } else {
2421 pd = p->phys_offset;
2422 }
2423
bellard3a7d9292005-08-21 09:26:42 +00002424 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002425 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2426 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2427 } else {
2428 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2429 (addr & ~TARGET_PAGE_MASK);
2430 stl_p(ptr, val);
2431 }
2432}
2433
2434/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002435void stl_phys(target_phys_addr_t addr, uint32_t val)
2436{
2437 int io_index;
2438 uint8_t *ptr;
2439 unsigned long pd;
2440 PhysPageDesc *p;
2441
2442 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2443 if (!p) {
2444 pd = IO_MEM_UNASSIGNED;
2445 } else {
2446 pd = p->phys_offset;
2447 }
2448
bellard3a7d9292005-08-21 09:26:42 +00002449 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002450 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2451 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2452 } else {
2453 unsigned long addr1;
2454 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2455 /* RAM case */
2456 ptr = phys_ram_base + addr1;
2457 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002458 if (!cpu_physical_memory_is_dirty(addr1)) {
2459 /* invalidate code */
2460 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2461 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002462 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2463 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002464 }
bellard8df1cd02005-01-28 22:37:22 +00002465 }
2466}
2467
bellardaab33092005-10-30 20:48:42 +00002468/* XXX: optimize */
2469void stb_phys(target_phys_addr_t addr, uint32_t val)
2470{
2471 uint8_t v = val;
2472 cpu_physical_memory_write(addr, &v, 1);
2473}
2474
2475/* XXX: optimize */
2476void stw_phys(target_phys_addr_t addr, uint32_t val)
2477{
2478 uint16_t v = tswap16(val);
2479 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2480}
2481
2482/* XXX: optimize */
2483void stq_phys(target_phys_addr_t addr, uint64_t val)
2484{
2485 val = tswap64(val);
2486 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2487}
2488
bellard13eb76e2004-01-24 15:23:36 +00002489#endif
2490
2491/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002492int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2493 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002494{
2495 int l;
2496 target_ulong page, phys_addr;
2497
2498 while (len > 0) {
2499 page = addr & TARGET_PAGE_MASK;
2500 phys_addr = cpu_get_phys_page_debug(env, page);
2501 /* if no physical page mapped, return an error */
2502 if (phys_addr == -1)
2503 return -1;
2504 l = (page + TARGET_PAGE_SIZE) - addr;
2505 if (l > len)
2506 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002507 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2508 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002509 len -= l;
2510 buf += l;
2511 addr += l;
2512 }
2513 return 0;
2514}
2515
bellarde3db7222005-01-26 22:00:47 +00002516void dump_exec_info(FILE *f,
2517 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2518{
2519 int i, target_code_size, max_target_code_size;
2520 int direct_jmp_count, direct_jmp2_count, cross_page;
2521 TranslationBlock *tb;
2522
2523 target_code_size = 0;
2524 max_target_code_size = 0;
2525 cross_page = 0;
2526 direct_jmp_count = 0;
2527 direct_jmp2_count = 0;
2528 for(i = 0; i < nb_tbs; i++) {
2529 tb = &tbs[i];
2530 target_code_size += tb->size;
2531 if (tb->size > max_target_code_size)
2532 max_target_code_size = tb->size;
2533 if (tb->page_addr[1] != -1)
2534 cross_page++;
2535 if (tb->tb_next_offset[0] != 0xffff) {
2536 direct_jmp_count++;
2537 if (tb->tb_next_offset[1] != 0xffff) {
2538 direct_jmp2_count++;
2539 }
2540 }
2541 }
2542 /* XXX: avoid using doubles ? */
2543 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2544 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2545 nb_tbs ? target_code_size / nb_tbs : 0,
2546 max_target_code_size);
2547 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2548 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2549 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2550 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2551 cross_page,
2552 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2553 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2554 direct_jmp_count,
2555 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2556 direct_jmp2_count,
2557 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2558 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2559 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2560 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2561}
2562
bellard61382a52003-10-27 21:22:23 +00002563#if !defined(CONFIG_USER_ONLY)
2564
2565#define MMUSUFFIX _cmmu
2566#define GETPC() NULL
2567#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002568#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002569
2570#define SHIFT 0
2571#include "softmmu_template.h"
2572
2573#define SHIFT 1
2574#include "softmmu_template.h"
2575
2576#define SHIFT 2
2577#include "softmmu_template.h"
2578
2579#define SHIFT 3
2580#include "softmmu_template.h"
2581
2582#undef env
2583
2584#endif