blob: dc13c9bffeacc16729c4bba451fe56eeabf43a54 [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"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
pbrook53a59602006-03-25 19:31:22 +000039#if defined(CONFIG_USER_ONLY)
40#include <qemu.h>
41#endif
bellard54936002003-05-13 00:25:15 +000042
bellardfd6ce8f2003-05-14 19:00:11 +000043//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000044//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000045//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000046//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000047
48/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000049//#define DEBUG_TB_CHECK
50//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000051
ths1196be32007-03-17 15:17:58 +000052//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000053//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000054
pbrook99773bd2006-04-16 15:14:59 +000055#if !defined(CONFIG_USER_ONLY)
56/* TB consistency checks only implemented for usermode emulation. */
57#undef DEBUG_TB_CHECK
58#endif
59
bellardfd6ce8f2003-05-14 19:00:11 +000060/* threshold to flush the translated code buffer */
blueswir1d07bde82007-12-11 19:35:45 +000061#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
bellardfd6ce8f2003-05-14 19:00:11 +000062
bellard9fa3e852004-01-04 18:06:42 +000063#define SMC_BITMAP_USE_THRESHOLD 10
64
65#define MMAP_AREA_START 0x00000000
66#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000067
bellard108c49b2005-07-24 12:55:09 +000068#if defined(TARGET_SPARC64)
69#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000070#elif defined(TARGET_SPARC)
71#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000072#elif defined(TARGET_ALPHA)
73#define TARGET_PHYS_ADDR_SPACE_BITS 42
74#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000075#elif defined(TARGET_PPC64)
76#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000077#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
78#define TARGET_PHYS_ADDR_SPACE_BITS 42
79#elif defined(TARGET_I386) && !defined(USE_KQEMU)
80#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000081#else
82/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
83#define TARGET_PHYS_ADDR_SPACE_BITS 32
84#endif
85
bellardfd6ce8f2003-05-14 19:00:11 +000086TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000087TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000088int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000089/* any access to the tbs or the page table must use this lock */
90spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000091
bellard7cb69ca2008-05-10 10:55:51 +000092uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellardb8076a72005-04-07 22:20:31 +000093uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000094uint8_t *code_gen_ptr;
95
aurel3200f82b82008-04-27 21:12:55 +000096ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +000097int phys_ram_fd;
98uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000099uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000100static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +0000101
bellard6a00d602005-11-21 23:25:50 +0000102CPUState *first_cpu;
103/* current CPU in the current thread. It is only valid inside
104 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000105CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000106
bellard54936002003-05-13 00:25:15 +0000107typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000108 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000109 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000110 /* in order to optimize self modifying code, we count the number
111 of lookups we do to a given page to use a bitmap */
112 unsigned int code_write_count;
113 uint8_t *code_bitmap;
114#if defined(CONFIG_USER_ONLY)
115 unsigned long flags;
116#endif
bellard54936002003-05-13 00:25:15 +0000117} PageDesc;
118
bellard92e873b2004-05-21 14:52:29 +0000119typedef struct PhysPageDesc {
120 /* offset in host memory of the page + io_index in the low 12 bits */
aurel3200f82b82008-04-27 21:12:55 +0000121 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000122} PhysPageDesc;
123
bellard54936002003-05-13 00:25:15 +0000124#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000125#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
126/* XXX: this is a temporary hack for alpha target.
127 * In the future, this is to be replaced by a multi-level table
128 * to actually be able to handle the complete 64 bits address space.
129 */
130#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
131#else
aurel3203875442008-04-22 20:45:18 +0000132#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000133#endif
bellard54936002003-05-13 00:25:15 +0000134
135#define L1_SIZE (1 << L1_BITS)
136#define L2_SIZE (1 << L2_BITS)
137
bellard33417e72003-08-10 21:47:01 +0000138static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000139
bellard83fb7ad2004-07-05 21:25:26 +0000140unsigned long qemu_real_host_page_size;
141unsigned long qemu_host_page_bits;
142unsigned long qemu_host_page_size;
143unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000144
bellard92e873b2004-05-21 14:52:29 +0000145/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000146static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000147PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000148
bellard33417e72003-08-10 21:47:01 +0000149/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000150CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
151CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000152void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000153static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000154#if defined(CONFIG_SOFTMMU)
155static int io_mem_watch;
156#endif
bellard33417e72003-08-10 21:47:01 +0000157
bellard34865132003-10-05 14:28:56 +0000158/* log support */
159char *logfilename = "/tmp/qemu.log";
160FILE *logfile;
161int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000162static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000163
bellarde3db7222005-01-26 22:00:47 +0000164/* statistics */
165static int tlb_flush_count;
166static int tb_flush_count;
167static int tb_phys_invalidate_count;
168
blueswir1db7b5422007-05-26 17:36:03 +0000169#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
170typedef struct subpage_t {
171 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000172 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
173 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
174 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000175} subpage_t;
176
bellard7cb69ca2008-05-10 10:55:51 +0000177#ifdef _WIN32
178static void map_exec(void *addr, long size)
179{
180 DWORD old_protect;
181 VirtualProtect(addr, size,
182 PAGE_EXECUTE_READWRITE, &old_protect);
183
184}
185#else
186static void map_exec(void *addr, long size)
187{
188 unsigned long start, end;
189
190 start = (unsigned long)addr;
191 start &= ~(qemu_real_host_page_size - 1);
192
193 end = (unsigned long)addr + size;
194 end += qemu_real_host_page_size - 1;
195 end &= ~(qemu_real_host_page_size - 1);
196
197 mprotect((void *)start, end - start,
198 PROT_READ | PROT_WRITE | PROT_EXEC);
199}
200#endif
201
bellardb346ff42003-06-15 20:05:50 +0000202static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000203{
bellard83fb7ad2004-07-05 21:25:26 +0000204 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000205 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000206#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000207 {
208 SYSTEM_INFO system_info;
209 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000210
bellardd5a8f072004-09-29 21:15:28 +0000211 GetSystemInfo(&system_info);
212 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000213 }
bellard67b915a2004-03-31 23:37:16 +0000214#else
bellard83fb7ad2004-07-05 21:25:26 +0000215 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000216#endif
bellard7cb69ca2008-05-10 10:55:51 +0000217 map_exec(code_gen_buffer, sizeof(code_gen_buffer));
218 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
bellardd5a8f072004-09-29 21:15:28 +0000219
bellard83fb7ad2004-07-05 21:25:26 +0000220 if (qemu_host_page_size == 0)
221 qemu_host_page_size = qemu_real_host_page_size;
222 if (qemu_host_page_size < TARGET_PAGE_SIZE)
223 qemu_host_page_size = TARGET_PAGE_SIZE;
224 qemu_host_page_bits = 0;
225 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
226 qemu_host_page_bits++;
227 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000228 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
229 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000230
231#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
232 {
233 long long startaddr, endaddr;
234 FILE *f;
235 int n;
236
237 f = fopen("/proc/self/maps", "r");
238 if (f) {
239 do {
240 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
241 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000242 startaddr = MIN(startaddr,
243 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
244 endaddr = MIN(endaddr,
245 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
balrog50a95692007-12-12 01:16:23 +0000246 page_set_flags(TARGET_PAGE_ALIGN(startaddr),
247 TARGET_PAGE_ALIGN(endaddr),
248 PAGE_RESERVED);
249 }
250 } while (!feof(f));
251 fclose(f);
252 }
253 }
254#endif
bellard54936002003-05-13 00:25:15 +0000255}
256
aurel3200f82b82008-04-27 21:12:55 +0000257static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000258{
bellard54936002003-05-13 00:25:15 +0000259 PageDesc **lp, *p;
260
bellard54936002003-05-13 00:25:15 +0000261 lp = &l1_map[index >> L2_BITS];
262 p = *lp;
263 if (!p) {
264 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000265 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000266 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000267 *lp = p;
268 }
269 return p + (index & (L2_SIZE - 1));
270}
271
aurel3200f82b82008-04-27 21:12:55 +0000272static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000273{
bellard54936002003-05-13 00:25:15 +0000274 PageDesc *p;
275
bellard54936002003-05-13 00:25:15 +0000276 p = l1_map[index >> L2_BITS];
277 if (!p)
278 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000279 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000280}
281
bellard108c49b2005-07-24 12:55:09 +0000282static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000283{
bellard108c49b2005-07-24 12:55:09 +0000284 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000285 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000286
bellard108c49b2005-07-24 12:55:09 +0000287 p = (void **)l1_phys_map;
288#if TARGET_PHYS_ADDR_SPACE_BITS > 32
289
290#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
291#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
292#endif
293 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000294 p = *lp;
295 if (!p) {
296 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000297 if (!alloc)
298 return NULL;
299 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
300 memset(p, 0, sizeof(void *) * L1_SIZE);
301 *lp = p;
302 }
303#endif
304 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000305 pd = *lp;
306 if (!pd) {
307 int i;
bellard108c49b2005-07-24 12:55:09 +0000308 /* allocate if not found */
309 if (!alloc)
310 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000311 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
312 *lp = pd;
313 for (i = 0; i < L2_SIZE; i++)
314 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000315 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000316 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000317}
318
bellard108c49b2005-07-24 12:55:09 +0000319static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000320{
bellard108c49b2005-07-24 12:55:09 +0000321 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000322}
323
bellard9fa3e852004-01-04 18:06:42 +0000324#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000325static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000326static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000327 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000328#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000329
bellard6a00d602005-11-21 23:25:50 +0000330void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000331{
bellard6a00d602005-11-21 23:25:50 +0000332 CPUState **penv;
333 int cpu_index;
334
bellardfd6ce8f2003-05-14 19:00:11 +0000335 if (!code_gen_ptr) {
bellard57fec1f2008-02-01 10:50:11 +0000336 cpu_gen_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000337 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000338 page_init();
bellard33417e72003-08-10 21:47:01 +0000339 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000340 }
bellard6a00d602005-11-21 23:25:50 +0000341 env->next_cpu = NULL;
342 penv = &first_cpu;
343 cpu_index = 0;
344 while (*penv != NULL) {
345 penv = (CPUState **)&(*penv)->next_cpu;
346 cpu_index++;
347 }
348 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000349 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000350 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000351}
352
bellard9fa3e852004-01-04 18:06:42 +0000353static inline void invalidate_page_bitmap(PageDesc *p)
354{
355 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000356 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000357 p->code_bitmap = NULL;
358 }
359 p->code_write_count = 0;
360}
361
bellardfd6ce8f2003-05-14 19:00:11 +0000362/* set to NULL all the 'first_tb' fields in all PageDescs */
363static void page_flush_tb(void)
364{
365 int i, j;
366 PageDesc *p;
367
368 for(i = 0; i < L1_SIZE; i++) {
369 p = l1_map[i];
370 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000371 for(j = 0; j < L2_SIZE; j++) {
372 p->first_tb = NULL;
373 invalidate_page_bitmap(p);
374 p++;
375 }
bellardfd6ce8f2003-05-14 19:00:11 +0000376 }
377 }
378}
379
380/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000381/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000382void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000383{
bellard6a00d602005-11-21 23:25:50 +0000384 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000385#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000386 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
387 (unsigned long)(code_gen_ptr - code_gen_buffer),
388 nb_tbs, nb_tbs > 0 ?
389 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000390#endif
pbrooka208e542008-03-31 17:07:36 +0000391 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE)
392 cpu_abort(env1, "Internal error: code buffer overflow\n");
393
bellardfd6ce8f2003-05-14 19:00:11 +0000394 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000395
bellard6a00d602005-11-21 23:25:50 +0000396 for(env = first_cpu; env != NULL; env = env->next_cpu) {
397 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
398 }
bellard9fa3e852004-01-04 18:06:42 +0000399
bellard8a8a6082004-10-03 13:36:49 +0000400 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000401 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000402
bellardfd6ce8f2003-05-14 19:00:11 +0000403 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000404 /* XXX: flush processor icache at this point if cache flush is
405 expensive */
bellarde3db7222005-01-26 22:00:47 +0000406 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000407}
408
409#ifdef DEBUG_TB_CHECK
410
j_mayerbc98a7e2007-04-04 07:55:12 +0000411static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000412{
413 TranslationBlock *tb;
414 int i;
415 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000416 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
417 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000418 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
419 address >= tb->pc + tb->size)) {
420 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000421 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000422 }
423 }
424 }
425}
426
427/* verify that all the pages have correct rights for code */
428static void tb_page_check(void)
429{
430 TranslationBlock *tb;
431 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000432
pbrook99773bd2006-04-16 15:14:59 +0000433 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
434 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000435 flags1 = page_get_flags(tb->pc);
436 flags2 = page_get_flags(tb->pc + tb->size - 1);
437 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
438 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000439 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000440 }
441 }
442 }
443}
444
bellardd4e81642003-05-25 16:46:15 +0000445void tb_jmp_check(TranslationBlock *tb)
446{
447 TranslationBlock *tb1;
448 unsigned int n1;
449
450 /* suppress any remaining jumps to this TB */
451 tb1 = tb->jmp_first;
452 for(;;) {
453 n1 = (long)tb1 & 3;
454 tb1 = (TranslationBlock *)((long)tb1 & ~3);
455 if (n1 == 2)
456 break;
457 tb1 = tb1->jmp_next[n1];
458 }
459 /* check end of list */
460 if (tb1 != tb) {
461 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
462 }
463}
464
bellardfd6ce8f2003-05-14 19:00:11 +0000465#endif
466
467/* invalidate one TB */
468static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
469 int next_offset)
470{
471 TranslationBlock *tb1;
472 for(;;) {
473 tb1 = *ptb;
474 if (tb1 == tb) {
475 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
476 break;
477 }
478 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
479 }
480}
481
bellard9fa3e852004-01-04 18:06:42 +0000482static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
483{
484 TranslationBlock *tb1;
485 unsigned int n1;
486
487 for(;;) {
488 tb1 = *ptb;
489 n1 = (long)tb1 & 3;
490 tb1 = (TranslationBlock *)((long)tb1 & ~3);
491 if (tb1 == tb) {
492 *ptb = tb1->page_next[n1];
493 break;
494 }
495 ptb = &tb1->page_next[n1];
496 }
497}
498
bellardd4e81642003-05-25 16:46:15 +0000499static inline void tb_jmp_remove(TranslationBlock *tb, int n)
500{
501 TranslationBlock *tb1, **ptb;
502 unsigned int n1;
503
504 ptb = &tb->jmp_next[n];
505 tb1 = *ptb;
506 if (tb1) {
507 /* find tb(n) in circular list */
508 for(;;) {
509 tb1 = *ptb;
510 n1 = (long)tb1 & 3;
511 tb1 = (TranslationBlock *)((long)tb1 & ~3);
512 if (n1 == n && tb1 == tb)
513 break;
514 if (n1 == 2) {
515 ptb = &tb1->jmp_first;
516 } else {
517 ptb = &tb1->jmp_next[n1];
518 }
519 }
520 /* now we can suppress tb(n) from the list */
521 *ptb = tb->jmp_next[n];
522
523 tb->jmp_next[n] = NULL;
524 }
525}
526
527/* reset the jump entry 'n' of a TB so that it is not chained to
528 another TB */
529static inline void tb_reset_jump(TranslationBlock *tb, int n)
530{
531 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
532}
533
aurel3200f82b82008-04-27 21:12:55 +0000534static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000535{
bellard6a00d602005-11-21 23:25:50 +0000536 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000537 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000538 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000539 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000540 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000541
bellard9fa3e852004-01-04 18:06:42 +0000542 /* remove the TB from the hash list */
543 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
544 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000545 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000546 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000547
bellard9fa3e852004-01-04 18:06:42 +0000548 /* remove the TB from the page list */
549 if (tb->page_addr[0] != page_addr) {
550 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
551 tb_page_remove(&p->first_tb, tb);
552 invalidate_page_bitmap(p);
553 }
554 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
555 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
556 tb_page_remove(&p->first_tb, tb);
557 invalidate_page_bitmap(p);
558 }
559
bellard8a40a182005-11-20 10:35:40 +0000560 tb_invalidated_flag = 1;
561
562 /* remove the TB from the hash list */
563 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000564 for(env = first_cpu; env != NULL; env = env->next_cpu) {
565 if (env->tb_jmp_cache[h] == tb)
566 env->tb_jmp_cache[h] = NULL;
567 }
bellard8a40a182005-11-20 10:35:40 +0000568
569 /* suppress this TB from the two jump lists */
570 tb_jmp_remove(tb, 0);
571 tb_jmp_remove(tb, 1);
572
573 /* suppress any remaining jumps to this TB */
574 tb1 = tb->jmp_first;
575 for(;;) {
576 n1 = (long)tb1 & 3;
577 if (n1 == 2)
578 break;
579 tb1 = (TranslationBlock *)((long)tb1 & ~3);
580 tb2 = tb1->jmp_next[n1];
581 tb_reset_jump(tb1, n1);
582 tb1->jmp_next[n1] = NULL;
583 tb1 = tb2;
584 }
585 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
586
bellarde3db7222005-01-26 22:00:47 +0000587 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000588}
589
590static inline void set_bits(uint8_t *tab, int start, int len)
591{
592 int end, mask, end1;
593
594 end = start + len;
595 tab += start >> 3;
596 mask = 0xff << (start & 7);
597 if ((start & ~7) == (end & ~7)) {
598 if (start < end) {
599 mask &= ~(0xff << (end & 7));
600 *tab |= mask;
601 }
602 } else {
603 *tab++ |= mask;
604 start = (start + 8) & ~7;
605 end1 = end & ~7;
606 while (start < end1) {
607 *tab++ = 0xff;
608 start += 8;
609 }
610 if (start < end) {
611 mask = ~(0xff << (end & 7));
612 *tab |= mask;
613 }
614 }
615}
616
617static void build_page_bitmap(PageDesc *p)
618{
619 int n, tb_start, tb_end;
620 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000621
bellard59817cc2004-02-16 22:01:13 +0000622 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000623 if (!p->code_bitmap)
624 return;
625 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
626
627 tb = p->first_tb;
628 while (tb != NULL) {
629 n = (long)tb & 3;
630 tb = (TranslationBlock *)((long)tb & ~3);
631 /* NOTE: this is subtle as a TB may span two physical pages */
632 if (n == 0) {
633 /* NOTE: tb_end may be after the end of the page, but
634 it is not a problem */
635 tb_start = tb->pc & ~TARGET_PAGE_MASK;
636 tb_end = tb_start + tb->size;
637 if (tb_end > TARGET_PAGE_SIZE)
638 tb_end = TARGET_PAGE_SIZE;
639 } else {
640 tb_start = 0;
641 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
642 }
643 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
644 tb = tb->page_next[n];
645 }
646}
647
bellardd720b932004-04-25 17:57:43 +0000648#ifdef TARGET_HAS_PRECISE_SMC
649
ths5fafdf22007-09-16 21:08:06 +0000650static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000651 target_ulong pc, target_ulong cs_base, int flags,
652 int cflags)
653{
654 TranslationBlock *tb;
655 uint8_t *tc_ptr;
656 target_ulong phys_pc, phys_page2, virt_page2;
657 int code_gen_size;
658
bellardc27004e2005-01-03 23:35:10 +0000659 phys_pc = get_phys_addr_code(env, pc);
660 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000661 if (!tb) {
662 /* flush must be done */
663 tb_flush(env);
664 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000665 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000666 }
667 tc_ptr = code_gen_ptr;
668 tb->tc_ptr = tc_ptr;
669 tb->cs_base = cs_base;
670 tb->flags = flags;
671 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000672 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000673 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 +0000674
bellardd720b932004-04-25 17:57:43 +0000675 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000676 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000677 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000678 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000679 phys_page2 = get_phys_addr_code(env, virt_page2);
680 }
681 tb_link_phys(tb, phys_pc, phys_page2);
682}
683#endif
ths3b46e622007-09-17 08:09:54 +0000684
bellard9fa3e852004-01-04 18:06:42 +0000685/* invalidate all TBs which intersect with the target physical page
686 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000687 the same physical page. 'is_cpu_write_access' should be true if called
688 from a real cpu write access: the virtual CPU will exit the current
689 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000690void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000691 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000692{
bellardd720b932004-04-25 17:57:43 +0000693 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000694 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000695 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000696 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000697 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000698 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000699
700 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000701 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000702 return;
ths5fafdf22007-09-16 21:08:06 +0000703 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000704 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
705 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000706 /* build code bitmap */
707 build_page_bitmap(p);
708 }
709
710 /* we remove all the TBs in the range [start, end[ */
711 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000712 current_tb_not_found = is_cpu_write_access;
713 current_tb_modified = 0;
714 current_tb = NULL; /* avoid warning */
715 current_pc = 0; /* avoid warning */
716 current_cs_base = 0; /* avoid warning */
717 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000718 tb = p->first_tb;
719 while (tb != NULL) {
720 n = (long)tb & 3;
721 tb = (TranslationBlock *)((long)tb & ~3);
722 tb_next = tb->page_next[n];
723 /* NOTE: this is subtle as a TB may span two physical pages */
724 if (n == 0) {
725 /* NOTE: tb_end may be after the end of the page, but
726 it is not a problem */
727 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
728 tb_end = tb_start + tb->size;
729 } else {
730 tb_start = tb->page_addr[1];
731 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
732 }
733 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000734#ifdef TARGET_HAS_PRECISE_SMC
735 if (current_tb_not_found) {
736 current_tb_not_found = 0;
737 current_tb = NULL;
738 if (env->mem_write_pc) {
739 /* now we have a real cpu fault */
740 current_tb = tb_find_pc(env->mem_write_pc);
741 }
742 }
743 if (current_tb == tb &&
744 !(current_tb->cflags & CF_SINGLE_INSN)) {
745 /* If we are modifying the current TB, we must stop
746 its execution. We could be more precise by checking
747 that the modification is after the current PC, but it
748 would require a specialized function to partially
749 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000750
bellardd720b932004-04-25 17:57:43 +0000751 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000752 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000753 env->mem_write_pc, NULL);
754#if defined(TARGET_I386)
755 current_flags = env->hflags;
756 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
757 current_cs_base = (target_ulong)env->segs[R_CS].base;
758 current_pc = current_cs_base + env->eip;
759#else
760#error unsupported CPU
761#endif
762 }
763#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000764 /* we need to do that to handle the case where a signal
765 occurs while doing tb_phys_invalidate() */
766 saved_tb = NULL;
767 if (env) {
768 saved_tb = env->current_tb;
769 env->current_tb = NULL;
770 }
bellard9fa3e852004-01-04 18:06:42 +0000771 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000772 if (env) {
773 env->current_tb = saved_tb;
774 if (env->interrupt_request && env->current_tb)
775 cpu_interrupt(env, env->interrupt_request);
776 }
bellard9fa3e852004-01-04 18:06:42 +0000777 }
778 tb = tb_next;
779 }
780#if !defined(CONFIG_USER_ONLY)
781 /* if no code remaining, no need to continue to use slow writes */
782 if (!p->first_tb) {
783 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000784 if (is_cpu_write_access) {
785 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
786 }
787 }
788#endif
789#ifdef TARGET_HAS_PRECISE_SMC
790 if (current_tb_modified) {
791 /* we generate a block containing just the instruction
792 modifying the memory. It will ensure that it cannot modify
793 itself */
bellardea1c1802004-06-14 18:56:36 +0000794 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000795 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000796 CF_SINGLE_INSN);
797 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000798 }
799#endif
800}
801
802/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000803static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000804{
805 PageDesc *p;
806 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000807#if 0
bellarda4193c82004-06-03 14:01:43 +0000808 if (1) {
809 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000810 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
811 cpu_single_env->mem_write_vaddr, len,
812 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000813 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
814 }
bellard59817cc2004-02-16 22:01:13 +0000815 }
816#endif
bellard9fa3e852004-01-04 18:06:42 +0000817 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000818 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000819 return;
820 if (p->code_bitmap) {
821 offset = start & ~TARGET_PAGE_MASK;
822 b = p->code_bitmap[offset >> 3] >> (offset & 7);
823 if (b & ((1 << len) - 1))
824 goto do_invalidate;
825 } else {
826 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000827 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000828 }
829}
830
bellard9fa3e852004-01-04 18:06:42 +0000831#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000832static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000833 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000834{
bellardd720b932004-04-25 17:57:43 +0000835 int n, current_flags, current_tb_modified;
836 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000837 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000838 TranslationBlock *tb, *current_tb;
839#ifdef TARGET_HAS_PRECISE_SMC
840 CPUState *env = cpu_single_env;
841#endif
bellard9fa3e852004-01-04 18:06:42 +0000842
843 addr &= TARGET_PAGE_MASK;
844 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000845 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000846 return;
847 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000848 current_tb_modified = 0;
849 current_tb = NULL;
850 current_pc = 0; /* avoid warning */
851 current_cs_base = 0; /* avoid warning */
852 current_flags = 0; /* avoid warning */
853#ifdef TARGET_HAS_PRECISE_SMC
854 if (tb && pc != 0) {
855 current_tb = tb_find_pc(pc);
856 }
857#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000858 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000859 n = (long)tb & 3;
860 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000861#ifdef TARGET_HAS_PRECISE_SMC
862 if (current_tb == tb &&
863 !(current_tb->cflags & CF_SINGLE_INSN)) {
864 /* If we are modifying the current TB, we must stop
865 its execution. We could be more precise by checking
866 that the modification is after the current PC, but it
867 would require a specialized function to partially
868 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000869
bellardd720b932004-04-25 17:57:43 +0000870 current_tb_modified = 1;
871 cpu_restore_state(current_tb, env, pc, puc);
872#if defined(TARGET_I386)
873 current_flags = env->hflags;
874 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
875 current_cs_base = (target_ulong)env->segs[R_CS].base;
876 current_pc = current_cs_base + env->eip;
877#else
878#error unsupported CPU
879#endif
880 }
881#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000882 tb_phys_invalidate(tb, addr);
883 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000884 }
885 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000886#ifdef TARGET_HAS_PRECISE_SMC
887 if (current_tb_modified) {
888 /* we generate a block containing just the instruction
889 modifying the memory. It will ensure that it cannot modify
890 itself */
bellardea1c1802004-06-14 18:56:36 +0000891 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000892 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000893 CF_SINGLE_INSN);
894 cpu_resume_from_signal(env, puc);
895 }
896#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000897}
bellard9fa3e852004-01-04 18:06:42 +0000898#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000899
900/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000901static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000902 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000903{
904 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000905 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000906
bellard9fa3e852004-01-04 18:06:42 +0000907 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000908 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000909 tb->page_next[n] = p->first_tb;
910 last_first_tb = p->first_tb;
911 p->first_tb = (TranslationBlock *)((long)tb | n);
912 invalidate_page_bitmap(p);
913
bellard107db442004-06-22 18:48:46 +0000914#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000915
bellard9fa3e852004-01-04 18:06:42 +0000916#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000917 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000918 target_ulong addr;
919 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000920 int prot;
921
bellardfd6ce8f2003-05-14 19:00:11 +0000922 /* force the host page as non writable (writes will have a
923 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000924 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000925 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000926 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
927 addr += TARGET_PAGE_SIZE) {
928
929 p2 = page_find (addr >> TARGET_PAGE_BITS);
930 if (!p2)
931 continue;
932 prot |= p2->flags;
933 p2->flags &= ~PAGE_WRITE;
934 page_get_flags(addr);
935 }
ths5fafdf22007-09-16 21:08:06 +0000936 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000937 (prot & PAGE_BITS) & ~PAGE_WRITE);
938#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +0000939 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +0000940 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000941#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000942 }
bellard9fa3e852004-01-04 18:06:42 +0000943#else
944 /* if some code is already present, then the pages are already
945 protected. So we handle the case where only the first TB is
946 allocated in a physical page */
947 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000948 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000949 }
950#endif
bellardd720b932004-04-25 17:57:43 +0000951
952#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000953}
954
955/* Allocate a new translation block. Flush the translation buffer if
956 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000957TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000958{
959 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000960
ths5fafdf22007-09-16 21:08:06 +0000961 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
bellardfd6ce8f2003-05-14 19:00:11 +0000962 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000963 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000964 tb = &tbs[nb_tbs++];
965 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000966 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000967 return tb;
968}
969
bellard9fa3e852004-01-04 18:06:42 +0000970/* add a new TB and link it to the physical page tables. phys_page2 is
971 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +0000972void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +0000973 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000974{
bellard9fa3e852004-01-04 18:06:42 +0000975 unsigned int h;
976 TranslationBlock **ptb;
977
978 /* add in the physical hash table */
979 h = tb_phys_hash_func(phys_pc);
980 ptb = &tb_phys_hash[h];
981 tb->phys_hash_next = *ptb;
982 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000983
984 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000985 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
986 if (phys_page2 != -1)
987 tb_alloc_page(tb, 1, phys_page2);
988 else
989 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000990
bellardd4e81642003-05-25 16:46:15 +0000991 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
992 tb->jmp_next[0] = NULL;
993 tb->jmp_next[1] = NULL;
994
995 /* init original jump addresses */
996 if (tb->tb_next_offset[0] != 0xffff)
997 tb_reset_jump(tb, 0);
998 if (tb->tb_next_offset[1] != 0xffff)
999 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001000
1001#ifdef DEBUG_TB_CHECK
1002 tb_page_check();
1003#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001004}
1005
bellarda513fe12003-05-27 23:29:48 +00001006/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1007 tb[1].tc_ptr. Return NULL if not found */
1008TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1009{
1010 int m_min, m_max, m;
1011 unsigned long v;
1012 TranslationBlock *tb;
1013
1014 if (nb_tbs <= 0)
1015 return NULL;
1016 if (tc_ptr < (unsigned long)code_gen_buffer ||
1017 tc_ptr >= (unsigned long)code_gen_ptr)
1018 return NULL;
1019 /* binary search (cf Knuth) */
1020 m_min = 0;
1021 m_max = nb_tbs - 1;
1022 while (m_min <= m_max) {
1023 m = (m_min + m_max) >> 1;
1024 tb = &tbs[m];
1025 v = (unsigned long)tb->tc_ptr;
1026 if (v == tc_ptr)
1027 return tb;
1028 else if (tc_ptr < v) {
1029 m_max = m - 1;
1030 } else {
1031 m_min = m + 1;
1032 }
ths5fafdf22007-09-16 21:08:06 +00001033 }
bellarda513fe12003-05-27 23:29:48 +00001034 return &tbs[m_max];
1035}
bellard75012672003-06-21 13:11:07 +00001036
bellardea041c02003-06-25 16:16:50 +00001037static void tb_reset_jump_recursive(TranslationBlock *tb);
1038
1039static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1040{
1041 TranslationBlock *tb1, *tb_next, **ptb;
1042 unsigned int n1;
1043
1044 tb1 = tb->jmp_next[n];
1045 if (tb1 != NULL) {
1046 /* find head of list */
1047 for(;;) {
1048 n1 = (long)tb1 & 3;
1049 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1050 if (n1 == 2)
1051 break;
1052 tb1 = tb1->jmp_next[n1];
1053 }
1054 /* we are now sure now that tb jumps to tb1 */
1055 tb_next = tb1;
1056
1057 /* remove tb from the jmp_first list */
1058 ptb = &tb_next->jmp_first;
1059 for(;;) {
1060 tb1 = *ptb;
1061 n1 = (long)tb1 & 3;
1062 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1063 if (n1 == n && tb1 == tb)
1064 break;
1065 ptb = &tb1->jmp_next[n1];
1066 }
1067 *ptb = tb->jmp_next[n];
1068 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001069
bellardea041c02003-06-25 16:16:50 +00001070 /* suppress the jump to next tb in generated code */
1071 tb_reset_jump(tb, n);
1072
bellard01243112004-01-04 15:48:17 +00001073 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001074 tb_reset_jump_recursive(tb_next);
1075 }
1076}
1077
1078static void tb_reset_jump_recursive(TranslationBlock *tb)
1079{
1080 tb_reset_jump_recursive2(tb, 0);
1081 tb_reset_jump_recursive2(tb, 1);
1082}
1083
bellard1fddef42005-04-17 19:16:13 +00001084#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001085static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1086{
j_mayer9b3c35e2007-04-07 11:21:28 +00001087 target_phys_addr_t addr;
1088 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001089 ram_addr_t ram_addr;
1090 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001091
pbrookc2f07f82006-04-08 17:14:56 +00001092 addr = cpu_get_phys_page_debug(env, pc);
1093 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1094 if (!p) {
1095 pd = IO_MEM_UNASSIGNED;
1096 } else {
1097 pd = p->phys_offset;
1098 }
1099 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001100 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001101}
bellardc27004e2005-01-03 23:35:10 +00001102#endif
bellardd720b932004-04-25 17:57:43 +00001103
pbrook6658ffb2007-03-16 23:58:11 +00001104/* Add a watchpoint. */
1105int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1106{
1107 int i;
1108
1109 for (i = 0; i < env->nb_watchpoints; i++) {
1110 if (addr == env->watchpoint[i].vaddr)
1111 return 0;
1112 }
1113 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1114 return -1;
1115
1116 i = env->nb_watchpoints++;
1117 env->watchpoint[i].vaddr = addr;
1118 tlb_flush_page(env, addr);
1119 /* FIXME: This flush is needed because of the hack to make memory ops
1120 terminate the TB. It can be removed once the proper IO trap and
1121 re-execute bits are in. */
1122 tb_flush(env);
1123 return i;
1124}
1125
1126/* Remove a watchpoint. */
1127int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1128{
1129 int i;
1130
1131 for (i = 0; i < env->nb_watchpoints; i++) {
1132 if (addr == env->watchpoint[i].vaddr) {
1133 env->nb_watchpoints--;
1134 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1135 tlb_flush_page(env, addr);
1136 return 0;
1137 }
1138 }
1139 return -1;
1140}
1141
edgar_igl7d03f822008-05-17 18:58:29 +00001142/* Remove all watchpoints. */
1143void cpu_watchpoint_remove_all(CPUState *env) {
1144 int i;
1145
1146 for (i = 0; i < env->nb_watchpoints; i++) {
1147 tlb_flush_page(env, env->watchpoint[i].vaddr);
1148 }
1149 env->nb_watchpoints = 0;
1150}
1151
bellardc33a3462003-07-29 20:50:33 +00001152/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1153 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001154int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001155{
bellard1fddef42005-04-17 19:16:13 +00001156#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001157 int i;
ths3b46e622007-09-17 08:09:54 +00001158
bellard4c3a88a2003-07-26 12:06:08 +00001159 for(i = 0; i < env->nb_breakpoints; i++) {
1160 if (env->breakpoints[i] == pc)
1161 return 0;
1162 }
1163
1164 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1165 return -1;
1166 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001167
bellardd720b932004-04-25 17:57:43 +00001168 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001169 return 0;
1170#else
1171 return -1;
1172#endif
1173}
1174
edgar_igl7d03f822008-05-17 18:58:29 +00001175/* remove all breakpoints */
1176void cpu_breakpoint_remove_all(CPUState *env) {
1177#if defined(TARGET_HAS_ICE)
1178 int i;
1179 for(i = 0; i < env->nb_breakpoints; i++) {
1180 breakpoint_invalidate(env, env->breakpoints[i]);
1181 }
1182 env->nb_breakpoints = 0;
1183#endif
1184}
1185
bellard4c3a88a2003-07-26 12:06:08 +00001186/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001187int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001188{
bellard1fddef42005-04-17 19:16:13 +00001189#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001190 int i;
1191 for(i = 0; i < env->nb_breakpoints; i++) {
1192 if (env->breakpoints[i] == pc)
1193 goto found;
1194 }
1195 return -1;
1196 found:
bellard4c3a88a2003-07-26 12:06:08 +00001197 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001198 if (i < env->nb_breakpoints)
1199 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001200
1201 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001202 return 0;
1203#else
1204 return -1;
1205#endif
1206}
1207
bellardc33a3462003-07-29 20:50:33 +00001208/* enable or disable single step mode. EXCP_DEBUG is returned by the
1209 CPU loop after each instruction */
1210void cpu_single_step(CPUState *env, int enabled)
1211{
bellard1fddef42005-04-17 19:16:13 +00001212#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001213 if (env->singlestep_enabled != enabled) {
1214 env->singlestep_enabled = enabled;
1215 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001216 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001217 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001218 }
1219#endif
1220}
1221
bellard34865132003-10-05 14:28:56 +00001222/* enable or disable low levels log */
1223void cpu_set_log(int log_flags)
1224{
1225 loglevel = log_flags;
1226 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001227 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001228 if (!logfile) {
1229 perror(logfilename);
1230 _exit(1);
1231 }
bellard9fa3e852004-01-04 18:06:42 +00001232#if !defined(CONFIG_SOFTMMU)
1233 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1234 {
1235 static uint8_t logfile_buf[4096];
1236 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1237 }
1238#else
bellard34865132003-10-05 14:28:56 +00001239 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001240#endif
pbrooke735b912007-06-30 13:53:24 +00001241 log_append = 1;
1242 }
1243 if (!loglevel && logfile) {
1244 fclose(logfile);
1245 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001246 }
1247}
1248
1249void cpu_set_log_filename(const char *filename)
1250{
1251 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001252 if (logfile) {
1253 fclose(logfile);
1254 logfile = NULL;
1255 }
1256 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001257}
bellardc33a3462003-07-29 20:50:33 +00001258
bellard01243112004-01-04 15:48:17 +00001259/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001260void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001261{
1262 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001263 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
bellard59817cc2004-02-16 22:01:13 +00001264
bellard68a79312003-06-30 13:12:32 +00001265 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001266 /* if the cpu is currently executing code, we must unlink it and
1267 all the potentially executing TB */
1268 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001269 if (tb && !testandset(&interrupt_lock)) {
1270 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001271 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001272 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001273 }
1274}
1275
bellardb54ad042004-05-20 13:42:52 +00001276void cpu_reset_interrupt(CPUState *env, int mask)
1277{
1278 env->interrupt_request &= ~mask;
1279}
1280
bellardf193c792004-03-21 17:06:25 +00001281CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001282 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001283 "show generated host assembly code for each compiled TB" },
1284 { CPU_LOG_TB_IN_ASM, "in_asm",
1285 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001286 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001287 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001288 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001289 "show micro ops "
1290#ifdef TARGET_I386
1291 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001292#endif
blueswir1e01a1152008-03-14 17:37:11 +00001293 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001294 { CPU_LOG_INT, "int",
1295 "show interrupts/exceptions in short format" },
1296 { CPU_LOG_EXEC, "exec",
1297 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001298 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001299 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001300#ifdef TARGET_I386
1301 { CPU_LOG_PCALL, "pcall",
1302 "show protected mode far calls/returns/exceptions" },
1303#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001304#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001305 { CPU_LOG_IOPORT, "ioport",
1306 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001307#endif
bellardf193c792004-03-21 17:06:25 +00001308 { 0, NULL, NULL },
1309};
1310
1311static int cmp1(const char *s1, int n, const char *s2)
1312{
1313 if (strlen(s2) != n)
1314 return 0;
1315 return memcmp(s1, s2, n) == 0;
1316}
ths3b46e622007-09-17 08:09:54 +00001317
bellardf193c792004-03-21 17:06:25 +00001318/* takes a comma separated list of log masks. Return 0 if error. */
1319int cpu_str_to_log_mask(const char *str)
1320{
1321 CPULogItem *item;
1322 int mask;
1323 const char *p, *p1;
1324
1325 p = str;
1326 mask = 0;
1327 for(;;) {
1328 p1 = strchr(p, ',');
1329 if (!p1)
1330 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001331 if(cmp1(p,p1-p,"all")) {
1332 for(item = cpu_log_items; item->mask != 0; item++) {
1333 mask |= item->mask;
1334 }
1335 } else {
bellardf193c792004-03-21 17:06:25 +00001336 for(item = cpu_log_items; item->mask != 0; item++) {
1337 if (cmp1(p, p1 - p, item->name))
1338 goto found;
1339 }
1340 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001341 }
bellardf193c792004-03-21 17:06:25 +00001342 found:
1343 mask |= item->mask;
1344 if (*p1 != ',')
1345 break;
1346 p = p1 + 1;
1347 }
1348 return mask;
1349}
bellardea041c02003-06-25 16:16:50 +00001350
bellard75012672003-06-21 13:11:07 +00001351void cpu_abort(CPUState *env, const char *fmt, ...)
1352{
1353 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001354 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001355
1356 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001357 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001358 fprintf(stderr, "qemu: fatal: ");
1359 vfprintf(stderr, fmt, ap);
1360 fprintf(stderr, "\n");
1361#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001362 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1363#else
1364 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001365#endif
balrog924edca2007-06-10 14:07:13 +00001366 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001367 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001368 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001369 fprintf(logfile, "\n");
1370#ifdef TARGET_I386
1371 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1372#else
1373 cpu_dump_state(env, logfile, fprintf, 0);
1374#endif
balrog924edca2007-06-10 14:07:13 +00001375 fflush(logfile);
1376 fclose(logfile);
1377 }
pbrook493ae1f2007-11-23 16:53:59 +00001378 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001379 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001380 abort();
1381}
1382
thsc5be9f02007-02-28 20:20:53 +00001383CPUState *cpu_copy(CPUState *env)
1384{
ths01ba9812007-12-09 02:22:57 +00001385 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001386 /* preserve chaining and index */
1387 CPUState *next_cpu = new_env->next_cpu;
1388 int cpu_index = new_env->cpu_index;
1389 memcpy(new_env, env, sizeof(CPUState));
1390 new_env->next_cpu = next_cpu;
1391 new_env->cpu_index = cpu_index;
1392 return new_env;
1393}
1394
bellard01243112004-01-04 15:48:17 +00001395#if !defined(CONFIG_USER_ONLY)
1396
edgar_igl5c751e92008-05-06 08:44:21 +00001397static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1398{
1399 unsigned int i;
1400
1401 /* Discard jump cache entries for any tb which might potentially
1402 overlap the flushed page. */
1403 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1404 memset (&env->tb_jmp_cache[i], 0,
1405 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1406
1407 i = tb_jmp_cache_hash_page(addr);
1408 memset (&env->tb_jmp_cache[i], 0,
1409 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1410}
1411
bellardee8b7022004-02-03 23:35:10 +00001412/* NOTE: if flush_global is true, also flush global entries (not
1413 implemented yet) */
1414void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001415{
bellard33417e72003-08-10 21:47:01 +00001416 int i;
bellard01243112004-01-04 15:48:17 +00001417
bellard9fa3e852004-01-04 18:06:42 +00001418#if defined(DEBUG_TLB)
1419 printf("tlb_flush:\n");
1420#endif
bellard01243112004-01-04 15:48:17 +00001421 /* must reset current TB so that interrupts cannot modify the
1422 links while we are modifying them */
1423 env->current_tb = NULL;
1424
bellard33417e72003-08-10 21:47:01 +00001425 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001426 env->tlb_table[0][i].addr_read = -1;
1427 env->tlb_table[0][i].addr_write = -1;
1428 env->tlb_table[0][i].addr_code = -1;
1429 env->tlb_table[1][i].addr_read = -1;
1430 env->tlb_table[1][i].addr_write = -1;
1431 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001432#if (NB_MMU_MODES >= 3)
1433 env->tlb_table[2][i].addr_read = -1;
1434 env->tlb_table[2][i].addr_write = -1;
1435 env->tlb_table[2][i].addr_code = -1;
1436#if (NB_MMU_MODES == 4)
1437 env->tlb_table[3][i].addr_read = -1;
1438 env->tlb_table[3][i].addr_write = -1;
1439 env->tlb_table[3][i].addr_code = -1;
1440#endif
1441#endif
bellard33417e72003-08-10 21:47:01 +00001442 }
bellard9fa3e852004-01-04 18:06:42 +00001443
bellard8a40a182005-11-20 10:35:40 +00001444 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001445
1446#if !defined(CONFIG_SOFTMMU)
1447 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1448#endif
bellard0a962c02005-02-10 22:00:27 +00001449#ifdef USE_KQEMU
1450 if (env->kqemu_enabled) {
1451 kqemu_flush(env, flush_global);
1452 }
1453#endif
bellarde3db7222005-01-26 22:00:47 +00001454 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001455}
1456
bellard274da6b2004-05-20 21:56:27 +00001457static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001458{
ths5fafdf22007-09-16 21:08:06 +00001459 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001460 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001461 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001462 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001463 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001464 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1465 tlb_entry->addr_read = -1;
1466 tlb_entry->addr_write = -1;
1467 tlb_entry->addr_code = -1;
1468 }
bellard61382a52003-10-27 21:22:23 +00001469}
1470
bellard2e126692004-04-25 21:28:44 +00001471void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001472{
bellard8a40a182005-11-20 10:35:40 +00001473 int i;
bellard01243112004-01-04 15:48:17 +00001474
bellard9fa3e852004-01-04 18:06:42 +00001475#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001476 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001477#endif
bellard01243112004-01-04 15:48:17 +00001478 /* must reset current TB so that interrupts cannot modify the
1479 links while we are modifying them */
1480 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001481
bellard61382a52003-10-27 21:22:23 +00001482 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001483 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001484 tlb_flush_entry(&env->tlb_table[0][i], addr);
1485 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001486#if (NB_MMU_MODES >= 3)
1487 tlb_flush_entry(&env->tlb_table[2][i], addr);
1488#if (NB_MMU_MODES == 4)
1489 tlb_flush_entry(&env->tlb_table[3][i], addr);
1490#endif
1491#endif
bellard01243112004-01-04 15:48:17 +00001492
edgar_igl5c751e92008-05-06 08:44:21 +00001493 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001494
bellard01243112004-01-04 15:48:17 +00001495#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001496 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001497 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001498#endif
bellard0a962c02005-02-10 22:00:27 +00001499#ifdef USE_KQEMU
1500 if (env->kqemu_enabled) {
1501 kqemu_flush_page(env, addr);
1502 }
1503#endif
bellard9fa3e852004-01-04 18:06:42 +00001504}
1505
bellard9fa3e852004-01-04 18:06:42 +00001506/* update the TLBs so that writes to code in the virtual page 'addr'
1507 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001508static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001509{
ths5fafdf22007-09-16 21:08:06 +00001510 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001511 ram_addr + TARGET_PAGE_SIZE,
1512 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001513}
1514
bellard9fa3e852004-01-04 18:06:42 +00001515/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001516 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001517static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001518 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001519{
bellard3a7d9292005-08-21 09:26:42 +00001520 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001521}
1522
ths5fafdf22007-09-16 21:08:06 +00001523static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001524 unsigned long start, unsigned long length)
1525{
1526 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001527 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1528 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001529 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001530 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001531 }
1532 }
1533}
1534
bellard3a7d9292005-08-21 09:26:42 +00001535void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001536 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001537{
1538 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001539 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001540 int i, mask, len;
1541 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001542
1543 start &= TARGET_PAGE_MASK;
1544 end = TARGET_PAGE_ALIGN(end);
1545
1546 length = end - start;
1547 if (length == 0)
1548 return;
bellard0a962c02005-02-10 22:00:27 +00001549 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001550#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001551 /* XXX: should not depend on cpu context */
1552 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001553 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001554 ram_addr_t addr;
1555 addr = start;
1556 for(i = 0; i < len; i++) {
1557 kqemu_set_notdirty(env, addr);
1558 addr += TARGET_PAGE_SIZE;
1559 }
bellard3a7d9292005-08-21 09:26:42 +00001560 }
1561#endif
bellardf23db162005-08-21 19:12:28 +00001562 mask = ~dirty_flags;
1563 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1564 for(i = 0; i < len; i++)
1565 p[i] &= mask;
1566
bellard1ccde1c2004-02-06 19:46:14 +00001567 /* we modify the TLB cache so that the dirty bit will be set again
1568 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001569 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001570 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1571 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001572 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001573 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001574 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001575#if (NB_MMU_MODES >= 3)
1576 for(i = 0; i < CPU_TLB_SIZE; i++)
1577 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1578#if (NB_MMU_MODES == 4)
1579 for(i = 0; i < CPU_TLB_SIZE; i++)
1580 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1581#endif
1582#endif
bellard6a00d602005-11-21 23:25:50 +00001583 }
bellard59817cc2004-02-16 22:01:13 +00001584
1585#if !defined(CONFIG_SOFTMMU)
1586 /* XXX: this is expensive */
1587 {
1588 VirtPageDesc *p;
1589 int j;
1590 target_ulong addr;
1591
1592 for(i = 0; i < L1_SIZE; i++) {
1593 p = l1_virt_map[i];
1594 if (p) {
1595 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1596 for(j = 0; j < L2_SIZE; j++) {
1597 if (p->valid_tag == virt_valid_tag &&
1598 p->phys_addr >= start && p->phys_addr < end &&
1599 (p->prot & PROT_WRITE)) {
1600 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001601 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001602 p->prot & ~PROT_WRITE);
1603 }
1604 }
1605 addr += TARGET_PAGE_SIZE;
1606 p++;
1607 }
1608 }
1609 }
1610 }
1611#endif
bellard1ccde1c2004-02-06 19:46:14 +00001612}
1613
bellard3a7d9292005-08-21 09:26:42 +00001614static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1615{
1616 ram_addr_t ram_addr;
1617
bellard84b7b8e2005-11-28 21:19:04 +00001618 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001619 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001620 tlb_entry->addend - (unsigned long)phys_ram_base;
1621 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001622 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001623 }
1624 }
1625}
1626
1627/* update the TLB according to the current state of the dirty bits */
1628void cpu_tlb_update_dirty(CPUState *env)
1629{
1630 int i;
1631 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001632 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001633 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001634 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001635#if (NB_MMU_MODES >= 3)
1636 for(i = 0; i < CPU_TLB_SIZE; i++)
1637 tlb_update_dirty(&env->tlb_table[2][i]);
1638#if (NB_MMU_MODES == 4)
1639 for(i = 0; i < CPU_TLB_SIZE; i++)
1640 tlb_update_dirty(&env->tlb_table[3][i]);
1641#endif
1642#endif
bellard3a7d9292005-08-21 09:26:42 +00001643}
1644
ths5fafdf22007-09-16 21:08:06 +00001645static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001646 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001647{
1648 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001649 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1650 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001651 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001652 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001653 }
1654 }
1655}
1656
1657/* update the TLB corresponding to virtual page vaddr and phys addr
1658 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001659static inline void tlb_set_dirty(CPUState *env,
1660 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001661{
bellard1ccde1c2004-02-06 19:46:14 +00001662 int i;
1663
bellard1ccde1c2004-02-06 19:46:14 +00001664 addr &= TARGET_PAGE_MASK;
1665 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001666 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1667 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001668#if (NB_MMU_MODES >= 3)
1669 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1670#if (NB_MMU_MODES == 4)
1671 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1672#endif
1673#endif
bellard9fa3e852004-01-04 18:06:42 +00001674}
1675
bellard59817cc2004-02-16 22:01:13 +00001676/* add a new TLB entry. At most one entry for a given virtual address
1677 is permitted. Return 0 if OK or 2 if the page could not be mapped
1678 (can only happen in non SOFTMMU mode for I/O pages or pages
1679 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001680int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1681 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001682 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001683{
bellard92e873b2004-05-21 14:52:29 +00001684 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001685 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001686 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001687 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001688 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001689 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001690 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001691 int i;
bellard9fa3e852004-01-04 18:06:42 +00001692
bellard92e873b2004-05-21 14:52:29 +00001693 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001694 if (!p) {
1695 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001696 } else {
1697 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001698 }
1699#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001700 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1701 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001702#endif
1703
1704 ret = 0;
1705#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001706 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001707#endif
1708 {
bellard2a4188a2006-06-25 21:54:59 +00001709 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001710 /* IO memory case */
1711 address = vaddr | pd;
1712 addend = paddr;
1713 } else {
1714 /* standard memory */
1715 address = vaddr;
1716 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1717 }
pbrook6658ffb2007-03-16 23:58:11 +00001718
1719 /* Make accesses to pages with watchpoints go via the
1720 watchpoint trap routines. */
1721 for (i = 0; i < env->nb_watchpoints; i++) {
1722 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1723 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001724 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001725 address = vaddr | io_mem_watch;
1726 } else {
balrogd79acba2007-06-26 20:01:13 +00001727 env->watchpoint[i].addend = pd - paddr +
1728 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001729 /* TODO: Figure out how to make read watchpoints coexist
1730 with code. */
1731 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1732 }
1733 }
1734 }
balrogd79acba2007-06-26 20:01:13 +00001735
bellard90f18422005-07-24 10:17:31 +00001736 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001737 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001738 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001739 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001740 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001741 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001742 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001743 te->addr_read = -1;
1744 }
edgar_igl5c751e92008-05-06 08:44:21 +00001745
1746 if (te->addr_code != -1) {
1747 tlb_flush_jmp_cache(env, te->addr_code);
1748 }
bellard84b7b8e2005-11-28 21:19:04 +00001749 if (prot & PAGE_EXEC) {
1750 te->addr_code = address;
1751 } else {
1752 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001753 }
bellard67b915a2004-03-31 23:37:16 +00001754 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001755 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001756 (pd & IO_MEM_ROMD)) {
1757 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001758 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001759 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001760 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001761 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001762 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001763 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001764 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001765 }
1766 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001767 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001768 }
1769 }
1770#if !defined(CONFIG_SOFTMMU)
1771 else {
1772 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1773 /* IO access: no mapping is done as it will be handled by the
1774 soft MMU */
1775 if (!(env->hflags & HF_SOFTMMU_MASK))
1776 ret = 2;
1777 } else {
1778 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001779
bellard59817cc2004-02-16 22:01:13 +00001780 if (vaddr >= MMAP_AREA_END) {
1781 ret = 2;
1782 } else {
1783 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001784 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001785#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001786 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001787#endif
ths5fafdf22007-09-16 21:08:06 +00001788 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001789 !cpu_physical_memory_is_dirty(pd))) {
1790 /* ROM: we do as if code was inside */
1791 /* if code is present, we only map as read only and save the
1792 original mapping */
1793 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001794
bellard90f18422005-07-24 10:17:31 +00001795 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001796 vp->phys_addr = pd;
1797 vp->prot = prot;
1798 vp->valid_tag = virt_valid_tag;
1799 prot &= ~PAGE_WRITE;
1800 }
bellard9fa3e852004-01-04 18:06:42 +00001801 }
ths5fafdf22007-09-16 21:08:06 +00001802 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001803 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1804 if (map_addr == MAP_FAILED) {
1805 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1806 paddr, vaddr);
1807 }
bellard9fa3e852004-01-04 18:06:42 +00001808 }
1809 }
1810 }
1811#endif
1812 return ret;
1813}
1814
1815/* called from signal handler: invalidate the code and unprotect the
1816 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001817int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001818{
1819#if !defined(CONFIG_SOFTMMU)
1820 VirtPageDesc *vp;
1821
1822#if defined(DEBUG_TLB)
1823 printf("page_unprotect: addr=0x%08x\n", addr);
1824#endif
1825 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001826
1827 /* if it is not mapped, no need to worry here */
1828 if (addr >= MMAP_AREA_END)
1829 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001830 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1831 if (!vp)
1832 return 0;
1833 /* NOTE: in this case, validate_tag is _not_ tested as it
1834 validates only the code TLB */
1835 if (vp->valid_tag != virt_valid_tag)
1836 return 0;
1837 if (!(vp->prot & PAGE_WRITE))
1838 return 0;
1839#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001840 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001841 addr, vp->phys_addr, vp->prot);
1842#endif
bellard59817cc2004-02-16 22:01:13 +00001843 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1844 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1845 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001846 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001847 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001848 /* flush the code inside */
1849 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001850 return 1;
1851#else
1852 return 0;
1853#endif
bellard33417e72003-08-10 21:47:01 +00001854}
1855
bellard01243112004-01-04 15:48:17 +00001856#else
1857
bellardee8b7022004-02-03 23:35:10 +00001858void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001859{
1860}
1861
bellard2e126692004-04-25 21:28:44 +00001862void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001863{
1864}
1865
ths5fafdf22007-09-16 21:08:06 +00001866int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1867 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001868 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001869{
bellard9fa3e852004-01-04 18:06:42 +00001870 return 0;
1871}
bellard33417e72003-08-10 21:47:01 +00001872
bellard9fa3e852004-01-04 18:06:42 +00001873/* dump memory mappings */
1874void page_dump(FILE *f)
1875{
1876 unsigned long start, end;
1877 int i, j, prot, prot1;
1878 PageDesc *p;
1879
1880 fprintf(f, "%-8s %-8s %-8s %s\n",
1881 "start", "end", "size", "prot");
1882 start = -1;
1883 end = -1;
1884 prot = 0;
1885 for(i = 0; i <= L1_SIZE; i++) {
1886 if (i < L1_SIZE)
1887 p = l1_map[i];
1888 else
1889 p = NULL;
1890 for(j = 0;j < L2_SIZE; j++) {
1891 if (!p)
1892 prot1 = 0;
1893 else
1894 prot1 = p[j].flags;
1895 if (prot1 != prot) {
1896 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1897 if (start != -1) {
1898 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001899 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001900 prot & PAGE_READ ? 'r' : '-',
1901 prot & PAGE_WRITE ? 'w' : '-',
1902 prot & PAGE_EXEC ? 'x' : '-');
1903 }
1904 if (prot1 != 0)
1905 start = end;
1906 else
1907 start = -1;
1908 prot = prot1;
1909 }
1910 if (!p)
1911 break;
1912 }
bellard33417e72003-08-10 21:47:01 +00001913 }
bellard33417e72003-08-10 21:47:01 +00001914}
1915
pbrook53a59602006-03-25 19:31:22 +00001916int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001917{
bellard9fa3e852004-01-04 18:06:42 +00001918 PageDesc *p;
1919
1920 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001921 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001922 return 0;
1923 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001924}
1925
bellard9fa3e852004-01-04 18:06:42 +00001926/* modify the flags of a page and invalidate the code if
1927 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1928 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001929void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001930{
1931 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001932 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001933
1934 start = start & TARGET_PAGE_MASK;
1935 end = TARGET_PAGE_ALIGN(end);
1936 if (flags & PAGE_WRITE)
1937 flags |= PAGE_WRITE_ORG;
1938 spin_lock(&tb_lock);
1939 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1940 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1941 /* if the write protection is set, then we invalidate the code
1942 inside */
ths5fafdf22007-09-16 21:08:06 +00001943 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001944 (flags & PAGE_WRITE) &&
1945 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001946 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001947 }
1948 p->flags = flags;
1949 }
1950 spin_unlock(&tb_lock);
1951}
1952
ths3d97b402007-11-02 19:02:07 +00001953int page_check_range(target_ulong start, target_ulong len, int flags)
1954{
1955 PageDesc *p;
1956 target_ulong end;
1957 target_ulong addr;
1958
1959 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1960 start = start & TARGET_PAGE_MASK;
1961
1962 if( end < start )
1963 /* we've wrapped around */
1964 return -1;
1965 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1966 p = page_find(addr >> TARGET_PAGE_BITS);
1967 if( !p )
1968 return -1;
1969 if( !(p->flags & PAGE_VALID) )
1970 return -1;
1971
bellarddae32702007-11-14 10:51:00 +00001972 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001973 return -1;
bellarddae32702007-11-14 10:51:00 +00001974 if (flags & PAGE_WRITE) {
1975 if (!(p->flags & PAGE_WRITE_ORG))
1976 return -1;
1977 /* unprotect the page if it was put read-only because it
1978 contains translated code */
1979 if (!(p->flags & PAGE_WRITE)) {
1980 if (!page_unprotect(addr, 0, NULL))
1981 return -1;
1982 }
1983 return 0;
1984 }
ths3d97b402007-11-02 19:02:07 +00001985 }
1986 return 0;
1987}
1988
bellard9fa3e852004-01-04 18:06:42 +00001989/* called from signal handler: invalidate the code and unprotect the
1990 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001991int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001992{
1993 unsigned int page_index, prot, pindex;
1994 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001995 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001996
bellard83fb7ad2004-07-05 21:25:26 +00001997 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001998 page_index = host_start >> TARGET_PAGE_BITS;
1999 p1 = page_find(page_index);
2000 if (!p1)
2001 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00002002 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002003 p = p1;
2004 prot = 0;
2005 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2006 prot |= p->flags;
2007 p++;
2008 }
2009 /* if the page was really writable, then we change its
2010 protection back to writable */
2011 if (prot & PAGE_WRITE_ORG) {
2012 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2013 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002014 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002015 (prot & PAGE_BITS) | PAGE_WRITE);
2016 p1[pindex].flags |= PAGE_WRITE;
2017 /* and since the content will be modified, we must invalidate
2018 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002019 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002020#ifdef DEBUG_TB_CHECK
2021 tb_invalidate_check(address);
2022#endif
2023 return 1;
2024 }
2025 }
2026 return 0;
2027}
2028
bellard6a00d602005-11-21 23:25:50 +00002029static inline void tlb_set_dirty(CPUState *env,
2030 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002031{
2032}
bellard9fa3e852004-01-04 18:06:42 +00002033#endif /* defined(CONFIG_USER_ONLY) */
2034
blueswir1db7b5422007-05-26 17:36:03 +00002035static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002036 ram_addr_t memory);
2037static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2038 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002039#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2040 need_subpage) \
2041 do { \
2042 if (addr > start_addr) \
2043 start_addr2 = 0; \
2044 else { \
2045 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2046 if (start_addr2 > 0) \
2047 need_subpage = 1; \
2048 } \
2049 \
blueswir149e9fba2007-05-30 17:25:06 +00002050 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002051 end_addr2 = TARGET_PAGE_SIZE - 1; \
2052 else { \
2053 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2054 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2055 need_subpage = 1; \
2056 } \
2057 } while (0)
2058
bellard33417e72003-08-10 21:47:01 +00002059/* register physical memory. 'size' must be a multiple of the target
2060 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2061 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002062void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002063 ram_addr_t size,
2064 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002065{
bellard108c49b2005-07-24 12:55:09 +00002066 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002067 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002068 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002069 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002070 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002071
bellard5fd386f2004-05-23 21:11:22 +00002072 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002073 end_addr = start_addr + (target_phys_addr_t)size;
2074 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002075 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2076 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002077 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002078 target_phys_addr_t start_addr2, end_addr2;
2079 int need_subpage = 0;
2080
2081 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2082 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002083 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002084 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2085 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2086 &p->phys_offset, orig_memory);
2087 } else {
2088 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2089 >> IO_MEM_SHIFT];
2090 }
2091 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2092 } else {
2093 p->phys_offset = phys_offset;
2094 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2095 (phys_offset & IO_MEM_ROMD))
2096 phys_offset += TARGET_PAGE_SIZE;
2097 }
2098 } else {
2099 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2100 p->phys_offset = phys_offset;
2101 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2102 (phys_offset & IO_MEM_ROMD))
2103 phys_offset += TARGET_PAGE_SIZE;
2104 else {
2105 target_phys_addr_t start_addr2, end_addr2;
2106 int need_subpage = 0;
2107
2108 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2109 end_addr2, need_subpage);
2110
blueswir14254fab2008-01-01 16:57:19 +00002111 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002112 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2113 &p->phys_offset, IO_MEM_UNASSIGNED);
2114 subpage_register(subpage, start_addr2, end_addr2,
2115 phys_offset);
2116 }
2117 }
2118 }
bellard33417e72003-08-10 21:47:01 +00002119 }
ths3b46e622007-09-17 08:09:54 +00002120
bellard9d420372006-06-25 22:25:22 +00002121 /* since each CPU stores ram addresses in its TLB cache, we must
2122 reset the modified entries */
2123 /* XXX: slow ! */
2124 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2125 tlb_flush(env, 1);
2126 }
bellard33417e72003-08-10 21:47:01 +00002127}
2128
bellardba863452006-09-24 18:41:10 +00002129/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002130ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002131{
2132 PhysPageDesc *p;
2133
2134 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2135 if (!p)
2136 return IO_MEM_UNASSIGNED;
2137 return p->phys_offset;
2138}
2139
bellarde9a1ab12007-02-08 23:08:38 +00002140/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002141ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002142{
2143 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002144 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
aurel3200f82b82008-04-27 21:12:55 +00002145 fprintf(stderr, "Not enough memory (requested_size = %lu, max memory = %ld)\n",
aurel3203875442008-04-22 20:45:18 +00002146 size, phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002147 abort();
2148 }
2149 addr = phys_ram_alloc_offset;
2150 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2151 return addr;
2152}
2153
2154void qemu_ram_free(ram_addr_t addr)
2155{
2156}
2157
bellarda4193c82004-06-03 14:01:43 +00002158static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002159{
pbrook67d3b952006-12-18 05:03:52 +00002160#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002161 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002162#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002163#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002164 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002165#elif TARGET_CRIS
2166 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002167#endif
bellard33417e72003-08-10 21:47:01 +00002168 return 0;
2169}
2170
bellarda4193c82004-06-03 14:01:43 +00002171static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002172{
pbrook67d3b952006-12-18 05:03:52 +00002173#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002174 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002175#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002176#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002177 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002178#elif TARGET_CRIS
2179 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002180#endif
bellard33417e72003-08-10 21:47:01 +00002181}
2182
2183static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2184 unassigned_mem_readb,
2185 unassigned_mem_readb,
2186 unassigned_mem_readb,
2187};
2188
2189static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2190 unassigned_mem_writeb,
2191 unassigned_mem_writeb,
2192 unassigned_mem_writeb,
2193};
2194
bellarda4193c82004-06-03 14:01:43 +00002195static void notdirty_mem_writeb(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, 1);
2204 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2205#endif
2206 }
bellardc27004e2005-01-03 23:35:10 +00002207 stb_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
bellarda4193c82004-06-03 14:01:43 +00002221static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002222{
bellard3a7d9292005-08-21 09:26:42 +00002223 unsigned long ram_addr;
2224 int dirty_flags;
2225 ram_addr = addr - (unsigned long)phys_ram_base;
2226 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2227 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2228#if !defined(CONFIG_USER_ONLY)
2229 tb_invalidate_phys_page_fast(ram_addr, 2);
2230 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2231#endif
2232 }
bellardc27004e2005-01-03 23:35:10 +00002233 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002234#ifdef USE_KQEMU
2235 if (cpu_single_env->kqemu_enabled &&
2236 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2237 kqemu_modify_page(cpu_single_env, ram_addr);
2238#endif
bellardf23db162005-08-21 19:12:28 +00002239 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2240 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2241 /* we remove the notdirty callback only if the code has been
2242 flushed */
2243 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002244 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002245}
2246
bellarda4193c82004-06-03 14:01:43 +00002247static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002248{
bellard3a7d9292005-08-21 09:26:42 +00002249 unsigned long ram_addr;
2250 int dirty_flags;
2251 ram_addr = addr - (unsigned long)phys_ram_base;
2252 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2253 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2254#if !defined(CONFIG_USER_ONLY)
2255 tb_invalidate_phys_page_fast(ram_addr, 4);
2256 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2257#endif
2258 }
bellardc27004e2005-01-03 23:35:10 +00002259 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002260#ifdef USE_KQEMU
2261 if (cpu_single_env->kqemu_enabled &&
2262 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2263 kqemu_modify_page(cpu_single_env, ram_addr);
2264#endif
bellardf23db162005-08-21 19:12:28 +00002265 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2266 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2267 /* we remove the notdirty callback only if the code has been
2268 flushed */
2269 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002270 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002271}
2272
bellard3a7d9292005-08-21 09:26:42 +00002273static CPUReadMemoryFunc *error_mem_read[3] = {
2274 NULL, /* never used */
2275 NULL, /* never used */
2276 NULL, /* never used */
2277};
2278
bellard1ccde1c2004-02-06 19:46:14 +00002279static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2280 notdirty_mem_writeb,
2281 notdirty_mem_writew,
2282 notdirty_mem_writel,
2283};
2284
pbrook6658ffb2007-03-16 23:58:11 +00002285#if defined(CONFIG_SOFTMMU)
2286/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2287 so these check for a hit then pass through to the normal out-of-line
2288 phys routines. */
2289static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2290{
2291 return ldub_phys(addr);
2292}
2293
2294static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2295{
2296 return lduw_phys(addr);
2297}
2298
2299static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2300{
2301 return ldl_phys(addr);
2302}
2303
2304/* Generate a debug exception if a watchpoint has been hit.
2305 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002306 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002307static target_ulong check_watchpoint(target_phys_addr_t addr)
2308{
2309 CPUState *env = cpu_single_env;
2310 target_ulong watch;
2311 target_ulong retaddr;
2312 int i;
2313
2314 retaddr = addr;
2315 for (i = 0; i < env->nb_watchpoints; i++) {
2316 watch = env->watchpoint[i].vaddr;
2317 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002318 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002319 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2320 cpu_single_env->watchpoint_hit = i + 1;
2321 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2322 break;
2323 }
2324 }
2325 }
2326 return retaddr;
2327}
2328
2329static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2330 uint32_t val)
2331{
2332 addr = check_watchpoint(addr);
2333 stb_phys(addr, val);
2334}
2335
2336static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2337 uint32_t val)
2338{
2339 addr = check_watchpoint(addr);
2340 stw_phys(addr, val);
2341}
2342
2343static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2344 uint32_t val)
2345{
2346 addr = check_watchpoint(addr);
2347 stl_phys(addr, val);
2348}
2349
2350static CPUReadMemoryFunc *watch_mem_read[3] = {
2351 watch_mem_readb,
2352 watch_mem_readw,
2353 watch_mem_readl,
2354};
2355
2356static CPUWriteMemoryFunc *watch_mem_write[3] = {
2357 watch_mem_writeb,
2358 watch_mem_writew,
2359 watch_mem_writel,
2360};
2361#endif
2362
blueswir1db7b5422007-05-26 17:36:03 +00002363static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2364 unsigned int len)
2365{
blueswir1db7b5422007-05-26 17:36:03 +00002366 uint32_t ret;
2367 unsigned int idx;
2368
2369 idx = SUBPAGE_IDX(addr - mmio->base);
2370#if defined(DEBUG_SUBPAGE)
2371 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2372 mmio, len, addr, idx);
2373#endif
blueswir13ee89922008-01-02 19:45:26 +00002374 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002375
2376 return ret;
2377}
2378
2379static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2380 uint32_t value, unsigned int len)
2381{
blueswir1db7b5422007-05-26 17:36:03 +00002382 unsigned int idx;
2383
2384 idx = SUBPAGE_IDX(addr - mmio->base);
2385#if defined(DEBUG_SUBPAGE)
2386 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2387 mmio, len, addr, idx, value);
2388#endif
blueswir13ee89922008-01-02 19:45:26 +00002389 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002390}
2391
2392static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2393{
2394#if defined(DEBUG_SUBPAGE)
2395 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2396#endif
2397
2398 return subpage_readlen(opaque, addr, 0);
2399}
2400
2401static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2402 uint32_t value)
2403{
2404#if defined(DEBUG_SUBPAGE)
2405 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2406#endif
2407 subpage_writelen(opaque, addr, value, 0);
2408}
2409
2410static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2411{
2412#if defined(DEBUG_SUBPAGE)
2413 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2414#endif
2415
2416 return subpage_readlen(opaque, addr, 1);
2417}
2418
2419static void subpage_writew (void *opaque, target_phys_addr_t addr,
2420 uint32_t value)
2421{
2422#if defined(DEBUG_SUBPAGE)
2423 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2424#endif
2425 subpage_writelen(opaque, addr, value, 1);
2426}
2427
2428static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2429{
2430#if defined(DEBUG_SUBPAGE)
2431 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2432#endif
2433
2434 return subpage_readlen(opaque, addr, 2);
2435}
2436
2437static void subpage_writel (void *opaque,
2438 target_phys_addr_t addr, uint32_t value)
2439{
2440#if defined(DEBUG_SUBPAGE)
2441 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2442#endif
2443 subpage_writelen(opaque, addr, value, 2);
2444}
2445
2446static CPUReadMemoryFunc *subpage_read[] = {
2447 &subpage_readb,
2448 &subpage_readw,
2449 &subpage_readl,
2450};
2451
2452static CPUWriteMemoryFunc *subpage_write[] = {
2453 &subpage_writeb,
2454 &subpage_writew,
2455 &subpage_writel,
2456};
2457
2458static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002459 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002460{
2461 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002462 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002463
2464 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2465 return -1;
2466 idx = SUBPAGE_IDX(start);
2467 eidx = SUBPAGE_IDX(end);
2468#if defined(DEBUG_SUBPAGE)
2469 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2470 mmio, start, end, idx, eidx, memory);
2471#endif
2472 memory >>= IO_MEM_SHIFT;
2473 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002474 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002475 if (io_mem_read[memory][i]) {
2476 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2477 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2478 }
2479 if (io_mem_write[memory][i]) {
2480 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2481 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2482 }
blueswir14254fab2008-01-01 16:57:19 +00002483 }
blueswir1db7b5422007-05-26 17:36:03 +00002484 }
2485
2486 return 0;
2487}
2488
aurel3200f82b82008-04-27 21:12:55 +00002489static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2490 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002491{
2492 subpage_t *mmio;
2493 int subpage_memory;
2494
2495 mmio = qemu_mallocz(sizeof(subpage_t));
2496 if (mmio != NULL) {
2497 mmio->base = base;
2498 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2499#if defined(DEBUG_SUBPAGE)
2500 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2501 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2502#endif
2503 *phys = subpage_memory | IO_MEM_SUBPAGE;
2504 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2505 }
2506
2507 return mmio;
2508}
2509
bellard33417e72003-08-10 21:47:01 +00002510static void io_mem_init(void)
2511{
bellard3a7d9292005-08-21 09:26:42 +00002512 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002513 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002514 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002515 io_mem_nb = 5;
2516
pbrook6658ffb2007-03-16 23:58:11 +00002517#if defined(CONFIG_SOFTMMU)
2518 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2519 watch_mem_write, NULL);
2520#endif
bellard1ccde1c2004-02-06 19:46:14 +00002521 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002522 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002523 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002524}
2525
2526/* mem_read and mem_write are arrays of functions containing the
2527 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002528 2). Functions can be omitted with a NULL function pointer. The
2529 registered functions may be modified dynamically later.
2530 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002531 modified. If it is zero, a new io zone is allocated. The return
2532 value can be used with cpu_register_physical_memory(). (-1) is
2533 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002534int cpu_register_io_memory(int io_index,
2535 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002536 CPUWriteMemoryFunc **mem_write,
2537 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002538{
blueswir14254fab2008-01-01 16:57:19 +00002539 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002540
2541 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002542 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002543 return -1;
2544 io_index = io_mem_nb++;
2545 } else {
2546 if (io_index >= IO_MEM_NB_ENTRIES)
2547 return -1;
2548 }
bellardb5ff1b32005-11-26 10:38:39 +00002549
bellard33417e72003-08-10 21:47:01 +00002550 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002551 if (!mem_read[i] || !mem_write[i])
2552 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002553 io_mem_read[io_index][i] = mem_read[i];
2554 io_mem_write[io_index][i] = mem_write[i];
2555 }
bellarda4193c82004-06-03 14:01:43 +00002556 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002557 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002558}
bellard61382a52003-10-27 21:22:23 +00002559
bellard8926b512004-10-10 15:14:20 +00002560CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2561{
2562 return io_mem_write[io_index >> IO_MEM_SHIFT];
2563}
2564
2565CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2566{
2567 return io_mem_read[io_index >> IO_MEM_SHIFT];
2568}
2569
bellard13eb76e2004-01-24 15:23:36 +00002570/* physical memory access (slow version, mainly for debug) */
2571#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002572void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002573 int len, int is_write)
2574{
2575 int l, flags;
2576 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002577 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002578
2579 while (len > 0) {
2580 page = addr & TARGET_PAGE_MASK;
2581 l = (page + TARGET_PAGE_SIZE) - addr;
2582 if (l > len)
2583 l = len;
2584 flags = page_get_flags(page);
2585 if (!(flags & PAGE_VALID))
2586 return;
2587 if (is_write) {
2588 if (!(flags & PAGE_WRITE))
2589 return;
bellard579a97f2007-11-11 14:26:47 +00002590 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002591 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002592 /* FIXME - should this return an error rather than just fail? */
2593 return;
aurel3272fb7da2008-04-27 23:53:45 +00002594 memcpy(p, buf, l);
2595 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002596 } else {
2597 if (!(flags & PAGE_READ))
2598 return;
bellard579a97f2007-11-11 14:26:47 +00002599 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002600 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002601 /* FIXME - should this return an error rather than just fail? */
2602 return;
aurel3272fb7da2008-04-27 23:53:45 +00002603 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002604 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002605 }
2606 len -= l;
2607 buf += l;
2608 addr += l;
2609 }
2610}
bellard8df1cd02005-01-28 22:37:22 +00002611
bellard13eb76e2004-01-24 15:23:36 +00002612#else
ths5fafdf22007-09-16 21:08:06 +00002613void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002614 int len, int is_write)
2615{
2616 int l, io_index;
2617 uint8_t *ptr;
2618 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002619 target_phys_addr_t page;
2620 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002621 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002622
bellard13eb76e2004-01-24 15:23:36 +00002623 while (len > 0) {
2624 page = addr & TARGET_PAGE_MASK;
2625 l = (page + TARGET_PAGE_SIZE) - addr;
2626 if (l > len)
2627 l = len;
bellard92e873b2004-05-21 14:52:29 +00002628 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002629 if (!p) {
2630 pd = IO_MEM_UNASSIGNED;
2631 } else {
2632 pd = p->phys_offset;
2633 }
ths3b46e622007-09-17 08:09:54 +00002634
bellard13eb76e2004-01-24 15:23:36 +00002635 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002636 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002637 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002638 /* XXX: could force cpu_single_env to NULL to avoid
2639 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002640 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002641 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002642 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002643 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002644 l = 4;
2645 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002646 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002647 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002648 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002649 l = 2;
2650 } else {
bellard1c213d12005-09-03 10:49:04 +00002651 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002652 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002653 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002654 l = 1;
2655 }
2656 } else {
bellardb448f2f2004-02-25 23:24:04 +00002657 unsigned long addr1;
2658 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002659 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002660 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002661 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002662 if (!cpu_physical_memory_is_dirty(addr1)) {
2663 /* invalidate code */
2664 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2665 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002666 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002667 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002668 }
bellard13eb76e2004-01-24 15:23:36 +00002669 }
2670 } else {
ths5fafdf22007-09-16 21:08:06 +00002671 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002672 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002673 /* I/O case */
2674 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2675 if (l >= 4 && ((addr & 3) == 0)) {
2676 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002677 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002678 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002679 l = 4;
2680 } else if (l >= 2 && ((addr & 1) == 0)) {
2681 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002682 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002683 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002684 l = 2;
2685 } else {
bellard1c213d12005-09-03 10:49:04 +00002686 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002687 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002688 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002689 l = 1;
2690 }
2691 } else {
2692 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002693 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002694 (addr & ~TARGET_PAGE_MASK);
2695 memcpy(buf, ptr, l);
2696 }
2697 }
2698 len -= l;
2699 buf += l;
2700 addr += l;
2701 }
2702}
bellard8df1cd02005-01-28 22:37:22 +00002703
bellardd0ecd2a2006-04-23 17:14:48 +00002704/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002705void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002706 const uint8_t *buf, int len)
2707{
2708 int l;
2709 uint8_t *ptr;
2710 target_phys_addr_t page;
2711 unsigned long pd;
2712 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002713
bellardd0ecd2a2006-04-23 17:14:48 +00002714 while (len > 0) {
2715 page = addr & TARGET_PAGE_MASK;
2716 l = (page + TARGET_PAGE_SIZE) - addr;
2717 if (l > len)
2718 l = len;
2719 p = phys_page_find(page >> TARGET_PAGE_BITS);
2720 if (!p) {
2721 pd = IO_MEM_UNASSIGNED;
2722 } else {
2723 pd = p->phys_offset;
2724 }
ths3b46e622007-09-17 08:09:54 +00002725
bellardd0ecd2a2006-04-23 17:14:48 +00002726 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002727 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2728 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002729 /* do nothing */
2730 } else {
2731 unsigned long addr1;
2732 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2733 /* ROM/RAM case */
2734 ptr = phys_ram_base + addr1;
2735 memcpy(ptr, buf, l);
2736 }
2737 len -= l;
2738 buf += l;
2739 addr += l;
2740 }
2741}
2742
2743
bellard8df1cd02005-01-28 22:37:22 +00002744/* warning: addr must be aligned */
2745uint32_t ldl_phys(target_phys_addr_t addr)
2746{
2747 int io_index;
2748 uint8_t *ptr;
2749 uint32_t val;
2750 unsigned long pd;
2751 PhysPageDesc *p;
2752
2753 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2754 if (!p) {
2755 pd = IO_MEM_UNASSIGNED;
2756 } else {
2757 pd = p->phys_offset;
2758 }
ths3b46e622007-09-17 08:09:54 +00002759
ths5fafdf22007-09-16 21:08:06 +00002760 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002761 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002762 /* I/O case */
2763 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2764 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2765 } else {
2766 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002767 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002768 (addr & ~TARGET_PAGE_MASK);
2769 val = ldl_p(ptr);
2770 }
2771 return val;
2772}
2773
bellard84b7b8e2005-11-28 21:19:04 +00002774/* warning: addr must be aligned */
2775uint64_t ldq_phys(target_phys_addr_t addr)
2776{
2777 int io_index;
2778 uint8_t *ptr;
2779 uint64_t val;
2780 unsigned long pd;
2781 PhysPageDesc *p;
2782
2783 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2784 if (!p) {
2785 pd = IO_MEM_UNASSIGNED;
2786 } else {
2787 pd = p->phys_offset;
2788 }
ths3b46e622007-09-17 08:09:54 +00002789
bellard2a4188a2006-06-25 21:54:59 +00002790 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2791 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002792 /* I/O case */
2793 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2794#ifdef TARGET_WORDS_BIGENDIAN
2795 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2796 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2797#else
2798 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2799 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2800#endif
2801 } else {
2802 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002803 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002804 (addr & ~TARGET_PAGE_MASK);
2805 val = ldq_p(ptr);
2806 }
2807 return val;
2808}
2809
bellardaab33092005-10-30 20:48:42 +00002810/* XXX: optimize */
2811uint32_t ldub_phys(target_phys_addr_t addr)
2812{
2813 uint8_t val;
2814 cpu_physical_memory_read(addr, &val, 1);
2815 return val;
2816}
2817
2818/* XXX: optimize */
2819uint32_t lduw_phys(target_phys_addr_t addr)
2820{
2821 uint16_t val;
2822 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2823 return tswap16(val);
2824}
2825
bellard8df1cd02005-01-28 22:37:22 +00002826/* warning: addr must be aligned. The ram page is not masked as dirty
2827 and the code inside is not invalidated. It is useful if the dirty
2828 bits are used to track modified PTEs */
2829void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2830{
2831 int io_index;
2832 uint8_t *ptr;
2833 unsigned long pd;
2834 PhysPageDesc *p;
2835
2836 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2837 if (!p) {
2838 pd = IO_MEM_UNASSIGNED;
2839 } else {
2840 pd = p->phys_offset;
2841 }
ths3b46e622007-09-17 08:09:54 +00002842
bellard3a7d9292005-08-21 09:26:42 +00002843 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002844 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2845 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2846 } else {
ths5fafdf22007-09-16 21:08:06 +00002847 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002848 (addr & ~TARGET_PAGE_MASK);
2849 stl_p(ptr, val);
2850 }
2851}
2852
j_mayerbc98a7e2007-04-04 07:55:12 +00002853void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2854{
2855 int io_index;
2856 uint8_t *ptr;
2857 unsigned long pd;
2858 PhysPageDesc *p;
2859
2860 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2861 if (!p) {
2862 pd = IO_MEM_UNASSIGNED;
2863 } else {
2864 pd = p->phys_offset;
2865 }
ths3b46e622007-09-17 08:09:54 +00002866
j_mayerbc98a7e2007-04-04 07:55:12 +00002867 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2868 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2869#ifdef TARGET_WORDS_BIGENDIAN
2870 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2871 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2872#else
2873 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2874 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2875#endif
2876 } else {
ths5fafdf22007-09-16 21:08:06 +00002877 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002878 (addr & ~TARGET_PAGE_MASK);
2879 stq_p(ptr, val);
2880 }
2881}
2882
bellard8df1cd02005-01-28 22:37:22 +00002883/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002884void stl_phys(target_phys_addr_t addr, uint32_t val)
2885{
2886 int io_index;
2887 uint8_t *ptr;
2888 unsigned long pd;
2889 PhysPageDesc *p;
2890
2891 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2892 if (!p) {
2893 pd = IO_MEM_UNASSIGNED;
2894 } else {
2895 pd = p->phys_offset;
2896 }
ths3b46e622007-09-17 08:09:54 +00002897
bellard3a7d9292005-08-21 09:26:42 +00002898 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002899 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2900 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2901 } else {
2902 unsigned long addr1;
2903 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2904 /* RAM case */
2905 ptr = phys_ram_base + addr1;
2906 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002907 if (!cpu_physical_memory_is_dirty(addr1)) {
2908 /* invalidate code */
2909 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2910 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002911 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2912 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002913 }
bellard8df1cd02005-01-28 22:37:22 +00002914 }
2915}
2916
bellardaab33092005-10-30 20:48:42 +00002917/* XXX: optimize */
2918void stb_phys(target_phys_addr_t addr, uint32_t val)
2919{
2920 uint8_t v = val;
2921 cpu_physical_memory_write(addr, &v, 1);
2922}
2923
2924/* XXX: optimize */
2925void stw_phys(target_phys_addr_t addr, uint32_t val)
2926{
2927 uint16_t v = tswap16(val);
2928 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2929}
2930
2931/* XXX: optimize */
2932void stq_phys(target_phys_addr_t addr, uint64_t val)
2933{
2934 val = tswap64(val);
2935 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2936}
2937
bellard13eb76e2004-01-24 15:23:36 +00002938#endif
2939
2940/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002941int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002942 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002943{
2944 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002945 target_phys_addr_t phys_addr;
2946 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002947
2948 while (len > 0) {
2949 page = addr & TARGET_PAGE_MASK;
2950 phys_addr = cpu_get_phys_page_debug(env, page);
2951 /* if no physical page mapped, return an error */
2952 if (phys_addr == -1)
2953 return -1;
2954 l = (page + TARGET_PAGE_SIZE) - addr;
2955 if (l > len)
2956 l = len;
ths5fafdf22007-09-16 21:08:06 +00002957 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002958 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002959 len -= l;
2960 buf += l;
2961 addr += l;
2962 }
2963 return 0;
2964}
2965
bellarde3db7222005-01-26 22:00:47 +00002966void dump_exec_info(FILE *f,
2967 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2968{
2969 int i, target_code_size, max_target_code_size;
2970 int direct_jmp_count, direct_jmp2_count, cross_page;
2971 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002972
bellarde3db7222005-01-26 22:00:47 +00002973 target_code_size = 0;
2974 max_target_code_size = 0;
2975 cross_page = 0;
2976 direct_jmp_count = 0;
2977 direct_jmp2_count = 0;
2978 for(i = 0; i < nb_tbs; i++) {
2979 tb = &tbs[i];
2980 target_code_size += tb->size;
2981 if (tb->size > max_target_code_size)
2982 max_target_code_size = tb->size;
2983 if (tb->page_addr[1] != -1)
2984 cross_page++;
2985 if (tb->tb_next_offset[0] != 0xffff) {
2986 direct_jmp_count++;
2987 if (tb->tb_next_offset[1] != 0xffff) {
2988 direct_jmp2_count++;
2989 }
2990 }
2991 }
2992 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002993 cpu_fprintf(f, "Translation buffer state:\n");
bellarde3db7222005-01-26 22:00:47 +00002994 cpu_fprintf(f, "TB count %d\n", nb_tbs);
ths5fafdf22007-09-16 21:08:06 +00002995 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002996 nb_tbs ? target_code_size / nb_tbs : 0,
2997 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00002998 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00002999 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3000 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003001 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3002 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003003 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3004 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003005 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003006 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3007 direct_jmp2_count,
3008 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003009 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003010 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3011 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3012 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellard57fec1f2008-02-01 10:50:11 +00003013#ifdef CONFIG_PROFILER
3014 {
3015 int64_t tot;
3016 tot = dyngen_interm_time + dyngen_code_time;
3017 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
3018 tot, tot / 2.4e9);
3019 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
3020 dyngen_tb_count,
3021 dyngen_tb_count1 - dyngen_tb_count,
3022 dyngen_tb_count1 ? (double)(dyngen_tb_count1 - dyngen_tb_count) / dyngen_tb_count1 * 100.0 : 0);
3023 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
3024 dyngen_tb_count ? (double)dyngen_op_count / dyngen_tb_count : 0, dyngen_op_count_max);
3025 cpu_fprintf(f, "old ops/total ops %0.1f%%\n",
3026 dyngen_op_count ? (double)dyngen_old_op_count / dyngen_op_count * 100.0 : 0);
3027 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
3028 dyngen_tb_count ?
3029 (double)dyngen_tcg_del_op_count / dyngen_tb_count : 0);
3030 cpu_fprintf(f, "cycles/op %0.1f\n",
3031 dyngen_op_count ? (double)tot / dyngen_op_count : 0);
3032 cpu_fprintf(f, "cycles/in byte %0.1f\n",
3033 dyngen_code_in_len ? (double)tot / dyngen_code_in_len : 0);
3034 cpu_fprintf(f, "cycles/out byte %0.1f\n",
3035 dyngen_code_out_len ? (double)tot / dyngen_code_out_len : 0);
3036 if (tot == 0)
3037 tot = 1;
3038 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
3039 (double)dyngen_interm_time / tot * 100.0);
3040 cpu_fprintf(f, " gen_code time %0.1f%%\n",
3041 (double)dyngen_code_time / tot * 100.0);
3042 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
3043 dyngen_restore_count);
3044 cpu_fprintf(f, " avg cycles %0.1f\n",
3045 dyngen_restore_count ? (double)dyngen_restore_time / dyngen_restore_count : 0);
3046 {
3047 extern void dump_op_count(void);
3048 dump_op_count();
3049 }
3050 }
3051#endif
bellarde3db7222005-01-26 22:00:47 +00003052}
3053
ths5fafdf22007-09-16 21:08:06 +00003054#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003055
3056#define MMUSUFFIX _cmmu
3057#define GETPC() NULL
3058#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003059#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003060
3061#define SHIFT 0
3062#include "softmmu_template.h"
3063
3064#define SHIFT 1
3065#include "softmmu_template.h"
3066
3067#define SHIFT 2
3068#include "softmmu_template.h"
3069
3070#define SHIFT 3
3071#include "softmmu_template.h"
3072
3073#undef env
3074
3075#endif