blob: 58a0cffacb4a37b6a626634e6ea7c08c5eb5c11f [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"
pbrookb3c77242008-06-30 16:31:04 +000040#include "hw/hw.h"
aliguori74576192008-10-06 14:02:03 +000041#include "osdep.h"
aliguori7ba1e612008-11-05 16:04:33 +000042#include "kvm.h"
pbrook53a59602006-03-25 19:31:22 +000043#if defined(CONFIG_USER_ONLY)
44#include <qemu.h>
45#endif
bellard54936002003-05-13 00:25:15 +000046
bellardfd6ce8f2003-05-14 19:00:11 +000047//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000048//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000049//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000050//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000051
52/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000053//#define DEBUG_TB_CHECK
54//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000055
ths1196be32007-03-17 15:17:58 +000056//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000057//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000058
pbrook99773bd2006-04-16 15:14:59 +000059#if !defined(CONFIG_USER_ONLY)
60/* TB consistency checks only implemented for usermode emulation. */
61#undef DEBUG_TB_CHECK
62#endif
63
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
blueswir1bdaf78e2008-10-04 07:24:27 +000087static TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000088int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000089TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
blueswir1bdaf78e2008-10-04 07:24:27 +000090static int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000091/* any access to the tbs or the page table must use this lock */
92spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000093
blueswir1141ac462008-07-26 15:05:57 +000094#if defined(__arm__) || defined(__sparc_v9__)
95/* The prologue must be reachable with a direct jump. ARM and Sparc64
96 have limited branch ranges (possibly also PPC) so place it in a
blueswir1d03d8602008-07-10 17:21:31 +000097 section close to code segment. */
98#define code_gen_section \
99 __attribute__((__section__(".gen_code"))) \
100 __attribute__((aligned (32)))
101#else
102#define code_gen_section \
103 __attribute__((aligned (32)))
104#endif
105
106uint8_t code_gen_prologue[1024] code_gen_section;
blueswir1bdaf78e2008-10-04 07:24:27 +0000107static uint8_t *code_gen_buffer;
108static unsigned long code_gen_buffer_size;
bellard26a5f132008-05-28 12:30:31 +0000109/* threshold to flush the translated code buffer */
blueswir1bdaf78e2008-10-04 07:24:27 +0000110static unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000111uint8_t *code_gen_ptr;
112
pbrooke2eef172008-06-08 01:09:01 +0000113#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +0000114ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000115int phys_ram_fd;
116uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000117uint8_t *phys_ram_dirty;
aliguori74576192008-10-06 14:02:03 +0000118static int in_migration;
bellarde9a1ab12007-02-08 23:08:38 +0000119static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000120#endif
bellard9fa3e852004-01-04 18:06:42 +0000121
bellard6a00d602005-11-21 23:25:50 +0000122CPUState *first_cpu;
123/* current CPU in the current thread. It is only valid inside
124 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000125CPUState *cpu_single_env;
pbrook2e70f6e2008-06-29 01:03:05 +0000126/* 0 = Do not count executed instructions.
thsbf20dc02008-06-30 17:22:19 +0000127 1 = Precise instruction counting.
pbrook2e70f6e2008-06-29 01:03:05 +0000128 2 = Adaptive rate instruction counting. */
129int use_icount = 0;
130/* Current instruction counter. While executing translated code this may
131 include some instructions that have not yet been executed. */
132int64_t qemu_icount;
bellard6a00d602005-11-21 23:25:50 +0000133
bellard54936002003-05-13 00:25:15 +0000134typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000135 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000136 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000137 /* in order to optimize self modifying code, we count the number
138 of lookups we do to a given page to use a bitmap */
139 unsigned int code_write_count;
140 uint8_t *code_bitmap;
141#if defined(CONFIG_USER_ONLY)
142 unsigned long flags;
143#endif
bellard54936002003-05-13 00:25:15 +0000144} PageDesc;
145
bellard92e873b2004-05-21 14:52:29 +0000146typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000147 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000148 ram_addr_t phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +0000149 ram_addr_t region_offset;
bellard92e873b2004-05-21 14:52:29 +0000150} PhysPageDesc;
151
bellard54936002003-05-13 00:25:15 +0000152#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000153#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
154/* XXX: this is a temporary hack for alpha target.
155 * In the future, this is to be replaced by a multi-level table
156 * to actually be able to handle the complete 64 bits address space.
157 */
158#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
159#else
aurel3203875442008-04-22 20:45:18 +0000160#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000161#endif
bellard54936002003-05-13 00:25:15 +0000162
163#define L1_SIZE (1 << L1_BITS)
164#define L2_SIZE (1 << L2_BITS)
165
bellard83fb7ad2004-07-05 21:25:26 +0000166unsigned long qemu_real_host_page_size;
167unsigned long qemu_host_page_bits;
168unsigned long qemu_host_page_size;
169unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000170
bellard92e873b2004-05-21 14:52:29 +0000171/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000172static PageDesc *l1_map[L1_SIZE];
blueswir1bdaf78e2008-10-04 07:24:27 +0000173static PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000174
pbrooke2eef172008-06-08 01:09:01 +0000175#if !defined(CONFIG_USER_ONLY)
176static void io_mem_init(void);
177
bellard33417e72003-08-10 21:47:01 +0000178/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000179CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
180CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000181void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000182static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000183static int io_mem_watch;
184#endif
bellard33417e72003-08-10 21:47:01 +0000185
bellard34865132003-10-05 14:28:56 +0000186/* log support */
blueswir1d9b630f2008-10-05 09:57:08 +0000187static const char *logfilename = "/tmp/qemu.log";
bellard34865132003-10-05 14:28:56 +0000188FILE *logfile;
189int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000190static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000191
bellarde3db7222005-01-26 22:00:47 +0000192/* statistics */
193static int tlb_flush_count;
194static int tb_flush_count;
195static int tb_phys_invalidate_count;
196
blueswir1db7b5422007-05-26 17:36:03 +0000197#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
198typedef struct subpage_t {
199 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000200 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
201 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
202 void *opaque[TARGET_PAGE_SIZE][2][4];
pbrook8da3ff12008-12-01 18:59:50 +0000203 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000204} subpage_t;
205
bellard7cb69ca2008-05-10 10:55:51 +0000206#ifdef _WIN32
207static void map_exec(void *addr, long size)
208{
209 DWORD old_protect;
210 VirtualProtect(addr, size,
211 PAGE_EXECUTE_READWRITE, &old_protect);
212
213}
214#else
215static void map_exec(void *addr, long size)
216{
bellard43694152008-05-29 09:35:57 +0000217 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000218
bellard43694152008-05-29 09:35:57 +0000219 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000220 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000221 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000222
223 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000224 end += page_size - 1;
225 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000226
227 mprotect((void *)start, end - start,
228 PROT_READ | PROT_WRITE | PROT_EXEC);
229}
230#endif
231
bellardb346ff42003-06-15 20:05:50 +0000232static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000233{
bellard83fb7ad2004-07-05 21:25:26 +0000234 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000235 TARGET_PAGE_SIZE */
aliguoric2b48b62008-11-11 22:06:42 +0000236#ifdef _WIN32
237 {
238 SYSTEM_INFO system_info;
239
240 GetSystemInfo(&system_info);
241 qemu_real_host_page_size = system_info.dwPageSize;
242 }
243#else
244 qemu_real_host_page_size = getpagesize();
245#endif
bellard83fb7ad2004-07-05 21:25:26 +0000246 if (qemu_host_page_size == 0)
247 qemu_host_page_size = qemu_real_host_page_size;
248 if (qemu_host_page_size < TARGET_PAGE_SIZE)
249 qemu_host_page_size = TARGET_PAGE_SIZE;
250 qemu_host_page_bits = 0;
251 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
252 qemu_host_page_bits++;
253 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000254 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
255 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000256
257#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
258 {
259 long long startaddr, endaddr;
260 FILE *f;
261 int n;
262
pbrookc8a706f2008-06-02 16:16:42 +0000263 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000264 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000265 f = fopen("/proc/self/maps", "r");
266 if (f) {
267 do {
268 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
269 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000270 startaddr = MIN(startaddr,
271 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
272 endaddr = MIN(endaddr,
273 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000274 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000275 TARGET_PAGE_ALIGN(endaddr),
276 PAGE_RESERVED);
277 }
278 } while (!feof(f));
279 fclose(f);
280 }
pbrookc8a706f2008-06-02 16:16:42 +0000281 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000282 }
283#endif
bellard54936002003-05-13 00:25:15 +0000284}
285
aliguori434929b2008-09-15 15:56:30 +0000286static inline PageDesc **page_l1_map(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000287{
pbrook17e23772008-06-09 13:47:45 +0000288#if TARGET_LONG_BITS > 32
289 /* Host memory outside guest VM. For 32-bit targets we have already
290 excluded high addresses. */
thsd8173e02008-08-29 13:10:00 +0000291 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
pbrook17e23772008-06-09 13:47:45 +0000292 return NULL;
293#endif
aliguori434929b2008-09-15 15:56:30 +0000294 return &l1_map[index >> L2_BITS];
295}
296
297static inline PageDesc *page_find_alloc(target_ulong index)
298{
299 PageDesc **lp, *p;
300 lp = page_l1_map(index);
301 if (!lp)
302 return NULL;
303
bellard54936002003-05-13 00:25:15 +0000304 p = *lp;
305 if (!p) {
306 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000307#if defined(CONFIG_USER_ONLY)
308 unsigned long addr;
309 size_t len = sizeof(PageDesc) * L2_SIZE;
310 /* Don't use qemu_malloc because it may recurse. */
311 p = mmap(0, len, PROT_READ | PROT_WRITE,
312 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000313 *lp = p;
pbrook17e23772008-06-09 13:47:45 +0000314 addr = h2g(p);
315 if (addr == (target_ulong)addr) {
316 page_set_flags(addr & TARGET_PAGE_MASK,
317 TARGET_PAGE_ALIGN(addr + len),
318 PAGE_RESERVED);
319 }
320#else
321 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
322 *lp = p;
323#endif
bellard54936002003-05-13 00:25:15 +0000324 }
325 return p + (index & (L2_SIZE - 1));
326}
327
aurel3200f82b82008-04-27 21:12:55 +0000328static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000329{
aliguori434929b2008-09-15 15:56:30 +0000330 PageDesc **lp, *p;
331 lp = page_l1_map(index);
332 if (!lp)
333 return NULL;
bellard54936002003-05-13 00:25:15 +0000334
aliguori434929b2008-09-15 15:56:30 +0000335 p = *lp;
bellard54936002003-05-13 00:25:15 +0000336 if (!p)
337 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000338 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000339}
340
bellard108c49b2005-07-24 12:55:09 +0000341static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000342{
bellard108c49b2005-07-24 12:55:09 +0000343 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000344 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000345
bellard108c49b2005-07-24 12:55:09 +0000346 p = (void **)l1_phys_map;
347#if TARGET_PHYS_ADDR_SPACE_BITS > 32
348
349#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
350#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
351#endif
352 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000353 p = *lp;
354 if (!p) {
355 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000356 if (!alloc)
357 return NULL;
358 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
359 memset(p, 0, sizeof(void *) * L1_SIZE);
360 *lp = p;
361 }
362#endif
363 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000364 pd = *lp;
365 if (!pd) {
366 int i;
bellard108c49b2005-07-24 12:55:09 +0000367 /* allocate if not found */
368 if (!alloc)
369 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000370 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
371 *lp = pd;
372 for (i = 0; i < L2_SIZE; i++)
373 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000374 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000375 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000376}
377
bellard108c49b2005-07-24 12:55:09 +0000378static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000379{
bellard108c49b2005-07-24 12:55:09 +0000380 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000381}
382
bellard9fa3e852004-01-04 18:06:42 +0000383#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000384static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000385static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000386 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000387#define mmap_lock() do { } while(0)
388#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000389#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000390
bellard43694152008-05-29 09:35:57 +0000391#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
392
393#if defined(CONFIG_USER_ONLY)
394/* Currently it is not recommanded to allocate big chunks of data in
395 user mode. It will change when a dedicated libc will be used */
396#define USE_STATIC_CODE_GEN_BUFFER
397#endif
398
399#ifdef USE_STATIC_CODE_GEN_BUFFER
400static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
401#endif
402
blueswir18fcd3692008-08-17 20:26:25 +0000403static void code_gen_alloc(unsigned long tb_size)
bellard26a5f132008-05-28 12:30:31 +0000404{
bellard43694152008-05-29 09:35:57 +0000405#ifdef USE_STATIC_CODE_GEN_BUFFER
406 code_gen_buffer = static_code_gen_buffer;
407 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
408 map_exec(code_gen_buffer, code_gen_buffer_size);
409#else
bellard26a5f132008-05-28 12:30:31 +0000410 code_gen_buffer_size = tb_size;
411 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000412#if defined(CONFIG_USER_ONLY)
413 /* in user mode, phys_ram_size is not meaningful */
414 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
415#else
bellard26a5f132008-05-28 12:30:31 +0000416 /* XXX: needs ajustments */
aliguori174a9a12008-09-24 14:10:36 +0000417 code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000418#endif
bellard26a5f132008-05-28 12:30:31 +0000419 }
420 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
421 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
422 /* The code gen buffer location may have constraints depending on
423 the host cpu and OS */
424#if defined(__linux__)
425 {
426 int flags;
blueswir1141ac462008-07-26 15:05:57 +0000427 void *start = NULL;
428
bellard26a5f132008-05-28 12:30:31 +0000429 flags = MAP_PRIVATE | MAP_ANONYMOUS;
430#if defined(__x86_64__)
431 flags |= MAP_32BIT;
432 /* Cannot map more than that */
433 if (code_gen_buffer_size > (800 * 1024 * 1024))
434 code_gen_buffer_size = (800 * 1024 * 1024);
blueswir1141ac462008-07-26 15:05:57 +0000435#elif defined(__sparc_v9__)
436 // Map the buffer below 2G, so we can use direct calls and branches
437 flags |= MAP_FIXED;
438 start = (void *) 0x60000000UL;
439 if (code_gen_buffer_size > (512 * 1024 * 1024))
440 code_gen_buffer_size = (512 * 1024 * 1024);
balrog1cb06612008-12-01 02:10:17 +0000441#elif defined(__arm__)
balrog63d41242008-12-01 02:19:41 +0000442 /* Map the buffer below 32M, so we can use direct calls and branches */
balrog1cb06612008-12-01 02:10:17 +0000443 flags |= MAP_FIXED;
444 start = (void *) 0x01000000UL;
445 if (code_gen_buffer_size > 16 * 1024 * 1024)
446 code_gen_buffer_size = 16 * 1024 * 1024;
bellard26a5f132008-05-28 12:30:31 +0000447#endif
blueswir1141ac462008-07-26 15:05:57 +0000448 code_gen_buffer = mmap(start, code_gen_buffer_size,
449 PROT_WRITE | PROT_READ | PROT_EXEC,
bellard26a5f132008-05-28 12:30:31 +0000450 flags, -1, 0);
451 if (code_gen_buffer == MAP_FAILED) {
452 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
453 exit(1);
454 }
455 }
aliguori06e67a82008-09-27 15:32:41 +0000456#elif defined(__FreeBSD__)
457 {
458 int flags;
459 void *addr = NULL;
460 flags = MAP_PRIVATE | MAP_ANONYMOUS;
461#if defined(__x86_64__)
462 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
463 * 0x40000000 is free */
464 flags |= MAP_FIXED;
465 addr = (void *)0x40000000;
466 /* Cannot map more than that */
467 if (code_gen_buffer_size > (800 * 1024 * 1024))
468 code_gen_buffer_size = (800 * 1024 * 1024);
469#endif
470 code_gen_buffer = mmap(addr, code_gen_buffer_size,
471 PROT_WRITE | PROT_READ | PROT_EXEC,
472 flags, -1, 0);
473 if (code_gen_buffer == MAP_FAILED) {
474 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
475 exit(1);
476 }
477 }
bellard26a5f132008-05-28 12:30:31 +0000478#else
479 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
480 if (!code_gen_buffer) {
481 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
482 exit(1);
483 }
484 map_exec(code_gen_buffer, code_gen_buffer_size);
485#endif
bellard43694152008-05-29 09:35:57 +0000486#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000487 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
488 code_gen_buffer_max_size = code_gen_buffer_size -
489 code_gen_max_block_size();
490 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
491 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
492}
493
494/* Must be called before using the QEMU cpus. 'tb_size' is the size
495 (in bytes) allocated to the translation buffer. Zero means default
496 size. */
497void cpu_exec_init_all(unsigned long tb_size)
498{
bellard26a5f132008-05-28 12:30:31 +0000499 cpu_gen_init();
500 code_gen_alloc(tb_size);
501 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000502 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000503#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000504 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000505#endif
bellard26a5f132008-05-28 12:30:31 +0000506}
507
pbrook9656f322008-07-01 20:01:19 +0000508#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
509
510#define CPU_COMMON_SAVE_VERSION 1
511
512static void cpu_common_save(QEMUFile *f, void *opaque)
513{
514 CPUState *env = opaque;
515
516 qemu_put_be32s(f, &env->halted);
517 qemu_put_be32s(f, &env->interrupt_request);
518}
519
520static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
521{
522 CPUState *env = opaque;
523
524 if (version_id != CPU_COMMON_SAVE_VERSION)
525 return -EINVAL;
526
527 qemu_get_be32s(f, &env->halted);
pbrook75f482a2008-07-01 21:53:33 +0000528 qemu_get_be32s(f, &env->interrupt_request);
pbrook9656f322008-07-01 20:01:19 +0000529 tlb_flush(env, 1);
530
531 return 0;
532}
533#endif
534
bellard6a00d602005-11-21 23:25:50 +0000535void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000536{
bellard6a00d602005-11-21 23:25:50 +0000537 CPUState **penv;
538 int cpu_index;
539
bellard6a00d602005-11-21 23:25:50 +0000540 env->next_cpu = NULL;
541 penv = &first_cpu;
542 cpu_index = 0;
543 while (*penv != NULL) {
544 penv = (CPUState **)&(*penv)->next_cpu;
545 cpu_index++;
546 }
547 env->cpu_index = cpu_index;
aliguoric0ce9982008-11-25 22:13:57 +0000548 TAILQ_INIT(&env->breakpoints);
549 TAILQ_INIT(&env->watchpoints);
bellard6a00d602005-11-21 23:25:50 +0000550 *penv = env;
pbrookb3c77242008-06-30 16:31:04 +0000551#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
pbrook9656f322008-07-01 20:01:19 +0000552 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
553 cpu_common_save, cpu_common_load, env);
pbrookb3c77242008-06-30 16:31:04 +0000554 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
555 cpu_save, cpu_load, env);
556#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000557}
558
bellard9fa3e852004-01-04 18:06:42 +0000559static inline void invalidate_page_bitmap(PageDesc *p)
560{
561 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000562 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000563 p->code_bitmap = NULL;
564 }
565 p->code_write_count = 0;
566}
567
bellardfd6ce8f2003-05-14 19:00:11 +0000568/* set to NULL all the 'first_tb' fields in all PageDescs */
569static void page_flush_tb(void)
570{
571 int i, j;
572 PageDesc *p;
573
574 for(i = 0; i < L1_SIZE; i++) {
575 p = l1_map[i];
576 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000577 for(j = 0; j < L2_SIZE; j++) {
578 p->first_tb = NULL;
579 invalidate_page_bitmap(p);
580 p++;
581 }
bellardfd6ce8f2003-05-14 19:00:11 +0000582 }
583 }
584}
585
586/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000587/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000588void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000589{
bellard6a00d602005-11-21 23:25:50 +0000590 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000591#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000592 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
593 (unsigned long)(code_gen_ptr - code_gen_buffer),
594 nb_tbs, nb_tbs > 0 ?
595 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000596#endif
bellard26a5f132008-05-28 12:30:31 +0000597 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000598 cpu_abort(env1, "Internal error: code buffer overflow\n");
599
bellardfd6ce8f2003-05-14 19:00:11 +0000600 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000601
bellard6a00d602005-11-21 23:25:50 +0000602 for(env = first_cpu; env != NULL; env = env->next_cpu) {
603 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
604 }
bellard9fa3e852004-01-04 18:06:42 +0000605
bellard8a8a6082004-10-03 13:36:49 +0000606 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000607 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000608
bellardfd6ce8f2003-05-14 19:00:11 +0000609 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000610 /* XXX: flush processor icache at this point if cache flush is
611 expensive */
bellarde3db7222005-01-26 22:00:47 +0000612 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000613}
614
615#ifdef DEBUG_TB_CHECK
616
j_mayerbc98a7e2007-04-04 07:55:12 +0000617static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000618{
619 TranslationBlock *tb;
620 int i;
621 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000622 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
623 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000624 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
625 address >= tb->pc + tb->size)) {
626 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000627 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000628 }
629 }
630 }
631}
632
633/* verify that all the pages have correct rights for code */
634static void tb_page_check(void)
635{
636 TranslationBlock *tb;
637 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000638
pbrook99773bd2006-04-16 15:14:59 +0000639 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
640 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000641 flags1 = page_get_flags(tb->pc);
642 flags2 = page_get_flags(tb->pc + tb->size - 1);
643 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
644 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000645 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000646 }
647 }
648 }
649}
650
blueswir1bdaf78e2008-10-04 07:24:27 +0000651static void tb_jmp_check(TranslationBlock *tb)
bellardd4e81642003-05-25 16:46:15 +0000652{
653 TranslationBlock *tb1;
654 unsigned int n1;
655
656 /* suppress any remaining jumps to this TB */
657 tb1 = tb->jmp_first;
658 for(;;) {
659 n1 = (long)tb1 & 3;
660 tb1 = (TranslationBlock *)((long)tb1 & ~3);
661 if (n1 == 2)
662 break;
663 tb1 = tb1->jmp_next[n1];
664 }
665 /* check end of list */
666 if (tb1 != tb) {
667 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
668 }
669}
670
bellardfd6ce8f2003-05-14 19:00:11 +0000671#endif
672
673/* invalidate one TB */
674static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
675 int next_offset)
676{
677 TranslationBlock *tb1;
678 for(;;) {
679 tb1 = *ptb;
680 if (tb1 == tb) {
681 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
682 break;
683 }
684 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
685 }
686}
687
bellard9fa3e852004-01-04 18:06:42 +0000688static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
689{
690 TranslationBlock *tb1;
691 unsigned int n1;
692
693 for(;;) {
694 tb1 = *ptb;
695 n1 = (long)tb1 & 3;
696 tb1 = (TranslationBlock *)((long)tb1 & ~3);
697 if (tb1 == tb) {
698 *ptb = tb1->page_next[n1];
699 break;
700 }
701 ptb = &tb1->page_next[n1];
702 }
703}
704
bellardd4e81642003-05-25 16:46:15 +0000705static inline void tb_jmp_remove(TranslationBlock *tb, int n)
706{
707 TranslationBlock *tb1, **ptb;
708 unsigned int n1;
709
710 ptb = &tb->jmp_next[n];
711 tb1 = *ptb;
712 if (tb1) {
713 /* find tb(n) in circular list */
714 for(;;) {
715 tb1 = *ptb;
716 n1 = (long)tb1 & 3;
717 tb1 = (TranslationBlock *)((long)tb1 & ~3);
718 if (n1 == n && tb1 == tb)
719 break;
720 if (n1 == 2) {
721 ptb = &tb1->jmp_first;
722 } else {
723 ptb = &tb1->jmp_next[n1];
724 }
725 }
726 /* now we can suppress tb(n) from the list */
727 *ptb = tb->jmp_next[n];
728
729 tb->jmp_next[n] = NULL;
730 }
731}
732
733/* reset the jump entry 'n' of a TB so that it is not chained to
734 another TB */
735static inline void tb_reset_jump(TranslationBlock *tb, int n)
736{
737 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
738}
739
pbrook2e70f6e2008-06-29 01:03:05 +0000740void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000741{
bellard6a00d602005-11-21 23:25:50 +0000742 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000743 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000744 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000745 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000746 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000747
bellard9fa3e852004-01-04 18:06:42 +0000748 /* remove the TB from the hash list */
749 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
750 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000751 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000752 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000753
bellard9fa3e852004-01-04 18:06:42 +0000754 /* remove the TB from the page list */
755 if (tb->page_addr[0] != page_addr) {
756 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
757 tb_page_remove(&p->first_tb, tb);
758 invalidate_page_bitmap(p);
759 }
760 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
761 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
762 tb_page_remove(&p->first_tb, tb);
763 invalidate_page_bitmap(p);
764 }
765
bellard8a40a182005-11-20 10:35:40 +0000766 tb_invalidated_flag = 1;
767
768 /* remove the TB from the hash list */
769 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000770 for(env = first_cpu; env != NULL; env = env->next_cpu) {
771 if (env->tb_jmp_cache[h] == tb)
772 env->tb_jmp_cache[h] = NULL;
773 }
bellard8a40a182005-11-20 10:35:40 +0000774
775 /* suppress this TB from the two jump lists */
776 tb_jmp_remove(tb, 0);
777 tb_jmp_remove(tb, 1);
778
779 /* suppress any remaining jumps to this TB */
780 tb1 = tb->jmp_first;
781 for(;;) {
782 n1 = (long)tb1 & 3;
783 if (n1 == 2)
784 break;
785 tb1 = (TranslationBlock *)((long)tb1 & ~3);
786 tb2 = tb1->jmp_next[n1];
787 tb_reset_jump(tb1, n1);
788 tb1->jmp_next[n1] = NULL;
789 tb1 = tb2;
790 }
791 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
792
bellarde3db7222005-01-26 22:00:47 +0000793 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000794}
795
796static inline void set_bits(uint8_t *tab, int start, int len)
797{
798 int end, mask, end1;
799
800 end = start + len;
801 tab += start >> 3;
802 mask = 0xff << (start & 7);
803 if ((start & ~7) == (end & ~7)) {
804 if (start < end) {
805 mask &= ~(0xff << (end & 7));
806 *tab |= mask;
807 }
808 } else {
809 *tab++ |= mask;
810 start = (start + 8) & ~7;
811 end1 = end & ~7;
812 while (start < end1) {
813 *tab++ = 0xff;
814 start += 8;
815 }
816 if (start < end) {
817 mask = ~(0xff << (end & 7));
818 *tab |= mask;
819 }
820 }
821}
822
823static void build_page_bitmap(PageDesc *p)
824{
825 int n, tb_start, tb_end;
826 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000827
pbrookb2a70812008-06-09 13:57:23 +0000828 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000829 if (!p->code_bitmap)
830 return;
bellard9fa3e852004-01-04 18:06:42 +0000831
832 tb = p->first_tb;
833 while (tb != NULL) {
834 n = (long)tb & 3;
835 tb = (TranslationBlock *)((long)tb & ~3);
836 /* NOTE: this is subtle as a TB may span two physical pages */
837 if (n == 0) {
838 /* NOTE: tb_end may be after the end of the page, but
839 it is not a problem */
840 tb_start = tb->pc & ~TARGET_PAGE_MASK;
841 tb_end = tb_start + tb->size;
842 if (tb_end > TARGET_PAGE_SIZE)
843 tb_end = TARGET_PAGE_SIZE;
844 } else {
845 tb_start = 0;
846 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
847 }
848 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
849 tb = tb->page_next[n];
850 }
851}
852
pbrook2e70f6e2008-06-29 01:03:05 +0000853TranslationBlock *tb_gen_code(CPUState *env,
854 target_ulong pc, target_ulong cs_base,
855 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000856{
857 TranslationBlock *tb;
858 uint8_t *tc_ptr;
859 target_ulong phys_pc, phys_page2, virt_page2;
860 int code_gen_size;
861
bellardc27004e2005-01-03 23:35:10 +0000862 phys_pc = get_phys_addr_code(env, pc);
863 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000864 if (!tb) {
865 /* flush must be done */
866 tb_flush(env);
867 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000868 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000869 /* Don't forget to invalidate previous TB info. */
870 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000871 }
872 tc_ptr = code_gen_ptr;
873 tb->tc_ptr = tc_ptr;
874 tb->cs_base = cs_base;
875 tb->flags = flags;
876 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000877 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000878 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 +0000879
bellardd720b932004-04-25 17:57:43 +0000880 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000881 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000882 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000883 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000884 phys_page2 = get_phys_addr_code(env, virt_page2);
885 }
886 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000887 return tb;
bellardd720b932004-04-25 17:57:43 +0000888}
ths3b46e622007-09-17 08:09:54 +0000889
bellard9fa3e852004-01-04 18:06:42 +0000890/* invalidate all TBs which intersect with the target physical page
891 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000892 the same physical page. 'is_cpu_write_access' should be true if called
893 from a real cpu write access: the virtual CPU will exit the current
894 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000895void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000896 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000897{
aliguori6b917542008-11-18 19:46:41 +0000898 TranslationBlock *tb, *tb_next, *saved_tb;
bellardd720b932004-04-25 17:57:43 +0000899 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000900 target_ulong tb_start, tb_end;
aliguori6b917542008-11-18 19:46:41 +0000901 PageDesc *p;
902 int n;
903#ifdef TARGET_HAS_PRECISE_SMC
904 int current_tb_not_found = is_cpu_write_access;
905 TranslationBlock *current_tb = NULL;
906 int current_tb_modified = 0;
907 target_ulong current_pc = 0;
908 target_ulong current_cs_base = 0;
909 int current_flags = 0;
910#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000911
912 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000913 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000914 return;
ths5fafdf22007-09-16 21:08:06 +0000915 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000916 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
917 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000918 /* build code bitmap */
919 build_page_bitmap(p);
920 }
921
922 /* we remove all the TBs in the range [start, end[ */
923 /* XXX: see if in some cases it could be faster to invalidate all the code */
924 tb = p->first_tb;
925 while (tb != NULL) {
926 n = (long)tb & 3;
927 tb = (TranslationBlock *)((long)tb & ~3);
928 tb_next = tb->page_next[n];
929 /* NOTE: this is subtle as a TB may span two physical pages */
930 if (n == 0) {
931 /* NOTE: tb_end may be after the end of the page, but
932 it is not a problem */
933 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
934 tb_end = tb_start + tb->size;
935 } else {
936 tb_start = tb->page_addr[1];
937 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
938 }
939 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000940#ifdef TARGET_HAS_PRECISE_SMC
941 if (current_tb_not_found) {
942 current_tb_not_found = 0;
943 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000944 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000945 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000946 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000947 }
948 }
949 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000950 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000951 /* If we are modifying the current TB, we must stop
952 its execution. We could be more precise by checking
953 that the modification is after the current PC, but it
954 would require a specialized function to partially
955 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000956
bellardd720b932004-04-25 17:57:43 +0000957 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000958 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000959 env->mem_io_pc, NULL);
aliguori6b917542008-11-18 19:46:41 +0000960 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
961 &current_flags);
bellardd720b932004-04-25 17:57:43 +0000962 }
963#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000964 /* we need to do that to handle the case where a signal
965 occurs while doing tb_phys_invalidate() */
966 saved_tb = NULL;
967 if (env) {
968 saved_tb = env->current_tb;
969 env->current_tb = NULL;
970 }
bellard9fa3e852004-01-04 18:06:42 +0000971 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000972 if (env) {
973 env->current_tb = saved_tb;
974 if (env->interrupt_request && env->current_tb)
975 cpu_interrupt(env, env->interrupt_request);
976 }
bellard9fa3e852004-01-04 18:06:42 +0000977 }
978 tb = tb_next;
979 }
980#if !defined(CONFIG_USER_ONLY)
981 /* if no code remaining, no need to continue to use slow writes */
982 if (!p->first_tb) {
983 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000984 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000985 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000986 }
987 }
988#endif
989#ifdef TARGET_HAS_PRECISE_SMC
990 if (current_tb_modified) {
991 /* we generate a block containing just the instruction
992 modifying the memory. It will ensure that it cannot modify
993 itself */
bellardea1c1802004-06-14 18:56:36 +0000994 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000995 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000996 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000997 }
998#endif
999}
1000
1001/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +00001002static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +00001003{
1004 PageDesc *p;
1005 int offset, b;
bellard59817cc2004-02-16 22:01:13 +00001006#if 0
bellarda4193c82004-06-03 14:01:43 +00001007 if (1) {
1008 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +00001009 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
pbrook2e70f6e2008-06-29 01:03:05 +00001010 cpu_single_env->mem_io_vaddr, len,
ths5fafdf22007-09-16 21:08:06 +00001011 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +00001012 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
1013 }
bellard59817cc2004-02-16 22:01:13 +00001014 }
1015#endif
bellard9fa3e852004-01-04 18:06:42 +00001016 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001017 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001018 return;
1019 if (p->code_bitmap) {
1020 offset = start & ~TARGET_PAGE_MASK;
1021 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1022 if (b & ((1 << len) - 1))
1023 goto do_invalidate;
1024 } else {
1025 do_invalidate:
bellardd720b932004-04-25 17:57:43 +00001026 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +00001027 }
1028}
1029
bellard9fa3e852004-01-04 18:06:42 +00001030#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +00001031static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +00001032 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001033{
aliguori6b917542008-11-18 19:46:41 +00001034 TranslationBlock *tb;
bellard9fa3e852004-01-04 18:06:42 +00001035 PageDesc *p;
aliguori6b917542008-11-18 19:46:41 +00001036 int n;
bellardd720b932004-04-25 17:57:43 +00001037#ifdef TARGET_HAS_PRECISE_SMC
aliguori6b917542008-11-18 19:46:41 +00001038 TranslationBlock *current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001039 CPUState *env = cpu_single_env;
aliguori6b917542008-11-18 19:46:41 +00001040 int current_tb_modified = 0;
1041 target_ulong current_pc = 0;
1042 target_ulong current_cs_base = 0;
1043 int current_flags = 0;
bellardd720b932004-04-25 17:57:43 +00001044#endif
bellard9fa3e852004-01-04 18:06:42 +00001045
1046 addr &= TARGET_PAGE_MASK;
1047 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001048 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +00001049 return;
1050 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +00001051#ifdef TARGET_HAS_PRECISE_SMC
1052 if (tb && pc != 0) {
1053 current_tb = tb_find_pc(pc);
1054 }
1055#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001056 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +00001057 n = (long)tb & 3;
1058 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +00001059#ifdef TARGET_HAS_PRECISE_SMC
1060 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +00001061 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +00001062 /* If we are modifying the current TB, we must stop
1063 its execution. We could be more precise by checking
1064 that the modification is after the current PC, but it
1065 would require a specialized function to partially
1066 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +00001067
bellardd720b932004-04-25 17:57:43 +00001068 current_tb_modified = 1;
1069 cpu_restore_state(current_tb, env, pc, puc);
aliguori6b917542008-11-18 19:46:41 +00001070 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1071 &current_flags);
bellardd720b932004-04-25 17:57:43 +00001072 }
1073#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +00001074 tb_phys_invalidate(tb, addr);
1075 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +00001076 }
1077 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001078#ifdef TARGET_HAS_PRECISE_SMC
1079 if (current_tb_modified) {
1080 /* we generate a block containing just the instruction
1081 modifying the memory. It will ensure that it cannot modify
1082 itself */
bellardea1c1802004-06-14 18:56:36 +00001083 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001084 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001085 cpu_resume_from_signal(env, puc);
1086 }
1087#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001088}
bellard9fa3e852004-01-04 18:06:42 +00001089#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001090
1091/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001092static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001093 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001094{
1095 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001096 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001097
bellard9fa3e852004-01-04 18:06:42 +00001098 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001099 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001100 tb->page_next[n] = p->first_tb;
1101 last_first_tb = p->first_tb;
1102 p->first_tb = (TranslationBlock *)((long)tb | n);
1103 invalidate_page_bitmap(p);
1104
bellard107db442004-06-22 18:48:46 +00001105#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001106
bellard9fa3e852004-01-04 18:06:42 +00001107#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001108 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001109 target_ulong addr;
1110 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001111 int prot;
1112
bellardfd6ce8f2003-05-14 19:00:11 +00001113 /* force the host page as non writable (writes will have a
1114 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001115 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001116 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001117 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1118 addr += TARGET_PAGE_SIZE) {
1119
1120 p2 = page_find (addr >> TARGET_PAGE_BITS);
1121 if (!p2)
1122 continue;
1123 prot |= p2->flags;
1124 p2->flags &= ~PAGE_WRITE;
1125 page_get_flags(addr);
1126 }
ths5fafdf22007-09-16 21:08:06 +00001127 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001128 (prot & PAGE_BITS) & ~PAGE_WRITE);
1129#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001130 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001131 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001132#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001133 }
bellard9fa3e852004-01-04 18:06:42 +00001134#else
1135 /* if some code is already present, then the pages are already
1136 protected. So we handle the case where only the first TB is
1137 allocated in a physical page */
1138 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001139 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001140 }
1141#endif
bellardd720b932004-04-25 17:57:43 +00001142
1143#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001144}
1145
1146/* Allocate a new translation block. Flush the translation buffer if
1147 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001148TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001149{
1150 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001151
bellard26a5f132008-05-28 12:30:31 +00001152 if (nb_tbs >= code_gen_max_blocks ||
1153 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001154 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001155 tb = &tbs[nb_tbs++];
1156 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001157 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001158 return tb;
1159}
1160
pbrook2e70f6e2008-06-29 01:03:05 +00001161void tb_free(TranslationBlock *tb)
1162{
thsbf20dc02008-06-30 17:22:19 +00001163 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001164 Ignore the hard cases and just back up if this TB happens to
1165 be the last one generated. */
1166 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1167 code_gen_ptr = tb->tc_ptr;
1168 nb_tbs--;
1169 }
1170}
1171
bellard9fa3e852004-01-04 18:06:42 +00001172/* add a new TB and link it to the physical page tables. phys_page2 is
1173 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001174void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001175 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001176{
bellard9fa3e852004-01-04 18:06:42 +00001177 unsigned int h;
1178 TranslationBlock **ptb;
1179
pbrookc8a706f2008-06-02 16:16:42 +00001180 /* Grab the mmap lock to stop another thread invalidating this TB
1181 before we are done. */
1182 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001183 /* add in the physical hash table */
1184 h = tb_phys_hash_func(phys_pc);
1185 ptb = &tb_phys_hash[h];
1186 tb->phys_hash_next = *ptb;
1187 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001188
1189 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001190 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1191 if (phys_page2 != -1)
1192 tb_alloc_page(tb, 1, phys_page2);
1193 else
1194 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001195
bellardd4e81642003-05-25 16:46:15 +00001196 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1197 tb->jmp_next[0] = NULL;
1198 tb->jmp_next[1] = NULL;
1199
1200 /* init original jump addresses */
1201 if (tb->tb_next_offset[0] != 0xffff)
1202 tb_reset_jump(tb, 0);
1203 if (tb->tb_next_offset[1] != 0xffff)
1204 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001205
1206#ifdef DEBUG_TB_CHECK
1207 tb_page_check();
1208#endif
pbrookc8a706f2008-06-02 16:16:42 +00001209 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001210}
1211
bellarda513fe12003-05-27 23:29:48 +00001212/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1213 tb[1].tc_ptr. Return NULL if not found */
1214TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1215{
1216 int m_min, m_max, m;
1217 unsigned long v;
1218 TranslationBlock *tb;
1219
1220 if (nb_tbs <= 0)
1221 return NULL;
1222 if (tc_ptr < (unsigned long)code_gen_buffer ||
1223 tc_ptr >= (unsigned long)code_gen_ptr)
1224 return NULL;
1225 /* binary search (cf Knuth) */
1226 m_min = 0;
1227 m_max = nb_tbs - 1;
1228 while (m_min <= m_max) {
1229 m = (m_min + m_max) >> 1;
1230 tb = &tbs[m];
1231 v = (unsigned long)tb->tc_ptr;
1232 if (v == tc_ptr)
1233 return tb;
1234 else if (tc_ptr < v) {
1235 m_max = m - 1;
1236 } else {
1237 m_min = m + 1;
1238 }
ths5fafdf22007-09-16 21:08:06 +00001239 }
bellarda513fe12003-05-27 23:29:48 +00001240 return &tbs[m_max];
1241}
bellard75012672003-06-21 13:11:07 +00001242
bellardea041c02003-06-25 16:16:50 +00001243static void tb_reset_jump_recursive(TranslationBlock *tb);
1244
1245static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1246{
1247 TranslationBlock *tb1, *tb_next, **ptb;
1248 unsigned int n1;
1249
1250 tb1 = tb->jmp_next[n];
1251 if (tb1 != NULL) {
1252 /* find head of list */
1253 for(;;) {
1254 n1 = (long)tb1 & 3;
1255 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1256 if (n1 == 2)
1257 break;
1258 tb1 = tb1->jmp_next[n1];
1259 }
1260 /* we are now sure now that tb jumps to tb1 */
1261 tb_next = tb1;
1262
1263 /* remove tb from the jmp_first list */
1264 ptb = &tb_next->jmp_first;
1265 for(;;) {
1266 tb1 = *ptb;
1267 n1 = (long)tb1 & 3;
1268 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1269 if (n1 == n && tb1 == tb)
1270 break;
1271 ptb = &tb1->jmp_next[n1];
1272 }
1273 *ptb = tb->jmp_next[n];
1274 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001275
bellardea041c02003-06-25 16:16:50 +00001276 /* suppress the jump to next tb in generated code */
1277 tb_reset_jump(tb, n);
1278
bellard01243112004-01-04 15:48:17 +00001279 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001280 tb_reset_jump_recursive(tb_next);
1281 }
1282}
1283
1284static void tb_reset_jump_recursive(TranslationBlock *tb)
1285{
1286 tb_reset_jump_recursive2(tb, 0);
1287 tb_reset_jump_recursive2(tb, 1);
1288}
1289
bellard1fddef42005-04-17 19:16:13 +00001290#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001291static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1292{
j_mayer9b3c35e2007-04-07 11:21:28 +00001293 target_phys_addr_t addr;
1294 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001295 ram_addr_t ram_addr;
1296 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001297
pbrookc2f07f82006-04-08 17:14:56 +00001298 addr = cpu_get_phys_page_debug(env, pc);
1299 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1300 if (!p) {
1301 pd = IO_MEM_UNASSIGNED;
1302 } else {
1303 pd = p->phys_offset;
1304 }
1305 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001306 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001307}
bellardc27004e2005-01-03 23:35:10 +00001308#endif
bellardd720b932004-04-25 17:57:43 +00001309
pbrook6658ffb2007-03-16 23:58:11 +00001310/* Add a watchpoint. */
aliguoria1d1bb32008-11-18 20:07:32 +00001311int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
1312 int flags, CPUWatchpoint **watchpoint)
pbrook6658ffb2007-03-16 23:58:11 +00001313{
aliguorib4051332008-11-18 20:14:20 +00001314 target_ulong len_mask = ~(len - 1);
aliguoric0ce9982008-11-25 22:13:57 +00001315 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001316
aliguorib4051332008-11-18 20:14:20 +00001317 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1318 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1319 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1320 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1321 return -EINVAL;
1322 }
aliguoria1d1bb32008-11-18 20:07:32 +00001323 wp = qemu_malloc(sizeof(*wp));
1324 if (!wp)
aliguori426cd5d2008-11-18 21:52:54 +00001325 return -ENOMEM;
pbrook6658ffb2007-03-16 23:58:11 +00001326
aliguoria1d1bb32008-11-18 20:07:32 +00001327 wp->vaddr = addr;
aliguorib4051332008-11-18 20:14:20 +00001328 wp->len_mask = len_mask;
aliguoria1d1bb32008-11-18 20:07:32 +00001329 wp->flags = flags;
1330
aliguori2dc9f412008-11-18 20:56:59 +00001331 /* keep all GDB-injected watchpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001332 if (flags & BP_GDB)
1333 TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
1334 else
1335 TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001336
pbrook6658ffb2007-03-16 23:58:11 +00001337 tlb_flush_page(env, addr);
aliguoria1d1bb32008-11-18 20:07:32 +00001338
1339 if (watchpoint)
1340 *watchpoint = wp;
1341 return 0;
pbrook6658ffb2007-03-16 23:58:11 +00001342}
1343
aliguoria1d1bb32008-11-18 20:07:32 +00001344/* Remove a specific watchpoint. */
1345int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
1346 int flags)
pbrook6658ffb2007-03-16 23:58:11 +00001347{
aliguorib4051332008-11-18 20:14:20 +00001348 target_ulong len_mask = ~(len - 1);
aliguoria1d1bb32008-11-18 20:07:32 +00001349 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001350
aliguoric0ce9982008-11-25 22:13:57 +00001351 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00001352 if (addr == wp->vaddr && len_mask == wp->len_mask
aliguori6e140f22008-11-18 20:37:55 +00001353 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
aliguoria1d1bb32008-11-18 20:07:32 +00001354 cpu_watchpoint_remove_by_ref(env, wp);
pbrook6658ffb2007-03-16 23:58:11 +00001355 return 0;
1356 }
1357 }
aliguoria1d1bb32008-11-18 20:07:32 +00001358 return -ENOENT;
pbrook6658ffb2007-03-16 23:58:11 +00001359}
1360
aliguoria1d1bb32008-11-18 20:07:32 +00001361/* Remove a specific watchpoint by reference. */
1362void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
1363{
aliguoric0ce9982008-11-25 22:13:57 +00001364 TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
edgar_igl7d03f822008-05-17 18:58:29 +00001365
aliguoria1d1bb32008-11-18 20:07:32 +00001366 tlb_flush_page(env, watchpoint->vaddr);
1367
1368 qemu_free(watchpoint);
edgar_igl7d03f822008-05-17 18:58:29 +00001369}
1370
aliguoria1d1bb32008-11-18 20:07:32 +00001371/* Remove all matching watchpoints. */
1372void cpu_watchpoint_remove_all(CPUState *env, int mask)
1373{
aliguoric0ce9982008-11-25 22:13:57 +00001374 CPUWatchpoint *wp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001375
aliguoric0ce9982008-11-25 22:13:57 +00001376 TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001377 if (wp->flags & mask)
1378 cpu_watchpoint_remove_by_ref(env, wp);
aliguoric0ce9982008-11-25 22:13:57 +00001379 }
aliguoria1d1bb32008-11-18 20:07:32 +00001380}
1381
1382/* Add a breakpoint. */
1383int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
1384 CPUBreakpoint **breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001385{
bellard1fddef42005-04-17 19:16:13 +00001386#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001387 CPUBreakpoint *bp;
ths3b46e622007-09-17 08:09:54 +00001388
aliguoria1d1bb32008-11-18 20:07:32 +00001389 bp = qemu_malloc(sizeof(*bp));
1390 if (!bp)
aliguori426cd5d2008-11-18 21:52:54 +00001391 return -ENOMEM;
aliguoria1d1bb32008-11-18 20:07:32 +00001392
1393 bp->pc = pc;
1394 bp->flags = flags;
1395
aliguori2dc9f412008-11-18 20:56:59 +00001396 /* keep all GDB-injected breakpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001397 if (flags & BP_GDB)
1398 TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
1399 else
1400 TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001401
1402 breakpoint_invalidate(env, pc);
1403
1404 if (breakpoint)
1405 *breakpoint = bp;
1406 return 0;
1407#else
1408 return -ENOSYS;
1409#endif
1410}
1411
1412/* Remove a specific breakpoint. */
1413int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
1414{
1415#if defined(TARGET_HAS_ICE)
1416 CPUBreakpoint *bp;
1417
aliguoric0ce9982008-11-25 22:13:57 +00001418 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001419 if (bp->pc == pc && bp->flags == flags) {
1420 cpu_breakpoint_remove_by_ref(env, bp);
bellard4c3a88a2003-07-26 12:06:08 +00001421 return 0;
aliguoria1d1bb32008-11-18 20:07:32 +00001422 }
bellard4c3a88a2003-07-26 12:06:08 +00001423 }
aliguoria1d1bb32008-11-18 20:07:32 +00001424 return -ENOENT;
bellard4c3a88a2003-07-26 12:06:08 +00001425#else
aliguoria1d1bb32008-11-18 20:07:32 +00001426 return -ENOSYS;
bellard4c3a88a2003-07-26 12:06:08 +00001427#endif
1428}
1429
aliguoria1d1bb32008-11-18 20:07:32 +00001430/* Remove a specific breakpoint by reference. */
1431void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001432{
bellard1fddef42005-04-17 19:16:13 +00001433#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001434 TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
bellardd720b932004-04-25 17:57:43 +00001435
aliguoria1d1bb32008-11-18 20:07:32 +00001436 breakpoint_invalidate(env, breakpoint->pc);
1437
1438 qemu_free(breakpoint);
1439#endif
1440}
1441
1442/* Remove all matching breakpoints. */
1443void cpu_breakpoint_remove_all(CPUState *env, int mask)
1444{
1445#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001446 CPUBreakpoint *bp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001447
aliguoric0ce9982008-11-25 22:13:57 +00001448 TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001449 if (bp->flags & mask)
1450 cpu_breakpoint_remove_by_ref(env, bp);
aliguoric0ce9982008-11-25 22:13:57 +00001451 }
bellard4c3a88a2003-07-26 12:06:08 +00001452#endif
1453}
1454
bellardc33a3462003-07-29 20:50:33 +00001455/* enable or disable single step mode. EXCP_DEBUG is returned by the
1456 CPU loop after each instruction */
1457void cpu_single_step(CPUState *env, int enabled)
1458{
bellard1fddef42005-04-17 19:16:13 +00001459#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001460 if (env->singlestep_enabled != enabled) {
1461 env->singlestep_enabled = enabled;
1462 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001463 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001464 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001465 }
1466#endif
1467}
1468
bellard34865132003-10-05 14:28:56 +00001469/* enable or disable low levels log */
1470void cpu_set_log(int log_flags)
1471{
1472 loglevel = log_flags;
1473 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001474 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001475 if (!logfile) {
1476 perror(logfilename);
1477 _exit(1);
1478 }
bellard9fa3e852004-01-04 18:06:42 +00001479#if !defined(CONFIG_SOFTMMU)
1480 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1481 {
blueswir1b55266b2008-09-20 08:07:15 +00001482 static char logfile_buf[4096];
bellard9fa3e852004-01-04 18:06:42 +00001483 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1484 }
1485#else
bellard34865132003-10-05 14:28:56 +00001486 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001487#endif
pbrooke735b912007-06-30 13:53:24 +00001488 log_append = 1;
1489 }
1490 if (!loglevel && logfile) {
1491 fclose(logfile);
1492 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001493 }
1494}
1495
1496void cpu_set_log_filename(const char *filename)
1497{
1498 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001499 if (logfile) {
1500 fclose(logfile);
1501 logfile = NULL;
1502 }
1503 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001504}
bellardc33a3462003-07-29 20:50:33 +00001505
bellard01243112004-01-04 15:48:17 +00001506/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001507void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001508{
pbrookd5975362008-06-07 20:50:51 +00001509#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001510 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001511 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001512#endif
pbrook2e70f6e2008-06-29 01:03:05 +00001513 int old_mask;
bellard59817cc2004-02-16 22:01:13 +00001514
pbrook2e70f6e2008-06-29 01:03:05 +00001515 old_mask = env->interrupt_request;
pbrookd5975362008-06-07 20:50:51 +00001516 /* FIXME: This is probably not threadsafe. A different thread could
thsbf20dc02008-06-30 17:22:19 +00001517 be in the middle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001518 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001519#if defined(USE_NPTL)
1520 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1521 problem and hope the cpu will stop of its own accord. For userspace
1522 emulation this often isn't actually as bad as it sounds. Often
1523 signals are used primarily to interrupt blocking syscalls. */
1524#else
pbrook2e70f6e2008-06-29 01:03:05 +00001525 if (use_icount) {
pbrook266910c2008-07-09 15:31:50 +00001526 env->icount_decr.u16.high = 0xffff;
pbrook2e70f6e2008-06-29 01:03:05 +00001527#ifndef CONFIG_USER_ONLY
1528 /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
1529 an async event happened and we need to process it. */
1530 if (!can_do_io(env)
1531 && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
1532 cpu_abort(env, "Raised interrupt while not in I/O function");
1533 }
1534#endif
1535 } else {
1536 tb = env->current_tb;
1537 /* if the cpu is currently executing code, we must unlink it and
1538 all the potentially executing TB */
1539 if (tb && !testandset(&interrupt_lock)) {
1540 env->current_tb = NULL;
1541 tb_reset_jump_recursive(tb);
1542 resetlock(&interrupt_lock);
1543 }
bellardea041c02003-06-25 16:16:50 +00001544 }
pbrookd5975362008-06-07 20:50:51 +00001545#endif
bellardea041c02003-06-25 16:16:50 +00001546}
1547
bellardb54ad042004-05-20 13:42:52 +00001548void cpu_reset_interrupt(CPUState *env, int mask)
1549{
1550 env->interrupt_request &= ~mask;
1551}
1552
blueswir1c7cd6a32008-10-02 18:27:46 +00001553const CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001554 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001555 "show generated host assembly code for each compiled TB" },
1556 { CPU_LOG_TB_IN_ASM, "in_asm",
1557 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001558 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001559 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001560 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001561 "show micro ops "
1562#ifdef TARGET_I386
1563 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001564#endif
blueswir1e01a1152008-03-14 17:37:11 +00001565 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001566 { CPU_LOG_INT, "int",
1567 "show interrupts/exceptions in short format" },
1568 { CPU_LOG_EXEC, "exec",
1569 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001570 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001571 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001572#ifdef TARGET_I386
1573 { CPU_LOG_PCALL, "pcall",
1574 "show protected mode far calls/returns/exceptions" },
1575#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001576#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001577 { CPU_LOG_IOPORT, "ioport",
1578 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001579#endif
bellardf193c792004-03-21 17:06:25 +00001580 { 0, NULL, NULL },
1581};
1582
1583static int cmp1(const char *s1, int n, const char *s2)
1584{
1585 if (strlen(s2) != n)
1586 return 0;
1587 return memcmp(s1, s2, n) == 0;
1588}
ths3b46e622007-09-17 08:09:54 +00001589
bellardf193c792004-03-21 17:06:25 +00001590/* takes a comma separated list of log masks. Return 0 if error. */
1591int cpu_str_to_log_mask(const char *str)
1592{
blueswir1c7cd6a32008-10-02 18:27:46 +00001593 const CPULogItem *item;
bellardf193c792004-03-21 17:06:25 +00001594 int mask;
1595 const char *p, *p1;
1596
1597 p = str;
1598 mask = 0;
1599 for(;;) {
1600 p1 = strchr(p, ',');
1601 if (!p1)
1602 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001603 if(cmp1(p,p1-p,"all")) {
1604 for(item = cpu_log_items; item->mask != 0; item++) {
1605 mask |= item->mask;
1606 }
1607 } else {
bellardf193c792004-03-21 17:06:25 +00001608 for(item = cpu_log_items; item->mask != 0; item++) {
1609 if (cmp1(p, p1 - p, item->name))
1610 goto found;
1611 }
1612 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001613 }
bellardf193c792004-03-21 17:06:25 +00001614 found:
1615 mask |= item->mask;
1616 if (*p1 != ',')
1617 break;
1618 p = p1 + 1;
1619 }
1620 return mask;
1621}
bellardea041c02003-06-25 16:16:50 +00001622
bellard75012672003-06-21 13:11:07 +00001623void cpu_abort(CPUState *env, const char *fmt, ...)
1624{
1625 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001626 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001627
1628 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001629 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001630 fprintf(stderr, "qemu: fatal: ");
1631 vfprintf(stderr, fmt, ap);
1632 fprintf(stderr, "\n");
1633#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001634 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1635#else
1636 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001637#endif
balrog924edca2007-06-10 14:07:13 +00001638 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001639 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001640 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001641 fprintf(logfile, "\n");
1642#ifdef TARGET_I386
1643 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1644#else
1645 cpu_dump_state(env, logfile, fprintf, 0);
1646#endif
balrog924edca2007-06-10 14:07:13 +00001647 fflush(logfile);
1648 fclose(logfile);
1649 }
pbrook493ae1f2007-11-23 16:53:59 +00001650 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001651 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001652 abort();
1653}
1654
thsc5be9f02007-02-28 20:20:53 +00001655CPUState *cpu_copy(CPUState *env)
1656{
ths01ba9812007-12-09 02:22:57 +00001657 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001658 /* preserve chaining and index */
1659 CPUState *next_cpu = new_env->next_cpu;
1660 int cpu_index = new_env->cpu_index;
1661 memcpy(new_env, env, sizeof(CPUState));
1662 new_env->next_cpu = next_cpu;
1663 new_env->cpu_index = cpu_index;
1664 return new_env;
1665}
1666
bellard01243112004-01-04 15:48:17 +00001667#if !defined(CONFIG_USER_ONLY)
1668
edgar_igl5c751e92008-05-06 08:44:21 +00001669static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1670{
1671 unsigned int i;
1672
1673 /* Discard jump cache entries for any tb which might potentially
1674 overlap the flushed page. */
1675 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1676 memset (&env->tb_jmp_cache[i], 0,
1677 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1678
1679 i = tb_jmp_cache_hash_page(addr);
1680 memset (&env->tb_jmp_cache[i], 0,
1681 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1682}
1683
bellardee8b7022004-02-03 23:35:10 +00001684/* NOTE: if flush_global is true, also flush global entries (not
1685 implemented yet) */
1686void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001687{
bellard33417e72003-08-10 21:47:01 +00001688 int i;
bellard01243112004-01-04 15:48:17 +00001689
bellard9fa3e852004-01-04 18:06:42 +00001690#if defined(DEBUG_TLB)
1691 printf("tlb_flush:\n");
1692#endif
bellard01243112004-01-04 15:48:17 +00001693 /* must reset current TB so that interrupts cannot modify the
1694 links while we are modifying them */
1695 env->current_tb = NULL;
1696
bellard33417e72003-08-10 21:47:01 +00001697 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001698 env->tlb_table[0][i].addr_read = -1;
1699 env->tlb_table[0][i].addr_write = -1;
1700 env->tlb_table[0][i].addr_code = -1;
1701 env->tlb_table[1][i].addr_read = -1;
1702 env->tlb_table[1][i].addr_write = -1;
1703 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001704#if (NB_MMU_MODES >= 3)
1705 env->tlb_table[2][i].addr_read = -1;
1706 env->tlb_table[2][i].addr_write = -1;
1707 env->tlb_table[2][i].addr_code = -1;
1708#if (NB_MMU_MODES == 4)
1709 env->tlb_table[3][i].addr_read = -1;
1710 env->tlb_table[3][i].addr_write = -1;
1711 env->tlb_table[3][i].addr_code = -1;
1712#endif
1713#endif
bellard33417e72003-08-10 21:47:01 +00001714 }
bellard9fa3e852004-01-04 18:06:42 +00001715
bellard8a40a182005-11-20 10:35:40 +00001716 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001717
bellard0a962c02005-02-10 22:00:27 +00001718#ifdef USE_KQEMU
1719 if (env->kqemu_enabled) {
1720 kqemu_flush(env, flush_global);
1721 }
1722#endif
bellarde3db7222005-01-26 22:00:47 +00001723 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001724}
1725
bellard274da6b2004-05-20 21:56:27 +00001726static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001727{
ths5fafdf22007-09-16 21:08:06 +00001728 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001729 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001730 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001731 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001732 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001733 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1734 tlb_entry->addr_read = -1;
1735 tlb_entry->addr_write = -1;
1736 tlb_entry->addr_code = -1;
1737 }
bellard61382a52003-10-27 21:22:23 +00001738}
1739
bellard2e126692004-04-25 21:28:44 +00001740void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001741{
bellard8a40a182005-11-20 10:35:40 +00001742 int i;
bellard01243112004-01-04 15:48:17 +00001743
bellard9fa3e852004-01-04 18:06:42 +00001744#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001745 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001746#endif
bellard01243112004-01-04 15:48:17 +00001747 /* must reset current TB so that interrupts cannot modify the
1748 links while we are modifying them */
1749 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001750
bellard61382a52003-10-27 21:22:23 +00001751 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001752 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001753 tlb_flush_entry(&env->tlb_table[0][i], addr);
1754 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001755#if (NB_MMU_MODES >= 3)
1756 tlb_flush_entry(&env->tlb_table[2][i], addr);
1757#if (NB_MMU_MODES == 4)
1758 tlb_flush_entry(&env->tlb_table[3][i], addr);
1759#endif
1760#endif
bellard01243112004-01-04 15:48:17 +00001761
edgar_igl5c751e92008-05-06 08:44:21 +00001762 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001763
bellard0a962c02005-02-10 22:00:27 +00001764#ifdef USE_KQEMU
1765 if (env->kqemu_enabled) {
1766 kqemu_flush_page(env, addr);
1767 }
1768#endif
bellard9fa3e852004-01-04 18:06:42 +00001769}
1770
bellard9fa3e852004-01-04 18:06:42 +00001771/* update the TLBs so that writes to code in the virtual page 'addr'
1772 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001773static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001774{
ths5fafdf22007-09-16 21:08:06 +00001775 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001776 ram_addr + TARGET_PAGE_SIZE,
1777 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001778}
1779
bellard9fa3e852004-01-04 18:06:42 +00001780/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001781 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001782static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001783 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001784{
bellard3a7d9292005-08-21 09:26:42 +00001785 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001786}
1787
ths5fafdf22007-09-16 21:08:06 +00001788static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001789 unsigned long start, unsigned long length)
1790{
1791 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001792 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1793 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001794 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001795 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001796 }
1797 }
1798}
1799
bellard3a7d9292005-08-21 09:26:42 +00001800void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001801 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001802{
1803 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001804 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001805 int i, mask, len;
1806 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001807
1808 start &= TARGET_PAGE_MASK;
1809 end = TARGET_PAGE_ALIGN(end);
1810
1811 length = end - start;
1812 if (length == 0)
1813 return;
bellard0a962c02005-02-10 22:00:27 +00001814 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001815#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001816 /* XXX: should not depend on cpu context */
1817 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001818 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001819 ram_addr_t addr;
1820 addr = start;
1821 for(i = 0; i < len; i++) {
1822 kqemu_set_notdirty(env, addr);
1823 addr += TARGET_PAGE_SIZE;
1824 }
bellard3a7d9292005-08-21 09:26:42 +00001825 }
1826#endif
bellardf23db162005-08-21 19:12:28 +00001827 mask = ~dirty_flags;
1828 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1829 for(i = 0; i < len; i++)
1830 p[i] &= mask;
1831
bellard1ccde1c2004-02-06 19:46:14 +00001832 /* we modify the TLB cache so that the dirty bit will be set again
1833 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001834 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001835 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1836 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001837 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001838 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001839 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001840#if (NB_MMU_MODES >= 3)
1841 for(i = 0; i < CPU_TLB_SIZE; i++)
1842 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1843#if (NB_MMU_MODES == 4)
1844 for(i = 0; i < CPU_TLB_SIZE; i++)
1845 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1846#endif
1847#endif
bellard6a00d602005-11-21 23:25:50 +00001848 }
bellard1ccde1c2004-02-06 19:46:14 +00001849}
1850
aliguori74576192008-10-06 14:02:03 +00001851int cpu_physical_memory_set_dirty_tracking(int enable)
1852{
1853 in_migration = enable;
1854 return 0;
1855}
1856
1857int cpu_physical_memory_get_dirty_tracking(void)
1858{
1859 return in_migration;
1860}
1861
aliguori2bec46d2008-11-24 20:21:41 +00001862void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
1863{
1864 if (kvm_enabled())
1865 kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1866}
1867
bellard3a7d9292005-08-21 09:26:42 +00001868static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1869{
1870 ram_addr_t ram_addr;
1871
bellard84b7b8e2005-11-28 21:19:04 +00001872 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001873 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001874 tlb_entry->addend - (unsigned long)phys_ram_base;
1875 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001876 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001877 }
1878 }
1879}
1880
1881/* update the TLB according to the current state of the dirty bits */
1882void cpu_tlb_update_dirty(CPUState *env)
1883{
1884 int i;
1885 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001886 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001887 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001888 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001889#if (NB_MMU_MODES >= 3)
1890 for(i = 0; i < CPU_TLB_SIZE; i++)
1891 tlb_update_dirty(&env->tlb_table[2][i]);
1892#if (NB_MMU_MODES == 4)
1893 for(i = 0; i < CPU_TLB_SIZE; i++)
1894 tlb_update_dirty(&env->tlb_table[3][i]);
1895#endif
1896#endif
bellard3a7d9292005-08-21 09:26:42 +00001897}
1898
pbrook0f459d12008-06-09 00:20:13 +00001899static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001900{
pbrook0f459d12008-06-09 00:20:13 +00001901 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1902 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001903}
1904
pbrook0f459d12008-06-09 00:20:13 +00001905/* update the TLB corresponding to virtual page vaddr
1906 so that it is no longer dirty */
1907static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001908{
bellard1ccde1c2004-02-06 19:46:14 +00001909 int i;
1910
pbrook0f459d12008-06-09 00:20:13 +00001911 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001912 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001913 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1914 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001915#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001916 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001917#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001918 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001919#endif
1920#endif
bellard9fa3e852004-01-04 18:06:42 +00001921}
1922
bellard59817cc2004-02-16 22:01:13 +00001923/* add a new TLB entry. At most one entry for a given virtual address
1924 is permitted. Return 0 if OK or 2 if the page could not be mapped
1925 (can only happen in non SOFTMMU mode for I/O pages or pages
1926 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001927int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1928 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001929 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001930{
bellard92e873b2004-05-21 14:52:29 +00001931 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001932 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001933 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001934 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001935 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001936 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001937 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001938 CPUTLBEntry *te;
aliguoria1d1bb32008-11-18 20:07:32 +00001939 CPUWatchpoint *wp;
pbrook0f459d12008-06-09 00:20:13 +00001940 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001941
bellard92e873b2004-05-21 14:52:29 +00001942 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001943 if (!p) {
1944 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001945 } else {
1946 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001947 }
1948#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001949 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1950 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001951#endif
1952
1953 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001954 address = vaddr;
1955 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1956 /* IO memory case (romd handled later) */
1957 address |= TLB_MMIO;
1958 }
1959 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1960 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1961 /* Normal RAM. */
1962 iotlb = pd & TARGET_PAGE_MASK;
1963 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1964 iotlb |= IO_MEM_NOTDIRTY;
1965 else
1966 iotlb |= IO_MEM_ROM;
1967 } else {
1968 /* IO handlers are currently passed a phsical address.
1969 It would be nice to pass an offset from the base address
1970 of that region. This would avoid having to special case RAM,
1971 and avoid full address decoding in every device.
1972 We can't use the high bits of pd for this because
1973 IO_MEM_ROMD uses these as a ram address. */
pbrook8da3ff12008-12-01 18:59:50 +00001974 iotlb = (pd & ~TARGET_PAGE_MASK);
1975 if (p) {
pbrook8da3ff12008-12-01 18:59:50 +00001976 iotlb += p->region_offset;
1977 } else {
1978 iotlb += paddr;
1979 }
pbrook0f459d12008-06-09 00:20:13 +00001980 }
pbrook6658ffb2007-03-16 23:58:11 +00001981
pbrook0f459d12008-06-09 00:20:13 +00001982 code_address = address;
1983 /* Make accesses to pages with watchpoints go via the
1984 watchpoint trap routines. */
aliguoric0ce9982008-11-25 22:13:57 +00001985 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001986 if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
pbrook0f459d12008-06-09 00:20:13 +00001987 iotlb = io_mem_watch + paddr;
1988 /* TODO: The memory case can be optimized by not trapping
1989 reads of pages with a write breakpoint. */
1990 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00001991 }
pbrook0f459d12008-06-09 00:20:13 +00001992 }
balrogd79acba2007-06-26 20:01:13 +00001993
pbrook0f459d12008-06-09 00:20:13 +00001994 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1995 env->iotlb[mmu_idx][index] = iotlb - vaddr;
1996 te = &env->tlb_table[mmu_idx][index];
1997 te->addend = addend - vaddr;
1998 if (prot & PAGE_READ) {
1999 te->addr_read = address;
2000 } else {
2001 te->addr_read = -1;
2002 }
edgar_igl5c751e92008-05-06 08:44:21 +00002003
pbrook0f459d12008-06-09 00:20:13 +00002004 if (prot & PAGE_EXEC) {
2005 te->addr_code = code_address;
2006 } else {
2007 te->addr_code = -1;
2008 }
2009 if (prot & PAGE_WRITE) {
2010 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
2011 (pd & IO_MEM_ROMD)) {
2012 /* Write access calls the I/O callback. */
2013 te->addr_write = address | TLB_MMIO;
2014 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2015 !cpu_physical_memory_is_dirty(pd)) {
2016 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00002017 } else {
pbrook0f459d12008-06-09 00:20:13 +00002018 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00002019 }
pbrook0f459d12008-06-09 00:20:13 +00002020 } else {
2021 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00002022 }
bellard9fa3e852004-01-04 18:06:42 +00002023 return ret;
2024}
2025
bellard01243112004-01-04 15:48:17 +00002026#else
2027
bellardee8b7022004-02-03 23:35:10 +00002028void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00002029{
2030}
2031
bellard2e126692004-04-25 21:28:44 +00002032void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00002033{
2034}
2035
ths5fafdf22007-09-16 21:08:06 +00002036int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
2037 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00002038 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00002039{
bellard9fa3e852004-01-04 18:06:42 +00002040 return 0;
2041}
bellard33417e72003-08-10 21:47:01 +00002042
bellard9fa3e852004-01-04 18:06:42 +00002043/* dump memory mappings */
2044void page_dump(FILE *f)
2045{
2046 unsigned long start, end;
2047 int i, j, prot, prot1;
2048 PageDesc *p;
2049
2050 fprintf(f, "%-8s %-8s %-8s %s\n",
2051 "start", "end", "size", "prot");
2052 start = -1;
2053 end = -1;
2054 prot = 0;
2055 for(i = 0; i <= L1_SIZE; i++) {
2056 if (i < L1_SIZE)
2057 p = l1_map[i];
2058 else
2059 p = NULL;
2060 for(j = 0;j < L2_SIZE; j++) {
2061 if (!p)
2062 prot1 = 0;
2063 else
2064 prot1 = p[j].flags;
2065 if (prot1 != prot) {
2066 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2067 if (start != -1) {
2068 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00002069 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00002070 prot & PAGE_READ ? 'r' : '-',
2071 prot & PAGE_WRITE ? 'w' : '-',
2072 prot & PAGE_EXEC ? 'x' : '-');
2073 }
2074 if (prot1 != 0)
2075 start = end;
2076 else
2077 start = -1;
2078 prot = prot1;
2079 }
2080 if (!p)
2081 break;
2082 }
bellard33417e72003-08-10 21:47:01 +00002083 }
bellard33417e72003-08-10 21:47:01 +00002084}
2085
pbrook53a59602006-03-25 19:31:22 +00002086int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002087{
bellard9fa3e852004-01-04 18:06:42 +00002088 PageDesc *p;
2089
2090 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002091 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002092 return 0;
2093 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002094}
2095
bellard9fa3e852004-01-04 18:06:42 +00002096/* modify the flags of a page and invalidate the code if
2097 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2098 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002099void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002100{
2101 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002102 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002103
pbrookc8a706f2008-06-02 16:16:42 +00002104 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002105 start = start & TARGET_PAGE_MASK;
2106 end = TARGET_PAGE_ALIGN(end);
2107 if (flags & PAGE_WRITE)
2108 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002109 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2110 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00002111 /* We may be called for host regions that are outside guest
2112 address space. */
2113 if (!p)
2114 return;
bellard9fa3e852004-01-04 18:06:42 +00002115 /* if the write protection is set, then we invalidate the code
2116 inside */
ths5fafdf22007-09-16 21:08:06 +00002117 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002118 (flags & PAGE_WRITE) &&
2119 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002120 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002121 }
2122 p->flags = flags;
2123 }
bellard9fa3e852004-01-04 18:06:42 +00002124}
2125
ths3d97b402007-11-02 19:02:07 +00002126int page_check_range(target_ulong start, target_ulong len, int flags)
2127{
2128 PageDesc *p;
2129 target_ulong end;
2130 target_ulong addr;
2131
balrog55f280c2008-10-28 10:24:11 +00002132 if (start + len < start)
2133 /* we've wrapped around */
2134 return -1;
2135
ths3d97b402007-11-02 19:02:07 +00002136 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2137 start = start & TARGET_PAGE_MASK;
2138
ths3d97b402007-11-02 19:02:07 +00002139 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2140 p = page_find(addr >> TARGET_PAGE_BITS);
2141 if( !p )
2142 return -1;
2143 if( !(p->flags & PAGE_VALID) )
2144 return -1;
2145
bellarddae32702007-11-14 10:51:00 +00002146 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002147 return -1;
bellarddae32702007-11-14 10:51:00 +00002148 if (flags & PAGE_WRITE) {
2149 if (!(p->flags & PAGE_WRITE_ORG))
2150 return -1;
2151 /* unprotect the page if it was put read-only because it
2152 contains translated code */
2153 if (!(p->flags & PAGE_WRITE)) {
2154 if (!page_unprotect(addr, 0, NULL))
2155 return -1;
2156 }
2157 return 0;
2158 }
ths3d97b402007-11-02 19:02:07 +00002159 }
2160 return 0;
2161}
2162
bellard9fa3e852004-01-04 18:06:42 +00002163/* called from signal handler: invalidate the code and unprotect the
2164 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002165int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002166{
2167 unsigned int page_index, prot, pindex;
2168 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002169 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002170
pbrookc8a706f2008-06-02 16:16:42 +00002171 /* Technically this isn't safe inside a signal handler. However we
2172 know this only ever happens in a synchronous SEGV handler, so in
2173 practice it seems to be ok. */
2174 mmap_lock();
2175
bellard83fb7ad2004-07-05 21:25:26 +00002176 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002177 page_index = host_start >> TARGET_PAGE_BITS;
2178 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002179 if (!p1) {
2180 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002181 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002182 }
bellard83fb7ad2004-07-05 21:25:26 +00002183 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002184 p = p1;
2185 prot = 0;
2186 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2187 prot |= p->flags;
2188 p++;
2189 }
2190 /* if the page was really writable, then we change its
2191 protection back to writable */
2192 if (prot & PAGE_WRITE_ORG) {
2193 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2194 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002195 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002196 (prot & PAGE_BITS) | PAGE_WRITE);
2197 p1[pindex].flags |= PAGE_WRITE;
2198 /* and since the content will be modified, we must invalidate
2199 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002200 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002201#ifdef DEBUG_TB_CHECK
2202 tb_invalidate_check(address);
2203#endif
pbrookc8a706f2008-06-02 16:16:42 +00002204 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002205 return 1;
2206 }
2207 }
pbrookc8a706f2008-06-02 16:16:42 +00002208 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002209 return 0;
2210}
2211
bellard6a00d602005-11-21 23:25:50 +00002212static inline void tlb_set_dirty(CPUState *env,
2213 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002214{
2215}
bellard9fa3e852004-01-04 18:06:42 +00002216#endif /* defined(CONFIG_USER_ONLY) */
2217
pbrooke2eef172008-06-08 01:09:01 +00002218#if !defined(CONFIG_USER_ONLY)
pbrook8da3ff12008-12-01 18:59:50 +00002219
blueswir1db7b5422007-05-26 17:36:03 +00002220static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002221 ram_addr_t memory, ram_addr_t region_offset);
aurel3200f82b82008-04-27 21:12:55 +00002222static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002223 ram_addr_t orig_memory, ram_addr_t region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002224#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2225 need_subpage) \
2226 do { \
2227 if (addr > start_addr) \
2228 start_addr2 = 0; \
2229 else { \
2230 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2231 if (start_addr2 > 0) \
2232 need_subpage = 1; \
2233 } \
2234 \
blueswir149e9fba2007-05-30 17:25:06 +00002235 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002236 end_addr2 = TARGET_PAGE_SIZE - 1; \
2237 else { \
2238 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2239 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2240 need_subpage = 1; \
2241 } \
2242 } while (0)
2243
bellard33417e72003-08-10 21:47:01 +00002244/* register physical memory. 'size' must be a multiple of the target
2245 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
pbrook8da3ff12008-12-01 18:59:50 +00002246 io memory page. The address used when calling the IO function is
2247 the offset from the start of the region, plus region_offset. Both
2248 start_region and regon_offset are rounded down to a page boundary
2249 before calculating this offset. This should not be a problem unless
2250 the low bits of start_addr and region_offset differ. */
2251void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2252 ram_addr_t size,
2253 ram_addr_t phys_offset,
2254 ram_addr_t region_offset)
bellard33417e72003-08-10 21:47:01 +00002255{
bellard108c49b2005-07-24 12:55:09 +00002256 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002257 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002258 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002259 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002260 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002261
bellardda260242008-05-30 20:48:25 +00002262#ifdef USE_KQEMU
2263 /* XXX: should not depend on cpu context */
2264 env = first_cpu;
2265 if (env->kqemu_enabled) {
2266 kqemu_set_phys_mem(start_addr, size, phys_offset);
2267 }
2268#endif
aliguori7ba1e612008-11-05 16:04:33 +00002269 if (kvm_enabled())
2270 kvm_set_phys_mem(start_addr, size, phys_offset);
2271
pbrook8da3ff12008-12-01 18:59:50 +00002272 region_offset &= TARGET_PAGE_MASK;
bellard5fd386f2004-05-23 21:11:22 +00002273 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002274 end_addr = start_addr + (target_phys_addr_t)size;
2275 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002276 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2277 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002278 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002279 target_phys_addr_t start_addr2, end_addr2;
2280 int need_subpage = 0;
2281
2282 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2283 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002284 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002285 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2286 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002287 &p->phys_offset, orig_memory,
2288 p->region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002289 } else {
2290 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2291 >> IO_MEM_SHIFT];
2292 }
pbrook8da3ff12008-12-01 18:59:50 +00002293 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2294 region_offset);
2295 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002296 } else {
2297 p->phys_offset = phys_offset;
2298 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2299 (phys_offset & IO_MEM_ROMD))
2300 phys_offset += TARGET_PAGE_SIZE;
2301 }
2302 } else {
2303 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2304 p->phys_offset = phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +00002305 p->region_offset = region_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002306 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
pbrook8da3ff12008-12-01 18:59:50 +00002307 (phys_offset & IO_MEM_ROMD)) {
blueswir1db7b5422007-05-26 17:36:03 +00002308 phys_offset += TARGET_PAGE_SIZE;
pbrook0e8f0962008-12-02 09:02:15 +00002309 } else {
blueswir1db7b5422007-05-26 17:36:03 +00002310 target_phys_addr_t start_addr2, end_addr2;
2311 int need_subpage = 0;
2312
2313 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2314 end_addr2, need_subpage);
2315
blueswir14254fab2008-01-01 16:57:19 +00002316 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002317 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002318 &p->phys_offset, IO_MEM_UNASSIGNED,
2319 0);
blueswir1db7b5422007-05-26 17:36:03 +00002320 subpage_register(subpage, start_addr2, end_addr2,
pbrook8da3ff12008-12-01 18:59:50 +00002321 phys_offset, region_offset);
2322 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002323 }
2324 }
2325 }
pbrook8da3ff12008-12-01 18:59:50 +00002326 region_offset += TARGET_PAGE_SIZE;
bellard33417e72003-08-10 21:47:01 +00002327 }
ths3b46e622007-09-17 08:09:54 +00002328
bellard9d420372006-06-25 22:25:22 +00002329 /* since each CPU stores ram addresses in its TLB cache, we must
2330 reset the modified entries */
2331 /* XXX: slow ! */
2332 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2333 tlb_flush(env, 1);
2334 }
bellard33417e72003-08-10 21:47:01 +00002335}
2336
bellardba863452006-09-24 18:41:10 +00002337/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002338ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002339{
2340 PhysPageDesc *p;
2341
2342 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2343 if (!p)
2344 return IO_MEM_UNASSIGNED;
2345 return p->phys_offset;
2346}
2347
bellarde9a1ab12007-02-08 23:08:38 +00002348/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002349ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002350{
2351 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002352 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
ths012a7042008-10-02 17:34:21 +00002353 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
bellarded441462008-05-23 11:56:45 +00002354 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002355 abort();
2356 }
2357 addr = phys_ram_alloc_offset;
2358 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2359 return addr;
2360}
2361
2362void qemu_ram_free(ram_addr_t addr)
2363{
2364}
2365
bellarda4193c82004-06-03 14:01:43 +00002366static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002367{
pbrook67d3b952006-12-18 05:03:52 +00002368#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002369 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002370#endif
blueswir1e18231a2008-10-06 18:46:28 +00002371#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2372 do_unassigned_access(addr, 0, 0, 0, 1);
2373#endif
2374 return 0;
2375}
2376
2377static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
2378{
2379#ifdef DEBUG_UNASSIGNED
2380 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2381#endif
2382#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2383 do_unassigned_access(addr, 0, 0, 0, 2);
2384#endif
2385 return 0;
2386}
2387
2388static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
2389{
2390#ifdef DEBUG_UNASSIGNED
2391 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2392#endif
2393#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2394 do_unassigned_access(addr, 0, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002395#endif
bellard33417e72003-08-10 21:47:01 +00002396 return 0;
2397}
2398
bellarda4193c82004-06-03 14:01:43 +00002399static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002400{
pbrook67d3b952006-12-18 05:03:52 +00002401#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002402 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002403#endif
blueswir1e18231a2008-10-06 18:46:28 +00002404#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2405 do_unassigned_access(addr, 1, 0, 0, 1);
2406#endif
2407}
2408
2409static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2410{
2411#ifdef DEBUG_UNASSIGNED
2412 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2413#endif
2414#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2415 do_unassigned_access(addr, 1, 0, 0, 2);
2416#endif
2417}
2418
2419static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2420{
2421#ifdef DEBUG_UNASSIGNED
2422 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2423#endif
2424#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
2425 do_unassigned_access(addr, 1, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002426#endif
bellard33417e72003-08-10 21:47:01 +00002427}
2428
2429static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2430 unassigned_mem_readb,
blueswir1e18231a2008-10-06 18:46:28 +00002431 unassigned_mem_readw,
2432 unassigned_mem_readl,
bellard33417e72003-08-10 21:47:01 +00002433};
2434
2435static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2436 unassigned_mem_writeb,
blueswir1e18231a2008-10-06 18:46:28 +00002437 unassigned_mem_writew,
2438 unassigned_mem_writel,
bellard33417e72003-08-10 21:47:01 +00002439};
2440
pbrook0f459d12008-06-09 00:20:13 +00002441static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2442 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002443{
bellard3a7d9292005-08-21 09:26:42 +00002444 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002445 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2446 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2447#if !defined(CONFIG_USER_ONLY)
2448 tb_invalidate_phys_page_fast(ram_addr, 1);
2449 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2450#endif
2451 }
pbrook0f459d12008-06-09 00:20:13 +00002452 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002453#ifdef USE_KQEMU
2454 if (cpu_single_env->kqemu_enabled &&
2455 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2456 kqemu_modify_page(cpu_single_env, ram_addr);
2457#endif
bellardf23db162005-08-21 19:12:28 +00002458 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2459 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2460 /* we remove the notdirty callback only if the code has been
2461 flushed */
2462 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002463 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002464}
2465
pbrook0f459d12008-06-09 00:20:13 +00002466static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2467 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002468{
bellard3a7d9292005-08-21 09:26:42 +00002469 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002470 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2471 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2472#if !defined(CONFIG_USER_ONLY)
2473 tb_invalidate_phys_page_fast(ram_addr, 2);
2474 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2475#endif
2476 }
pbrook0f459d12008-06-09 00:20:13 +00002477 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002478#ifdef USE_KQEMU
2479 if (cpu_single_env->kqemu_enabled &&
2480 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2481 kqemu_modify_page(cpu_single_env, ram_addr);
2482#endif
bellardf23db162005-08-21 19:12:28 +00002483 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2484 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2485 /* we remove the notdirty callback only if the code has been
2486 flushed */
2487 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002488 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002489}
2490
pbrook0f459d12008-06-09 00:20:13 +00002491static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2492 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002493{
bellard3a7d9292005-08-21 09:26:42 +00002494 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002495 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2496 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2497#if !defined(CONFIG_USER_ONLY)
2498 tb_invalidate_phys_page_fast(ram_addr, 4);
2499 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2500#endif
2501 }
pbrook0f459d12008-06-09 00:20:13 +00002502 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002503#ifdef USE_KQEMU
2504 if (cpu_single_env->kqemu_enabled &&
2505 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2506 kqemu_modify_page(cpu_single_env, ram_addr);
2507#endif
bellardf23db162005-08-21 19:12:28 +00002508 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2509 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2510 /* we remove the notdirty callback only if the code has been
2511 flushed */
2512 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002513 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002514}
2515
bellard3a7d9292005-08-21 09:26:42 +00002516static CPUReadMemoryFunc *error_mem_read[3] = {
2517 NULL, /* never used */
2518 NULL, /* never used */
2519 NULL, /* never used */
2520};
2521
bellard1ccde1c2004-02-06 19:46:14 +00002522static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2523 notdirty_mem_writeb,
2524 notdirty_mem_writew,
2525 notdirty_mem_writel,
2526};
2527
pbrook0f459d12008-06-09 00:20:13 +00002528/* Generate a debug exception if a watchpoint has been hit. */
aliguorib4051332008-11-18 20:14:20 +00002529static void check_watchpoint(int offset, int len_mask, int flags)
pbrook0f459d12008-06-09 00:20:13 +00002530{
2531 CPUState *env = cpu_single_env;
aliguori06d55cc2008-11-18 20:24:06 +00002532 target_ulong pc, cs_base;
2533 TranslationBlock *tb;
pbrook0f459d12008-06-09 00:20:13 +00002534 target_ulong vaddr;
aliguoria1d1bb32008-11-18 20:07:32 +00002535 CPUWatchpoint *wp;
aliguori06d55cc2008-11-18 20:24:06 +00002536 int cpu_flags;
pbrook0f459d12008-06-09 00:20:13 +00002537
aliguori06d55cc2008-11-18 20:24:06 +00002538 if (env->watchpoint_hit) {
2539 /* We re-entered the check after replacing the TB. Now raise
2540 * the debug interrupt so that is will trigger after the
2541 * current instruction. */
2542 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2543 return;
2544 }
pbrook2e70f6e2008-06-29 01:03:05 +00002545 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
aliguoric0ce9982008-11-25 22:13:57 +00002546 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00002547 if ((vaddr == (wp->vaddr & len_mask) ||
2548 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
aliguori6e140f22008-11-18 20:37:55 +00002549 wp->flags |= BP_WATCHPOINT_HIT;
2550 if (!env->watchpoint_hit) {
2551 env->watchpoint_hit = wp;
2552 tb = tb_find_pc(env->mem_io_pc);
2553 if (!tb) {
2554 cpu_abort(env, "check_watchpoint: could not find TB for "
2555 "pc=%p", (void *)env->mem_io_pc);
2556 }
2557 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
2558 tb_phys_invalidate(tb, -1);
2559 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2560 env->exception_index = EXCP_DEBUG;
2561 } else {
2562 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2563 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2564 }
2565 cpu_resume_from_signal(env, NULL);
aliguori06d55cc2008-11-18 20:24:06 +00002566 }
aliguori6e140f22008-11-18 20:37:55 +00002567 } else {
2568 wp->flags &= ~BP_WATCHPOINT_HIT;
pbrook0f459d12008-06-09 00:20:13 +00002569 }
2570 }
2571}
2572
pbrook6658ffb2007-03-16 23:58:11 +00002573/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2574 so these check for a hit then pass through to the normal out-of-line
2575 phys routines. */
2576static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2577{
aliguorib4051332008-11-18 20:14:20 +00002578 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002579 return ldub_phys(addr);
2580}
2581
2582static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2583{
aliguorib4051332008-11-18 20:14:20 +00002584 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002585 return lduw_phys(addr);
2586}
2587
2588static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2589{
aliguorib4051332008-11-18 20:14:20 +00002590 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002591 return ldl_phys(addr);
2592}
2593
pbrook6658ffb2007-03-16 23:58:11 +00002594static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2595 uint32_t val)
2596{
aliguorib4051332008-11-18 20:14:20 +00002597 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002598 stb_phys(addr, val);
2599}
2600
2601static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2602 uint32_t val)
2603{
aliguorib4051332008-11-18 20:14:20 +00002604 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002605 stw_phys(addr, val);
2606}
2607
2608static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2609 uint32_t val)
2610{
aliguorib4051332008-11-18 20:14:20 +00002611 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002612 stl_phys(addr, val);
2613}
2614
2615static CPUReadMemoryFunc *watch_mem_read[3] = {
2616 watch_mem_readb,
2617 watch_mem_readw,
2618 watch_mem_readl,
2619};
2620
2621static CPUWriteMemoryFunc *watch_mem_write[3] = {
2622 watch_mem_writeb,
2623 watch_mem_writew,
2624 watch_mem_writel,
2625};
pbrook6658ffb2007-03-16 23:58:11 +00002626
blueswir1db7b5422007-05-26 17:36:03 +00002627static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2628 unsigned int len)
2629{
blueswir1db7b5422007-05-26 17:36:03 +00002630 uint32_t ret;
2631 unsigned int idx;
2632
pbrook8da3ff12008-12-01 18:59:50 +00002633 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002634#if defined(DEBUG_SUBPAGE)
2635 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2636 mmio, len, addr, idx);
2637#endif
pbrook8da3ff12008-12-01 18:59:50 +00002638 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2639 addr + mmio->region_offset[idx][0][len]);
blueswir1db7b5422007-05-26 17:36:03 +00002640
2641 return ret;
2642}
2643
2644static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2645 uint32_t value, unsigned int len)
2646{
blueswir1db7b5422007-05-26 17:36:03 +00002647 unsigned int idx;
2648
pbrook8da3ff12008-12-01 18:59:50 +00002649 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002650#if defined(DEBUG_SUBPAGE)
2651 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2652 mmio, len, addr, idx, value);
2653#endif
pbrook8da3ff12008-12-01 18:59:50 +00002654 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2655 addr + mmio->region_offset[idx][1][len],
2656 value);
blueswir1db7b5422007-05-26 17:36:03 +00002657}
2658
2659static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2660{
2661#if defined(DEBUG_SUBPAGE)
2662 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2663#endif
2664
2665 return subpage_readlen(opaque, addr, 0);
2666}
2667
2668static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2669 uint32_t value)
2670{
2671#if defined(DEBUG_SUBPAGE)
2672 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2673#endif
2674 subpage_writelen(opaque, addr, value, 0);
2675}
2676
2677static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2678{
2679#if defined(DEBUG_SUBPAGE)
2680 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2681#endif
2682
2683 return subpage_readlen(opaque, addr, 1);
2684}
2685
2686static void subpage_writew (void *opaque, target_phys_addr_t addr,
2687 uint32_t value)
2688{
2689#if defined(DEBUG_SUBPAGE)
2690 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2691#endif
2692 subpage_writelen(opaque, addr, value, 1);
2693}
2694
2695static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2696{
2697#if defined(DEBUG_SUBPAGE)
2698 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2699#endif
2700
2701 return subpage_readlen(opaque, addr, 2);
2702}
2703
2704static void subpage_writel (void *opaque,
2705 target_phys_addr_t addr, uint32_t value)
2706{
2707#if defined(DEBUG_SUBPAGE)
2708 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2709#endif
2710 subpage_writelen(opaque, addr, value, 2);
2711}
2712
2713static CPUReadMemoryFunc *subpage_read[] = {
2714 &subpage_readb,
2715 &subpage_readw,
2716 &subpage_readl,
2717};
2718
2719static CPUWriteMemoryFunc *subpage_write[] = {
2720 &subpage_writeb,
2721 &subpage_writew,
2722 &subpage_writel,
2723};
2724
2725static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002726 ram_addr_t memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002727{
2728 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002729 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002730
2731 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2732 return -1;
2733 idx = SUBPAGE_IDX(start);
2734 eidx = SUBPAGE_IDX(end);
2735#if defined(DEBUG_SUBPAGE)
2736 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2737 mmio, start, end, idx, eidx, memory);
2738#endif
2739 memory >>= IO_MEM_SHIFT;
2740 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002741 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002742 if (io_mem_read[memory][i]) {
2743 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2744 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002745 mmio->region_offset[idx][0][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002746 }
2747 if (io_mem_write[memory][i]) {
2748 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2749 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002750 mmio->region_offset[idx][1][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002751 }
blueswir14254fab2008-01-01 16:57:19 +00002752 }
blueswir1db7b5422007-05-26 17:36:03 +00002753 }
2754
2755 return 0;
2756}
2757
aurel3200f82b82008-04-27 21:12:55 +00002758static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002759 ram_addr_t orig_memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002760{
2761 subpage_t *mmio;
2762 int subpage_memory;
2763
2764 mmio = qemu_mallocz(sizeof(subpage_t));
2765 if (mmio != NULL) {
2766 mmio->base = base;
2767 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2768#if defined(DEBUG_SUBPAGE)
2769 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2770 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2771#endif
2772 *phys = subpage_memory | IO_MEM_SUBPAGE;
pbrook8da3ff12008-12-01 18:59:50 +00002773 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
2774 region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002775 }
2776
2777 return mmio;
2778}
2779
bellard33417e72003-08-10 21:47:01 +00002780static void io_mem_init(void)
2781{
bellard3a7d9292005-08-21 09:26:42 +00002782 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002783 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002784 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002785 io_mem_nb = 5;
2786
pbrook0f459d12008-06-09 00:20:13 +00002787 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002788 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002789 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002790 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002791 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002792}
2793
2794/* mem_read and mem_write are arrays of functions containing the
2795 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002796 2). Functions can be omitted with a NULL function pointer. The
2797 registered functions may be modified dynamically later.
2798 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002799 modified. If it is zero, a new io zone is allocated. The return
2800 value can be used with cpu_register_physical_memory(). (-1) is
2801 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002802int cpu_register_io_memory(int io_index,
2803 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002804 CPUWriteMemoryFunc **mem_write,
2805 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002806{
blueswir14254fab2008-01-01 16:57:19 +00002807 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002808
2809 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002810 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002811 return -1;
2812 io_index = io_mem_nb++;
2813 } else {
2814 if (io_index >= IO_MEM_NB_ENTRIES)
2815 return -1;
2816 }
bellardb5ff1b32005-11-26 10:38:39 +00002817
bellard33417e72003-08-10 21:47:01 +00002818 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002819 if (!mem_read[i] || !mem_write[i])
2820 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002821 io_mem_read[io_index][i] = mem_read[i];
2822 io_mem_write[io_index][i] = mem_write[i];
2823 }
bellarda4193c82004-06-03 14:01:43 +00002824 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002825 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002826}
bellard61382a52003-10-27 21:22:23 +00002827
bellard8926b512004-10-10 15:14:20 +00002828CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2829{
2830 return io_mem_write[io_index >> IO_MEM_SHIFT];
2831}
2832
2833CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2834{
2835 return io_mem_read[io_index >> IO_MEM_SHIFT];
2836}
2837
pbrooke2eef172008-06-08 01:09:01 +00002838#endif /* !defined(CONFIG_USER_ONLY) */
2839
bellard13eb76e2004-01-24 15:23:36 +00002840/* physical memory access (slow version, mainly for debug) */
2841#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002842void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002843 int len, int is_write)
2844{
2845 int l, flags;
2846 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002847 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002848
2849 while (len > 0) {
2850 page = addr & TARGET_PAGE_MASK;
2851 l = (page + TARGET_PAGE_SIZE) - addr;
2852 if (l > len)
2853 l = len;
2854 flags = page_get_flags(page);
2855 if (!(flags & PAGE_VALID))
2856 return;
2857 if (is_write) {
2858 if (!(flags & PAGE_WRITE))
2859 return;
bellard579a97f2007-11-11 14:26:47 +00002860 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002861 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002862 /* FIXME - should this return an error rather than just fail? */
2863 return;
aurel3272fb7da2008-04-27 23:53:45 +00002864 memcpy(p, buf, l);
2865 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002866 } else {
2867 if (!(flags & PAGE_READ))
2868 return;
bellard579a97f2007-11-11 14:26:47 +00002869 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002870 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002871 /* FIXME - should this return an error rather than just fail? */
2872 return;
aurel3272fb7da2008-04-27 23:53:45 +00002873 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002874 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002875 }
2876 len -= l;
2877 buf += l;
2878 addr += l;
2879 }
2880}
bellard8df1cd02005-01-28 22:37:22 +00002881
bellard13eb76e2004-01-24 15:23:36 +00002882#else
ths5fafdf22007-09-16 21:08:06 +00002883void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002884 int len, int is_write)
2885{
2886 int l, io_index;
2887 uint8_t *ptr;
2888 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002889 target_phys_addr_t page;
2890 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002891 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002892
bellard13eb76e2004-01-24 15:23:36 +00002893 while (len > 0) {
2894 page = addr & TARGET_PAGE_MASK;
2895 l = (page + TARGET_PAGE_SIZE) - addr;
2896 if (l > len)
2897 l = len;
bellard92e873b2004-05-21 14:52:29 +00002898 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002899 if (!p) {
2900 pd = IO_MEM_UNASSIGNED;
2901 } else {
2902 pd = p->phys_offset;
2903 }
ths3b46e622007-09-17 08:09:54 +00002904
bellard13eb76e2004-01-24 15:23:36 +00002905 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002906 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002907 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002908 if (p)
2909 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard6a00d602005-11-21 23:25:50 +00002910 /* XXX: could force cpu_single_env to NULL to avoid
2911 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002912 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002913 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002914 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002915 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002916 l = 4;
2917 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002918 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002919 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002920 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002921 l = 2;
2922 } else {
bellard1c213d12005-09-03 10:49:04 +00002923 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002924 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002925 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002926 l = 1;
2927 }
2928 } else {
bellardb448f2f2004-02-25 23:24:04 +00002929 unsigned long addr1;
2930 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002931 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002932 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002933 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002934 if (!cpu_physical_memory_is_dirty(addr1)) {
2935 /* invalidate code */
2936 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2937 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002938 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002939 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002940 }
bellard13eb76e2004-01-24 15:23:36 +00002941 }
2942 } else {
ths5fafdf22007-09-16 21:08:06 +00002943 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002944 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002945 /* I/O case */
2946 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002947 if (p)
2948 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard13eb76e2004-01-24 15:23:36 +00002949 if (l >= 4 && ((addr & 3) == 0)) {
2950 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002951 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002952 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002953 l = 4;
2954 } else if (l >= 2 && ((addr & 1) == 0)) {
2955 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002956 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002957 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002958 l = 2;
2959 } else {
bellard1c213d12005-09-03 10:49:04 +00002960 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002961 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002962 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002963 l = 1;
2964 }
2965 } else {
2966 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002967 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002968 (addr & ~TARGET_PAGE_MASK);
2969 memcpy(buf, ptr, l);
2970 }
2971 }
2972 len -= l;
2973 buf += l;
2974 addr += l;
2975 }
2976}
bellard8df1cd02005-01-28 22:37:22 +00002977
bellardd0ecd2a2006-04-23 17:14:48 +00002978/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002979void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002980 const uint8_t *buf, int len)
2981{
2982 int l;
2983 uint8_t *ptr;
2984 target_phys_addr_t page;
2985 unsigned long pd;
2986 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002987
bellardd0ecd2a2006-04-23 17:14:48 +00002988 while (len > 0) {
2989 page = addr & TARGET_PAGE_MASK;
2990 l = (page + TARGET_PAGE_SIZE) - addr;
2991 if (l > len)
2992 l = len;
2993 p = phys_page_find(page >> TARGET_PAGE_BITS);
2994 if (!p) {
2995 pd = IO_MEM_UNASSIGNED;
2996 } else {
2997 pd = p->phys_offset;
2998 }
ths3b46e622007-09-17 08:09:54 +00002999
bellardd0ecd2a2006-04-23 17:14:48 +00003000 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00003001 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3002 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00003003 /* do nothing */
3004 } else {
3005 unsigned long addr1;
3006 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3007 /* ROM/RAM case */
3008 ptr = phys_ram_base + addr1;
3009 memcpy(ptr, buf, l);
3010 }
3011 len -= l;
3012 buf += l;
3013 addr += l;
3014 }
3015}
3016
3017
bellard8df1cd02005-01-28 22:37:22 +00003018/* warning: addr must be aligned */
3019uint32_t ldl_phys(target_phys_addr_t addr)
3020{
3021 int io_index;
3022 uint8_t *ptr;
3023 uint32_t val;
3024 unsigned long pd;
3025 PhysPageDesc *p;
3026
3027 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3028 if (!p) {
3029 pd = IO_MEM_UNASSIGNED;
3030 } else {
3031 pd = p->phys_offset;
3032 }
ths3b46e622007-09-17 08:09:54 +00003033
ths5fafdf22007-09-16 21:08:06 +00003034 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003035 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00003036 /* I/O case */
3037 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003038 if (p)
3039 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003040 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3041 } else {
3042 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003043 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00003044 (addr & ~TARGET_PAGE_MASK);
3045 val = ldl_p(ptr);
3046 }
3047 return val;
3048}
3049
bellard84b7b8e2005-11-28 21:19:04 +00003050/* warning: addr must be aligned */
3051uint64_t ldq_phys(target_phys_addr_t addr)
3052{
3053 int io_index;
3054 uint8_t *ptr;
3055 uint64_t val;
3056 unsigned long pd;
3057 PhysPageDesc *p;
3058
3059 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3060 if (!p) {
3061 pd = IO_MEM_UNASSIGNED;
3062 } else {
3063 pd = p->phys_offset;
3064 }
ths3b46e622007-09-17 08:09:54 +00003065
bellard2a4188a2006-06-25 21:54:59 +00003066 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3067 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00003068 /* I/O case */
3069 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003070 if (p)
3071 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard84b7b8e2005-11-28 21:19:04 +00003072#ifdef TARGET_WORDS_BIGENDIAN
3073 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3074 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3075#else
3076 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3077 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3078#endif
3079 } else {
3080 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003081 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00003082 (addr & ~TARGET_PAGE_MASK);
3083 val = ldq_p(ptr);
3084 }
3085 return val;
3086}
3087
bellardaab33092005-10-30 20:48:42 +00003088/* XXX: optimize */
3089uint32_t ldub_phys(target_phys_addr_t addr)
3090{
3091 uint8_t val;
3092 cpu_physical_memory_read(addr, &val, 1);
3093 return val;
3094}
3095
3096/* XXX: optimize */
3097uint32_t lduw_phys(target_phys_addr_t addr)
3098{
3099 uint16_t val;
3100 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3101 return tswap16(val);
3102}
3103
bellard8df1cd02005-01-28 22:37:22 +00003104/* warning: addr must be aligned. The ram page is not masked as dirty
3105 and the code inside is not invalidated. It is useful if the dirty
3106 bits are used to track modified PTEs */
3107void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
3108{
3109 int io_index;
3110 uint8_t *ptr;
3111 unsigned long pd;
3112 PhysPageDesc *p;
3113
3114 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3115 if (!p) {
3116 pd = IO_MEM_UNASSIGNED;
3117 } else {
3118 pd = p->phys_offset;
3119 }
ths3b46e622007-09-17 08:09:54 +00003120
bellard3a7d9292005-08-21 09:26:42 +00003121 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003122 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003123 if (p)
3124 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003125 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3126 } else {
aliguori74576192008-10-06 14:02:03 +00003127 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3128 ptr = phys_ram_base + addr1;
bellard8df1cd02005-01-28 22:37:22 +00003129 stl_p(ptr, val);
aliguori74576192008-10-06 14:02:03 +00003130
3131 if (unlikely(in_migration)) {
3132 if (!cpu_physical_memory_is_dirty(addr1)) {
3133 /* invalidate code */
3134 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3135 /* set dirty bit */
3136 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3137 (0xff & ~CODE_DIRTY_FLAG);
3138 }
3139 }
bellard8df1cd02005-01-28 22:37:22 +00003140 }
3141}
3142
j_mayerbc98a7e2007-04-04 07:55:12 +00003143void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
3144{
3145 int io_index;
3146 uint8_t *ptr;
3147 unsigned long pd;
3148 PhysPageDesc *p;
3149
3150 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3151 if (!p) {
3152 pd = IO_MEM_UNASSIGNED;
3153 } else {
3154 pd = p->phys_offset;
3155 }
ths3b46e622007-09-17 08:09:54 +00003156
j_mayerbc98a7e2007-04-04 07:55:12 +00003157 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3158 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003159 if (p)
3160 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
j_mayerbc98a7e2007-04-04 07:55:12 +00003161#ifdef TARGET_WORDS_BIGENDIAN
3162 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3163 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3164#else
3165 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3166 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3167#endif
3168 } else {
ths5fafdf22007-09-16 21:08:06 +00003169 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00003170 (addr & ~TARGET_PAGE_MASK);
3171 stq_p(ptr, val);
3172 }
3173}
3174
bellard8df1cd02005-01-28 22:37:22 +00003175/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00003176void stl_phys(target_phys_addr_t addr, uint32_t val)
3177{
3178 int io_index;
3179 uint8_t *ptr;
3180 unsigned long pd;
3181 PhysPageDesc *p;
3182
3183 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3184 if (!p) {
3185 pd = IO_MEM_UNASSIGNED;
3186 } else {
3187 pd = p->phys_offset;
3188 }
ths3b46e622007-09-17 08:09:54 +00003189
bellard3a7d9292005-08-21 09:26:42 +00003190 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003191 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003192 if (p)
3193 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003194 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3195 } else {
3196 unsigned long addr1;
3197 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3198 /* RAM case */
3199 ptr = phys_ram_base + addr1;
3200 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003201 if (!cpu_physical_memory_is_dirty(addr1)) {
3202 /* invalidate code */
3203 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3204 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003205 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3206 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003207 }
bellard8df1cd02005-01-28 22:37:22 +00003208 }
3209}
3210
bellardaab33092005-10-30 20:48:42 +00003211/* XXX: optimize */
3212void stb_phys(target_phys_addr_t addr, uint32_t val)
3213{
3214 uint8_t v = val;
3215 cpu_physical_memory_write(addr, &v, 1);
3216}
3217
3218/* XXX: optimize */
3219void stw_phys(target_phys_addr_t addr, uint32_t val)
3220{
3221 uint16_t v = tswap16(val);
3222 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3223}
3224
3225/* XXX: optimize */
3226void stq_phys(target_phys_addr_t addr, uint64_t val)
3227{
3228 val = tswap64(val);
3229 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3230}
3231
bellard13eb76e2004-01-24 15:23:36 +00003232#endif
3233
3234/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00003235int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003236 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003237{
3238 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003239 target_phys_addr_t phys_addr;
3240 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003241
3242 while (len > 0) {
3243 page = addr & TARGET_PAGE_MASK;
3244 phys_addr = cpu_get_phys_page_debug(env, page);
3245 /* if no physical page mapped, return an error */
3246 if (phys_addr == -1)
3247 return -1;
3248 l = (page + TARGET_PAGE_SIZE) - addr;
3249 if (l > len)
3250 l = len;
ths5fafdf22007-09-16 21:08:06 +00003251 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00003252 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003253 len -= l;
3254 buf += l;
3255 addr += l;
3256 }
3257 return 0;
3258}
3259
pbrook2e70f6e2008-06-29 01:03:05 +00003260/* in deterministic execution mode, instructions doing device I/Os
3261 must be at the end of the TB */
3262void cpu_io_recompile(CPUState *env, void *retaddr)
3263{
3264 TranslationBlock *tb;
3265 uint32_t n, cflags;
3266 target_ulong pc, cs_base;
3267 uint64_t flags;
3268
3269 tb = tb_find_pc((unsigned long)retaddr);
3270 if (!tb) {
3271 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3272 retaddr);
3273 }
3274 n = env->icount_decr.u16.low + tb->icount;
3275 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3276 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003277 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003278 n = n - env->icount_decr.u16.low;
3279 /* Generate a new TB ending on the I/O insn. */
3280 n++;
3281 /* On MIPS and SH, delay slot instructions can only be restarted if
3282 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003283 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003284 branch. */
3285#if defined(TARGET_MIPS)
3286 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3287 env->active_tc.PC -= 4;
3288 env->icount_decr.u16.low++;
3289 env->hflags &= ~MIPS_HFLAG_BMASK;
3290 }
3291#elif defined(TARGET_SH4)
3292 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3293 && n > 1) {
3294 env->pc -= 2;
3295 env->icount_decr.u16.low++;
3296 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3297 }
3298#endif
3299 /* This should never happen. */
3300 if (n > CF_COUNT_MASK)
3301 cpu_abort(env, "TB too big during recompile");
3302
3303 cflags = n | CF_LAST_IO;
3304 pc = tb->pc;
3305 cs_base = tb->cs_base;
3306 flags = tb->flags;
3307 tb_phys_invalidate(tb, -1);
3308 /* FIXME: In theory this could raise an exception. In practice
3309 we have already translated the block once so it's probably ok. */
3310 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003311 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003312 the first in the TB) then we end up generating a whole new TB and
3313 repeating the fault, which is horribly inefficient.
3314 Better would be to execute just this insn uncached, or generate a
3315 second new TB. */
3316 cpu_resume_from_signal(env, NULL);
3317}
3318
bellarde3db7222005-01-26 22:00:47 +00003319void dump_exec_info(FILE *f,
3320 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3321{
3322 int i, target_code_size, max_target_code_size;
3323 int direct_jmp_count, direct_jmp2_count, cross_page;
3324 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003325
bellarde3db7222005-01-26 22:00:47 +00003326 target_code_size = 0;
3327 max_target_code_size = 0;
3328 cross_page = 0;
3329 direct_jmp_count = 0;
3330 direct_jmp2_count = 0;
3331 for(i = 0; i < nb_tbs; i++) {
3332 tb = &tbs[i];
3333 target_code_size += tb->size;
3334 if (tb->size > max_target_code_size)
3335 max_target_code_size = tb->size;
3336 if (tb->page_addr[1] != -1)
3337 cross_page++;
3338 if (tb->tb_next_offset[0] != 0xffff) {
3339 direct_jmp_count++;
3340 if (tb->tb_next_offset[1] != 0xffff) {
3341 direct_jmp2_count++;
3342 }
3343 }
3344 }
3345 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003346 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003347 cpu_fprintf(f, "gen code size %ld/%ld\n",
3348 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3349 cpu_fprintf(f, "TB count %d/%d\n",
3350 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003351 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003352 nb_tbs ? target_code_size / nb_tbs : 0,
3353 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003354 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003355 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3356 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003357 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3358 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003359 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3360 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003361 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003362 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3363 direct_jmp2_count,
3364 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003365 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003366 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3367 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3368 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003369 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003370}
3371
ths5fafdf22007-09-16 21:08:06 +00003372#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003373
3374#define MMUSUFFIX _cmmu
3375#define GETPC() NULL
3376#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003377#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003378
3379#define SHIFT 0
3380#include "softmmu_template.h"
3381
3382#define SHIFT 1
3383#include "softmmu_template.h"
3384
3385#define SHIFT 2
3386#include "softmmu_template.h"
3387
3388#define SHIFT 3
3389#include "softmmu_template.h"
3390
3391#undef env
3392
3393#endif