blob: b74d90920cb3dd66f7700a42ef38ba54e4083e38 [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * 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
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
pbrook53a59602006-03-25 19:31:22 +000038#if defined(CONFIG_USER_ONLY)
39#include <qemu.h>
40#endif
bellard54936002003-05-13 00:25:15 +000041
bellardfd6ce8f2003-05-14 19:00:11 +000042//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000043//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000044//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000045//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000046
47/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000048//#define DEBUG_TB_CHECK
49//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000050
ths1196be32007-03-17 15:17:58 +000051//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000052//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000053
pbrook99773bd2006-04-16 15:14:59 +000054#if !defined(CONFIG_USER_ONLY)
55/* TB consistency checks only implemented for usermode emulation. */
56#undef DEBUG_TB_CHECK
57#endif
58
bellardfd6ce8f2003-05-14 19:00:11 +000059/* threshold to flush the translated code buffer */
blueswir1d07bde82007-12-11 19:35:45 +000060#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
bellardfd6ce8f2003-05-14 19:00:11 +000061
bellard9fa3e852004-01-04 18:06:42 +000062#define SMC_BITMAP_USE_THRESHOLD 10
63
64#define MMAP_AREA_START 0x00000000
65#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000066
bellard108c49b2005-07-24 12:55:09 +000067#if defined(TARGET_SPARC64)
68#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000069#elif defined(TARGET_SPARC)
70#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000071#elif defined(TARGET_ALPHA)
72#define TARGET_PHYS_ADDR_SPACE_BITS 42
73#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000074#elif defined(TARGET_PPC64)
75#define TARGET_PHYS_ADDR_SPACE_BITS 42
76#else
77/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
78#define TARGET_PHYS_ADDR_SPACE_BITS 32
79#endif
80
bellardfd6ce8f2003-05-14 19:00:11 +000081TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000082TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000083int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000084/* any access to the tbs or the page table must use this lock */
85spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000086
bellardb8076a72005-04-07 22:20:31 +000087uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000088uint8_t *code_gen_ptr;
89
bellard9fa3e852004-01-04 18:06:42 +000090int phys_ram_size;
91int phys_ram_fd;
92uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000093uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +000094static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000095
bellard6a00d602005-11-21 23:25:50 +000096CPUState *first_cpu;
97/* current CPU in the current thread. It is only valid inside
98 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +000099CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000100
bellard54936002003-05-13 00:25:15 +0000101typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000102 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000103 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000104 /* in order to optimize self modifying code, we count the number
105 of lookups we do to a given page to use a bitmap */
106 unsigned int code_write_count;
107 uint8_t *code_bitmap;
108#if defined(CONFIG_USER_ONLY)
109 unsigned long flags;
110#endif
bellard54936002003-05-13 00:25:15 +0000111} PageDesc;
112
bellard92e873b2004-05-21 14:52:29 +0000113typedef struct PhysPageDesc {
114 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000115 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000116} PhysPageDesc;
117
bellard54936002003-05-13 00:25:15 +0000118#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000119#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
120/* XXX: this is a temporary hack for alpha target.
121 * In the future, this is to be replaced by a multi-level table
122 * to actually be able to handle the complete 64 bits address space.
123 */
124#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
125#else
bellard54936002003-05-13 00:25:15 +0000126#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000127#endif
bellard54936002003-05-13 00:25:15 +0000128
129#define L1_SIZE (1 << L1_BITS)
130#define L2_SIZE (1 << L2_BITS)
131
bellard33417e72003-08-10 21:47:01 +0000132static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000133
bellard83fb7ad2004-07-05 21:25:26 +0000134unsigned long qemu_real_host_page_size;
135unsigned long qemu_host_page_bits;
136unsigned long qemu_host_page_size;
137unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000138
bellard92e873b2004-05-21 14:52:29 +0000139/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000140static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000141PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000142
bellard33417e72003-08-10 21:47:01 +0000143/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000144CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
145CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000146void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000147static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000148#if defined(CONFIG_SOFTMMU)
149static int io_mem_watch;
150#endif
bellard33417e72003-08-10 21:47:01 +0000151
bellard34865132003-10-05 14:28:56 +0000152/* log support */
153char *logfilename = "/tmp/qemu.log";
154FILE *logfile;
155int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000156static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000157
bellarde3db7222005-01-26 22:00:47 +0000158/* statistics */
159static int tlb_flush_count;
160static int tb_flush_count;
161static int tb_phys_invalidate_count;
162
blueswir1db7b5422007-05-26 17:36:03 +0000163#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
164typedef struct subpage_t {
165 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000166 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
167 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
168 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000169} subpage_t;
170
bellardb346ff42003-06-15 20:05:50 +0000171static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000172{
bellard83fb7ad2004-07-05 21:25:26 +0000173 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000174 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000175#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000176 {
177 SYSTEM_INFO system_info;
178 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000179
bellardd5a8f072004-09-29 21:15:28 +0000180 GetSystemInfo(&system_info);
181 qemu_real_host_page_size = system_info.dwPageSize;
ths3b46e622007-09-17 08:09:54 +0000182
bellardd5a8f072004-09-29 21:15:28 +0000183 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
184 PAGE_EXECUTE_READWRITE, &old_protect);
185 }
bellard67b915a2004-03-31 23:37:16 +0000186#else
bellard83fb7ad2004-07-05 21:25:26 +0000187 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000188 {
189 unsigned long start, end;
190
191 start = (unsigned long)code_gen_buffer;
192 start &= ~(qemu_real_host_page_size - 1);
ths3b46e622007-09-17 08:09:54 +0000193
bellardd5a8f072004-09-29 21:15:28 +0000194 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
195 end += qemu_real_host_page_size - 1;
196 end &= ~(qemu_real_host_page_size - 1);
ths3b46e622007-09-17 08:09:54 +0000197
ths5fafdf22007-09-16 21:08:06 +0000198 mprotect((void *)start, end - start,
bellardd5a8f072004-09-29 21:15:28 +0000199 PROT_READ | PROT_WRITE | PROT_EXEC);
200 }
bellard67b915a2004-03-31 23:37:16 +0000201#endif
bellardd5a8f072004-09-29 21:15:28 +0000202
bellard83fb7ad2004-07-05 21:25:26 +0000203 if (qemu_host_page_size == 0)
204 qemu_host_page_size = qemu_real_host_page_size;
205 if (qemu_host_page_size < TARGET_PAGE_SIZE)
206 qemu_host_page_size = TARGET_PAGE_SIZE;
207 qemu_host_page_bits = 0;
208 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
209 qemu_host_page_bits++;
210 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000211 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
212 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000213
214#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
215 {
216 long long startaddr, endaddr;
217 FILE *f;
218 int n;
219
220 f = fopen("/proc/self/maps", "r");
221 if (f) {
222 do {
223 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
224 if (n == 2) {
225 page_set_flags(TARGET_PAGE_ALIGN(startaddr),
226 TARGET_PAGE_ALIGN(endaddr),
227 PAGE_RESERVED);
228 }
229 } while (!feof(f));
230 fclose(f);
231 }
232 }
233#endif
bellard54936002003-05-13 00:25:15 +0000234}
235
bellardfd6ce8f2003-05-14 19:00:11 +0000236static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000237{
bellard54936002003-05-13 00:25:15 +0000238 PageDesc **lp, *p;
239
bellard54936002003-05-13 00:25:15 +0000240 lp = &l1_map[index >> L2_BITS];
241 p = *lp;
242 if (!p) {
243 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000244 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000245 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000246 *lp = p;
247 }
248 return p + (index & (L2_SIZE - 1));
249}
250
bellardfd6ce8f2003-05-14 19:00:11 +0000251static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000252{
bellard54936002003-05-13 00:25:15 +0000253 PageDesc *p;
254
bellard54936002003-05-13 00:25:15 +0000255 p = l1_map[index >> L2_BITS];
256 if (!p)
257 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000258 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000259}
260
bellard108c49b2005-07-24 12:55:09 +0000261static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000262{
bellard108c49b2005-07-24 12:55:09 +0000263 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000264 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000265
bellard108c49b2005-07-24 12:55:09 +0000266 p = (void **)l1_phys_map;
267#if TARGET_PHYS_ADDR_SPACE_BITS > 32
268
269#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
270#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
271#endif
272 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000273 p = *lp;
274 if (!p) {
275 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000276 if (!alloc)
277 return NULL;
278 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
279 memset(p, 0, sizeof(void *) * L1_SIZE);
280 *lp = p;
281 }
282#endif
283 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000284 pd = *lp;
285 if (!pd) {
286 int i;
bellard108c49b2005-07-24 12:55:09 +0000287 /* allocate if not found */
288 if (!alloc)
289 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000290 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
291 *lp = pd;
292 for (i = 0; i < L2_SIZE; i++)
293 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000294 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000295 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000296}
297
bellard108c49b2005-07-24 12:55:09 +0000298static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000299{
bellard108c49b2005-07-24 12:55:09 +0000300 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000301}
302
bellard9fa3e852004-01-04 18:06:42 +0000303#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000304static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000305static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000306 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000307#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000308
bellard6a00d602005-11-21 23:25:50 +0000309void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000310{
bellard6a00d602005-11-21 23:25:50 +0000311 CPUState **penv;
312 int cpu_index;
313
bellardfd6ce8f2003-05-14 19:00:11 +0000314 if (!code_gen_ptr) {
bellard57fec1f2008-02-01 10:50:11 +0000315 cpu_gen_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000316 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000317 page_init();
bellard33417e72003-08-10 21:47:01 +0000318 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000319 }
bellard6a00d602005-11-21 23:25:50 +0000320 env->next_cpu = NULL;
321 penv = &first_cpu;
322 cpu_index = 0;
323 while (*penv != NULL) {
324 penv = (CPUState **)&(*penv)->next_cpu;
325 cpu_index++;
326 }
327 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000328 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000329 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000330}
331
bellard9fa3e852004-01-04 18:06:42 +0000332static inline void invalidate_page_bitmap(PageDesc *p)
333{
334 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000335 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000336 p->code_bitmap = NULL;
337 }
338 p->code_write_count = 0;
339}
340
bellardfd6ce8f2003-05-14 19:00:11 +0000341/* set to NULL all the 'first_tb' fields in all PageDescs */
342static void page_flush_tb(void)
343{
344 int i, j;
345 PageDesc *p;
346
347 for(i = 0; i < L1_SIZE; i++) {
348 p = l1_map[i];
349 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000350 for(j = 0; j < L2_SIZE; j++) {
351 p->first_tb = NULL;
352 invalidate_page_bitmap(p);
353 p++;
354 }
bellardfd6ce8f2003-05-14 19:00:11 +0000355 }
356 }
357}
358
359/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000360/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000361void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000362{
bellard6a00d602005-11-21 23:25:50 +0000363 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000364#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000365 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
366 (unsigned long)(code_gen_ptr - code_gen_buffer),
367 nb_tbs, nb_tbs > 0 ?
368 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000369#endif
370 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000371
bellard6a00d602005-11-21 23:25:50 +0000372 for(env = first_cpu; env != NULL; env = env->next_cpu) {
373 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
374 }
bellard9fa3e852004-01-04 18:06:42 +0000375
bellard8a8a6082004-10-03 13:36:49 +0000376 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000377 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000378
bellardfd6ce8f2003-05-14 19:00:11 +0000379 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000380 /* XXX: flush processor icache at this point if cache flush is
381 expensive */
bellarde3db7222005-01-26 22:00:47 +0000382 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000383}
384
385#ifdef DEBUG_TB_CHECK
386
j_mayerbc98a7e2007-04-04 07:55:12 +0000387static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000388{
389 TranslationBlock *tb;
390 int i;
391 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000392 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
393 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000394 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
395 address >= tb->pc + tb->size)) {
396 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000397 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000398 }
399 }
400 }
401}
402
403/* verify that all the pages have correct rights for code */
404static void tb_page_check(void)
405{
406 TranslationBlock *tb;
407 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000408
pbrook99773bd2006-04-16 15:14:59 +0000409 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
410 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000411 flags1 = page_get_flags(tb->pc);
412 flags2 = page_get_flags(tb->pc + tb->size - 1);
413 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
414 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000415 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000416 }
417 }
418 }
419}
420
bellardd4e81642003-05-25 16:46:15 +0000421void tb_jmp_check(TranslationBlock *tb)
422{
423 TranslationBlock *tb1;
424 unsigned int n1;
425
426 /* suppress any remaining jumps to this TB */
427 tb1 = tb->jmp_first;
428 for(;;) {
429 n1 = (long)tb1 & 3;
430 tb1 = (TranslationBlock *)((long)tb1 & ~3);
431 if (n1 == 2)
432 break;
433 tb1 = tb1->jmp_next[n1];
434 }
435 /* check end of list */
436 if (tb1 != tb) {
437 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
438 }
439}
440
bellardfd6ce8f2003-05-14 19:00:11 +0000441#endif
442
443/* invalidate one TB */
444static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
445 int next_offset)
446{
447 TranslationBlock *tb1;
448 for(;;) {
449 tb1 = *ptb;
450 if (tb1 == tb) {
451 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
452 break;
453 }
454 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
455 }
456}
457
bellard9fa3e852004-01-04 18:06:42 +0000458static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
459{
460 TranslationBlock *tb1;
461 unsigned int n1;
462
463 for(;;) {
464 tb1 = *ptb;
465 n1 = (long)tb1 & 3;
466 tb1 = (TranslationBlock *)((long)tb1 & ~3);
467 if (tb1 == tb) {
468 *ptb = tb1->page_next[n1];
469 break;
470 }
471 ptb = &tb1->page_next[n1];
472 }
473}
474
bellardd4e81642003-05-25 16:46:15 +0000475static inline void tb_jmp_remove(TranslationBlock *tb, int n)
476{
477 TranslationBlock *tb1, **ptb;
478 unsigned int n1;
479
480 ptb = &tb->jmp_next[n];
481 tb1 = *ptb;
482 if (tb1) {
483 /* find tb(n) in circular list */
484 for(;;) {
485 tb1 = *ptb;
486 n1 = (long)tb1 & 3;
487 tb1 = (TranslationBlock *)((long)tb1 & ~3);
488 if (n1 == n && tb1 == tb)
489 break;
490 if (n1 == 2) {
491 ptb = &tb1->jmp_first;
492 } else {
493 ptb = &tb1->jmp_next[n1];
494 }
495 }
496 /* now we can suppress tb(n) from the list */
497 *ptb = tb->jmp_next[n];
498
499 tb->jmp_next[n] = NULL;
500 }
501}
502
503/* reset the jump entry 'n' of a TB so that it is not chained to
504 another TB */
505static inline void tb_reset_jump(TranslationBlock *tb, int n)
506{
507 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
508}
509
bellard9fa3e852004-01-04 18:06:42 +0000510static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000511{
bellard6a00d602005-11-21 23:25:50 +0000512 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000513 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000514 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000515 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000516 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000517
bellard9fa3e852004-01-04 18:06:42 +0000518 /* remove the TB from the hash list */
519 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
520 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000521 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000522 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000523
bellard9fa3e852004-01-04 18:06:42 +0000524 /* remove the TB from the page list */
525 if (tb->page_addr[0] != page_addr) {
526 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
527 tb_page_remove(&p->first_tb, tb);
528 invalidate_page_bitmap(p);
529 }
530 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
531 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
532 tb_page_remove(&p->first_tb, tb);
533 invalidate_page_bitmap(p);
534 }
535
bellard8a40a182005-11-20 10:35:40 +0000536 tb_invalidated_flag = 1;
537
538 /* remove the TB from the hash list */
539 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000540 for(env = first_cpu; env != NULL; env = env->next_cpu) {
541 if (env->tb_jmp_cache[h] == tb)
542 env->tb_jmp_cache[h] = NULL;
543 }
bellard8a40a182005-11-20 10:35:40 +0000544
545 /* suppress this TB from the two jump lists */
546 tb_jmp_remove(tb, 0);
547 tb_jmp_remove(tb, 1);
548
549 /* suppress any remaining jumps to this TB */
550 tb1 = tb->jmp_first;
551 for(;;) {
552 n1 = (long)tb1 & 3;
553 if (n1 == 2)
554 break;
555 tb1 = (TranslationBlock *)((long)tb1 & ~3);
556 tb2 = tb1->jmp_next[n1];
557 tb_reset_jump(tb1, n1);
558 tb1->jmp_next[n1] = NULL;
559 tb1 = tb2;
560 }
561 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
562
bellarde3db7222005-01-26 22:00:47 +0000563 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000564}
565
566static inline void set_bits(uint8_t *tab, int start, int len)
567{
568 int end, mask, end1;
569
570 end = start + len;
571 tab += start >> 3;
572 mask = 0xff << (start & 7);
573 if ((start & ~7) == (end & ~7)) {
574 if (start < end) {
575 mask &= ~(0xff << (end & 7));
576 *tab |= mask;
577 }
578 } else {
579 *tab++ |= mask;
580 start = (start + 8) & ~7;
581 end1 = end & ~7;
582 while (start < end1) {
583 *tab++ = 0xff;
584 start += 8;
585 }
586 if (start < end) {
587 mask = ~(0xff << (end & 7));
588 *tab |= mask;
589 }
590 }
591}
592
593static void build_page_bitmap(PageDesc *p)
594{
595 int n, tb_start, tb_end;
596 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000597
bellard59817cc2004-02-16 22:01:13 +0000598 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000599 if (!p->code_bitmap)
600 return;
601 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
602
603 tb = p->first_tb;
604 while (tb != NULL) {
605 n = (long)tb & 3;
606 tb = (TranslationBlock *)((long)tb & ~3);
607 /* NOTE: this is subtle as a TB may span two physical pages */
608 if (n == 0) {
609 /* NOTE: tb_end may be after the end of the page, but
610 it is not a problem */
611 tb_start = tb->pc & ~TARGET_PAGE_MASK;
612 tb_end = tb_start + tb->size;
613 if (tb_end > TARGET_PAGE_SIZE)
614 tb_end = TARGET_PAGE_SIZE;
615 } else {
616 tb_start = 0;
617 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
618 }
619 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
620 tb = tb->page_next[n];
621 }
622}
623
bellardd720b932004-04-25 17:57:43 +0000624#ifdef TARGET_HAS_PRECISE_SMC
625
ths5fafdf22007-09-16 21:08:06 +0000626static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000627 target_ulong pc, target_ulong cs_base, int flags,
628 int cflags)
629{
630 TranslationBlock *tb;
631 uint8_t *tc_ptr;
632 target_ulong phys_pc, phys_page2, virt_page2;
633 int code_gen_size;
634
bellardc27004e2005-01-03 23:35:10 +0000635 phys_pc = get_phys_addr_code(env, pc);
636 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000637 if (!tb) {
638 /* flush must be done */
639 tb_flush(env);
640 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000641 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000642 }
643 tc_ptr = code_gen_ptr;
644 tb->tc_ptr = tc_ptr;
645 tb->cs_base = cs_base;
646 tb->flags = flags;
647 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000648 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000649 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
ths3b46e622007-09-17 08:09:54 +0000650
bellardd720b932004-04-25 17:57:43 +0000651 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000652 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000653 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000654 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000655 phys_page2 = get_phys_addr_code(env, virt_page2);
656 }
657 tb_link_phys(tb, phys_pc, phys_page2);
658}
659#endif
ths3b46e622007-09-17 08:09:54 +0000660
bellard9fa3e852004-01-04 18:06:42 +0000661/* invalidate all TBs which intersect with the target physical page
662 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000663 the same physical page. 'is_cpu_write_access' should be true if called
664 from a real cpu write access: the virtual CPU will exit the current
665 TB if code is modified inside this TB. */
ths5fafdf22007-09-16 21:08:06 +0000666void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
bellardd720b932004-04-25 17:57:43 +0000667 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000668{
bellardd720b932004-04-25 17:57:43 +0000669 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000670 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000671 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000672 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000673 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000674 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000675
676 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000677 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000678 return;
ths5fafdf22007-09-16 21:08:06 +0000679 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000680 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
681 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000682 /* build code bitmap */
683 build_page_bitmap(p);
684 }
685
686 /* we remove all the TBs in the range [start, end[ */
687 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000688 current_tb_not_found = is_cpu_write_access;
689 current_tb_modified = 0;
690 current_tb = NULL; /* avoid warning */
691 current_pc = 0; /* avoid warning */
692 current_cs_base = 0; /* avoid warning */
693 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000694 tb = p->first_tb;
695 while (tb != NULL) {
696 n = (long)tb & 3;
697 tb = (TranslationBlock *)((long)tb & ~3);
698 tb_next = tb->page_next[n];
699 /* NOTE: this is subtle as a TB may span two physical pages */
700 if (n == 0) {
701 /* NOTE: tb_end may be after the end of the page, but
702 it is not a problem */
703 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
704 tb_end = tb_start + tb->size;
705 } else {
706 tb_start = tb->page_addr[1];
707 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
708 }
709 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000710#ifdef TARGET_HAS_PRECISE_SMC
711 if (current_tb_not_found) {
712 current_tb_not_found = 0;
713 current_tb = NULL;
714 if (env->mem_write_pc) {
715 /* now we have a real cpu fault */
716 current_tb = tb_find_pc(env->mem_write_pc);
717 }
718 }
719 if (current_tb == tb &&
720 !(current_tb->cflags & CF_SINGLE_INSN)) {
721 /* If we are modifying the current TB, we must stop
722 its execution. We could be more precise by checking
723 that the modification is after the current PC, but it
724 would require a specialized function to partially
725 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000726
bellardd720b932004-04-25 17:57:43 +0000727 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000728 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000729 env->mem_write_pc, NULL);
730#if defined(TARGET_I386)
731 current_flags = env->hflags;
732 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
733 current_cs_base = (target_ulong)env->segs[R_CS].base;
734 current_pc = current_cs_base + env->eip;
735#else
736#error unsupported CPU
737#endif
738 }
739#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000740 /* we need to do that to handle the case where a signal
741 occurs while doing tb_phys_invalidate() */
742 saved_tb = NULL;
743 if (env) {
744 saved_tb = env->current_tb;
745 env->current_tb = NULL;
746 }
bellard9fa3e852004-01-04 18:06:42 +0000747 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000748 if (env) {
749 env->current_tb = saved_tb;
750 if (env->interrupt_request && env->current_tb)
751 cpu_interrupt(env, env->interrupt_request);
752 }
bellard9fa3e852004-01-04 18:06:42 +0000753 }
754 tb = tb_next;
755 }
756#if !defined(CONFIG_USER_ONLY)
757 /* if no code remaining, no need to continue to use slow writes */
758 if (!p->first_tb) {
759 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000760 if (is_cpu_write_access) {
761 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
762 }
763 }
764#endif
765#ifdef TARGET_HAS_PRECISE_SMC
766 if (current_tb_modified) {
767 /* we generate a block containing just the instruction
768 modifying the memory. It will ensure that it cannot modify
769 itself */
bellardea1c1802004-06-14 18:56:36 +0000770 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000771 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000772 CF_SINGLE_INSN);
773 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000774 }
775#endif
776}
777
778/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000779static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000780{
781 PageDesc *p;
782 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000783#if 0
bellarda4193c82004-06-03 14:01:43 +0000784 if (1) {
785 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000786 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
787 cpu_single_env->mem_write_vaddr, len,
788 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000789 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
790 }
bellard59817cc2004-02-16 22:01:13 +0000791 }
792#endif
bellard9fa3e852004-01-04 18:06:42 +0000793 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000794 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000795 return;
796 if (p->code_bitmap) {
797 offset = start & ~TARGET_PAGE_MASK;
798 b = p->code_bitmap[offset >> 3] >> (offset & 7);
799 if (b & ((1 << len) - 1))
800 goto do_invalidate;
801 } else {
802 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000803 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000804 }
805}
806
bellard9fa3e852004-01-04 18:06:42 +0000807#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +0000808static void tb_invalidate_phys_page(target_ulong addr,
bellardd720b932004-04-25 17:57:43 +0000809 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000810{
bellardd720b932004-04-25 17:57:43 +0000811 int n, current_flags, current_tb_modified;
812 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000813 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000814 TranslationBlock *tb, *current_tb;
815#ifdef TARGET_HAS_PRECISE_SMC
816 CPUState *env = cpu_single_env;
817#endif
bellard9fa3e852004-01-04 18:06:42 +0000818
819 addr &= TARGET_PAGE_MASK;
820 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000821 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000822 return;
823 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000824 current_tb_modified = 0;
825 current_tb = NULL;
826 current_pc = 0; /* avoid warning */
827 current_cs_base = 0; /* avoid warning */
828 current_flags = 0; /* avoid warning */
829#ifdef TARGET_HAS_PRECISE_SMC
830 if (tb && pc != 0) {
831 current_tb = tb_find_pc(pc);
832 }
833#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000834 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000835 n = (long)tb & 3;
836 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000837#ifdef TARGET_HAS_PRECISE_SMC
838 if (current_tb == tb &&
839 !(current_tb->cflags & CF_SINGLE_INSN)) {
840 /* If we are modifying the current TB, we must stop
841 its execution. We could be more precise by checking
842 that the modification is after the current PC, but it
843 would require a specialized function to partially
844 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000845
bellardd720b932004-04-25 17:57:43 +0000846 current_tb_modified = 1;
847 cpu_restore_state(current_tb, env, pc, puc);
848#if defined(TARGET_I386)
849 current_flags = env->hflags;
850 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
851 current_cs_base = (target_ulong)env->segs[R_CS].base;
852 current_pc = current_cs_base + env->eip;
853#else
854#error unsupported CPU
855#endif
856 }
857#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000858 tb_phys_invalidate(tb, addr);
859 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000860 }
861 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000862#ifdef TARGET_HAS_PRECISE_SMC
863 if (current_tb_modified) {
864 /* we generate a block containing just the instruction
865 modifying the memory. It will ensure that it cannot modify
866 itself */
bellardea1c1802004-06-14 18:56:36 +0000867 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000868 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000869 CF_SINGLE_INSN);
870 cpu_resume_from_signal(env, puc);
871 }
872#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000873}
bellard9fa3e852004-01-04 18:06:42 +0000874#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000875
876/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000877static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000878 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000879{
880 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000881 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000882
bellard9fa3e852004-01-04 18:06:42 +0000883 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000884 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000885 tb->page_next[n] = p->first_tb;
886 last_first_tb = p->first_tb;
887 p->first_tb = (TranslationBlock *)((long)tb | n);
888 invalidate_page_bitmap(p);
889
bellard107db442004-06-22 18:48:46 +0000890#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000891
bellard9fa3e852004-01-04 18:06:42 +0000892#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000893 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000894 target_ulong addr;
895 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000896 int prot;
897
bellardfd6ce8f2003-05-14 19:00:11 +0000898 /* force the host page as non writable (writes will have a
899 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000900 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000901 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000902 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
903 addr += TARGET_PAGE_SIZE) {
904
905 p2 = page_find (addr >> TARGET_PAGE_BITS);
906 if (!p2)
907 continue;
908 prot |= p2->flags;
909 p2->flags &= ~PAGE_WRITE;
910 page_get_flags(addr);
911 }
ths5fafdf22007-09-16 21:08:06 +0000912 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000913 (prot & PAGE_BITS) & ~PAGE_WRITE);
914#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +0000915 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +0000916 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000917#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000918 }
bellard9fa3e852004-01-04 18:06:42 +0000919#else
920 /* if some code is already present, then the pages are already
921 protected. So we handle the case where only the first TB is
922 allocated in a physical page */
923 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000924 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000925 }
926#endif
bellardd720b932004-04-25 17:57:43 +0000927
928#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000929}
930
931/* Allocate a new translation block. Flush the translation buffer if
932 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000933TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000934{
935 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000936
ths5fafdf22007-09-16 21:08:06 +0000937 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
bellardfd6ce8f2003-05-14 19:00:11 +0000938 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000939 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000940 tb = &tbs[nb_tbs++];
941 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000942 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000943 return tb;
944}
945
bellard9fa3e852004-01-04 18:06:42 +0000946/* add a new TB and link it to the physical page tables. phys_page2 is
947 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +0000948void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +0000949 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000950{
bellard9fa3e852004-01-04 18:06:42 +0000951 unsigned int h;
952 TranslationBlock **ptb;
953
954 /* add in the physical hash table */
955 h = tb_phys_hash_func(phys_pc);
956 ptb = &tb_phys_hash[h];
957 tb->phys_hash_next = *ptb;
958 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000959
960 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000961 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
962 if (phys_page2 != -1)
963 tb_alloc_page(tb, 1, phys_page2);
964 else
965 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000966
bellardd4e81642003-05-25 16:46:15 +0000967 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
968 tb->jmp_next[0] = NULL;
969 tb->jmp_next[1] = NULL;
970
971 /* init original jump addresses */
972 if (tb->tb_next_offset[0] != 0xffff)
973 tb_reset_jump(tb, 0);
974 if (tb->tb_next_offset[1] != 0xffff)
975 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000976
977#ifdef DEBUG_TB_CHECK
978 tb_page_check();
979#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000980}
981
bellarda513fe12003-05-27 23:29:48 +0000982/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
983 tb[1].tc_ptr. Return NULL if not found */
984TranslationBlock *tb_find_pc(unsigned long tc_ptr)
985{
986 int m_min, m_max, m;
987 unsigned long v;
988 TranslationBlock *tb;
989
990 if (nb_tbs <= 0)
991 return NULL;
992 if (tc_ptr < (unsigned long)code_gen_buffer ||
993 tc_ptr >= (unsigned long)code_gen_ptr)
994 return NULL;
995 /* binary search (cf Knuth) */
996 m_min = 0;
997 m_max = nb_tbs - 1;
998 while (m_min <= m_max) {
999 m = (m_min + m_max) >> 1;
1000 tb = &tbs[m];
1001 v = (unsigned long)tb->tc_ptr;
1002 if (v == tc_ptr)
1003 return tb;
1004 else if (tc_ptr < v) {
1005 m_max = m - 1;
1006 } else {
1007 m_min = m + 1;
1008 }
ths5fafdf22007-09-16 21:08:06 +00001009 }
bellarda513fe12003-05-27 23:29:48 +00001010 return &tbs[m_max];
1011}
bellard75012672003-06-21 13:11:07 +00001012
bellardea041c02003-06-25 16:16:50 +00001013static void tb_reset_jump_recursive(TranslationBlock *tb);
1014
1015static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1016{
1017 TranslationBlock *tb1, *tb_next, **ptb;
1018 unsigned int n1;
1019
1020 tb1 = tb->jmp_next[n];
1021 if (tb1 != NULL) {
1022 /* find head of list */
1023 for(;;) {
1024 n1 = (long)tb1 & 3;
1025 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1026 if (n1 == 2)
1027 break;
1028 tb1 = tb1->jmp_next[n1];
1029 }
1030 /* we are now sure now that tb jumps to tb1 */
1031 tb_next = tb1;
1032
1033 /* remove tb from the jmp_first list */
1034 ptb = &tb_next->jmp_first;
1035 for(;;) {
1036 tb1 = *ptb;
1037 n1 = (long)tb1 & 3;
1038 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1039 if (n1 == n && tb1 == tb)
1040 break;
1041 ptb = &tb1->jmp_next[n1];
1042 }
1043 *ptb = tb->jmp_next[n];
1044 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001045
bellardea041c02003-06-25 16:16:50 +00001046 /* suppress the jump to next tb in generated code */
1047 tb_reset_jump(tb, n);
1048
bellard01243112004-01-04 15:48:17 +00001049 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001050 tb_reset_jump_recursive(tb_next);
1051 }
1052}
1053
1054static void tb_reset_jump_recursive(TranslationBlock *tb)
1055{
1056 tb_reset_jump_recursive2(tb, 0);
1057 tb_reset_jump_recursive2(tb, 1);
1058}
1059
bellard1fddef42005-04-17 19:16:13 +00001060#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001061static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1062{
j_mayer9b3c35e2007-04-07 11:21:28 +00001063 target_phys_addr_t addr;
1064 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001065 ram_addr_t ram_addr;
1066 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001067
pbrookc2f07f82006-04-08 17:14:56 +00001068 addr = cpu_get_phys_page_debug(env, pc);
1069 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1070 if (!p) {
1071 pd = IO_MEM_UNASSIGNED;
1072 } else {
1073 pd = p->phys_offset;
1074 }
1075 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001076 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001077}
bellardc27004e2005-01-03 23:35:10 +00001078#endif
bellardd720b932004-04-25 17:57:43 +00001079
pbrook6658ffb2007-03-16 23:58:11 +00001080/* Add a watchpoint. */
1081int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1082{
1083 int i;
1084
1085 for (i = 0; i < env->nb_watchpoints; i++) {
1086 if (addr == env->watchpoint[i].vaddr)
1087 return 0;
1088 }
1089 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1090 return -1;
1091
1092 i = env->nb_watchpoints++;
1093 env->watchpoint[i].vaddr = addr;
1094 tlb_flush_page(env, addr);
1095 /* FIXME: This flush is needed because of the hack to make memory ops
1096 terminate the TB. It can be removed once the proper IO trap and
1097 re-execute bits are in. */
1098 tb_flush(env);
1099 return i;
1100}
1101
1102/* Remove a watchpoint. */
1103int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1104{
1105 int i;
1106
1107 for (i = 0; i < env->nb_watchpoints; i++) {
1108 if (addr == env->watchpoint[i].vaddr) {
1109 env->nb_watchpoints--;
1110 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1111 tlb_flush_page(env, addr);
1112 return 0;
1113 }
1114 }
1115 return -1;
1116}
1117
bellardc33a3462003-07-29 20:50:33 +00001118/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1119 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001120int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001121{
bellard1fddef42005-04-17 19:16:13 +00001122#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001123 int i;
ths3b46e622007-09-17 08:09:54 +00001124
bellard4c3a88a2003-07-26 12:06:08 +00001125 for(i = 0; i < env->nb_breakpoints; i++) {
1126 if (env->breakpoints[i] == pc)
1127 return 0;
1128 }
1129
1130 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1131 return -1;
1132 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001133
bellardd720b932004-04-25 17:57:43 +00001134 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001135 return 0;
1136#else
1137 return -1;
1138#endif
1139}
1140
1141/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001142int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001143{
bellard1fddef42005-04-17 19:16:13 +00001144#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001145 int i;
1146 for(i = 0; i < env->nb_breakpoints; i++) {
1147 if (env->breakpoints[i] == pc)
1148 goto found;
1149 }
1150 return -1;
1151 found:
bellard4c3a88a2003-07-26 12:06:08 +00001152 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001153 if (i < env->nb_breakpoints)
1154 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001155
1156 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001157 return 0;
1158#else
1159 return -1;
1160#endif
1161}
1162
bellardc33a3462003-07-29 20:50:33 +00001163/* enable or disable single step mode. EXCP_DEBUG is returned by the
1164 CPU loop after each instruction */
1165void cpu_single_step(CPUState *env, int enabled)
1166{
bellard1fddef42005-04-17 19:16:13 +00001167#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001168 if (env->singlestep_enabled != enabled) {
1169 env->singlestep_enabled = enabled;
1170 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001171 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001172 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001173 }
1174#endif
1175}
1176
bellard34865132003-10-05 14:28:56 +00001177/* enable or disable low levels log */
1178void cpu_set_log(int log_flags)
1179{
1180 loglevel = log_flags;
1181 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001182 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001183 if (!logfile) {
1184 perror(logfilename);
1185 _exit(1);
1186 }
bellard9fa3e852004-01-04 18:06:42 +00001187#if !defined(CONFIG_SOFTMMU)
1188 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1189 {
1190 static uint8_t logfile_buf[4096];
1191 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1192 }
1193#else
bellard34865132003-10-05 14:28:56 +00001194 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001195#endif
pbrooke735b912007-06-30 13:53:24 +00001196 log_append = 1;
1197 }
1198 if (!loglevel && logfile) {
1199 fclose(logfile);
1200 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001201 }
1202}
1203
1204void cpu_set_log_filename(const char *filename)
1205{
1206 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001207 if (logfile) {
1208 fclose(logfile);
1209 logfile = NULL;
1210 }
1211 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001212}
bellardc33a3462003-07-29 20:50:33 +00001213
bellard01243112004-01-04 15:48:17 +00001214/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001215void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001216{
1217 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001218 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001219
bellard68a79312003-06-30 13:12:32 +00001220 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001221 /* if the cpu is currently executing code, we must unlink it and
1222 all the potentially executing TB */
1223 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001224 if (tb && !testandset(&interrupt_lock)) {
1225 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001226 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001227 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001228 }
1229}
1230
bellardb54ad042004-05-20 13:42:52 +00001231void cpu_reset_interrupt(CPUState *env, int mask)
1232{
1233 env->interrupt_request &= ~mask;
1234}
1235
bellardf193c792004-03-21 17:06:25 +00001236CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001237 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001238 "show generated host assembly code for each compiled TB" },
1239 { CPU_LOG_TB_IN_ASM, "in_asm",
1240 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001241 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001242 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001243 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001244 "show micro ops "
1245#ifdef TARGET_I386
1246 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001247#endif
blueswir1e01a1152008-03-14 17:37:11 +00001248 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001249 { CPU_LOG_INT, "int",
1250 "show interrupts/exceptions in short format" },
1251 { CPU_LOG_EXEC, "exec",
1252 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001253 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001254 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001255#ifdef TARGET_I386
1256 { CPU_LOG_PCALL, "pcall",
1257 "show protected mode far calls/returns/exceptions" },
1258#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001259#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001260 { CPU_LOG_IOPORT, "ioport",
1261 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001262#endif
bellardf193c792004-03-21 17:06:25 +00001263 { 0, NULL, NULL },
1264};
1265
1266static int cmp1(const char *s1, int n, const char *s2)
1267{
1268 if (strlen(s2) != n)
1269 return 0;
1270 return memcmp(s1, s2, n) == 0;
1271}
ths3b46e622007-09-17 08:09:54 +00001272
bellardf193c792004-03-21 17:06:25 +00001273/* takes a comma separated list of log masks. Return 0 if error. */
1274int cpu_str_to_log_mask(const char *str)
1275{
1276 CPULogItem *item;
1277 int mask;
1278 const char *p, *p1;
1279
1280 p = str;
1281 mask = 0;
1282 for(;;) {
1283 p1 = strchr(p, ',');
1284 if (!p1)
1285 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001286 if(cmp1(p,p1-p,"all")) {
1287 for(item = cpu_log_items; item->mask != 0; item++) {
1288 mask |= item->mask;
1289 }
1290 } else {
bellardf193c792004-03-21 17:06:25 +00001291 for(item = cpu_log_items; item->mask != 0; item++) {
1292 if (cmp1(p, p1 - p, item->name))
1293 goto found;
1294 }
1295 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001296 }
bellardf193c792004-03-21 17:06:25 +00001297 found:
1298 mask |= item->mask;
1299 if (*p1 != ',')
1300 break;
1301 p = p1 + 1;
1302 }
1303 return mask;
1304}
bellardea041c02003-06-25 16:16:50 +00001305
bellard75012672003-06-21 13:11:07 +00001306void cpu_abort(CPUState *env, const char *fmt, ...)
1307{
1308 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001309 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001310
1311 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001312 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001313 fprintf(stderr, "qemu: fatal: ");
1314 vfprintf(stderr, fmt, ap);
1315 fprintf(stderr, "\n");
1316#ifdef TARGET_I386
ths0573fbf2007-09-23 15:28:04 +00001317 if(env->intercept & INTERCEPT_SVM_MASK) {
1318 /* most probably the virtual machine should not
1319 be shut down but rather caught by the VMM */
1320 vmexit(SVM_EXIT_SHUTDOWN, 0);
1321 }
bellard7fe48482004-10-09 18:08:01 +00001322 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1323#else
1324 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001325#endif
balrog924edca2007-06-10 14:07:13 +00001326 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001327 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001328 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001329 fprintf(logfile, "\n");
1330#ifdef TARGET_I386
1331 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1332#else
1333 cpu_dump_state(env, logfile, fprintf, 0);
1334#endif
balrog924edca2007-06-10 14:07:13 +00001335 fflush(logfile);
1336 fclose(logfile);
1337 }
pbrook493ae1f2007-11-23 16:53:59 +00001338 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001339 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001340 abort();
1341}
1342
thsc5be9f02007-02-28 20:20:53 +00001343CPUState *cpu_copy(CPUState *env)
1344{
ths01ba9812007-12-09 02:22:57 +00001345 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001346 /* preserve chaining and index */
1347 CPUState *next_cpu = new_env->next_cpu;
1348 int cpu_index = new_env->cpu_index;
1349 memcpy(new_env, env, sizeof(CPUState));
1350 new_env->next_cpu = next_cpu;
1351 new_env->cpu_index = cpu_index;
1352 return new_env;
1353}
1354
bellard01243112004-01-04 15:48:17 +00001355#if !defined(CONFIG_USER_ONLY)
1356
bellardee8b7022004-02-03 23:35:10 +00001357/* NOTE: if flush_global is true, also flush global entries (not
1358 implemented yet) */
1359void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001360{
bellard33417e72003-08-10 21:47:01 +00001361 int i;
bellard01243112004-01-04 15:48:17 +00001362
bellard9fa3e852004-01-04 18:06:42 +00001363#if defined(DEBUG_TLB)
1364 printf("tlb_flush:\n");
1365#endif
bellard01243112004-01-04 15:48:17 +00001366 /* must reset current TB so that interrupts cannot modify the
1367 links while we are modifying them */
1368 env->current_tb = NULL;
1369
bellard33417e72003-08-10 21:47:01 +00001370 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001371 env->tlb_table[0][i].addr_read = -1;
1372 env->tlb_table[0][i].addr_write = -1;
1373 env->tlb_table[0][i].addr_code = -1;
1374 env->tlb_table[1][i].addr_read = -1;
1375 env->tlb_table[1][i].addr_write = -1;
1376 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001377#if (NB_MMU_MODES >= 3)
1378 env->tlb_table[2][i].addr_read = -1;
1379 env->tlb_table[2][i].addr_write = -1;
1380 env->tlb_table[2][i].addr_code = -1;
1381#if (NB_MMU_MODES == 4)
1382 env->tlb_table[3][i].addr_read = -1;
1383 env->tlb_table[3][i].addr_write = -1;
1384 env->tlb_table[3][i].addr_code = -1;
1385#endif
1386#endif
bellard33417e72003-08-10 21:47:01 +00001387 }
bellard9fa3e852004-01-04 18:06:42 +00001388
bellard8a40a182005-11-20 10:35:40 +00001389 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001390
1391#if !defined(CONFIG_SOFTMMU)
1392 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1393#endif
bellard0a962c02005-02-10 22:00:27 +00001394#ifdef USE_KQEMU
1395 if (env->kqemu_enabled) {
1396 kqemu_flush(env, flush_global);
1397 }
1398#endif
bellarde3db7222005-01-26 22:00:47 +00001399 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001400}
1401
bellard274da6b2004-05-20 21:56:27 +00001402static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001403{
ths5fafdf22007-09-16 21:08:06 +00001404 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001405 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001406 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001407 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001408 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001409 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1410 tlb_entry->addr_read = -1;
1411 tlb_entry->addr_write = -1;
1412 tlb_entry->addr_code = -1;
1413 }
bellard61382a52003-10-27 21:22:23 +00001414}
1415
bellard2e126692004-04-25 21:28:44 +00001416void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001417{
bellard8a40a182005-11-20 10:35:40 +00001418 int i;
bellard9fa3e852004-01-04 18:06:42 +00001419 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001420
bellard9fa3e852004-01-04 18:06:42 +00001421#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001422 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001423#endif
bellard01243112004-01-04 15:48:17 +00001424 /* must reset current TB so that interrupts cannot modify the
1425 links while we are modifying them */
1426 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001427
bellard61382a52003-10-27 21:22:23 +00001428 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001429 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001430 tlb_flush_entry(&env->tlb_table[0][i], addr);
1431 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001432#if (NB_MMU_MODES >= 3)
1433 tlb_flush_entry(&env->tlb_table[2][i], addr);
1434#if (NB_MMU_MODES == 4)
1435 tlb_flush_entry(&env->tlb_table[3][i], addr);
1436#endif
1437#endif
bellard01243112004-01-04 15:48:17 +00001438
pbrookb362e5e2006-11-12 20:40:55 +00001439 /* Discard jump cache entries for any tb which might potentially
1440 overlap the flushed page. */
1441 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1442 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1443
1444 i = tb_jmp_cache_hash_page(addr);
1445 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001446
bellard01243112004-01-04 15:48:17 +00001447#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001448 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001449 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001450#endif
bellard0a962c02005-02-10 22:00:27 +00001451#ifdef USE_KQEMU
1452 if (env->kqemu_enabled) {
1453 kqemu_flush_page(env, addr);
1454 }
1455#endif
bellard9fa3e852004-01-04 18:06:42 +00001456}
1457
bellard9fa3e852004-01-04 18:06:42 +00001458/* update the TLBs so that writes to code in the virtual page 'addr'
1459 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001460static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001461{
ths5fafdf22007-09-16 21:08:06 +00001462 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001463 ram_addr + TARGET_PAGE_SIZE,
1464 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001465}
1466
bellard9fa3e852004-01-04 18:06:42 +00001467/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001468 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001469static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001470 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001471{
bellard3a7d9292005-08-21 09:26:42 +00001472 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001473}
1474
ths5fafdf22007-09-16 21:08:06 +00001475static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001476 unsigned long start, unsigned long length)
1477{
1478 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001479 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1480 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001481 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001482 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001483 }
1484 }
1485}
1486
bellard3a7d9292005-08-21 09:26:42 +00001487void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001488 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001489{
1490 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001491 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001492 int i, mask, len;
1493 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001494
1495 start &= TARGET_PAGE_MASK;
1496 end = TARGET_PAGE_ALIGN(end);
1497
1498 length = end - start;
1499 if (length == 0)
1500 return;
bellard0a962c02005-02-10 22:00:27 +00001501 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001502#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001503 /* XXX: should not depend on cpu context */
1504 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001505 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001506 ram_addr_t addr;
1507 addr = start;
1508 for(i = 0; i < len; i++) {
1509 kqemu_set_notdirty(env, addr);
1510 addr += TARGET_PAGE_SIZE;
1511 }
bellard3a7d9292005-08-21 09:26:42 +00001512 }
1513#endif
bellardf23db162005-08-21 19:12:28 +00001514 mask = ~dirty_flags;
1515 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1516 for(i = 0; i < len; i++)
1517 p[i] &= mask;
1518
bellard1ccde1c2004-02-06 19:46:14 +00001519 /* we modify the TLB cache so that the dirty bit will be set again
1520 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001521 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001522 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1523 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001524 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001525 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001526 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001527#if (NB_MMU_MODES >= 3)
1528 for(i = 0; i < CPU_TLB_SIZE; i++)
1529 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1530#if (NB_MMU_MODES == 4)
1531 for(i = 0; i < CPU_TLB_SIZE; i++)
1532 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1533#endif
1534#endif
bellard6a00d602005-11-21 23:25:50 +00001535 }
bellard59817cc2004-02-16 22:01:13 +00001536
1537#if !defined(CONFIG_SOFTMMU)
1538 /* XXX: this is expensive */
1539 {
1540 VirtPageDesc *p;
1541 int j;
1542 target_ulong addr;
1543
1544 for(i = 0; i < L1_SIZE; i++) {
1545 p = l1_virt_map[i];
1546 if (p) {
1547 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1548 for(j = 0; j < L2_SIZE; j++) {
1549 if (p->valid_tag == virt_valid_tag &&
1550 p->phys_addr >= start && p->phys_addr < end &&
1551 (p->prot & PROT_WRITE)) {
1552 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001553 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001554 p->prot & ~PROT_WRITE);
1555 }
1556 }
1557 addr += TARGET_PAGE_SIZE;
1558 p++;
1559 }
1560 }
1561 }
1562 }
1563#endif
bellard1ccde1c2004-02-06 19:46:14 +00001564}
1565
bellard3a7d9292005-08-21 09:26:42 +00001566static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1567{
1568 ram_addr_t ram_addr;
1569
bellard84b7b8e2005-11-28 21:19:04 +00001570 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001571 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001572 tlb_entry->addend - (unsigned long)phys_ram_base;
1573 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001574 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001575 }
1576 }
1577}
1578
1579/* update the TLB according to the current state of the dirty bits */
1580void cpu_tlb_update_dirty(CPUState *env)
1581{
1582 int i;
1583 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001584 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001585 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001586 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001587#if (NB_MMU_MODES >= 3)
1588 for(i = 0; i < CPU_TLB_SIZE; i++)
1589 tlb_update_dirty(&env->tlb_table[2][i]);
1590#if (NB_MMU_MODES == 4)
1591 for(i = 0; i < CPU_TLB_SIZE; i++)
1592 tlb_update_dirty(&env->tlb_table[3][i]);
1593#endif
1594#endif
bellard3a7d9292005-08-21 09:26:42 +00001595}
1596
ths5fafdf22007-09-16 21:08:06 +00001597static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001598 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001599{
1600 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001601 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1602 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001603 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001604 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001605 }
1606 }
1607}
1608
1609/* update the TLB corresponding to virtual page vaddr and phys addr
1610 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001611static inline void tlb_set_dirty(CPUState *env,
1612 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001613{
bellard1ccde1c2004-02-06 19:46:14 +00001614 int i;
1615
bellard1ccde1c2004-02-06 19:46:14 +00001616 addr &= TARGET_PAGE_MASK;
1617 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001618 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1619 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001620#if (NB_MMU_MODES >= 3)
1621 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1622#if (NB_MMU_MODES == 4)
1623 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1624#endif
1625#endif
bellard9fa3e852004-01-04 18:06:42 +00001626}
1627
bellard59817cc2004-02-16 22:01:13 +00001628/* add a new TLB entry. At most one entry for a given virtual address
1629 is permitted. Return 0 if OK or 2 if the page could not be mapped
1630 (can only happen in non SOFTMMU mode for I/O pages or pages
1631 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001632int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1633 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001634 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001635{
bellard92e873b2004-05-21 14:52:29 +00001636 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001637 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001638 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001639 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001640 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001641 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001642 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001643 int i;
bellard9fa3e852004-01-04 18:06:42 +00001644
bellard92e873b2004-05-21 14:52:29 +00001645 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001646 if (!p) {
1647 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001648 } else {
1649 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001650 }
1651#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001652 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1653 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001654#endif
1655
1656 ret = 0;
1657#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001658 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001659#endif
1660 {
bellard2a4188a2006-06-25 21:54:59 +00001661 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001662 /* IO memory case */
1663 address = vaddr | pd;
1664 addend = paddr;
1665 } else {
1666 /* standard memory */
1667 address = vaddr;
1668 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1669 }
pbrook6658ffb2007-03-16 23:58:11 +00001670
1671 /* Make accesses to pages with watchpoints go via the
1672 watchpoint trap routines. */
1673 for (i = 0; i < env->nb_watchpoints; i++) {
1674 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1675 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001676 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001677 address = vaddr | io_mem_watch;
1678 } else {
balrogd79acba2007-06-26 20:01:13 +00001679 env->watchpoint[i].addend = pd - paddr +
1680 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001681 /* TODO: Figure out how to make read watchpoints coexist
1682 with code. */
1683 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1684 }
1685 }
1686 }
balrogd79acba2007-06-26 20:01:13 +00001687
bellard90f18422005-07-24 10:17:31 +00001688 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001689 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001690 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001691 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001692 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001693 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001694 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001695 te->addr_read = -1;
1696 }
1697 if (prot & PAGE_EXEC) {
1698 te->addr_code = address;
1699 } else {
1700 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001701 }
bellard67b915a2004-03-31 23:37:16 +00001702 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001703 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001704 (pd & IO_MEM_ROMD)) {
1705 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001706 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001707 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001708 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001709 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001710 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001711 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001712 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001713 }
1714 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001715 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001716 }
1717 }
1718#if !defined(CONFIG_SOFTMMU)
1719 else {
1720 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1721 /* IO access: no mapping is done as it will be handled by the
1722 soft MMU */
1723 if (!(env->hflags & HF_SOFTMMU_MASK))
1724 ret = 2;
1725 } else {
1726 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001727
bellard59817cc2004-02-16 22:01:13 +00001728 if (vaddr >= MMAP_AREA_END) {
1729 ret = 2;
1730 } else {
1731 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001732 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001733#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001734 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001735#endif
ths5fafdf22007-09-16 21:08:06 +00001736 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001737 !cpu_physical_memory_is_dirty(pd))) {
1738 /* ROM: we do as if code was inside */
1739 /* if code is present, we only map as read only and save the
1740 original mapping */
1741 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001742
bellard90f18422005-07-24 10:17:31 +00001743 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001744 vp->phys_addr = pd;
1745 vp->prot = prot;
1746 vp->valid_tag = virt_valid_tag;
1747 prot &= ~PAGE_WRITE;
1748 }
bellard9fa3e852004-01-04 18:06:42 +00001749 }
ths5fafdf22007-09-16 21:08:06 +00001750 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001751 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1752 if (map_addr == MAP_FAILED) {
1753 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1754 paddr, vaddr);
1755 }
bellard9fa3e852004-01-04 18:06:42 +00001756 }
1757 }
1758 }
1759#endif
1760 return ret;
1761}
1762
1763/* called from signal handler: invalidate the code and unprotect the
1764 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001765int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001766{
1767#if !defined(CONFIG_SOFTMMU)
1768 VirtPageDesc *vp;
1769
1770#if defined(DEBUG_TLB)
1771 printf("page_unprotect: addr=0x%08x\n", addr);
1772#endif
1773 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001774
1775 /* if it is not mapped, no need to worry here */
1776 if (addr >= MMAP_AREA_END)
1777 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001778 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1779 if (!vp)
1780 return 0;
1781 /* NOTE: in this case, validate_tag is _not_ tested as it
1782 validates only the code TLB */
1783 if (vp->valid_tag != virt_valid_tag)
1784 return 0;
1785 if (!(vp->prot & PAGE_WRITE))
1786 return 0;
1787#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001788 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001789 addr, vp->phys_addr, vp->prot);
1790#endif
bellard59817cc2004-02-16 22:01:13 +00001791 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1792 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1793 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001794 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001795 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001796 /* flush the code inside */
1797 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001798 return 1;
1799#else
1800 return 0;
1801#endif
bellard33417e72003-08-10 21:47:01 +00001802}
1803
bellard01243112004-01-04 15:48:17 +00001804#else
1805
bellardee8b7022004-02-03 23:35:10 +00001806void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001807{
1808}
1809
bellard2e126692004-04-25 21:28:44 +00001810void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001811{
1812}
1813
ths5fafdf22007-09-16 21:08:06 +00001814int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1815 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001816 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001817{
bellard9fa3e852004-01-04 18:06:42 +00001818 return 0;
1819}
bellard33417e72003-08-10 21:47:01 +00001820
bellard9fa3e852004-01-04 18:06:42 +00001821/* dump memory mappings */
1822void page_dump(FILE *f)
1823{
1824 unsigned long start, end;
1825 int i, j, prot, prot1;
1826 PageDesc *p;
1827
1828 fprintf(f, "%-8s %-8s %-8s %s\n",
1829 "start", "end", "size", "prot");
1830 start = -1;
1831 end = -1;
1832 prot = 0;
1833 for(i = 0; i <= L1_SIZE; i++) {
1834 if (i < L1_SIZE)
1835 p = l1_map[i];
1836 else
1837 p = NULL;
1838 for(j = 0;j < L2_SIZE; j++) {
1839 if (!p)
1840 prot1 = 0;
1841 else
1842 prot1 = p[j].flags;
1843 if (prot1 != prot) {
1844 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1845 if (start != -1) {
1846 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001847 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001848 prot & PAGE_READ ? 'r' : '-',
1849 prot & PAGE_WRITE ? 'w' : '-',
1850 prot & PAGE_EXEC ? 'x' : '-');
1851 }
1852 if (prot1 != 0)
1853 start = end;
1854 else
1855 start = -1;
1856 prot = prot1;
1857 }
1858 if (!p)
1859 break;
1860 }
bellard33417e72003-08-10 21:47:01 +00001861 }
bellard33417e72003-08-10 21:47:01 +00001862}
1863
pbrook53a59602006-03-25 19:31:22 +00001864int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001865{
bellard9fa3e852004-01-04 18:06:42 +00001866 PageDesc *p;
1867
1868 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001869 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001870 return 0;
1871 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001872}
1873
bellard9fa3e852004-01-04 18:06:42 +00001874/* modify the flags of a page and invalidate the code if
1875 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1876 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001877void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001878{
1879 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001880 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001881
1882 start = start & TARGET_PAGE_MASK;
1883 end = TARGET_PAGE_ALIGN(end);
1884 if (flags & PAGE_WRITE)
1885 flags |= PAGE_WRITE_ORG;
1886 spin_lock(&tb_lock);
1887 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1888 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1889 /* if the write protection is set, then we invalidate the code
1890 inside */
ths5fafdf22007-09-16 21:08:06 +00001891 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001892 (flags & PAGE_WRITE) &&
1893 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001894 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001895 }
1896 p->flags = flags;
1897 }
1898 spin_unlock(&tb_lock);
1899}
1900
ths3d97b402007-11-02 19:02:07 +00001901int page_check_range(target_ulong start, target_ulong len, int flags)
1902{
1903 PageDesc *p;
1904 target_ulong end;
1905 target_ulong addr;
1906
1907 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1908 start = start & TARGET_PAGE_MASK;
1909
1910 if( end < start )
1911 /* we've wrapped around */
1912 return -1;
1913 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1914 p = page_find(addr >> TARGET_PAGE_BITS);
1915 if( !p )
1916 return -1;
1917 if( !(p->flags & PAGE_VALID) )
1918 return -1;
1919
bellarddae32702007-11-14 10:51:00 +00001920 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001921 return -1;
bellarddae32702007-11-14 10:51:00 +00001922 if (flags & PAGE_WRITE) {
1923 if (!(p->flags & PAGE_WRITE_ORG))
1924 return -1;
1925 /* unprotect the page if it was put read-only because it
1926 contains translated code */
1927 if (!(p->flags & PAGE_WRITE)) {
1928 if (!page_unprotect(addr, 0, NULL))
1929 return -1;
1930 }
1931 return 0;
1932 }
ths3d97b402007-11-02 19:02:07 +00001933 }
1934 return 0;
1935}
1936
bellard9fa3e852004-01-04 18:06:42 +00001937/* called from signal handler: invalidate the code and unprotect the
1938 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001939int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001940{
1941 unsigned int page_index, prot, pindex;
1942 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001943 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001944
bellard83fb7ad2004-07-05 21:25:26 +00001945 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001946 page_index = host_start >> TARGET_PAGE_BITS;
1947 p1 = page_find(page_index);
1948 if (!p1)
1949 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001950 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001951 p = p1;
1952 prot = 0;
1953 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1954 prot |= p->flags;
1955 p++;
1956 }
1957 /* if the page was really writable, then we change its
1958 protection back to writable */
1959 if (prot & PAGE_WRITE_ORG) {
1960 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1961 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00001962 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001963 (prot & PAGE_BITS) | PAGE_WRITE);
1964 p1[pindex].flags |= PAGE_WRITE;
1965 /* and since the content will be modified, we must invalidate
1966 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001967 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001968#ifdef DEBUG_TB_CHECK
1969 tb_invalidate_check(address);
1970#endif
1971 return 1;
1972 }
1973 }
1974 return 0;
1975}
1976
bellard6a00d602005-11-21 23:25:50 +00001977static inline void tlb_set_dirty(CPUState *env,
1978 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001979{
1980}
bellard9fa3e852004-01-04 18:06:42 +00001981#endif /* defined(CONFIG_USER_ONLY) */
1982
blueswir1db7b5422007-05-26 17:36:03 +00001983static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
1984 int memory);
1985static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
1986 int orig_memory);
1987#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
1988 need_subpage) \
1989 do { \
1990 if (addr > start_addr) \
1991 start_addr2 = 0; \
1992 else { \
1993 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
1994 if (start_addr2 > 0) \
1995 need_subpage = 1; \
1996 } \
1997 \
blueswir149e9fba2007-05-30 17:25:06 +00001998 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00001999 end_addr2 = TARGET_PAGE_SIZE - 1; \
2000 else { \
2001 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2002 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2003 need_subpage = 1; \
2004 } \
2005 } while (0)
2006
bellard33417e72003-08-10 21:47:01 +00002007/* register physical memory. 'size' must be a multiple of the target
2008 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2009 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002010void cpu_register_physical_memory(target_phys_addr_t start_addr,
bellard2e126692004-04-25 21:28:44 +00002011 unsigned long size,
2012 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00002013{
bellard108c49b2005-07-24 12:55:09 +00002014 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002015 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002016 CPUState *env;
blueswir1db7b5422007-05-26 17:36:03 +00002017 unsigned long orig_size = size;
2018 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002019
bellard5fd386f2004-05-23 21:11:22 +00002020 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002021 end_addr = start_addr + (target_phys_addr_t)size;
2022 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002023 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2024 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
2025 unsigned long orig_memory = p->phys_offset;
2026 target_phys_addr_t start_addr2, end_addr2;
2027 int need_subpage = 0;
2028
2029 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2030 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002031 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002032 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2033 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2034 &p->phys_offset, orig_memory);
2035 } else {
2036 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2037 >> IO_MEM_SHIFT];
2038 }
2039 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2040 } else {
2041 p->phys_offset = phys_offset;
2042 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2043 (phys_offset & IO_MEM_ROMD))
2044 phys_offset += TARGET_PAGE_SIZE;
2045 }
2046 } else {
2047 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2048 p->phys_offset = phys_offset;
2049 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2050 (phys_offset & IO_MEM_ROMD))
2051 phys_offset += TARGET_PAGE_SIZE;
2052 else {
2053 target_phys_addr_t start_addr2, end_addr2;
2054 int need_subpage = 0;
2055
2056 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2057 end_addr2, need_subpage);
2058
blueswir14254fab2008-01-01 16:57:19 +00002059 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002060 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2061 &p->phys_offset, IO_MEM_UNASSIGNED);
2062 subpage_register(subpage, start_addr2, end_addr2,
2063 phys_offset);
2064 }
2065 }
2066 }
bellard33417e72003-08-10 21:47:01 +00002067 }
ths3b46e622007-09-17 08:09:54 +00002068
bellard9d420372006-06-25 22:25:22 +00002069 /* since each CPU stores ram addresses in its TLB cache, we must
2070 reset the modified entries */
2071 /* XXX: slow ! */
2072 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2073 tlb_flush(env, 1);
2074 }
bellard33417e72003-08-10 21:47:01 +00002075}
2076
bellardba863452006-09-24 18:41:10 +00002077/* XXX: temporary until new memory mapping API */
2078uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
2079{
2080 PhysPageDesc *p;
2081
2082 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2083 if (!p)
2084 return IO_MEM_UNASSIGNED;
2085 return p->phys_offset;
2086}
2087
bellarde9a1ab12007-02-08 23:08:38 +00002088/* XXX: better than nothing */
2089ram_addr_t qemu_ram_alloc(unsigned int size)
2090{
2091 ram_addr_t addr;
2092 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
ths5fafdf22007-09-16 21:08:06 +00002093 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
bellarde9a1ab12007-02-08 23:08:38 +00002094 size, phys_ram_size);
2095 abort();
2096 }
2097 addr = phys_ram_alloc_offset;
2098 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2099 return addr;
2100}
2101
2102void qemu_ram_free(ram_addr_t addr)
2103{
2104}
2105
bellarda4193c82004-06-03 14:01:43 +00002106static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002107{
pbrook67d3b952006-12-18 05:03:52 +00002108#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002109 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002110#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002111#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002112 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002113#elif TARGET_CRIS
2114 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002115#endif
bellard33417e72003-08-10 21:47:01 +00002116 return 0;
2117}
2118
bellarda4193c82004-06-03 14:01:43 +00002119static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002120{
pbrook67d3b952006-12-18 05:03:52 +00002121#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002122 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002123#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002124#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002125 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002126#elif TARGET_CRIS
2127 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002128#endif
bellard33417e72003-08-10 21:47:01 +00002129}
2130
2131static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2132 unassigned_mem_readb,
2133 unassigned_mem_readb,
2134 unassigned_mem_readb,
2135};
2136
2137static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2138 unassigned_mem_writeb,
2139 unassigned_mem_writeb,
2140 unassigned_mem_writeb,
2141};
2142
bellarda4193c82004-06-03 14:01:43 +00002143static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002144{
bellard3a7d9292005-08-21 09:26:42 +00002145 unsigned long ram_addr;
2146 int dirty_flags;
2147 ram_addr = addr - (unsigned long)phys_ram_base;
2148 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2149 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2150#if !defined(CONFIG_USER_ONLY)
2151 tb_invalidate_phys_page_fast(ram_addr, 1);
2152 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2153#endif
2154 }
bellardc27004e2005-01-03 23:35:10 +00002155 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002156#ifdef USE_KQEMU
2157 if (cpu_single_env->kqemu_enabled &&
2158 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2159 kqemu_modify_page(cpu_single_env, ram_addr);
2160#endif
bellardf23db162005-08-21 19:12:28 +00002161 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2162 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2163 /* we remove the notdirty callback only if the code has been
2164 flushed */
2165 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002166 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002167}
2168
bellarda4193c82004-06-03 14:01:43 +00002169static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002170{
bellard3a7d9292005-08-21 09:26:42 +00002171 unsigned long ram_addr;
2172 int dirty_flags;
2173 ram_addr = addr - (unsigned long)phys_ram_base;
2174 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2175 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2176#if !defined(CONFIG_USER_ONLY)
2177 tb_invalidate_phys_page_fast(ram_addr, 2);
2178 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2179#endif
2180 }
bellardc27004e2005-01-03 23:35:10 +00002181 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002182#ifdef USE_KQEMU
2183 if (cpu_single_env->kqemu_enabled &&
2184 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2185 kqemu_modify_page(cpu_single_env, ram_addr);
2186#endif
bellardf23db162005-08-21 19:12:28 +00002187 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2188 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2189 /* we remove the notdirty callback only if the code has been
2190 flushed */
2191 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002192 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002193}
2194
bellarda4193c82004-06-03 14:01:43 +00002195static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002196{
bellard3a7d9292005-08-21 09:26:42 +00002197 unsigned long ram_addr;
2198 int dirty_flags;
2199 ram_addr = addr - (unsigned long)phys_ram_base;
2200 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2201 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2202#if !defined(CONFIG_USER_ONLY)
2203 tb_invalidate_phys_page_fast(ram_addr, 4);
2204 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2205#endif
2206 }
bellardc27004e2005-01-03 23:35:10 +00002207 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002208#ifdef USE_KQEMU
2209 if (cpu_single_env->kqemu_enabled &&
2210 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2211 kqemu_modify_page(cpu_single_env, ram_addr);
2212#endif
bellardf23db162005-08-21 19:12:28 +00002213 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2214 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2215 /* we remove the notdirty callback only if the code has been
2216 flushed */
2217 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002218 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002219}
2220
bellard3a7d9292005-08-21 09:26:42 +00002221static CPUReadMemoryFunc *error_mem_read[3] = {
2222 NULL, /* never used */
2223 NULL, /* never used */
2224 NULL, /* never used */
2225};
2226
bellard1ccde1c2004-02-06 19:46:14 +00002227static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2228 notdirty_mem_writeb,
2229 notdirty_mem_writew,
2230 notdirty_mem_writel,
2231};
2232
pbrook6658ffb2007-03-16 23:58:11 +00002233#if defined(CONFIG_SOFTMMU)
2234/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2235 so these check for a hit then pass through to the normal out-of-line
2236 phys routines. */
2237static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2238{
2239 return ldub_phys(addr);
2240}
2241
2242static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2243{
2244 return lduw_phys(addr);
2245}
2246
2247static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2248{
2249 return ldl_phys(addr);
2250}
2251
2252/* Generate a debug exception if a watchpoint has been hit.
2253 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002254 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002255static target_ulong check_watchpoint(target_phys_addr_t addr)
2256{
2257 CPUState *env = cpu_single_env;
2258 target_ulong watch;
2259 target_ulong retaddr;
2260 int i;
2261
2262 retaddr = addr;
2263 for (i = 0; i < env->nb_watchpoints; i++) {
2264 watch = env->watchpoint[i].vaddr;
2265 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002266 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002267 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2268 cpu_single_env->watchpoint_hit = i + 1;
2269 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2270 break;
2271 }
2272 }
2273 }
2274 return retaddr;
2275}
2276
2277static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2278 uint32_t val)
2279{
2280 addr = check_watchpoint(addr);
2281 stb_phys(addr, val);
2282}
2283
2284static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2285 uint32_t val)
2286{
2287 addr = check_watchpoint(addr);
2288 stw_phys(addr, val);
2289}
2290
2291static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2292 uint32_t val)
2293{
2294 addr = check_watchpoint(addr);
2295 stl_phys(addr, val);
2296}
2297
2298static CPUReadMemoryFunc *watch_mem_read[3] = {
2299 watch_mem_readb,
2300 watch_mem_readw,
2301 watch_mem_readl,
2302};
2303
2304static CPUWriteMemoryFunc *watch_mem_write[3] = {
2305 watch_mem_writeb,
2306 watch_mem_writew,
2307 watch_mem_writel,
2308};
2309#endif
2310
blueswir1db7b5422007-05-26 17:36:03 +00002311static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2312 unsigned int len)
2313{
blueswir1db7b5422007-05-26 17:36:03 +00002314 uint32_t ret;
2315 unsigned int idx;
2316
2317 idx = SUBPAGE_IDX(addr - mmio->base);
2318#if defined(DEBUG_SUBPAGE)
2319 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2320 mmio, len, addr, idx);
2321#endif
blueswir13ee89922008-01-02 19:45:26 +00002322 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002323
2324 return ret;
2325}
2326
2327static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2328 uint32_t value, unsigned int len)
2329{
blueswir1db7b5422007-05-26 17:36:03 +00002330 unsigned int idx;
2331
2332 idx = SUBPAGE_IDX(addr - mmio->base);
2333#if defined(DEBUG_SUBPAGE)
2334 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2335 mmio, len, addr, idx, value);
2336#endif
blueswir13ee89922008-01-02 19:45:26 +00002337 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002338}
2339
2340static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2341{
2342#if defined(DEBUG_SUBPAGE)
2343 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2344#endif
2345
2346 return subpage_readlen(opaque, addr, 0);
2347}
2348
2349static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2350 uint32_t value)
2351{
2352#if defined(DEBUG_SUBPAGE)
2353 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2354#endif
2355 subpage_writelen(opaque, addr, value, 0);
2356}
2357
2358static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2359{
2360#if defined(DEBUG_SUBPAGE)
2361 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2362#endif
2363
2364 return subpage_readlen(opaque, addr, 1);
2365}
2366
2367static void subpage_writew (void *opaque, target_phys_addr_t addr,
2368 uint32_t value)
2369{
2370#if defined(DEBUG_SUBPAGE)
2371 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2372#endif
2373 subpage_writelen(opaque, addr, value, 1);
2374}
2375
2376static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2377{
2378#if defined(DEBUG_SUBPAGE)
2379 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2380#endif
2381
2382 return subpage_readlen(opaque, addr, 2);
2383}
2384
2385static void subpage_writel (void *opaque,
2386 target_phys_addr_t addr, uint32_t value)
2387{
2388#if defined(DEBUG_SUBPAGE)
2389 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2390#endif
2391 subpage_writelen(opaque, addr, value, 2);
2392}
2393
2394static CPUReadMemoryFunc *subpage_read[] = {
2395 &subpage_readb,
2396 &subpage_readw,
2397 &subpage_readl,
2398};
2399
2400static CPUWriteMemoryFunc *subpage_write[] = {
2401 &subpage_writeb,
2402 &subpage_writew,
2403 &subpage_writel,
2404};
2405
2406static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
2407 int memory)
2408{
2409 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002410 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002411
2412 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2413 return -1;
2414 idx = SUBPAGE_IDX(start);
2415 eidx = SUBPAGE_IDX(end);
2416#if defined(DEBUG_SUBPAGE)
2417 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2418 mmio, start, end, idx, eidx, memory);
2419#endif
2420 memory >>= IO_MEM_SHIFT;
2421 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002422 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002423 if (io_mem_read[memory][i]) {
2424 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2425 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2426 }
2427 if (io_mem_write[memory][i]) {
2428 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2429 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2430 }
blueswir14254fab2008-01-01 16:57:19 +00002431 }
blueswir1db7b5422007-05-26 17:36:03 +00002432 }
2433
2434 return 0;
2435}
2436
2437static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
2438 int orig_memory)
2439{
2440 subpage_t *mmio;
2441 int subpage_memory;
2442
2443 mmio = qemu_mallocz(sizeof(subpage_t));
2444 if (mmio != NULL) {
2445 mmio->base = base;
2446 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2447#if defined(DEBUG_SUBPAGE)
2448 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2449 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2450#endif
2451 *phys = subpage_memory | IO_MEM_SUBPAGE;
2452 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2453 }
2454
2455 return mmio;
2456}
2457
bellard33417e72003-08-10 21:47:01 +00002458static void io_mem_init(void)
2459{
bellard3a7d9292005-08-21 09:26:42 +00002460 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002461 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002462 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002463 io_mem_nb = 5;
2464
pbrook6658ffb2007-03-16 23:58:11 +00002465#if defined(CONFIG_SOFTMMU)
2466 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2467 watch_mem_write, NULL);
2468#endif
bellard1ccde1c2004-02-06 19:46:14 +00002469 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002470 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002471 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002472}
2473
2474/* mem_read and mem_write are arrays of functions containing the
2475 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002476 2). Functions can be omitted with a NULL function pointer. The
2477 registered functions may be modified dynamically later.
2478 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002479 modified. If it is zero, a new io zone is allocated. The return
2480 value can be used with cpu_register_physical_memory(). (-1) is
2481 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002482int cpu_register_io_memory(int io_index,
2483 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002484 CPUWriteMemoryFunc **mem_write,
2485 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002486{
blueswir14254fab2008-01-01 16:57:19 +00002487 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002488
2489 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002490 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002491 return -1;
2492 io_index = io_mem_nb++;
2493 } else {
2494 if (io_index >= IO_MEM_NB_ENTRIES)
2495 return -1;
2496 }
bellardb5ff1b32005-11-26 10:38:39 +00002497
bellard33417e72003-08-10 21:47:01 +00002498 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002499 if (!mem_read[i] || !mem_write[i])
2500 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002501 io_mem_read[io_index][i] = mem_read[i];
2502 io_mem_write[io_index][i] = mem_write[i];
2503 }
bellarda4193c82004-06-03 14:01:43 +00002504 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002505 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002506}
bellard61382a52003-10-27 21:22:23 +00002507
bellard8926b512004-10-10 15:14:20 +00002508CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2509{
2510 return io_mem_write[io_index >> IO_MEM_SHIFT];
2511}
2512
2513CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2514{
2515 return io_mem_read[io_index >> IO_MEM_SHIFT];
2516}
2517
bellard13eb76e2004-01-24 15:23:36 +00002518/* physical memory access (slow version, mainly for debug) */
2519#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002520void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002521 int len, int is_write)
2522{
2523 int l, flags;
2524 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002525 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002526
2527 while (len > 0) {
2528 page = addr & TARGET_PAGE_MASK;
2529 l = (page + TARGET_PAGE_SIZE) - addr;
2530 if (l > len)
2531 l = len;
2532 flags = page_get_flags(page);
2533 if (!(flags & PAGE_VALID))
2534 return;
2535 if (is_write) {
2536 if (!(flags & PAGE_WRITE))
2537 return;
bellard579a97f2007-11-11 14:26:47 +00002538 /* XXX: this code should not depend on lock_user */
2539 if (!(p = lock_user(VERIFY_WRITE, addr, len, 0)))
2540 /* FIXME - should this return an error rather than just fail? */
2541 return;
pbrook53a59602006-03-25 19:31:22 +00002542 memcpy(p, buf, len);
2543 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002544 } else {
2545 if (!(flags & PAGE_READ))
2546 return;
bellard579a97f2007-11-11 14:26:47 +00002547 /* XXX: this code should not depend on lock_user */
2548 if (!(p = lock_user(VERIFY_READ, addr, len, 1)))
2549 /* FIXME - should this return an error rather than just fail? */
2550 return;
pbrook53a59602006-03-25 19:31:22 +00002551 memcpy(buf, p, len);
2552 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002553 }
2554 len -= l;
2555 buf += l;
2556 addr += l;
2557 }
2558}
bellard8df1cd02005-01-28 22:37:22 +00002559
bellard13eb76e2004-01-24 15:23:36 +00002560#else
ths5fafdf22007-09-16 21:08:06 +00002561void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002562 int len, int is_write)
2563{
2564 int l, io_index;
2565 uint8_t *ptr;
2566 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002567 target_phys_addr_t page;
2568 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002569 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002570
bellard13eb76e2004-01-24 15:23:36 +00002571 while (len > 0) {
2572 page = addr & TARGET_PAGE_MASK;
2573 l = (page + TARGET_PAGE_SIZE) - addr;
2574 if (l > len)
2575 l = len;
bellard92e873b2004-05-21 14:52:29 +00002576 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002577 if (!p) {
2578 pd = IO_MEM_UNASSIGNED;
2579 } else {
2580 pd = p->phys_offset;
2581 }
ths3b46e622007-09-17 08:09:54 +00002582
bellard13eb76e2004-01-24 15:23:36 +00002583 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002584 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002585 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002586 /* XXX: could force cpu_single_env to NULL to avoid
2587 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002588 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002589 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002590 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002591 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002592 l = 4;
2593 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002594 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002595 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002596 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002597 l = 2;
2598 } else {
bellard1c213d12005-09-03 10:49:04 +00002599 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002600 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002601 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002602 l = 1;
2603 }
2604 } else {
bellardb448f2f2004-02-25 23:24:04 +00002605 unsigned long addr1;
2606 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002607 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002608 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002609 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002610 if (!cpu_physical_memory_is_dirty(addr1)) {
2611 /* invalidate code */
2612 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2613 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002614 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002615 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002616 }
bellard13eb76e2004-01-24 15:23:36 +00002617 }
2618 } else {
ths5fafdf22007-09-16 21:08:06 +00002619 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002620 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002621 /* I/O case */
2622 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2623 if (l >= 4 && ((addr & 3) == 0)) {
2624 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002625 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002626 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002627 l = 4;
2628 } else if (l >= 2 && ((addr & 1) == 0)) {
2629 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002630 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002631 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002632 l = 2;
2633 } else {
bellard1c213d12005-09-03 10:49:04 +00002634 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002635 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002636 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002637 l = 1;
2638 }
2639 } else {
2640 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002641 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002642 (addr & ~TARGET_PAGE_MASK);
2643 memcpy(buf, ptr, l);
2644 }
2645 }
2646 len -= l;
2647 buf += l;
2648 addr += l;
2649 }
2650}
bellard8df1cd02005-01-28 22:37:22 +00002651
bellardd0ecd2a2006-04-23 17:14:48 +00002652/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002653void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002654 const uint8_t *buf, int len)
2655{
2656 int l;
2657 uint8_t *ptr;
2658 target_phys_addr_t page;
2659 unsigned long pd;
2660 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002661
bellardd0ecd2a2006-04-23 17:14:48 +00002662 while (len > 0) {
2663 page = addr & TARGET_PAGE_MASK;
2664 l = (page + TARGET_PAGE_SIZE) - addr;
2665 if (l > len)
2666 l = len;
2667 p = phys_page_find(page >> TARGET_PAGE_BITS);
2668 if (!p) {
2669 pd = IO_MEM_UNASSIGNED;
2670 } else {
2671 pd = p->phys_offset;
2672 }
ths3b46e622007-09-17 08:09:54 +00002673
bellardd0ecd2a2006-04-23 17:14:48 +00002674 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002675 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2676 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002677 /* do nothing */
2678 } else {
2679 unsigned long addr1;
2680 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2681 /* ROM/RAM case */
2682 ptr = phys_ram_base + addr1;
2683 memcpy(ptr, buf, l);
2684 }
2685 len -= l;
2686 buf += l;
2687 addr += l;
2688 }
2689}
2690
2691
bellard8df1cd02005-01-28 22:37:22 +00002692/* warning: addr must be aligned */
2693uint32_t ldl_phys(target_phys_addr_t addr)
2694{
2695 int io_index;
2696 uint8_t *ptr;
2697 uint32_t val;
2698 unsigned long pd;
2699 PhysPageDesc *p;
2700
2701 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2702 if (!p) {
2703 pd = IO_MEM_UNASSIGNED;
2704 } else {
2705 pd = p->phys_offset;
2706 }
ths3b46e622007-09-17 08:09:54 +00002707
ths5fafdf22007-09-16 21:08:06 +00002708 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002709 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002710 /* I/O case */
2711 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2712 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2713 } else {
2714 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002715 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002716 (addr & ~TARGET_PAGE_MASK);
2717 val = ldl_p(ptr);
2718 }
2719 return val;
2720}
2721
bellard84b7b8e2005-11-28 21:19:04 +00002722/* warning: addr must be aligned */
2723uint64_t ldq_phys(target_phys_addr_t addr)
2724{
2725 int io_index;
2726 uint8_t *ptr;
2727 uint64_t val;
2728 unsigned long pd;
2729 PhysPageDesc *p;
2730
2731 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2732 if (!p) {
2733 pd = IO_MEM_UNASSIGNED;
2734 } else {
2735 pd = p->phys_offset;
2736 }
ths3b46e622007-09-17 08:09:54 +00002737
bellard2a4188a2006-06-25 21:54:59 +00002738 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2739 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002740 /* I/O case */
2741 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2742#ifdef TARGET_WORDS_BIGENDIAN
2743 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2744 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2745#else
2746 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2747 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2748#endif
2749 } else {
2750 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002751 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002752 (addr & ~TARGET_PAGE_MASK);
2753 val = ldq_p(ptr);
2754 }
2755 return val;
2756}
2757
bellardaab33092005-10-30 20:48:42 +00002758/* XXX: optimize */
2759uint32_t ldub_phys(target_phys_addr_t addr)
2760{
2761 uint8_t val;
2762 cpu_physical_memory_read(addr, &val, 1);
2763 return val;
2764}
2765
2766/* XXX: optimize */
2767uint32_t lduw_phys(target_phys_addr_t addr)
2768{
2769 uint16_t val;
2770 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2771 return tswap16(val);
2772}
2773
bellard8df1cd02005-01-28 22:37:22 +00002774/* warning: addr must be aligned. The ram page is not masked as dirty
2775 and the code inside is not invalidated. It is useful if the dirty
2776 bits are used to track modified PTEs */
2777void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2778{
2779 int io_index;
2780 uint8_t *ptr;
2781 unsigned long pd;
2782 PhysPageDesc *p;
2783
2784 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2785 if (!p) {
2786 pd = IO_MEM_UNASSIGNED;
2787 } else {
2788 pd = p->phys_offset;
2789 }
ths3b46e622007-09-17 08:09:54 +00002790
bellard3a7d9292005-08-21 09:26:42 +00002791 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002792 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2793 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2794 } else {
ths5fafdf22007-09-16 21:08:06 +00002795 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002796 (addr & ~TARGET_PAGE_MASK);
2797 stl_p(ptr, val);
2798 }
2799}
2800
j_mayerbc98a7e2007-04-04 07:55:12 +00002801void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2802{
2803 int io_index;
2804 uint8_t *ptr;
2805 unsigned long pd;
2806 PhysPageDesc *p;
2807
2808 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2809 if (!p) {
2810 pd = IO_MEM_UNASSIGNED;
2811 } else {
2812 pd = p->phys_offset;
2813 }
ths3b46e622007-09-17 08:09:54 +00002814
j_mayerbc98a7e2007-04-04 07:55:12 +00002815 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2816 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2817#ifdef TARGET_WORDS_BIGENDIAN
2818 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2819 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2820#else
2821 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2822 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2823#endif
2824 } else {
ths5fafdf22007-09-16 21:08:06 +00002825 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002826 (addr & ~TARGET_PAGE_MASK);
2827 stq_p(ptr, val);
2828 }
2829}
2830
bellard8df1cd02005-01-28 22:37:22 +00002831/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002832void stl_phys(target_phys_addr_t addr, uint32_t val)
2833{
2834 int io_index;
2835 uint8_t *ptr;
2836 unsigned long pd;
2837 PhysPageDesc *p;
2838
2839 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2840 if (!p) {
2841 pd = IO_MEM_UNASSIGNED;
2842 } else {
2843 pd = p->phys_offset;
2844 }
ths3b46e622007-09-17 08:09:54 +00002845
bellard3a7d9292005-08-21 09:26:42 +00002846 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002847 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2848 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2849 } else {
2850 unsigned long addr1;
2851 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2852 /* RAM case */
2853 ptr = phys_ram_base + addr1;
2854 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002855 if (!cpu_physical_memory_is_dirty(addr1)) {
2856 /* invalidate code */
2857 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2858 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002859 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2860 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002861 }
bellard8df1cd02005-01-28 22:37:22 +00002862 }
2863}
2864
bellardaab33092005-10-30 20:48:42 +00002865/* XXX: optimize */
2866void stb_phys(target_phys_addr_t addr, uint32_t val)
2867{
2868 uint8_t v = val;
2869 cpu_physical_memory_write(addr, &v, 1);
2870}
2871
2872/* XXX: optimize */
2873void stw_phys(target_phys_addr_t addr, uint32_t val)
2874{
2875 uint16_t v = tswap16(val);
2876 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2877}
2878
2879/* XXX: optimize */
2880void stq_phys(target_phys_addr_t addr, uint64_t val)
2881{
2882 val = tswap64(val);
2883 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2884}
2885
bellard13eb76e2004-01-24 15:23:36 +00002886#endif
2887
2888/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002889int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002890 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002891{
2892 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002893 target_phys_addr_t phys_addr;
2894 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002895
2896 while (len > 0) {
2897 page = addr & TARGET_PAGE_MASK;
2898 phys_addr = cpu_get_phys_page_debug(env, page);
2899 /* if no physical page mapped, return an error */
2900 if (phys_addr == -1)
2901 return -1;
2902 l = (page + TARGET_PAGE_SIZE) - addr;
2903 if (l > len)
2904 l = len;
ths5fafdf22007-09-16 21:08:06 +00002905 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002906 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002907 len -= l;
2908 buf += l;
2909 addr += l;
2910 }
2911 return 0;
2912}
2913
bellarde3db7222005-01-26 22:00:47 +00002914void dump_exec_info(FILE *f,
2915 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2916{
2917 int i, target_code_size, max_target_code_size;
2918 int direct_jmp_count, direct_jmp2_count, cross_page;
2919 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002920
bellarde3db7222005-01-26 22:00:47 +00002921 target_code_size = 0;
2922 max_target_code_size = 0;
2923 cross_page = 0;
2924 direct_jmp_count = 0;
2925 direct_jmp2_count = 0;
2926 for(i = 0; i < nb_tbs; i++) {
2927 tb = &tbs[i];
2928 target_code_size += tb->size;
2929 if (tb->size > max_target_code_size)
2930 max_target_code_size = tb->size;
2931 if (tb->page_addr[1] != -1)
2932 cross_page++;
2933 if (tb->tb_next_offset[0] != 0xffff) {
2934 direct_jmp_count++;
2935 if (tb->tb_next_offset[1] != 0xffff) {
2936 direct_jmp2_count++;
2937 }
2938 }
2939 }
2940 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002941 cpu_fprintf(f, "Translation buffer state:\n");
bellarde3db7222005-01-26 22:00:47 +00002942 cpu_fprintf(f, "TB count %d\n", nb_tbs);
ths5fafdf22007-09-16 21:08:06 +00002943 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002944 nb_tbs ? target_code_size / nb_tbs : 0,
2945 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00002946 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00002947 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2948 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00002949 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2950 cross_page,
bellarde3db7222005-01-26 22:00:47 +00002951 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2952 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00002953 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00002954 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2955 direct_jmp2_count,
2956 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00002957 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00002958 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2959 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2960 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellard57fec1f2008-02-01 10:50:11 +00002961#ifdef CONFIG_PROFILER
2962 {
2963 int64_t tot;
2964 tot = dyngen_interm_time + dyngen_code_time;
2965 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2966 tot, tot / 2.4e9);
2967 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2968 dyngen_tb_count,
2969 dyngen_tb_count1 - dyngen_tb_count,
2970 dyngen_tb_count1 ? (double)(dyngen_tb_count1 - dyngen_tb_count) / dyngen_tb_count1 * 100.0 : 0);
2971 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2972 dyngen_tb_count ? (double)dyngen_op_count / dyngen_tb_count : 0, dyngen_op_count_max);
2973 cpu_fprintf(f, "old ops/total ops %0.1f%%\n",
2974 dyngen_op_count ? (double)dyngen_old_op_count / dyngen_op_count * 100.0 : 0);
2975 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2976 dyngen_tb_count ?
2977 (double)dyngen_tcg_del_op_count / dyngen_tb_count : 0);
2978 cpu_fprintf(f, "cycles/op %0.1f\n",
2979 dyngen_op_count ? (double)tot / dyngen_op_count : 0);
2980 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2981 dyngen_code_in_len ? (double)tot / dyngen_code_in_len : 0);
2982 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2983 dyngen_code_out_len ? (double)tot / dyngen_code_out_len : 0);
2984 if (tot == 0)
2985 tot = 1;
2986 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2987 (double)dyngen_interm_time / tot * 100.0);
2988 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2989 (double)dyngen_code_time / tot * 100.0);
2990 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2991 dyngen_restore_count);
2992 cpu_fprintf(f, " avg cycles %0.1f\n",
2993 dyngen_restore_count ? (double)dyngen_restore_time / dyngen_restore_count : 0);
2994 {
2995 extern void dump_op_count(void);
2996 dump_op_count();
2997 }
2998 }
2999#endif
bellarde3db7222005-01-26 22:00:47 +00003000}
3001
ths5fafdf22007-09-16 21:08:06 +00003002#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003003
3004#define MMUSUFFIX _cmmu
3005#define GETPC() NULL
3006#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003007#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003008
3009#define SHIFT 0
3010#include "softmmu_template.h"
3011
3012#define SHIFT 1
3013#include "softmmu_template.h"
3014
3015#define SHIFT 2
3016#include "softmmu_template.h"
3017
3018#define SHIFT 3
3019#include "softmmu_template.h"
3020
3021#undef env
3022
3023#endif