blob: 53bad8cb3fe5844cb4ccce6e9d200b20a6501efb [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"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrook53a59602006-03-25 19:31:22 +000040#if defined(CONFIG_USER_ONLY)
41#include <qemu.h>
42#endif
bellard54936002003-05-13 00:25:15 +000043
bellardfd6ce8f2003-05-14 19:00:11 +000044//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000045//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000046//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000047//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000048
49/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000050//#define DEBUG_TB_CHECK
51//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000052
ths1196be32007-03-17 15:17:58 +000053//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000054//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000055
pbrook99773bd2006-04-16 15:14:59 +000056#if !defined(CONFIG_USER_ONLY)
57/* TB consistency checks only implemented for usermode emulation. */
58#undef DEBUG_TB_CHECK
59#endif
60
bellardfd6ce8f2003-05-14 19:00:11 +000061/* threshold to flush the translated code buffer */
blueswir1d07bde82007-12-11 19:35:45 +000062#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
bellardfd6ce8f2003-05-14 19:00:11 +000063
bellard9fa3e852004-01-04 18:06:42 +000064#define SMC_BITMAP_USE_THRESHOLD 10
65
66#define MMAP_AREA_START 0x00000000
67#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000068
bellard108c49b2005-07-24 12:55:09 +000069#if defined(TARGET_SPARC64)
70#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000071#elif defined(TARGET_SPARC)
72#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000073#elif defined(TARGET_ALPHA)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
75#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000076#elif defined(TARGET_PPC64)
77#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000078#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
79#define TARGET_PHYS_ADDR_SPACE_BITS 42
80#elif defined(TARGET_I386) && !defined(USE_KQEMU)
81#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000082#else
83/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
84#define TARGET_PHYS_ADDR_SPACE_BITS 32
85#endif
86
bellardfd6ce8f2003-05-14 19:00:11 +000087TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000088TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000089int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000090/* any access to the tbs or the page table must use this lock */
91spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000092
bellard7cb69ca2008-05-10 10:55:51 +000093uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellardb8076a72005-04-07 22:20:31 +000094uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000095uint8_t *code_gen_ptr;
96
aurel3200f82b82008-04-27 21:12:55 +000097ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +000098int phys_ram_fd;
99uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000100uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000101static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +0000102
bellard6a00d602005-11-21 23:25:50 +0000103CPUState *first_cpu;
104/* current CPU in the current thread. It is only valid inside
105 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000106CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000107
bellard54936002003-05-13 00:25:15 +0000108typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000109 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000110 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000111 /* in order to optimize self modifying code, we count the number
112 of lookups we do to a given page to use a bitmap */
113 unsigned int code_write_count;
114 uint8_t *code_bitmap;
115#if defined(CONFIG_USER_ONLY)
116 unsigned long flags;
117#endif
bellard54936002003-05-13 00:25:15 +0000118} PageDesc;
119
bellard92e873b2004-05-21 14:52:29 +0000120typedef struct PhysPageDesc {
121 /* offset in host memory of the page + io_index in the low 12 bits */
aurel3200f82b82008-04-27 21:12:55 +0000122 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000123} PhysPageDesc;
124
bellard54936002003-05-13 00:25:15 +0000125#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000126#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
127/* XXX: this is a temporary hack for alpha target.
128 * In the future, this is to be replaced by a multi-level table
129 * to actually be able to handle the complete 64 bits address space.
130 */
131#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
132#else
aurel3203875442008-04-22 20:45:18 +0000133#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000134#endif
bellard54936002003-05-13 00:25:15 +0000135
136#define L1_SIZE (1 << L1_BITS)
137#define L2_SIZE (1 << L2_BITS)
138
bellard33417e72003-08-10 21:47:01 +0000139static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000140
bellard83fb7ad2004-07-05 21:25:26 +0000141unsigned long qemu_real_host_page_size;
142unsigned long qemu_host_page_bits;
143unsigned long qemu_host_page_size;
144unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000145
bellard92e873b2004-05-21 14:52:29 +0000146/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000147static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000148PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000149
bellard33417e72003-08-10 21:47:01 +0000150/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000151CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
152CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000153void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000154static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000155#if defined(CONFIG_SOFTMMU)
156static int io_mem_watch;
157#endif
bellard33417e72003-08-10 21:47:01 +0000158
bellard34865132003-10-05 14:28:56 +0000159/* log support */
160char *logfilename = "/tmp/qemu.log";
161FILE *logfile;
162int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000163static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000164
bellarde3db7222005-01-26 22:00:47 +0000165/* statistics */
166static int tlb_flush_count;
167static int tb_flush_count;
168static int tb_phys_invalidate_count;
169
blueswir1db7b5422007-05-26 17:36:03 +0000170#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
171typedef struct subpage_t {
172 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000173 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
174 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
175 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000176} subpage_t;
177
bellard7cb69ca2008-05-10 10:55:51 +0000178#ifdef _WIN32
179static void map_exec(void *addr, long size)
180{
181 DWORD old_protect;
182 VirtualProtect(addr, size,
183 PAGE_EXECUTE_READWRITE, &old_protect);
184
185}
186#else
187static void map_exec(void *addr, long size)
188{
189 unsigned long start, end;
190
191 start = (unsigned long)addr;
192 start &= ~(qemu_real_host_page_size - 1);
193
194 end = (unsigned long)addr + size;
195 end += qemu_real_host_page_size - 1;
196 end &= ~(qemu_real_host_page_size - 1);
197
198 mprotect((void *)start, end - start,
199 PROT_READ | PROT_WRITE | PROT_EXEC);
200}
201#endif
202
bellardb346ff42003-06-15 20:05:50 +0000203static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000204{
bellard83fb7ad2004-07-05 21:25:26 +0000205 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000206 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000207#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000208 {
209 SYSTEM_INFO system_info;
210 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000211
bellardd5a8f072004-09-29 21:15:28 +0000212 GetSystemInfo(&system_info);
213 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000214 }
bellard67b915a2004-03-31 23:37:16 +0000215#else
bellard83fb7ad2004-07-05 21:25:26 +0000216 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000217#endif
bellard7cb69ca2008-05-10 10:55:51 +0000218 map_exec(code_gen_buffer, sizeof(code_gen_buffer));
219 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
bellardd5a8f072004-09-29 21:15:28 +0000220
bellard83fb7ad2004-07-05 21:25:26 +0000221 if (qemu_host_page_size == 0)
222 qemu_host_page_size = qemu_real_host_page_size;
223 if (qemu_host_page_size < TARGET_PAGE_SIZE)
224 qemu_host_page_size = TARGET_PAGE_SIZE;
225 qemu_host_page_bits = 0;
226 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
227 qemu_host_page_bits++;
228 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000229 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
230 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000231
232#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
233 {
234 long long startaddr, endaddr;
235 FILE *f;
236 int n;
237
238 f = fopen("/proc/self/maps", "r");
239 if (f) {
240 do {
241 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
242 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000243 startaddr = MIN(startaddr,
244 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
245 endaddr = MIN(endaddr,
246 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
balrog50a95692007-12-12 01:16:23 +0000247 page_set_flags(TARGET_PAGE_ALIGN(startaddr),
248 TARGET_PAGE_ALIGN(endaddr),
249 PAGE_RESERVED);
250 }
251 } while (!feof(f));
252 fclose(f);
253 }
254 }
255#endif
bellard54936002003-05-13 00:25:15 +0000256}
257
aurel3200f82b82008-04-27 21:12:55 +0000258static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000259{
bellard54936002003-05-13 00:25:15 +0000260 PageDesc **lp, *p;
261
bellard54936002003-05-13 00:25:15 +0000262 lp = &l1_map[index >> L2_BITS];
263 p = *lp;
264 if (!p) {
265 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000266 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000267 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000268 *lp = p;
269 }
270 return p + (index & (L2_SIZE - 1));
271}
272
aurel3200f82b82008-04-27 21:12:55 +0000273static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000274{
bellard54936002003-05-13 00:25:15 +0000275 PageDesc *p;
276
bellard54936002003-05-13 00:25:15 +0000277 p = l1_map[index >> L2_BITS];
278 if (!p)
279 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000280 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000281}
282
bellard108c49b2005-07-24 12:55:09 +0000283static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000284{
bellard108c49b2005-07-24 12:55:09 +0000285 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000286 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000287
bellard108c49b2005-07-24 12:55:09 +0000288 p = (void **)l1_phys_map;
289#if TARGET_PHYS_ADDR_SPACE_BITS > 32
290
291#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
292#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
293#endif
294 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000295 p = *lp;
296 if (!p) {
297 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000298 if (!alloc)
299 return NULL;
300 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
301 memset(p, 0, sizeof(void *) * L1_SIZE);
302 *lp = p;
303 }
304#endif
305 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000306 pd = *lp;
307 if (!pd) {
308 int i;
bellard108c49b2005-07-24 12:55:09 +0000309 /* allocate if not found */
310 if (!alloc)
311 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000312 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
313 *lp = pd;
314 for (i = 0; i < L2_SIZE; i++)
315 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000316 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000317 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000318}
319
bellard108c49b2005-07-24 12:55:09 +0000320static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000321{
bellard108c49b2005-07-24 12:55:09 +0000322 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000323}
324
bellard9fa3e852004-01-04 18:06:42 +0000325#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000326static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000327static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000328 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000329#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000330
bellard6a00d602005-11-21 23:25:50 +0000331void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000332{
bellard6a00d602005-11-21 23:25:50 +0000333 CPUState **penv;
334 int cpu_index;
335
bellardfd6ce8f2003-05-14 19:00:11 +0000336 if (!code_gen_ptr) {
bellard57fec1f2008-02-01 10:50:11 +0000337 cpu_gen_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000338 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000339 page_init();
bellard33417e72003-08-10 21:47:01 +0000340 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000341 }
bellard6a00d602005-11-21 23:25:50 +0000342 env->next_cpu = NULL;
343 penv = &first_cpu;
344 cpu_index = 0;
345 while (*penv != NULL) {
346 penv = (CPUState **)&(*penv)->next_cpu;
347 cpu_index++;
348 }
349 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000350 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000351 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000352}
353
bellard9fa3e852004-01-04 18:06:42 +0000354static inline void invalidate_page_bitmap(PageDesc *p)
355{
356 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000357 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000358 p->code_bitmap = NULL;
359 }
360 p->code_write_count = 0;
361}
362
bellardfd6ce8f2003-05-14 19:00:11 +0000363/* set to NULL all the 'first_tb' fields in all PageDescs */
364static void page_flush_tb(void)
365{
366 int i, j;
367 PageDesc *p;
368
369 for(i = 0; i < L1_SIZE; i++) {
370 p = l1_map[i];
371 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000372 for(j = 0; j < L2_SIZE; j++) {
373 p->first_tb = NULL;
374 invalidate_page_bitmap(p);
375 p++;
376 }
bellardfd6ce8f2003-05-14 19:00:11 +0000377 }
378 }
379}
380
381/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000382/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000383void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000384{
bellard6a00d602005-11-21 23:25:50 +0000385 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000386#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000387 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
388 (unsigned long)(code_gen_ptr - code_gen_buffer),
389 nb_tbs, nb_tbs > 0 ?
390 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000391#endif
pbrooka208e542008-03-31 17:07:36 +0000392 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE)
393 cpu_abort(env1, "Internal error: code buffer overflow\n");
394
bellardfd6ce8f2003-05-14 19:00:11 +0000395 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000396
bellard6a00d602005-11-21 23:25:50 +0000397 for(env = first_cpu; env != NULL; env = env->next_cpu) {
398 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
399 }
bellard9fa3e852004-01-04 18:06:42 +0000400
bellard8a8a6082004-10-03 13:36:49 +0000401 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000402 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000403
bellardfd6ce8f2003-05-14 19:00:11 +0000404 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000405 /* XXX: flush processor icache at this point if cache flush is
406 expensive */
bellarde3db7222005-01-26 22:00:47 +0000407 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000408}
409
410#ifdef DEBUG_TB_CHECK
411
j_mayerbc98a7e2007-04-04 07:55:12 +0000412static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000413{
414 TranslationBlock *tb;
415 int i;
416 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000417 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
418 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000419 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
420 address >= tb->pc + tb->size)) {
421 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000422 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000423 }
424 }
425 }
426}
427
428/* verify that all the pages have correct rights for code */
429static void tb_page_check(void)
430{
431 TranslationBlock *tb;
432 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000433
pbrook99773bd2006-04-16 15:14:59 +0000434 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
435 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000436 flags1 = page_get_flags(tb->pc);
437 flags2 = page_get_flags(tb->pc + tb->size - 1);
438 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
439 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000440 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000441 }
442 }
443 }
444}
445
bellardd4e81642003-05-25 16:46:15 +0000446void tb_jmp_check(TranslationBlock *tb)
447{
448 TranslationBlock *tb1;
449 unsigned int n1;
450
451 /* suppress any remaining jumps to this TB */
452 tb1 = tb->jmp_first;
453 for(;;) {
454 n1 = (long)tb1 & 3;
455 tb1 = (TranslationBlock *)((long)tb1 & ~3);
456 if (n1 == 2)
457 break;
458 tb1 = tb1->jmp_next[n1];
459 }
460 /* check end of list */
461 if (tb1 != tb) {
462 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
463 }
464}
465
bellardfd6ce8f2003-05-14 19:00:11 +0000466#endif
467
468/* invalidate one TB */
469static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
470 int next_offset)
471{
472 TranslationBlock *tb1;
473 for(;;) {
474 tb1 = *ptb;
475 if (tb1 == tb) {
476 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
477 break;
478 }
479 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
480 }
481}
482
bellard9fa3e852004-01-04 18:06:42 +0000483static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
484{
485 TranslationBlock *tb1;
486 unsigned int n1;
487
488 for(;;) {
489 tb1 = *ptb;
490 n1 = (long)tb1 & 3;
491 tb1 = (TranslationBlock *)((long)tb1 & ~3);
492 if (tb1 == tb) {
493 *ptb = tb1->page_next[n1];
494 break;
495 }
496 ptb = &tb1->page_next[n1];
497 }
498}
499
bellardd4e81642003-05-25 16:46:15 +0000500static inline void tb_jmp_remove(TranslationBlock *tb, int n)
501{
502 TranslationBlock *tb1, **ptb;
503 unsigned int n1;
504
505 ptb = &tb->jmp_next[n];
506 tb1 = *ptb;
507 if (tb1) {
508 /* find tb(n) in circular list */
509 for(;;) {
510 tb1 = *ptb;
511 n1 = (long)tb1 & 3;
512 tb1 = (TranslationBlock *)((long)tb1 & ~3);
513 if (n1 == n && tb1 == tb)
514 break;
515 if (n1 == 2) {
516 ptb = &tb1->jmp_first;
517 } else {
518 ptb = &tb1->jmp_next[n1];
519 }
520 }
521 /* now we can suppress tb(n) from the list */
522 *ptb = tb->jmp_next[n];
523
524 tb->jmp_next[n] = NULL;
525 }
526}
527
528/* reset the jump entry 'n' of a TB so that it is not chained to
529 another TB */
530static inline void tb_reset_jump(TranslationBlock *tb, int n)
531{
532 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
533}
534
aurel3200f82b82008-04-27 21:12:55 +0000535static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000536{
bellard6a00d602005-11-21 23:25:50 +0000537 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000538 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000539 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000540 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000541 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000542
bellard9fa3e852004-01-04 18:06:42 +0000543 /* remove the TB from the hash list */
544 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
545 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000546 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000547 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000548
bellard9fa3e852004-01-04 18:06:42 +0000549 /* remove the TB from the page list */
550 if (tb->page_addr[0] != page_addr) {
551 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
552 tb_page_remove(&p->first_tb, tb);
553 invalidate_page_bitmap(p);
554 }
555 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
556 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
557 tb_page_remove(&p->first_tb, tb);
558 invalidate_page_bitmap(p);
559 }
560
bellard8a40a182005-11-20 10:35:40 +0000561 tb_invalidated_flag = 1;
562
563 /* remove the TB from the hash list */
564 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000565 for(env = first_cpu; env != NULL; env = env->next_cpu) {
566 if (env->tb_jmp_cache[h] == tb)
567 env->tb_jmp_cache[h] = NULL;
568 }
bellard8a40a182005-11-20 10:35:40 +0000569
570 /* suppress this TB from the two jump lists */
571 tb_jmp_remove(tb, 0);
572 tb_jmp_remove(tb, 1);
573
574 /* suppress any remaining jumps to this TB */
575 tb1 = tb->jmp_first;
576 for(;;) {
577 n1 = (long)tb1 & 3;
578 if (n1 == 2)
579 break;
580 tb1 = (TranslationBlock *)((long)tb1 & ~3);
581 tb2 = tb1->jmp_next[n1];
582 tb_reset_jump(tb1, n1);
583 tb1->jmp_next[n1] = NULL;
584 tb1 = tb2;
585 }
586 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
587
bellarde3db7222005-01-26 22:00:47 +0000588 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000589}
590
591static inline void set_bits(uint8_t *tab, int start, int len)
592{
593 int end, mask, end1;
594
595 end = start + len;
596 tab += start >> 3;
597 mask = 0xff << (start & 7);
598 if ((start & ~7) == (end & ~7)) {
599 if (start < end) {
600 mask &= ~(0xff << (end & 7));
601 *tab |= mask;
602 }
603 } else {
604 *tab++ |= mask;
605 start = (start + 8) & ~7;
606 end1 = end & ~7;
607 while (start < end1) {
608 *tab++ = 0xff;
609 start += 8;
610 }
611 if (start < end) {
612 mask = ~(0xff << (end & 7));
613 *tab |= mask;
614 }
615 }
616}
617
618static void build_page_bitmap(PageDesc *p)
619{
620 int n, tb_start, tb_end;
621 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000622
bellard59817cc2004-02-16 22:01:13 +0000623 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000624 if (!p->code_bitmap)
625 return;
626 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
627
628 tb = p->first_tb;
629 while (tb != NULL) {
630 n = (long)tb & 3;
631 tb = (TranslationBlock *)((long)tb & ~3);
632 /* NOTE: this is subtle as a TB may span two physical pages */
633 if (n == 0) {
634 /* NOTE: tb_end may be after the end of the page, but
635 it is not a problem */
636 tb_start = tb->pc & ~TARGET_PAGE_MASK;
637 tb_end = tb_start + tb->size;
638 if (tb_end > TARGET_PAGE_SIZE)
639 tb_end = TARGET_PAGE_SIZE;
640 } else {
641 tb_start = 0;
642 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
643 }
644 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
645 tb = tb->page_next[n];
646 }
647}
648
bellardd720b932004-04-25 17:57:43 +0000649#ifdef TARGET_HAS_PRECISE_SMC
650
ths5fafdf22007-09-16 21:08:06 +0000651static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000652 target_ulong pc, target_ulong cs_base, int flags,
653 int cflags)
654{
655 TranslationBlock *tb;
656 uint8_t *tc_ptr;
657 target_ulong phys_pc, phys_page2, virt_page2;
658 int code_gen_size;
659
bellardc27004e2005-01-03 23:35:10 +0000660 phys_pc = get_phys_addr_code(env, pc);
661 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000662 if (!tb) {
663 /* flush must be done */
664 tb_flush(env);
665 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000666 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000667 }
668 tc_ptr = code_gen_ptr;
669 tb->tc_ptr = tc_ptr;
670 tb->cs_base = cs_base;
671 tb->flags = flags;
672 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000673 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000674 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 +0000675
bellardd720b932004-04-25 17:57:43 +0000676 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000677 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000678 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000679 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000680 phys_page2 = get_phys_addr_code(env, virt_page2);
681 }
682 tb_link_phys(tb, phys_pc, phys_page2);
683}
684#endif
ths3b46e622007-09-17 08:09:54 +0000685
bellard9fa3e852004-01-04 18:06:42 +0000686/* invalidate all TBs which intersect with the target physical page
687 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000688 the same physical page. 'is_cpu_write_access' should be true if called
689 from a real cpu write access: the virtual CPU will exit the current
690 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000691void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000692 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000693{
bellardd720b932004-04-25 17:57:43 +0000694 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000695 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000696 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000697 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000698 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000699 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000700
701 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000702 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000703 return;
ths5fafdf22007-09-16 21:08:06 +0000704 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000705 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
706 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000707 /* build code bitmap */
708 build_page_bitmap(p);
709 }
710
711 /* we remove all the TBs in the range [start, end[ */
712 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000713 current_tb_not_found = is_cpu_write_access;
714 current_tb_modified = 0;
715 current_tb = NULL; /* avoid warning */
716 current_pc = 0; /* avoid warning */
717 current_cs_base = 0; /* avoid warning */
718 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000719 tb = p->first_tb;
720 while (tb != NULL) {
721 n = (long)tb & 3;
722 tb = (TranslationBlock *)((long)tb & ~3);
723 tb_next = tb->page_next[n];
724 /* NOTE: this is subtle as a TB may span two physical pages */
725 if (n == 0) {
726 /* NOTE: tb_end may be after the end of the page, but
727 it is not a problem */
728 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
729 tb_end = tb_start + tb->size;
730 } else {
731 tb_start = tb->page_addr[1];
732 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
733 }
734 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000735#ifdef TARGET_HAS_PRECISE_SMC
736 if (current_tb_not_found) {
737 current_tb_not_found = 0;
738 current_tb = NULL;
739 if (env->mem_write_pc) {
740 /* now we have a real cpu fault */
741 current_tb = tb_find_pc(env->mem_write_pc);
742 }
743 }
744 if (current_tb == tb &&
745 !(current_tb->cflags & CF_SINGLE_INSN)) {
746 /* If we are modifying the current TB, we must stop
747 its execution. We could be more precise by checking
748 that the modification is after the current PC, but it
749 would require a specialized function to partially
750 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000751
bellardd720b932004-04-25 17:57:43 +0000752 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000753 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000754 env->mem_write_pc, NULL);
755#if defined(TARGET_I386)
756 current_flags = env->hflags;
757 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
758 current_cs_base = (target_ulong)env->segs[R_CS].base;
759 current_pc = current_cs_base + env->eip;
760#else
761#error unsupported CPU
762#endif
763 }
764#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000765 /* we need to do that to handle the case where a signal
766 occurs while doing tb_phys_invalidate() */
767 saved_tb = NULL;
768 if (env) {
769 saved_tb = env->current_tb;
770 env->current_tb = NULL;
771 }
bellard9fa3e852004-01-04 18:06:42 +0000772 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000773 if (env) {
774 env->current_tb = saved_tb;
775 if (env->interrupt_request && env->current_tb)
776 cpu_interrupt(env, env->interrupt_request);
777 }
bellard9fa3e852004-01-04 18:06:42 +0000778 }
779 tb = tb_next;
780 }
781#if !defined(CONFIG_USER_ONLY)
782 /* if no code remaining, no need to continue to use slow writes */
783 if (!p->first_tb) {
784 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000785 if (is_cpu_write_access) {
786 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
787 }
788 }
789#endif
790#ifdef TARGET_HAS_PRECISE_SMC
791 if (current_tb_modified) {
792 /* we generate a block containing just the instruction
793 modifying the memory. It will ensure that it cannot modify
794 itself */
bellardea1c1802004-06-14 18:56:36 +0000795 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000796 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000797 CF_SINGLE_INSN);
798 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000799 }
800#endif
801}
802
803/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000804static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000805{
806 PageDesc *p;
807 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000808#if 0
bellarda4193c82004-06-03 14:01:43 +0000809 if (1) {
810 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000811 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
812 cpu_single_env->mem_write_vaddr, len,
813 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000814 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
815 }
bellard59817cc2004-02-16 22:01:13 +0000816 }
817#endif
bellard9fa3e852004-01-04 18:06:42 +0000818 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000819 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000820 return;
821 if (p->code_bitmap) {
822 offset = start & ~TARGET_PAGE_MASK;
823 b = p->code_bitmap[offset >> 3] >> (offset & 7);
824 if (b & ((1 << len) - 1))
825 goto do_invalidate;
826 } else {
827 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000828 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000829 }
830}
831
bellard9fa3e852004-01-04 18:06:42 +0000832#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000833static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000834 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000835{
bellardd720b932004-04-25 17:57:43 +0000836 int n, current_flags, current_tb_modified;
837 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000838 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000839 TranslationBlock *tb, *current_tb;
840#ifdef TARGET_HAS_PRECISE_SMC
841 CPUState *env = cpu_single_env;
842#endif
bellard9fa3e852004-01-04 18:06:42 +0000843
844 addr &= TARGET_PAGE_MASK;
845 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000846 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000847 return;
848 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000849 current_tb_modified = 0;
850 current_tb = NULL;
851 current_pc = 0; /* avoid warning */
852 current_cs_base = 0; /* avoid warning */
853 current_flags = 0; /* avoid warning */
854#ifdef TARGET_HAS_PRECISE_SMC
855 if (tb && pc != 0) {
856 current_tb = tb_find_pc(pc);
857 }
858#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000859 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000860 n = (long)tb & 3;
861 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000862#ifdef TARGET_HAS_PRECISE_SMC
863 if (current_tb == tb &&
864 !(current_tb->cflags & CF_SINGLE_INSN)) {
865 /* If we are modifying the current TB, we must stop
866 its execution. We could be more precise by checking
867 that the modification is after the current PC, but it
868 would require a specialized function to partially
869 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000870
bellardd720b932004-04-25 17:57:43 +0000871 current_tb_modified = 1;
872 cpu_restore_state(current_tb, env, pc, puc);
873#if defined(TARGET_I386)
874 current_flags = env->hflags;
875 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
876 current_cs_base = (target_ulong)env->segs[R_CS].base;
877 current_pc = current_cs_base + env->eip;
878#else
879#error unsupported CPU
880#endif
881 }
882#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000883 tb_phys_invalidate(tb, addr);
884 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000885 }
886 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000887#ifdef TARGET_HAS_PRECISE_SMC
888 if (current_tb_modified) {
889 /* we generate a block containing just the instruction
890 modifying the memory. It will ensure that it cannot modify
891 itself */
bellardea1c1802004-06-14 18:56:36 +0000892 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000893 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000894 CF_SINGLE_INSN);
895 cpu_resume_from_signal(env, puc);
896 }
897#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000898}
bellard9fa3e852004-01-04 18:06:42 +0000899#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000900
901/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000902static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000903 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000904{
905 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000906 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000907
bellard9fa3e852004-01-04 18:06:42 +0000908 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000909 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000910 tb->page_next[n] = p->first_tb;
911 last_first_tb = p->first_tb;
912 p->first_tb = (TranslationBlock *)((long)tb | n);
913 invalidate_page_bitmap(p);
914
bellard107db442004-06-22 18:48:46 +0000915#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000916
bellard9fa3e852004-01-04 18:06:42 +0000917#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000918 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000919 target_ulong addr;
920 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000921 int prot;
922
bellardfd6ce8f2003-05-14 19:00:11 +0000923 /* force the host page as non writable (writes will have a
924 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000925 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000926 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000927 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
928 addr += TARGET_PAGE_SIZE) {
929
930 p2 = page_find (addr >> TARGET_PAGE_BITS);
931 if (!p2)
932 continue;
933 prot |= p2->flags;
934 p2->flags &= ~PAGE_WRITE;
935 page_get_flags(addr);
936 }
ths5fafdf22007-09-16 21:08:06 +0000937 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000938 (prot & PAGE_BITS) & ~PAGE_WRITE);
939#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +0000940 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +0000941 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000942#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000943 }
bellard9fa3e852004-01-04 18:06:42 +0000944#else
945 /* if some code is already present, then the pages are already
946 protected. So we handle the case where only the first TB is
947 allocated in a physical page */
948 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000949 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000950 }
951#endif
bellardd720b932004-04-25 17:57:43 +0000952
953#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000954}
955
956/* Allocate a new translation block. Flush the translation buffer if
957 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000958TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000959{
960 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000961
ths5fafdf22007-09-16 21:08:06 +0000962 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
bellardfd6ce8f2003-05-14 19:00:11 +0000963 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000964 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000965 tb = &tbs[nb_tbs++];
966 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000967 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000968 return tb;
969}
970
bellard9fa3e852004-01-04 18:06:42 +0000971/* add a new TB and link it to the physical page tables. phys_page2 is
972 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +0000973void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +0000974 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000975{
bellard9fa3e852004-01-04 18:06:42 +0000976 unsigned int h;
977 TranslationBlock **ptb;
978
979 /* add in the physical hash table */
980 h = tb_phys_hash_func(phys_pc);
981 ptb = &tb_phys_hash[h];
982 tb->phys_hash_next = *ptb;
983 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000984
985 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000986 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
987 if (phys_page2 != -1)
988 tb_alloc_page(tb, 1, phys_page2);
989 else
990 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000991
bellardd4e81642003-05-25 16:46:15 +0000992 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
993 tb->jmp_next[0] = NULL;
994 tb->jmp_next[1] = NULL;
995
996 /* init original jump addresses */
997 if (tb->tb_next_offset[0] != 0xffff)
998 tb_reset_jump(tb, 0);
999 if (tb->tb_next_offset[1] != 0xffff)
1000 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001001
1002#ifdef DEBUG_TB_CHECK
1003 tb_page_check();
1004#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001005}
1006
bellarda513fe12003-05-27 23:29:48 +00001007/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1008 tb[1].tc_ptr. Return NULL if not found */
1009TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1010{
1011 int m_min, m_max, m;
1012 unsigned long v;
1013 TranslationBlock *tb;
1014
1015 if (nb_tbs <= 0)
1016 return NULL;
1017 if (tc_ptr < (unsigned long)code_gen_buffer ||
1018 tc_ptr >= (unsigned long)code_gen_ptr)
1019 return NULL;
1020 /* binary search (cf Knuth) */
1021 m_min = 0;
1022 m_max = nb_tbs - 1;
1023 while (m_min <= m_max) {
1024 m = (m_min + m_max) >> 1;
1025 tb = &tbs[m];
1026 v = (unsigned long)tb->tc_ptr;
1027 if (v == tc_ptr)
1028 return tb;
1029 else if (tc_ptr < v) {
1030 m_max = m - 1;
1031 } else {
1032 m_min = m + 1;
1033 }
ths5fafdf22007-09-16 21:08:06 +00001034 }
bellarda513fe12003-05-27 23:29:48 +00001035 return &tbs[m_max];
1036}
bellard75012672003-06-21 13:11:07 +00001037
bellardea041c02003-06-25 16:16:50 +00001038static void tb_reset_jump_recursive(TranslationBlock *tb);
1039
1040static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1041{
1042 TranslationBlock *tb1, *tb_next, **ptb;
1043 unsigned int n1;
1044
1045 tb1 = tb->jmp_next[n];
1046 if (tb1 != NULL) {
1047 /* find head of list */
1048 for(;;) {
1049 n1 = (long)tb1 & 3;
1050 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1051 if (n1 == 2)
1052 break;
1053 tb1 = tb1->jmp_next[n1];
1054 }
1055 /* we are now sure now that tb jumps to tb1 */
1056 tb_next = tb1;
1057
1058 /* remove tb from the jmp_first list */
1059 ptb = &tb_next->jmp_first;
1060 for(;;) {
1061 tb1 = *ptb;
1062 n1 = (long)tb1 & 3;
1063 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1064 if (n1 == n && tb1 == tb)
1065 break;
1066 ptb = &tb1->jmp_next[n1];
1067 }
1068 *ptb = tb->jmp_next[n];
1069 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001070
bellardea041c02003-06-25 16:16:50 +00001071 /* suppress the jump to next tb in generated code */
1072 tb_reset_jump(tb, n);
1073
bellard01243112004-01-04 15:48:17 +00001074 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001075 tb_reset_jump_recursive(tb_next);
1076 }
1077}
1078
1079static void tb_reset_jump_recursive(TranslationBlock *tb)
1080{
1081 tb_reset_jump_recursive2(tb, 0);
1082 tb_reset_jump_recursive2(tb, 1);
1083}
1084
bellard1fddef42005-04-17 19:16:13 +00001085#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001086static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1087{
j_mayer9b3c35e2007-04-07 11:21:28 +00001088 target_phys_addr_t addr;
1089 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001090 ram_addr_t ram_addr;
1091 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001092
pbrookc2f07f82006-04-08 17:14:56 +00001093 addr = cpu_get_phys_page_debug(env, pc);
1094 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1095 if (!p) {
1096 pd = IO_MEM_UNASSIGNED;
1097 } else {
1098 pd = p->phys_offset;
1099 }
1100 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001101 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001102}
bellardc27004e2005-01-03 23:35:10 +00001103#endif
bellardd720b932004-04-25 17:57:43 +00001104
pbrook6658ffb2007-03-16 23:58:11 +00001105/* Add a watchpoint. */
1106int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1107{
1108 int i;
1109
1110 for (i = 0; i < env->nb_watchpoints; i++) {
1111 if (addr == env->watchpoint[i].vaddr)
1112 return 0;
1113 }
1114 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1115 return -1;
1116
1117 i = env->nb_watchpoints++;
1118 env->watchpoint[i].vaddr = addr;
1119 tlb_flush_page(env, addr);
1120 /* FIXME: This flush is needed because of the hack to make memory ops
1121 terminate the TB. It can be removed once the proper IO trap and
1122 re-execute bits are in. */
1123 tb_flush(env);
1124 return i;
1125}
1126
1127/* Remove a watchpoint. */
1128int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1129{
1130 int i;
1131
1132 for (i = 0; i < env->nb_watchpoints; i++) {
1133 if (addr == env->watchpoint[i].vaddr) {
1134 env->nb_watchpoints--;
1135 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1136 tlb_flush_page(env, addr);
1137 return 0;
1138 }
1139 }
1140 return -1;
1141}
1142
edgar_igl7d03f822008-05-17 18:58:29 +00001143/* Remove all watchpoints. */
1144void cpu_watchpoint_remove_all(CPUState *env) {
1145 int i;
1146
1147 for (i = 0; i < env->nb_watchpoints; i++) {
1148 tlb_flush_page(env, env->watchpoint[i].vaddr);
1149 }
1150 env->nb_watchpoints = 0;
1151}
1152
bellardc33a3462003-07-29 20:50:33 +00001153/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1154 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001155int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001156{
bellard1fddef42005-04-17 19:16:13 +00001157#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001158 int i;
ths3b46e622007-09-17 08:09:54 +00001159
bellard4c3a88a2003-07-26 12:06:08 +00001160 for(i = 0; i < env->nb_breakpoints; i++) {
1161 if (env->breakpoints[i] == pc)
1162 return 0;
1163 }
1164
1165 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1166 return -1;
1167 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001168
bellardd720b932004-04-25 17:57:43 +00001169 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001170 return 0;
1171#else
1172 return -1;
1173#endif
1174}
1175
edgar_igl7d03f822008-05-17 18:58:29 +00001176/* remove all breakpoints */
1177void cpu_breakpoint_remove_all(CPUState *env) {
1178#if defined(TARGET_HAS_ICE)
1179 int i;
1180 for(i = 0; i < env->nb_breakpoints; i++) {
1181 breakpoint_invalidate(env, env->breakpoints[i]);
1182 }
1183 env->nb_breakpoints = 0;
1184#endif
1185}
1186
bellard4c3a88a2003-07-26 12:06:08 +00001187/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001188int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001189{
bellard1fddef42005-04-17 19:16:13 +00001190#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001191 int i;
1192 for(i = 0; i < env->nb_breakpoints; i++) {
1193 if (env->breakpoints[i] == pc)
1194 goto found;
1195 }
1196 return -1;
1197 found:
bellard4c3a88a2003-07-26 12:06:08 +00001198 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001199 if (i < env->nb_breakpoints)
1200 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001201
1202 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001203 return 0;
1204#else
1205 return -1;
1206#endif
1207}
1208
bellardc33a3462003-07-29 20:50:33 +00001209/* enable or disable single step mode. EXCP_DEBUG is returned by the
1210 CPU loop after each instruction */
1211void cpu_single_step(CPUState *env, int enabled)
1212{
bellard1fddef42005-04-17 19:16:13 +00001213#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001214 if (env->singlestep_enabled != enabled) {
1215 env->singlestep_enabled = enabled;
1216 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001217 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001218 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001219 }
1220#endif
1221}
1222
bellard34865132003-10-05 14:28:56 +00001223/* enable or disable low levels log */
1224void cpu_set_log(int log_flags)
1225{
1226 loglevel = log_flags;
1227 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001228 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001229 if (!logfile) {
1230 perror(logfilename);
1231 _exit(1);
1232 }
bellard9fa3e852004-01-04 18:06:42 +00001233#if !defined(CONFIG_SOFTMMU)
1234 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1235 {
1236 static uint8_t logfile_buf[4096];
1237 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1238 }
1239#else
bellard34865132003-10-05 14:28:56 +00001240 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001241#endif
pbrooke735b912007-06-30 13:53:24 +00001242 log_append = 1;
1243 }
1244 if (!loglevel && logfile) {
1245 fclose(logfile);
1246 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001247 }
1248}
1249
1250void cpu_set_log_filename(const char *filename)
1251{
1252 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001253 if (logfile) {
1254 fclose(logfile);
1255 logfile = NULL;
1256 }
1257 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001258}
bellardc33a3462003-07-29 20:50:33 +00001259
bellard01243112004-01-04 15:48:17 +00001260/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001261void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001262{
1263 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001264 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
bellard59817cc2004-02-16 22:01:13 +00001265
bellard68a79312003-06-30 13:12:32 +00001266 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001267 /* if the cpu is currently executing code, we must unlink it and
1268 all the potentially executing TB */
1269 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001270 if (tb && !testandset(&interrupt_lock)) {
1271 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001272 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001273 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001274 }
1275}
1276
bellardb54ad042004-05-20 13:42:52 +00001277void cpu_reset_interrupt(CPUState *env, int mask)
1278{
1279 env->interrupt_request &= ~mask;
1280}
1281
bellardf193c792004-03-21 17:06:25 +00001282CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001283 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001284 "show generated host assembly code for each compiled TB" },
1285 { CPU_LOG_TB_IN_ASM, "in_asm",
1286 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001287 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001288 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001289 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001290 "show micro ops "
1291#ifdef TARGET_I386
1292 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001293#endif
blueswir1e01a1152008-03-14 17:37:11 +00001294 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001295 { CPU_LOG_INT, "int",
1296 "show interrupts/exceptions in short format" },
1297 { CPU_LOG_EXEC, "exec",
1298 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001299 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001300 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001301#ifdef TARGET_I386
1302 { CPU_LOG_PCALL, "pcall",
1303 "show protected mode far calls/returns/exceptions" },
1304#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001305#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001306 { CPU_LOG_IOPORT, "ioport",
1307 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001308#endif
bellardf193c792004-03-21 17:06:25 +00001309 { 0, NULL, NULL },
1310};
1311
1312static int cmp1(const char *s1, int n, const char *s2)
1313{
1314 if (strlen(s2) != n)
1315 return 0;
1316 return memcmp(s1, s2, n) == 0;
1317}
ths3b46e622007-09-17 08:09:54 +00001318
bellardf193c792004-03-21 17:06:25 +00001319/* takes a comma separated list of log masks. Return 0 if error. */
1320int cpu_str_to_log_mask(const char *str)
1321{
1322 CPULogItem *item;
1323 int mask;
1324 const char *p, *p1;
1325
1326 p = str;
1327 mask = 0;
1328 for(;;) {
1329 p1 = strchr(p, ',');
1330 if (!p1)
1331 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001332 if(cmp1(p,p1-p,"all")) {
1333 for(item = cpu_log_items; item->mask != 0; item++) {
1334 mask |= item->mask;
1335 }
1336 } else {
bellardf193c792004-03-21 17:06:25 +00001337 for(item = cpu_log_items; item->mask != 0; item++) {
1338 if (cmp1(p, p1 - p, item->name))
1339 goto found;
1340 }
1341 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001342 }
bellardf193c792004-03-21 17:06:25 +00001343 found:
1344 mask |= item->mask;
1345 if (*p1 != ',')
1346 break;
1347 p = p1 + 1;
1348 }
1349 return mask;
1350}
bellardea041c02003-06-25 16:16:50 +00001351
bellard75012672003-06-21 13:11:07 +00001352void cpu_abort(CPUState *env, const char *fmt, ...)
1353{
1354 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001355 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001356
1357 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001358 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001359 fprintf(stderr, "qemu: fatal: ");
1360 vfprintf(stderr, fmt, ap);
1361 fprintf(stderr, "\n");
1362#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001363 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1364#else
1365 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001366#endif
balrog924edca2007-06-10 14:07:13 +00001367 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001368 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001369 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001370 fprintf(logfile, "\n");
1371#ifdef TARGET_I386
1372 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1373#else
1374 cpu_dump_state(env, logfile, fprintf, 0);
1375#endif
balrog924edca2007-06-10 14:07:13 +00001376 fflush(logfile);
1377 fclose(logfile);
1378 }
pbrook493ae1f2007-11-23 16:53:59 +00001379 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001380 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001381 abort();
1382}
1383
thsc5be9f02007-02-28 20:20:53 +00001384CPUState *cpu_copy(CPUState *env)
1385{
ths01ba9812007-12-09 02:22:57 +00001386 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001387 /* preserve chaining and index */
1388 CPUState *next_cpu = new_env->next_cpu;
1389 int cpu_index = new_env->cpu_index;
1390 memcpy(new_env, env, sizeof(CPUState));
1391 new_env->next_cpu = next_cpu;
1392 new_env->cpu_index = cpu_index;
1393 return new_env;
1394}
1395
bellard01243112004-01-04 15:48:17 +00001396#if !defined(CONFIG_USER_ONLY)
1397
edgar_igl5c751e92008-05-06 08:44:21 +00001398static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1399{
1400 unsigned int i;
1401
1402 /* Discard jump cache entries for any tb which might potentially
1403 overlap the flushed page. */
1404 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1405 memset (&env->tb_jmp_cache[i], 0,
1406 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1407
1408 i = tb_jmp_cache_hash_page(addr);
1409 memset (&env->tb_jmp_cache[i], 0,
1410 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1411}
1412
bellardee8b7022004-02-03 23:35:10 +00001413/* NOTE: if flush_global is true, also flush global entries (not
1414 implemented yet) */
1415void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001416{
bellard33417e72003-08-10 21:47:01 +00001417 int i;
bellard01243112004-01-04 15:48:17 +00001418
bellard9fa3e852004-01-04 18:06:42 +00001419#if defined(DEBUG_TLB)
1420 printf("tlb_flush:\n");
1421#endif
bellard01243112004-01-04 15:48:17 +00001422 /* must reset current TB so that interrupts cannot modify the
1423 links while we are modifying them */
1424 env->current_tb = NULL;
1425
bellard33417e72003-08-10 21:47:01 +00001426 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001427 env->tlb_table[0][i].addr_read = -1;
1428 env->tlb_table[0][i].addr_write = -1;
1429 env->tlb_table[0][i].addr_code = -1;
1430 env->tlb_table[1][i].addr_read = -1;
1431 env->tlb_table[1][i].addr_write = -1;
1432 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001433#if (NB_MMU_MODES >= 3)
1434 env->tlb_table[2][i].addr_read = -1;
1435 env->tlb_table[2][i].addr_write = -1;
1436 env->tlb_table[2][i].addr_code = -1;
1437#if (NB_MMU_MODES == 4)
1438 env->tlb_table[3][i].addr_read = -1;
1439 env->tlb_table[3][i].addr_write = -1;
1440 env->tlb_table[3][i].addr_code = -1;
1441#endif
1442#endif
bellard33417e72003-08-10 21:47:01 +00001443 }
bellard9fa3e852004-01-04 18:06:42 +00001444
bellard8a40a182005-11-20 10:35:40 +00001445 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001446
1447#if !defined(CONFIG_SOFTMMU)
1448 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1449#endif
bellard0a962c02005-02-10 22:00:27 +00001450#ifdef USE_KQEMU
1451 if (env->kqemu_enabled) {
1452 kqemu_flush(env, flush_global);
1453 }
1454#endif
bellarde3db7222005-01-26 22:00:47 +00001455 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001456}
1457
bellard274da6b2004-05-20 21:56:27 +00001458static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001459{
ths5fafdf22007-09-16 21:08:06 +00001460 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001461 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001462 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001463 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001464 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001465 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1466 tlb_entry->addr_read = -1;
1467 tlb_entry->addr_write = -1;
1468 tlb_entry->addr_code = -1;
1469 }
bellard61382a52003-10-27 21:22:23 +00001470}
1471
bellard2e126692004-04-25 21:28:44 +00001472void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001473{
bellard8a40a182005-11-20 10:35:40 +00001474 int i;
bellard01243112004-01-04 15:48:17 +00001475
bellard9fa3e852004-01-04 18:06:42 +00001476#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001477 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001478#endif
bellard01243112004-01-04 15:48:17 +00001479 /* must reset current TB so that interrupts cannot modify the
1480 links while we are modifying them */
1481 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001482
bellard61382a52003-10-27 21:22:23 +00001483 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001484 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001485 tlb_flush_entry(&env->tlb_table[0][i], addr);
1486 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001487#if (NB_MMU_MODES >= 3)
1488 tlb_flush_entry(&env->tlb_table[2][i], addr);
1489#if (NB_MMU_MODES == 4)
1490 tlb_flush_entry(&env->tlb_table[3][i], addr);
1491#endif
1492#endif
bellard01243112004-01-04 15:48:17 +00001493
edgar_igl5c751e92008-05-06 08:44:21 +00001494 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001495
bellard01243112004-01-04 15:48:17 +00001496#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001497 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001498 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001499#endif
bellard0a962c02005-02-10 22:00:27 +00001500#ifdef USE_KQEMU
1501 if (env->kqemu_enabled) {
1502 kqemu_flush_page(env, addr);
1503 }
1504#endif
bellard9fa3e852004-01-04 18:06:42 +00001505}
1506
bellard9fa3e852004-01-04 18:06:42 +00001507/* update the TLBs so that writes to code in the virtual page 'addr'
1508 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001509static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001510{
ths5fafdf22007-09-16 21:08:06 +00001511 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001512 ram_addr + TARGET_PAGE_SIZE,
1513 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001514}
1515
bellard9fa3e852004-01-04 18:06:42 +00001516/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001517 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001518static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001519 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001520{
bellard3a7d9292005-08-21 09:26:42 +00001521 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001522}
1523
ths5fafdf22007-09-16 21:08:06 +00001524static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001525 unsigned long start, unsigned long length)
1526{
1527 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001528 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1529 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001530 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001531 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001532 }
1533 }
1534}
1535
bellard3a7d9292005-08-21 09:26:42 +00001536void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001537 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001538{
1539 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001540 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001541 int i, mask, len;
1542 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001543
1544 start &= TARGET_PAGE_MASK;
1545 end = TARGET_PAGE_ALIGN(end);
1546
1547 length = end - start;
1548 if (length == 0)
1549 return;
bellard0a962c02005-02-10 22:00:27 +00001550 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001551#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001552 /* XXX: should not depend on cpu context */
1553 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001554 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001555 ram_addr_t addr;
1556 addr = start;
1557 for(i = 0; i < len; i++) {
1558 kqemu_set_notdirty(env, addr);
1559 addr += TARGET_PAGE_SIZE;
1560 }
bellard3a7d9292005-08-21 09:26:42 +00001561 }
1562#endif
bellardf23db162005-08-21 19:12:28 +00001563 mask = ~dirty_flags;
1564 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1565 for(i = 0; i < len; i++)
1566 p[i] &= mask;
1567
bellard1ccde1c2004-02-06 19:46:14 +00001568 /* we modify the TLB cache so that the dirty bit will be set again
1569 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001570 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001571 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1572 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001573 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001574 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001575 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001576#if (NB_MMU_MODES >= 3)
1577 for(i = 0; i < CPU_TLB_SIZE; i++)
1578 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1579#if (NB_MMU_MODES == 4)
1580 for(i = 0; i < CPU_TLB_SIZE; i++)
1581 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1582#endif
1583#endif
bellard6a00d602005-11-21 23:25:50 +00001584 }
bellard59817cc2004-02-16 22:01:13 +00001585
1586#if !defined(CONFIG_SOFTMMU)
1587 /* XXX: this is expensive */
1588 {
1589 VirtPageDesc *p;
1590 int j;
1591 target_ulong addr;
1592
1593 for(i = 0; i < L1_SIZE; i++) {
1594 p = l1_virt_map[i];
1595 if (p) {
1596 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1597 for(j = 0; j < L2_SIZE; j++) {
1598 if (p->valid_tag == virt_valid_tag &&
1599 p->phys_addr >= start && p->phys_addr < end &&
1600 (p->prot & PROT_WRITE)) {
1601 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001602 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001603 p->prot & ~PROT_WRITE);
1604 }
1605 }
1606 addr += TARGET_PAGE_SIZE;
1607 p++;
1608 }
1609 }
1610 }
1611 }
1612#endif
bellard1ccde1c2004-02-06 19:46:14 +00001613}
1614
bellard3a7d9292005-08-21 09:26:42 +00001615static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1616{
1617 ram_addr_t ram_addr;
1618
bellard84b7b8e2005-11-28 21:19:04 +00001619 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001620 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001621 tlb_entry->addend - (unsigned long)phys_ram_base;
1622 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001623 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001624 }
1625 }
1626}
1627
1628/* update the TLB according to the current state of the dirty bits */
1629void cpu_tlb_update_dirty(CPUState *env)
1630{
1631 int i;
1632 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001633 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001634 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001635 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001636#if (NB_MMU_MODES >= 3)
1637 for(i = 0; i < CPU_TLB_SIZE; i++)
1638 tlb_update_dirty(&env->tlb_table[2][i]);
1639#if (NB_MMU_MODES == 4)
1640 for(i = 0; i < CPU_TLB_SIZE; i++)
1641 tlb_update_dirty(&env->tlb_table[3][i]);
1642#endif
1643#endif
bellard3a7d9292005-08-21 09:26:42 +00001644}
1645
ths5fafdf22007-09-16 21:08:06 +00001646static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001647 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001648{
1649 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001650 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1651 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001652 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001653 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001654 }
1655 }
1656}
1657
1658/* update the TLB corresponding to virtual page vaddr and phys addr
1659 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001660static inline void tlb_set_dirty(CPUState *env,
1661 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001662{
bellard1ccde1c2004-02-06 19:46:14 +00001663 int i;
1664
bellard1ccde1c2004-02-06 19:46:14 +00001665 addr &= TARGET_PAGE_MASK;
1666 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001667 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1668 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001669#if (NB_MMU_MODES >= 3)
1670 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1671#if (NB_MMU_MODES == 4)
1672 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1673#endif
1674#endif
bellard9fa3e852004-01-04 18:06:42 +00001675}
1676
bellard59817cc2004-02-16 22:01:13 +00001677/* add a new TLB entry. At most one entry for a given virtual address
1678 is permitted. Return 0 if OK or 2 if the page could not be mapped
1679 (can only happen in non SOFTMMU mode for I/O pages or pages
1680 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001681int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1682 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001683 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001684{
bellard92e873b2004-05-21 14:52:29 +00001685 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001686 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001687 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001688 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001689 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001690 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001691 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001692 int i;
bellard9fa3e852004-01-04 18:06:42 +00001693
bellard92e873b2004-05-21 14:52:29 +00001694 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001695 if (!p) {
1696 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001697 } else {
1698 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001699 }
1700#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001701 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1702 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001703#endif
1704
1705 ret = 0;
1706#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001707 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001708#endif
1709 {
bellard2a4188a2006-06-25 21:54:59 +00001710 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001711 /* IO memory case */
1712 address = vaddr | pd;
1713 addend = paddr;
1714 } else {
1715 /* standard memory */
1716 address = vaddr;
1717 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1718 }
pbrook6658ffb2007-03-16 23:58:11 +00001719
1720 /* Make accesses to pages with watchpoints go via the
1721 watchpoint trap routines. */
1722 for (i = 0; i < env->nb_watchpoints; i++) {
1723 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1724 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001725 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001726 address = vaddr | io_mem_watch;
1727 } else {
balrogd79acba2007-06-26 20:01:13 +00001728 env->watchpoint[i].addend = pd - paddr +
1729 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001730 /* TODO: Figure out how to make read watchpoints coexist
1731 with code. */
1732 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1733 }
1734 }
1735 }
balrogd79acba2007-06-26 20:01:13 +00001736
bellard90f18422005-07-24 10:17:31 +00001737 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001738 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001739 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001740 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001741 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001742 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001743 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001744 te->addr_read = -1;
1745 }
edgar_igl5c751e92008-05-06 08:44:21 +00001746
1747 if (te->addr_code != -1) {
1748 tlb_flush_jmp_cache(env, te->addr_code);
1749 }
bellard84b7b8e2005-11-28 21:19:04 +00001750 if (prot & PAGE_EXEC) {
1751 te->addr_code = address;
1752 } else {
1753 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001754 }
bellard67b915a2004-03-31 23:37:16 +00001755 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001756 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001757 (pd & IO_MEM_ROMD)) {
1758 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001759 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001760 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001761 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001762 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001763 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001764 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001765 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001766 }
1767 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001768 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001769 }
1770 }
1771#if !defined(CONFIG_SOFTMMU)
1772 else {
1773 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1774 /* IO access: no mapping is done as it will be handled by the
1775 soft MMU */
1776 if (!(env->hflags & HF_SOFTMMU_MASK))
1777 ret = 2;
1778 } else {
1779 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001780
bellard59817cc2004-02-16 22:01:13 +00001781 if (vaddr >= MMAP_AREA_END) {
1782 ret = 2;
1783 } else {
1784 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001785 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001786#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001787 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001788#endif
ths5fafdf22007-09-16 21:08:06 +00001789 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001790 !cpu_physical_memory_is_dirty(pd))) {
1791 /* ROM: we do as if code was inside */
1792 /* if code is present, we only map as read only and save the
1793 original mapping */
1794 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001795
bellard90f18422005-07-24 10:17:31 +00001796 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001797 vp->phys_addr = pd;
1798 vp->prot = prot;
1799 vp->valid_tag = virt_valid_tag;
1800 prot &= ~PAGE_WRITE;
1801 }
bellard9fa3e852004-01-04 18:06:42 +00001802 }
ths5fafdf22007-09-16 21:08:06 +00001803 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001804 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1805 if (map_addr == MAP_FAILED) {
1806 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1807 paddr, vaddr);
1808 }
bellard9fa3e852004-01-04 18:06:42 +00001809 }
1810 }
1811 }
1812#endif
1813 return ret;
1814}
1815
1816/* called from signal handler: invalidate the code and unprotect the
1817 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001818int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001819{
1820#if !defined(CONFIG_SOFTMMU)
1821 VirtPageDesc *vp;
1822
1823#if defined(DEBUG_TLB)
1824 printf("page_unprotect: addr=0x%08x\n", addr);
1825#endif
1826 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001827
1828 /* if it is not mapped, no need to worry here */
1829 if (addr >= MMAP_AREA_END)
1830 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001831 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1832 if (!vp)
1833 return 0;
1834 /* NOTE: in this case, validate_tag is _not_ tested as it
1835 validates only the code TLB */
1836 if (vp->valid_tag != virt_valid_tag)
1837 return 0;
1838 if (!(vp->prot & PAGE_WRITE))
1839 return 0;
1840#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001841 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001842 addr, vp->phys_addr, vp->prot);
1843#endif
bellard59817cc2004-02-16 22:01:13 +00001844 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1845 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1846 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001847 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001848 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001849 /* flush the code inside */
1850 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001851 return 1;
1852#else
1853 return 0;
1854#endif
bellard33417e72003-08-10 21:47:01 +00001855}
1856
bellard01243112004-01-04 15:48:17 +00001857#else
1858
bellardee8b7022004-02-03 23:35:10 +00001859void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001860{
1861}
1862
bellard2e126692004-04-25 21:28:44 +00001863void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001864{
1865}
1866
ths5fafdf22007-09-16 21:08:06 +00001867int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1868 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001869 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001870{
bellard9fa3e852004-01-04 18:06:42 +00001871 return 0;
1872}
bellard33417e72003-08-10 21:47:01 +00001873
bellard9fa3e852004-01-04 18:06:42 +00001874/* dump memory mappings */
1875void page_dump(FILE *f)
1876{
1877 unsigned long start, end;
1878 int i, j, prot, prot1;
1879 PageDesc *p;
1880
1881 fprintf(f, "%-8s %-8s %-8s %s\n",
1882 "start", "end", "size", "prot");
1883 start = -1;
1884 end = -1;
1885 prot = 0;
1886 for(i = 0; i <= L1_SIZE; i++) {
1887 if (i < L1_SIZE)
1888 p = l1_map[i];
1889 else
1890 p = NULL;
1891 for(j = 0;j < L2_SIZE; j++) {
1892 if (!p)
1893 prot1 = 0;
1894 else
1895 prot1 = p[j].flags;
1896 if (prot1 != prot) {
1897 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1898 if (start != -1) {
1899 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001900 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001901 prot & PAGE_READ ? 'r' : '-',
1902 prot & PAGE_WRITE ? 'w' : '-',
1903 prot & PAGE_EXEC ? 'x' : '-');
1904 }
1905 if (prot1 != 0)
1906 start = end;
1907 else
1908 start = -1;
1909 prot = prot1;
1910 }
1911 if (!p)
1912 break;
1913 }
bellard33417e72003-08-10 21:47:01 +00001914 }
bellard33417e72003-08-10 21:47:01 +00001915}
1916
pbrook53a59602006-03-25 19:31:22 +00001917int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001918{
bellard9fa3e852004-01-04 18:06:42 +00001919 PageDesc *p;
1920
1921 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001922 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001923 return 0;
1924 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001925}
1926
bellard9fa3e852004-01-04 18:06:42 +00001927/* modify the flags of a page and invalidate the code if
1928 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1929 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001930void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001931{
1932 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001933 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001934
1935 start = start & TARGET_PAGE_MASK;
1936 end = TARGET_PAGE_ALIGN(end);
1937 if (flags & PAGE_WRITE)
1938 flags |= PAGE_WRITE_ORG;
1939 spin_lock(&tb_lock);
1940 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1941 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1942 /* if the write protection is set, then we invalidate the code
1943 inside */
ths5fafdf22007-09-16 21:08:06 +00001944 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001945 (flags & PAGE_WRITE) &&
1946 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001947 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001948 }
1949 p->flags = flags;
1950 }
1951 spin_unlock(&tb_lock);
1952}
1953
ths3d97b402007-11-02 19:02:07 +00001954int page_check_range(target_ulong start, target_ulong len, int flags)
1955{
1956 PageDesc *p;
1957 target_ulong end;
1958 target_ulong addr;
1959
1960 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1961 start = start & TARGET_PAGE_MASK;
1962
1963 if( end < start )
1964 /* we've wrapped around */
1965 return -1;
1966 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1967 p = page_find(addr >> TARGET_PAGE_BITS);
1968 if( !p )
1969 return -1;
1970 if( !(p->flags & PAGE_VALID) )
1971 return -1;
1972
bellarddae32702007-11-14 10:51:00 +00001973 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001974 return -1;
bellarddae32702007-11-14 10:51:00 +00001975 if (flags & PAGE_WRITE) {
1976 if (!(p->flags & PAGE_WRITE_ORG))
1977 return -1;
1978 /* unprotect the page if it was put read-only because it
1979 contains translated code */
1980 if (!(p->flags & PAGE_WRITE)) {
1981 if (!page_unprotect(addr, 0, NULL))
1982 return -1;
1983 }
1984 return 0;
1985 }
ths3d97b402007-11-02 19:02:07 +00001986 }
1987 return 0;
1988}
1989
bellard9fa3e852004-01-04 18:06:42 +00001990/* called from signal handler: invalidate the code and unprotect the
1991 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001992int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001993{
1994 unsigned int page_index, prot, pindex;
1995 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001996 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001997
bellard83fb7ad2004-07-05 21:25:26 +00001998 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001999 page_index = host_start >> TARGET_PAGE_BITS;
2000 p1 = page_find(page_index);
2001 if (!p1)
2002 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00002003 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002004 p = p1;
2005 prot = 0;
2006 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2007 prot |= p->flags;
2008 p++;
2009 }
2010 /* if the page was really writable, then we change its
2011 protection back to writable */
2012 if (prot & PAGE_WRITE_ORG) {
2013 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2014 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002015 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002016 (prot & PAGE_BITS) | PAGE_WRITE);
2017 p1[pindex].flags |= PAGE_WRITE;
2018 /* and since the content will be modified, we must invalidate
2019 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002020 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002021#ifdef DEBUG_TB_CHECK
2022 tb_invalidate_check(address);
2023#endif
2024 return 1;
2025 }
2026 }
2027 return 0;
2028}
2029
bellard6a00d602005-11-21 23:25:50 +00002030static inline void tlb_set_dirty(CPUState *env,
2031 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002032{
2033}
bellard9fa3e852004-01-04 18:06:42 +00002034#endif /* defined(CONFIG_USER_ONLY) */
2035
blueswir1db7b5422007-05-26 17:36:03 +00002036static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002037 ram_addr_t memory);
2038static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2039 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002040#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2041 need_subpage) \
2042 do { \
2043 if (addr > start_addr) \
2044 start_addr2 = 0; \
2045 else { \
2046 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2047 if (start_addr2 > 0) \
2048 need_subpage = 1; \
2049 } \
2050 \
blueswir149e9fba2007-05-30 17:25:06 +00002051 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002052 end_addr2 = TARGET_PAGE_SIZE - 1; \
2053 else { \
2054 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2055 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2056 need_subpage = 1; \
2057 } \
2058 } while (0)
2059
bellard33417e72003-08-10 21:47:01 +00002060/* register physical memory. 'size' must be a multiple of the target
2061 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2062 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002063void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002064 ram_addr_t size,
2065 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002066{
bellard108c49b2005-07-24 12:55:09 +00002067 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002068 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002069 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002070 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002071 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002072
bellard5fd386f2004-05-23 21:11:22 +00002073 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002074 end_addr = start_addr + (target_phys_addr_t)size;
2075 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002076 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2077 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002078 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002079 target_phys_addr_t start_addr2, end_addr2;
2080 int need_subpage = 0;
2081
2082 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2083 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002084 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002085 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2086 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2087 &p->phys_offset, orig_memory);
2088 } else {
2089 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2090 >> IO_MEM_SHIFT];
2091 }
2092 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2093 } else {
2094 p->phys_offset = phys_offset;
2095 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2096 (phys_offset & IO_MEM_ROMD))
2097 phys_offset += TARGET_PAGE_SIZE;
2098 }
2099 } else {
2100 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2101 p->phys_offset = phys_offset;
2102 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2103 (phys_offset & IO_MEM_ROMD))
2104 phys_offset += TARGET_PAGE_SIZE;
2105 else {
2106 target_phys_addr_t start_addr2, end_addr2;
2107 int need_subpage = 0;
2108
2109 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2110 end_addr2, need_subpage);
2111
blueswir14254fab2008-01-01 16:57:19 +00002112 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002113 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2114 &p->phys_offset, IO_MEM_UNASSIGNED);
2115 subpage_register(subpage, start_addr2, end_addr2,
2116 phys_offset);
2117 }
2118 }
2119 }
bellard33417e72003-08-10 21:47:01 +00002120 }
ths3b46e622007-09-17 08:09:54 +00002121
bellard9d420372006-06-25 22:25:22 +00002122 /* since each CPU stores ram addresses in its TLB cache, we must
2123 reset the modified entries */
2124 /* XXX: slow ! */
2125 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2126 tlb_flush(env, 1);
2127 }
bellard33417e72003-08-10 21:47:01 +00002128}
2129
bellardba863452006-09-24 18:41:10 +00002130/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002131ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002132{
2133 PhysPageDesc *p;
2134
2135 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2136 if (!p)
2137 return IO_MEM_UNASSIGNED;
2138 return p->phys_offset;
2139}
2140
bellarde9a1ab12007-02-08 23:08:38 +00002141/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002142ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002143{
2144 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002145 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002146 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2147 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002148 abort();
2149 }
2150 addr = phys_ram_alloc_offset;
2151 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2152 return addr;
2153}
2154
2155void qemu_ram_free(ram_addr_t addr)
2156{
2157}
2158
bellarda4193c82004-06-03 14:01:43 +00002159static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002160{
pbrook67d3b952006-12-18 05:03:52 +00002161#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002162 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002163#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002164#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002165 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002166#elif TARGET_CRIS
2167 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002168#endif
bellard33417e72003-08-10 21:47:01 +00002169 return 0;
2170}
2171
bellarda4193c82004-06-03 14:01:43 +00002172static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002173{
pbrook67d3b952006-12-18 05:03:52 +00002174#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002175 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002176#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002177#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002178 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002179#elif TARGET_CRIS
2180 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002181#endif
bellard33417e72003-08-10 21:47:01 +00002182}
2183
2184static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2185 unassigned_mem_readb,
2186 unassigned_mem_readb,
2187 unassigned_mem_readb,
2188};
2189
2190static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2191 unassigned_mem_writeb,
2192 unassigned_mem_writeb,
2193 unassigned_mem_writeb,
2194};
2195
bellarda4193c82004-06-03 14:01:43 +00002196static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002197{
bellard3a7d9292005-08-21 09:26:42 +00002198 unsigned long ram_addr;
2199 int dirty_flags;
2200 ram_addr = addr - (unsigned long)phys_ram_base;
2201 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2202 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2203#if !defined(CONFIG_USER_ONLY)
2204 tb_invalidate_phys_page_fast(ram_addr, 1);
2205 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2206#endif
2207 }
bellardc27004e2005-01-03 23:35:10 +00002208 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002209#ifdef USE_KQEMU
2210 if (cpu_single_env->kqemu_enabled &&
2211 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2212 kqemu_modify_page(cpu_single_env, ram_addr);
2213#endif
bellardf23db162005-08-21 19:12:28 +00002214 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2215 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2216 /* we remove the notdirty callback only if the code has been
2217 flushed */
2218 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002219 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002220}
2221
bellarda4193c82004-06-03 14:01:43 +00002222static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002223{
bellard3a7d9292005-08-21 09:26:42 +00002224 unsigned long ram_addr;
2225 int dirty_flags;
2226 ram_addr = addr - (unsigned long)phys_ram_base;
2227 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2228 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2229#if !defined(CONFIG_USER_ONLY)
2230 tb_invalidate_phys_page_fast(ram_addr, 2);
2231 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2232#endif
2233 }
bellardc27004e2005-01-03 23:35:10 +00002234 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002235#ifdef USE_KQEMU
2236 if (cpu_single_env->kqemu_enabled &&
2237 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2238 kqemu_modify_page(cpu_single_env, ram_addr);
2239#endif
bellardf23db162005-08-21 19:12:28 +00002240 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2241 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2242 /* we remove the notdirty callback only if the code has been
2243 flushed */
2244 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002245 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002246}
2247
bellarda4193c82004-06-03 14:01:43 +00002248static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002249{
bellard3a7d9292005-08-21 09:26:42 +00002250 unsigned long ram_addr;
2251 int dirty_flags;
2252 ram_addr = addr - (unsigned long)phys_ram_base;
2253 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2254 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2255#if !defined(CONFIG_USER_ONLY)
2256 tb_invalidate_phys_page_fast(ram_addr, 4);
2257 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2258#endif
2259 }
bellardc27004e2005-01-03 23:35:10 +00002260 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002261#ifdef USE_KQEMU
2262 if (cpu_single_env->kqemu_enabled &&
2263 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2264 kqemu_modify_page(cpu_single_env, ram_addr);
2265#endif
bellardf23db162005-08-21 19:12:28 +00002266 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2267 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2268 /* we remove the notdirty callback only if the code has been
2269 flushed */
2270 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002271 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002272}
2273
bellard3a7d9292005-08-21 09:26:42 +00002274static CPUReadMemoryFunc *error_mem_read[3] = {
2275 NULL, /* never used */
2276 NULL, /* never used */
2277 NULL, /* never used */
2278};
2279
bellard1ccde1c2004-02-06 19:46:14 +00002280static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2281 notdirty_mem_writeb,
2282 notdirty_mem_writew,
2283 notdirty_mem_writel,
2284};
2285
pbrook6658ffb2007-03-16 23:58:11 +00002286#if defined(CONFIG_SOFTMMU)
2287/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2288 so these check for a hit then pass through to the normal out-of-line
2289 phys routines. */
2290static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2291{
2292 return ldub_phys(addr);
2293}
2294
2295static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2296{
2297 return lduw_phys(addr);
2298}
2299
2300static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2301{
2302 return ldl_phys(addr);
2303}
2304
2305/* Generate a debug exception if a watchpoint has been hit.
2306 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002307 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002308static target_ulong check_watchpoint(target_phys_addr_t addr)
2309{
2310 CPUState *env = cpu_single_env;
2311 target_ulong watch;
2312 target_ulong retaddr;
2313 int i;
2314
2315 retaddr = addr;
2316 for (i = 0; i < env->nb_watchpoints; i++) {
2317 watch = env->watchpoint[i].vaddr;
2318 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002319 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002320 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2321 cpu_single_env->watchpoint_hit = i + 1;
2322 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2323 break;
2324 }
2325 }
2326 }
2327 return retaddr;
2328}
2329
2330static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2331 uint32_t val)
2332{
2333 addr = check_watchpoint(addr);
2334 stb_phys(addr, val);
2335}
2336
2337static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2338 uint32_t val)
2339{
2340 addr = check_watchpoint(addr);
2341 stw_phys(addr, val);
2342}
2343
2344static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2345 uint32_t val)
2346{
2347 addr = check_watchpoint(addr);
2348 stl_phys(addr, val);
2349}
2350
2351static CPUReadMemoryFunc *watch_mem_read[3] = {
2352 watch_mem_readb,
2353 watch_mem_readw,
2354 watch_mem_readl,
2355};
2356
2357static CPUWriteMemoryFunc *watch_mem_write[3] = {
2358 watch_mem_writeb,
2359 watch_mem_writew,
2360 watch_mem_writel,
2361};
2362#endif
2363
blueswir1db7b5422007-05-26 17:36:03 +00002364static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2365 unsigned int len)
2366{
blueswir1db7b5422007-05-26 17:36:03 +00002367 uint32_t ret;
2368 unsigned int idx;
2369
2370 idx = SUBPAGE_IDX(addr - mmio->base);
2371#if defined(DEBUG_SUBPAGE)
2372 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2373 mmio, len, addr, idx);
2374#endif
blueswir13ee89922008-01-02 19:45:26 +00002375 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002376
2377 return ret;
2378}
2379
2380static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2381 uint32_t value, unsigned int len)
2382{
blueswir1db7b5422007-05-26 17:36:03 +00002383 unsigned int idx;
2384
2385 idx = SUBPAGE_IDX(addr - mmio->base);
2386#if defined(DEBUG_SUBPAGE)
2387 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2388 mmio, len, addr, idx, value);
2389#endif
blueswir13ee89922008-01-02 19:45:26 +00002390 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002391}
2392
2393static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2394{
2395#if defined(DEBUG_SUBPAGE)
2396 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2397#endif
2398
2399 return subpage_readlen(opaque, addr, 0);
2400}
2401
2402static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2403 uint32_t value)
2404{
2405#if defined(DEBUG_SUBPAGE)
2406 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2407#endif
2408 subpage_writelen(opaque, addr, value, 0);
2409}
2410
2411static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2412{
2413#if defined(DEBUG_SUBPAGE)
2414 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2415#endif
2416
2417 return subpage_readlen(opaque, addr, 1);
2418}
2419
2420static void subpage_writew (void *opaque, target_phys_addr_t addr,
2421 uint32_t value)
2422{
2423#if defined(DEBUG_SUBPAGE)
2424 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2425#endif
2426 subpage_writelen(opaque, addr, value, 1);
2427}
2428
2429static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2430{
2431#if defined(DEBUG_SUBPAGE)
2432 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2433#endif
2434
2435 return subpage_readlen(opaque, addr, 2);
2436}
2437
2438static void subpage_writel (void *opaque,
2439 target_phys_addr_t addr, uint32_t value)
2440{
2441#if defined(DEBUG_SUBPAGE)
2442 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2443#endif
2444 subpage_writelen(opaque, addr, value, 2);
2445}
2446
2447static CPUReadMemoryFunc *subpage_read[] = {
2448 &subpage_readb,
2449 &subpage_readw,
2450 &subpage_readl,
2451};
2452
2453static CPUWriteMemoryFunc *subpage_write[] = {
2454 &subpage_writeb,
2455 &subpage_writew,
2456 &subpage_writel,
2457};
2458
2459static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002460 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002461{
2462 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002463 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002464
2465 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2466 return -1;
2467 idx = SUBPAGE_IDX(start);
2468 eidx = SUBPAGE_IDX(end);
2469#if defined(DEBUG_SUBPAGE)
2470 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2471 mmio, start, end, idx, eidx, memory);
2472#endif
2473 memory >>= IO_MEM_SHIFT;
2474 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002475 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002476 if (io_mem_read[memory][i]) {
2477 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2478 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2479 }
2480 if (io_mem_write[memory][i]) {
2481 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2482 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2483 }
blueswir14254fab2008-01-01 16:57:19 +00002484 }
blueswir1db7b5422007-05-26 17:36:03 +00002485 }
2486
2487 return 0;
2488}
2489
aurel3200f82b82008-04-27 21:12:55 +00002490static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2491 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002492{
2493 subpage_t *mmio;
2494 int subpage_memory;
2495
2496 mmio = qemu_mallocz(sizeof(subpage_t));
2497 if (mmio != NULL) {
2498 mmio->base = base;
2499 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2500#if defined(DEBUG_SUBPAGE)
2501 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2502 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2503#endif
2504 *phys = subpage_memory | IO_MEM_SUBPAGE;
2505 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2506 }
2507
2508 return mmio;
2509}
2510
bellard33417e72003-08-10 21:47:01 +00002511static void io_mem_init(void)
2512{
bellard3a7d9292005-08-21 09:26:42 +00002513 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002514 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002515 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002516 io_mem_nb = 5;
2517
pbrook6658ffb2007-03-16 23:58:11 +00002518#if defined(CONFIG_SOFTMMU)
2519 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2520 watch_mem_write, NULL);
2521#endif
bellard1ccde1c2004-02-06 19:46:14 +00002522 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002523 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002524 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002525}
2526
2527/* mem_read and mem_write are arrays of functions containing the
2528 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002529 2). Functions can be omitted with a NULL function pointer. The
2530 registered functions may be modified dynamically later.
2531 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002532 modified. If it is zero, a new io zone is allocated. The return
2533 value can be used with cpu_register_physical_memory(). (-1) is
2534 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002535int cpu_register_io_memory(int io_index,
2536 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002537 CPUWriteMemoryFunc **mem_write,
2538 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002539{
blueswir14254fab2008-01-01 16:57:19 +00002540 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002541
2542 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002543 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002544 return -1;
2545 io_index = io_mem_nb++;
2546 } else {
2547 if (io_index >= IO_MEM_NB_ENTRIES)
2548 return -1;
2549 }
bellardb5ff1b32005-11-26 10:38:39 +00002550
bellard33417e72003-08-10 21:47:01 +00002551 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002552 if (!mem_read[i] || !mem_write[i])
2553 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002554 io_mem_read[io_index][i] = mem_read[i];
2555 io_mem_write[io_index][i] = mem_write[i];
2556 }
bellarda4193c82004-06-03 14:01:43 +00002557 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002558 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002559}
bellard61382a52003-10-27 21:22:23 +00002560
bellard8926b512004-10-10 15:14:20 +00002561CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2562{
2563 return io_mem_write[io_index >> IO_MEM_SHIFT];
2564}
2565
2566CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2567{
2568 return io_mem_read[io_index >> IO_MEM_SHIFT];
2569}
2570
bellard13eb76e2004-01-24 15:23:36 +00002571/* physical memory access (slow version, mainly for debug) */
2572#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002573void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002574 int len, int is_write)
2575{
2576 int l, flags;
2577 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002578 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002579
2580 while (len > 0) {
2581 page = addr & TARGET_PAGE_MASK;
2582 l = (page + TARGET_PAGE_SIZE) - addr;
2583 if (l > len)
2584 l = len;
2585 flags = page_get_flags(page);
2586 if (!(flags & PAGE_VALID))
2587 return;
2588 if (is_write) {
2589 if (!(flags & PAGE_WRITE))
2590 return;
bellard579a97f2007-11-11 14:26:47 +00002591 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002592 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002593 /* FIXME - should this return an error rather than just fail? */
2594 return;
aurel3272fb7da2008-04-27 23:53:45 +00002595 memcpy(p, buf, l);
2596 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002597 } else {
2598 if (!(flags & PAGE_READ))
2599 return;
bellard579a97f2007-11-11 14:26:47 +00002600 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002601 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002602 /* FIXME - should this return an error rather than just fail? */
2603 return;
aurel3272fb7da2008-04-27 23:53:45 +00002604 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002605 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002606 }
2607 len -= l;
2608 buf += l;
2609 addr += l;
2610 }
2611}
bellard8df1cd02005-01-28 22:37:22 +00002612
bellard13eb76e2004-01-24 15:23:36 +00002613#else
ths5fafdf22007-09-16 21:08:06 +00002614void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002615 int len, int is_write)
2616{
2617 int l, io_index;
2618 uint8_t *ptr;
2619 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002620 target_phys_addr_t page;
2621 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002622 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002623
bellard13eb76e2004-01-24 15:23:36 +00002624 while (len > 0) {
2625 page = addr & TARGET_PAGE_MASK;
2626 l = (page + TARGET_PAGE_SIZE) - addr;
2627 if (l > len)
2628 l = len;
bellard92e873b2004-05-21 14:52:29 +00002629 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002630 if (!p) {
2631 pd = IO_MEM_UNASSIGNED;
2632 } else {
2633 pd = p->phys_offset;
2634 }
ths3b46e622007-09-17 08:09:54 +00002635
bellard13eb76e2004-01-24 15:23:36 +00002636 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002637 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002638 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002639 /* XXX: could force cpu_single_env to NULL to avoid
2640 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002641 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002642 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002643 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002644 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002645 l = 4;
2646 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002647 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002648 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002649 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002650 l = 2;
2651 } else {
bellard1c213d12005-09-03 10:49:04 +00002652 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002653 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002654 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002655 l = 1;
2656 }
2657 } else {
bellardb448f2f2004-02-25 23:24:04 +00002658 unsigned long addr1;
2659 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002660 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002661 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002662 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002663 if (!cpu_physical_memory_is_dirty(addr1)) {
2664 /* invalidate code */
2665 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2666 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002667 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002668 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002669 }
bellard13eb76e2004-01-24 15:23:36 +00002670 }
2671 } else {
ths5fafdf22007-09-16 21:08:06 +00002672 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002673 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002674 /* I/O case */
2675 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2676 if (l >= 4 && ((addr & 3) == 0)) {
2677 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002678 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002679 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002680 l = 4;
2681 } else if (l >= 2 && ((addr & 1) == 0)) {
2682 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002683 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002684 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002685 l = 2;
2686 } else {
bellard1c213d12005-09-03 10:49:04 +00002687 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002688 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002689 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002690 l = 1;
2691 }
2692 } else {
2693 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002694 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002695 (addr & ~TARGET_PAGE_MASK);
2696 memcpy(buf, ptr, l);
2697 }
2698 }
2699 len -= l;
2700 buf += l;
2701 addr += l;
2702 }
2703}
bellard8df1cd02005-01-28 22:37:22 +00002704
bellardd0ecd2a2006-04-23 17:14:48 +00002705/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002706void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002707 const uint8_t *buf, int len)
2708{
2709 int l;
2710 uint8_t *ptr;
2711 target_phys_addr_t page;
2712 unsigned long pd;
2713 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002714
bellardd0ecd2a2006-04-23 17:14:48 +00002715 while (len > 0) {
2716 page = addr & TARGET_PAGE_MASK;
2717 l = (page + TARGET_PAGE_SIZE) - addr;
2718 if (l > len)
2719 l = len;
2720 p = phys_page_find(page >> TARGET_PAGE_BITS);
2721 if (!p) {
2722 pd = IO_MEM_UNASSIGNED;
2723 } else {
2724 pd = p->phys_offset;
2725 }
ths3b46e622007-09-17 08:09:54 +00002726
bellardd0ecd2a2006-04-23 17:14:48 +00002727 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002728 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2729 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002730 /* do nothing */
2731 } else {
2732 unsigned long addr1;
2733 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2734 /* ROM/RAM case */
2735 ptr = phys_ram_base + addr1;
2736 memcpy(ptr, buf, l);
2737 }
2738 len -= l;
2739 buf += l;
2740 addr += l;
2741 }
2742}
2743
2744
bellard8df1cd02005-01-28 22:37:22 +00002745/* warning: addr must be aligned */
2746uint32_t ldl_phys(target_phys_addr_t addr)
2747{
2748 int io_index;
2749 uint8_t *ptr;
2750 uint32_t val;
2751 unsigned long pd;
2752 PhysPageDesc *p;
2753
2754 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2755 if (!p) {
2756 pd = IO_MEM_UNASSIGNED;
2757 } else {
2758 pd = p->phys_offset;
2759 }
ths3b46e622007-09-17 08:09:54 +00002760
ths5fafdf22007-09-16 21:08:06 +00002761 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002762 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002763 /* I/O case */
2764 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2765 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2766 } else {
2767 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002768 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002769 (addr & ~TARGET_PAGE_MASK);
2770 val = ldl_p(ptr);
2771 }
2772 return val;
2773}
2774
bellard84b7b8e2005-11-28 21:19:04 +00002775/* warning: addr must be aligned */
2776uint64_t ldq_phys(target_phys_addr_t addr)
2777{
2778 int io_index;
2779 uint8_t *ptr;
2780 uint64_t val;
2781 unsigned long pd;
2782 PhysPageDesc *p;
2783
2784 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2785 if (!p) {
2786 pd = IO_MEM_UNASSIGNED;
2787 } else {
2788 pd = p->phys_offset;
2789 }
ths3b46e622007-09-17 08:09:54 +00002790
bellard2a4188a2006-06-25 21:54:59 +00002791 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2792 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002793 /* I/O case */
2794 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2795#ifdef TARGET_WORDS_BIGENDIAN
2796 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2797 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2798#else
2799 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2800 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2801#endif
2802 } else {
2803 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002804 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002805 (addr & ~TARGET_PAGE_MASK);
2806 val = ldq_p(ptr);
2807 }
2808 return val;
2809}
2810
bellardaab33092005-10-30 20:48:42 +00002811/* XXX: optimize */
2812uint32_t ldub_phys(target_phys_addr_t addr)
2813{
2814 uint8_t val;
2815 cpu_physical_memory_read(addr, &val, 1);
2816 return val;
2817}
2818
2819/* XXX: optimize */
2820uint32_t lduw_phys(target_phys_addr_t addr)
2821{
2822 uint16_t val;
2823 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2824 return tswap16(val);
2825}
2826
bellard8df1cd02005-01-28 22:37:22 +00002827/* warning: addr must be aligned. The ram page is not masked as dirty
2828 and the code inside is not invalidated. It is useful if the dirty
2829 bits are used to track modified PTEs */
2830void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2831{
2832 int io_index;
2833 uint8_t *ptr;
2834 unsigned long pd;
2835 PhysPageDesc *p;
2836
2837 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2838 if (!p) {
2839 pd = IO_MEM_UNASSIGNED;
2840 } else {
2841 pd = p->phys_offset;
2842 }
ths3b46e622007-09-17 08:09:54 +00002843
bellard3a7d9292005-08-21 09:26:42 +00002844 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002845 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2846 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2847 } else {
ths5fafdf22007-09-16 21:08:06 +00002848 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002849 (addr & ~TARGET_PAGE_MASK);
2850 stl_p(ptr, val);
2851 }
2852}
2853
j_mayerbc98a7e2007-04-04 07:55:12 +00002854void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2855{
2856 int io_index;
2857 uint8_t *ptr;
2858 unsigned long pd;
2859 PhysPageDesc *p;
2860
2861 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2862 if (!p) {
2863 pd = IO_MEM_UNASSIGNED;
2864 } else {
2865 pd = p->phys_offset;
2866 }
ths3b46e622007-09-17 08:09:54 +00002867
j_mayerbc98a7e2007-04-04 07:55:12 +00002868 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2869 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2870#ifdef TARGET_WORDS_BIGENDIAN
2871 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2872 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2873#else
2874 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2875 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2876#endif
2877 } else {
ths5fafdf22007-09-16 21:08:06 +00002878 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002879 (addr & ~TARGET_PAGE_MASK);
2880 stq_p(ptr, val);
2881 }
2882}
2883
bellard8df1cd02005-01-28 22:37:22 +00002884/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002885void stl_phys(target_phys_addr_t addr, uint32_t val)
2886{
2887 int io_index;
2888 uint8_t *ptr;
2889 unsigned long pd;
2890 PhysPageDesc *p;
2891
2892 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2893 if (!p) {
2894 pd = IO_MEM_UNASSIGNED;
2895 } else {
2896 pd = p->phys_offset;
2897 }
ths3b46e622007-09-17 08:09:54 +00002898
bellard3a7d9292005-08-21 09:26:42 +00002899 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002900 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2901 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2902 } else {
2903 unsigned long addr1;
2904 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2905 /* RAM case */
2906 ptr = phys_ram_base + addr1;
2907 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002908 if (!cpu_physical_memory_is_dirty(addr1)) {
2909 /* invalidate code */
2910 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2911 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002912 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2913 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002914 }
bellard8df1cd02005-01-28 22:37:22 +00002915 }
2916}
2917
bellardaab33092005-10-30 20:48:42 +00002918/* XXX: optimize */
2919void stb_phys(target_phys_addr_t addr, uint32_t val)
2920{
2921 uint8_t v = val;
2922 cpu_physical_memory_write(addr, &v, 1);
2923}
2924
2925/* XXX: optimize */
2926void stw_phys(target_phys_addr_t addr, uint32_t val)
2927{
2928 uint16_t v = tswap16(val);
2929 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2930}
2931
2932/* XXX: optimize */
2933void stq_phys(target_phys_addr_t addr, uint64_t val)
2934{
2935 val = tswap64(val);
2936 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2937}
2938
bellard13eb76e2004-01-24 15:23:36 +00002939#endif
2940
2941/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002942int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002943 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002944{
2945 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002946 target_phys_addr_t phys_addr;
2947 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002948
2949 while (len > 0) {
2950 page = addr & TARGET_PAGE_MASK;
2951 phys_addr = cpu_get_phys_page_debug(env, page);
2952 /* if no physical page mapped, return an error */
2953 if (phys_addr == -1)
2954 return -1;
2955 l = (page + TARGET_PAGE_SIZE) - addr;
2956 if (l > len)
2957 l = len;
ths5fafdf22007-09-16 21:08:06 +00002958 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002959 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002960 len -= l;
2961 buf += l;
2962 addr += l;
2963 }
2964 return 0;
2965}
2966
bellarde3db7222005-01-26 22:00:47 +00002967void dump_exec_info(FILE *f,
2968 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2969{
2970 int i, target_code_size, max_target_code_size;
2971 int direct_jmp_count, direct_jmp2_count, cross_page;
2972 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002973
bellarde3db7222005-01-26 22:00:47 +00002974 target_code_size = 0;
2975 max_target_code_size = 0;
2976 cross_page = 0;
2977 direct_jmp_count = 0;
2978 direct_jmp2_count = 0;
2979 for(i = 0; i < nb_tbs; i++) {
2980 tb = &tbs[i];
2981 target_code_size += tb->size;
2982 if (tb->size > max_target_code_size)
2983 max_target_code_size = tb->size;
2984 if (tb->page_addr[1] != -1)
2985 cross_page++;
2986 if (tb->tb_next_offset[0] != 0xffff) {
2987 direct_jmp_count++;
2988 if (tb->tb_next_offset[1] != 0xffff) {
2989 direct_jmp2_count++;
2990 }
2991 }
2992 }
2993 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002994 cpu_fprintf(f, "Translation buffer state:\n");
bellarde3db7222005-01-26 22:00:47 +00002995 cpu_fprintf(f, "TB count %d\n", nb_tbs);
ths5fafdf22007-09-16 21:08:06 +00002996 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002997 nb_tbs ? target_code_size / nb_tbs : 0,
2998 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00002999 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003000 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3001 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003002 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3003 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003004 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3005 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003006 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003007 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3008 direct_jmp2_count,
3009 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003010 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003011 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3012 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3013 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003014 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003015}
3016
ths5fafdf22007-09-16 21:08:06 +00003017#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003018
3019#define MMUSUFFIX _cmmu
3020#define GETPC() NULL
3021#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003022#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003023
3024#define SHIFT 0
3025#include "softmmu_template.h"
3026
3027#define SHIFT 1
3028#include "softmmu_template.h"
3029
3030#define SHIFT 2
3031#include "softmmu_template.h"
3032
3033#define SHIFT 3
3034#include "softmmu_template.h"
3035
3036#undef env
3037
3038#endif