blob: adbf7e5b257f2f7da5dc66c5b8fd6238bb3211e5 [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
pbrookfab94c02008-05-24 13:56:15 +000087TranslationBlock *tbs;
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();
pbrookfab94c02008-05-24 13:56:15 +0000338 tbs = qemu_malloc(CODE_GEN_MAX_BLOCKS * sizeof(TranslationBlock));
bellardfd6ce8f2003-05-14 19:00:11 +0000339 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000340 page_init();
bellard33417e72003-08-10 21:47:01 +0000341 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000342 }
bellard6a00d602005-11-21 23:25:50 +0000343 env->next_cpu = NULL;
344 penv = &first_cpu;
345 cpu_index = 0;
346 while (*penv != NULL) {
347 penv = (CPUState **)&(*penv)->next_cpu;
348 cpu_index++;
349 }
350 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000351 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000352 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000353}
354
bellard9fa3e852004-01-04 18:06:42 +0000355static inline void invalidate_page_bitmap(PageDesc *p)
356{
357 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000358 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000359 p->code_bitmap = NULL;
360 }
361 p->code_write_count = 0;
362}
363
bellardfd6ce8f2003-05-14 19:00:11 +0000364/* set to NULL all the 'first_tb' fields in all PageDescs */
365static void page_flush_tb(void)
366{
367 int i, j;
368 PageDesc *p;
369
370 for(i = 0; i < L1_SIZE; i++) {
371 p = l1_map[i];
372 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000373 for(j = 0; j < L2_SIZE; j++) {
374 p->first_tb = NULL;
375 invalidate_page_bitmap(p);
376 p++;
377 }
bellardfd6ce8f2003-05-14 19:00:11 +0000378 }
379 }
380}
381
382/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000383/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000384void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000385{
bellard6a00d602005-11-21 23:25:50 +0000386 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000387#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000388 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
389 (unsigned long)(code_gen_ptr - code_gen_buffer),
390 nb_tbs, nb_tbs > 0 ?
391 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000392#endif
pbrooka208e542008-03-31 17:07:36 +0000393 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE)
394 cpu_abort(env1, "Internal error: code buffer overflow\n");
395
bellardfd6ce8f2003-05-14 19:00:11 +0000396 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000397
bellard6a00d602005-11-21 23:25:50 +0000398 for(env = first_cpu; env != NULL; env = env->next_cpu) {
399 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
400 }
bellard9fa3e852004-01-04 18:06:42 +0000401
bellard8a8a6082004-10-03 13:36:49 +0000402 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000403 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000404
bellardfd6ce8f2003-05-14 19:00:11 +0000405 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000406 /* XXX: flush processor icache at this point if cache flush is
407 expensive */
bellarde3db7222005-01-26 22:00:47 +0000408 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000409}
410
411#ifdef DEBUG_TB_CHECK
412
j_mayerbc98a7e2007-04-04 07:55:12 +0000413static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000414{
415 TranslationBlock *tb;
416 int i;
417 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000418 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
419 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000420 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
421 address >= tb->pc + tb->size)) {
422 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000423 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000424 }
425 }
426 }
427}
428
429/* verify that all the pages have correct rights for code */
430static void tb_page_check(void)
431{
432 TranslationBlock *tb;
433 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000434
pbrook99773bd2006-04-16 15:14:59 +0000435 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
436 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000437 flags1 = page_get_flags(tb->pc);
438 flags2 = page_get_flags(tb->pc + tb->size - 1);
439 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
440 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000441 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000442 }
443 }
444 }
445}
446
bellardd4e81642003-05-25 16:46:15 +0000447void tb_jmp_check(TranslationBlock *tb)
448{
449 TranslationBlock *tb1;
450 unsigned int n1;
451
452 /* suppress any remaining jumps to this TB */
453 tb1 = tb->jmp_first;
454 for(;;) {
455 n1 = (long)tb1 & 3;
456 tb1 = (TranslationBlock *)((long)tb1 & ~3);
457 if (n1 == 2)
458 break;
459 tb1 = tb1->jmp_next[n1];
460 }
461 /* check end of list */
462 if (tb1 != tb) {
463 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
464 }
465}
466
bellardfd6ce8f2003-05-14 19:00:11 +0000467#endif
468
469/* invalidate one TB */
470static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
471 int next_offset)
472{
473 TranslationBlock *tb1;
474 for(;;) {
475 tb1 = *ptb;
476 if (tb1 == tb) {
477 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
478 break;
479 }
480 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
481 }
482}
483
bellard9fa3e852004-01-04 18:06:42 +0000484static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
485{
486 TranslationBlock *tb1;
487 unsigned int n1;
488
489 for(;;) {
490 tb1 = *ptb;
491 n1 = (long)tb1 & 3;
492 tb1 = (TranslationBlock *)((long)tb1 & ~3);
493 if (tb1 == tb) {
494 *ptb = tb1->page_next[n1];
495 break;
496 }
497 ptb = &tb1->page_next[n1];
498 }
499}
500
bellardd4e81642003-05-25 16:46:15 +0000501static inline void tb_jmp_remove(TranslationBlock *tb, int n)
502{
503 TranslationBlock *tb1, **ptb;
504 unsigned int n1;
505
506 ptb = &tb->jmp_next[n];
507 tb1 = *ptb;
508 if (tb1) {
509 /* find tb(n) in circular list */
510 for(;;) {
511 tb1 = *ptb;
512 n1 = (long)tb1 & 3;
513 tb1 = (TranslationBlock *)((long)tb1 & ~3);
514 if (n1 == n && tb1 == tb)
515 break;
516 if (n1 == 2) {
517 ptb = &tb1->jmp_first;
518 } else {
519 ptb = &tb1->jmp_next[n1];
520 }
521 }
522 /* now we can suppress tb(n) from the list */
523 *ptb = tb->jmp_next[n];
524
525 tb->jmp_next[n] = NULL;
526 }
527}
528
529/* reset the jump entry 'n' of a TB so that it is not chained to
530 another TB */
531static inline void tb_reset_jump(TranslationBlock *tb, int n)
532{
533 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
534}
535
aurel3200f82b82008-04-27 21:12:55 +0000536static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000537{
bellard6a00d602005-11-21 23:25:50 +0000538 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000539 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000540 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000541 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000542 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000543
bellard9fa3e852004-01-04 18:06:42 +0000544 /* remove the TB from the hash list */
545 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
546 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000547 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000548 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000549
bellard9fa3e852004-01-04 18:06:42 +0000550 /* remove the TB from the page list */
551 if (tb->page_addr[0] != page_addr) {
552 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
553 tb_page_remove(&p->first_tb, tb);
554 invalidate_page_bitmap(p);
555 }
556 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
557 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
558 tb_page_remove(&p->first_tb, tb);
559 invalidate_page_bitmap(p);
560 }
561
bellard8a40a182005-11-20 10:35:40 +0000562 tb_invalidated_flag = 1;
563
564 /* remove the TB from the hash list */
565 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000566 for(env = first_cpu; env != NULL; env = env->next_cpu) {
567 if (env->tb_jmp_cache[h] == tb)
568 env->tb_jmp_cache[h] = NULL;
569 }
bellard8a40a182005-11-20 10:35:40 +0000570
571 /* suppress this TB from the two jump lists */
572 tb_jmp_remove(tb, 0);
573 tb_jmp_remove(tb, 1);
574
575 /* suppress any remaining jumps to this TB */
576 tb1 = tb->jmp_first;
577 for(;;) {
578 n1 = (long)tb1 & 3;
579 if (n1 == 2)
580 break;
581 tb1 = (TranslationBlock *)((long)tb1 & ~3);
582 tb2 = tb1->jmp_next[n1];
583 tb_reset_jump(tb1, n1);
584 tb1->jmp_next[n1] = NULL;
585 tb1 = tb2;
586 }
587 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
588
bellarde3db7222005-01-26 22:00:47 +0000589 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000590}
591
592static inline void set_bits(uint8_t *tab, int start, int len)
593{
594 int end, mask, end1;
595
596 end = start + len;
597 tab += start >> 3;
598 mask = 0xff << (start & 7);
599 if ((start & ~7) == (end & ~7)) {
600 if (start < end) {
601 mask &= ~(0xff << (end & 7));
602 *tab |= mask;
603 }
604 } else {
605 *tab++ |= mask;
606 start = (start + 8) & ~7;
607 end1 = end & ~7;
608 while (start < end1) {
609 *tab++ = 0xff;
610 start += 8;
611 }
612 if (start < end) {
613 mask = ~(0xff << (end & 7));
614 *tab |= mask;
615 }
616 }
617}
618
619static void build_page_bitmap(PageDesc *p)
620{
621 int n, tb_start, tb_end;
622 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000623
bellard59817cc2004-02-16 22:01:13 +0000624 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000625 if (!p->code_bitmap)
626 return;
627 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
628
629 tb = p->first_tb;
630 while (tb != NULL) {
631 n = (long)tb & 3;
632 tb = (TranslationBlock *)((long)tb & ~3);
633 /* NOTE: this is subtle as a TB may span two physical pages */
634 if (n == 0) {
635 /* NOTE: tb_end may be after the end of the page, but
636 it is not a problem */
637 tb_start = tb->pc & ~TARGET_PAGE_MASK;
638 tb_end = tb_start + tb->size;
639 if (tb_end > TARGET_PAGE_SIZE)
640 tb_end = TARGET_PAGE_SIZE;
641 } else {
642 tb_start = 0;
643 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
644 }
645 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
646 tb = tb->page_next[n];
647 }
648}
649
bellardd720b932004-04-25 17:57:43 +0000650#ifdef TARGET_HAS_PRECISE_SMC
651
ths5fafdf22007-09-16 21:08:06 +0000652static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000653 target_ulong pc, target_ulong cs_base, int flags,
654 int cflags)
655{
656 TranslationBlock *tb;
657 uint8_t *tc_ptr;
658 target_ulong phys_pc, phys_page2, virt_page2;
659 int code_gen_size;
660
bellardc27004e2005-01-03 23:35:10 +0000661 phys_pc = get_phys_addr_code(env, pc);
662 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000663 if (!tb) {
664 /* flush must be done */
665 tb_flush(env);
666 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000667 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000668 }
669 tc_ptr = code_gen_ptr;
670 tb->tc_ptr = tc_ptr;
671 tb->cs_base = cs_base;
672 tb->flags = flags;
673 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000674 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000675 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 +0000676
bellardd720b932004-04-25 17:57:43 +0000677 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000678 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000679 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000680 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000681 phys_page2 = get_phys_addr_code(env, virt_page2);
682 }
683 tb_link_phys(tb, phys_pc, phys_page2);
684}
685#endif
ths3b46e622007-09-17 08:09:54 +0000686
bellard9fa3e852004-01-04 18:06:42 +0000687/* invalidate all TBs which intersect with the target physical page
688 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000689 the same physical page. 'is_cpu_write_access' should be true if called
690 from a real cpu write access: the virtual CPU will exit the current
691 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000692void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000693 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000694{
bellardd720b932004-04-25 17:57:43 +0000695 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000696 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000697 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000698 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000699 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000700 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000701
702 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000703 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000704 return;
ths5fafdf22007-09-16 21:08:06 +0000705 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000706 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
707 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000708 /* build code bitmap */
709 build_page_bitmap(p);
710 }
711
712 /* we remove all the TBs in the range [start, end[ */
713 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000714 current_tb_not_found = is_cpu_write_access;
715 current_tb_modified = 0;
716 current_tb = NULL; /* avoid warning */
717 current_pc = 0; /* avoid warning */
718 current_cs_base = 0; /* avoid warning */
719 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000720 tb = p->first_tb;
721 while (tb != NULL) {
722 n = (long)tb & 3;
723 tb = (TranslationBlock *)((long)tb & ~3);
724 tb_next = tb->page_next[n];
725 /* NOTE: this is subtle as a TB may span two physical pages */
726 if (n == 0) {
727 /* NOTE: tb_end may be after the end of the page, but
728 it is not a problem */
729 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
730 tb_end = tb_start + tb->size;
731 } else {
732 tb_start = tb->page_addr[1];
733 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
734 }
735 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000736#ifdef TARGET_HAS_PRECISE_SMC
737 if (current_tb_not_found) {
738 current_tb_not_found = 0;
739 current_tb = NULL;
740 if (env->mem_write_pc) {
741 /* now we have a real cpu fault */
742 current_tb = tb_find_pc(env->mem_write_pc);
743 }
744 }
745 if (current_tb == tb &&
746 !(current_tb->cflags & CF_SINGLE_INSN)) {
747 /* If we are modifying the current TB, we must stop
748 its execution. We could be more precise by checking
749 that the modification is after the current PC, but it
750 would require a specialized function to partially
751 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000752
bellardd720b932004-04-25 17:57:43 +0000753 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000754 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000755 env->mem_write_pc, NULL);
756#if defined(TARGET_I386)
757 current_flags = env->hflags;
758 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
759 current_cs_base = (target_ulong)env->segs[R_CS].base;
760 current_pc = current_cs_base + env->eip;
761#else
762#error unsupported CPU
763#endif
764 }
765#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000766 /* we need to do that to handle the case where a signal
767 occurs while doing tb_phys_invalidate() */
768 saved_tb = NULL;
769 if (env) {
770 saved_tb = env->current_tb;
771 env->current_tb = NULL;
772 }
bellard9fa3e852004-01-04 18:06:42 +0000773 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000774 if (env) {
775 env->current_tb = saved_tb;
776 if (env->interrupt_request && env->current_tb)
777 cpu_interrupt(env, env->interrupt_request);
778 }
bellard9fa3e852004-01-04 18:06:42 +0000779 }
780 tb = tb_next;
781 }
782#if !defined(CONFIG_USER_ONLY)
783 /* if no code remaining, no need to continue to use slow writes */
784 if (!p->first_tb) {
785 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000786 if (is_cpu_write_access) {
787 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
788 }
789 }
790#endif
791#ifdef TARGET_HAS_PRECISE_SMC
792 if (current_tb_modified) {
793 /* we generate a block containing just the instruction
794 modifying the memory. It will ensure that it cannot modify
795 itself */
bellardea1c1802004-06-14 18:56:36 +0000796 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000797 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000798 CF_SINGLE_INSN);
799 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000800 }
801#endif
802}
803
804/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000805static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000806{
807 PageDesc *p;
808 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000809#if 0
bellarda4193c82004-06-03 14:01:43 +0000810 if (1) {
811 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000812 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
813 cpu_single_env->mem_write_vaddr, len,
814 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000815 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
816 }
bellard59817cc2004-02-16 22:01:13 +0000817 }
818#endif
bellard9fa3e852004-01-04 18:06:42 +0000819 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000820 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000821 return;
822 if (p->code_bitmap) {
823 offset = start & ~TARGET_PAGE_MASK;
824 b = p->code_bitmap[offset >> 3] >> (offset & 7);
825 if (b & ((1 << len) - 1))
826 goto do_invalidate;
827 } else {
828 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000829 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000830 }
831}
832
bellard9fa3e852004-01-04 18:06:42 +0000833#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000834static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000835 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000836{
bellardd720b932004-04-25 17:57:43 +0000837 int n, current_flags, current_tb_modified;
838 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000839 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000840 TranslationBlock *tb, *current_tb;
841#ifdef TARGET_HAS_PRECISE_SMC
842 CPUState *env = cpu_single_env;
843#endif
bellard9fa3e852004-01-04 18:06:42 +0000844
845 addr &= TARGET_PAGE_MASK;
846 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000847 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000848 return;
849 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000850 current_tb_modified = 0;
851 current_tb = NULL;
852 current_pc = 0; /* avoid warning */
853 current_cs_base = 0; /* avoid warning */
854 current_flags = 0; /* avoid warning */
855#ifdef TARGET_HAS_PRECISE_SMC
856 if (tb && pc != 0) {
857 current_tb = tb_find_pc(pc);
858 }
859#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000860 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000861 n = (long)tb & 3;
862 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000863#ifdef TARGET_HAS_PRECISE_SMC
864 if (current_tb == tb &&
865 !(current_tb->cflags & CF_SINGLE_INSN)) {
866 /* If we are modifying the current TB, we must stop
867 its execution. We could be more precise by checking
868 that the modification is after the current PC, but it
869 would require a specialized function to partially
870 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000871
bellardd720b932004-04-25 17:57:43 +0000872 current_tb_modified = 1;
873 cpu_restore_state(current_tb, env, pc, puc);
874#if defined(TARGET_I386)
875 current_flags = env->hflags;
876 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
877 current_cs_base = (target_ulong)env->segs[R_CS].base;
878 current_pc = current_cs_base + env->eip;
879#else
880#error unsupported CPU
881#endif
882 }
883#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000884 tb_phys_invalidate(tb, addr);
885 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000886 }
887 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000888#ifdef TARGET_HAS_PRECISE_SMC
889 if (current_tb_modified) {
890 /* we generate a block containing just the instruction
891 modifying the memory. It will ensure that it cannot modify
892 itself */
bellardea1c1802004-06-14 18:56:36 +0000893 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000894 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000895 CF_SINGLE_INSN);
896 cpu_resume_from_signal(env, puc);
897 }
898#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000899}
bellard9fa3e852004-01-04 18:06:42 +0000900#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000901
902/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000903static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000904 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000905{
906 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000907 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000908
bellard9fa3e852004-01-04 18:06:42 +0000909 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000910 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000911 tb->page_next[n] = p->first_tb;
912 last_first_tb = p->first_tb;
913 p->first_tb = (TranslationBlock *)((long)tb | n);
914 invalidate_page_bitmap(p);
915
bellard107db442004-06-22 18:48:46 +0000916#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000917
bellard9fa3e852004-01-04 18:06:42 +0000918#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000919 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000920 target_ulong addr;
921 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000922 int prot;
923
bellardfd6ce8f2003-05-14 19:00:11 +0000924 /* force the host page as non writable (writes will have a
925 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000926 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000927 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000928 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
929 addr += TARGET_PAGE_SIZE) {
930
931 p2 = page_find (addr >> TARGET_PAGE_BITS);
932 if (!p2)
933 continue;
934 prot |= p2->flags;
935 p2->flags &= ~PAGE_WRITE;
936 page_get_flags(addr);
937 }
ths5fafdf22007-09-16 21:08:06 +0000938 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000939 (prot & PAGE_BITS) & ~PAGE_WRITE);
940#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +0000941 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +0000942 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000943#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000944 }
bellard9fa3e852004-01-04 18:06:42 +0000945#else
946 /* if some code is already present, then the pages are already
947 protected. So we handle the case where only the first TB is
948 allocated in a physical page */
949 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000950 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000951 }
952#endif
bellardd720b932004-04-25 17:57:43 +0000953
954#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000955}
956
957/* Allocate a new translation block. Flush the translation buffer if
958 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000959TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000960{
961 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000962
ths5fafdf22007-09-16 21:08:06 +0000963 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
bellardfd6ce8f2003-05-14 19:00:11 +0000964 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000965 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000966 tb = &tbs[nb_tbs++];
967 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000968 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000969 return tb;
970}
971
bellard9fa3e852004-01-04 18:06:42 +0000972/* add a new TB and link it to the physical page tables. phys_page2 is
973 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +0000974void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +0000975 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000976{
bellard9fa3e852004-01-04 18:06:42 +0000977 unsigned int h;
978 TranslationBlock **ptb;
979
980 /* add in the physical hash table */
981 h = tb_phys_hash_func(phys_pc);
982 ptb = &tb_phys_hash[h];
983 tb->phys_hash_next = *ptb;
984 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000985
986 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000987 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
988 if (phys_page2 != -1)
989 tb_alloc_page(tb, 1, phys_page2);
990 else
991 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000992
bellardd4e81642003-05-25 16:46:15 +0000993 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
994 tb->jmp_next[0] = NULL;
995 tb->jmp_next[1] = NULL;
996
997 /* init original jump addresses */
998 if (tb->tb_next_offset[0] != 0xffff)
999 tb_reset_jump(tb, 0);
1000 if (tb->tb_next_offset[1] != 0xffff)
1001 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001002
1003#ifdef DEBUG_TB_CHECK
1004 tb_page_check();
1005#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001006}
1007
bellarda513fe12003-05-27 23:29:48 +00001008/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1009 tb[1].tc_ptr. Return NULL if not found */
1010TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1011{
1012 int m_min, m_max, m;
1013 unsigned long v;
1014 TranslationBlock *tb;
1015
1016 if (nb_tbs <= 0)
1017 return NULL;
1018 if (tc_ptr < (unsigned long)code_gen_buffer ||
1019 tc_ptr >= (unsigned long)code_gen_ptr)
1020 return NULL;
1021 /* binary search (cf Knuth) */
1022 m_min = 0;
1023 m_max = nb_tbs - 1;
1024 while (m_min <= m_max) {
1025 m = (m_min + m_max) >> 1;
1026 tb = &tbs[m];
1027 v = (unsigned long)tb->tc_ptr;
1028 if (v == tc_ptr)
1029 return tb;
1030 else if (tc_ptr < v) {
1031 m_max = m - 1;
1032 } else {
1033 m_min = m + 1;
1034 }
ths5fafdf22007-09-16 21:08:06 +00001035 }
bellarda513fe12003-05-27 23:29:48 +00001036 return &tbs[m_max];
1037}
bellard75012672003-06-21 13:11:07 +00001038
bellardea041c02003-06-25 16:16:50 +00001039static void tb_reset_jump_recursive(TranslationBlock *tb);
1040
1041static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1042{
1043 TranslationBlock *tb1, *tb_next, **ptb;
1044 unsigned int n1;
1045
1046 tb1 = tb->jmp_next[n];
1047 if (tb1 != NULL) {
1048 /* find head of list */
1049 for(;;) {
1050 n1 = (long)tb1 & 3;
1051 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1052 if (n1 == 2)
1053 break;
1054 tb1 = tb1->jmp_next[n1];
1055 }
1056 /* we are now sure now that tb jumps to tb1 */
1057 tb_next = tb1;
1058
1059 /* remove tb from the jmp_first list */
1060 ptb = &tb_next->jmp_first;
1061 for(;;) {
1062 tb1 = *ptb;
1063 n1 = (long)tb1 & 3;
1064 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1065 if (n1 == n && tb1 == tb)
1066 break;
1067 ptb = &tb1->jmp_next[n1];
1068 }
1069 *ptb = tb->jmp_next[n];
1070 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001071
bellardea041c02003-06-25 16:16:50 +00001072 /* suppress the jump to next tb in generated code */
1073 tb_reset_jump(tb, n);
1074
bellard01243112004-01-04 15:48:17 +00001075 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001076 tb_reset_jump_recursive(tb_next);
1077 }
1078}
1079
1080static void tb_reset_jump_recursive(TranslationBlock *tb)
1081{
1082 tb_reset_jump_recursive2(tb, 0);
1083 tb_reset_jump_recursive2(tb, 1);
1084}
1085
bellard1fddef42005-04-17 19:16:13 +00001086#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001087static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1088{
j_mayer9b3c35e2007-04-07 11:21:28 +00001089 target_phys_addr_t addr;
1090 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001091 ram_addr_t ram_addr;
1092 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001093
pbrookc2f07f82006-04-08 17:14:56 +00001094 addr = cpu_get_phys_page_debug(env, pc);
1095 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1096 if (!p) {
1097 pd = IO_MEM_UNASSIGNED;
1098 } else {
1099 pd = p->phys_offset;
1100 }
1101 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001102 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001103}
bellardc27004e2005-01-03 23:35:10 +00001104#endif
bellardd720b932004-04-25 17:57:43 +00001105
pbrook6658ffb2007-03-16 23:58:11 +00001106/* Add a watchpoint. */
1107int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1108{
1109 int i;
1110
1111 for (i = 0; i < env->nb_watchpoints; i++) {
1112 if (addr == env->watchpoint[i].vaddr)
1113 return 0;
1114 }
1115 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1116 return -1;
1117
1118 i = env->nb_watchpoints++;
1119 env->watchpoint[i].vaddr = addr;
1120 tlb_flush_page(env, addr);
1121 /* FIXME: This flush is needed because of the hack to make memory ops
1122 terminate the TB. It can be removed once the proper IO trap and
1123 re-execute bits are in. */
1124 tb_flush(env);
1125 return i;
1126}
1127
1128/* Remove a watchpoint. */
1129int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1130{
1131 int i;
1132
1133 for (i = 0; i < env->nb_watchpoints; i++) {
1134 if (addr == env->watchpoint[i].vaddr) {
1135 env->nb_watchpoints--;
1136 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1137 tlb_flush_page(env, addr);
1138 return 0;
1139 }
1140 }
1141 return -1;
1142}
1143
edgar_igl7d03f822008-05-17 18:58:29 +00001144/* Remove all watchpoints. */
1145void cpu_watchpoint_remove_all(CPUState *env) {
1146 int i;
1147
1148 for (i = 0; i < env->nb_watchpoints; i++) {
1149 tlb_flush_page(env, env->watchpoint[i].vaddr);
1150 }
1151 env->nb_watchpoints = 0;
1152}
1153
bellardc33a3462003-07-29 20:50:33 +00001154/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1155 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001156int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001157{
bellard1fddef42005-04-17 19:16:13 +00001158#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001159 int i;
ths3b46e622007-09-17 08:09:54 +00001160
bellard4c3a88a2003-07-26 12:06:08 +00001161 for(i = 0; i < env->nb_breakpoints; i++) {
1162 if (env->breakpoints[i] == pc)
1163 return 0;
1164 }
1165
1166 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1167 return -1;
1168 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001169
bellardd720b932004-04-25 17:57:43 +00001170 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001171 return 0;
1172#else
1173 return -1;
1174#endif
1175}
1176
edgar_igl7d03f822008-05-17 18:58:29 +00001177/* remove all breakpoints */
1178void cpu_breakpoint_remove_all(CPUState *env) {
1179#if defined(TARGET_HAS_ICE)
1180 int i;
1181 for(i = 0; i < env->nb_breakpoints; i++) {
1182 breakpoint_invalidate(env, env->breakpoints[i]);
1183 }
1184 env->nb_breakpoints = 0;
1185#endif
1186}
1187
bellard4c3a88a2003-07-26 12:06:08 +00001188/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001189int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001190{
bellard1fddef42005-04-17 19:16:13 +00001191#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001192 int i;
1193 for(i = 0; i < env->nb_breakpoints; i++) {
1194 if (env->breakpoints[i] == pc)
1195 goto found;
1196 }
1197 return -1;
1198 found:
bellard4c3a88a2003-07-26 12:06:08 +00001199 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001200 if (i < env->nb_breakpoints)
1201 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001202
1203 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001204 return 0;
1205#else
1206 return -1;
1207#endif
1208}
1209
bellardc33a3462003-07-29 20:50:33 +00001210/* enable or disable single step mode. EXCP_DEBUG is returned by the
1211 CPU loop after each instruction */
1212void cpu_single_step(CPUState *env, int enabled)
1213{
bellard1fddef42005-04-17 19:16:13 +00001214#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001215 if (env->singlestep_enabled != enabled) {
1216 env->singlestep_enabled = enabled;
1217 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001218 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001219 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001220 }
1221#endif
1222}
1223
bellard34865132003-10-05 14:28:56 +00001224/* enable or disable low levels log */
1225void cpu_set_log(int log_flags)
1226{
1227 loglevel = log_flags;
1228 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001229 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001230 if (!logfile) {
1231 perror(logfilename);
1232 _exit(1);
1233 }
bellard9fa3e852004-01-04 18:06:42 +00001234#if !defined(CONFIG_SOFTMMU)
1235 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1236 {
1237 static uint8_t logfile_buf[4096];
1238 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1239 }
1240#else
bellard34865132003-10-05 14:28:56 +00001241 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001242#endif
pbrooke735b912007-06-30 13:53:24 +00001243 log_append = 1;
1244 }
1245 if (!loglevel && logfile) {
1246 fclose(logfile);
1247 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001248 }
1249}
1250
1251void cpu_set_log_filename(const char *filename)
1252{
1253 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001254 if (logfile) {
1255 fclose(logfile);
1256 logfile = NULL;
1257 }
1258 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001259}
bellardc33a3462003-07-29 20:50:33 +00001260
bellard01243112004-01-04 15:48:17 +00001261/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001262void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001263{
1264 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001265 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
bellard59817cc2004-02-16 22:01:13 +00001266
bellard68a79312003-06-30 13:12:32 +00001267 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001268 /* if the cpu is currently executing code, we must unlink it and
1269 all the potentially executing TB */
1270 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001271 if (tb && !testandset(&interrupt_lock)) {
1272 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001273 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001274 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001275 }
1276}
1277
bellardb54ad042004-05-20 13:42:52 +00001278void cpu_reset_interrupt(CPUState *env, int mask)
1279{
1280 env->interrupt_request &= ~mask;
1281}
1282
bellardf193c792004-03-21 17:06:25 +00001283CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001284 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001285 "show generated host assembly code for each compiled TB" },
1286 { CPU_LOG_TB_IN_ASM, "in_asm",
1287 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001288 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001289 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001290 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001291 "show micro ops "
1292#ifdef TARGET_I386
1293 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001294#endif
blueswir1e01a1152008-03-14 17:37:11 +00001295 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001296 { CPU_LOG_INT, "int",
1297 "show interrupts/exceptions in short format" },
1298 { CPU_LOG_EXEC, "exec",
1299 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001300 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001301 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001302#ifdef TARGET_I386
1303 { CPU_LOG_PCALL, "pcall",
1304 "show protected mode far calls/returns/exceptions" },
1305#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001306#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001307 { CPU_LOG_IOPORT, "ioport",
1308 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001309#endif
bellardf193c792004-03-21 17:06:25 +00001310 { 0, NULL, NULL },
1311};
1312
1313static int cmp1(const char *s1, int n, const char *s2)
1314{
1315 if (strlen(s2) != n)
1316 return 0;
1317 return memcmp(s1, s2, n) == 0;
1318}
ths3b46e622007-09-17 08:09:54 +00001319
bellardf193c792004-03-21 17:06:25 +00001320/* takes a comma separated list of log masks. Return 0 if error. */
1321int cpu_str_to_log_mask(const char *str)
1322{
1323 CPULogItem *item;
1324 int mask;
1325 const char *p, *p1;
1326
1327 p = str;
1328 mask = 0;
1329 for(;;) {
1330 p1 = strchr(p, ',');
1331 if (!p1)
1332 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001333 if(cmp1(p,p1-p,"all")) {
1334 for(item = cpu_log_items; item->mask != 0; item++) {
1335 mask |= item->mask;
1336 }
1337 } else {
bellardf193c792004-03-21 17:06:25 +00001338 for(item = cpu_log_items; item->mask != 0; item++) {
1339 if (cmp1(p, p1 - p, item->name))
1340 goto found;
1341 }
1342 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001343 }
bellardf193c792004-03-21 17:06:25 +00001344 found:
1345 mask |= item->mask;
1346 if (*p1 != ',')
1347 break;
1348 p = p1 + 1;
1349 }
1350 return mask;
1351}
bellardea041c02003-06-25 16:16:50 +00001352
bellard75012672003-06-21 13:11:07 +00001353void cpu_abort(CPUState *env, const char *fmt, ...)
1354{
1355 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001356 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001357
1358 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001359 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001360 fprintf(stderr, "qemu: fatal: ");
1361 vfprintf(stderr, fmt, ap);
1362 fprintf(stderr, "\n");
1363#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001364 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1365#else
1366 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001367#endif
balrog924edca2007-06-10 14:07:13 +00001368 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001369 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001370 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001371 fprintf(logfile, "\n");
1372#ifdef TARGET_I386
1373 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1374#else
1375 cpu_dump_state(env, logfile, fprintf, 0);
1376#endif
balrog924edca2007-06-10 14:07:13 +00001377 fflush(logfile);
1378 fclose(logfile);
1379 }
pbrook493ae1f2007-11-23 16:53:59 +00001380 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001381 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001382 abort();
1383}
1384
thsc5be9f02007-02-28 20:20:53 +00001385CPUState *cpu_copy(CPUState *env)
1386{
ths01ba9812007-12-09 02:22:57 +00001387 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001388 /* preserve chaining and index */
1389 CPUState *next_cpu = new_env->next_cpu;
1390 int cpu_index = new_env->cpu_index;
1391 memcpy(new_env, env, sizeof(CPUState));
1392 new_env->next_cpu = next_cpu;
1393 new_env->cpu_index = cpu_index;
1394 return new_env;
1395}
1396
bellard01243112004-01-04 15:48:17 +00001397#if !defined(CONFIG_USER_ONLY)
1398
edgar_igl5c751e92008-05-06 08:44:21 +00001399static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1400{
1401 unsigned int i;
1402
1403 /* Discard jump cache entries for any tb which might potentially
1404 overlap the flushed page. */
1405 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1406 memset (&env->tb_jmp_cache[i], 0,
1407 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1408
1409 i = tb_jmp_cache_hash_page(addr);
1410 memset (&env->tb_jmp_cache[i], 0,
1411 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1412}
1413
bellardee8b7022004-02-03 23:35:10 +00001414/* NOTE: if flush_global is true, also flush global entries (not
1415 implemented yet) */
1416void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001417{
bellard33417e72003-08-10 21:47:01 +00001418 int i;
bellard01243112004-01-04 15:48:17 +00001419
bellard9fa3e852004-01-04 18:06:42 +00001420#if defined(DEBUG_TLB)
1421 printf("tlb_flush:\n");
1422#endif
bellard01243112004-01-04 15:48:17 +00001423 /* must reset current TB so that interrupts cannot modify the
1424 links while we are modifying them */
1425 env->current_tb = NULL;
1426
bellard33417e72003-08-10 21:47:01 +00001427 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001428 env->tlb_table[0][i].addr_read = -1;
1429 env->tlb_table[0][i].addr_write = -1;
1430 env->tlb_table[0][i].addr_code = -1;
1431 env->tlb_table[1][i].addr_read = -1;
1432 env->tlb_table[1][i].addr_write = -1;
1433 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001434#if (NB_MMU_MODES >= 3)
1435 env->tlb_table[2][i].addr_read = -1;
1436 env->tlb_table[2][i].addr_write = -1;
1437 env->tlb_table[2][i].addr_code = -1;
1438#if (NB_MMU_MODES == 4)
1439 env->tlb_table[3][i].addr_read = -1;
1440 env->tlb_table[3][i].addr_write = -1;
1441 env->tlb_table[3][i].addr_code = -1;
1442#endif
1443#endif
bellard33417e72003-08-10 21:47:01 +00001444 }
bellard9fa3e852004-01-04 18:06:42 +00001445
bellard8a40a182005-11-20 10:35:40 +00001446 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001447
1448#if !defined(CONFIG_SOFTMMU)
1449 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1450#endif
bellard0a962c02005-02-10 22:00:27 +00001451#ifdef USE_KQEMU
1452 if (env->kqemu_enabled) {
1453 kqemu_flush(env, flush_global);
1454 }
1455#endif
bellarde3db7222005-01-26 22:00:47 +00001456 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001457}
1458
bellard274da6b2004-05-20 21:56:27 +00001459static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001460{
ths5fafdf22007-09-16 21:08:06 +00001461 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001462 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001463 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001464 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001465 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001466 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1467 tlb_entry->addr_read = -1;
1468 tlb_entry->addr_write = -1;
1469 tlb_entry->addr_code = -1;
1470 }
bellard61382a52003-10-27 21:22:23 +00001471}
1472
bellard2e126692004-04-25 21:28:44 +00001473void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001474{
bellard8a40a182005-11-20 10:35:40 +00001475 int i;
bellard01243112004-01-04 15:48:17 +00001476
bellard9fa3e852004-01-04 18:06:42 +00001477#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001478 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001479#endif
bellard01243112004-01-04 15:48:17 +00001480 /* must reset current TB so that interrupts cannot modify the
1481 links while we are modifying them */
1482 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001483
bellard61382a52003-10-27 21:22:23 +00001484 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001485 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001486 tlb_flush_entry(&env->tlb_table[0][i], addr);
1487 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001488#if (NB_MMU_MODES >= 3)
1489 tlb_flush_entry(&env->tlb_table[2][i], addr);
1490#if (NB_MMU_MODES == 4)
1491 tlb_flush_entry(&env->tlb_table[3][i], addr);
1492#endif
1493#endif
bellard01243112004-01-04 15:48:17 +00001494
edgar_igl5c751e92008-05-06 08:44:21 +00001495 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001496
bellard01243112004-01-04 15:48:17 +00001497#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001498 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001499 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001500#endif
bellard0a962c02005-02-10 22:00:27 +00001501#ifdef USE_KQEMU
1502 if (env->kqemu_enabled) {
1503 kqemu_flush_page(env, addr);
1504 }
1505#endif
bellard9fa3e852004-01-04 18:06:42 +00001506}
1507
bellard9fa3e852004-01-04 18:06:42 +00001508/* update the TLBs so that writes to code in the virtual page 'addr'
1509 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001510static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001511{
ths5fafdf22007-09-16 21:08:06 +00001512 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001513 ram_addr + TARGET_PAGE_SIZE,
1514 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001515}
1516
bellard9fa3e852004-01-04 18:06:42 +00001517/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001518 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001519static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001520 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001521{
bellard3a7d9292005-08-21 09:26:42 +00001522 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001523}
1524
ths5fafdf22007-09-16 21:08:06 +00001525static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001526 unsigned long start, unsigned long length)
1527{
1528 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001529 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1530 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001531 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001532 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001533 }
1534 }
1535}
1536
bellard3a7d9292005-08-21 09:26:42 +00001537void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001538 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001539{
1540 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001541 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001542 int i, mask, len;
1543 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001544
1545 start &= TARGET_PAGE_MASK;
1546 end = TARGET_PAGE_ALIGN(end);
1547
1548 length = end - start;
1549 if (length == 0)
1550 return;
bellard0a962c02005-02-10 22:00:27 +00001551 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001552#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001553 /* XXX: should not depend on cpu context */
1554 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001555 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001556 ram_addr_t addr;
1557 addr = start;
1558 for(i = 0; i < len; i++) {
1559 kqemu_set_notdirty(env, addr);
1560 addr += TARGET_PAGE_SIZE;
1561 }
bellard3a7d9292005-08-21 09:26:42 +00001562 }
1563#endif
bellardf23db162005-08-21 19:12:28 +00001564 mask = ~dirty_flags;
1565 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1566 for(i = 0; i < len; i++)
1567 p[i] &= mask;
1568
bellard1ccde1c2004-02-06 19:46:14 +00001569 /* we modify the TLB cache so that the dirty bit will be set again
1570 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001571 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001572 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1573 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001574 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001575 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001576 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001577#if (NB_MMU_MODES >= 3)
1578 for(i = 0; i < CPU_TLB_SIZE; i++)
1579 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1580#if (NB_MMU_MODES == 4)
1581 for(i = 0; i < CPU_TLB_SIZE; i++)
1582 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1583#endif
1584#endif
bellard6a00d602005-11-21 23:25:50 +00001585 }
bellard59817cc2004-02-16 22:01:13 +00001586
1587#if !defined(CONFIG_SOFTMMU)
1588 /* XXX: this is expensive */
1589 {
1590 VirtPageDesc *p;
1591 int j;
1592 target_ulong addr;
1593
1594 for(i = 0; i < L1_SIZE; i++) {
1595 p = l1_virt_map[i];
1596 if (p) {
1597 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1598 for(j = 0; j < L2_SIZE; j++) {
1599 if (p->valid_tag == virt_valid_tag &&
1600 p->phys_addr >= start && p->phys_addr < end &&
1601 (p->prot & PROT_WRITE)) {
1602 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001603 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001604 p->prot & ~PROT_WRITE);
1605 }
1606 }
1607 addr += TARGET_PAGE_SIZE;
1608 p++;
1609 }
1610 }
1611 }
1612 }
1613#endif
bellard1ccde1c2004-02-06 19:46:14 +00001614}
1615
bellard3a7d9292005-08-21 09:26:42 +00001616static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1617{
1618 ram_addr_t ram_addr;
1619
bellard84b7b8e2005-11-28 21:19:04 +00001620 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001621 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001622 tlb_entry->addend - (unsigned long)phys_ram_base;
1623 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001624 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001625 }
1626 }
1627}
1628
1629/* update the TLB according to the current state of the dirty bits */
1630void cpu_tlb_update_dirty(CPUState *env)
1631{
1632 int i;
1633 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001634 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001635 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001636 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001637#if (NB_MMU_MODES >= 3)
1638 for(i = 0; i < CPU_TLB_SIZE; i++)
1639 tlb_update_dirty(&env->tlb_table[2][i]);
1640#if (NB_MMU_MODES == 4)
1641 for(i = 0; i < CPU_TLB_SIZE; i++)
1642 tlb_update_dirty(&env->tlb_table[3][i]);
1643#endif
1644#endif
bellard3a7d9292005-08-21 09:26:42 +00001645}
1646
ths5fafdf22007-09-16 21:08:06 +00001647static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001648 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001649{
1650 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001651 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1652 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001653 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001654 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001655 }
1656 }
1657}
1658
1659/* update the TLB corresponding to virtual page vaddr and phys addr
1660 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001661static inline void tlb_set_dirty(CPUState *env,
1662 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001663{
bellard1ccde1c2004-02-06 19:46:14 +00001664 int i;
1665
bellard1ccde1c2004-02-06 19:46:14 +00001666 addr &= TARGET_PAGE_MASK;
1667 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001668 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1669 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001670#if (NB_MMU_MODES >= 3)
1671 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1672#if (NB_MMU_MODES == 4)
1673 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1674#endif
1675#endif
bellard9fa3e852004-01-04 18:06:42 +00001676}
1677
bellard59817cc2004-02-16 22:01:13 +00001678/* add a new TLB entry. At most one entry for a given virtual address
1679 is permitted. Return 0 if OK or 2 if the page could not be mapped
1680 (can only happen in non SOFTMMU mode for I/O pages or pages
1681 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001682int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1683 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001684 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001685{
bellard92e873b2004-05-21 14:52:29 +00001686 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001687 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001688 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001689 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001690 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001691 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001692 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001693 int i;
bellard9fa3e852004-01-04 18:06:42 +00001694
bellard92e873b2004-05-21 14:52:29 +00001695 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001696 if (!p) {
1697 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001698 } else {
1699 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001700 }
1701#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001702 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1703 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001704#endif
1705
1706 ret = 0;
1707#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001708 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001709#endif
1710 {
bellard2a4188a2006-06-25 21:54:59 +00001711 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001712 /* IO memory case */
1713 address = vaddr | pd;
1714 addend = paddr;
1715 } else {
1716 /* standard memory */
1717 address = vaddr;
1718 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1719 }
pbrook6658ffb2007-03-16 23:58:11 +00001720
1721 /* Make accesses to pages with watchpoints go via the
1722 watchpoint trap routines. */
1723 for (i = 0; i < env->nb_watchpoints; i++) {
1724 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1725 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001726 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001727 address = vaddr | io_mem_watch;
1728 } else {
balrogd79acba2007-06-26 20:01:13 +00001729 env->watchpoint[i].addend = pd - paddr +
1730 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001731 /* TODO: Figure out how to make read watchpoints coexist
1732 with code. */
1733 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1734 }
1735 }
1736 }
balrogd79acba2007-06-26 20:01:13 +00001737
bellard90f18422005-07-24 10:17:31 +00001738 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001739 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001740 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001741 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001742 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001743 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001744 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001745 te->addr_read = -1;
1746 }
edgar_igl5c751e92008-05-06 08:44:21 +00001747
1748 if (te->addr_code != -1) {
1749 tlb_flush_jmp_cache(env, te->addr_code);
1750 }
bellard84b7b8e2005-11-28 21:19:04 +00001751 if (prot & PAGE_EXEC) {
1752 te->addr_code = address;
1753 } else {
1754 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001755 }
bellard67b915a2004-03-31 23:37:16 +00001756 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001757 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001758 (pd & IO_MEM_ROMD)) {
1759 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001760 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001761 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001762 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001763 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001764 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001765 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001766 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001767 }
1768 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001769 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001770 }
1771 }
1772#if !defined(CONFIG_SOFTMMU)
1773 else {
1774 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1775 /* IO access: no mapping is done as it will be handled by the
1776 soft MMU */
1777 if (!(env->hflags & HF_SOFTMMU_MASK))
1778 ret = 2;
1779 } else {
1780 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001781
bellard59817cc2004-02-16 22:01:13 +00001782 if (vaddr >= MMAP_AREA_END) {
1783 ret = 2;
1784 } else {
1785 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001786 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001787#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001788 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001789#endif
ths5fafdf22007-09-16 21:08:06 +00001790 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001791 !cpu_physical_memory_is_dirty(pd))) {
1792 /* ROM: we do as if code was inside */
1793 /* if code is present, we only map as read only and save the
1794 original mapping */
1795 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001796
bellard90f18422005-07-24 10:17:31 +00001797 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001798 vp->phys_addr = pd;
1799 vp->prot = prot;
1800 vp->valid_tag = virt_valid_tag;
1801 prot &= ~PAGE_WRITE;
1802 }
bellard9fa3e852004-01-04 18:06:42 +00001803 }
ths5fafdf22007-09-16 21:08:06 +00001804 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001805 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1806 if (map_addr == MAP_FAILED) {
1807 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1808 paddr, vaddr);
1809 }
bellard9fa3e852004-01-04 18:06:42 +00001810 }
1811 }
1812 }
1813#endif
1814 return ret;
1815}
1816
1817/* called from signal handler: invalidate the code and unprotect the
1818 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001819int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001820{
1821#if !defined(CONFIG_SOFTMMU)
1822 VirtPageDesc *vp;
1823
1824#if defined(DEBUG_TLB)
1825 printf("page_unprotect: addr=0x%08x\n", addr);
1826#endif
1827 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001828
1829 /* if it is not mapped, no need to worry here */
1830 if (addr >= MMAP_AREA_END)
1831 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001832 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1833 if (!vp)
1834 return 0;
1835 /* NOTE: in this case, validate_tag is _not_ tested as it
1836 validates only the code TLB */
1837 if (vp->valid_tag != virt_valid_tag)
1838 return 0;
1839 if (!(vp->prot & PAGE_WRITE))
1840 return 0;
1841#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001842 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001843 addr, vp->phys_addr, vp->prot);
1844#endif
bellard59817cc2004-02-16 22:01:13 +00001845 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1846 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1847 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001848 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001849 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001850 /* flush the code inside */
1851 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001852 return 1;
1853#else
1854 return 0;
1855#endif
bellard33417e72003-08-10 21:47:01 +00001856}
1857
bellard01243112004-01-04 15:48:17 +00001858#else
1859
bellardee8b7022004-02-03 23:35:10 +00001860void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001861{
1862}
1863
bellard2e126692004-04-25 21:28:44 +00001864void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001865{
1866}
1867
ths5fafdf22007-09-16 21:08:06 +00001868int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1869 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001870 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001871{
bellard9fa3e852004-01-04 18:06:42 +00001872 return 0;
1873}
bellard33417e72003-08-10 21:47:01 +00001874
bellard9fa3e852004-01-04 18:06:42 +00001875/* dump memory mappings */
1876void page_dump(FILE *f)
1877{
1878 unsigned long start, end;
1879 int i, j, prot, prot1;
1880 PageDesc *p;
1881
1882 fprintf(f, "%-8s %-8s %-8s %s\n",
1883 "start", "end", "size", "prot");
1884 start = -1;
1885 end = -1;
1886 prot = 0;
1887 for(i = 0; i <= L1_SIZE; i++) {
1888 if (i < L1_SIZE)
1889 p = l1_map[i];
1890 else
1891 p = NULL;
1892 for(j = 0;j < L2_SIZE; j++) {
1893 if (!p)
1894 prot1 = 0;
1895 else
1896 prot1 = p[j].flags;
1897 if (prot1 != prot) {
1898 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1899 if (start != -1) {
1900 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001901 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001902 prot & PAGE_READ ? 'r' : '-',
1903 prot & PAGE_WRITE ? 'w' : '-',
1904 prot & PAGE_EXEC ? 'x' : '-');
1905 }
1906 if (prot1 != 0)
1907 start = end;
1908 else
1909 start = -1;
1910 prot = prot1;
1911 }
1912 if (!p)
1913 break;
1914 }
bellard33417e72003-08-10 21:47:01 +00001915 }
bellard33417e72003-08-10 21:47:01 +00001916}
1917
pbrook53a59602006-03-25 19:31:22 +00001918int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001919{
bellard9fa3e852004-01-04 18:06:42 +00001920 PageDesc *p;
1921
1922 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001923 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001924 return 0;
1925 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001926}
1927
bellard9fa3e852004-01-04 18:06:42 +00001928/* modify the flags of a page and invalidate the code if
1929 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1930 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001931void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001932{
1933 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001934 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001935
1936 start = start & TARGET_PAGE_MASK;
1937 end = TARGET_PAGE_ALIGN(end);
1938 if (flags & PAGE_WRITE)
1939 flags |= PAGE_WRITE_ORG;
1940 spin_lock(&tb_lock);
1941 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1942 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1943 /* if the write protection is set, then we invalidate the code
1944 inside */
ths5fafdf22007-09-16 21:08:06 +00001945 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001946 (flags & PAGE_WRITE) &&
1947 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001948 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001949 }
1950 p->flags = flags;
1951 }
1952 spin_unlock(&tb_lock);
1953}
1954
ths3d97b402007-11-02 19:02:07 +00001955int page_check_range(target_ulong start, target_ulong len, int flags)
1956{
1957 PageDesc *p;
1958 target_ulong end;
1959 target_ulong addr;
1960
1961 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1962 start = start & TARGET_PAGE_MASK;
1963
1964 if( end < start )
1965 /* we've wrapped around */
1966 return -1;
1967 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1968 p = page_find(addr >> TARGET_PAGE_BITS);
1969 if( !p )
1970 return -1;
1971 if( !(p->flags & PAGE_VALID) )
1972 return -1;
1973
bellarddae32702007-11-14 10:51:00 +00001974 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001975 return -1;
bellarddae32702007-11-14 10:51:00 +00001976 if (flags & PAGE_WRITE) {
1977 if (!(p->flags & PAGE_WRITE_ORG))
1978 return -1;
1979 /* unprotect the page if it was put read-only because it
1980 contains translated code */
1981 if (!(p->flags & PAGE_WRITE)) {
1982 if (!page_unprotect(addr, 0, NULL))
1983 return -1;
1984 }
1985 return 0;
1986 }
ths3d97b402007-11-02 19:02:07 +00001987 }
1988 return 0;
1989}
1990
bellard9fa3e852004-01-04 18:06:42 +00001991/* called from signal handler: invalidate the code and unprotect the
1992 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001993int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001994{
1995 unsigned int page_index, prot, pindex;
1996 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001997 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001998
bellard83fb7ad2004-07-05 21:25:26 +00001999 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002000 page_index = host_start >> TARGET_PAGE_BITS;
2001 p1 = page_find(page_index);
2002 if (!p1)
2003 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00002004 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002005 p = p1;
2006 prot = 0;
2007 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2008 prot |= p->flags;
2009 p++;
2010 }
2011 /* if the page was really writable, then we change its
2012 protection back to writable */
2013 if (prot & PAGE_WRITE_ORG) {
2014 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2015 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002016 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002017 (prot & PAGE_BITS) | PAGE_WRITE);
2018 p1[pindex].flags |= PAGE_WRITE;
2019 /* and since the content will be modified, we must invalidate
2020 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002021 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002022#ifdef DEBUG_TB_CHECK
2023 tb_invalidate_check(address);
2024#endif
2025 return 1;
2026 }
2027 }
2028 return 0;
2029}
2030
bellard6a00d602005-11-21 23:25:50 +00002031static inline void tlb_set_dirty(CPUState *env,
2032 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002033{
2034}
bellard9fa3e852004-01-04 18:06:42 +00002035#endif /* defined(CONFIG_USER_ONLY) */
2036
blueswir1db7b5422007-05-26 17:36:03 +00002037static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002038 ram_addr_t memory);
2039static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2040 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002041#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2042 need_subpage) \
2043 do { \
2044 if (addr > start_addr) \
2045 start_addr2 = 0; \
2046 else { \
2047 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2048 if (start_addr2 > 0) \
2049 need_subpage = 1; \
2050 } \
2051 \
blueswir149e9fba2007-05-30 17:25:06 +00002052 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002053 end_addr2 = TARGET_PAGE_SIZE - 1; \
2054 else { \
2055 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2056 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2057 need_subpage = 1; \
2058 } \
2059 } while (0)
2060
bellard33417e72003-08-10 21:47:01 +00002061/* register physical memory. 'size' must be a multiple of the target
2062 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2063 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002064void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002065 ram_addr_t size,
2066 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002067{
bellard108c49b2005-07-24 12:55:09 +00002068 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002069 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002070 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002071 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002072 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002073
bellard5fd386f2004-05-23 21:11:22 +00002074 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002075 end_addr = start_addr + (target_phys_addr_t)size;
2076 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002077 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2078 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002079 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002080 target_phys_addr_t start_addr2, end_addr2;
2081 int need_subpage = 0;
2082
2083 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2084 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002085 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002086 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2087 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2088 &p->phys_offset, orig_memory);
2089 } else {
2090 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2091 >> IO_MEM_SHIFT];
2092 }
2093 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2094 } else {
2095 p->phys_offset = phys_offset;
2096 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2097 (phys_offset & IO_MEM_ROMD))
2098 phys_offset += TARGET_PAGE_SIZE;
2099 }
2100 } else {
2101 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2102 p->phys_offset = phys_offset;
2103 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2104 (phys_offset & IO_MEM_ROMD))
2105 phys_offset += TARGET_PAGE_SIZE;
2106 else {
2107 target_phys_addr_t start_addr2, end_addr2;
2108 int need_subpage = 0;
2109
2110 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2111 end_addr2, need_subpage);
2112
blueswir14254fab2008-01-01 16:57:19 +00002113 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002114 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2115 &p->phys_offset, IO_MEM_UNASSIGNED);
2116 subpage_register(subpage, start_addr2, end_addr2,
2117 phys_offset);
2118 }
2119 }
2120 }
bellard33417e72003-08-10 21:47:01 +00002121 }
ths3b46e622007-09-17 08:09:54 +00002122
bellard9d420372006-06-25 22:25:22 +00002123 /* since each CPU stores ram addresses in its TLB cache, we must
2124 reset the modified entries */
2125 /* XXX: slow ! */
2126 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2127 tlb_flush(env, 1);
2128 }
bellard33417e72003-08-10 21:47:01 +00002129}
2130
bellardba863452006-09-24 18:41:10 +00002131/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002132ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002133{
2134 PhysPageDesc *p;
2135
2136 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2137 if (!p)
2138 return IO_MEM_UNASSIGNED;
2139 return p->phys_offset;
2140}
2141
bellarde9a1ab12007-02-08 23:08:38 +00002142/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002143ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002144{
2145 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002146 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002147 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2148 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002149 abort();
2150 }
2151 addr = phys_ram_alloc_offset;
2152 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2153 return addr;
2154}
2155
2156void qemu_ram_free(ram_addr_t addr)
2157{
2158}
2159
bellarda4193c82004-06-03 14:01:43 +00002160static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002161{
pbrook67d3b952006-12-18 05:03:52 +00002162#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002163 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002164#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002165#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002166 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002167#elif TARGET_CRIS
2168 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002169#endif
bellard33417e72003-08-10 21:47:01 +00002170 return 0;
2171}
2172
bellarda4193c82004-06-03 14:01:43 +00002173static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002174{
pbrook67d3b952006-12-18 05:03:52 +00002175#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002176 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002177#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002178#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002179 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002180#elif TARGET_CRIS
2181 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002182#endif
bellard33417e72003-08-10 21:47:01 +00002183}
2184
2185static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2186 unassigned_mem_readb,
2187 unassigned_mem_readb,
2188 unassigned_mem_readb,
2189};
2190
2191static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2192 unassigned_mem_writeb,
2193 unassigned_mem_writeb,
2194 unassigned_mem_writeb,
2195};
2196
bellarda4193c82004-06-03 14:01:43 +00002197static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002198{
bellard3a7d9292005-08-21 09:26:42 +00002199 unsigned long ram_addr;
2200 int dirty_flags;
2201 ram_addr = addr - (unsigned long)phys_ram_base;
2202 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2203 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2204#if !defined(CONFIG_USER_ONLY)
2205 tb_invalidate_phys_page_fast(ram_addr, 1);
2206 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2207#endif
2208 }
bellardc27004e2005-01-03 23:35:10 +00002209 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002210#ifdef USE_KQEMU
2211 if (cpu_single_env->kqemu_enabled &&
2212 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2213 kqemu_modify_page(cpu_single_env, ram_addr);
2214#endif
bellardf23db162005-08-21 19:12:28 +00002215 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2216 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2217 /* we remove the notdirty callback only if the code has been
2218 flushed */
2219 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002220 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002221}
2222
bellarda4193c82004-06-03 14:01:43 +00002223static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002224{
bellard3a7d9292005-08-21 09:26:42 +00002225 unsigned long ram_addr;
2226 int dirty_flags;
2227 ram_addr = addr - (unsigned long)phys_ram_base;
2228 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2229 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2230#if !defined(CONFIG_USER_ONLY)
2231 tb_invalidate_phys_page_fast(ram_addr, 2);
2232 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2233#endif
2234 }
bellardc27004e2005-01-03 23:35:10 +00002235 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002236#ifdef USE_KQEMU
2237 if (cpu_single_env->kqemu_enabled &&
2238 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2239 kqemu_modify_page(cpu_single_env, ram_addr);
2240#endif
bellardf23db162005-08-21 19:12:28 +00002241 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2242 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2243 /* we remove the notdirty callback only if the code has been
2244 flushed */
2245 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002246 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002247}
2248
bellarda4193c82004-06-03 14:01:43 +00002249static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002250{
bellard3a7d9292005-08-21 09:26:42 +00002251 unsigned long ram_addr;
2252 int dirty_flags;
2253 ram_addr = addr - (unsigned long)phys_ram_base;
2254 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2255 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2256#if !defined(CONFIG_USER_ONLY)
2257 tb_invalidate_phys_page_fast(ram_addr, 4);
2258 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2259#endif
2260 }
bellardc27004e2005-01-03 23:35:10 +00002261 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002262#ifdef USE_KQEMU
2263 if (cpu_single_env->kqemu_enabled &&
2264 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2265 kqemu_modify_page(cpu_single_env, ram_addr);
2266#endif
bellardf23db162005-08-21 19:12:28 +00002267 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2268 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2269 /* we remove the notdirty callback only if the code has been
2270 flushed */
2271 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002272 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002273}
2274
bellard3a7d9292005-08-21 09:26:42 +00002275static CPUReadMemoryFunc *error_mem_read[3] = {
2276 NULL, /* never used */
2277 NULL, /* never used */
2278 NULL, /* never used */
2279};
2280
bellard1ccde1c2004-02-06 19:46:14 +00002281static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2282 notdirty_mem_writeb,
2283 notdirty_mem_writew,
2284 notdirty_mem_writel,
2285};
2286
pbrook6658ffb2007-03-16 23:58:11 +00002287#if defined(CONFIG_SOFTMMU)
2288/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2289 so these check for a hit then pass through to the normal out-of-line
2290 phys routines. */
2291static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2292{
2293 return ldub_phys(addr);
2294}
2295
2296static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2297{
2298 return lduw_phys(addr);
2299}
2300
2301static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2302{
2303 return ldl_phys(addr);
2304}
2305
2306/* Generate a debug exception if a watchpoint has been hit.
2307 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002308 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002309static target_ulong check_watchpoint(target_phys_addr_t addr)
2310{
2311 CPUState *env = cpu_single_env;
2312 target_ulong watch;
2313 target_ulong retaddr;
2314 int i;
2315
2316 retaddr = addr;
2317 for (i = 0; i < env->nb_watchpoints; i++) {
2318 watch = env->watchpoint[i].vaddr;
2319 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002320 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002321 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2322 cpu_single_env->watchpoint_hit = i + 1;
2323 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2324 break;
2325 }
2326 }
2327 }
2328 return retaddr;
2329}
2330
2331static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2332 uint32_t val)
2333{
2334 addr = check_watchpoint(addr);
2335 stb_phys(addr, val);
2336}
2337
2338static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2339 uint32_t val)
2340{
2341 addr = check_watchpoint(addr);
2342 stw_phys(addr, val);
2343}
2344
2345static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2346 uint32_t val)
2347{
2348 addr = check_watchpoint(addr);
2349 stl_phys(addr, val);
2350}
2351
2352static CPUReadMemoryFunc *watch_mem_read[3] = {
2353 watch_mem_readb,
2354 watch_mem_readw,
2355 watch_mem_readl,
2356};
2357
2358static CPUWriteMemoryFunc *watch_mem_write[3] = {
2359 watch_mem_writeb,
2360 watch_mem_writew,
2361 watch_mem_writel,
2362};
2363#endif
2364
blueswir1db7b5422007-05-26 17:36:03 +00002365static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2366 unsigned int len)
2367{
blueswir1db7b5422007-05-26 17:36:03 +00002368 uint32_t ret;
2369 unsigned int idx;
2370
2371 idx = SUBPAGE_IDX(addr - mmio->base);
2372#if defined(DEBUG_SUBPAGE)
2373 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2374 mmio, len, addr, idx);
2375#endif
blueswir13ee89922008-01-02 19:45:26 +00002376 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002377
2378 return ret;
2379}
2380
2381static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2382 uint32_t value, unsigned int len)
2383{
blueswir1db7b5422007-05-26 17:36:03 +00002384 unsigned int idx;
2385
2386 idx = SUBPAGE_IDX(addr - mmio->base);
2387#if defined(DEBUG_SUBPAGE)
2388 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2389 mmio, len, addr, idx, value);
2390#endif
blueswir13ee89922008-01-02 19:45:26 +00002391 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002392}
2393
2394static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2395{
2396#if defined(DEBUG_SUBPAGE)
2397 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2398#endif
2399
2400 return subpage_readlen(opaque, addr, 0);
2401}
2402
2403static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2404 uint32_t value)
2405{
2406#if defined(DEBUG_SUBPAGE)
2407 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2408#endif
2409 subpage_writelen(opaque, addr, value, 0);
2410}
2411
2412static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2413{
2414#if defined(DEBUG_SUBPAGE)
2415 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2416#endif
2417
2418 return subpage_readlen(opaque, addr, 1);
2419}
2420
2421static void subpage_writew (void *opaque, target_phys_addr_t addr,
2422 uint32_t value)
2423{
2424#if defined(DEBUG_SUBPAGE)
2425 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2426#endif
2427 subpage_writelen(opaque, addr, value, 1);
2428}
2429
2430static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2431{
2432#if defined(DEBUG_SUBPAGE)
2433 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2434#endif
2435
2436 return subpage_readlen(opaque, addr, 2);
2437}
2438
2439static void subpage_writel (void *opaque,
2440 target_phys_addr_t addr, uint32_t value)
2441{
2442#if defined(DEBUG_SUBPAGE)
2443 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2444#endif
2445 subpage_writelen(opaque, addr, value, 2);
2446}
2447
2448static CPUReadMemoryFunc *subpage_read[] = {
2449 &subpage_readb,
2450 &subpage_readw,
2451 &subpage_readl,
2452};
2453
2454static CPUWriteMemoryFunc *subpage_write[] = {
2455 &subpage_writeb,
2456 &subpage_writew,
2457 &subpage_writel,
2458};
2459
2460static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002461 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002462{
2463 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002464 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002465
2466 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2467 return -1;
2468 idx = SUBPAGE_IDX(start);
2469 eidx = SUBPAGE_IDX(end);
2470#if defined(DEBUG_SUBPAGE)
2471 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2472 mmio, start, end, idx, eidx, memory);
2473#endif
2474 memory >>= IO_MEM_SHIFT;
2475 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002476 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002477 if (io_mem_read[memory][i]) {
2478 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2479 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2480 }
2481 if (io_mem_write[memory][i]) {
2482 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2483 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2484 }
blueswir14254fab2008-01-01 16:57:19 +00002485 }
blueswir1db7b5422007-05-26 17:36:03 +00002486 }
2487
2488 return 0;
2489}
2490
aurel3200f82b82008-04-27 21:12:55 +00002491static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2492 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002493{
2494 subpage_t *mmio;
2495 int subpage_memory;
2496
2497 mmio = qemu_mallocz(sizeof(subpage_t));
2498 if (mmio != NULL) {
2499 mmio->base = base;
2500 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2501#if defined(DEBUG_SUBPAGE)
2502 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2503 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2504#endif
2505 *phys = subpage_memory | IO_MEM_SUBPAGE;
2506 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2507 }
2508
2509 return mmio;
2510}
2511
bellard33417e72003-08-10 21:47:01 +00002512static void io_mem_init(void)
2513{
bellard3a7d9292005-08-21 09:26:42 +00002514 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002515 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002516 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002517 io_mem_nb = 5;
2518
pbrook6658ffb2007-03-16 23:58:11 +00002519#if defined(CONFIG_SOFTMMU)
2520 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2521 watch_mem_write, NULL);
2522#endif
bellard1ccde1c2004-02-06 19:46:14 +00002523 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002524 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002525 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002526}
2527
2528/* mem_read and mem_write are arrays of functions containing the
2529 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002530 2). Functions can be omitted with a NULL function pointer. The
2531 registered functions may be modified dynamically later.
2532 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002533 modified. If it is zero, a new io zone is allocated. The return
2534 value can be used with cpu_register_physical_memory(). (-1) is
2535 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002536int cpu_register_io_memory(int io_index,
2537 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002538 CPUWriteMemoryFunc **mem_write,
2539 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002540{
blueswir14254fab2008-01-01 16:57:19 +00002541 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002542
2543 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002544 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002545 return -1;
2546 io_index = io_mem_nb++;
2547 } else {
2548 if (io_index >= IO_MEM_NB_ENTRIES)
2549 return -1;
2550 }
bellardb5ff1b32005-11-26 10:38:39 +00002551
bellard33417e72003-08-10 21:47:01 +00002552 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002553 if (!mem_read[i] || !mem_write[i])
2554 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002555 io_mem_read[io_index][i] = mem_read[i];
2556 io_mem_write[io_index][i] = mem_write[i];
2557 }
bellarda4193c82004-06-03 14:01:43 +00002558 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002559 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002560}
bellard61382a52003-10-27 21:22:23 +00002561
bellard8926b512004-10-10 15:14:20 +00002562CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2563{
2564 return io_mem_write[io_index >> IO_MEM_SHIFT];
2565}
2566
2567CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2568{
2569 return io_mem_read[io_index >> IO_MEM_SHIFT];
2570}
2571
bellard13eb76e2004-01-24 15:23:36 +00002572/* physical memory access (slow version, mainly for debug) */
2573#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002574void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002575 int len, int is_write)
2576{
2577 int l, flags;
2578 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002579 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002580
2581 while (len > 0) {
2582 page = addr & TARGET_PAGE_MASK;
2583 l = (page + TARGET_PAGE_SIZE) - addr;
2584 if (l > len)
2585 l = len;
2586 flags = page_get_flags(page);
2587 if (!(flags & PAGE_VALID))
2588 return;
2589 if (is_write) {
2590 if (!(flags & PAGE_WRITE))
2591 return;
bellard579a97f2007-11-11 14:26:47 +00002592 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002593 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002594 /* FIXME - should this return an error rather than just fail? */
2595 return;
aurel3272fb7da2008-04-27 23:53:45 +00002596 memcpy(p, buf, l);
2597 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002598 } else {
2599 if (!(flags & PAGE_READ))
2600 return;
bellard579a97f2007-11-11 14:26:47 +00002601 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002602 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002603 /* FIXME - should this return an error rather than just fail? */
2604 return;
aurel3272fb7da2008-04-27 23:53:45 +00002605 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002606 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002607 }
2608 len -= l;
2609 buf += l;
2610 addr += l;
2611 }
2612}
bellard8df1cd02005-01-28 22:37:22 +00002613
bellard13eb76e2004-01-24 15:23:36 +00002614#else
ths5fafdf22007-09-16 21:08:06 +00002615void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002616 int len, int is_write)
2617{
2618 int l, io_index;
2619 uint8_t *ptr;
2620 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002621 target_phys_addr_t page;
2622 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002623 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002624
bellard13eb76e2004-01-24 15:23:36 +00002625 while (len > 0) {
2626 page = addr & TARGET_PAGE_MASK;
2627 l = (page + TARGET_PAGE_SIZE) - addr;
2628 if (l > len)
2629 l = len;
bellard92e873b2004-05-21 14:52:29 +00002630 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002631 if (!p) {
2632 pd = IO_MEM_UNASSIGNED;
2633 } else {
2634 pd = p->phys_offset;
2635 }
ths3b46e622007-09-17 08:09:54 +00002636
bellard13eb76e2004-01-24 15:23:36 +00002637 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002638 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002639 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002640 /* XXX: could force cpu_single_env to NULL to avoid
2641 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002642 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002643 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002644 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002645 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002646 l = 4;
2647 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002648 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002649 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002650 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002651 l = 2;
2652 } else {
bellard1c213d12005-09-03 10:49:04 +00002653 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002654 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002655 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002656 l = 1;
2657 }
2658 } else {
bellardb448f2f2004-02-25 23:24:04 +00002659 unsigned long addr1;
2660 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002661 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002662 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002663 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002664 if (!cpu_physical_memory_is_dirty(addr1)) {
2665 /* invalidate code */
2666 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2667 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002668 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002669 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002670 }
bellard13eb76e2004-01-24 15:23:36 +00002671 }
2672 } else {
ths5fafdf22007-09-16 21:08:06 +00002673 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002674 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002675 /* I/O case */
2676 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2677 if (l >= 4 && ((addr & 3) == 0)) {
2678 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002679 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002680 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002681 l = 4;
2682 } else if (l >= 2 && ((addr & 1) == 0)) {
2683 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002684 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002685 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002686 l = 2;
2687 } else {
bellard1c213d12005-09-03 10:49:04 +00002688 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002689 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002690 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002691 l = 1;
2692 }
2693 } else {
2694 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002695 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002696 (addr & ~TARGET_PAGE_MASK);
2697 memcpy(buf, ptr, l);
2698 }
2699 }
2700 len -= l;
2701 buf += l;
2702 addr += l;
2703 }
2704}
bellard8df1cd02005-01-28 22:37:22 +00002705
bellardd0ecd2a2006-04-23 17:14:48 +00002706/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002707void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002708 const uint8_t *buf, int len)
2709{
2710 int l;
2711 uint8_t *ptr;
2712 target_phys_addr_t page;
2713 unsigned long pd;
2714 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002715
bellardd0ecd2a2006-04-23 17:14:48 +00002716 while (len > 0) {
2717 page = addr & TARGET_PAGE_MASK;
2718 l = (page + TARGET_PAGE_SIZE) - addr;
2719 if (l > len)
2720 l = len;
2721 p = phys_page_find(page >> TARGET_PAGE_BITS);
2722 if (!p) {
2723 pd = IO_MEM_UNASSIGNED;
2724 } else {
2725 pd = p->phys_offset;
2726 }
ths3b46e622007-09-17 08:09:54 +00002727
bellardd0ecd2a2006-04-23 17:14:48 +00002728 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002729 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2730 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002731 /* do nothing */
2732 } else {
2733 unsigned long addr1;
2734 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2735 /* ROM/RAM case */
2736 ptr = phys_ram_base + addr1;
2737 memcpy(ptr, buf, l);
2738 }
2739 len -= l;
2740 buf += l;
2741 addr += l;
2742 }
2743}
2744
2745
bellard8df1cd02005-01-28 22:37:22 +00002746/* warning: addr must be aligned */
2747uint32_t ldl_phys(target_phys_addr_t addr)
2748{
2749 int io_index;
2750 uint8_t *ptr;
2751 uint32_t val;
2752 unsigned long pd;
2753 PhysPageDesc *p;
2754
2755 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2756 if (!p) {
2757 pd = IO_MEM_UNASSIGNED;
2758 } else {
2759 pd = p->phys_offset;
2760 }
ths3b46e622007-09-17 08:09:54 +00002761
ths5fafdf22007-09-16 21:08:06 +00002762 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002763 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002764 /* I/O case */
2765 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2766 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2767 } else {
2768 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002769 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002770 (addr & ~TARGET_PAGE_MASK);
2771 val = ldl_p(ptr);
2772 }
2773 return val;
2774}
2775
bellard84b7b8e2005-11-28 21:19:04 +00002776/* warning: addr must be aligned */
2777uint64_t ldq_phys(target_phys_addr_t addr)
2778{
2779 int io_index;
2780 uint8_t *ptr;
2781 uint64_t val;
2782 unsigned long pd;
2783 PhysPageDesc *p;
2784
2785 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2786 if (!p) {
2787 pd = IO_MEM_UNASSIGNED;
2788 } else {
2789 pd = p->phys_offset;
2790 }
ths3b46e622007-09-17 08:09:54 +00002791
bellard2a4188a2006-06-25 21:54:59 +00002792 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2793 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002794 /* I/O case */
2795 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2796#ifdef TARGET_WORDS_BIGENDIAN
2797 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2798 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2799#else
2800 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2801 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2802#endif
2803 } else {
2804 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002805 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002806 (addr & ~TARGET_PAGE_MASK);
2807 val = ldq_p(ptr);
2808 }
2809 return val;
2810}
2811
bellardaab33092005-10-30 20:48:42 +00002812/* XXX: optimize */
2813uint32_t ldub_phys(target_phys_addr_t addr)
2814{
2815 uint8_t val;
2816 cpu_physical_memory_read(addr, &val, 1);
2817 return val;
2818}
2819
2820/* XXX: optimize */
2821uint32_t lduw_phys(target_phys_addr_t addr)
2822{
2823 uint16_t val;
2824 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2825 return tswap16(val);
2826}
2827
bellard8df1cd02005-01-28 22:37:22 +00002828/* warning: addr must be aligned. The ram page is not masked as dirty
2829 and the code inside is not invalidated. It is useful if the dirty
2830 bits are used to track modified PTEs */
2831void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2832{
2833 int io_index;
2834 uint8_t *ptr;
2835 unsigned long pd;
2836 PhysPageDesc *p;
2837
2838 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2839 if (!p) {
2840 pd = IO_MEM_UNASSIGNED;
2841 } else {
2842 pd = p->phys_offset;
2843 }
ths3b46e622007-09-17 08:09:54 +00002844
bellard3a7d9292005-08-21 09:26:42 +00002845 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002846 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2847 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2848 } else {
ths5fafdf22007-09-16 21:08:06 +00002849 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002850 (addr & ~TARGET_PAGE_MASK);
2851 stl_p(ptr, val);
2852 }
2853}
2854
j_mayerbc98a7e2007-04-04 07:55:12 +00002855void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2856{
2857 int io_index;
2858 uint8_t *ptr;
2859 unsigned long pd;
2860 PhysPageDesc *p;
2861
2862 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2863 if (!p) {
2864 pd = IO_MEM_UNASSIGNED;
2865 } else {
2866 pd = p->phys_offset;
2867 }
ths3b46e622007-09-17 08:09:54 +00002868
j_mayerbc98a7e2007-04-04 07:55:12 +00002869 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2870 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2871#ifdef TARGET_WORDS_BIGENDIAN
2872 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2873 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2874#else
2875 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2876 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2877#endif
2878 } else {
ths5fafdf22007-09-16 21:08:06 +00002879 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002880 (addr & ~TARGET_PAGE_MASK);
2881 stq_p(ptr, val);
2882 }
2883}
2884
bellard8df1cd02005-01-28 22:37:22 +00002885/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002886void stl_phys(target_phys_addr_t addr, uint32_t val)
2887{
2888 int io_index;
2889 uint8_t *ptr;
2890 unsigned long pd;
2891 PhysPageDesc *p;
2892
2893 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2894 if (!p) {
2895 pd = IO_MEM_UNASSIGNED;
2896 } else {
2897 pd = p->phys_offset;
2898 }
ths3b46e622007-09-17 08:09:54 +00002899
bellard3a7d9292005-08-21 09:26:42 +00002900 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002901 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2902 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2903 } else {
2904 unsigned long addr1;
2905 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2906 /* RAM case */
2907 ptr = phys_ram_base + addr1;
2908 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002909 if (!cpu_physical_memory_is_dirty(addr1)) {
2910 /* invalidate code */
2911 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2912 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002913 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2914 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002915 }
bellard8df1cd02005-01-28 22:37:22 +00002916 }
2917}
2918
bellardaab33092005-10-30 20:48:42 +00002919/* XXX: optimize */
2920void stb_phys(target_phys_addr_t addr, uint32_t val)
2921{
2922 uint8_t v = val;
2923 cpu_physical_memory_write(addr, &v, 1);
2924}
2925
2926/* XXX: optimize */
2927void stw_phys(target_phys_addr_t addr, uint32_t val)
2928{
2929 uint16_t v = tswap16(val);
2930 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2931}
2932
2933/* XXX: optimize */
2934void stq_phys(target_phys_addr_t addr, uint64_t val)
2935{
2936 val = tswap64(val);
2937 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2938}
2939
bellard13eb76e2004-01-24 15:23:36 +00002940#endif
2941
2942/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002943int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002944 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002945{
2946 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002947 target_phys_addr_t phys_addr;
2948 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002949
2950 while (len > 0) {
2951 page = addr & TARGET_PAGE_MASK;
2952 phys_addr = cpu_get_phys_page_debug(env, page);
2953 /* if no physical page mapped, return an error */
2954 if (phys_addr == -1)
2955 return -1;
2956 l = (page + TARGET_PAGE_SIZE) - addr;
2957 if (l > len)
2958 l = len;
ths5fafdf22007-09-16 21:08:06 +00002959 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002960 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002961 len -= l;
2962 buf += l;
2963 addr += l;
2964 }
2965 return 0;
2966}
2967
bellarde3db7222005-01-26 22:00:47 +00002968void dump_exec_info(FILE *f,
2969 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2970{
2971 int i, target_code_size, max_target_code_size;
2972 int direct_jmp_count, direct_jmp2_count, cross_page;
2973 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002974
bellarde3db7222005-01-26 22:00:47 +00002975 target_code_size = 0;
2976 max_target_code_size = 0;
2977 cross_page = 0;
2978 direct_jmp_count = 0;
2979 direct_jmp2_count = 0;
2980 for(i = 0; i < nb_tbs; i++) {
2981 tb = &tbs[i];
2982 target_code_size += tb->size;
2983 if (tb->size > max_target_code_size)
2984 max_target_code_size = tb->size;
2985 if (tb->page_addr[1] != -1)
2986 cross_page++;
2987 if (tb->tb_next_offset[0] != 0xffff) {
2988 direct_jmp_count++;
2989 if (tb->tb_next_offset[1] != 0xffff) {
2990 direct_jmp2_count++;
2991 }
2992 }
2993 }
2994 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002995 cpu_fprintf(f, "Translation buffer state:\n");
bellarde3db7222005-01-26 22:00:47 +00002996 cpu_fprintf(f, "TB count %d\n", nb_tbs);
ths5fafdf22007-09-16 21:08:06 +00002997 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002998 nb_tbs ? target_code_size / nb_tbs : 0,
2999 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003000 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003001 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3002 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003003 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3004 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003005 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3006 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003007 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003008 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3009 direct_jmp2_count,
3010 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003011 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003012 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3013 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3014 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003015 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003016}
3017
ths5fafdf22007-09-16 21:08:06 +00003018#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003019
3020#define MMUSUFFIX _cmmu
3021#define GETPC() NULL
3022#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003023#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003024
3025#define SHIFT 0
3026#include "softmmu_template.h"
3027
3028#define SHIFT 1
3029#include "softmmu_template.h"
3030
3031#define SHIFT 2
3032#include "softmmu_template.h"
3033
3034#define SHIFT 3
3035#include "softmmu_template.h"
3036
3037#undef env
3038
3039#endif