blob: 48600e49a978556d2bdd1e57cef0faa3d542f6e6 [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
pbrookb2a70812008-06-09 13:57:23 +0000724 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000725 if (!p->code_bitmap)
726 return;
bellard9fa3e852004-01-04 18:06:42 +0000727
728 tb = p->first_tb;
729 while (tb != NULL) {
730 n = (long)tb & 3;
731 tb = (TranslationBlock *)((long)tb & ~3);
732 /* NOTE: this is subtle as a TB may span two physical pages */
733 if (n == 0) {
734 /* NOTE: tb_end may be after the end of the page, but
735 it is not a problem */
736 tb_start = tb->pc & ~TARGET_PAGE_MASK;
737 tb_end = tb_start + tb->size;
738 if (tb_end > TARGET_PAGE_SIZE)
739 tb_end = TARGET_PAGE_SIZE;
740 } else {
741 tb_start = 0;
742 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
743 }
744 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
745 tb = tb->page_next[n];
746 }
747}
748
bellardd720b932004-04-25 17:57:43 +0000749#ifdef TARGET_HAS_PRECISE_SMC
750
ths5fafdf22007-09-16 21:08:06 +0000751static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000752 target_ulong pc, target_ulong cs_base, int flags,
753 int cflags)
754{
755 TranslationBlock *tb;
756 uint8_t *tc_ptr;
757 target_ulong phys_pc, phys_page2, virt_page2;
758 int code_gen_size;
759
bellardc27004e2005-01-03 23:35:10 +0000760 phys_pc = get_phys_addr_code(env, pc);
761 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000762 if (!tb) {
763 /* flush must be done */
764 tb_flush(env);
765 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000766 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000767 }
768 tc_ptr = code_gen_ptr;
769 tb->tc_ptr = tc_ptr;
770 tb->cs_base = cs_base;
771 tb->flags = flags;
772 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000773 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000774 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 +0000775
bellardd720b932004-04-25 17:57:43 +0000776 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000777 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000778 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000779 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000780 phys_page2 = get_phys_addr_code(env, virt_page2);
781 }
782 tb_link_phys(tb, phys_pc, phys_page2);
783}
784#endif
ths3b46e622007-09-17 08:09:54 +0000785
bellard9fa3e852004-01-04 18:06:42 +0000786/* invalidate all TBs which intersect with the target physical page
787 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000788 the same physical page. 'is_cpu_write_access' should be true if called
789 from a real cpu write access: the virtual CPU will exit the current
790 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000791void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000792 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000793{
bellardd720b932004-04-25 17:57:43 +0000794 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000795 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000796 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000797 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000798 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000799 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000800
801 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000802 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000803 return;
ths5fafdf22007-09-16 21:08:06 +0000804 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000805 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
806 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000807 /* build code bitmap */
808 build_page_bitmap(p);
809 }
810
811 /* we remove all the TBs in the range [start, end[ */
812 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000813 current_tb_not_found = is_cpu_write_access;
814 current_tb_modified = 0;
815 current_tb = NULL; /* avoid warning */
816 current_pc = 0; /* avoid warning */
817 current_cs_base = 0; /* avoid warning */
818 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000819 tb = p->first_tb;
820 while (tb != NULL) {
821 n = (long)tb & 3;
822 tb = (TranslationBlock *)((long)tb & ~3);
823 tb_next = tb->page_next[n];
824 /* NOTE: this is subtle as a TB may span two physical pages */
825 if (n == 0) {
826 /* NOTE: tb_end may be after the end of the page, but
827 it is not a problem */
828 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
829 tb_end = tb_start + tb->size;
830 } else {
831 tb_start = tb->page_addr[1];
832 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
833 }
834 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000835#ifdef TARGET_HAS_PRECISE_SMC
836 if (current_tb_not_found) {
837 current_tb_not_found = 0;
838 current_tb = NULL;
839 if (env->mem_write_pc) {
840 /* now we have a real cpu fault */
841 current_tb = tb_find_pc(env->mem_write_pc);
842 }
843 }
844 if (current_tb == tb &&
845 !(current_tb->cflags & CF_SINGLE_INSN)) {
846 /* If we are modifying the current TB, we must stop
847 its execution. We could be more precise by checking
848 that the modification is after the current PC, but it
849 would require a specialized function to partially
850 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000851
bellardd720b932004-04-25 17:57:43 +0000852 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000853 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000854 env->mem_write_pc, NULL);
855#if defined(TARGET_I386)
856 current_flags = env->hflags;
857 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
858 current_cs_base = (target_ulong)env->segs[R_CS].base;
859 current_pc = current_cs_base + env->eip;
860#else
861#error unsupported CPU
862#endif
863 }
864#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000865 /* we need to do that to handle the case where a signal
866 occurs while doing tb_phys_invalidate() */
867 saved_tb = NULL;
868 if (env) {
869 saved_tb = env->current_tb;
870 env->current_tb = NULL;
871 }
bellard9fa3e852004-01-04 18:06:42 +0000872 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000873 if (env) {
874 env->current_tb = saved_tb;
875 if (env->interrupt_request && env->current_tb)
876 cpu_interrupt(env, env->interrupt_request);
877 }
bellard9fa3e852004-01-04 18:06:42 +0000878 }
879 tb = tb_next;
880 }
881#if !defined(CONFIG_USER_ONLY)
882 /* if no code remaining, no need to continue to use slow writes */
883 if (!p->first_tb) {
884 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000885 if (is_cpu_write_access) {
886 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
887 }
888 }
889#endif
890#ifdef TARGET_HAS_PRECISE_SMC
891 if (current_tb_modified) {
892 /* we generate a block containing just the instruction
893 modifying the memory. It will ensure that it cannot modify
894 itself */
bellardea1c1802004-06-14 18:56:36 +0000895 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000896 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000897 CF_SINGLE_INSN);
898 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000899 }
900#endif
901}
902
903/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000904static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000905{
906 PageDesc *p;
907 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000908#if 0
bellarda4193c82004-06-03 14:01:43 +0000909 if (1) {
910 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000911 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
912 cpu_single_env->mem_write_vaddr, len,
913 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000914 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
915 }
bellard59817cc2004-02-16 22:01:13 +0000916 }
917#endif
bellard9fa3e852004-01-04 18:06:42 +0000918 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000919 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000920 return;
921 if (p->code_bitmap) {
922 offset = start & ~TARGET_PAGE_MASK;
923 b = p->code_bitmap[offset >> 3] >> (offset & 7);
924 if (b & ((1 << len) - 1))
925 goto do_invalidate;
926 } else {
927 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000928 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000929 }
930}
931
bellard9fa3e852004-01-04 18:06:42 +0000932#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000933static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000934 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000935{
bellardd720b932004-04-25 17:57:43 +0000936 int n, current_flags, current_tb_modified;
937 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000938 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000939 TranslationBlock *tb, *current_tb;
940#ifdef TARGET_HAS_PRECISE_SMC
941 CPUState *env = cpu_single_env;
942#endif
bellard9fa3e852004-01-04 18:06:42 +0000943
944 addr &= TARGET_PAGE_MASK;
945 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000946 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000947 return;
948 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000949 current_tb_modified = 0;
950 current_tb = NULL;
951 current_pc = 0; /* avoid warning */
952 current_cs_base = 0; /* avoid warning */
953 current_flags = 0; /* avoid warning */
954#ifdef TARGET_HAS_PRECISE_SMC
955 if (tb && pc != 0) {
956 current_tb = tb_find_pc(pc);
957 }
958#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000959 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000960 n = (long)tb & 3;
961 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000962#ifdef TARGET_HAS_PRECISE_SMC
963 if (current_tb == tb &&
964 !(current_tb->cflags & CF_SINGLE_INSN)) {
965 /* If we are modifying the current TB, we must stop
966 its execution. We could be more precise by checking
967 that the modification is after the current PC, but it
968 would require a specialized function to partially
969 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000970
bellardd720b932004-04-25 17:57:43 +0000971 current_tb_modified = 1;
972 cpu_restore_state(current_tb, env, pc, puc);
973#if defined(TARGET_I386)
974 current_flags = env->hflags;
975 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
976 current_cs_base = (target_ulong)env->segs[R_CS].base;
977 current_pc = current_cs_base + env->eip;
978#else
979#error unsupported CPU
980#endif
981 }
982#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000983 tb_phys_invalidate(tb, addr);
984 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000985 }
986 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000987#ifdef TARGET_HAS_PRECISE_SMC
988 if (current_tb_modified) {
989 /* we generate a block containing just the instruction
990 modifying the memory. It will ensure that it cannot modify
991 itself */
bellardea1c1802004-06-14 18:56:36 +0000992 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000993 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000994 CF_SINGLE_INSN);
995 cpu_resume_from_signal(env, puc);
996 }
997#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000998}
bellard9fa3e852004-01-04 18:06:42 +0000999#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001000
1001/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001002static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001003 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001004{
1005 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001006 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001007
bellard9fa3e852004-01-04 18:06:42 +00001008 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001009 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001010 tb->page_next[n] = p->first_tb;
1011 last_first_tb = p->first_tb;
1012 p->first_tb = (TranslationBlock *)((long)tb | n);
1013 invalidate_page_bitmap(p);
1014
bellard107db442004-06-22 18:48:46 +00001015#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001016
bellard9fa3e852004-01-04 18:06:42 +00001017#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001018 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001019 target_ulong addr;
1020 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001021 int prot;
1022
bellardfd6ce8f2003-05-14 19:00:11 +00001023 /* force the host page as non writable (writes will have a
1024 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001025 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001026 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001027 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1028 addr += TARGET_PAGE_SIZE) {
1029
1030 p2 = page_find (addr >> TARGET_PAGE_BITS);
1031 if (!p2)
1032 continue;
1033 prot |= p2->flags;
1034 p2->flags &= ~PAGE_WRITE;
1035 page_get_flags(addr);
1036 }
ths5fafdf22007-09-16 21:08:06 +00001037 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001038 (prot & PAGE_BITS) & ~PAGE_WRITE);
1039#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001040 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001041 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001042#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001043 }
bellard9fa3e852004-01-04 18:06:42 +00001044#else
1045 /* if some code is already present, then the pages are already
1046 protected. So we handle the case where only the first TB is
1047 allocated in a physical page */
1048 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001049 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001050 }
1051#endif
bellardd720b932004-04-25 17:57:43 +00001052
1053#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001054}
1055
1056/* Allocate a new translation block. Flush the translation buffer if
1057 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001058TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001059{
1060 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001061
bellard26a5f132008-05-28 12:30:31 +00001062 if (nb_tbs >= code_gen_max_blocks ||
1063 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001064 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001065 tb = &tbs[nb_tbs++];
1066 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001067 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001068 return tb;
1069}
1070
bellard9fa3e852004-01-04 18:06:42 +00001071/* add a new TB and link it to the physical page tables. phys_page2 is
1072 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001073void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001074 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001075{
bellard9fa3e852004-01-04 18:06:42 +00001076 unsigned int h;
1077 TranslationBlock **ptb;
1078
pbrookc8a706f2008-06-02 16:16:42 +00001079 /* Grab the mmap lock to stop another thread invalidating this TB
1080 before we are done. */
1081 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001082 /* add in the physical hash table */
1083 h = tb_phys_hash_func(phys_pc);
1084 ptb = &tb_phys_hash[h];
1085 tb->phys_hash_next = *ptb;
1086 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001087
1088 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001089 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1090 if (phys_page2 != -1)
1091 tb_alloc_page(tb, 1, phys_page2);
1092 else
1093 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001094
bellardd4e81642003-05-25 16:46:15 +00001095 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1096 tb->jmp_next[0] = NULL;
1097 tb->jmp_next[1] = NULL;
1098
1099 /* init original jump addresses */
1100 if (tb->tb_next_offset[0] != 0xffff)
1101 tb_reset_jump(tb, 0);
1102 if (tb->tb_next_offset[1] != 0xffff)
1103 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001104
1105#ifdef DEBUG_TB_CHECK
1106 tb_page_check();
1107#endif
pbrookc8a706f2008-06-02 16:16:42 +00001108 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001109}
1110
bellarda513fe12003-05-27 23:29:48 +00001111/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1112 tb[1].tc_ptr. Return NULL if not found */
1113TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1114{
1115 int m_min, m_max, m;
1116 unsigned long v;
1117 TranslationBlock *tb;
1118
1119 if (nb_tbs <= 0)
1120 return NULL;
1121 if (tc_ptr < (unsigned long)code_gen_buffer ||
1122 tc_ptr >= (unsigned long)code_gen_ptr)
1123 return NULL;
1124 /* binary search (cf Knuth) */
1125 m_min = 0;
1126 m_max = nb_tbs - 1;
1127 while (m_min <= m_max) {
1128 m = (m_min + m_max) >> 1;
1129 tb = &tbs[m];
1130 v = (unsigned long)tb->tc_ptr;
1131 if (v == tc_ptr)
1132 return tb;
1133 else if (tc_ptr < v) {
1134 m_max = m - 1;
1135 } else {
1136 m_min = m + 1;
1137 }
ths5fafdf22007-09-16 21:08:06 +00001138 }
bellarda513fe12003-05-27 23:29:48 +00001139 return &tbs[m_max];
1140}
bellard75012672003-06-21 13:11:07 +00001141
bellardea041c02003-06-25 16:16:50 +00001142static void tb_reset_jump_recursive(TranslationBlock *tb);
1143
1144static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1145{
1146 TranslationBlock *tb1, *tb_next, **ptb;
1147 unsigned int n1;
1148
1149 tb1 = tb->jmp_next[n];
1150 if (tb1 != NULL) {
1151 /* find head of list */
1152 for(;;) {
1153 n1 = (long)tb1 & 3;
1154 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1155 if (n1 == 2)
1156 break;
1157 tb1 = tb1->jmp_next[n1];
1158 }
1159 /* we are now sure now that tb jumps to tb1 */
1160 tb_next = tb1;
1161
1162 /* remove tb from the jmp_first list */
1163 ptb = &tb_next->jmp_first;
1164 for(;;) {
1165 tb1 = *ptb;
1166 n1 = (long)tb1 & 3;
1167 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1168 if (n1 == n && tb1 == tb)
1169 break;
1170 ptb = &tb1->jmp_next[n1];
1171 }
1172 *ptb = tb->jmp_next[n];
1173 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001174
bellardea041c02003-06-25 16:16:50 +00001175 /* suppress the jump to next tb in generated code */
1176 tb_reset_jump(tb, n);
1177
bellard01243112004-01-04 15:48:17 +00001178 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001179 tb_reset_jump_recursive(tb_next);
1180 }
1181}
1182
1183static void tb_reset_jump_recursive(TranslationBlock *tb)
1184{
1185 tb_reset_jump_recursive2(tb, 0);
1186 tb_reset_jump_recursive2(tb, 1);
1187}
1188
bellard1fddef42005-04-17 19:16:13 +00001189#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001190static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1191{
j_mayer9b3c35e2007-04-07 11:21:28 +00001192 target_phys_addr_t addr;
1193 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001194 ram_addr_t ram_addr;
1195 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001196
pbrookc2f07f82006-04-08 17:14:56 +00001197 addr = cpu_get_phys_page_debug(env, pc);
1198 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1199 if (!p) {
1200 pd = IO_MEM_UNASSIGNED;
1201 } else {
1202 pd = p->phys_offset;
1203 }
1204 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001205 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001206}
bellardc27004e2005-01-03 23:35:10 +00001207#endif
bellardd720b932004-04-25 17:57:43 +00001208
pbrook6658ffb2007-03-16 23:58:11 +00001209/* Add a watchpoint. */
pbrook0f459d12008-06-09 00:20:13 +00001210int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
pbrook6658ffb2007-03-16 23:58:11 +00001211{
1212 int i;
1213
1214 for (i = 0; i < env->nb_watchpoints; i++) {
1215 if (addr == env->watchpoint[i].vaddr)
1216 return 0;
1217 }
1218 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1219 return -1;
1220
1221 i = env->nb_watchpoints++;
1222 env->watchpoint[i].vaddr = addr;
pbrook0f459d12008-06-09 00:20:13 +00001223 env->watchpoint[i].type = type;
pbrook6658ffb2007-03-16 23:58:11 +00001224 tlb_flush_page(env, addr);
1225 /* FIXME: This flush is needed because of the hack to make memory ops
1226 terminate the TB. It can be removed once the proper IO trap and
1227 re-execute bits are in. */
1228 tb_flush(env);
1229 return i;
1230}
1231
1232/* Remove a watchpoint. */
1233int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1234{
1235 int i;
1236
1237 for (i = 0; i < env->nb_watchpoints; i++) {
1238 if (addr == env->watchpoint[i].vaddr) {
1239 env->nb_watchpoints--;
1240 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1241 tlb_flush_page(env, addr);
1242 return 0;
1243 }
1244 }
1245 return -1;
1246}
1247
edgar_igl7d03f822008-05-17 18:58:29 +00001248/* Remove all watchpoints. */
1249void cpu_watchpoint_remove_all(CPUState *env) {
1250 int i;
1251
1252 for (i = 0; i < env->nb_watchpoints; i++) {
1253 tlb_flush_page(env, env->watchpoint[i].vaddr);
1254 }
1255 env->nb_watchpoints = 0;
1256}
1257
bellardc33a3462003-07-29 20:50:33 +00001258/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1259 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001260int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001261{
bellard1fddef42005-04-17 19:16:13 +00001262#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001263 int i;
ths3b46e622007-09-17 08:09:54 +00001264
bellard4c3a88a2003-07-26 12:06:08 +00001265 for(i = 0; i < env->nb_breakpoints; i++) {
1266 if (env->breakpoints[i] == pc)
1267 return 0;
1268 }
1269
1270 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1271 return -1;
1272 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001273
bellardd720b932004-04-25 17:57:43 +00001274 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001275 return 0;
1276#else
1277 return -1;
1278#endif
1279}
1280
edgar_igl7d03f822008-05-17 18:58:29 +00001281/* remove all breakpoints */
1282void cpu_breakpoint_remove_all(CPUState *env) {
1283#if defined(TARGET_HAS_ICE)
1284 int i;
1285 for(i = 0; i < env->nb_breakpoints; i++) {
1286 breakpoint_invalidate(env, env->breakpoints[i]);
1287 }
1288 env->nb_breakpoints = 0;
1289#endif
1290}
1291
bellard4c3a88a2003-07-26 12:06:08 +00001292/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001293int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001294{
bellard1fddef42005-04-17 19:16:13 +00001295#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001296 int i;
1297 for(i = 0; i < env->nb_breakpoints; i++) {
1298 if (env->breakpoints[i] == pc)
1299 goto found;
1300 }
1301 return -1;
1302 found:
bellard4c3a88a2003-07-26 12:06:08 +00001303 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001304 if (i < env->nb_breakpoints)
1305 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001306
1307 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001308 return 0;
1309#else
1310 return -1;
1311#endif
1312}
1313
bellardc33a3462003-07-29 20:50:33 +00001314/* enable or disable single step mode. EXCP_DEBUG is returned by the
1315 CPU loop after each instruction */
1316void cpu_single_step(CPUState *env, int enabled)
1317{
bellard1fddef42005-04-17 19:16:13 +00001318#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001319 if (env->singlestep_enabled != enabled) {
1320 env->singlestep_enabled = enabled;
1321 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001322 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001323 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001324 }
1325#endif
1326}
1327
bellard34865132003-10-05 14:28:56 +00001328/* enable or disable low levels log */
1329void cpu_set_log(int log_flags)
1330{
1331 loglevel = log_flags;
1332 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001333 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001334 if (!logfile) {
1335 perror(logfilename);
1336 _exit(1);
1337 }
bellard9fa3e852004-01-04 18:06:42 +00001338#if !defined(CONFIG_SOFTMMU)
1339 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1340 {
1341 static uint8_t logfile_buf[4096];
1342 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1343 }
1344#else
bellard34865132003-10-05 14:28:56 +00001345 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001346#endif
pbrooke735b912007-06-30 13:53:24 +00001347 log_append = 1;
1348 }
1349 if (!loglevel && logfile) {
1350 fclose(logfile);
1351 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001352 }
1353}
1354
1355void cpu_set_log_filename(const char *filename)
1356{
1357 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001358 if (logfile) {
1359 fclose(logfile);
1360 logfile = NULL;
1361 }
1362 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001363}
bellardc33a3462003-07-29 20:50:33 +00001364
bellard01243112004-01-04 15:48:17 +00001365/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001366void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001367{
pbrookd5975362008-06-07 20:50:51 +00001368#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001369 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001370 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001371#endif
bellard59817cc2004-02-16 22:01:13 +00001372
pbrookd5975362008-06-07 20:50:51 +00001373 /* FIXME: This is probably not threadsafe. A different thread could
1374 be in the mittle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001375 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001376#if defined(USE_NPTL)
1377 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1378 problem and hope the cpu will stop of its own accord. For userspace
1379 emulation this often isn't actually as bad as it sounds. Often
1380 signals are used primarily to interrupt blocking syscalls. */
1381#else
bellardea041c02003-06-25 16:16:50 +00001382 /* if the cpu is currently executing code, we must unlink it and
1383 all the potentially executing TB */
1384 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001385 if (tb && !testandset(&interrupt_lock)) {
1386 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001387 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001388 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001389 }
pbrookd5975362008-06-07 20:50:51 +00001390#endif
bellardea041c02003-06-25 16:16:50 +00001391}
1392
bellardb54ad042004-05-20 13:42:52 +00001393void cpu_reset_interrupt(CPUState *env, int mask)
1394{
1395 env->interrupt_request &= ~mask;
1396}
1397
bellardf193c792004-03-21 17:06:25 +00001398CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001399 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001400 "show generated host assembly code for each compiled TB" },
1401 { CPU_LOG_TB_IN_ASM, "in_asm",
1402 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001403 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001404 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001405 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001406 "show micro ops "
1407#ifdef TARGET_I386
1408 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001409#endif
blueswir1e01a1152008-03-14 17:37:11 +00001410 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001411 { CPU_LOG_INT, "int",
1412 "show interrupts/exceptions in short format" },
1413 { CPU_LOG_EXEC, "exec",
1414 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001415 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001416 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001417#ifdef TARGET_I386
1418 { CPU_LOG_PCALL, "pcall",
1419 "show protected mode far calls/returns/exceptions" },
1420#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001421#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001422 { CPU_LOG_IOPORT, "ioport",
1423 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001424#endif
bellardf193c792004-03-21 17:06:25 +00001425 { 0, NULL, NULL },
1426};
1427
1428static int cmp1(const char *s1, int n, const char *s2)
1429{
1430 if (strlen(s2) != n)
1431 return 0;
1432 return memcmp(s1, s2, n) == 0;
1433}
ths3b46e622007-09-17 08:09:54 +00001434
bellardf193c792004-03-21 17:06:25 +00001435/* takes a comma separated list of log masks. Return 0 if error. */
1436int cpu_str_to_log_mask(const char *str)
1437{
1438 CPULogItem *item;
1439 int mask;
1440 const char *p, *p1;
1441
1442 p = str;
1443 mask = 0;
1444 for(;;) {
1445 p1 = strchr(p, ',');
1446 if (!p1)
1447 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001448 if(cmp1(p,p1-p,"all")) {
1449 for(item = cpu_log_items; item->mask != 0; item++) {
1450 mask |= item->mask;
1451 }
1452 } else {
bellardf193c792004-03-21 17:06:25 +00001453 for(item = cpu_log_items; item->mask != 0; item++) {
1454 if (cmp1(p, p1 - p, item->name))
1455 goto found;
1456 }
1457 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001458 }
bellardf193c792004-03-21 17:06:25 +00001459 found:
1460 mask |= item->mask;
1461 if (*p1 != ',')
1462 break;
1463 p = p1 + 1;
1464 }
1465 return mask;
1466}
bellardea041c02003-06-25 16:16:50 +00001467
bellard75012672003-06-21 13:11:07 +00001468void cpu_abort(CPUState *env, const char *fmt, ...)
1469{
1470 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001471 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001472
1473 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001474 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001475 fprintf(stderr, "qemu: fatal: ");
1476 vfprintf(stderr, fmt, ap);
1477 fprintf(stderr, "\n");
1478#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001479 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1480#else
1481 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001482#endif
balrog924edca2007-06-10 14:07:13 +00001483 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001484 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001485 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001486 fprintf(logfile, "\n");
1487#ifdef TARGET_I386
1488 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1489#else
1490 cpu_dump_state(env, logfile, fprintf, 0);
1491#endif
balrog924edca2007-06-10 14:07:13 +00001492 fflush(logfile);
1493 fclose(logfile);
1494 }
pbrook493ae1f2007-11-23 16:53:59 +00001495 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001496 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001497 abort();
1498}
1499
thsc5be9f02007-02-28 20:20:53 +00001500CPUState *cpu_copy(CPUState *env)
1501{
ths01ba9812007-12-09 02:22:57 +00001502 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001503 /* preserve chaining and index */
1504 CPUState *next_cpu = new_env->next_cpu;
1505 int cpu_index = new_env->cpu_index;
1506 memcpy(new_env, env, sizeof(CPUState));
1507 new_env->next_cpu = next_cpu;
1508 new_env->cpu_index = cpu_index;
1509 return new_env;
1510}
1511
bellard01243112004-01-04 15:48:17 +00001512#if !defined(CONFIG_USER_ONLY)
1513
edgar_igl5c751e92008-05-06 08:44:21 +00001514static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1515{
1516 unsigned int i;
1517
1518 /* Discard jump cache entries for any tb which might potentially
1519 overlap the flushed page. */
1520 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1521 memset (&env->tb_jmp_cache[i], 0,
1522 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1523
1524 i = tb_jmp_cache_hash_page(addr);
1525 memset (&env->tb_jmp_cache[i], 0,
1526 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1527}
1528
bellardee8b7022004-02-03 23:35:10 +00001529/* NOTE: if flush_global is true, also flush global entries (not
1530 implemented yet) */
1531void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001532{
bellard33417e72003-08-10 21:47:01 +00001533 int i;
bellard01243112004-01-04 15:48:17 +00001534
bellard9fa3e852004-01-04 18:06:42 +00001535#if defined(DEBUG_TLB)
1536 printf("tlb_flush:\n");
1537#endif
bellard01243112004-01-04 15:48:17 +00001538 /* must reset current TB so that interrupts cannot modify the
1539 links while we are modifying them */
1540 env->current_tb = NULL;
1541
bellard33417e72003-08-10 21:47:01 +00001542 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001543 env->tlb_table[0][i].addr_read = -1;
1544 env->tlb_table[0][i].addr_write = -1;
1545 env->tlb_table[0][i].addr_code = -1;
1546 env->tlb_table[1][i].addr_read = -1;
1547 env->tlb_table[1][i].addr_write = -1;
1548 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001549#if (NB_MMU_MODES >= 3)
1550 env->tlb_table[2][i].addr_read = -1;
1551 env->tlb_table[2][i].addr_write = -1;
1552 env->tlb_table[2][i].addr_code = -1;
1553#if (NB_MMU_MODES == 4)
1554 env->tlb_table[3][i].addr_read = -1;
1555 env->tlb_table[3][i].addr_write = -1;
1556 env->tlb_table[3][i].addr_code = -1;
1557#endif
1558#endif
bellard33417e72003-08-10 21:47:01 +00001559 }
bellard9fa3e852004-01-04 18:06:42 +00001560
bellard8a40a182005-11-20 10:35:40 +00001561 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001562
bellard0a962c02005-02-10 22:00:27 +00001563#ifdef USE_KQEMU
1564 if (env->kqemu_enabled) {
1565 kqemu_flush(env, flush_global);
1566 }
1567#endif
bellarde3db7222005-01-26 22:00:47 +00001568 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001569}
1570
bellard274da6b2004-05-20 21:56:27 +00001571static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001572{
ths5fafdf22007-09-16 21:08:06 +00001573 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001574 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001575 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001576 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001577 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001578 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1579 tlb_entry->addr_read = -1;
1580 tlb_entry->addr_write = -1;
1581 tlb_entry->addr_code = -1;
1582 }
bellard61382a52003-10-27 21:22:23 +00001583}
1584
bellard2e126692004-04-25 21:28:44 +00001585void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001586{
bellard8a40a182005-11-20 10:35:40 +00001587 int i;
bellard01243112004-01-04 15:48:17 +00001588
bellard9fa3e852004-01-04 18:06:42 +00001589#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001590 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001591#endif
bellard01243112004-01-04 15:48:17 +00001592 /* must reset current TB so that interrupts cannot modify the
1593 links while we are modifying them */
1594 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001595
bellard61382a52003-10-27 21:22:23 +00001596 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001597 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001598 tlb_flush_entry(&env->tlb_table[0][i], addr);
1599 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001600#if (NB_MMU_MODES >= 3)
1601 tlb_flush_entry(&env->tlb_table[2][i], addr);
1602#if (NB_MMU_MODES == 4)
1603 tlb_flush_entry(&env->tlb_table[3][i], addr);
1604#endif
1605#endif
bellard01243112004-01-04 15:48:17 +00001606
edgar_igl5c751e92008-05-06 08:44:21 +00001607 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001608
bellard0a962c02005-02-10 22:00:27 +00001609#ifdef USE_KQEMU
1610 if (env->kqemu_enabled) {
1611 kqemu_flush_page(env, addr);
1612 }
1613#endif
bellard9fa3e852004-01-04 18:06:42 +00001614}
1615
bellard9fa3e852004-01-04 18:06:42 +00001616/* update the TLBs so that writes to code in the virtual page 'addr'
1617 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001618static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001619{
ths5fafdf22007-09-16 21:08:06 +00001620 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001621 ram_addr + TARGET_PAGE_SIZE,
1622 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001623}
1624
bellard9fa3e852004-01-04 18:06:42 +00001625/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001626 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001627static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001628 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001629{
bellard3a7d9292005-08-21 09:26:42 +00001630 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001631}
1632
ths5fafdf22007-09-16 21:08:06 +00001633static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001634 unsigned long start, unsigned long length)
1635{
1636 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001637 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1638 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001639 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001640 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001641 }
1642 }
1643}
1644
bellard3a7d9292005-08-21 09:26:42 +00001645void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001646 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001647{
1648 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001649 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001650 int i, mask, len;
1651 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001652
1653 start &= TARGET_PAGE_MASK;
1654 end = TARGET_PAGE_ALIGN(end);
1655
1656 length = end - start;
1657 if (length == 0)
1658 return;
bellard0a962c02005-02-10 22:00:27 +00001659 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001660#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001661 /* XXX: should not depend on cpu context */
1662 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001663 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001664 ram_addr_t addr;
1665 addr = start;
1666 for(i = 0; i < len; i++) {
1667 kqemu_set_notdirty(env, addr);
1668 addr += TARGET_PAGE_SIZE;
1669 }
bellard3a7d9292005-08-21 09:26:42 +00001670 }
1671#endif
bellardf23db162005-08-21 19:12:28 +00001672 mask = ~dirty_flags;
1673 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1674 for(i = 0; i < len; i++)
1675 p[i] &= mask;
1676
bellard1ccde1c2004-02-06 19:46:14 +00001677 /* we modify the TLB cache so that the dirty bit will be set again
1678 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001679 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001680 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1681 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001682 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001683 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001684 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001685#if (NB_MMU_MODES >= 3)
1686 for(i = 0; i < CPU_TLB_SIZE; i++)
1687 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1688#if (NB_MMU_MODES == 4)
1689 for(i = 0; i < CPU_TLB_SIZE; i++)
1690 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1691#endif
1692#endif
bellard6a00d602005-11-21 23:25:50 +00001693 }
bellard1ccde1c2004-02-06 19:46:14 +00001694}
1695
bellard3a7d9292005-08-21 09:26:42 +00001696static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1697{
1698 ram_addr_t ram_addr;
1699
bellard84b7b8e2005-11-28 21:19:04 +00001700 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001701 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001702 tlb_entry->addend - (unsigned long)phys_ram_base;
1703 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001704 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001705 }
1706 }
1707}
1708
1709/* update the TLB according to the current state of the dirty bits */
1710void cpu_tlb_update_dirty(CPUState *env)
1711{
1712 int i;
1713 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001714 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001715 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001716 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001717#if (NB_MMU_MODES >= 3)
1718 for(i = 0; i < CPU_TLB_SIZE; i++)
1719 tlb_update_dirty(&env->tlb_table[2][i]);
1720#if (NB_MMU_MODES == 4)
1721 for(i = 0; i < CPU_TLB_SIZE; i++)
1722 tlb_update_dirty(&env->tlb_table[3][i]);
1723#endif
1724#endif
bellard3a7d9292005-08-21 09:26:42 +00001725}
1726
pbrook0f459d12008-06-09 00:20:13 +00001727static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001728{
pbrook0f459d12008-06-09 00:20:13 +00001729 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1730 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001731}
1732
pbrook0f459d12008-06-09 00:20:13 +00001733/* update the TLB corresponding to virtual page vaddr
1734 so that it is no longer dirty */
1735static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001736{
bellard1ccde1c2004-02-06 19:46:14 +00001737 int i;
1738
pbrook0f459d12008-06-09 00:20:13 +00001739 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001740 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001741 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1742 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001743#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001744 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001745#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001746 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001747#endif
1748#endif
bellard9fa3e852004-01-04 18:06:42 +00001749}
1750
bellard59817cc2004-02-16 22:01:13 +00001751/* add a new TLB entry. At most one entry for a given virtual address
1752 is permitted. Return 0 if OK or 2 if the page could not be mapped
1753 (can only happen in non SOFTMMU mode for I/O pages or pages
1754 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001755int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1756 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001757 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001758{
bellard92e873b2004-05-21 14:52:29 +00001759 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001760 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001761 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001762 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001763 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001764 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001765 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001766 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001767 int i;
pbrook0f459d12008-06-09 00:20:13 +00001768 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001769
bellard92e873b2004-05-21 14:52:29 +00001770 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001771 if (!p) {
1772 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001773 } else {
1774 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001775 }
1776#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001777 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1778 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001779#endif
1780
1781 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001782 address = vaddr;
1783 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1784 /* IO memory case (romd handled later) */
1785 address |= TLB_MMIO;
1786 }
1787 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1788 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1789 /* Normal RAM. */
1790 iotlb = pd & TARGET_PAGE_MASK;
1791 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1792 iotlb |= IO_MEM_NOTDIRTY;
1793 else
1794 iotlb |= IO_MEM_ROM;
1795 } else {
1796 /* IO handlers are currently passed a phsical address.
1797 It would be nice to pass an offset from the base address
1798 of that region. This would avoid having to special case RAM,
1799 and avoid full address decoding in every device.
1800 We can't use the high bits of pd for this because
1801 IO_MEM_ROMD uses these as a ram address. */
1802 iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
1803 }
pbrook6658ffb2007-03-16 23:58:11 +00001804
pbrook0f459d12008-06-09 00:20:13 +00001805 code_address = address;
1806 /* Make accesses to pages with watchpoints go via the
1807 watchpoint trap routines. */
1808 for (i = 0; i < env->nb_watchpoints; i++) {
1809 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1810 iotlb = io_mem_watch + paddr;
1811 /* TODO: The memory case can be optimized by not trapping
1812 reads of pages with a write breakpoint. */
1813 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00001814 }
pbrook0f459d12008-06-09 00:20:13 +00001815 }
balrogd79acba2007-06-26 20:01:13 +00001816
pbrook0f459d12008-06-09 00:20:13 +00001817 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1818 env->iotlb[mmu_idx][index] = iotlb - vaddr;
1819 te = &env->tlb_table[mmu_idx][index];
1820 te->addend = addend - vaddr;
1821 if (prot & PAGE_READ) {
1822 te->addr_read = address;
1823 } else {
1824 te->addr_read = -1;
1825 }
edgar_igl5c751e92008-05-06 08:44:21 +00001826
pbrook0f459d12008-06-09 00:20:13 +00001827 if (prot & PAGE_EXEC) {
1828 te->addr_code = code_address;
1829 } else {
1830 te->addr_code = -1;
1831 }
1832 if (prot & PAGE_WRITE) {
1833 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1834 (pd & IO_MEM_ROMD)) {
1835 /* Write access calls the I/O callback. */
1836 te->addr_write = address | TLB_MMIO;
1837 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1838 !cpu_physical_memory_is_dirty(pd)) {
1839 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00001840 } else {
pbrook0f459d12008-06-09 00:20:13 +00001841 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001842 }
pbrook0f459d12008-06-09 00:20:13 +00001843 } else {
1844 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001845 }
bellard9fa3e852004-01-04 18:06:42 +00001846 return ret;
1847}
1848
bellard01243112004-01-04 15:48:17 +00001849#else
1850
bellardee8b7022004-02-03 23:35:10 +00001851void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001852{
1853}
1854
bellard2e126692004-04-25 21:28:44 +00001855void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001856{
1857}
1858
ths5fafdf22007-09-16 21:08:06 +00001859int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1860 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001861 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001862{
bellard9fa3e852004-01-04 18:06:42 +00001863 return 0;
1864}
bellard33417e72003-08-10 21:47:01 +00001865
bellard9fa3e852004-01-04 18:06:42 +00001866/* dump memory mappings */
1867void page_dump(FILE *f)
1868{
1869 unsigned long start, end;
1870 int i, j, prot, prot1;
1871 PageDesc *p;
1872
1873 fprintf(f, "%-8s %-8s %-8s %s\n",
1874 "start", "end", "size", "prot");
1875 start = -1;
1876 end = -1;
1877 prot = 0;
1878 for(i = 0; i <= L1_SIZE; i++) {
1879 if (i < L1_SIZE)
1880 p = l1_map[i];
1881 else
1882 p = NULL;
1883 for(j = 0;j < L2_SIZE; j++) {
1884 if (!p)
1885 prot1 = 0;
1886 else
1887 prot1 = p[j].flags;
1888 if (prot1 != prot) {
1889 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1890 if (start != -1) {
1891 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001892 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001893 prot & PAGE_READ ? 'r' : '-',
1894 prot & PAGE_WRITE ? 'w' : '-',
1895 prot & PAGE_EXEC ? 'x' : '-');
1896 }
1897 if (prot1 != 0)
1898 start = end;
1899 else
1900 start = -1;
1901 prot = prot1;
1902 }
1903 if (!p)
1904 break;
1905 }
bellard33417e72003-08-10 21:47:01 +00001906 }
bellard33417e72003-08-10 21:47:01 +00001907}
1908
pbrook53a59602006-03-25 19:31:22 +00001909int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001910{
bellard9fa3e852004-01-04 18:06:42 +00001911 PageDesc *p;
1912
1913 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001914 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001915 return 0;
1916 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001917}
1918
bellard9fa3e852004-01-04 18:06:42 +00001919/* modify the flags of a page and invalidate the code if
1920 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1921 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001922void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001923{
1924 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001925 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001926
pbrookc8a706f2008-06-02 16:16:42 +00001927 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00001928 start = start & TARGET_PAGE_MASK;
1929 end = TARGET_PAGE_ALIGN(end);
1930 if (flags & PAGE_WRITE)
1931 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00001932 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1933 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00001934 /* We may be called for host regions that are outside guest
1935 address space. */
1936 if (!p)
1937 return;
bellard9fa3e852004-01-04 18:06:42 +00001938 /* if the write protection is set, then we invalidate the code
1939 inside */
ths5fafdf22007-09-16 21:08:06 +00001940 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001941 (flags & PAGE_WRITE) &&
1942 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001943 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001944 }
1945 p->flags = flags;
1946 }
bellard9fa3e852004-01-04 18:06:42 +00001947}
1948
ths3d97b402007-11-02 19:02:07 +00001949int page_check_range(target_ulong start, target_ulong len, int flags)
1950{
1951 PageDesc *p;
1952 target_ulong end;
1953 target_ulong addr;
1954
1955 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1956 start = start & TARGET_PAGE_MASK;
1957
1958 if( end < start )
1959 /* we've wrapped around */
1960 return -1;
1961 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1962 p = page_find(addr >> TARGET_PAGE_BITS);
1963 if( !p )
1964 return -1;
1965 if( !(p->flags & PAGE_VALID) )
1966 return -1;
1967
bellarddae32702007-11-14 10:51:00 +00001968 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001969 return -1;
bellarddae32702007-11-14 10:51:00 +00001970 if (flags & PAGE_WRITE) {
1971 if (!(p->flags & PAGE_WRITE_ORG))
1972 return -1;
1973 /* unprotect the page if it was put read-only because it
1974 contains translated code */
1975 if (!(p->flags & PAGE_WRITE)) {
1976 if (!page_unprotect(addr, 0, NULL))
1977 return -1;
1978 }
1979 return 0;
1980 }
ths3d97b402007-11-02 19:02:07 +00001981 }
1982 return 0;
1983}
1984
bellard9fa3e852004-01-04 18:06:42 +00001985/* called from signal handler: invalidate the code and unprotect the
1986 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001987int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001988{
1989 unsigned int page_index, prot, pindex;
1990 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001991 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001992
pbrookc8a706f2008-06-02 16:16:42 +00001993 /* Technically this isn't safe inside a signal handler. However we
1994 know this only ever happens in a synchronous SEGV handler, so in
1995 practice it seems to be ok. */
1996 mmap_lock();
1997
bellard83fb7ad2004-07-05 21:25:26 +00001998 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001999 page_index = host_start >> TARGET_PAGE_BITS;
2000 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002001 if (!p1) {
2002 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002003 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002004 }
bellard83fb7ad2004-07-05 21:25:26 +00002005 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002006 p = p1;
2007 prot = 0;
2008 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2009 prot |= p->flags;
2010 p++;
2011 }
2012 /* if the page was really writable, then we change its
2013 protection back to writable */
2014 if (prot & PAGE_WRITE_ORG) {
2015 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2016 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002017 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002018 (prot & PAGE_BITS) | PAGE_WRITE);
2019 p1[pindex].flags |= PAGE_WRITE;
2020 /* and since the content will be modified, we must invalidate
2021 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002022 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002023#ifdef DEBUG_TB_CHECK
2024 tb_invalidate_check(address);
2025#endif
pbrookc8a706f2008-06-02 16:16:42 +00002026 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002027 return 1;
2028 }
2029 }
pbrookc8a706f2008-06-02 16:16:42 +00002030 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002031 return 0;
2032}
2033
bellard6a00d602005-11-21 23:25:50 +00002034static inline void tlb_set_dirty(CPUState *env,
2035 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002036{
2037}
bellard9fa3e852004-01-04 18:06:42 +00002038#endif /* defined(CONFIG_USER_ONLY) */
2039
pbrooke2eef172008-06-08 01:09:01 +00002040#if !defined(CONFIG_USER_ONLY)
blueswir1db7b5422007-05-26 17:36:03 +00002041static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002042 ram_addr_t memory);
2043static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2044 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002045#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2046 need_subpage) \
2047 do { \
2048 if (addr > start_addr) \
2049 start_addr2 = 0; \
2050 else { \
2051 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2052 if (start_addr2 > 0) \
2053 need_subpage = 1; \
2054 } \
2055 \
blueswir149e9fba2007-05-30 17:25:06 +00002056 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002057 end_addr2 = TARGET_PAGE_SIZE - 1; \
2058 else { \
2059 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2060 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2061 need_subpage = 1; \
2062 } \
2063 } while (0)
2064
bellard33417e72003-08-10 21:47:01 +00002065/* register physical memory. 'size' must be a multiple of the target
2066 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2067 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002068void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002069 ram_addr_t size,
2070 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002071{
bellard108c49b2005-07-24 12:55:09 +00002072 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002073 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002074 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002075 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002076 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002077
bellardda260242008-05-30 20:48:25 +00002078#ifdef USE_KQEMU
2079 /* XXX: should not depend on cpu context */
2080 env = first_cpu;
2081 if (env->kqemu_enabled) {
2082 kqemu_set_phys_mem(start_addr, size, phys_offset);
2083 }
2084#endif
bellard5fd386f2004-05-23 21:11:22 +00002085 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002086 end_addr = start_addr + (target_phys_addr_t)size;
2087 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002088 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2089 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002090 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002091 target_phys_addr_t start_addr2, end_addr2;
2092 int need_subpage = 0;
2093
2094 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2095 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002096 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002097 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2098 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2099 &p->phys_offset, orig_memory);
2100 } else {
2101 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2102 >> IO_MEM_SHIFT];
2103 }
2104 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2105 } else {
2106 p->phys_offset = phys_offset;
2107 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2108 (phys_offset & IO_MEM_ROMD))
2109 phys_offset += TARGET_PAGE_SIZE;
2110 }
2111 } else {
2112 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2113 p->phys_offset = phys_offset;
2114 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2115 (phys_offset & IO_MEM_ROMD))
2116 phys_offset += TARGET_PAGE_SIZE;
2117 else {
2118 target_phys_addr_t start_addr2, end_addr2;
2119 int need_subpage = 0;
2120
2121 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2122 end_addr2, need_subpage);
2123
blueswir14254fab2008-01-01 16:57:19 +00002124 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002125 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2126 &p->phys_offset, IO_MEM_UNASSIGNED);
2127 subpage_register(subpage, start_addr2, end_addr2,
2128 phys_offset);
2129 }
2130 }
2131 }
bellard33417e72003-08-10 21:47:01 +00002132 }
ths3b46e622007-09-17 08:09:54 +00002133
bellard9d420372006-06-25 22:25:22 +00002134 /* since each CPU stores ram addresses in its TLB cache, we must
2135 reset the modified entries */
2136 /* XXX: slow ! */
2137 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2138 tlb_flush(env, 1);
2139 }
bellard33417e72003-08-10 21:47:01 +00002140}
2141
bellardba863452006-09-24 18:41:10 +00002142/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002143ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002144{
2145 PhysPageDesc *p;
2146
2147 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2148 if (!p)
2149 return IO_MEM_UNASSIGNED;
2150 return p->phys_offset;
2151}
2152
bellarde9a1ab12007-02-08 23:08:38 +00002153/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002154ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002155{
2156 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002157 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002158 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2159 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002160 abort();
2161 }
2162 addr = phys_ram_alloc_offset;
2163 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2164 return addr;
2165}
2166
2167void qemu_ram_free(ram_addr_t addr)
2168{
2169}
2170
bellarda4193c82004-06-03 14:01:43 +00002171static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002172{
pbrook67d3b952006-12-18 05:03:52 +00002173#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002174 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002175#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002176#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002177 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002178#elif TARGET_CRIS
2179 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002180#endif
bellard33417e72003-08-10 21:47:01 +00002181 return 0;
2182}
2183
bellarda4193c82004-06-03 14:01:43 +00002184static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002185{
pbrook67d3b952006-12-18 05:03:52 +00002186#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002187 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002188#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002189#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002190 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002191#elif TARGET_CRIS
2192 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002193#endif
bellard33417e72003-08-10 21:47:01 +00002194}
2195
2196static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2197 unassigned_mem_readb,
2198 unassigned_mem_readb,
2199 unassigned_mem_readb,
2200};
2201
2202static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2203 unassigned_mem_writeb,
2204 unassigned_mem_writeb,
2205 unassigned_mem_writeb,
2206};
2207
pbrook0f459d12008-06-09 00:20:13 +00002208static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2209 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002210{
bellard3a7d9292005-08-21 09:26:42 +00002211 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002212 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2213 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2214#if !defined(CONFIG_USER_ONLY)
2215 tb_invalidate_phys_page_fast(ram_addr, 1);
2216 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2217#endif
2218 }
pbrook0f459d12008-06-09 00:20:13 +00002219 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002220#ifdef USE_KQEMU
2221 if (cpu_single_env->kqemu_enabled &&
2222 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2223 kqemu_modify_page(cpu_single_env, ram_addr);
2224#endif
bellardf23db162005-08-21 19:12:28 +00002225 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2226 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2227 /* we remove the notdirty callback only if the code has been
2228 flushed */
2229 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002230 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002231}
2232
pbrook0f459d12008-06-09 00:20:13 +00002233static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2234 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002235{
bellard3a7d9292005-08-21 09:26:42 +00002236 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002237 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2238 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2239#if !defined(CONFIG_USER_ONLY)
2240 tb_invalidate_phys_page_fast(ram_addr, 2);
2241 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2242#endif
2243 }
pbrook0f459d12008-06-09 00:20:13 +00002244 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002245#ifdef USE_KQEMU
2246 if (cpu_single_env->kqemu_enabled &&
2247 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2248 kqemu_modify_page(cpu_single_env, ram_addr);
2249#endif
bellardf23db162005-08-21 19:12:28 +00002250 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2251 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2252 /* we remove the notdirty callback only if the code has been
2253 flushed */
2254 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002255 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002256}
2257
pbrook0f459d12008-06-09 00:20:13 +00002258static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2259 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002260{
bellard3a7d9292005-08-21 09:26:42 +00002261 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002262 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2263 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2264#if !defined(CONFIG_USER_ONLY)
2265 tb_invalidate_phys_page_fast(ram_addr, 4);
2266 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2267#endif
2268 }
pbrook0f459d12008-06-09 00:20:13 +00002269 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002270#ifdef USE_KQEMU
2271 if (cpu_single_env->kqemu_enabled &&
2272 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2273 kqemu_modify_page(cpu_single_env, ram_addr);
2274#endif
bellardf23db162005-08-21 19:12:28 +00002275 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2276 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2277 /* we remove the notdirty callback only if the code has been
2278 flushed */
2279 if (dirty_flags == 0xff)
pbrook0f459d12008-06-09 00:20:13 +00002280 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002281}
2282
bellard3a7d9292005-08-21 09:26:42 +00002283static CPUReadMemoryFunc *error_mem_read[3] = {
2284 NULL, /* never used */
2285 NULL, /* never used */
2286 NULL, /* never used */
2287};
2288
bellard1ccde1c2004-02-06 19:46:14 +00002289static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2290 notdirty_mem_writeb,
2291 notdirty_mem_writew,
2292 notdirty_mem_writel,
2293};
2294
pbrook0f459d12008-06-09 00:20:13 +00002295/* Generate a debug exception if a watchpoint has been hit. */
2296static void check_watchpoint(int offset, int flags)
2297{
2298 CPUState *env = cpu_single_env;
2299 target_ulong vaddr;
2300 int i;
2301
2302 vaddr = (env->mem_write_vaddr & TARGET_PAGE_MASK) + offset;
2303 for (i = 0; i < env->nb_watchpoints; i++) {
2304 if (vaddr == env->watchpoint[i].vaddr
2305 && (env->watchpoint[i].type & flags)) {
2306 env->watchpoint_hit = i + 1;
2307 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2308 break;
2309 }
2310 }
2311}
2312
pbrook6658ffb2007-03-16 23:58:11 +00002313/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2314 so these check for a hit then pass through to the normal out-of-line
2315 phys routines. */
2316static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2317{
pbrook0f459d12008-06-09 00:20:13 +00002318 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002319 return ldub_phys(addr);
2320}
2321
2322static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2323{
pbrook0f459d12008-06-09 00:20:13 +00002324 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002325 return lduw_phys(addr);
2326}
2327
2328static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2329{
pbrook0f459d12008-06-09 00:20:13 +00002330 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002331 return ldl_phys(addr);
2332}
2333
pbrook6658ffb2007-03-16 23:58:11 +00002334static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2335 uint32_t val)
2336{
pbrook0f459d12008-06-09 00:20:13 +00002337 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002338 stb_phys(addr, val);
2339}
2340
2341static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2342 uint32_t val)
2343{
pbrook0f459d12008-06-09 00:20:13 +00002344 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002345 stw_phys(addr, val);
2346}
2347
2348static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2349 uint32_t val)
2350{
pbrook0f459d12008-06-09 00:20:13 +00002351 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002352 stl_phys(addr, val);
2353}
2354
2355static CPUReadMemoryFunc *watch_mem_read[3] = {
2356 watch_mem_readb,
2357 watch_mem_readw,
2358 watch_mem_readl,
2359};
2360
2361static CPUWriteMemoryFunc *watch_mem_write[3] = {
2362 watch_mem_writeb,
2363 watch_mem_writew,
2364 watch_mem_writel,
2365};
pbrook6658ffb2007-03-16 23:58:11 +00002366
blueswir1db7b5422007-05-26 17:36:03 +00002367static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2368 unsigned int len)
2369{
blueswir1db7b5422007-05-26 17:36:03 +00002370 uint32_t ret;
2371 unsigned int idx;
2372
2373 idx = SUBPAGE_IDX(addr - mmio->base);
2374#if defined(DEBUG_SUBPAGE)
2375 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2376 mmio, len, addr, idx);
2377#endif
blueswir13ee89922008-01-02 19:45:26 +00002378 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002379
2380 return ret;
2381}
2382
2383static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2384 uint32_t value, unsigned int len)
2385{
blueswir1db7b5422007-05-26 17:36:03 +00002386 unsigned int idx;
2387
2388 idx = SUBPAGE_IDX(addr - mmio->base);
2389#if defined(DEBUG_SUBPAGE)
2390 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2391 mmio, len, addr, idx, value);
2392#endif
blueswir13ee89922008-01-02 19:45:26 +00002393 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002394}
2395
2396static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2397{
2398#if defined(DEBUG_SUBPAGE)
2399 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2400#endif
2401
2402 return subpage_readlen(opaque, addr, 0);
2403}
2404
2405static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2406 uint32_t value)
2407{
2408#if defined(DEBUG_SUBPAGE)
2409 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2410#endif
2411 subpage_writelen(opaque, addr, value, 0);
2412}
2413
2414static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2415{
2416#if defined(DEBUG_SUBPAGE)
2417 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2418#endif
2419
2420 return subpage_readlen(opaque, addr, 1);
2421}
2422
2423static void subpage_writew (void *opaque, target_phys_addr_t addr,
2424 uint32_t value)
2425{
2426#if defined(DEBUG_SUBPAGE)
2427 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2428#endif
2429 subpage_writelen(opaque, addr, value, 1);
2430}
2431
2432static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2433{
2434#if defined(DEBUG_SUBPAGE)
2435 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2436#endif
2437
2438 return subpage_readlen(opaque, addr, 2);
2439}
2440
2441static void subpage_writel (void *opaque,
2442 target_phys_addr_t addr, uint32_t value)
2443{
2444#if defined(DEBUG_SUBPAGE)
2445 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2446#endif
2447 subpage_writelen(opaque, addr, value, 2);
2448}
2449
2450static CPUReadMemoryFunc *subpage_read[] = {
2451 &subpage_readb,
2452 &subpage_readw,
2453 &subpage_readl,
2454};
2455
2456static CPUWriteMemoryFunc *subpage_write[] = {
2457 &subpage_writeb,
2458 &subpage_writew,
2459 &subpage_writel,
2460};
2461
2462static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002463 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002464{
2465 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002466 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002467
2468 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2469 return -1;
2470 idx = SUBPAGE_IDX(start);
2471 eidx = SUBPAGE_IDX(end);
2472#if defined(DEBUG_SUBPAGE)
2473 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2474 mmio, start, end, idx, eidx, memory);
2475#endif
2476 memory >>= IO_MEM_SHIFT;
2477 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002478 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002479 if (io_mem_read[memory][i]) {
2480 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2481 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2482 }
2483 if (io_mem_write[memory][i]) {
2484 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2485 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2486 }
blueswir14254fab2008-01-01 16:57:19 +00002487 }
blueswir1db7b5422007-05-26 17:36:03 +00002488 }
2489
2490 return 0;
2491}
2492
aurel3200f82b82008-04-27 21:12:55 +00002493static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2494 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002495{
2496 subpage_t *mmio;
2497 int subpage_memory;
2498
2499 mmio = qemu_mallocz(sizeof(subpage_t));
2500 if (mmio != NULL) {
2501 mmio->base = base;
2502 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2503#if defined(DEBUG_SUBPAGE)
2504 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2505 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2506#endif
2507 *phys = subpage_memory | IO_MEM_SUBPAGE;
2508 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2509 }
2510
2511 return mmio;
2512}
2513
bellard33417e72003-08-10 21:47:01 +00002514static void io_mem_init(void)
2515{
bellard3a7d9292005-08-21 09:26:42 +00002516 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002517 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002518 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002519 io_mem_nb = 5;
2520
pbrook0f459d12008-06-09 00:20:13 +00002521 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002522 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002523 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002524 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002525 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002526}
2527
2528/* mem_read and mem_write are arrays of functions containing the
2529 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002530 2). Functions can be omitted with a NULL function pointer. The
2531 registered functions may be modified dynamically later.
2532 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002533 modified. If it is zero, a new io zone is allocated. The return
2534 value can be used with cpu_register_physical_memory(). (-1) is
2535 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002536int cpu_register_io_memory(int io_index,
2537 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002538 CPUWriteMemoryFunc **mem_write,
2539 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002540{
blueswir14254fab2008-01-01 16:57:19 +00002541 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002542
2543 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002544 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002545 return -1;
2546 io_index = io_mem_nb++;
2547 } else {
2548 if (io_index >= IO_MEM_NB_ENTRIES)
2549 return -1;
2550 }
bellardb5ff1b32005-11-26 10:38:39 +00002551
bellard33417e72003-08-10 21:47:01 +00002552 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002553 if (!mem_read[i] || !mem_write[i])
2554 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002555 io_mem_read[io_index][i] = mem_read[i];
2556 io_mem_write[io_index][i] = mem_write[i];
2557 }
bellarda4193c82004-06-03 14:01:43 +00002558 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002559 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002560}
bellard61382a52003-10-27 21:22:23 +00002561
bellard8926b512004-10-10 15:14:20 +00002562CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2563{
2564 return io_mem_write[io_index >> IO_MEM_SHIFT];
2565}
2566
2567CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2568{
2569 return io_mem_read[io_index >> IO_MEM_SHIFT];
2570}
2571
pbrooke2eef172008-06-08 01:09:01 +00002572#endif /* !defined(CONFIG_USER_ONLY) */
2573
bellard13eb76e2004-01-24 15:23:36 +00002574/* physical memory access (slow version, mainly for debug) */
2575#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002576void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002577 int len, int is_write)
2578{
2579 int l, flags;
2580 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002581 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002582
2583 while (len > 0) {
2584 page = addr & TARGET_PAGE_MASK;
2585 l = (page + TARGET_PAGE_SIZE) - addr;
2586 if (l > len)
2587 l = len;
2588 flags = page_get_flags(page);
2589 if (!(flags & PAGE_VALID))
2590 return;
2591 if (is_write) {
2592 if (!(flags & PAGE_WRITE))
2593 return;
bellard579a97f2007-11-11 14:26:47 +00002594 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002595 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002596 /* FIXME - should this return an error rather than just fail? */
2597 return;
aurel3272fb7da2008-04-27 23:53:45 +00002598 memcpy(p, buf, l);
2599 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002600 } else {
2601 if (!(flags & PAGE_READ))
2602 return;
bellard579a97f2007-11-11 14:26:47 +00002603 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002604 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002605 /* FIXME - should this return an error rather than just fail? */
2606 return;
aurel3272fb7da2008-04-27 23:53:45 +00002607 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002608 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002609 }
2610 len -= l;
2611 buf += l;
2612 addr += l;
2613 }
2614}
bellard8df1cd02005-01-28 22:37:22 +00002615
bellard13eb76e2004-01-24 15:23:36 +00002616#else
ths5fafdf22007-09-16 21:08:06 +00002617void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002618 int len, int is_write)
2619{
2620 int l, io_index;
2621 uint8_t *ptr;
2622 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002623 target_phys_addr_t page;
2624 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002625 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002626
bellard13eb76e2004-01-24 15:23:36 +00002627 while (len > 0) {
2628 page = addr & TARGET_PAGE_MASK;
2629 l = (page + TARGET_PAGE_SIZE) - addr;
2630 if (l > len)
2631 l = len;
bellard92e873b2004-05-21 14:52:29 +00002632 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002633 if (!p) {
2634 pd = IO_MEM_UNASSIGNED;
2635 } else {
2636 pd = p->phys_offset;
2637 }
ths3b46e622007-09-17 08:09:54 +00002638
bellard13eb76e2004-01-24 15:23:36 +00002639 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002640 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002641 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002642 /* XXX: could force cpu_single_env to NULL to avoid
2643 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002644 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002645 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002646 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002647 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002648 l = 4;
2649 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002650 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002651 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002652 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002653 l = 2;
2654 } else {
bellard1c213d12005-09-03 10:49:04 +00002655 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002656 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002657 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002658 l = 1;
2659 }
2660 } else {
bellardb448f2f2004-02-25 23:24:04 +00002661 unsigned long addr1;
2662 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002663 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002664 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002665 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002666 if (!cpu_physical_memory_is_dirty(addr1)) {
2667 /* invalidate code */
2668 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2669 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002670 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002671 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002672 }
bellard13eb76e2004-01-24 15:23:36 +00002673 }
2674 } else {
ths5fafdf22007-09-16 21:08:06 +00002675 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002676 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002677 /* I/O case */
2678 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2679 if (l >= 4 && ((addr & 3) == 0)) {
2680 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002681 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002682 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002683 l = 4;
2684 } else if (l >= 2 && ((addr & 1) == 0)) {
2685 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002686 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002687 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002688 l = 2;
2689 } else {
bellard1c213d12005-09-03 10:49:04 +00002690 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002691 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002692 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002693 l = 1;
2694 }
2695 } else {
2696 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002697 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002698 (addr & ~TARGET_PAGE_MASK);
2699 memcpy(buf, ptr, l);
2700 }
2701 }
2702 len -= l;
2703 buf += l;
2704 addr += l;
2705 }
2706}
bellard8df1cd02005-01-28 22:37:22 +00002707
bellardd0ecd2a2006-04-23 17:14:48 +00002708/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002709void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002710 const uint8_t *buf, int len)
2711{
2712 int l;
2713 uint8_t *ptr;
2714 target_phys_addr_t page;
2715 unsigned long pd;
2716 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002717
bellardd0ecd2a2006-04-23 17:14:48 +00002718 while (len > 0) {
2719 page = addr & TARGET_PAGE_MASK;
2720 l = (page + TARGET_PAGE_SIZE) - addr;
2721 if (l > len)
2722 l = len;
2723 p = phys_page_find(page >> TARGET_PAGE_BITS);
2724 if (!p) {
2725 pd = IO_MEM_UNASSIGNED;
2726 } else {
2727 pd = p->phys_offset;
2728 }
ths3b46e622007-09-17 08:09:54 +00002729
bellardd0ecd2a2006-04-23 17:14:48 +00002730 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002731 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2732 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002733 /* do nothing */
2734 } else {
2735 unsigned long addr1;
2736 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2737 /* ROM/RAM case */
2738 ptr = phys_ram_base + addr1;
2739 memcpy(ptr, buf, l);
2740 }
2741 len -= l;
2742 buf += l;
2743 addr += l;
2744 }
2745}
2746
2747
bellard8df1cd02005-01-28 22:37:22 +00002748/* warning: addr must be aligned */
2749uint32_t ldl_phys(target_phys_addr_t addr)
2750{
2751 int io_index;
2752 uint8_t *ptr;
2753 uint32_t val;
2754 unsigned long pd;
2755 PhysPageDesc *p;
2756
2757 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2758 if (!p) {
2759 pd = IO_MEM_UNASSIGNED;
2760 } else {
2761 pd = p->phys_offset;
2762 }
ths3b46e622007-09-17 08:09:54 +00002763
ths5fafdf22007-09-16 21:08:06 +00002764 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002765 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002766 /* I/O case */
2767 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2768 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2769 } else {
2770 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002771 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002772 (addr & ~TARGET_PAGE_MASK);
2773 val = ldl_p(ptr);
2774 }
2775 return val;
2776}
2777
bellard84b7b8e2005-11-28 21:19:04 +00002778/* warning: addr must be aligned */
2779uint64_t ldq_phys(target_phys_addr_t addr)
2780{
2781 int io_index;
2782 uint8_t *ptr;
2783 uint64_t val;
2784 unsigned long pd;
2785 PhysPageDesc *p;
2786
2787 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2788 if (!p) {
2789 pd = IO_MEM_UNASSIGNED;
2790 } else {
2791 pd = p->phys_offset;
2792 }
ths3b46e622007-09-17 08:09:54 +00002793
bellard2a4188a2006-06-25 21:54:59 +00002794 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2795 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002796 /* I/O case */
2797 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2798#ifdef TARGET_WORDS_BIGENDIAN
2799 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2800 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2801#else
2802 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2803 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2804#endif
2805 } else {
2806 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002807 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002808 (addr & ~TARGET_PAGE_MASK);
2809 val = ldq_p(ptr);
2810 }
2811 return val;
2812}
2813
bellardaab33092005-10-30 20:48:42 +00002814/* XXX: optimize */
2815uint32_t ldub_phys(target_phys_addr_t addr)
2816{
2817 uint8_t val;
2818 cpu_physical_memory_read(addr, &val, 1);
2819 return val;
2820}
2821
2822/* XXX: optimize */
2823uint32_t lduw_phys(target_phys_addr_t addr)
2824{
2825 uint16_t val;
2826 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2827 return tswap16(val);
2828}
2829
bellard8df1cd02005-01-28 22:37:22 +00002830/* warning: addr must be aligned. The ram page is not masked as dirty
2831 and the code inside is not invalidated. It is useful if the dirty
2832 bits are used to track modified PTEs */
2833void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2834{
2835 int io_index;
2836 uint8_t *ptr;
2837 unsigned long pd;
2838 PhysPageDesc *p;
2839
2840 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2841 if (!p) {
2842 pd = IO_MEM_UNASSIGNED;
2843 } else {
2844 pd = p->phys_offset;
2845 }
ths3b46e622007-09-17 08:09:54 +00002846
bellard3a7d9292005-08-21 09:26:42 +00002847 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002848 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2849 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2850 } else {
ths5fafdf22007-09-16 21:08:06 +00002851 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002852 (addr & ~TARGET_PAGE_MASK);
2853 stl_p(ptr, val);
2854 }
2855}
2856
j_mayerbc98a7e2007-04-04 07:55:12 +00002857void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2858{
2859 int io_index;
2860 uint8_t *ptr;
2861 unsigned long pd;
2862 PhysPageDesc *p;
2863
2864 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2865 if (!p) {
2866 pd = IO_MEM_UNASSIGNED;
2867 } else {
2868 pd = p->phys_offset;
2869 }
ths3b46e622007-09-17 08:09:54 +00002870
j_mayerbc98a7e2007-04-04 07:55:12 +00002871 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2872 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2873#ifdef TARGET_WORDS_BIGENDIAN
2874 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2875 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2876#else
2877 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2878 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2879#endif
2880 } else {
ths5fafdf22007-09-16 21:08:06 +00002881 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002882 (addr & ~TARGET_PAGE_MASK);
2883 stq_p(ptr, val);
2884 }
2885}
2886
bellard8df1cd02005-01-28 22:37:22 +00002887/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002888void stl_phys(target_phys_addr_t addr, uint32_t val)
2889{
2890 int io_index;
2891 uint8_t *ptr;
2892 unsigned long pd;
2893 PhysPageDesc *p;
2894
2895 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2896 if (!p) {
2897 pd = IO_MEM_UNASSIGNED;
2898 } else {
2899 pd = p->phys_offset;
2900 }
ths3b46e622007-09-17 08:09:54 +00002901
bellard3a7d9292005-08-21 09:26:42 +00002902 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002903 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2904 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2905 } else {
2906 unsigned long addr1;
2907 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2908 /* RAM case */
2909 ptr = phys_ram_base + addr1;
2910 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002911 if (!cpu_physical_memory_is_dirty(addr1)) {
2912 /* invalidate code */
2913 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2914 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002915 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2916 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002917 }
bellard8df1cd02005-01-28 22:37:22 +00002918 }
2919}
2920
bellardaab33092005-10-30 20:48:42 +00002921/* XXX: optimize */
2922void stb_phys(target_phys_addr_t addr, uint32_t val)
2923{
2924 uint8_t v = val;
2925 cpu_physical_memory_write(addr, &v, 1);
2926}
2927
2928/* XXX: optimize */
2929void stw_phys(target_phys_addr_t addr, uint32_t val)
2930{
2931 uint16_t v = tswap16(val);
2932 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2933}
2934
2935/* XXX: optimize */
2936void stq_phys(target_phys_addr_t addr, uint64_t val)
2937{
2938 val = tswap64(val);
2939 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2940}
2941
bellard13eb76e2004-01-24 15:23:36 +00002942#endif
2943
2944/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002945int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002946 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002947{
2948 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002949 target_phys_addr_t phys_addr;
2950 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002951
2952 while (len > 0) {
2953 page = addr & TARGET_PAGE_MASK;
2954 phys_addr = cpu_get_phys_page_debug(env, page);
2955 /* if no physical page mapped, return an error */
2956 if (phys_addr == -1)
2957 return -1;
2958 l = (page + TARGET_PAGE_SIZE) - addr;
2959 if (l > len)
2960 l = len;
ths5fafdf22007-09-16 21:08:06 +00002961 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002962 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002963 len -= l;
2964 buf += l;
2965 addr += l;
2966 }
2967 return 0;
2968}
2969
bellarde3db7222005-01-26 22:00:47 +00002970void dump_exec_info(FILE *f,
2971 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2972{
2973 int i, target_code_size, max_target_code_size;
2974 int direct_jmp_count, direct_jmp2_count, cross_page;
2975 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002976
bellarde3db7222005-01-26 22:00:47 +00002977 target_code_size = 0;
2978 max_target_code_size = 0;
2979 cross_page = 0;
2980 direct_jmp_count = 0;
2981 direct_jmp2_count = 0;
2982 for(i = 0; i < nb_tbs; i++) {
2983 tb = &tbs[i];
2984 target_code_size += tb->size;
2985 if (tb->size > max_target_code_size)
2986 max_target_code_size = tb->size;
2987 if (tb->page_addr[1] != -1)
2988 cross_page++;
2989 if (tb->tb_next_offset[0] != 0xffff) {
2990 direct_jmp_count++;
2991 if (tb->tb_next_offset[1] != 0xffff) {
2992 direct_jmp2_count++;
2993 }
2994 }
2995 }
2996 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002997 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00002998 cpu_fprintf(f, "gen code size %ld/%ld\n",
2999 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3000 cpu_fprintf(f, "TB count %d/%d\n",
3001 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003002 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003003 nb_tbs ? target_code_size / nb_tbs : 0,
3004 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003005 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003006 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3007 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003008 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3009 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003010 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3011 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003012 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003013 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3014 direct_jmp2_count,
3015 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003016 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003017 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3018 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3019 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003020 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003021}
3022
ths5fafdf22007-09-16 21:08:06 +00003023#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003024
3025#define MMUSUFFIX _cmmu
3026#define GETPC() NULL
3027#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003028#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003029
3030#define SHIFT 0
3031#include "softmmu_template.h"
3032
3033#define SHIFT 1
3034#include "softmmu_template.h"
3035
3036#define SHIFT 2
3037#include "softmmu_template.h"
3038
3039#define SHIFT 3
3040#include "softmmu_template.h"
3041
3042#undef env
3043
3044#endif