blob: 18f8f5f557a14f13503f0494d394d6ad4bb21ee7 [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrook53a59602006-03-25 19:31:22 +000040#if defined(CONFIG_USER_ONLY)
41#include <qemu.h>
42#endif
bellard54936002003-05-13 00:25:15 +000043
bellardfd6ce8f2003-05-14 19:00:11 +000044//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000045//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000046//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000047//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000048
49/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000050//#define DEBUG_TB_CHECK
51//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000052
ths1196be32007-03-17 15:17:58 +000053//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000054//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000055
pbrook99773bd2006-04-16 15:14:59 +000056#if !defined(CONFIG_USER_ONLY)
57/* TB consistency checks only implemented for usermode emulation. */
58#undef DEBUG_TB_CHECK
59#endif
60
bellard9fa3e852004-01-04 18:06:42 +000061#define SMC_BITMAP_USE_THRESHOLD 10
62
63#define MMAP_AREA_START 0x00000000
64#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000065
bellard108c49b2005-07-24 12:55:09 +000066#if defined(TARGET_SPARC64)
67#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000068#elif defined(TARGET_SPARC)
69#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000070#elif defined(TARGET_ALPHA)
71#define TARGET_PHYS_ADDR_SPACE_BITS 42
72#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000073#elif defined(TARGET_PPC64)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000075#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
76#define TARGET_PHYS_ADDR_SPACE_BITS 42
77#elif defined(TARGET_I386) && !defined(USE_KQEMU)
78#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000079#else
80/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
81#define TARGET_PHYS_ADDR_SPACE_BITS 32
82#endif
83
pbrookfab94c02008-05-24 13:56:15 +000084TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000085int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000086TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000087int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000088/* any access to the tbs or the page table must use this lock */
89spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000090
bellard7cb69ca2008-05-10 10:55:51 +000091uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellard26a5f132008-05-28 12:30:31 +000092uint8_t *code_gen_buffer;
93unsigned long code_gen_buffer_size;
94/* threshold to flush the translated code buffer */
95unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +000096uint8_t *code_gen_ptr;
97
pbrooke2eef172008-06-08 01:09:01 +000098#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +000099ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000100int phys_ram_fd;
101uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000102uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000103static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000104#endif
bellard9fa3e852004-01-04 18:06:42 +0000105
bellard6a00d602005-11-21 23:25:50 +0000106CPUState *first_cpu;
107/* current CPU in the current thread. It is only valid inside
108 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000109CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000110
bellard54936002003-05-13 00:25:15 +0000111typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000112 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000113 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000114 /* in order to optimize self modifying code, we count the number
115 of lookups we do to a given page to use a bitmap */
116 unsigned int code_write_count;
117 uint8_t *code_bitmap;
118#if defined(CONFIG_USER_ONLY)
119 unsigned long flags;
120#endif
bellard54936002003-05-13 00:25:15 +0000121} PageDesc;
122
bellard92e873b2004-05-21 14:52:29 +0000123typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000124 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000125 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000126} PhysPageDesc;
127
bellard54936002003-05-13 00:25:15 +0000128#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000129#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
130/* XXX: this is a temporary hack for alpha target.
131 * In the future, this is to be replaced by a multi-level table
132 * to actually be able to handle the complete 64 bits address space.
133 */
134#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
135#else
aurel3203875442008-04-22 20:45:18 +0000136#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000137#endif
bellard54936002003-05-13 00:25:15 +0000138
139#define L1_SIZE (1 << L1_BITS)
140#define L2_SIZE (1 << L2_BITS)
141
bellard83fb7ad2004-07-05 21:25:26 +0000142unsigned long qemu_real_host_page_size;
143unsigned long qemu_host_page_bits;
144unsigned long qemu_host_page_size;
145unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000146
bellard92e873b2004-05-21 14:52:29 +0000147/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000148static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000149PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000150
pbrooke2eef172008-06-08 01:09:01 +0000151#if !defined(CONFIG_USER_ONLY)
152static void io_mem_init(void);
153
bellard33417e72003-08-10 21:47:01 +0000154/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000155CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
156CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000157void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000158static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000159static int io_mem_watch;
160#endif
bellard33417e72003-08-10 21:47:01 +0000161
bellard34865132003-10-05 14:28:56 +0000162/* log support */
163char *logfilename = "/tmp/qemu.log";
164FILE *logfile;
165int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000166static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000167
bellarde3db7222005-01-26 22:00:47 +0000168/* statistics */
169static int tlb_flush_count;
170static int tb_flush_count;
171static int tb_phys_invalidate_count;
172
blueswir1db7b5422007-05-26 17:36:03 +0000173#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
174typedef struct subpage_t {
175 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000176 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
177 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
178 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000179} subpage_t;
180
bellard7cb69ca2008-05-10 10:55:51 +0000181#ifdef _WIN32
182static void map_exec(void *addr, long size)
183{
184 DWORD old_protect;
185 VirtualProtect(addr, size,
186 PAGE_EXECUTE_READWRITE, &old_protect);
187
188}
189#else
190static void map_exec(void *addr, long size)
191{
bellard43694152008-05-29 09:35:57 +0000192 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000193
bellard43694152008-05-29 09:35:57 +0000194 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000195 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000196 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000197
198 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000199 end += page_size - 1;
200 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000201
202 mprotect((void *)start, end - start,
203 PROT_READ | PROT_WRITE | PROT_EXEC);
204}
205#endif
206
bellardb346ff42003-06-15 20:05:50 +0000207static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000208{
bellard83fb7ad2004-07-05 21:25:26 +0000209 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000210 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000211#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000212 {
213 SYSTEM_INFO system_info;
214 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000215
bellardd5a8f072004-09-29 21:15:28 +0000216 GetSystemInfo(&system_info);
217 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000218 }
bellard67b915a2004-03-31 23:37:16 +0000219#else
bellard83fb7ad2004-07-05 21:25:26 +0000220 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000221#endif
bellard83fb7ad2004-07-05 21:25:26 +0000222 if (qemu_host_page_size == 0)
223 qemu_host_page_size = qemu_real_host_page_size;
224 if (qemu_host_page_size < TARGET_PAGE_SIZE)
225 qemu_host_page_size = TARGET_PAGE_SIZE;
226 qemu_host_page_bits = 0;
227 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
228 qemu_host_page_bits++;
229 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000230 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
231 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000232
233#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
234 {
235 long long startaddr, endaddr;
236 FILE *f;
237 int n;
238
pbrookc8a706f2008-06-02 16:16:42 +0000239 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000240 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000241 f = fopen("/proc/self/maps", "r");
242 if (f) {
243 do {
244 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
245 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000246 startaddr = MIN(startaddr,
247 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
248 endaddr = MIN(endaddr,
249 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000250 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000251 TARGET_PAGE_ALIGN(endaddr),
252 PAGE_RESERVED);
253 }
254 } while (!feof(f));
255 fclose(f);
256 }
pbrookc8a706f2008-06-02 16:16:42 +0000257 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000258 }
259#endif
bellard54936002003-05-13 00:25:15 +0000260}
261
aurel3200f82b82008-04-27 21:12:55 +0000262static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000263{
bellard54936002003-05-13 00:25:15 +0000264 PageDesc **lp, *p;
265
pbrook17e23772008-06-09 13:47:45 +0000266#if TARGET_LONG_BITS > 32
267 /* Host memory outside guest VM. For 32-bit targets we have already
268 excluded high addresses. */
269 if (index > ((target_ulong)L2_SIZE * L1_SIZE * TARGET_PAGE_SIZE))
270 return NULL;
271#endif
bellard54936002003-05-13 00:25:15 +0000272 lp = &l1_map[index >> L2_BITS];
273 p = *lp;
274 if (!p) {
275 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000276#if defined(CONFIG_USER_ONLY)
277 unsigned long addr;
278 size_t len = sizeof(PageDesc) * L2_SIZE;
279 /* Don't use qemu_malloc because it may recurse. */
280 p = mmap(0, len, PROT_READ | PROT_WRITE,
281 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000282 *lp = p;
pbrook17e23772008-06-09 13:47:45 +0000283 addr = h2g(p);
284 if (addr == (target_ulong)addr) {
285 page_set_flags(addr & TARGET_PAGE_MASK,
286 TARGET_PAGE_ALIGN(addr + len),
287 PAGE_RESERVED);
288 }
289#else
290 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
291 *lp = p;
292#endif
bellard54936002003-05-13 00:25:15 +0000293 }
294 return p + (index & (L2_SIZE - 1));
295}
296
aurel3200f82b82008-04-27 21:12:55 +0000297static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000298{
bellard54936002003-05-13 00:25:15 +0000299 PageDesc *p;
300
bellard54936002003-05-13 00:25:15 +0000301 p = l1_map[index >> L2_BITS];
302 if (!p)
303 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000304 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000305}
306
bellard108c49b2005-07-24 12:55:09 +0000307static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000308{
bellard108c49b2005-07-24 12:55:09 +0000309 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000310 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000311
bellard108c49b2005-07-24 12:55:09 +0000312 p = (void **)l1_phys_map;
313#if TARGET_PHYS_ADDR_SPACE_BITS > 32
314
315#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
316#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
317#endif
318 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000319 p = *lp;
320 if (!p) {
321 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000322 if (!alloc)
323 return NULL;
324 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
325 memset(p, 0, sizeof(void *) * L1_SIZE);
326 *lp = p;
327 }
328#endif
329 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000330 pd = *lp;
331 if (!pd) {
332 int i;
bellard108c49b2005-07-24 12:55:09 +0000333 /* allocate if not found */
334 if (!alloc)
335 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000336 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
337 *lp = pd;
338 for (i = 0; i < L2_SIZE; i++)
339 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000340 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000341 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000342}
343
bellard108c49b2005-07-24 12:55:09 +0000344static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000345{
bellard108c49b2005-07-24 12:55:09 +0000346 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000347}
348
bellard9fa3e852004-01-04 18:06:42 +0000349#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000350static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000351static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000352 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000353#define mmap_lock() do { } while(0)
354#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000355#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000356
bellard43694152008-05-29 09:35:57 +0000357#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
358
359#if defined(CONFIG_USER_ONLY)
360/* Currently it is not recommanded to allocate big chunks of data in
361 user mode. It will change when a dedicated libc will be used */
362#define USE_STATIC_CODE_GEN_BUFFER
363#endif
364
365#ifdef USE_STATIC_CODE_GEN_BUFFER
366static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
367#endif
368
bellard26a5f132008-05-28 12:30:31 +0000369void code_gen_alloc(unsigned long tb_size)
370{
bellard43694152008-05-29 09:35:57 +0000371#ifdef USE_STATIC_CODE_GEN_BUFFER
372 code_gen_buffer = static_code_gen_buffer;
373 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
374 map_exec(code_gen_buffer, code_gen_buffer_size);
375#else
bellard26a5f132008-05-28 12:30:31 +0000376 code_gen_buffer_size = tb_size;
377 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000378#if defined(CONFIG_USER_ONLY)
379 /* in user mode, phys_ram_size is not meaningful */
380 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
381#else
bellard26a5f132008-05-28 12:30:31 +0000382 /* XXX: needs ajustments */
383 code_gen_buffer_size = (int)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000384#endif
bellard26a5f132008-05-28 12:30:31 +0000385 }
386 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
387 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
388 /* The code gen buffer location may have constraints depending on
389 the host cpu and OS */
390#if defined(__linux__)
391 {
392 int flags;
393 flags = MAP_PRIVATE | MAP_ANONYMOUS;
394#if defined(__x86_64__)
395 flags |= MAP_32BIT;
396 /* Cannot map more than that */
397 if (code_gen_buffer_size > (800 * 1024 * 1024))
398 code_gen_buffer_size = (800 * 1024 * 1024);
399#endif
400 code_gen_buffer = mmap(NULL, code_gen_buffer_size,
401 PROT_WRITE | PROT_READ | PROT_EXEC,
402 flags, -1, 0);
403 if (code_gen_buffer == MAP_FAILED) {
404 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
405 exit(1);
406 }
407 }
408#else
409 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
410 if (!code_gen_buffer) {
411 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
412 exit(1);
413 }
414 map_exec(code_gen_buffer, code_gen_buffer_size);
415#endif
bellard43694152008-05-29 09:35:57 +0000416#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000417 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
418 code_gen_buffer_max_size = code_gen_buffer_size -
419 code_gen_max_block_size();
420 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
421 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
422}
423
424/* Must be called before using the QEMU cpus. 'tb_size' is the size
425 (in bytes) allocated to the translation buffer. Zero means default
426 size. */
427void cpu_exec_init_all(unsigned long tb_size)
428{
bellard26a5f132008-05-28 12:30:31 +0000429 cpu_gen_init();
430 code_gen_alloc(tb_size);
431 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000432 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000433#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000434 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000435#endif
bellard26a5f132008-05-28 12:30:31 +0000436}
437
bellard6a00d602005-11-21 23:25:50 +0000438void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000439{
bellard6a00d602005-11-21 23:25:50 +0000440 CPUState **penv;
441 int cpu_index;
442
bellard6a00d602005-11-21 23:25:50 +0000443 env->next_cpu = NULL;
444 penv = &first_cpu;
445 cpu_index = 0;
446 while (*penv != NULL) {
447 penv = (CPUState **)&(*penv)->next_cpu;
448 cpu_index++;
449 }
450 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000451 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000452 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000453}
454
bellard9fa3e852004-01-04 18:06:42 +0000455static inline void invalidate_page_bitmap(PageDesc *p)
456{
457 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000458 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000459 p->code_bitmap = NULL;
460 }
461 p->code_write_count = 0;
462}
463
bellardfd6ce8f2003-05-14 19:00:11 +0000464/* set to NULL all the 'first_tb' fields in all PageDescs */
465static void page_flush_tb(void)
466{
467 int i, j;
468 PageDesc *p;
469
470 for(i = 0; i < L1_SIZE; i++) {
471 p = l1_map[i];
472 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000473 for(j = 0; j < L2_SIZE; j++) {
474 p->first_tb = NULL;
475 invalidate_page_bitmap(p);
476 p++;
477 }
bellardfd6ce8f2003-05-14 19:00:11 +0000478 }
479 }
480}
481
482/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000483/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000484void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000485{
bellard6a00d602005-11-21 23:25:50 +0000486 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000487#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000488 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
489 (unsigned long)(code_gen_ptr - code_gen_buffer),
490 nb_tbs, nb_tbs > 0 ?
491 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000492#endif
bellard26a5f132008-05-28 12:30:31 +0000493 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000494 cpu_abort(env1, "Internal error: code buffer overflow\n");
495
bellardfd6ce8f2003-05-14 19:00:11 +0000496 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000497
bellard6a00d602005-11-21 23:25:50 +0000498 for(env = first_cpu; env != NULL; env = env->next_cpu) {
499 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
500 }
bellard9fa3e852004-01-04 18:06:42 +0000501
bellard8a8a6082004-10-03 13:36:49 +0000502 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000503 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000504
bellardfd6ce8f2003-05-14 19:00:11 +0000505 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000506 /* XXX: flush processor icache at this point if cache flush is
507 expensive */
bellarde3db7222005-01-26 22:00:47 +0000508 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000509}
510
511#ifdef DEBUG_TB_CHECK
512
j_mayerbc98a7e2007-04-04 07:55:12 +0000513static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000514{
515 TranslationBlock *tb;
516 int i;
517 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000518 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
519 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000520 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
521 address >= tb->pc + tb->size)) {
522 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000523 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000524 }
525 }
526 }
527}
528
529/* verify that all the pages have correct rights for code */
530static void tb_page_check(void)
531{
532 TranslationBlock *tb;
533 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000534
pbrook99773bd2006-04-16 15:14:59 +0000535 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
536 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000537 flags1 = page_get_flags(tb->pc);
538 flags2 = page_get_flags(tb->pc + tb->size - 1);
539 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
540 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000541 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000542 }
543 }
544 }
545}
546
bellardd4e81642003-05-25 16:46:15 +0000547void tb_jmp_check(TranslationBlock *tb)
548{
549 TranslationBlock *tb1;
550 unsigned int n1;
551
552 /* suppress any remaining jumps to this TB */
553 tb1 = tb->jmp_first;
554 for(;;) {
555 n1 = (long)tb1 & 3;
556 tb1 = (TranslationBlock *)((long)tb1 & ~3);
557 if (n1 == 2)
558 break;
559 tb1 = tb1->jmp_next[n1];
560 }
561 /* check end of list */
562 if (tb1 != tb) {
563 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
564 }
565}
566
bellardfd6ce8f2003-05-14 19:00:11 +0000567#endif
568
569/* invalidate one TB */
570static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
571 int next_offset)
572{
573 TranslationBlock *tb1;
574 for(;;) {
575 tb1 = *ptb;
576 if (tb1 == tb) {
577 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
578 break;
579 }
580 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
581 }
582}
583
bellard9fa3e852004-01-04 18:06:42 +0000584static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
585{
586 TranslationBlock *tb1;
587 unsigned int n1;
588
589 for(;;) {
590 tb1 = *ptb;
591 n1 = (long)tb1 & 3;
592 tb1 = (TranslationBlock *)((long)tb1 & ~3);
593 if (tb1 == tb) {
594 *ptb = tb1->page_next[n1];
595 break;
596 }
597 ptb = &tb1->page_next[n1];
598 }
599}
600
bellardd4e81642003-05-25 16:46:15 +0000601static inline void tb_jmp_remove(TranslationBlock *tb, int n)
602{
603 TranslationBlock *tb1, **ptb;
604 unsigned int n1;
605
606 ptb = &tb->jmp_next[n];
607 tb1 = *ptb;
608 if (tb1) {
609 /* find tb(n) in circular list */
610 for(;;) {
611 tb1 = *ptb;
612 n1 = (long)tb1 & 3;
613 tb1 = (TranslationBlock *)((long)tb1 & ~3);
614 if (n1 == n && tb1 == tb)
615 break;
616 if (n1 == 2) {
617 ptb = &tb1->jmp_first;
618 } else {
619 ptb = &tb1->jmp_next[n1];
620 }
621 }
622 /* now we can suppress tb(n) from the list */
623 *ptb = tb->jmp_next[n];
624
625 tb->jmp_next[n] = NULL;
626 }
627}
628
629/* reset the jump entry 'n' of a TB so that it is not chained to
630 another TB */
631static inline void tb_reset_jump(TranslationBlock *tb, int n)
632{
633 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
634}
635
aurel3200f82b82008-04-27 21:12:55 +0000636static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000637{
bellard6a00d602005-11-21 23:25:50 +0000638 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000639 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000640 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000641 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000642 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000643
bellard9fa3e852004-01-04 18:06:42 +0000644 /* remove the TB from the hash list */
645 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
646 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000647 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000648 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000649
bellard9fa3e852004-01-04 18:06:42 +0000650 /* remove the TB from the page list */
651 if (tb->page_addr[0] != page_addr) {
652 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
653 tb_page_remove(&p->first_tb, tb);
654 invalidate_page_bitmap(p);
655 }
656 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
657 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
658 tb_page_remove(&p->first_tb, tb);
659 invalidate_page_bitmap(p);
660 }
661
bellard8a40a182005-11-20 10:35:40 +0000662 tb_invalidated_flag = 1;
663
664 /* remove the TB from the hash list */
665 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000666 for(env = first_cpu; env != NULL; env = env->next_cpu) {
667 if (env->tb_jmp_cache[h] == tb)
668 env->tb_jmp_cache[h] = NULL;
669 }
bellard8a40a182005-11-20 10:35:40 +0000670
671 /* suppress this TB from the two jump lists */
672 tb_jmp_remove(tb, 0);
673 tb_jmp_remove(tb, 1);
674
675 /* suppress any remaining jumps to this TB */
676 tb1 = tb->jmp_first;
677 for(;;) {
678 n1 = (long)tb1 & 3;
679 if (n1 == 2)
680 break;
681 tb1 = (TranslationBlock *)((long)tb1 & ~3);
682 tb2 = tb1->jmp_next[n1];
683 tb_reset_jump(tb1, n1);
684 tb1->jmp_next[n1] = NULL;
685 tb1 = tb2;
686 }
687 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
688
bellarde3db7222005-01-26 22:00:47 +0000689 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000690}
691
692static inline void set_bits(uint8_t *tab, int start, int len)
693{
694 int end, mask, end1;
695
696 end = start + len;
697 tab += start >> 3;
698 mask = 0xff << (start & 7);
699 if ((start & ~7) == (end & ~7)) {
700 if (start < end) {
701 mask &= ~(0xff << (end & 7));
702 *tab |= mask;
703 }
704 } else {
705 *tab++ |= mask;
706 start = (start + 8) & ~7;
707 end1 = end & ~7;
708 while (start < end1) {
709 *tab++ = 0xff;
710 start += 8;
711 }
712 if (start < end) {
713 mask = ~(0xff << (end & 7));
714 *tab |= mask;
715 }
716 }
717}
718
719static void build_page_bitmap(PageDesc *p)
720{
721 int n, tb_start, tb_end;
722 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000723
bellard59817cc2004-02-16 22:01:13 +0000724 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000725 if (!p->code_bitmap)
726 return;
727 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
728
729 tb = p->first_tb;
730 while (tb != NULL) {
731 n = (long)tb & 3;
732 tb = (TranslationBlock *)((long)tb & ~3);
733 /* NOTE: this is subtle as a TB may span two physical pages */
734 if (n == 0) {
735 /* NOTE: tb_end may be after the end of the page, but
736 it is not a problem */
737 tb_start = tb->pc & ~TARGET_PAGE_MASK;
738 tb_end = tb_start + tb->size;
739 if (tb_end > TARGET_PAGE_SIZE)
740 tb_end = TARGET_PAGE_SIZE;
741 } else {
742 tb_start = 0;
743 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
744 }
745 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
746 tb = tb->page_next[n];
747 }
748}
749
bellardd720b932004-04-25 17:57:43 +0000750#ifdef TARGET_HAS_PRECISE_SMC
751
ths5fafdf22007-09-16 21:08:06 +0000752static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000753 target_ulong pc, target_ulong cs_base, int flags,
754 int cflags)
755{
756 TranslationBlock *tb;
757 uint8_t *tc_ptr;
758 target_ulong phys_pc, phys_page2, virt_page2;
759 int code_gen_size;
760
bellardc27004e2005-01-03 23:35:10 +0000761 phys_pc = get_phys_addr_code(env, pc);
762 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000763 if (!tb) {
764 /* flush must be done */
765 tb_flush(env);
766 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000767 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000768 }
769 tc_ptr = code_gen_ptr;
770 tb->tc_ptr = tc_ptr;
771 tb->cs_base = cs_base;
772 tb->flags = flags;
773 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000774 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000775 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 +0000776
bellardd720b932004-04-25 17:57:43 +0000777 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000778 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000779 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000780 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000781 phys_page2 = get_phys_addr_code(env, virt_page2);
782 }
783 tb_link_phys(tb, phys_pc, phys_page2);
784}
785#endif
ths3b46e622007-09-17 08:09:54 +0000786
bellard9fa3e852004-01-04 18:06:42 +0000787/* invalidate all TBs which intersect with the target physical page
788 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000789 the same physical page. 'is_cpu_write_access' should be true if called
790 from a real cpu write access: the virtual CPU will exit the current
791 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000792void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000793 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000794{
bellardd720b932004-04-25 17:57:43 +0000795 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000796 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000797 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000798 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000799 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000800 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000801
802 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000803 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000804 return;
ths5fafdf22007-09-16 21:08:06 +0000805 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000806 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
807 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000808 /* build code bitmap */
809 build_page_bitmap(p);
810 }
811
812 /* we remove all the TBs in the range [start, end[ */
813 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000814 current_tb_not_found = is_cpu_write_access;
815 current_tb_modified = 0;
816 current_tb = NULL; /* avoid warning */
817 current_pc = 0; /* avoid warning */
818 current_cs_base = 0; /* avoid warning */
819 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000820 tb = p->first_tb;
821 while (tb != NULL) {
822 n = (long)tb & 3;
823 tb = (TranslationBlock *)((long)tb & ~3);
824 tb_next = tb->page_next[n];
825 /* NOTE: this is subtle as a TB may span two physical pages */
826 if (n == 0) {
827 /* NOTE: tb_end may be after the end of the page, but
828 it is not a problem */
829 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
830 tb_end = tb_start + tb->size;
831 } else {
832 tb_start = tb->page_addr[1];
833 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
834 }
835 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000836#ifdef TARGET_HAS_PRECISE_SMC
837 if (current_tb_not_found) {
838 current_tb_not_found = 0;
839 current_tb = NULL;
840 if (env->mem_write_pc) {
841 /* now we have a real cpu fault */
842 current_tb = tb_find_pc(env->mem_write_pc);
843 }
844 }
845 if (current_tb == tb &&
846 !(current_tb->cflags & CF_SINGLE_INSN)) {
847 /* If we are modifying the current TB, we must stop
848 its execution. We could be more precise by checking
849 that the modification is after the current PC, but it
850 would require a specialized function to partially
851 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000852
bellardd720b932004-04-25 17:57:43 +0000853 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000854 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000855 env->mem_write_pc, NULL);
856#if defined(TARGET_I386)
857 current_flags = env->hflags;
858 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
859 current_cs_base = (target_ulong)env->segs[R_CS].base;
860 current_pc = current_cs_base + env->eip;
861#else
862#error unsupported CPU
863#endif
864 }
865#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000866 /* we need to do that to handle the case where a signal
867 occurs while doing tb_phys_invalidate() */
868 saved_tb = NULL;
869 if (env) {
870 saved_tb = env->current_tb;
871 env->current_tb = NULL;
872 }
bellard9fa3e852004-01-04 18:06:42 +0000873 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000874 if (env) {
875 env->current_tb = saved_tb;
876 if (env->interrupt_request && env->current_tb)
877 cpu_interrupt(env, env->interrupt_request);
878 }
bellard9fa3e852004-01-04 18:06:42 +0000879 }
880 tb = tb_next;
881 }
882#if !defined(CONFIG_USER_ONLY)
883 /* if no code remaining, no need to continue to use slow writes */
884 if (!p->first_tb) {
885 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000886 if (is_cpu_write_access) {
887 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
888 }
889 }
890#endif
891#ifdef TARGET_HAS_PRECISE_SMC
892 if (current_tb_modified) {
893 /* we generate a block containing just the instruction
894 modifying the memory. It will ensure that it cannot modify
895 itself */
bellardea1c1802004-06-14 18:56:36 +0000896 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000897 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000898 CF_SINGLE_INSN);
899 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000900 }
901#endif
902}
903
904/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000905static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000906{
907 PageDesc *p;
908 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000909#if 0
bellarda4193c82004-06-03 14:01:43 +0000910 if (1) {
911 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000912 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
913 cpu_single_env->mem_write_vaddr, len,
914 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000915 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
916 }
bellard59817cc2004-02-16 22:01:13 +0000917 }
918#endif
bellard9fa3e852004-01-04 18:06:42 +0000919 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000920 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000921 return;
922 if (p->code_bitmap) {
923 offset = start & ~TARGET_PAGE_MASK;
924 b = p->code_bitmap[offset >> 3] >> (offset & 7);
925 if (b & ((1 << len) - 1))
926 goto do_invalidate;
927 } else {
928 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000929 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000930 }
931}
932
bellard9fa3e852004-01-04 18:06:42 +0000933#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000934static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000935 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000936{
bellardd720b932004-04-25 17:57:43 +0000937 int n, current_flags, current_tb_modified;
938 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000939 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000940 TranslationBlock *tb, *current_tb;
941#ifdef TARGET_HAS_PRECISE_SMC
942 CPUState *env = cpu_single_env;
943#endif
bellard9fa3e852004-01-04 18:06:42 +0000944
945 addr &= TARGET_PAGE_MASK;
946 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000947 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000948 return;
949 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000950 current_tb_modified = 0;
951 current_tb = NULL;
952 current_pc = 0; /* avoid warning */
953 current_cs_base = 0; /* avoid warning */
954 current_flags = 0; /* avoid warning */
955#ifdef TARGET_HAS_PRECISE_SMC
956 if (tb && pc != 0) {
957 current_tb = tb_find_pc(pc);
958 }
959#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000960 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000961 n = (long)tb & 3;
962 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000963#ifdef TARGET_HAS_PRECISE_SMC
964 if (current_tb == tb &&
965 !(current_tb->cflags & CF_SINGLE_INSN)) {
966 /* If we are modifying the current TB, we must stop
967 its execution. We could be more precise by checking
968 that the modification is after the current PC, but it
969 would require a specialized function to partially
970 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000971
bellardd720b932004-04-25 17:57:43 +0000972 current_tb_modified = 1;
973 cpu_restore_state(current_tb, env, pc, puc);
974#if defined(TARGET_I386)
975 current_flags = env->hflags;
976 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
977 current_cs_base = (target_ulong)env->segs[R_CS].base;
978 current_pc = current_cs_base + env->eip;
979#else
980#error unsupported CPU
981#endif
982 }
983#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000984 tb_phys_invalidate(tb, addr);
985 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000986 }
987 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000988#ifdef TARGET_HAS_PRECISE_SMC
989 if (current_tb_modified) {
990 /* we generate a block containing just the instruction
991 modifying the memory. It will ensure that it cannot modify
992 itself */
bellardea1c1802004-06-14 18:56:36 +0000993 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000994 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000995 CF_SINGLE_INSN);
996 cpu_resume_from_signal(env, puc);
997 }
998#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000999}
bellard9fa3e852004-01-04 18:06:42 +00001000#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001001
1002/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001003static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001004 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001005{
1006 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001007 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001008
bellard9fa3e852004-01-04 18:06:42 +00001009 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001010 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001011 tb->page_next[n] = p->first_tb;
1012 last_first_tb = p->first_tb;
1013 p->first_tb = (TranslationBlock *)((long)tb | n);
1014 invalidate_page_bitmap(p);
1015
bellard107db442004-06-22 18:48:46 +00001016#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001017
bellard9fa3e852004-01-04 18:06:42 +00001018#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001019 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001020 target_ulong addr;
1021 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001022 int prot;
1023
bellardfd6ce8f2003-05-14 19:00:11 +00001024 /* force the host page as non writable (writes will have a
1025 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001026 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001027 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001028 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1029 addr += TARGET_PAGE_SIZE) {
1030
1031 p2 = page_find (addr >> TARGET_PAGE_BITS);
1032 if (!p2)
1033 continue;
1034 prot |= p2->flags;
1035 p2->flags &= ~PAGE_WRITE;
1036 page_get_flags(addr);
1037 }
ths5fafdf22007-09-16 21:08:06 +00001038 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001039 (prot & PAGE_BITS) & ~PAGE_WRITE);
1040#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001041 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001042 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001043#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001044 }
bellard9fa3e852004-01-04 18:06:42 +00001045#else
1046 /* if some code is already present, then the pages are already
1047 protected. So we handle the case where only the first TB is
1048 allocated in a physical page */
1049 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001050 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001051 }
1052#endif
bellardd720b932004-04-25 17:57:43 +00001053
1054#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001055}
1056
1057/* Allocate a new translation block. Flush the translation buffer if
1058 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001059TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001060{
1061 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001062
bellard26a5f132008-05-28 12:30:31 +00001063 if (nb_tbs >= code_gen_max_blocks ||
1064 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001065 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001066 tb = &tbs[nb_tbs++];
1067 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001068 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001069 return tb;
1070}
1071
bellard9fa3e852004-01-04 18:06:42 +00001072/* add a new TB and link it to the physical page tables. phys_page2 is
1073 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001074void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001075 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001076{
bellard9fa3e852004-01-04 18:06:42 +00001077 unsigned int h;
1078 TranslationBlock **ptb;
1079
pbrookc8a706f2008-06-02 16:16:42 +00001080 /* Grab the mmap lock to stop another thread invalidating this TB
1081 before we are done. */
1082 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001083 /* add in the physical hash table */
1084 h = tb_phys_hash_func(phys_pc);
1085 ptb = &tb_phys_hash[h];
1086 tb->phys_hash_next = *ptb;
1087 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001088
1089 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001090 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1091 if (phys_page2 != -1)
1092 tb_alloc_page(tb, 1, phys_page2);
1093 else
1094 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001095
bellardd4e81642003-05-25 16:46:15 +00001096 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1097 tb->jmp_next[0] = NULL;
1098 tb->jmp_next[1] = NULL;
1099
1100 /* init original jump addresses */
1101 if (tb->tb_next_offset[0] != 0xffff)
1102 tb_reset_jump(tb, 0);
1103 if (tb->tb_next_offset[1] != 0xffff)
1104 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001105
1106#ifdef DEBUG_TB_CHECK
1107 tb_page_check();
1108#endif
pbrookc8a706f2008-06-02 16:16:42 +00001109 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001110}
1111
bellarda513fe12003-05-27 23:29:48 +00001112/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1113 tb[1].tc_ptr. Return NULL if not found */
1114TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1115{
1116 int m_min, m_max, m;
1117 unsigned long v;
1118 TranslationBlock *tb;
1119
1120 if (nb_tbs <= 0)
1121 return NULL;
1122 if (tc_ptr < (unsigned long)code_gen_buffer ||
1123 tc_ptr >= (unsigned long)code_gen_ptr)
1124 return NULL;
1125 /* binary search (cf Knuth) */
1126 m_min = 0;
1127 m_max = nb_tbs - 1;
1128 while (m_min <= m_max) {
1129 m = (m_min + m_max) >> 1;
1130 tb = &tbs[m];
1131 v = (unsigned long)tb->tc_ptr;
1132 if (v == tc_ptr)
1133 return tb;
1134 else if (tc_ptr < v) {
1135 m_max = m - 1;
1136 } else {
1137 m_min = m + 1;
1138 }
ths5fafdf22007-09-16 21:08:06 +00001139 }
bellarda513fe12003-05-27 23:29:48 +00001140 return &tbs[m_max];
1141}
bellard75012672003-06-21 13:11:07 +00001142
bellardea041c02003-06-25 16:16:50 +00001143static void tb_reset_jump_recursive(TranslationBlock *tb);
1144
1145static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1146{
1147 TranslationBlock *tb1, *tb_next, **ptb;
1148 unsigned int n1;
1149
1150 tb1 = tb->jmp_next[n];
1151 if (tb1 != NULL) {
1152 /* find head of list */
1153 for(;;) {
1154 n1 = (long)tb1 & 3;
1155 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1156 if (n1 == 2)
1157 break;
1158 tb1 = tb1->jmp_next[n1];
1159 }
1160 /* we are now sure now that tb jumps to tb1 */
1161 tb_next = tb1;
1162
1163 /* remove tb from the jmp_first list */
1164 ptb = &tb_next->jmp_first;
1165 for(;;) {
1166 tb1 = *ptb;
1167 n1 = (long)tb1 & 3;
1168 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1169 if (n1 == n && tb1 == tb)
1170 break;
1171 ptb = &tb1->jmp_next[n1];
1172 }
1173 *ptb = tb->jmp_next[n];
1174 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001175
bellardea041c02003-06-25 16:16:50 +00001176 /* suppress the jump to next tb in generated code */
1177 tb_reset_jump(tb, n);
1178
bellard01243112004-01-04 15:48:17 +00001179 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001180 tb_reset_jump_recursive(tb_next);
1181 }
1182}
1183
1184static void tb_reset_jump_recursive(TranslationBlock *tb)
1185{
1186 tb_reset_jump_recursive2(tb, 0);
1187 tb_reset_jump_recursive2(tb, 1);
1188}
1189
bellard1fddef42005-04-17 19:16:13 +00001190#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001191static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1192{
j_mayer9b3c35e2007-04-07 11:21:28 +00001193 target_phys_addr_t addr;
1194 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001195 ram_addr_t ram_addr;
1196 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001197
pbrookc2f07f82006-04-08 17:14:56 +00001198 addr = cpu_get_phys_page_debug(env, pc);
1199 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1200 if (!p) {
1201 pd = IO_MEM_UNASSIGNED;
1202 } else {
1203 pd = p->phys_offset;
1204 }
1205 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001206 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001207}
bellardc27004e2005-01-03 23:35:10 +00001208#endif
bellardd720b932004-04-25 17:57:43 +00001209
pbrook6658ffb2007-03-16 23:58:11 +00001210/* Add a watchpoint. */
pbrook0f459d12008-06-09 00:20:13 +00001211int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
pbrook6658ffb2007-03-16 23:58:11 +00001212{
1213 int i;
1214
1215 for (i = 0; i < env->nb_watchpoints; i++) {
1216 if (addr == env->watchpoint[i].vaddr)
1217 return 0;
1218 }
1219 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1220 return -1;
1221
1222 i = env->nb_watchpoints++;
1223 env->watchpoint[i].vaddr = addr;
pbrook0f459d12008-06-09 00:20:13 +00001224 env->watchpoint[i].type = type;
pbrook6658ffb2007-03-16 23:58:11 +00001225 tlb_flush_page(env, addr);
1226 /* FIXME: This flush is needed because of the hack to make memory ops
1227 terminate the TB. It can be removed once the proper IO trap and
1228 re-execute bits are in. */
1229 tb_flush(env);
1230 return i;
1231}
1232
1233/* Remove a watchpoint. */
1234int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1235{
1236 int i;
1237
1238 for (i = 0; i < env->nb_watchpoints; i++) {
1239 if (addr == env->watchpoint[i].vaddr) {
1240 env->nb_watchpoints--;
1241 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1242 tlb_flush_page(env, addr);
1243 return 0;
1244 }
1245 }
1246 return -1;
1247}
1248
edgar_igl7d03f822008-05-17 18:58:29 +00001249/* Remove all watchpoints. */
1250void cpu_watchpoint_remove_all(CPUState *env) {
1251 int i;
1252
1253 for (i = 0; i < env->nb_watchpoints; i++) {
1254 tlb_flush_page(env, env->watchpoint[i].vaddr);
1255 }
1256 env->nb_watchpoints = 0;
1257}
1258
bellardc33a3462003-07-29 20:50:33 +00001259/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1260 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001261int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001262{
bellard1fddef42005-04-17 19:16:13 +00001263#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001264 int i;
ths3b46e622007-09-17 08:09:54 +00001265
bellard4c3a88a2003-07-26 12:06:08 +00001266 for(i = 0; i < env->nb_breakpoints; i++) {
1267 if (env->breakpoints[i] == pc)
1268 return 0;
1269 }
1270
1271 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1272 return -1;
1273 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001274
bellardd720b932004-04-25 17:57:43 +00001275 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001276 return 0;
1277#else
1278 return -1;
1279#endif
1280}
1281
edgar_igl7d03f822008-05-17 18:58:29 +00001282/* remove all breakpoints */
1283void cpu_breakpoint_remove_all(CPUState *env) {
1284#if defined(TARGET_HAS_ICE)
1285 int i;
1286 for(i = 0; i < env->nb_breakpoints; i++) {
1287 breakpoint_invalidate(env, env->breakpoints[i]);
1288 }
1289 env->nb_breakpoints = 0;
1290#endif
1291}
1292
bellard4c3a88a2003-07-26 12:06:08 +00001293/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001294int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001295{
bellard1fddef42005-04-17 19:16:13 +00001296#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001297 int i;
1298 for(i = 0; i < env->nb_breakpoints; i++) {
1299 if (env->breakpoints[i] == pc)
1300 goto found;
1301 }
1302 return -1;
1303 found:
bellard4c3a88a2003-07-26 12:06:08 +00001304 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001305 if (i < env->nb_breakpoints)
1306 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001307
1308 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001309 return 0;
1310#else
1311 return -1;
1312#endif
1313}
1314
bellardc33a3462003-07-29 20:50:33 +00001315/* enable or disable single step mode. EXCP_DEBUG is returned by the
1316 CPU loop after each instruction */
1317void cpu_single_step(CPUState *env, int enabled)
1318{
bellard1fddef42005-04-17 19:16:13 +00001319#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001320 if (env->singlestep_enabled != enabled) {
1321 env->singlestep_enabled = enabled;
1322 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001323 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001324 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001325 }
1326#endif
1327}
1328
bellard34865132003-10-05 14:28:56 +00001329/* enable or disable low levels log */
1330void cpu_set_log(int log_flags)
1331{
1332 loglevel = log_flags;
1333 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001334 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001335 if (!logfile) {
1336 perror(logfilename);
1337 _exit(1);
1338 }
bellard9fa3e852004-01-04 18:06:42 +00001339#if !defined(CONFIG_SOFTMMU)
1340 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1341 {
1342 static uint8_t logfile_buf[4096];
1343 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1344 }
1345#else
bellard34865132003-10-05 14:28:56 +00001346 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001347#endif
pbrooke735b912007-06-30 13:53:24 +00001348 log_append = 1;
1349 }
1350 if (!loglevel && logfile) {
1351 fclose(logfile);
1352 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001353 }
1354}
1355
1356void cpu_set_log_filename(const char *filename)
1357{
1358 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001359 if (logfile) {
1360 fclose(logfile);
1361 logfile = NULL;
1362 }
1363 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001364}
bellardc33a3462003-07-29 20:50:33 +00001365
bellard01243112004-01-04 15:48:17 +00001366/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001367void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001368{
pbrookd5975362008-06-07 20:50:51 +00001369#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001370 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001371 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001372#endif
bellard59817cc2004-02-16 22:01:13 +00001373
pbrookd5975362008-06-07 20:50:51 +00001374 /* FIXME: This is probably not threadsafe. A different thread could
1375 be in the mittle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001376 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001377#if defined(USE_NPTL)
1378 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1379 problem and hope the cpu will stop of its own accord. For userspace
1380 emulation this often isn't actually as bad as it sounds. Often
1381 signals are used primarily to interrupt blocking syscalls. */
1382#else
bellardea041c02003-06-25 16:16:50 +00001383 /* if the cpu is currently executing code, we must unlink it and
1384 all the potentially executing TB */
1385 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001386 if (tb && !testandset(&interrupt_lock)) {
1387 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001388 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001389 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001390 }
pbrookd5975362008-06-07 20:50:51 +00001391#endif
bellardea041c02003-06-25 16:16:50 +00001392}
1393
bellardb54ad042004-05-20 13:42:52 +00001394void cpu_reset_interrupt(CPUState *env, int mask)
1395{
1396 env->interrupt_request &= ~mask;
1397}
1398
bellardf193c792004-03-21 17:06:25 +00001399CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001400 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001401 "show generated host assembly code for each compiled TB" },
1402 { CPU_LOG_TB_IN_ASM, "in_asm",
1403 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001404 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001405 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001406 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001407 "show micro ops "
1408#ifdef TARGET_I386
1409 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001410#endif
blueswir1e01a1152008-03-14 17:37:11 +00001411 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001412 { CPU_LOG_INT, "int",
1413 "show interrupts/exceptions in short format" },
1414 { CPU_LOG_EXEC, "exec",
1415 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001416 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001417 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001418#ifdef TARGET_I386
1419 { CPU_LOG_PCALL, "pcall",
1420 "show protected mode far calls/returns/exceptions" },
1421#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001422#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001423 { CPU_LOG_IOPORT, "ioport",
1424 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001425#endif
bellardf193c792004-03-21 17:06:25 +00001426 { 0, NULL, NULL },
1427};
1428
1429static int cmp1(const char *s1, int n, const char *s2)
1430{
1431 if (strlen(s2) != n)
1432 return 0;
1433 return memcmp(s1, s2, n) == 0;
1434}
ths3b46e622007-09-17 08:09:54 +00001435
bellardf193c792004-03-21 17:06:25 +00001436/* takes a comma separated list of log masks. Return 0 if error. */
1437int cpu_str_to_log_mask(const char *str)
1438{
1439 CPULogItem *item;
1440 int mask;
1441 const char *p, *p1;
1442
1443 p = str;
1444 mask = 0;
1445 for(;;) {
1446 p1 = strchr(p, ',');
1447 if (!p1)
1448 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001449 if(cmp1(p,p1-p,"all")) {
1450 for(item = cpu_log_items; item->mask != 0; item++) {
1451 mask |= item->mask;
1452 }
1453 } else {
bellardf193c792004-03-21 17:06:25 +00001454 for(item = cpu_log_items; item->mask != 0; item++) {
1455 if (cmp1(p, p1 - p, item->name))
1456 goto found;
1457 }
1458 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001459 }
bellardf193c792004-03-21 17:06:25 +00001460 found:
1461 mask |= item->mask;
1462 if (*p1 != ',')
1463 break;
1464 p = p1 + 1;
1465 }
1466 return mask;
1467}
bellardea041c02003-06-25 16:16:50 +00001468
bellard75012672003-06-21 13:11:07 +00001469void cpu_abort(CPUState *env, const char *fmt, ...)
1470{
1471 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001472 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001473
1474 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001475 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001476 fprintf(stderr, "qemu: fatal: ");
1477 vfprintf(stderr, fmt, ap);
1478 fprintf(stderr, "\n");
1479#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001480 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1481#else
1482 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001483#endif
balrog924edca2007-06-10 14:07:13 +00001484 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001485 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001486 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001487 fprintf(logfile, "\n");
1488#ifdef TARGET_I386
1489 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1490#else
1491 cpu_dump_state(env, logfile, fprintf, 0);
1492#endif
balrog924edca2007-06-10 14:07:13 +00001493 fflush(logfile);
1494 fclose(logfile);
1495 }
pbrook493ae1f2007-11-23 16:53:59 +00001496 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001497 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001498 abort();
1499}
1500
thsc5be9f02007-02-28 20:20:53 +00001501CPUState *cpu_copy(CPUState *env)
1502{
ths01ba9812007-12-09 02:22:57 +00001503 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001504 /* preserve chaining and index */
1505 CPUState *next_cpu = new_env->next_cpu;
1506 int cpu_index = new_env->cpu_index;
1507 memcpy(new_env, env, sizeof(CPUState));
1508 new_env->next_cpu = next_cpu;
1509 new_env->cpu_index = cpu_index;
1510 return new_env;
1511}
1512
bellard01243112004-01-04 15:48:17 +00001513#if !defined(CONFIG_USER_ONLY)
1514
edgar_igl5c751e92008-05-06 08:44:21 +00001515static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1516{
1517 unsigned int i;
1518
1519 /* Discard jump cache entries for any tb which might potentially
1520 overlap the flushed page. */
1521 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1522 memset (&env->tb_jmp_cache[i], 0,
1523 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1524
1525 i = tb_jmp_cache_hash_page(addr);
1526 memset (&env->tb_jmp_cache[i], 0,
1527 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1528}
1529
bellardee8b7022004-02-03 23:35:10 +00001530/* NOTE: if flush_global is true, also flush global entries (not
1531 implemented yet) */
1532void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001533{
bellard33417e72003-08-10 21:47:01 +00001534 int i;
bellard01243112004-01-04 15:48:17 +00001535
bellard9fa3e852004-01-04 18:06:42 +00001536#if defined(DEBUG_TLB)
1537 printf("tlb_flush:\n");
1538#endif
bellard01243112004-01-04 15:48:17 +00001539 /* must reset current TB so that interrupts cannot modify the
1540 links while we are modifying them */
1541 env->current_tb = NULL;
1542
bellard33417e72003-08-10 21:47:01 +00001543 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001544 env->tlb_table[0][i].addr_read = -1;
1545 env->tlb_table[0][i].addr_write = -1;
1546 env->tlb_table[0][i].addr_code = -1;
1547 env->tlb_table[1][i].addr_read = -1;
1548 env->tlb_table[1][i].addr_write = -1;
1549 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001550#if (NB_MMU_MODES >= 3)
1551 env->tlb_table[2][i].addr_read = -1;
1552 env->tlb_table[2][i].addr_write = -1;
1553 env->tlb_table[2][i].addr_code = -1;
1554#if (NB_MMU_MODES == 4)
1555 env->tlb_table[3][i].addr_read = -1;
1556 env->tlb_table[3][i].addr_write = -1;
1557 env->tlb_table[3][i].addr_code = -1;
1558#endif
1559#endif
bellard33417e72003-08-10 21:47:01 +00001560 }
bellard9fa3e852004-01-04 18:06:42 +00001561
bellard8a40a182005-11-20 10:35:40 +00001562 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001563
bellard0a962c02005-02-10 22:00:27 +00001564#ifdef USE_KQEMU
1565 if (env->kqemu_enabled) {
1566 kqemu_flush(env, flush_global);
1567 }
1568#endif
bellarde3db7222005-01-26 22:00:47 +00001569 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001570}
1571
bellard274da6b2004-05-20 21:56:27 +00001572static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001573{
ths5fafdf22007-09-16 21:08:06 +00001574 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001575 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001576 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001577 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001578 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001579 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1580 tlb_entry->addr_read = -1;
1581 tlb_entry->addr_write = -1;
1582 tlb_entry->addr_code = -1;
1583 }
bellard61382a52003-10-27 21:22:23 +00001584}
1585
bellard2e126692004-04-25 21:28:44 +00001586void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001587{
bellard8a40a182005-11-20 10:35:40 +00001588 int i;
bellard01243112004-01-04 15:48:17 +00001589
bellard9fa3e852004-01-04 18:06:42 +00001590#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001591 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001592#endif
bellard01243112004-01-04 15:48:17 +00001593 /* must reset current TB so that interrupts cannot modify the
1594 links while we are modifying them */
1595 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001596
bellard61382a52003-10-27 21:22:23 +00001597 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001598 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001599 tlb_flush_entry(&env->tlb_table[0][i], addr);
1600 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001601#if (NB_MMU_MODES >= 3)
1602 tlb_flush_entry(&env->tlb_table[2][i], addr);
1603#if (NB_MMU_MODES == 4)
1604 tlb_flush_entry(&env->tlb_table[3][i], addr);
1605#endif
1606#endif
bellard01243112004-01-04 15:48:17 +00001607
edgar_igl5c751e92008-05-06 08:44:21 +00001608 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001609
bellard0a962c02005-02-10 22:00:27 +00001610#ifdef USE_KQEMU
1611 if (env->kqemu_enabled) {
1612 kqemu_flush_page(env, addr);
1613 }
1614#endif
bellard9fa3e852004-01-04 18:06:42 +00001615}
1616
bellard9fa3e852004-01-04 18:06:42 +00001617/* update the TLBs so that writes to code in the virtual page 'addr'
1618 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001619static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001620{
ths5fafdf22007-09-16 21:08:06 +00001621 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001622 ram_addr + TARGET_PAGE_SIZE,
1623 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001624}
1625
bellard9fa3e852004-01-04 18:06:42 +00001626/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001627 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001628static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001629 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001630{
bellard3a7d9292005-08-21 09:26:42 +00001631 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001632}
1633
ths5fafdf22007-09-16 21:08:06 +00001634static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001635 unsigned long start, unsigned long length)
1636{
1637 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001638 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1639 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001640 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001641 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001642 }
1643 }
1644}
1645
bellard3a7d9292005-08-21 09:26:42 +00001646void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001647 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001648{
1649 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001650 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001651 int i, mask, len;
1652 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001653
1654 start &= TARGET_PAGE_MASK;
1655 end = TARGET_PAGE_ALIGN(end);
1656
1657 length = end - start;
1658 if (length == 0)
1659 return;
bellard0a962c02005-02-10 22:00:27 +00001660 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001661#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001662 /* XXX: should not depend on cpu context */
1663 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001664 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001665 ram_addr_t addr;
1666 addr = start;
1667 for(i = 0; i < len; i++) {
1668 kqemu_set_notdirty(env, addr);
1669 addr += TARGET_PAGE_SIZE;
1670 }
bellard3a7d9292005-08-21 09:26:42 +00001671 }
1672#endif
bellardf23db162005-08-21 19:12:28 +00001673 mask = ~dirty_flags;
1674 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1675 for(i = 0; i < len; i++)
1676 p[i] &= mask;
1677
bellard1ccde1c2004-02-06 19:46:14 +00001678 /* we modify the TLB cache so that the dirty bit will be set again
1679 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001680 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001681 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1682 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001683 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001684 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001685 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001686#if (NB_MMU_MODES >= 3)
1687 for(i = 0; i < CPU_TLB_SIZE; i++)
1688 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1689#if (NB_MMU_MODES == 4)
1690 for(i = 0; i < CPU_TLB_SIZE; i++)
1691 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1692#endif
1693#endif
bellard6a00d602005-11-21 23:25:50 +00001694 }
bellard1ccde1c2004-02-06 19:46:14 +00001695}
1696
bellard3a7d9292005-08-21 09:26:42 +00001697static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1698{
1699 ram_addr_t ram_addr;
1700
bellard84b7b8e2005-11-28 21:19:04 +00001701 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001702 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001703 tlb_entry->addend - (unsigned long)phys_ram_base;
1704 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001705 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001706 }
1707 }
1708}
1709
1710/* update the TLB according to the current state of the dirty bits */
1711void cpu_tlb_update_dirty(CPUState *env)
1712{
1713 int i;
1714 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001715 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001716 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001717 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001718#if (NB_MMU_MODES >= 3)
1719 for(i = 0; i < CPU_TLB_SIZE; i++)
1720 tlb_update_dirty(&env->tlb_table[2][i]);
1721#if (NB_MMU_MODES == 4)
1722 for(i = 0; i < CPU_TLB_SIZE; i++)
1723 tlb_update_dirty(&env->tlb_table[3][i]);
1724#endif
1725#endif
bellard3a7d9292005-08-21 09:26:42 +00001726}
1727
pbrook0f459d12008-06-09 00:20:13 +00001728static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001729{
pbrook0f459d12008-06-09 00:20:13 +00001730 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1731 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001732}
1733
pbrook0f459d12008-06-09 00:20:13 +00001734/* update the TLB corresponding to virtual page vaddr
1735 so that it is no longer dirty */
1736static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001737{
bellard1ccde1c2004-02-06 19:46:14 +00001738 int i;
1739
pbrook0f459d12008-06-09 00:20:13 +00001740 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001741 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001742 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1743 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001744#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001745 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001746#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001747 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001748#endif
1749#endif
bellard9fa3e852004-01-04 18:06:42 +00001750}
1751
bellard59817cc2004-02-16 22:01:13 +00001752/* add a new TLB entry. At most one entry for a given virtual address
1753 is permitted. Return 0 if OK or 2 if the page could not be mapped
1754 (can only happen in non SOFTMMU mode for I/O pages or pages
1755 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001756int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1757 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001758 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001759{
bellard92e873b2004-05-21 14:52:29 +00001760 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001761 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001762 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001763 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001764 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001765 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001766 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001767 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001768 int i;
pbrook0f459d12008-06-09 00:20:13 +00001769 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001770
bellard92e873b2004-05-21 14:52:29 +00001771 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001772 if (!p) {
1773 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001774 } else {
1775 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001776 }
1777#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001778 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1779 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001780#endif
1781
1782 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001783 address = vaddr;
1784 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1785 /* IO memory case (romd handled later) */
1786 address |= TLB_MMIO;
1787 }
1788 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1789 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1790 /* Normal RAM. */
1791 iotlb = pd & TARGET_PAGE_MASK;
1792 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1793 iotlb |= IO_MEM_NOTDIRTY;
1794 else
1795 iotlb |= IO_MEM_ROM;
1796 } else {
1797 /* IO handlers are currently passed a phsical address.
1798 It would be nice to pass an offset from the base address
1799 of that region. This would avoid having to special case RAM,
1800 and avoid full address decoding in every device.
1801 We can't use the high bits of pd for this because
1802 IO_MEM_ROMD uses these as a ram address. */
1803 iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
1804 }
pbrook6658ffb2007-03-16 23:58:11 +00001805
pbrook0f459d12008-06-09 00:20:13 +00001806 code_address = address;
1807 /* Make accesses to pages with watchpoints go via the
1808 watchpoint trap routines. */
1809 for (i = 0; i < env->nb_watchpoints; i++) {
1810 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1811 iotlb = io_mem_watch + paddr;
1812 /* TODO: The memory case can be optimized by not trapping
1813 reads of pages with a write breakpoint. */
1814 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00001815 }
pbrook0f459d12008-06-09 00:20:13 +00001816 }
balrogd79acba2007-06-26 20:01:13 +00001817
pbrook0f459d12008-06-09 00:20:13 +00001818 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1819 env->iotlb[mmu_idx][index] = iotlb - vaddr;
1820 te = &env->tlb_table[mmu_idx][index];
1821 te->addend = addend - vaddr;
1822 if (prot & PAGE_READ) {
1823 te->addr_read = address;
1824 } else {
1825 te->addr_read = -1;
1826 }
edgar_igl5c751e92008-05-06 08:44:21 +00001827
pbrook0f459d12008-06-09 00:20:13 +00001828 if (prot & PAGE_EXEC) {
1829 te->addr_code = code_address;
1830 } else {
1831 te->addr_code = -1;
1832 }
1833 if (prot & PAGE_WRITE) {
1834 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1835 (pd & IO_MEM_ROMD)) {
1836 /* Write access calls the I/O callback. */
1837 te->addr_write = address | TLB_MMIO;
1838 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1839 !cpu_physical_memory_is_dirty(pd)) {
1840 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00001841 } else {
pbrook0f459d12008-06-09 00:20:13 +00001842 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001843 }
pbrook0f459d12008-06-09 00:20:13 +00001844 } else {
1845 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001846 }
bellard9fa3e852004-01-04 18:06:42 +00001847 return ret;
1848}
1849
bellard01243112004-01-04 15:48:17 +00001850#else
1851
bellardee8b7022004-02-03 23:35:10 +00001852void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001853{
1854}
1855
bellard2e126692004-04-25 21:28:44 +00001856void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001857{
1858}
1859
ths5fafdf22007-09-16 21:08:06 +00001860int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1861 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001862 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001863{
bellard9fa3e852004-01-04 18:06:42 +00001864 return 0;
1865}
bellard33417e72003-08-10 21:47:01 +00001866
bellard9fa3e852004-01-04 18:06:42 +00001867/* dump memory mappings */
1868void page_dump(FILE *f)
1869{
1870 unsigned long start, end;
1871 int i, j, prot, prot1;
1872 PageDesc *p;
1873
1874 fprintf(f, "%-8s %-8s %-8s %s\n",
1875 "start", "end", "size", "prot");
1876 start = -1;
1877 end = -1;
1878 prot = 0;
1879 for(i = 0; i <= L1_SIZE; i++) {
1880 if (i < L1_SIZE)
1881 p = l1_map[i];
1882 else
1883 p = NULL;
1884 for(j = 0;j < L2_SIZE; j++) {
1885 if (!p)
1886 prot1 = 0;
1887 else
1888 prot1 = p[j].flags;
1889 if (prot1 != prot) {
1890 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1891 if (start != -1) {
1892 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001893 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001894 prot & PAGE_READ ? 'r' : '-',
1895 prot & PAGE_WRITE ? 'w' : '-',
1896 prot & PAGE_EXEC ? 'x' : '-');
1897 }
1898 if (prot1 != 0)
1899 start = end;
1900 else
1901 start = -1;
1902 prot = prot1;
1903 }
1904 if (!p)
1905 break;
1906 }
bellard33417e72003-08-10 21:47:01 +00001907 }
bellard33417e72003-08-10 21:47:01 +00001908}
1909
pbrook53a59602006-03-25 19:31:22 +00001910int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001911{
bellard9fa3e852004-01-04 18:06:42 +00001912 PageDesc *p;
1913
1914 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001915 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001916 return 0;
1917 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001918}
1919
bellard9fa3e852004-01-04 18:06:42 +00001920/* modify the flags of a page and invalidate the code if
1921 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1922 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001923void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001924{
1925 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001926 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001927
pbrookc8a706f2008-06-02 16:16:42 +00001928 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00001929 start = start & TARGET_PAGE_MASK;
1930 end = TARGET_PAGE_ALIGN(end);
1931 if (flags & PAGE_WRITE)
1932 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00001933 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1934 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00001935 /* We may be called for host regions that are outside guest
1936 address space. */
1937 if (!p)
1938 return;
bellard9fa3e852004-01-04 18:06:42 +00001939 /* if the write protection is set, then we invalidate the code
1940 inside */
ths5fafdf22007-09-16 21:08:06 +00001941 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001942 (flags & PAGE_WRITE) &&
1943 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001944 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001945 }
1946 p->flags = flags;
1947 }
bellard9fa3e852004-01-04 18:06:42 +00001948}
1949
ths3d97b402007-11-02 19:02:07 +00001950int page_check_range(target_ulong start, target_ulong len, int flags)
1951{
1952 PageDesc *p;
1953 target_ulong end;
1954 target_ulong addr;
1955
1956 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1957 start = start & TARGET_PAGE_MASK;
1958
1959 if( end < start )
1960 /* we've wrapped around */
1961 return -1;
1962 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1963 p = page_find(addr >> TARGET_PAGE_BITS);
1964 if( !p )
1965 return -1;
1966 if( !(p->flags & PAGE_VALID) )
1967 return -1;
1968
bellarddae32702007-11-14 10:51:00 +00001969 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001970 return -1;
bellarddae32702007-11-14 10:51:00 +00001971 if (flags & PAGE_WRITE) {
1972 if (!(p->flags & PAGE_WRITE_ORG))
1973 return -1;
1974 /* unprotect the page if it was put read-only because it
1975 contains translated code */
1976 if (!(p->flags & PAGE_WRITE)) {
1977 if (!page_unprotect(addr, 0, NULL))
1978 return -1;
1979 }
1980 return 0;
1981 }
ths3d97b402007-11-02 19:02:07 +00001982 }
1983 return 0;
1984}
1985
bellard9fa3e852004-01-04 18:06:42 +00001986/* called from signal handler: invalidate the code and unprotect the
1987 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001988int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001989{
1990 unsigned int page_index, prot, pindex;
1991 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001992 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001993
pbrookc8a706f2008-06-02 16:16:42 +00001994 /* Technically this isn't safe inside a signal handler. However we
1995 know this only ever happens in a synchronous SEGV handler, so in
1996 practice it seems to be ok. */
1997 mmap_lock();
1998
bellard83fb7ad2004-07-05 21:25:26 +00001999 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002000 page_index = host_start >> TARGET_PAGE_BITS;
2001 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002002 if (!p1) {
2003 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002004 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002005 }
bellard83fb7ad2004-07-05 21:25:26 +00002006 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002007 p = p1;
2008 prot = 0;
2009 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2010 prot |= p->flags;
2011 p++;
2012 }
2013 /* if the page was really writable, then we change its
2014 protection back to writable */
2015 if (prot & PAGE_WRITE_ORG) {
2016 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2017 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002018 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002019 (prot & PAGE_BITS) | PAGE_WRITE);
2020 p1[pindex].flags |= PAGE_WRITE;
2021 /* and since the content will be modified, we must invalidate
2022 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002023 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002024#ifdef DEBUG_TB_CHECK
2025 tb_invalidate_check(address);
2026#endif
pbrookc8a706f2008-06-02 16:16:42 +00002027 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002028 return 1;
2029 }
2030 }
pbrookc8a706f2008-06-02 16:16:42 +00002031 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002032 return 0;
2033}
2034
bellard6a00d602005-11-21 23:25:50 +00002035static inline void tlb_set_dirty(CPUState *env,
2036 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002037{
2038}
bellard9fa3e852004-01-04 18:06:42 +00002039#endif /* defined(CONFIG_USER_ONLY) */
2040
pbrooke2eef172008-06-08 01:09:01 +00002041#if !defined(CONFIG_USER_ONLY)
blueswir1db7b5422007-05-26 17:36:03 +00002042static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002043 ram_addr_t memory);
2044static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2045 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002046#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2047 need_subpage) \
2048 do { \
2049 if (addr > start_addr) \
2050 start_addr2 = 0; \
2051 else { \
2052 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2053 if (start_addr2 > 0) \
2054 need_subpage = 1; \
2055 } \
2056 \
blueswir149e9fba2007-05-30 17:25:06 +00002057 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002058 end_addr2 = TARGET_PAGE_SIZE - 1; \
2059 else { \
2060 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2061 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2062 need_subpage = 1; \
2063 } \
2064 } while (0)
2065
bellard33417e72003-08-10 21:47:01 +00002066/* register physical memory. 'size' must be a multiple of the target
2067 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2068 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002069void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002070 ram_addr_t size,
2071 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002072{
bellard108c49b2005-07-24 12:55:09 +00002073 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002074 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002075 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002076 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002077 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002078
bellardda260242008-05-30 20:48:25 +00002079#ifdef USE_KQEMU
2080 /* XXX: should not depend on cpu context */
2081 env = first_cpu;
2082 if (env->kqemu_enabled) {
2083 kqemu_set_phys_mem(start_addr, size, phys_offset);
2084 }
2085#endif
bellard5fd386f2004-05-23 21:11:22 +00002086 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002087 end_addr = start_addr + (target_phys_addr_t)size;
2088 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002089 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2090 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002091 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002092 target_phys_addr_t start_addr2, end_addr2;
2093 int need_subpage = 0;
2094
2095 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2096 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002097 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002098 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2099 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2100 &p->phys_offset, orig_memory);
2101 } else {
2102 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2103 >> IO_MEM_SHIFT];
2104 }
2105 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2106 } else {
2107 p->phys_offset = phys_offset;
2108 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2109 (phys_offset & IO_MEM_ROMD))
2110 phys_offset += TARGET_PAGE_SIZE;
2111 }
2112 } else {
2113 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2114 p->phys_offset = phys_offset;
2115 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2116 (phys_offset & IO_MEM_ROMD))
2117 phys_offset += TARGET_PAGE_SIZE;
2118 else {
2119 target_phys_addr_t start_addr2, end_addr2;
2120 int need_subpage = 0;
2121
2122 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2123 end_addr2, need_subpage);
2124
blueswir14254fab2008-01-01 16:57:19 +00002125 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002126 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2127 &p->phys_offset, IO_MEM_UNASSIGNED);
2128 subpage_register(subpage, start_addr2, end_addr2,
2129 phys_offset);
2130 }
2131 }
2132 }
bellard33417e72003-08-10 21:47:01 +00002133 }
ths3b46e622007-09-17 08:09:54 +00002134
bellard9d420372006-06-25 22:25:22 +00002135 /* since each CPU stores ram addresses in its TLB cache, we must
2136 reset the modified entries */
2137 /* XXX: slow ! */
2138 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2139 tlb_flush(env, 1);
2140 }
bellard33417e72003-08-10 21:47:01 +00002141}
2142
bellardba863452006-09-24 18:41:10 +00002143/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002144ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002145{
2146 PhysPageDesc *p;
2147
2148 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2149 if (!p)
2150 return IO_MEM_UNASSIGNED;
2151 return p->phys_offset;
2152}
2153
bellarde9a1ab12007-02-08 23:08:38 +00002154/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002155ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002156{
2157 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002158 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002159 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2160 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002161 abort();
2162 }
2163 addr = phys_ram_alloc_offset;
2164 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2165 return addr;
2166}
2167
2168void qemu_ram_free(ram_addr_t addr)
2169{
2170}
2171
bellarda4193c82004-06-03 14:01:43 +00002172static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002173{
pbrook67d3b952006-12-18 05:03:52 +00002174#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002175 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002176#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002177#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002178 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002179#elif TARGET_CRIS
2180 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002181#endif
bellard33417e72003-08-10 21:47:01 +00002182 return 0;
2183}
2184
bellarda4193c82004-06-03 14:01:43 +00002185static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002186{
pbrook67d3b952006-12-18 05:03:52 +00002187#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002188 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002189#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002190#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002191 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002192#elif TARGET_CRIS
2193 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002194#endif
bellard33417e72003-08-10 21:47:01 +00002195}
2196
2197static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2198 unassigned_mem_readb,
2199 unassigned_mem_readb,
2200 unassigned_mem_readb,
2201};
2202
2203static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2204 unassigned_mem_writeb,
2205 unassigned_mem_writeb,
2206 unassigned_mem_writeb,
2207};
2208
pbrook0f459d12008-06-09 00:20:13 +00002209static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2210 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002211{
bellard3a7d9292005-08-21 09:26:42 +00002212 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002213 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2214 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2215#if !defined(CONFIG_USER_ONLY)
2216 tb_invalidate_phys_page_fast(ram_addr, 1);
2217 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2218#endif
2219 }
pbrook0f459d12008-06-09 00:20:13 +00002220 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002221#ifdef USE_KQEMU
2222 if (cpu_single_env->kqemu_enabled &&
2223 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2224 kqemu_modify_page(cpu_single_env, ram_addr);
2225#endif
bellardf23db162005-08-21 19:12:28 +00002226 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2227 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2228 /* we remove the notdirty callback only if the code has been
2229 flushed */
2230 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002231 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002232}
2233
pbrook0f459d12008-06-09 00:20:13 +00002234static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2235 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002236{
bellard3a7d9292005-08-21 09:26:42 +00002237 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002238 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2239 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2240#if !defined(CONFIG_USER_ONLY)
2241 tb_invalidate_phys_page_fast(ram_addr, 2);
2242 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2243#endif
2244 }
pbrook0f459d12008-06-09 00:20:13 +00002245 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002246#ifdef USE_KQEMU
2247 if (cpu_single_env->kqemu_enabled &&
2248 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2249 kqemu_modify_page(cpu_single_env, ram_addr);
2250#endif
bellardf23db162005-08-21 19:12:28 +00002251 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2252 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2253 /* we remove the notdirty callback only if the code has been
2254 flushed */
2255 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002256 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002257}
2258
pbrook0f459d12008-06-09 00:20:13 +00002259static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2260 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002261{
bellard3a7d9292005-08-21 09:26:42 +00002262 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002263 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2264 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2265#if !defined(CONFIG_USER_ONLY)
2266 tb_invalidate_phys_page_fast(ram_addr, 4);
2267 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2268#endif
2269 }
pbrook0f459d12008-06-09 00:20:13 +00002270 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002271#ifdef USE_KQEMU
2272 if (cpu_single_env->kqemu_enabled &&
2273 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2274 kqemu_modify_page(cpu_single_env, ram_addr);
2275#endif
bellardf23db162005-08-21 19:12:28 +00002276 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2277 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2278 /* we remove the notdirty callback only if the code has been
2279 flushed */
2280 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002281 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002282}
2283
bellard3a7d9292005-08-21 09:26:42 +00002284static CPUReadMemoryFunc *error_mem_read[3] = {
2285 NULL, /* never used */
2286 NULL, /* never used */
2287 NULL, /* never used */
2288};
2289
bellard1ccde1c2004-02-06 19:46:14 +00002290static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2291 notdirty_mem_writeb,
2292 notdirty_mem_writew,
2293 notdirty_mem_writel,
2294};
2295
pbrook0f459d12008-06-09 00:20:13 +00002296/* Generate a debug exception if a watchpoint has been hit. */
2297static void check_watchpoint(int offset, int flags)
2298{
2299 CPUState *env = cpu_single_env;
2300 target_ulong vaddr;
2301 int i;
2302
2303 vaddr = (env->mem_write_vaddr & TARGET_PAGE_MASK) + offset;
2304 for (i = 0; i < env->nb_watchpoints; i++) {
2305 if (vaddr == env->watchpoint[i].vaddr
2306 && (env->watchpoint[i].type & flags)) {
2307 env->watchpoint_hit = i + 1;
2308 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2309 break;
2310 }
2311 }
2312}
2313
pbrook6658ffb2007-03-16 23:58:11 +00002314/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2315 so these check for a hit then pass through to the normal out-of-line
2316 phys routines. */
2317static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2318{
pbrook0f459d12008-06-09 00:20:13 +00002319 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002320 return ldub_phys(addr);
2321}
2322
2323static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2324{
pbrook0f459d12008-06-09 00:20:13 +00002325 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002326 return lduw_phys(addr);
2327}
2328
2329static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2330{
pbrook0f459d12008-06-09 00:20:13 +00002331 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002332 return ldl_phys(addr);
2333}
2334
pbrook6658ffb2007-03-16 23:58:11 +00002335static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2336 uint32_t val)
2337{
pbrook0f459d12008-06-09 00:20:13 +00002338 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002339 stb_phys(addr, val);
2340}
2341
2342static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2343 uint32_t val)
2344{
pbrook0f459d12008-06-09 00:20:13 +00002345 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002346 stw_phys(addr, val);
2347}
2348
2349static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2350 uint32_t val)
2351{
pbrook0f459d12008-06-09 00:20:13 +00002352 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002353 stl_phys(addr, val);
2354}
2355
2356static CPUReadMemoryFunc *watch_mem_read[3] = {
2357 watch_mem_readb,
2358 watch_mem_readw,
2359 watch_mem_readl,
2360};
2361
2362static CPUWriteMemoryFunc *watch_mem_write[3] = {
2363 watch_mem_writeb,
2364 watch_mem_writew,
2365 watch_mem_writel,
2366};
pbrook6658ffb2007-03-16 23:58:11 +00002367
blueswir1db7b5422007-05-26 17:36:03 +00002368static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2369 unsigned int len)
2370{
blueswir1db7b5422007-05-26 17:36:03 +00002371 uint32_t ret;
2372 unsigned int idx;
2373
2374 idx = SUBPAGE_IDX(addr - mmio->base);
2375#if defined(DEBUG_SUBPAGE)
2376 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2377 mmio, len, addr, idx);
2378#endif
blueswir13ee89922008-01-02 19:45:26 +00002379 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002380
2381 return ret;
2382}
2383
2384static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2385 uint32_t value, unsigned int len)
2386{
blueswir1db7b5422007-05-26 17:36:03 +00002387 unsigned int idx;
2388
2389 idx = SUBPAGE_IDX(addr - mmio->base);
2390#if defined(DEBUG_SUBPAGE)
2391 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2392 mmio, len, addr, idx, value);
2393#endif
blueswir13ee89922008-01-02 19:45:26 +00002394 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002395}
2396
2397static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2398{
2399#if defined(DEBUG_SUBPAGE)
2400 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2401#endif
2402
2403 return subpage_readlen(opaque, addr, 0);
2404}
2405
2406static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2407 uint32_t value)
2408{
2409#if defined(DEBUG_SUBPAGE)
2410 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2411#endif
2412 subpage_writelen(opaque, addr, value, 0);
2413}
2414
2415static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2416{
2417#if defined(DEBUG_SUBPAGE)
2418 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2419#endif
2420
2421 return subpage_readlen(opaque, addr, 1);
2422}
2423
2424static void subpage_writew (void *opaque, target_phys_addr_t addr,
2425 uint32_t value)
2426{
2427#if defined(DEBUG_SUBPAGE)
2428 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2429#endif
2430 subpage_writelen(opaque, addr, value, 1);
2431}
2432
2433static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2434{
2435#if defined(DEBUG_SUBPAGE)
2436 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2437#endif
2438
2439 return subpage_readlen(opaque, addr, 2);
2440}
2441
2442static void subpage_writel (void *opaque,
2443 target_phys_addr_t addr, uint32_t value)
2444{
2445#if defined(DEBUG_SUBPAGE)
2446 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2447#endif
2448 subpage_writelen(opaque, addr, value, 2);
2449}
2450
2451static CPUReadMemoryFunc *subpage_read[] = {
2452 &subpage_readb,
2453 &subpage_readw,
2454 &subpage_readl,
2455};
2456
2457static CPUWriteMemoryFunc *subpage_write[] = {
2458 &subpage_writeb,
2459 &subpage_writew,
2460 &subpage_writel,
2461};
2462
2463static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002464 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002465{
2466 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002467 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002468
2469 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2470 return -1;
2471 idx = SUBPAGE_IDX(start);
2472 eidx = SUBPAGE_IDX(end);
2473#if defined(DEBUG_SUBPAGE)
2474 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2475 mmio, start, end, idx, eidx, memory);
2476#endif
2477 memory >>= IO_MEM_SHIFT;
2478 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002479 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002480 if (io_mem_read[memory][i]) {
2481 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2482 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2483 }
2484 if (io_mem_write[memory][i]) {
2485 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2486 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2487 }
blueswir14254fab2008-01-01 16:57:19 +00002488 }
blueswir1db7b5422007-05-26 17:36:03 +00002489 }
2490
2491 return 0;
2492}
2493
aurel3200f82b82008-04-27 21:12:55 +00002494static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2495 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002496{
2497 subpage_t *mmio;
2498 int subpage_memory;
2499
2500 mmio = qemu_mallocz(sizeof(subpage_t));
2501 if (mmio != NULL) {
2502 mmio->base = base;
2503 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2504#if defined(DEBUG_SUBPAGE)
2505 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2506 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2507#endif
2508 *phys = subpage_memory | IO_MEM_SUBPAGE;
2509 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2510 }
2511
2512 return mmio;
2513}
2514
bellard33417e72003-08-10 21:47:01 +00002515static void io_mem_init(void)
2516{
bellard3a7d9292005-08-21 09:26:42 +00002517 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002518 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002519 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002520 io_mem_nb = 5;
2521
pbrook0f459d12008-06-09 00:20:13 +00002522 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002523 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002524 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002525 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002526 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002527}
2528
2529/* mem_read and mem_write are arrays of functions containing the
2530 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002531 2). Functions can be omitted with a NULL function pointer. The
2532 registered functions may be modified dynamically later.
2533 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002534 modified. If it is zero, a new io zone is allocated. The return
2535 value can be used with cpu_register_physical_memory(). (-1) is
2536 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002537int cpu_register_io_memory(int io_index,
2538 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002539 CPUWriteMemoryFunc **mem_write,
2540 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002541{
blueswir14254fab2008-01-01 16:57:19 +00002542 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002543
2544 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002545 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002546 return -1;
2547 io_index = io_mem_nb++;
2548 } else {
2549 if (io_index >= IO_MEM_NB_ENTRIES)
2550 return -1;
2551 }
bellardb5ff1b32005-11-26 10:38:39 +00002552
bellard33417e72003-08-10 21:47:01 +00002553 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002554 if (!mem_read[i] || !mem_write[i])
2555 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002556 io_mem_read[io_index][i] = mem_read[i];
2557 io_mem_write[io_index][i] = mem_write[i];
2558 }
bellarda4193c82004-06-03 14:01:43 +00002559 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002560 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002561}
bellard61382a52003-10-27 21:22:23 +00002562
bellard8926b512004-10-10 15:14:20 +00002563CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2564{
2565 return io_mem_write[io_index >> IO_MEM_SHIFT];
2566}
2567
2568CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2569{
2570 return io_mem_read[io_index >> IO_MEM_SHIFT];
2571}
2572
pbrooke2eef172008-06-08 01:09:01 +00002573#endif /* !defined(CONFIG_USER_ONLY) */
2574
bellard13eb76e2004-01-24 15:23:36 +00002575/* physical memory access (slow version, mainly for debug) */
2576#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002577void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002578 int len, int is_write)
2579{
2580 int l, flags;
2581 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002582 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002583
2584 while (len > 0) {
2585 page = addr & TARGET_PAGE_MASK;
2586 l = (page + TARGET_PAGE_SIZE) - addr;
2587 if (l > len)
2588 l = len;
2589 flags = page_get_flags(page);
2590 if (!(flags & PAGE_VALID))
2591 return;
2592 if (is_write) {
2593 if (!(flags & PAGE_WRITE))
2594 return;
bellard579a97f2007-11-11 14:26:47 +00002595 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002596 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002597 /* FIXME - should this return an error rather than just fail? */
2598 return;
aurel3272fb7da2008-04-27 23:53:45 +00002599 memcpy(p, buf, l);
2600 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002601 } else {
2602 if (!(flags & PAGE_READ))
2603 return;
bellard579a97f2007-11-11 14:26:47 +00002604 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002605 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002606 /* FIXME - should this return an error rather than just fail? */
2607 return;
aurel3272fb7da2008-04-27 23:53:45 +00002608 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002609 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002610 }
2611 len -= l;
2612 buf += l;
2613 addr += l;
2614 }
2615}
bellard8df1cd02005-01-28 22:37:22 +00002616
bellard13eb76e2004-01-24 15:23:36 +00002617#else
ths5fafdf22007-09-16 21:08:06 +00002618void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002619 int len, int is_write)
2620{
2621 int l, io_index;
2622 uint8_t *ptr;
2623 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002624 target_phys_addr_t page;
2625 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002626 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002627
bellard13eb76e2004-01-24 15:23:36 +00002628 while (len > 0) {
2629 page = addr & TARGET_PAGE_MASK;
2630 l = (page + TARGET_PAGE_SIZE) - addr;
2631 if (l > len)
2632 l = len;
bellard92e873b2004-05-21 14:52:29 +00002633 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002634 if (!p) {
2635 pd = IO_MEM_UNASSIGNED;
2636 } else {
2637 pd = p->phys_offset;
2638 }
ths3b46e622007-09-17 08:09:54 +00002639
bellard13eb76e2004-01-24 15:23:36 +00002640 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002641 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002642 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002643 /* XXX: could force cpu_single_env to NULL to avoid
2644 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002645 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002646 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002647 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002648 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002649 l = 4;
2650 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002651 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002652 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002653 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002654 l = 2;
2655 } else {
bellard1c213d12005-09-03 10:49:04 +00002656 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002657 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002658 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002659 l = 1;
2660 }
2661 } else {
bellardb448f2f2004-02-25 23:24:04 +00002662 unsigned long addr1;
2663 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002664 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002665 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002666 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002667 if (!cpu_physical_memory_is_dirty(addr1)) {
2668 /* invalidate code */
2669 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2670 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002671 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002672 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002673 }
bellard13eb76e2004-01-24 15:23:36 +00002674 }
2675 } else {
ths5fafdf22007-09-16 21:08:06 +00002676 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002677 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002678 /* I/O case */
2679 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2680 if (l >= 4 && ((addr & 3) == 0)) {
2681 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002682 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002683 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002684 l = 4;
2685 } else if (l >= 2 && ((addr & 1) == 0)) {
2686 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002687 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002688 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002689 l = 2;
2690 } else {
bellard1c213d12005-09-03 10:49:04 +00002691 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002692 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002693 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002694 l = 1;
2695 }
2696 } else {
2697 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002698 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002699 (addr & ~TARGET_PAGE_MASK);
2700 memcpy(buf, ptr, l);
2701 }
2702 }
2703 len -= l;
2704 buf += l;
2705 addr += l;
2706 }
2707}
bellard8df1cd02005-01-28 22:37:22 +00002708
bellardd0ecd2a2006-04-23 17:14:48 +00002709/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002710void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002711 const uint8_t *buf, int len)
2712{
2713 int l;
2714 uint8_t *ptr;
2715 target_phys_addr_t page;
2716 unsigned long pd;
2717 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002718
bellardd0ecd2a2006-04-23 17:14:48 +00002719 while (len > 0) {
2720 page = addr & TARGET_PAGE_MASK;
2721 l = (page + TARGET_PAGE_SIZE) - addr;
2722 if (l > len)
2723 l = len;
2724 p = phys_page_find(page >> TARGET_PAGE_BITS);
2725 if (!p) {
2726 pd = IO_MEM_UNASSIGNED;
2727 } else {
2728 pd = p->phys_offset;
2729 }
ths3b46e622007-09-17 08:09:54 +00002730
bellardd0ecd2a2006-04-23 17:14:48 +00002731 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002732 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2733 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002734 /* do nothing */
2735 } else {
2736 unsigned long addr1;
2737 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2738 /* ROM/RAM case */
2739 ptr = phys_ram_base + addr1;
2740 memcpy(ptr, buf, l);
2741 }
2742 len -= l;
2743 buf += l;
2744 addr += l;
2745 }
2746}
2747
2748
bellard8df1cd02005-01-28 22:37:22 +00002749/* warning: addr must be aligned */
2750uint32_t ldl_phys(target_phys_addr_t addr)
2751{
2752 int io_index;
2753 uint8_t *ptr;
2754 uint32_t val;
2755 unsigned long pd;
2756 PhysPageDesc *p;
2757
2758 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2759 if (!p) {
2760 pd = IO_MEM_UNASSIGNED;
2761 } else {
2762 pd = p->phys_offset;
2763 }
ths3b46e622007-09-17 08:09:54 +00002764
ths5fafdf22007-09-16 21:08:06 +00002765 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002766 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002767 /* I/O case */
2768 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2769 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2770 } else {
2771 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002772 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002773 (addr & ~TARGET_PAGE_MASK);
2774 val = ldl_p(ptr);
2775 }
2776 return val;
2777}
2778
bellard84b7b8e2005-11-28 21:19:04 +00002779/* warning: addr must be aligned */
2780uint64_t ldq_phys(target_phys_addr_t addr)
2781{
2782 int io_index;
2783 uint8_t *ptr;
2784 uint64_t val;
2785 unsigned long pd;
2786 PhysPageDesc *p;
2787
2788 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2789 if (!p) {
2790 pd = IO_MEM_UNASSIGNED;
2791 } else {
2792 pd = p->phys_offset;
2793 }
ths3b46e622007-09-17 08:09:54 +00002794
bellard2a4188a2006-06-25 21:54:59 +00002795 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2796 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002797 /* I/O case */
2798 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2799#ifdef TARGET_WORDS_BIGENDIAN
2800 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2801 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2802#else
2803 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2804 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2805#endif
2806 } else {
2807 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002808 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002809 (addr & ~TARGET_PAGE_MASK);
2810 val = ldq_p(ptr);
2811 }
2812 return val;
2813}
2814
bellardaab33092005-10-30 20:48:42 +00002815/* XXX: optimize */
2816uint32_t ldub_phys(target_phys_addr_t addr)
2817{
2818 uint8_t val;
2819 cpu_physical_memory_read(addr, &val, 1);
2820 return val;
2821}
2822
2823/* XXX: optimize */
2824uint32_t lduw_phys(target_phys_addr_t addr)
2825{
2826 uint16_t val;
2827 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2828 return tswap16(val);
2829}
2830
bellard8df1cd02005-01-28 22:37:22 +00002831/* warning: addr must be aligned. The ram page is not masked as dirty
2832 and the code inside is not invalidated. It is useful if the dirty
2833 bits are used to track modified PTEs */
2834void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2835{
2836 int io_index;
2837 uint8_t *ptr;
2838 unsigned long pd;
2839 PhysPageDesc *p;
2840
2841 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2842 if (!p) {
2843 pd = IO_MEM_UNASSIGNED;
2844 } else {
2845 pd = p->phys_offset;
2846 }
ths3b46e622007-09-17 08:09:54 +00002847
bellard3a7d9292005-08-21 09:26:42 +00002848 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002849 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2850 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2851 } else {
ths5fafdf22007-09-16 21:08:06 +00002852 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002853 (addr & ~TARGET_PAGE_MASK);
2854 stl_p(ptr, val);
2855 }
2856}
2857
j_mayerbc98a7e2007-04-04 07:55:12 +00002858void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2859{
2860 int io_index;
2861 uint8_t *ptr;
2862 unsigned long pd;
2863 PhysPageDesc *p;
2864
2865 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2866 if (!p) {
2867 pd = IO_MEM_UNASSIGNED;
2868 } else {
2869 pd = p->phys_offset;
2870 }
ths3b46e622007-09-17 08:09:54 +00002871
j_mayerbc98a7e2007-04-04 07:55:12 +00002872 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2873 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2874#ifdef TARGET_WORDS_BIGENDIAN
2875 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2876 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2877#else
2878 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2879 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2880#endif
2881 } else {
ths5fafdf22007-09-16 21:08:06 +00002882 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002883 (addr & ~TARGET_PAGE_MASK);
2884 stq_p(ptr, val);
2885 }
2886}
2887
bellard8df1cd02005-01-28 22:37:22 +00002888/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002889void stl_phys(target_phys_addr_t addr, uint32_t val)
2890{
2891 int io_index;
2892 uint8_t *ptr;
2893 unsigned long pd;
2894 PhysPageDesc *p;
2895
2896 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2897 if (!p) {
2898 pd = IO_MEM_UNASSIGNED;
2899 } else {
2900 pd = p->phys_offset;
2901 }
ths3b46e622007-09-17 08:09:54 +00002902
bellard3a7d9292005-08-21 09:26:42 +00002903 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002904 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2905 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2906 } else {
2907 unsigned long addr1;
2908 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2909 /* RAM case */
2910 ptr = phys_ram_base + addr1;
2911 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002912 if (!cpu_physical_memory_is_dirty(addr1)) {
2913 /* invalidate code */
2914 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2915 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002916 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2917 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002918 }
bellard8df1cd02005-01-28 22:37:22 +00002919 }
2920}
2921
bellardaab33092005-10-30 20:48:42 +00002922/* XXX: optimize */
2923void stb_phys(target_phys_addr_t addr, uint32_t val)
2924{
2925 uint8_t v = val;
2926 cpu_physical_memory_write(addr, &v, 1);
2927}
2928
2929/* XXX: optimize */
2930void stw_phys(target_phys_addr_t addr, uint32_t val)
2931{
2932 uint16_t v = tswap16(val);
2933 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2934}
2935
2936/* XXX: optimize */
2937void stq_phys(target_phys_addr_t addr, uint64_t val)
2938{
2939 val = tswap64(val);
2940 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2941}
2942
bellard13eb76e2004-01-24 15:23:36 +00002943#endif
2944
2945/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002946int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002947 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002948{
2949 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002950 target_phys_addr_t phys_addr;
2951 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002952
2953 while (len > 0) {
2954 page = addr & TARGET_PAGE_MASK;
2955 phys_addr = cpu_get_phys_page_debug(env, page);
2956 /* if no physical page mapped, return an error */
2957 if (phys_addr == -1)
2958 return -1;
2959 l = (page + TARGET_PAGE_SIZE) - addr;
2960 if (l > len)
2961 l = len;
ths5fafdf22007-09-16 21:08:06 +00002962 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002963 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002964 len -= l;
2965 buf += l;
2966 addr += l;
2967 }
2968 return 0;
2969}
2970
bellarde3db7222005-01-26 22:00:47 +00002971void dump_exec_info(FILE *f,
2972 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2973{
2974 int i, target_code_size, max_target_code_size;
2975 int direct_jmp_count, direct_jmp2_count, cross_page;
2976 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002977
bellarde3db7222005-01-26 22:00:47 +00002978 target_code_size = 0;
2979 max_target_code_size = 0;
2980 cross_page = 0;
2981 direct_jmp_count = 0;
2982 direct_jmp2_count = 0;
2983 for(i = 0; i < nb_tbs; i++) {
2984 tb = &tbs[i];
2985 target_code_size += tb->size;
2986 if (tb->size > max_target_code_size)
2987 max_target_code_size = tb->size;
2988 if (tb->page_addr[1] != -1)
2989 cross_page++;
2990 if (tb->tb_next_offset[0] != 0xffff) {
2991 direct_jmp_count++;
2992 if (tb->tb_next_offset[1] != 0xffff) {
2993 direct_jmp2_count++;
2994 }
2995 }
2996 }
2997 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002998 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00002999 cpu_fprintf(f, "gen code size %ld/%ld\n",
3000 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3001 cpu_fprintf(f, "TB count %d/%d\n",
3002 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003003 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003004 nb_tbs ? target_code_size / nb_tbs : 0,
3005 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003006 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003007 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3008 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003009 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3010 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003011 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3012 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003013 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003014 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3015 direct_jmp2_count,
3016 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003017 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003018 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3019 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3020 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003021 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003022}
3023
ths5fafdf22007-09-16 21:08:06 +00003024#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003025
3026#define MMUSUFFIX _cmmu
3027#define GETPC() NULL
3028#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003029#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003030
3031#define SHIFT 0
3032#include "softmmu_template.h"
3033
3034#define SHIFT 1
3035#include "softmmu_template.h"
3036
3037#define SHIFT 2
3038#include "softmmu_template.h"
3039
3040#define SHIFT 3
3041#include "softmmu_template.h"
3042
3043#undef env
3044
3045#endif