blob: 5e94a8feea305818be71ea78a5e80bb567faef94 [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
aurel32fad6cb12009-01-04 22:05:52 +000018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
bellard54936002003-05-13 00:25:15 +000019 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrookb3c77242008-06-30 16:31:04 +000040#include "hw/hw.h"
aliguori74576192008-10-06 14:02:03 +000041#include "osdep.h"
aliguori7ba1e612008-11-05 16:04:33 +000042#include "kvm.h"
pbrook53a59602006-03-25 19:31:22 +000043#if defined(CONFIG_USER_ONLY)
44#include <qemu.h>
45#endif
bellard54936002003-05-13 00:25:15 +000046
bellardfd6ce8f2003-05-14 19:00:11 +000047//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000048//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000049//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000050//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000051
52/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000053//#define DEBUG_TB_CHECK
54//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000055
ths1196be32007-03-17 15:17:58 +000056//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000057//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000058
pbrook99773bd2006-04-16 15:14:59 +000059#if !defined(CONFIG_USER_ONLY)
60/* TB consistency checks only implemented for usermode emulation. */
61#undef DEBUG_TB_CHECK
62#endif
63
bellard9fa3e852004-01-04 18:06:42 +000064#define SMC_BITMAP_USE_THRESHOLD 10
65
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
blueswir1bdaf78e2008-10-04 07:24:27 +000084static TranslationBlock *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];
blueswir1bdaf78e2008-10-04 07:24:27 +000087static int 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
blueswir1141ac462008-07-26 15:05:57 +000091#if defined(__arm__) || defined(__sparc_v9__)
92/* The prologue must be reachable with a direct jump. ARM and Sparc64
93 have limited branch ranges (possibly also PPC) so place it in a
blueswir1d03d8602008-07-10 17:21:31 +000094 section close to code segment. */
95#define code_gen_section \
96 __attribute__((__section__(".gen_code"))) \
97 __attribute__((aligned (32)))
98#else
99#define code_gen_section \
100 __attribute__((aligned (32)))
101#endif
102
103uint8_t code_gen_prologue[1024] code_gen_section;
blueswir1bdaf78e2008-10-04 07:24:27 +0000104static uint8_t *code_gen_buffer;
105static unsigned long code_gen_buffer_size;
bellard26a5f132008-05-28 12:30:31 +0000106/* threshold to flush the translated code buffer */
blueswir1bdaf78e2008-10-04 07:24:27 +0000107static unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000108uint8_t *code_gen_ptr;
109
pbrooke2eef172008-06-08 01:09:01 +0000110#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +0000111ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000112int phys_ram_fd;
113uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000114uint8_t *phys_ram_dirty;
aliguori74576192008-10-06 14:02:03 +0000115static int in_migration;
bellarde9a1ab12007-02-08 23:08:38 +0000116static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000117#endif
bellard9fa3e852004-01-04 18:06:42 +0000118
bellard6a00d602005-11-21 23:25:50 +0000119CPUState *first_cpu;
120/* current CPU in the current thread. It is only valid inside
121 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000122CPUState *cpu_single_env;
pbrook2e70f6e2008-06-29 01:03:05 +0000123/* 0 = Do not count executed instructions.
thsbf20dc02008-06-30 17:22:19 +0000124 1 = Precise instruction counting.
pbrook2e70f6e2008-06-29 01:03:05 +0000125 2 = Adaptive rate instruction counting. */
126int use_icount = 0;
127/* Current instruction counter. While executing translated code this may
128 include some instructions that have not yet been executed. */
129int64_t qemu_icount;
bellard6a00d602005-11-21 23:25:50 +0000130
bellard54936002003-05-13 00:25:15 +0000131typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000132 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000133 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000134 /* in order to optimize self modifying code, we count the number
135 of lookups we do to a given page to use a bitmap */
136 unsigned int code_write_count;
137 uint8_t *code_bitmap;
138#if defined(CONFIG_USER_ONLY)
139 unsigned long flags;
140#endif
bellard54936002003-05-13 00:25:15 +0000141} PageDesc;
142
bellard92e873b2004-05-21 14:52:29 +0000143typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000144 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000145 ram_addr_t phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +0000146 ram_addr_t region_offset;
bellard92e873b2004-05-21 14:52:29 +0000147} PhysPageDesc;
148
bellard54936002003-05-13 00:25:15 +0000149#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000150#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
151/* XXX: this is a temporary hack for alpha target.
152 * In the future, this is to be replaced by a multi-level table
153 * to actually be able to handle the complete 64 bits address space.
154 */
155#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
156#else
aurel3203875442008-04-22 20:45:18 +0000157#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000158#endif
bellard54936002003-05-13 00:25:15 +0000159
160#define L1_SIZE (1 << L1_BITS)
161#define L2_SIZE (1 << L2_BITS)
162
bellard83fb7ad2004-07-05 21:25:26 +0000163unsigned long qemu_real_host_page_size;
164unsigned long qemu_host_page_bits;
165unsigned long qemu_host_page_size;
166unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000167
bellard92e873b2004-05-21 14:52:29 +0000168/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000169static PageDesc *l1_map[L1_SIZE];
blueswir1bdaf78e2008-10-04 07:24:27 +0000170static PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000171
pbrooke2eef172008-06-08 01:09:01 +0000172#if !defined(CONFIG_USER_ONLY)
173static void io_mem_init(void);
174
bellard33417e72003-08-10 21:47:01 +0000175/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000176CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
177CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000178void *io_mem_opaque[IO_MEM_NB_ENTRIES];
blueswir1511d2b12009-03-07 15:32:56 +0000179static char io_mem_used[IO_MEM_NB_ENTRIES];
pbrook6658ffb2007-03-16 23:58:11 +0000180static int io_mem_watch;
181#endif
bellard33417e72003-08-10 21:47:01 +0000182
bellard34865132003-10-05 14:28:56 +0000183/* log support */
blueswir1d9b630f2008-10-05 09:57:08 +0000184static const char *logfilename = "/tmp/qemu.log";
bellard34865132003-10-05 14:28:56 +0000185FILE *logfile;
186int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000187static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000188
bellarde3db7222005-01-26 22:00:47 +0000189/* statistics */
190static int tlb_flush_count;
191static int tb_flush_count;
192static int tb_phys_invalidate_count;
193
blueswir1db7b5422007-05-26 17:36:03 +0000194#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
195typedef struct subpage_t {
196 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000197 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
198 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
199 void *opaque[TARGET_PAGE_SIZE][2][4];
pbrook8da3ff12008-12-01 18:59:50 +0000200 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000201} subpage_t;
202
bellard7cb69ca2008-05-10 10:55:51 +0000203#ifdef _WIN32
204static void map_exec(void *addr, long size)
205{
206 DWORD old_protect;
207 VirtualProtect(addr, size,
208 PAGE_EXECUTE_READWRITE, &old_protect);
209
210}
211#else
212static void map_exec(void *addr, long size)
213{
bellard43694152008-05-29 09:35:57 +0000214 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000215
bellard43694152008-05-29 09:35:57 +0000216 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000217 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000218 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000219
220 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000221 end += page_size - 1;
222 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000223
224 mprotect((void *)start, end - start,
225 PROT_READ | PROT_WRITE | PROT_EXEC);
226}
227#endif
228
bellardb346ff42003-06-15 20:05:50 +0000229static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000230{
bellard83fb7ad2004-07-05 21:25:26 +0000231 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000232 TARGET_PAGE_SIZE */
aliguoric2b48b62008-11-11 22:06:42 +0000233#ifdef _WIN32
234 {
235 SYSTEM_INFO system_info;
236
237 GetSystemInfo(&system_info);
238 qemu_real_host_page_size = system_info.dwPageSize;
239 }
240#else
241 qemu_real_host_page_size = getpagesize();
242#endif
bellard83fb7ad2004-07-05 21:25:26 +0000243 if (qemu_host_page_size == 0)
244 qemu_host_page_size = qemu_real_host_page_size;
245 if (qemu_host_page_size < TARGET_PAGE_SIZE)
246 qemu_host_page_size = TARGET_PAGE_SIZE;
247 qemu_host_page_bits = 0;
248 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
249 qemu_host_page_bits++;
250 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000251 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
252 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000253
254#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
255 {
256 long long startaddr, endaddr;
257 FILE *f;
258 int n;
259
pbrookc8a706f2008-06-02 16:16:42 +0000260 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000261 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000262 f = fopen("/proc/self/maps", "r");
263 if (f) {
264 do {
265 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
266 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000267 startaddr = MIN(startaddr,
268 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
269 endaddr = MIN(endaddr,
270 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000271 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000272 TARGET_PAGE_ALIGN(endaddr),
273 PAGE_RESERVED);
274 }
275 } while (!feof(f));
276 fclose(f);
277 }
pbrookc8a706f2008-06-02 16:16:42 +0000278 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000279 }
280#endif
bellard54936002003-05-13 00:25:15 +0000281}
282
aliguori434929b2008-09-15 15:56:30 +0000283static inline PageDesc **page_l1_map(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000284{
pbrook17e23772008-06-09 13:47:45 +0000285#if TARGET_LONG_BITS > 32
286 /* Host memory outside guest VM. For 32-bit targets we have already
287 excluded high addresses. */
thsd8173e02008-08-29 13:10:00 +0000288 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
pbrook17e23772008-06-09 13:47:45 +0000289 return NULL;
290#endif
aliguori434929b2008-09-15 15:56:30 +0000291 return &l1_map[index >> L2_BITS];
292}
293
294static inline PageDesc *page_find_alloc(target_ulong index)
295{
296 PageDesc **lp, *p;
297 lp = page_l1_map(index);
298 if (!lp)
299 return NULL;
300
bellard54936002003-05-13 00:25:15 +0000301 p = *lp;
302 if (!p) {
303 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000304#if defined(CONFIG_USER_ONLY)
pbrook17e23772008-06-09 13:47:45 +0000305 size_t len = sizeof(PageDesc) * L2_SIZE;
306 /* Don't use qemu_malloc because it may recurse. */
307 p = mmap(0, len, PROT_READ | PROT_WRITE,
308 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000309 *lp = p;
aurel32fb1c2cd2008-12-08 18:12:26 +0000310 if (h2g_valid(p)) {
311 unsigned long addr = h2g(p);
pbrook17e23772008-06-09 13:47:45 +0000312 page_set_flags(addr & TARGET_PAGE_MASK,
313 TARGET_PAGE_ALIGN(addr + len),
314 PAGE_RESERVED);
315 }
316#else
317 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
318 *lp = p;
319#endif
bellard54936002003-05-13 00:25:15 +0000320 }
321 return p + (index & (L2_SIZE - 1));
322}
323
aurel3200f82b82008-04-27 21:12:55 +0000324static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000325{
aliguori434929b2008-09-15 15:56:30 +0000326 PageDesc **lp, *p;
327 lp = page_l1_map(index);
328 if (!lp)
329 return NULL;
bellard54936002003-05-13 00:25:15 +0000330
aliguori434929b2008-09-15 15:56:30 +0000331 p = *lp;
bellard54936002003-05-13 00:25:15 +0000332 if (!p)
333 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000334 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000335}
336
bellard108c49b2005-07-24 12:55:09 +0000337static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000338{
bellard108c49b2005-07-24 12:55:09 +0000339 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000340 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000341
bellard108c49b2005-07-24 12:55:09 +0000342 p = (void **)l1_phys_map;
343#if TARGET_PHYS_ADDR_SPACE_BITS > 32
344
345#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
346#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
347#endif
348 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000349 p = *lp;
350 if (!p) {
351 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000352 if (!alloc)
353 return NULL;
354 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
355 memset(p, 0, sizeof(void *) * L1_SIZE);
356 *lp = p;
357 }
358#endif
359 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000360 pd = *lp;
361 if (!pd) {
362 int i;
bellard108c49b2005-07-24 12:55:09 +0000363 /* allocate if not found */
364 if (!alloc)
365 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000366 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
367 *lp = pd;
pbrook67c4d232009-02-23 13:16:07 +0000368 for (i = 0; i < L2_SIZE; i++) {
pbrooke3f4e2a2006-04-08 20:02:06 +0000369 pd[i].phys_offset = IO_MEM_UNASSIGNED;
pbrook67c4d232009-02-23 13:16:07 +0000370 pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
371 }
bellard92e873b2004-05-21 14:52:29 +0000372 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000373 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000374}
375
bellard108c49b2005-07-24 12:55:09 +0000376static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000377{
bellard108c49b2005-07-24 12:55:09 +0000378 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000379}
380
bellard9fa3e852004-01-04 18:06:42 +0000381#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000382static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000383static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000384 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000385#define mmap_lock() do { } while(0)
386#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000387#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000388
bellard43694152008-05-29 09:35:57 +0000389#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
390
391#if defined(CONFIG_USER_ONLY)
392/* Currently it is not recommanded to allocate big chunks of data in
393 user mode. It will change when a dedicated libc will be used */
394#define USE_STATIC_CODE_GEN_BUFFER
395#endif
396
397#ifdef USE_STATIC_CODE_GEN_BUFFER
398static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
399#endif
400
blueswir18fcd3692008-08-17 20:26:25 +0000401static void code_gen_alloc(unsigned long tb_size)
bellard26a5f132008-05-28 12:30:31 +0000402{
bellard43694152008-05-29 09:35:57 +0000403#ifdef USE_STATIC_CODE_GEN_BUFFER
404 code_gen_buffer = static_code_gen_buffer;
405 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
406 map_exec(code_gen_buffer, code_gen_buffer_size);
407#else
bellard26a5f132008-05-28 12:30:31 +0000408 code_gen_buffer_size = tb_size;
409 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000410#if defined(CONFIG_USER_ONLY)
411 /* in user mode, phys_ram_size is not meaningful */
412 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
413#else
bellard26a5f132008-05-28 12:30:31 +0000414 /* XXX: needs ajustments */
aliguori174a9a12008-09-24 14:10:36 +0000415 code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000416#endif
bellard26a5f132008-05-28 12:30:31 +0000417 }
418 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
419 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
420 /* The code gen buffer location may have constraints depending on
421 the host cpu and OS */
422#if defined(__linux__)
423 {
424 int flags;
blueswir1141ac462008-07-26 15:05:57 +0000425 void *start = NULL;
426
bellard26a5f132008-05-28 12:30:31 +0000427 flags = MAP_PRIVATE | MAP_ANONYMOUS;
428#if defined(__x86_64__)
429 flags |= MAP_32BIT;
430 /* Cannot map more than that */
431 if (code_gen_buffer_size > (800 * 1024 * 1024))
432 code_gen_buffer_size = (800 * 1024 * 1024);
blueswir1141ac462008-07-26 15:05:57 +0000433#elif defined(__sparc_v9__)
434 // Map the buffer below 2G, so we can use direct calls and branches
435 flags |= MAP_FIXED;
436 start = (void *) 0x60000000UL;
437 if (code_gen_buffer_size > (512 * 1024 * 1024))
438 code_gen_buffer_size = (512 * 1024 * 1024);
balrog1cb06612008-12-01 02:10:17 +0000439#elif defined(__arm__)
balrog63d41242008-12-01 02:19:41 +0000440 /* Map the buffer below 32M, so we can use direct calls and branches */
balrog1cb06612008-12-01 02:10:17 +0000441 flags |= MAP_FIXED;
442 start = (void *) 0x01000000UL;
443 if (code_gen_buffer_size > 16 * 1024 * 1024)
444 code_gen_buffer_size = 16 * 1024 * 1024;
bellard26a5f132008-05-28 12:30:31 +0000445#endif
blueswir1141ac462008-07-26 15:05:57 +0000446 code_gen_buffer = mmap(start, code_gen_buffer_size,
447 PROT_WRITE | PROT_READ | PROT_EXEC,
bellard26a5f132008-05-28 12:30:31 +0000448 flags, -1, 0);
449 if (code_gen_buffer == MAP_FAILED) {
450 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
451 exit(1);
452 }
453 }
blueswir1c5e97232009-03-07 20:06:23 +0000454#elif defined(__FreeBSD__) || defined(__DragonFly__)
aliguori06e67a82008-09-27 15:32:41 +0000455 {
456 int flags;
457 void *addr = NULL;
458 flags = MAP_PRIVATE | MAP_ANONYMOUS;
459#if defined(__x86_64__)
460 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
461 * 0x40000000 is free */
462 flags |= MAP_FIXED;
463 addr = (void *)0x40000000;
464 /* Cannot map more than that */
465 if (code_gen_buffer_size > (800 * 1024 * 1024))
466 code_gen_buffer_size = (800 * 1024 * 1024);
467#endif
468 code_gen_buffer = mmap(addr, code_gen_buffer_size,
469 PROT_WRITE | PROT_READ | PROT_EXEC,
470 flags, -1, 0);
471 if (code_gen_buffer == MAP_FAILED) {
472 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
473 exit(1);
474 }
475 }
bellard26a5f132008-05-28 12:30:31 +0000476#else
477 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
bellard26a5f132008-05-28 12:30:31 +0000478 map_exec(code_gen_buffer, code_gen_buffer_size);
479#endif
bellard43694152008-05-29 09:35:57 +0000480#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000481 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
482 code_gen_buffer_max_size = code_gen_buffer_size -
483 code_gen_max_block_size();
484 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
485 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
486}
487
488/* Must be called before using the QEMU cpus. 'tb_size' is the size
489 (in bytes) allocated to the translation buffer. Zero means default
490 size. */
491void cpu_exec_init_all(unsigned long tb_size)
492{
bellard26a5f132008-05-28 12:30:31 +0000493 cpu_gen_init();
494 code_gen_alloc(tb_size);
495 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000496 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000497#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000498 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000499#endif
bellard26a5f132008-05-28 12:30:31 +0000500}
501
pbrook9656f322008-07-01 20:01:19 +0000502#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
503
504#define CPU_COMMON_SAVE_VERSION 1
505
506static void cpu_common_save(QEMUFile *f, void *opaque)
507{
508 CPUState *env = opaque;
509
510 qemu_put_be32s(f, &env->halted);
511 qemu_put_be32s(f, &env->interrupt_request);
512}
513
514static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
515{
516 CPUState *env = opaque;
517
518 if (version_id != CPU_COMMON_SAVE_VERSION)
519 return -EINVAL;
520
521 qemu_get_be32s(f, &env->halted);
pbrook75f482a2008-07-01 21:53:33 +0000522 qemu_get_be32s(f, &env->interrupt_request);
aurel323098dba2009-03-07 21:28:24 +0000523 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
524 version_id is increased. */
525 env->interrupt_request &= ~0x01;
pbrook9656f322008-07-01 20:01:19 +0000526 tlb_flush(env, 1);
527
528 return 0;
529}
530#endif
531
bellard6a00d602005-11-21 23:25:50 +0000532void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000533{
bellard6a00d602005-11-21 23:25:50 +0000534 CPUState **penv;
535 int cpu_index;
536
pbrookc2764712009-03-07 15:24:59 +0000537#if defined(CONFIG_USER_ONLY)
538 cpu_list_lock();
539#endif
bellard6a00d602005-11-21 23:25:50 +0000540 env->next_cpu = NULL;
541 penv = &first_cpu;
542 cpu_index = 0;
543 while (*penv != NULL) {
544 penv = (CPUState **)&(*penv)->next_cpu;
545 cpu_index++;
546 }
547 env->cpu_index = cpu_index;
aliguoric0ce9982008-11-25 22:13:57 +0000548 TAILQ_INIT(&env->breakpoints);
549 TAILQ_INIT(&env->watchpoints);
bellard6a00d602005-11-21 23:25:50 +0000550 *penv = env;
pbrookc2764712009-03-07 15:24:59 +0000551#if defined(CONFIG_USER_ONLY)
552 cpu_list_unlock();
553#endif
pbrookb3c77242008-06-30 16:31:04 +0000554#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
pbrook9656f322008-07-01 20:01:19 +0000555 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
556 cpu_common_save, cpu_common_load, env);
pbrookb3c77242008-06-30 16:31:04 +0000557 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
558 cpu_save, cpu_load, env);
559#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000560}
561
bellard9fa3e852004-01-04 18:06:42 +0000562static inline void invalidate_page_bitmap(PageDesc *p)
563{
564 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000565 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000566 p->code_bitmap = NULL;
567 }
568 p->code_write_count = 0;
569}
570
bellardfd6ce8f2003-05-14 19:00:11 +0000571/* set to NULL all the 'first_tb' fields in all PageDescs */
572static void page_flush_tb(void)
573{
574 int i, j;
575 PageDesc *p;
576
577 for(i = 0; i < L1_SIZE; i++) {
578 p = l1_map[i];
579 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000580 for(j = 0; j < L2_SIZE; j++) {
581 p->first_tb = NULL;
582 invalidate_page_bitmap(p);
583 p++;
584 }
bellardfd6ce8f2003-05-14 19:00:11 +0000585 }
586 }
587}
588
589/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000590/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000591void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000592{
bellard6a00d602005-11-21 23:25:50 +0000593 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000594#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000595 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
596 (unsigned long)(code_gen_ptr - code_gen_buffer),
597 nb_tbs, nb_tbs > 0 ?
598 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000599#endif
bellard26a5f132008-05-28 12:30:31 +0000600 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000601 cpu_abort(env1, "Internal error: code buffer overflow\n");
602
bellardfd6ce8f2003-05-14 19:00:11 +0000603 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000604
bellard6a00d602005-11-21 23:25:50 +0000605 for(env = first_cpu; env != NULL; env = env->next_cpu) {
606 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
607 }
bellard9fa3e852004-01-04 18:06:42 +0000608
bellard8a8a6082004-10-03 13:36:49 +0000609 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000610 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000611
bellardfd6ce8f2003-05-14 19:00:11 +0000612 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000613 /* XXX: flush processor icache at this point if cache flush is
614 expensive */
bellarde3db7222005-01-26 22:00:47 +0000615 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000616}
617
618#ifdef DEBUG_TB_CHECK
619
j_mayerbc98a7e2007-04-04 07:55:12 +0000620static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000621{
622 TranslationBlock *tb;
623 int i;
624 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000625 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
626 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000627 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
628 address >= tb->pc + tb->size)) {
629 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000630 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000631 }
632 }
633 }
634}
635
636/* verify that all the pages have correct rights for code */
637static void tb_page_check(void)
638{
639 TranslationBlock *tb;
640 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000641
pbrook99773bd2006-04-16 15:14:59 +0000642 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
643 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000644 flags1 = page_get_flags(tb->pc);
645 flags2 = page_get_flags(tb->pc + tb->size - 1);
646 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
647 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000648 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000649 }
650 }
651 }
652}
653
blueswir1bdaf78e2008-10-04 07:24:27 +0000654static void tb_jmp_check(TranslationBlock *tb)
bellardd4e81642003-05-25 16:46:15 +0000655{
656 TranslationBlock *tb1;
657 unsigned int n1;
658
659 /* suppress any remaining jumps to this TB */
660 tb1 = tb->jmp_first;
661 for(;;) {
662 n1 = (long)tb1 & 3;
663 tb1 = (TranslationBlock *)((long)tb1 & ~3);
664 if (n1 == 2)
665 break;
666 tb1 = tb1->jmp_next[n1];
667 }
668 /* check end of list */
669 if (tb1 != tb) {
670 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
671 }
672}
673
bellardfd6ce8f2003-05-14 19:00:11 +0000674#endif
675
676/* invalidate one TB */
677static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
678 int next_offset)
679{
680 TranslationBlock *tb1;
681 for(;;) {
682 tb1 = *ptb;
683 if (tb1 == tb) {
684 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
685 break;
686 }
687 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
688 }
689}
690
bellard9fa3e852004-01-04 18:06:42 +0000691static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
692{
693 TranslationBlock *tb1;
694 unsigned int n1;
695
696 for(;;) {
697 tb1 = *ptb;
698 n1 = (long)tb1 & 3;
699 tb1 = (TranslationBlock *)((long)tb1 & ~3);
700 if (tb1 == tb) {
701 *ptb = tb1->page_next[n1];
702 break;
703 }
704 ptb = &tb1->page_next[n1];
705 }
706}
707
bellardd4e81642003-05-25 16:46:15 +0000708static inline void tb_jmp_remove(TranslationBlock *tb, int n)
709{
710 TranslationBlock *tb1, **ptb;
711 unsigned int n1;
712
713 ptb = &tb->jmp_next[n];
714 tb1 = *ptb;
715 if (tb1) {
716 /* find tb(n) in circular list */
717 for(;;) {
718 tb1 = *ptb;
719 n1 = (long)tb1 & 3;
720 tb1 = (TranslationBlock *)((long)tb1 & ~3);
721 if (n1 == n && tb1 == tb)
722 break;
723 if (n1 == 2) {
724 ptb = &tb1->jmp_first;
725 } else {
726 ptb = &tb1->jmp_next[n1];
727 }
728 }
729 /* now we can suppress tb(n) from the list */
730 *ptb = tb->jmp_next[n];
731
732 tb->jmp_next[n] = NULL;
733 }
734}
735
736/* reset the jump entry 'n' of a TB so that it is not chained to
737 another TB */
738static inline void tb_reset_jump(TranslationBlock *tb, int n)
739{
740 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
741}
742
pbrook2e70f6e2008-06-29 01:03:05 +0000743void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000744{
bellard6a00d602005-11-21 23:25:50 +0000745 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000746 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000747 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000748 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000749 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000750
bellard9fa3e852004-01-04 18:06:42 +0000751 /* remove the TB from the hash list */
752 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
753 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000754 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000755 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000756
bellard9fa3e852004-01-04 18:06:42 +0000757 /* remove the TB from the page list */
758 if (tb->page_addr[0] != page_addr) {
759 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
760 tb_page_remove(&p->first_tb, tb);
761 invalidate_page_bitmap(p);
762 }
763 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
764 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
765 tb_page_remove(&p->first_tb, tb);
766 invalidate_page_bitmap(p);
767 }
768
bellard8a40a182005-11-20 10:35:40 +0000769 tb_invalidated_flag = 1;
770
771 /* remove the TB from the hash list */
772 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000773 for(env = first_cpu; env != NULL; env = env->next_cpu) {
774 if (env->tb_jmp_cache[h] == tb)
775 env->tb_jmp_cache[h] = NULL;
776 }
bellard8a40a182005-11-20 10:35:40 +0000777
778 /* suppress this TB from the two jump lists */
779 tb_jmp_remove(tb, 0);
780 tb_jmp_remove(tb, 1);
781
782 /* suppress any remaining jumps to this TB */
783 tb1 = tb->jmp_first;
784 for(;;) {
785 n1 = (long)tb1 & 3;
786 if (n1 == 2)
787 break;
788 tb1 = (TranslationBlock *)((long)tb1 & ~3);
789 tb2 = tb1->jmp_next[n1];
790 tb_reset_jump(tb1, n1);
791 tb1->jmp_next[n1] = NULL;
792 tb1 = tb2;
793 }
794 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
795
bellarde3db7222005-01-26 22:00:47 +0000796 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000797}
798
799static inline void set_bits(uint8_t *tab, int start, int len)
800{
801 int end, mask, end1;
802
803 end = start + len;
804 tab += start >> 3;
805 mask = 0xff << (start & 7);
806 if ((start & ~7) == (end & ~7)) {
807 if (start < end) {
808 mask &= ~(0xff << (end & 7));
809 *tab |= mask;
810 }
811 } else {
812 *tab++ |= mask;
813 start = (start + 8) & ~7;
814 end1 = end & ~7;
815 while (start < end1) {
816 *tab++ = 0xff;
817 start += 8;
818 }
819 if (start < end) {
820 mask = ~(0xff << (end & 7));
821 *tab |= mask;
822 }
823 }
824}
825
826static void build_page_bitmap(PageDesc *p)
827{
828 int n, tb_start, tb_end;
829 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000830
pbrookb2a70812008-06-09 13:57:23 +0000831 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000832
833 tb = p->first_tb;
834 while (tb != NULL) {
835 n = (long)tb & 3;
836 tb = (TranslationBlock *)((long)tb & ~3);
837 /* NOTE: this is subtle as a TB may span two physical pages */
838 if (n == 0) {
839 /* NOTE: tb_end may be after the end of the page, but
840 it is not a problem */
841 tb_start = tb->pc & ~TARGET_PAGE_MASK;
842 tb_end = tb_start + tb->size;
843 if (tb_end > TARGET_PAGE_SIZE)
844 tb_end = TARGET_PAGE_SIZE;
845 } else {
846 tb_start = 0;
847 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
848 }
849 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
850 tb = tb->page_next[n];
851 }
852}
853
pbrook2e70f6e2008-06-29 01:03:05 +0000854TranslationBlock *tb_gen_code(CPUState *env,
855 target_ulong pc, target_ulong cs_base,
856 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000857{
858 TranslationBlock *tb;
859 uint8_t *tc_ptr;
860 target_ulong phys_pc, phys_page2, virt_page2;
861 int code_gen_size;
862
bellardc27004e2005-01-03 23:35:10 +0000863 phys_pc = get_phys_addr_code(env, pc);
864 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000865 if (!tb) {
866 /* flush must be done */
867 tb_flush(env);
868 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000869 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000870 /* Don't forget to invalidate previous TB info. */
871 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000872 }
873 tc_ptr = code_gen_ptr;
874 tb->tc_ptr = tc_ptr;
875 tb->cs_base = cs_base;
876 tb->flags = flags;
877 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000878 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000879 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 +0000880
bellardd720b932004-04-25 17:57:43 +0000881 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000882 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000883 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000884 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000885 phys_page2 = get_phys_addr_code(env, virt_page2);
886 }
887 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000888 return tb;
bellardd720b932004-04-25 17:57:43 +0000889}
ths3b46e622007-09-17 08:09:54 +0000890
bellard9fa3e852004-01-04 18:06:42 +0000891/* invalidate all TBs which intersect with the target physical page
892 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000893 the same physical page. 'is_cpu_write_access' should be true if called
894 from a real cpu write access: the virtual CPU will exit the current
895 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000896void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000897 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000898{
aliguori6b917542008-11-18 19:46:41 +0000899 TranslationBlock *tb, *tb_next, *saved_tb;
bellardd720b932004-04-25 17:57:43 +0000900 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000901 target_ulong tb_start, tb_end;
aliguori6b917542008-11-18 19:46:41 +0000902 PageDesc *p;
903 int n;
904#ifdef TARGET_HAS_PRECISE_SMC
905 int current_tb_not_found = is_cpu_write_access;
906 TranslationBlock *current_tb = NULL;
907 int current_tb_modified = 0;
908 target_ulong current_pc = 0;
909 target_ulong current_cs_base = 0;
910 int current_flags = 0;
911#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000912
913 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000914 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000915 return;
ths5fafdf22007-09-16 21:08:06 +0000916 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000917 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
918 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000919 /* build code bitmap */
920 build_page_bitmap(p);
921 }
922
923 /* we remove all the TBs in the range [start, end[ */
924 /* XXX: see if in some cases it could be faster to invalidate all the code */
925 tb = p->first_tb;
926 while (tb != NULL) {
927 n = (long)tb & 3;
928 tb = (TranslationBlock *)((long)tb & ~3);
929 tb_next = tb->page_next[n];
930 /* NOTE: this is subtle as a TB may span two physical pages */
931 if (n == 0) {
932 /* NOTE: tb_end may be after the end of the page, but
933 it is not a problem */
934 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
935 tb_end = tb_start + tb->size;
936 } else {
937 tb_start = tb->page_addr[1];
938 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
939 }
940 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000941#ifdef TARGET_HAS_PRECISE_SMC
942 if (current_tb_not_found) {
943 current_tb_not_found = 0;
944 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000945 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000946 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000947 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000948 }
949 }
950 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000951 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000952 /* If we are modifying the current TB, we must stop
953 its execution. We could be more precise by checking
954 that the modification is after the current PC, but it
955 would require a specialized function to partially
956 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000957
bellardd720b932004-04-25 17:57:43 +0000958 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000959 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000960 env->mem_io_pc, NULL);
aliguori6b917542008-11-18 19:46:41 +0000961 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
962 &current_flags);
bellardd720b932004-04-25 17:57:43 +0000963 }
964#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000965 /* we need to do that to handle the case where a signal
966 occurs while doing tb_phys_invalidate() */
967 saved_tb = NULL;
968 if (env) {
969 saved_tb = env->current_tb;
970 env->current_tb = NULL;
971 }
bellard9fa3e852004-01-04 18:06:42 +0000972 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000973 if (env) {
974 env->current_tb = saved_tb;
975 if (env->interrupt_request && env->current_tb)
976 cpu_interrupt(env, env->interrupt_request);
977 }
bellard9fa3e852004-01-04 18:06:42 +0000978 }
979 tb = tb_next;
980 }
981#if !defined(CONFIG_USER_ONLY)
982 /* if no code remaining, no need to continue to use slow writes */
983 if (!p->first_tb) {
984 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000985 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000986 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000987 }
988 }
989#endif
990#ifdef TARGET_HAS_PRECISE_SMC
991 if (current_tb_modified) {
992 /* we generate a block containing just the instruction
993 modifying the memory. It will ensure that it cannot modify
994 itself */
bellardea1c1802004-06-14 18:56:36 +0000995 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000996 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000997 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000998 }
999#endif
1000}
1001
1002/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +00001003static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +00001004{
1005 PageDesc *p;
1006 int offset, b;
bellard59817cc2004-02-16 22:01:13 +00001007#if 0
bellarda4193c82004-06-03 14:01:43 +00001008 if (1) {
aliguori93fcfe32009-01-15 22:34:14 +00001009 qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
1010 cpu_single_env->mem_io_vaddr, len,
1011 cpu_single_env->eip,
1012 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
bellard59817cc2004-02-16 22:01:13 +00001013 }
1014#endif
bellard9fa3e852004-01-04 18:06:42 +00001015 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001016 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001017 return;
1018 if (p->code_bitmap) {
1019 offset = start & ~TARGET_PAGE_MASK;
1020 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1021 if (b & ((1 << len) - 1))
1022 goto do_invalidate;
1023 } else {
1024 do_invalidate:
bellardd720b932004-04-25 17:57:43 +00001025 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +00001026 }
1027}
1028
bellard9fa3e852004-01-04 18:06:42 +00001029#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +00001030static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +00001031 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001032{
aliguori6b917542008-11-18 19:46:41 +00001033 TranslationBlock *tb;
bellard9fa3e852004-01-04 18:06:42 +00001034 PageDesc *p;
aliguori6b917542008-11-18 19:46:41 +00001035 int n;
bellardd720b932004-04-25 17:57:43 +00001036#ifdef TARGET_HAS_PRECISE_SMC
aliguori6b917542008-11-18 19:46:41 +00001037 TranslationBlock *current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001038 CPUState *env = cpu_single_env;
aliguori6b917542008-11-18 19:46:41 +00001039 int current_tb_modified = 0;
1040 target_ulong current_pc = 0;
1041 target_ulong current_cs_base = 0;
1042 int current_flags = 0;
bellardd720b932004-04-25 17:57:43 +00001043#endif
bellard9fa3e852004-01-04 18:06:42 +00001044
1045 addr &= TARGET_PAGE_MASK;
1046 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001047 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +00001048 return;
1049 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +00001050#ifdef TARGET_HAS_PRECISE_SMC
1051 if (tb && pc != 0) {
1052 current_tb = tb_find_pc(pc);
1053 }
1054#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001055 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +00001056 n = (long)tb & 3;
1057 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +00001058#ifdef TARGET_HAS_PRECISE_SMC
1059 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +00001060 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +00001061 /* If we are modifying the current TB, we must stop
1062 its execution. We could be more precise by checking
1063 that the modification is after the current PC, but it
1064 would require a specialized function to partially
1065 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +00001066
bellardd720b932004-04-25 17:57:43 +00001067 current_tb_modified = 1;
1068 cpu_restore_state(current_tb, env, pc, puc);
aliguori6b917542008-11-18 19:46:41 +00001069 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1070 &current_flags);
bellardd720b932004-04-25 17:57:43 +00001071 }
1072#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +00001073 tb_phys_invalidate(tb, addr);
1074 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +00001075 }
1076 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001077#ifdef TARGET_HAS_PRECISE_SMC
1078 if (current_tb_modified) {
1079 /* we generate a block containing just the instruction
1080 modifying the memory. It will ensure that it cannot modify
1081 itself */
bellardea1c1802004-06-14 18:56:36 +00001082 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001083 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001084 cpu_resume_from_signal(env, puc);
1085 }
1086#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001087}
bellard9fa3e852004-01-04 18:06:42 +00001088#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001089
1090/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001091static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001092 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001093{
1094 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001095 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001096
bellard9fa3e852004-01-04 18:06:42 +00001097 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001098 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001099 tb->page_next[n] = p->first_tb;
1100 last_first_tb = p->first_tb;
1101 p->first_tb = (TranslationBlock *)((long)tb | n);
1102 invalidate_page_bitmap(p);
1103
bellard107db442004-06-22 18:48:46 +00001104#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001105
bellard9fa3e852004-01-04 18:06:42 +00001106#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001107 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001108 target_ulong addr;
1109 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001110 int prot;
1111
bellardfd6ce8f2003-05-14 19:00:11 +00001112 /* force the host page as non writable (writes will have a
1113 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001114 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001115 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001116 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1117 addr += TARGET_PAGE_SIZE) {
1118
1119 p2 = page_find (addr >> TARGET_PAGE_BITS);
1120 if (!p2)
1121 continue;
1122 prot |= p2->flags;
1123 p2->flags &= ~PAGE_WRITE;
1124 page_get_flags(addr);
1125 }
ths5fafdf22007-09-16 21:08:06 +00001126 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001127 (prot & PAGE_BITS) & ~PAGE_WRITE);
1128#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001129 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001130 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001131#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001132 }
bellard9fa3e852004-01-04 18:06:42 +00001133#else
1134 /* if some code is already present, then the pages are already
1135 protected. So we handle the case where only the first TB is
1136 allocated in a physical page */
1137 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001138 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001139 }
1140#endif
bellardd720b932004-04-25 17:57:43 +00001141
1142#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001143}
1144
1145/* Allocate a new translation block. Flush the translation buffer if
1146 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001147TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001148{
1149 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001150
bellard26a5f132008-05-28 12:30:31 +00001151 if (nb_tbs >= code_gen_max_blocks ||
1152 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001153 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001154 tb = &tbs[nb_tbs++];
1155 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001156 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001157 return tb;
1158}
1159
pbrook2e70f6e2008-06-29 01:03:05 +00001160void tb_free(TranslationBlock *tb)
1161{
thsbf20dc02008-06-30 17:22:19 +00001162 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001163 Ignore the hard cases and just back up if this TB happens to
1164 be the last one generated. */
1165 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1166 code_gen_ptr = tb->tc_ptr;
1167 nb_tbs--;
1168 }
1169}
1170
bellard9fa3e852004-01-04 18:06:42 +00001171/* add a new TB and link it to the physical page tables. phys_page2 is
1172 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001173void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001174 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001175{
bellard9fa3e852004-01-04 18:06:42 +00001176 unsigned int h;
1177 TranslationBlock **ptb;
1178
pbrookc8a706f2008-06-02 16:16:42 +00001179 /* Grab the mmap lock to stop another thread invalidating this TB
1180 before we are done. */
1181 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001182 /* add in the physical hash table */
1183 h = tb_phys_hash_func(phys_pc);
1184 ptb = &tb_phys_hash[h];
1185 tb->phys_hash_next = *ptb;
1186 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001187
1188 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001189 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1190 if (phys_page2 != -1)
1191 tb_alloc_page(tb, 1, phys_page2);
1192 else
1193 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001194
bellardd4e81642003-05-25 16:46:15 +00001195 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1196 tb->jmp_next[0] = NULL;
1197 tb->jmp_next[1] = NULL;
1198
1199 /* init original jump addresses */
1200 if (tb->tb_next_offset[0] != 0xffff)
1201 tb_reset_jump(tb, 0);
1202 if (tb->tb_next_offset[1] != 0xffff)
1203 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001204
1205#ifdef DEBUG_TB_CHECK
1206 tb_page_check();
1207#endif
pbrookc8a706f2008-06-02 16:16:42 +00001208 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001209}
1210
bellarda513fe12003-05-27 23:29:48 +00001211/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1212 tb[1].tc_ptr. Return NULL if not found */
1213TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1214{
1215 int m_min, m_max, m;
1216 unsigned long v;
1217 TranslationBlock *tb;
1218
1219 if (nb_tbs <= 0)
1220 return NULL;
1221 if (tc_ptr < (unsigned long)code_gen_buffer ||
1222 tc_ptr >= (unsigned long)code_gen_ptr)
1223 return NULL;
1224 /* binary search (cf Knuth) */
1225 m_min = 0;
1226 m_max = nb_tbs - 1;
1227 while (m_min <= m_max) {
1228 m = (m_min + m_max) >> 1;
1229 tb = &tbs[m];
1230 v = (unsigned long)tb->tc_ptr;
1231 if (v == tc_ptr)
1232 return tb;
1233 else if (tc_ptr < v) {
1234 m_max = m - 1;
1235 } else {
1236 m_min = m + 1;
1237 }
ths5fafdf22007-09-16 21:08:06 +00001238 }
bellarda513fe12003-05-27 23:29:48 +00001239 return &tbs[m_max];
1240}
bellard75012672003-06-21 13:11:07 +00001241
bellardea041c02003-06-25 16:16:50 +00001242static void tb_reset_jump_recursive(TranslationBlock *tb);
1243
1244static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1245{
1246 TranslationBlock *tb1, *tb_next, **ptb;
1247 unsigned int n1;
1248
1249 tb1 = tb->jmp_next[n];
1250 if (tb1 != NULL) {
1251 /* find head of list */
1252 for(;;) {
1253 n1 = (long)tb1 & 3;
1254 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1255 if (n1 == 2)
1256 break;
1257 tb1 = tb1->jmp_next[n1];
1258 }
1259 /* we are now sure now that tb jumps to tb1 */
1260 tb_next = tb1;
1261
1262 /* remove tb from the jmp_first list */
1263 ptb = &tb_next->jmp_first;
1264 for(;;) {
1265 tb1 = *ptb;
1266 n1 = (long)tb1 & 3;
1267 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1268 if (n1 == n && tb1 == tb)
1269 break;
1270 ptb = &tb1->jmp_next[n1];
1271 }
1272 *ptb = tb->jmp_next[n];
1273 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001274
bellardea041c02003-06-25 16:16:50 +00001275 /* suppress the jump to next tb in generated code */
1276 tb_reset_jump(tb, n);
1277
bellard01243112004-01-04 15:48:17 +00001278 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001279 tb_reset_jump_recursive(tb_next);
1280 }
1281}
1282
1283static void tb_reset_jump_recursive(TranslationBlock *tb)
1284{
1285 tb_reset_jump_recursive2(tb, 0);
1286 tb_reset_jump_recursive2(tb, 1);
1287}
1288
bellard1fddef42005-04-17 19:16:13 +00001289#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001290static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1291{
j_mayer9b3c35e2007-04-07 11:21:28 +00001292 target_phys_addr_t addr;
1293 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001294 ram_addr_t ram_addr;
1295 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001296
pbrookc2f07f82006-04-08 17:14:56 +00001297 addr = cpu_get_phys_page_debug(env, pc);
1298 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1299 if (!p) {
1300 pd = IO_MEM_UNASSIGNED;
1301 } else {
1302 pd = p->phys_offset;
1303 }
1304 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001305 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001306}
bellardc27004e2005-01-03 23:35:10 +00001307#endif
bellardd720b932004-04-25 17:57:43 +00001308
pbrook6658ffb2007-03-16 23:58:11 +00001309/* Add a watchpoint. */
aliguoria1d1bb32008-11-18 20:07:32 +00001310int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
1311 int flags, CPUWatchpoint **watchpoint)
pbrook6658ffb2007-03-16 23:58:11 +00001312{
aliguorib4051332008-11-18 20:14:20 +00001313 target_ulong len_mask = ~(len - 1);
aliguoric0ce9982008-11-25 22:13:57 +00001314 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001315
aliguorib4051332008-11-18 20:14:20 +00001316 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1317 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1318 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1319 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1320 return -EINVAL;
1321 }
aliguoria1d1bb32008-11-18 20:07:32 +00001322 wp = qemu_malloc(sizeof(*wp));
pbrook6658ffb2007-03-16 23:58:11 +00001323
aliguoria1d1bb32008-11-18 20:07:32 +00001324 wp->vaddr = addr;
aliguorib4051332008-11-18 20:14:20 +00001325 wp->len_mask = len_mask;
aliguoria1d1bb32008-11-18 20:07:32 +00001326 wp->flags = flags;
1327
aliguori2dc9f412008-11-18 20:56:59 +00001328 /* keep all GDB-injected watchpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001329 if (flags & BP_GDB)
1330 TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
1331 else
1332 TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001333
pbrook6658ffb2007-03-16 23:58:11 +00001334 tlb_flush_page(env, addr);
aliguoria1d1bb32008-11-18 20:07:32 +00001335
1336 if (watchpoint)
1337 *watchpoint = wp;
1338 return 0;
pbrook6658ffb2007-03-16 23:58:11 +00001339}
1340
aliguoria1d1bb32008-11-18 20:07:32 +00001341/* Remove a specific watchpoint. */
1342int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
1343 int flags)
pbrook6658ffb2007-03-16 23:58:11 +00001344{
aliguorib4051332008-11-18 20:14:20 +00001345 target_ulong len_mask = ~(len - 1);
aliguoria1d1bb32008-11-18 20:07:32 +00001346 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001347
aliguoric0ce9982008-11-25 22:13:57 +00001348 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00001349 if (addr == wp->vaddr && len_mask == wp->len_mask
aliguori6e140f22008-11-18 20:37:55 +00001350 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
aliguoria1d1bb32008-11-18 20:07:32 +00001351 cpu_watchpoint_remove_by_ref(env, wp);
pbrook6658ffb2007-03-16 23:58:11 +00001352 return 0;
1353 }
1354 }
aliguoria1d1bb32008-11-18 20:07:32 +00001355 return -ENOENT;
pbrook6658ffb2007-03-16 23:58:11 +00001356}
1357
aliguoria1d1bb32008-11-18 20:07:32 +00001358/* Remove a specific watchpoint by reference. */
1359void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
1360{
aliguoric0ce9982008-11-25 22:13:57 +00001361 TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
edgar_igl7d03f822008-05-17 18:58:29 +00001362
aliguoria1d1bb32008-11-18 20:07:32 +00001363 tlb_flush_page(env, watchpoint->vaddr);
1364
1365 qemu_free(watchpoint);
edgar_igl7d03f822008-05-17 18:58:29 +00001366}
1367
aliguoria1d1bb32008-11-18 20:07:32 +00001368/* Remove all matching watchpoints. */
1369void cpu_watchpoint_remove_all(CPUState *env, int mask)
1370{
aliguoric0ce9982008-11-25 22:13:57 +00001371 CPUWatchpoint *wp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001372
aliguoric0ce9982008-11-25 22:13:57 +00001373 TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001374 if (wp->flags & mask)
1375 cpu_watchpoint_remove_by_ref(env, wp);
aliguoric0ce9982008-11-25 22:13:57 +00001376 }
aliguoria1d1bb32008-11-18 20:07:32 +00001377}
1378
1379/* Add a breakpoint. */
1380int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
1381 CPUBreakpoint **breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001382{
bellard1fddef42005-04-17 19:16:13 +00001383#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001384 CPUBreakpoint *bp;
ths3b46e622007-09-17 08:09:54 +00001385
aliguoria1d1bb32008-11-18 20:07:32 +00001386 bp = qemu_malloc(sizeof(*bp));
aliguoria1d1bb32008-11-18 20:07:32 +00001387
1388 bp->pc = pc;
1389 bp->flags = flags;
1390
aliguori2dc9f412008-11-18 20:56:59 +00001391 /* keep all GDB-injected breakpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001392 if (flags & BP_GDB)
1393 TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
1394 else
1395 TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001396
1397 breakpoint_invalidate(env, pc);
1398
1399 if (breakpoint)
1400 *breakpoint = bp;
1401 return 0;
1402#else
1403 return -ENOSYS;
1404#endif
1405}
1406
1407/* Remove a specific breakpoint. */
1408int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
1409{
1410#if defined(TARGET_HAS_ICE)
1411 CPUBreakpoint *bp;
1412
aliguoric0ce9982008-11-25 22:13:57 +00001413 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001414 if (bp->pc == pc && bp->flags == flags) {
1415 cpu_breakpoint_remove_by_ref(env, bp);
bellard4c3a88a2003-07-26 12:06:08 +00001416 return 0;
aliguoria1d1bb32008-11-18 20:07:32 +00001417 }
bellard4c3a88a2003-07-26 12:06:08 +00001418 }
aliguoria1d1bb32008-11-18 20:07:32 +00001419 return -ENOENT;
bellard4c3a88a2003-07-26 12:06:08 +00001420#else
aliguoria1d1bb32008-11-18 20:07:32 +00001421 return -ENOSYS;
bellard4c3a88a2003-07-26 12:06:08 +00001422#endif
1423}
1424
aliguoria1d1bb32008-11-18 20:07:32 +00001425/* Remove a specific breakpoint by reference. */
1426void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001427{
bellard1fddef42005-04-17 19:16:13 +00001428#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001429 TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
bellardd720b932004-04-25 17:57:43 +00001430
aliguoria1d1bb32008-11-18 20:07:32 +00001431 breakpoint_invalidate(env, breakpoint->pc);
1432
1433 qemu_free(breakpoint);
1434#endif
1435}
1436
1437/* Remove all matching breakpoints. */
1438void cpu_breakpoint_remove_all(CPUState *env, int mask)
1439{
1440#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001441 CPUBreakpoint *bp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001442
aliguoric0ce9982008-11-25 22:13:57 +00001443 TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001444 if (bp->flags & mask)
1445 cpu_breakpoint_remove_by_ref(env, bp);
aliguoric0ce9982008-11-25 22:13:57 +00001446 }
bellard4c3a88a2003-07-26 12:06:08 +00001447#endif
1448}
1449
bellardc33a3462003-07-29 20:50:33 +00001450/* enable or disable single step mode. EXCP_DEBUG is returned by the
1451 CPU loop after each instruction */
1452void cpu_single_step(CPUState *env, int enabled)
1453{
bellard1fddef42005-04-17 19:16:13 +00001454#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001455 if (env->singlestep_enabled != enabled) {
1456 env->singlestep_enabled = enabled;
aliguorie22a25c2009-03-12 20:12:48 +00001457 if (kvm_enabled())
1458 kvm_update_guest_debug(env, 0);
1459 else {
1460 /* must flush all the translated code to avoid inconsistancies */
1461 /* XXX: only flush what is necessary */
1462 tb_flush(env);
1463 }
bellardc33a3462003-07-29 20:50:33 +00001464 }
1465#endif
1466}
1467
bellard34865132003-10-05 14:28:56 +00001468/* enable or disable low levels log */
1469void cpu_set_log(int log_flags)
1470{
1471 loglevel = log_flags;
1472 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001473 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001474 if (!logfile) {
1475 perror(logfilename);
1476 _exit(1);
1477 }
bellard9fa3e852004-01-04 18:06:42 +00001478#if !defined(CONFIG_SOFTMMU)
1479 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1480 {
blueswir1b55266b2008-09-20 08:07:15 +00001481 static char logfile_buf[4096];
bellard9fa3e852004-01-04 18:06:42 +00001482 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1483 }
1484#else
bellard34865132003-10-05 14:28:56 +00001485 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001486#endif
pbrooke735b912007-06-30 13:53:24 +00001487 log_append = 1;
1488 }
1489 if (!loglevel && logfile) {
1490 fclose(logfile);
1491 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001492 }
1493}
1494
1495void cpu_set_log_filename(const char *filename)
1496{
1497 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001498 if (logfile) {
1499 fclose(logfile);
1500 logfile = NULL;
1501 }
1502 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001503}
bellardc33a3462003-07-29 20:50:33 +00001504
aurel323098dba2009-03-07 21:28:24 +00001505static void cpu_unlink_tb(CPUState *env)
bellardea041c02003-06-25 16:16:50 +00001506{
pbrookd5975362008-06-07 20:50:51 +00001507#if defined(USE_NPTL)
1508 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1509 problem and hope the cpu will stop of its own accord. For userspace
1510 emulation this often isn't actually as bad as it sounds. Often
1511 signals are used primarily to interrupt blocking syscalls. */
1512#else
aurel323098dba2009-03-07 21:28:24 +00001513 TranslationBlock *tb;
1514 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
1515
1516 tb = env->current_tb;
1517 /* if the cpu is currently executing code, we must unlink it and
1518 all the potentially executing TB */
1519 if (tb && !testandset(&interrupt_lock)) {
1520 env->current_tb = NULL;
1521 tb_reset_jump_recursive(tb);
1522 resetlock(&interrupt_lock);
1523 }
1524#endif
1525}
1526
1527/* mask must never be zero, except for A20 change call */
1528void cpu_interrupt(CPUState *env, int mask)
1529{
1530 int old_mask;
1531
1532 old_mask = env->interrupt_request;
1533 env->interrupt_request |= mask;
1534
pbrook2e70f6e2008-06-29 01:03:05 +00001535 if (use_icount) {
pbrook266910c2008-07-09 15:31:50 +00001536 env->icount_decr.u16.high = 0xffff;
pbrook2e70f6e2008-06-29 01:03:05 +00001537#ifndef CONFIG_USER_ONLY
pbrook2e70f6e2008-06-29 01:03:05 +00001538 if (!can_do_io(env)
aurel32be214e62009-03-06 21:48:00 +00001539 && (mask & ~old_mask) != 0) {
pbrook2e70f6e2008-06-29 01:03:05 +00001540 cpu_abort(env, "Raised interrupt while not in I/O function");
1541 }
1542#endif
1543 } else {
aurel323098dba2009-03-07 21:28:24 +00001544 cpu_unlink_tb(env);
bellardea041c02003-06-25 16:16:50 +00001545 }
1546}
1547
bellardb54ad042004-05-20 13:42:52 +00001548void cpu_reset_interrupt(CPUState *env, int mask)
1549{
1550 env->interrupt_request &= ~mask;
1551}
1552
aurel323098dba2009-03-07 21:28:24 +00001553void cpu_exit(CPUState *env)
1554{
1555 env->exit_request = 1;
1556 cpu_unlink_tb(env);
1557}
1558
blueswir1c7cd6a32008-10-02 18:27:46 +00001559const CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001560 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001561 "show generated host assembly code for each compiled TB" },
1562 { CPU_LOG_TB_IN_ASM, "in_asm",
1563 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001564 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001565 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001566 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001567 "show micro ops "
1568#ifdef TARGET_I386
1569 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001570#endif
blueswir1e01a1152008-03-14 17:37:11 +00001571 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001572 { CPU_LOG_INT, "int",
1573 "show interrupts/exceptions in short format" },
1574 { CPU_LOG_EXEC, "exec",
1575 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001576 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001577 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001578#ifdef TARGET_I386
1579 { CPU_LOG_PCALL, "pcall",
1580 "show protected mode far calls/returns/exceptions" },
aliguorieca1bdf2009-01-26 19:54:31 +00001581 { CPU_LOG_RESET, "cpu_reset",
1582 "show CPU state before CPU resets" },
bellardf193c792004-03-21 17:06:25 +00001583#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001584#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001585 { CPU_LOG_IOPORT, "ioport",
1586 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001587#endif
bellardf193c792004-03-21 17:06:25 +00001588 { 0, NULL, NULL },
1589};
1590
1591static int cmp1(const char *s1, int n, const char *s2)
1592{
1593 if (strlen(s2) != n)
1594 return 0;
1595 return memcmp(s1, s2, n) == 0;
1596}
ths3b46e622007-09-17 08:09:54 +00001597
bellardf193c792004-03-21 17:06:25 +00001598/* takes a comma separated list of log masks. Return 0 if error. */
1599int cpu_str_to_log_mask(const char *str)
1600{
blueswir1c7cd6a32008-10-02 18:27:46 +00001601 const CPULogItem *item;
bellardf193c792004-03-21 17:06:25 +00001602 int mask;
1603 const char *p, *p1;
1604
1605 p = str;
1606 mask = 0;
1607 for(;;) {
1608 p1 = strchr(p, ',');
1609 if (!p1)
1610 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001611 if(cmp1(p,p1-p,"all")) {
1612 for(item = cpu_log_items; item->mask != 0; item++) {
1613 mask |= item->mask;
1614 }
1615 } else {
bellardf193c792004-03-21 17:06:25 +00001616 for(item = cpu_log_items; item->mask != 0; item++) {
1617 if (cmp1(p, p1 - p, item->name))
1618 goto found;
1619 }
1620 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001621 }
bellardf193c792004-03-21 17:06:25 +00001622 found:
1623 mask |= item->mask;
1624 if (*p1 != ',')
1625 break;
1626 p = p1 + 1;
1627 }
1628 return mask;
1629}
bellardea041c02003-06-25 16:16:50 +00001630
bellard75012672003-06-21 13:11:07 +00001631void cpu_abort(CPUState *env, const char *fmt, ...)
1632{
1633 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001634 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001635
1636 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001637 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001638 fprintf(stderr, "qemu: fatal: ");
1639 vfprintf(stderr, fmt, ap);
1640 fprintf(stderr, "\n");
1641#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001642 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1643#else
1644 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001645#endif
aliguori93fcfe32009-01-15 22:34:14 +00001646 if (qemu_log_enabled()) {
1647 qemu_log("qemu: fatal: ");
1648 qemu_log_vprintf(fmt, ap2);
1649 qemu_log("\n");
j_mayerf9373292007-09-29 12:18:20 +00001650#ifdef TARGET_I386
aliguori93fcfe32009-01-15 22:34:14 +00001651 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
j_mayerf9373292007-09-29 12:18:20 +00001652#else
aliguori93fcfe32009-01-15 22:34:14 +00001653 log_cpu_state(env, 0);
j_mayerf9373292007-09-29 12:18:20 +00001654#endif
aliguori31b1a7b2009-01-15 22:35:09 +00001655 qemu_log_flush();
aliguori93fcfe32009-01-15 22:34:14 +00001656 qemu_log_close();
balrog924edca2007-06-10 14:07:13 +00001657 }
pbrook493ae1f2007-11-23 16:53:59 +00001658 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001659 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001660 abort();
1661}
1662
thsc5be9f02007-02-28 20:20:53 +00001663CPUState *cpu_copy(CPUState *env)
1664{
ths01ba9812007-12-09 02:22:57 +00001665 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001666 CPUState *next_cpu = new_env->next_cpu;
1667 int cpu_index = new_env->cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001668#if defined(TARGET_HAS_ICE)
1669 CPUBreakpoint *bp;
1670 CPUWatchpoint *wp;
1671#endif
1672
thsc5be9f02007-02-28 20:20:53 +00001673 memcpy(new_env, env, sizeof(CPUState));
aliguori5a38f082009-01-15 20:16:51 +00001674
1675 /* Preserve chaining and index. */
thsc5be9f02007-02-28 20:20:53 +00001676 new_env->next_cpu = next_cpu;
1677 new_env->cpu_index = cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001678
1679 /* Clone all break/watchpoints.
1680 Note: Once we support ptrace with hw-debug register access, make sure
1681 BP_CPU break/watchpoints are handled correctly on clone. */
1682 TAILQ_INIT(&env->breakpoints);
1683 TAILQ_INIT(&env->watchpoints);
1684#if defined(TARGET_HAS_ICE)
1685 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
1686 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
1687 }
1688 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
1689 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
1690 wp->flags, NULL);
1691 }
1692#endif
1693
thsc5be9f02007-02-28 20:20:53 +00001694 return new_env;
1695}
1696
bellard01243112004-01-04 15:48:17 +00001697#if !defined(CONFIG_USER_ONLY)
1698
edgar_igl5c751e92008-05-06 08:44:21 +00001699static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1700{
1701 unsigned int i;
1702
1703 /* Discard jump cache entries for any tb which might potentially
1704 overlap the flushed page. */
1705 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1706 memset (&env->tb_jmp_cache[i], 0,
1707 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1708
1709 i = tb_jmp_cache_hash_page(addr);
1710 memset (&env->tb_jmp_cache[i], 0,
1711 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1712}
1713
bellardee8b7022004-02-03 23:35:10 +00001714/* NOTE: if flush_global is true, also flush global entries (not
1715 implemented yet) */
1716void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001717{
bellard33417e72003-08-10 21:47:01 +00001718 int i;
bellard01243112004-01-04 15:48:17 +00001719
bellard9fa3e852004-01-04 18:06:42 +00001720#if defined(DEBUG_TLB)
1721 printf("tlb_flush:\n");
1722#endif
bellard01243112004-01-04 15:48:17 +00001723 /* must reset current TB so that interrupts cannot modify the
1724 links while we are modifying them */
1725 env->current_tb = NULL;
1726
bellard33417e72003-08-10 21:47:01 +00001727 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001728 env->tlb_table[0][i].addr_read = -1;
1729 env->tlb_table[0][i].addr_write = -1;
1730 env->tlb_table[0][i].addr_code = -1;
1731 env->tlb_table[1][i].addr_read = -1;
1732 env->tlb_table[1][i].addr_write = -1;
1733 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001734#if (NB_MMU_MODES >= 3)
1735 env->tlb_table[2][i].addr_read = -1;
1736 env->tlb_table[2][i].addr_write = -1;
1737 env->tlb_table[2][i].addr_code = -1;
1738#if (NB_MMU_MODES == 4)
1739 env->tlb_table[3][i].addr_read = -1;
1740 env->tlb_table[3][i].addr_write = -1;
1741 env->tlb_table[3][i].addr_code = -1;
1742#endif
1743#endif
bellard33417e72003-08-10 21:47:01 +00001744 }
bellard9fa3e852004-01-04 18:06:42 +00001745
bellard8a40a182005-11-20 10:35:40 +00001746 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001747
bellard0a962c02005-02-10 22:00:27 +00001748#ifdef USE_KQEMU
1749 if (env->kqemu_enabled) {
1750 kqemu_flush(env, flush_global);
1751 }
1752#endif
bellarde3db7222005-01-26 22:00:47 +00001753 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001754}
1755
bellard274da6b2004-05-20 21:56:27 +00001756static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001757{
ths5fafdf22007-09-16 21:08:06 +00001758 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001759 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001760 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001761 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001762 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001763 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1764 tlb_entry->addr_read = -1;
1765 tlb_entry->addr_write = -1;
1766 tlb_entry->addr_code = -1;
1767 }
bellard61382a52003-10-27 21:22:23 +00001768}
1769
bellard2e126692004-04-25 21:28:44 +00001770void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001771{
bellard8a40a182005-11-20 10:35:40 +00001772 int i;
bellard01243112004-01-04 15:48:17 +00001773
bellard9fa3e852004-01-04 18:06:42 +00001774#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001775 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001776#endif
bellard01243112004-01-04 15:48:17 +00001777 /* must reset current TB so that interrupts cannot modify the
1778 links while we are modifying them */
1779 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001780
bellard61382a52003-10-27 21:22:23 +00001781 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001782 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001783 tlb_flush_entry(&env->tlb_table[0][i], addr);
1784 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001785#if (NB_MMU_MODES >= 3)
1786 tlb_flush_entry(&env->tlb_table[2][i], addr);
1787#if (NB_MMU_MODES == 4)
1788 tlb_flush_entry(&env->tlb_table[3][i], addr);
1789#endif
1790#endif
bellard01243112004-01-04 15:48:17 +00001791
edgar_igl5c751e92008-05-06 08:44:21 +00001792 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001793
bellard0a962c02005-02-10 22:00:27 +00001794#ifdef USE_KQEMU
1795 if (env->kqemu_enabled) {
1796 kqemu_flush_page(env, addr);
1797 }
1798#endif
bellard9fa3e852004-01-04 18:06:42 +00001799}
1800
bellard9fa3e852004-01-04 18:06:42 +00001801/* update the TLBs so that writes to code in the virtual page 'addr'
1802 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001803static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001804{
ths5fafdf22007-09-16 21:08:06 +00001805 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001806 ram_addr + TARGET_PAGE_SIZE,
1807 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001808}
1809
bellard9fa3e852004-01-04 18:06:42 +00001810/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001811 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001812static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001813 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001814{
bellard3a7d9292005-08-21 09:26:42 +00001815 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001816}
1817
ths5fafdf22007-09-16 21:08:06 +00001818static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001819 unsigned long start, unsigned long length)
1820{
1821 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001822 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1823 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001824 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001825 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001826 }
1827 }
1828}
1829
bellard3a7d9292005-08-21 09:26:42 +00001830void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001831 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001832{
1833 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001834 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001835 int i, mask, len;
1836 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001837
1838 start &= TARGET_PAGE_MASK;
1839 end = TARGET_PAGE_ALIGN(end);
1840
1841 length = end - start;
1842 if (length == 0)
1843 return;
bellard0a962c02005-02-10 22:00:27 +00001844 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001845#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001846 /* XXX: should not depend on cpu context */
1847 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001848 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001849 ram_addr_t addr;
1850 addr = start;
1851 for(i = 0; i < len; i++) {
1852 kqemu_set_notdirty(env, addr);
1853 addr += TARGET_PAGE_SIZE;
1854 }
bellard3a7d9292005-08-21 09:26:42 +00001855 }
1856#endif
bellardf23db162005-08-21 19:12:28 +00001857 mask = ~dirty_flags;
1858 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1859 for(i = 0; i < len; i++)
1860 p[i] &= mask;
1861
bellard1ccde1c2004-02-06 19:46:14 +00001862 /* we modify the TLB cache so that the dirty bit will be set again
1863 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001864 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001865 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1866 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001867 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001868 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001869 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001870#if (NB_MMU_MODES >= 3)
1871 for(i = 0; i < CPU_TLB_SIZE; i++)
1872 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1873#if (NB_MMU_MODES == 4)
1874 for(i = 0; i < CPU_TLB_SIZE; i++)
1875 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1876#endif
1877#endif
bellard6a00d602005-11-21 23:25:50 +00001878 }
bellard1ccde1c2004-02-06 19:46:14 +00001879}
1880
aliguori74576192008-10-06 14:02:03 +00001881int cpu_physical_memory_set_dirty_tracking(int enable)
1882{
1883 in_migration = enable;
1884 return 0;
1885}
1886
1887int cpu_physical_memory_get_dirty_tracking(void)
1888{
1889 return in_migration;
1890}
1891
aliguori2bec46d2008-11-24 20:21:41 +00001892void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
1893{
1894 if (kvm_enabled())
1895 kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1896}
1897
bellard3a7d9292005-08-21 09:26:42 +00001898static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1899{
1900 ram_addr_t ram_addr;
1901
bellard84b7b8e2005-11-28 21:19:04 +00001902 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001903 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001904 tlb_entry->addend - (unsigned long)phys_ram_base;
1905 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001906 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001907 }
1908 }
1909}
1910
1911/* update the TLB according to the current state of the dirty bits */
1912void cpu_tlb_update_dirty(CPUState *env)
1913{
1914 int i;
1915 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001916 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001917 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001918 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001919#if (NB_MMU_MODES >= 3)
1920 for(i = 0; i < CPU_TLB_SIZE; i++)
1921 tlb_update_dirty(&env->tlb_table[2][i]);
1922#if (NB_MMU_MODES == 4)
1923 for(i = 0; i < CPU_TLB_SIZE; i++)
1924 tlb_update_dirty(&env->tlb_table[3][i]);
1925#endif
1926#endif
bellard3a7d9292005-08-21 09:26:42 +00001927}
1928
pbrook0f459d12008-06-09 00:20:13 +00001929static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001930{
pbrook0f459d12008-06-09 00:20:13 +00001931 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1932 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001933}
1934
pbrook0f459d12008-06-09 00:20:13 +00001935/* update the TLB corresponding to virtual page vaddr
1936 so that it is no longer dirty */
1937static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001938{
bellard1ccde1c2004-02-06 19:46:14 +00001939 int i;
1940
pbrook0f459d12008-06-09 00:20:13 +00001941 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001942 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001943 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1944 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001945#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001946 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001947#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001948 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001949#endif
1950#endif
bellard9fa3e852004-01-04 18:06:42 +00001951}
1952
bellard59817cc2004-02-16 22:01:13 +00001953/* add a new TLB entry. At most one entry for a given virtual address
1954 is permitted. Return 0 if OK or 2 if the page could not be mapped
1955 (can only happen in non SOFTMMU mode for I/O pages or pages
1956 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001957int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1958 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001959 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001960{
bellard92e873b2004-05-21 14:52:29 +00001961 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001962 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001963 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001964 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001965 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001966 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001967 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001968 CPUTLBEntry *te;
aliguoria1d1bb32008-11-18 20:07:32 +00001969 CPUWatchpoint *wp;
pbrook0f459d12008-06-09 00:20:13 +00001970 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001971
bellard92e873b2004-05-21 14:52:29 +00001972 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001973 if (!p) {
1974 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001975 } else {
1976 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001977 }
1978#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001979 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1980 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001981#endif
1982
1983 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001984 address = vaddr;
1985 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1986 /* IO memory case (romd handled later) */
1987 address |= TLB_MMIO;
1988 }
1989 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1990 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1991 /* Normal RAM. */
1992 iotlb = pd & TARGET_PAGE_MASK;
1993 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1994 iotlb |= IO_MEM_NOTDIRTY;
1995 else
1996 iotlb |= IO_MEM_ROM;
1997 } else {
1998 /* IO handlers are currently passed a phsical address.
1999 It would be nice to pass an offset from the base address
2000 of that region. This would avoid having to special case RAM,
2001 and avoid full address decoding in every device.
2002 We can't use the high bits of pd for this because
2003 IO_MEM_ROMD uses these as a ram address. */
pbrook8da3ff12008-12-01 18:59:50 +00002004 iotlb = (pd & ~TARGET_PAGE_MASK);
2005 if (p) {
pbrook8da3ff12008-12-01 18:59:50 +00002006 iotlb += p->region_offset;
2007 } else {
2008 iotlb += paddr;
2009 }
pbrook0f459d12008-06-09 00:20:13 +00002010 }
pbrook6658ffb2007-03-16 23:58:11 +00002011
pbrook0f459d12008-06-09 00:20:13 +00002012 code_address = address;
2013 /* Make accesses to pages with watchpoints go via the
2014 watchpoint trap routines. */
aliguoric0ce9982008-11-25 22:13:57 +00002015 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00002016 if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
pbrook0f459d12008-06-09 00:20:13 +00002017 iotlb = io_mem_watch + paddr;
2018 /* TODO: The memory case can be optimized by not trapping
2019 reads of pages with a write breakpoint. */
2020 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00002021 }
pbrook0f459d12008-06-09 00:20:13 +00002022 }
balrogd79acba2007-06-26 20:01:13 +00002023
pbrook0f459d12008-06-09 00:20:13 +00002024 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
2025 env->iotlb[mmu_idx][index] = iotlb - vaddr;
2026 te = &env->tlb_table[mmu_idx][index];
2027 te->addend = addend - vaddr;
2028 if (prot & PAGE_READ) {
2029 te->addr_read = address;
2030 } else {
2031 te->addr_read = -1;
2032 }
edgar_igl5c751e92008-05-06 08:44:21 +00002033
pbrook0f459d12008-06-09 00:20:13 +00002034 if (prot & PAGE_EXEC) {
2035 te->addr_code = code_address;
2036 } else {
2037 te->addr_code = -1;
2038 }
2039 if (prot & PAGE_WRITE) {
2040 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
2041 (pd & IO_MEM_ROMD)) {
2042 /* Write access calls the I/O callback. */
2043 te->addr_write = address | TLB_MMIO;
2044 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2045 !cpu_physical_memory_is_dirty(pd)) {
2046 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00002047 } else {
pbrook0f459d12008-06-09 00:20:13 +00002048 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00002049 }
pbrook0f459d12008-06-09 00:20:13 +00002050 } else {
2051 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00002052 }
bellard9fa3e852004-01-04 18:06:42 +00002053 return ret;
2054}
2055
bellard01243112004-01-04 15:48:17 +00002056#else
2057
bellardee8b7022004-02-03 23:35:10 +00002058void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00002059{
2060}
2061
bellard2e126692004-04-25 21:28:44 +00002062void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00002063{
2064}
2065
ths5fafdf22007-09-16 21:08:06 +00002066int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
2067 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00002068 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00002069{
bellard9fa3e852004-01-04 18:06:42 +00002070 return 0;
2071}
bellard33417e72003-08-10 21:47:01 +00002072
bellard9fa3e852004-01-04 18:06:42 +00002073/* dump memory mappings */
2074void page_dump(FILE *f)
2075{
2076 unsigned long start, end;
2077 int i, j, prot, prot1;
2078 PageDesc *p;
2079
2080 fprintf(f, "%-8s %-8s %-8s %s\n",
2081 "start", "end", "size", "prot");
2082 start = -1;
2083 end = -1;
2084 prot = 0;
2085 for(i = 0; i <= L1_SIZE; i++) {
2086 if (i < L1_SIZE)
2087 p = l1_map[i];
2088 else
2089 p = NULL;
2090 for(j = 0;j < L2_SIZE; j++) {
2091 if (!p)
2092 prot1 = 0;
2093 else
2094 prot1 = p[j].flags;
2095 if (prot1 != prot) {
2096 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2097 if (start != -1) {
2098 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00002099 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00002100 prot & PAGE_READ ? 'r' : '-',
2101 prot & PAGE_WRITE ? 'w' : '-',
2102 prot & PAGE_EXEC ? 'x' : '-');
2103 }
2104 if (prot1 != 0)
2105 start = end;
2106 else
2107 start = -1;
2108 prot = prot1;
2109 }
2110 if (!p)
2111 break;
2112 }
bellard33417e72003-08-10 21:47:01 +00002113 }
bellard33417e72003-08-10 21:47:01 +00002114}
2115
pbrook53a59602006-03-25 19:31:22 +00002116int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002117{
bellard9fa3e852004-01-04 18:06:42 +00002118 PageDesc *p;
2119
2120 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002121 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002122 return 0;
2123 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002124}
2125
bellard9fa3e852004-01-04 18:06:42 +00002126/* modify the flags of a page and invalidate the code if
2127 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2128 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002129void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002130{
2131 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002132 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002133
pbrookc8a706f2008-06-02 16:16:42 +00002134 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002135 start = start & TARGET_PAGE_MASK;
2136 end = TARGET_PAGE_ALIGN(end);
2137 if (flags & PAGE_WRITE)
2138 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002139 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2140 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00002141 /* We may be called for host regions that are outside guest
2142 address space. */
2143 if (!p)
2144 return;
bellard9fa3e852004-01-04 18:06:42 +00002145 /* if the write protection is set, then we invalidate the code
2146 inside */
ths5fafdf22007-09-16 21:08:06 +00002147 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002148 (flags & PAGE_WRITE) &&
2149 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002150 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002151 }
2152 p->flags = flags;
2153 }
bellard9fa3e852004-01-04 18:06:42 +00002154}
2155
ths3d97b402007-11-02 19:02:07 +00002156int page_check_range(target_ulong start, target_ulong len, int flags)
2157{
2158 PageDesc *p;
2159 target_ulong end;
2160 target_ulong addr;
2161
balrog55f280c2008-10-28 10:24:11 +00002162 if (start + len < start)
2163 /* we've wrapped around */
2164 return -1;
2165
ths3d97b402007-11-02 19:02:07 +00002166 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2167 start = start & TARGET_PAGE_MASK;
2168
ths3d97b402007-11-02 19:02:07 +00002169 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2170 p = page_find(addr >> TARGET_PAGE_BITS);
2171 if( !p )
2172 return -1;
2173 if( !(p->flags & PAGE_VALID) )
2174 return -1;
2175
bellarddae32702007-11-14 10:51:00 +00002176 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002177 return -1;
bellarddae32702007-11-14 10:51:00 +00002178 if (flags & PAGE_WRITE) {
2179 if (!(p->flags & PAGE_WRITE_ORG))
2180 return -1;
2181 /* unprotect the page if it was put read-only because it
2182 contains translated code */
2183 if (!(p->flags & PAGE_WRITE)) {
2184 if (!page_unprotect(addr, 0, NULL))
2185 return -1;
2186 }
2187 return 0;
2188 }
ths3d97b402007-11-02 19:02:07 +00002189 }
2190 return 0;
2191}
2192
bellard9fa3e852004-01-04 18:06:42 +00002193/* called from signal handler: invalidate the code and unprotect the
2194 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002195int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002196{
2197 unsigned int page_index, prot, pindex;
2198 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002199 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002200
pbrookc8a706f2008-06-02 16:16:42 +00002201 /* Technically this isn't safe inside a signal handler. However we
2202 know this only ever happens in a synchronous SEGV handler, so in
2203 practice it seems to be ok. */
2204 mmap_lock();
2205
bellard83fb7ad2004-07-05 21:25:26 +00002206 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002207 page_index = host_start >> TARGET_PAGE_BITS;
2208 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002209 if (!p1) {
2210 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002211 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002212 }
bellard83fb7ad2004-07-05 21:25:26 +00002213 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002214 p = p1;
2215 prot = 0;
2216 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2217 prot |= p->flags;
2218 p++;
2219 }
2220 /* if the page was really writable, then we change its
2221 protection back to writable */
2222 if (prot & PAGE_WRITE_ORG) {
2223 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2224 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002225 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002226 (prot & PAGE_BITS) | PAGE_WRITE);
2227 p1[pindex].flags |= PAGE_WRITE;
2228 /* and since the content will be modified, we must invalidate
2229 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002230 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002231#ifdef DEBUG_TB_CHECK
2232 tb_invalidate_check(address);
2233#endif
pbrookc8a706f2008-06-02 16:16:42 +00002234 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002235 return 1;
2236 }
2237 }
pbrookc8a706f2008-06-02 16:16:42 +00002238 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002239 return 0;
2240}
2241
bellard6a00d602005-11-21 23:25:50 +00002242static inline void tlb_set_dirty(CPUState *env,
2243 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002244{
2245}
bellard9fa3e852004-01-04 18:06:42 +00002246#endif /* defined(CONFIG_USER_ONLY) */
2247
pbrooke2eef172008-06-08 01:09:01 +00002248#if !defined(CONFIG_USER_ONLY)
pbrook8da3ff12008-12-01 18:59:50 +00002249
blueswir1db7b5422007-05-26 17:36:03 +00002250static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002251 ram_addr_t memory, ram_addr_t region_offset);
aurel3200f82b82008-04-27 21:12:55 +00002252static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002253 ram_addr_t orig_memory, ram_addr_t region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002254#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2255 need_subpage) \
2256 do { \
2257 if (addr > start_addr) \
2258 start_addr2 = 0; \
2259 else { \
2260 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2261 if (start_addr2 > 0) \
2262 need_subpage = 1; \
2263 } \
2264 \
blueswir149e9fba2007-05-30 17:25:06 +00002265 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002266 end_addr2 = TARGET_PAGE_SIZE - 1; \
2267 else { \
2268 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2269 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2270 need_subpage = 1; \
2271 } \
2272 } while (0)
2273
bellard33417e72003-08-10 21:47:01 +00002274/* register physical memory. 'size' must be a multiple of the target
2275 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
pbrook8da3ff12008-12-01 18:59:50 +00002276 io memory page. The address used when calling the IO function is
2277 the offset from the start of the region, plus region_offset. Both
2278 start_region and regon_offset are rounded down to a page boundary
2279 before calculating this offset. This should not be a problem unless
2280 the low bits of start_addr and region_offset differ. */
2281void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2282 ram_addr_t size,
2283 ram_addr_t phys_offset,
2284 ram_addr_t region_offset)
bellard33417e72003-08-10 21:47:01 +00002285{
bellard108c49b2005-07-24 12:55:09 +00002286 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002287 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002288 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002289 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002290 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002291
bellardda260242008-05-30 20:48:25 +00002292#ifdef USE_KQEMU
2293 /* XXX: should not depend on cpu context */
2294 env = first_cpu;
2295 if (env->kqemu_enabled) {
2296 kqemu_set_phys_mem(start_addr, size, phys_offset);
2297 }
2298#endif
aliguori7ba1e612008-11-05 16:04:33 +00002299 if (kvm_enabled())
2300 kvm_set_phys_mem(start_addr, size, phys_offset);
2301
pbrook67c4d232009-02-23 13:16:07 +00002302 if (phys_offset == IO_MEM_UNASSIGNED) {
2303 region_offset = start_addr;
2304 }
pbrook8da3ff12008-12-01 18:59:50 +00002305 region_offset &= TARGET_PAGE_MASK;
bellard5fd386f2004-05-23 21:11:22 +00002306 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002307 end_addr = start_addr + (target_phys_addr_t)size;
2308 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002309 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2310 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002311 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002312 target_phys_addr_t start_addr2, end_addr2;
2313 int need_subpage = 0;
2314
2315 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2316 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002317 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002318 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2319 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002320 &p->phys_offset, orig_memory,
2321 p->region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002322 } else {
2323 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2324 >> IO_MEM_SHIFT];
2325 }
pbrook8da3ff12008-12-01 18:59:50 +00002326 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2327 region_offset);
2328 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002329 } else {
2330 p->phys_offset = phys_offset;
2331 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2332 (phys_offset & IO_MEM_ROMD))
2333 phys_offset += TARGET_PAGE_SIZE;
2334 }
2335 } else {
2336 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2337 p->phys_offset = phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +00002338 p->region_offset = region_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002339 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
pbrook8da3ff12008-12-01 18:59:50 +00002340 (phys_offset & IO_MEM_ROMD)) {
blueswir1db7b5422007-05-26 17:36:03 +00002341 phys_offset += TARGET_PAGE_SIZE;
pbrook0e8f0962008-12-02 09:02:15 +00002342 } else {
blueswir1db7b5422007-05-26 17:36:03 +00002343 target_phys_addr_t start_addr2, end_addr2;
2344 int need_subpage = 0;
2345
2346 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2347 end_addr2, need_subpage);
2348
blueswir14254fab2008-01-01 16:57:19 +00002349 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002350 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002351 &p->phys_offset, IO_MEM_UNASSIGNED,
pbrook67c4d232009-02-23 13:16:07 +00002352 addr & TARGET_PAGE_MASK);
blueswir1db7b5422007-05-26 17:36:03 +00002353 subpage_register(subpage, start_addr2, end_addr2,
pbrook8da3ff12008-12-01 18:59:50 +00002354 phys_offset, region_offset);
2355 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002356 }
2357 }
2358 }
pbrook8da3ff12008-12-01 18:59:50 +00002359 region_offset += TARGET_PAGE_SIZE;
bellard33417e72003-08-10 21:47:01 +00002360 }
ths3b46e622007-09-17 08:09:54 +00002361
bellard9d420372006-06-25 22:25:22 +00002362 /* since each CPU stores ram addresses in its TLB cache, we must
2363 reset the modified entries */
2364 /* XXX: slow ! */
2365 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2366 tlb_flush(env, 1);
2367 }
bellard33417e72003-08-10 21:47:01 +00002368}
2369
bellardba863452006-09-24 18:41:10 +00002370/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002371ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002372{
2373 PhysPageDesc *p;
2374
2375 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2376 if (!p)
2377 return IO_MEM_UNASSIGNED;
2378 return p->phys_offset;
2379}
2380
aliguorif65ed4c2008-12-09 20:09:57 +00002381void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2382{
2383 if (kvm_enabled())
2384 kvm_coalesce_mmio_region(addr, size);
2385}
2386
2387void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2388{
2389 if (kvm_enabled())
2390 kvm_uncoalesce_mmio_region(addr, size);
2391}
2392
bellarde9a1ab12007-02-08 23:08:38 +00002393/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002394ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002395{
2396 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002397 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
ths012a7042008-10-02 17:34:21 +00002398 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
bellarded441462008-05-23 11:56:45 +00002399 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002400 abort();
2401 }
2402 addr = phys_ram_alloc_offset;
2403 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2404 return addr;
2405}
2406
2407void qemu_ram_free(ram_addr_t addr)
2408{
2409}
2410
bellarda4193c82004-06-03 14:01:43 +00002411static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002412{
pbrook67d3b952006-12-18 05:03:52 +00002413#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002414 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002415#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002416#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002417 do_unassigned_access(addr, 0, 0, 0, 1);
2418#endif
2419 return 0;
2420}
2421
2422static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
2423{
2424#ifdef DEBUG_UNASSIGNED
2425 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2426#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002427#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002428 do_unassigned_access(addr, 0, 0, 0, 2);
2429#endif
2430 return 0;
2431}
2432
2433static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
2434{
2435#ifdef DEBUG_UNASSIGNED
2436 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2437#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002438#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002439 do_unassigned_access(addr, 0, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002440#endif
bellard33417e72003-08-10 21:47:01 +00002441 return 0;
2442}
2443
bellarda4193c82004-06-03 14:01:43 +00002444static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002445{
pbrook67d3b952006-12-18 05:03:52 +00002446#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002447 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002448#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002449#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002450 do_unassigned_access(addr, 1, 0, 0, 1);
2451#endif
2452}
2453
2454static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2455{
2456#ifdef DEBUG_UNASSIGNED
2457 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2458#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002459#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002460 do_unassigned_access(addr, 1, 0, 0, 2);
2461#endif
2462}
2463
2464static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2465{
2466#ifdef DEBUG_UNASSIGNED
2467 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2468#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002469#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002470 do_unassigned_access(addr, 1, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002471#endif
bellard33417e72003-08-10 21:47:01 +00002472}
2473
2474static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2475 unassigned_mem_readb,
blueswir1e18231a2008-10-06 18:46:28 +00002476 unassigned_mem_readw,
2477 unassigned_mem_readl,
bellard33417e72003-08-10 21:47:01 +00002478};
2479
2480static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2481 unassigned_mem_writeb,
blueswir1e18231a2008-10-06 18:46:28 +00002482 unassigned_mem_writew,
2483 unassigned_mem_writel,
bellard33417e72003-08-10 21:47:01 +00002484};
2485
pbrook0f459d12008-06-09 00:20:13 +00002486static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2487 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002488{
bellard3a7d9292005-08-21 09:26:42 +00002489 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002490 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2491 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2492#if !defined(CONFIG_USER_ONLY)
2493 tb_invalidate_phys_page_fast(ram_addr, 1);
2494 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2495#endif
2496 }
pbrook0f459d12008-06-09 00:20:13 +00002497 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002498#ifdef USE_KQEMU
2499 if (cpu_single_env->kqemu_enabled &&
2500 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2501 kqemu_modify_page(cpu_single_env, ram_addr);
2502#endif
bellardf23db162005-08-21 19:12:28 +00002503 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2504 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2505 /* we remove the notdirty callback only if the code has been
2506 flushed */
2507 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002508 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002509}
2510
pbrook0f459d12008-06-09 00:20:13 +00002511static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2512 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002513{
bellard3a7d9292005-08-21 09:26:42 +00002514 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002515 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2516 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2517#if !defined(CONFIG_USER_ONLY)
2518 tb_invalidate_phys_page_fast(ram_addr, 2);
2519 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2520#endif
2521 }
pbrook0f459d12008-06-09 00:20:13 +00002522 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002523#ifdef USE_KQEMU
2524 if (cpu_single_env->kqemu_enabled &&
2525 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2526 kqemu_modify_page(cpu_single_env, ram_addr);
2527#endif
bellardf23db162005-08-21 19:12:28 +00002528 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2529 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2530 /* we remove the notdirty callback only if the code has been
2531 flushed */
2532 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002533 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002534}
2535
pbrook0f459d12008-06-09 00:20:13 +00002536static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2537 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002538{
bellard3a7d9292005-08-21 09:26:42 +00002539 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002540 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2541 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2542#if !defined(CONFIG_USER_ONLY)
2543 tb_invalidate_phys_page_fast(ram_addr, 4);
2544 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2545#endif
2546 }
pbrook0f459d12008-06-09 00:20:13 +00002547 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002548#ifdef USE_KQEMU
2549 if (cpu_single_env->kqemu_enabled &&
2550 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2551 kqemu_modify_page(cpu_single_env, ram_addr);
2552#endif
bellardf23db162005-08-21 19:12:28 +00002553 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2554 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2555 /* we remove the notdirty callback only if the code has been
2556 flushed */
2557 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002558 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002559}
2560
bellard3a7d9292005-08-21 09:26:42 +00002561static CPUReadMemoryFunc *error_mem_read[3] = {
2562 NULL, /* never used */
2563 NULL, /* never used */
2564 NULL, /* never used */
2565};
2566
bellard1ccde1c2004-02-06 19:46:14 +00002567static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2568 notdirty_mem_writeb,
2569 notdirty_mem_writew,
2570 notdirty_mem_writel,
2571};
2572
pbrook0f459d12008-06-09 00:20:13 +00002573/* Generate a debug exception if a watchpoint has been hit. */
aliguorib4051332008-11-18 20:14:20 +00002574static void check_watchpoint(int offset, int len_mask, int flags)
pbrook0f459d12008-06-09 00:20:13 +00002575{
2576 CPUState *env = cpu_single_env;
aliguori06d55cc2008-11-18 20:24:06 +00002577 target_ulong pc, cs_base;
2578 TranslationBlock *tb;
pbrook0f459d12008-06-09 00:20:13 +00002579 target_ulong vaddr;
aliguoria1d1bb32008-11-18 20:07:32 +00002580 CPUWatchpoint *wp;
aliguori06d55cc2008-11-18 20:24:06 +00002581 int cpu_flags;
pbrook0f459d12008-06-09 00:20:13 +00002582
aliguori06d55cc2008-11-18 20:24:06 +00002583 if (env->watchpoint_hit) {
2584 /* We re-entered the check after replacing the TB. Now raise
2585 * the debug interrupt so that is will trigger after the
2586 * current instruction. */
2587 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2588 return;
2589 }
pbrook2e70f6e2008-06-29 01:03:05 +00002590 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
aliguoric0ce9982008-11-25 22:13:57 +00002591 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00002592 if ((vaddr == (wp->vaddr & len_mask) ||
2593 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
aliguori6e140f22008-11-18 20:37:55 +00002594 wp->flags |= BP_WATCHPOINT_HIT;
2595 if (!env->watchpoint_hit) {
2596 env->watchpoint_hit = wp;
2597 tb = tb_find_pc(env->mem_io_pc);
2598 if (!tb) {
2599 cpu_abort(env, "check_watchpoint: could not find TB for "
2600 "pc=%p", (void *)env->mem_io_pc);
2601 }
2602 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
2603 tb_phys_invalidate(tb, -1);
2604 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2605 env->exception_index = EXCP_DEBUG;
2606 } else {
2607 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2608 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2609 }
2610 cpu_resume_from_signal(env, NULL);
aliguori06d55cc2008-11-18 20:24:06 +00002611 }
aliguori6e140f22008-11-18 20:37:55 +00002612 } else {
2613 wp->flags &= ~BP_WATCHPOINT_HIT;
pbrook0f459d12008-06-09 00:20:13 +00002614 }
2615 }
2616}
2617
pbrook6658ffb2007-03-16 23:58:11 +00002618/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2619 so these check for a hit then pass through to the normal out-of-line
2620 phys routines. */
2621static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2622{
aliguorib4051332008-11-18 20:14:20 +00002623 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002624 return ldub_phys(addr);
2625}
2626
2627static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2628{
aliguorib4051332008-11-18 20:14:20 +00002629 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002630 return lduw_phys(addr);
2631}
2632
2633static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2634{
aliguorib4051332008-11-18 20:14:20 +00002635 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002636 return ldl_phys(addr);
2637}
2638
pbrook6658ffb2007-03-16 23:58:11 +00002639static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2640 uint32_t val)
2641{
aliguorib4051332008-11-18 20:14:20 +00002642 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002643 stb_phys(addr, val);
2644}
2645
2646static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2647 uint32_t val)
2648{
aliguorib4051332008-11-18 20:14:20 +00002649 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002650 stw_phys(addr, val);
2651}
2652
2653static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2654 uint32_t val)
2655{
aliguorib4051332008-11-18 20:14:20 +00002656 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002657 stl_phys(addr, val);
2658}
2659
2660static CPUReadMemoryFunc *watch_mem_read[3] = {
2661 watch_mem_readb,
2662 watch_mem_readw,
2663 watch_mem_readl,
2664};
2665
2666static CPUWriteMemoryFunc *watch_mem_write[3] = {
2667 watch_mem_writeb,
2668 watch_mem_writew,
2669 watch_mem_writel,
2670};
pbrook6658ffb2007-03-16 23:58:11 +00002671
blueswir1db7b5422007-05-26 17:36:03 +00002672static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2673 unsigned int len)
2674{
blueswir1db7b5422007-05-26 17:36:03 +00002675 uint32_t ret;
2676 unsigned int idx;
2677
pbrook8da3ff12008-12-01 18:59:50 +00002678 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002679#if defined(DEBUG_SUBPAGE)
2680 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2681 mmio, len, addr, idx);
2682#endif
pbrook8da3ff12008-12-01 18:59:50 +00002683 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2684 addr + mmio->region_offset[idx][0][len]);
blueswir1db7b5422007-05-26 17:36:03 +00002685
2686 return ret;
2687}
2688
2689static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2690 uint32_t value, unsigned int len)
2691{
blueswir1db7b5422007-05-26 17:36:03 +00002692 unsigned int idx;
2693
pbrook8da3ff12008-12-01 18:59:50 +00002694 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002695#if defined(DEBUG_SUBPAGE)
2696 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2697 mmio, len, addr, idx, value);
2698#endif
pbrook8da3ff12008-12-01 18:59:50 +00002699 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2700 addr + mmio->region_offset[idx][1][len],
2701 value);
blueswir1db7b5422007-05-26 17:36:03 +00002702}
2703
2704static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2705{
2706#if defined(DEBUG_SUBPAGE)
2707 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2708#endif
2709
2710 return subpage_readlen(opaque, addr, 0);
2711}
2712
2713static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2714 uint32_t value)
2715{
2716#if defined(DEBUG_SUBPAGE)
2717 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2718#endif
2719 subpage_writelen(opaque, addr, value, 0);
2720}
2721
2722static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2723{
2724#if defined(DEBUG_SUBPAGE)
2725 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2726#endif
2727
2728 return subpage_readlen(opaque, addr, 1);
2729}
2730
2731static void subpage_writew (void *opaque, target_phys_addr_t addr,
2732 uint32_t value)
2733{
2734#if defined(DEBUG_SUBPAGE)
2735 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2736#endif
2737 subpage_writelen(opaque, addr, value, 1);
2738}
2739
2740static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2741{
2742#if defined(DEBUG_SUBPAGE)
2743 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2744#endif
2745
2746 return subpage_readlen(opaque, addr, 2);
2747}
2748
2749static void subpage_writel (void *opaque,
2750 target_phys_addr_t addr, uint32_t value)
2751{
2752#if defined(DEBUG_SUBPAGE)
2753 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2754#endif
2755 subpage_writelen(opaque, addr, value, 2);
2756}
2757
2758static CPUReadMemoryFunc *subpage_read[] = {
2759 &subpage_readb,
2760 &subpage_readw,
2761 &subpage_readl,
2762};
2763
2764static CPUWriteMemoryFunc *subpage_write[] = {
2765 &subpage_writeb,
2766 &subpage_writew,
2767 &subpage_writel,
2768};
2769
2770static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002771 ram_addr_t memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002772{
2773 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002774 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002775
2776 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2777 return -1;
2778 idx = SUBPAGE_IDX(start);
2779 eidx = SUBPAGE_IDX(end);
2780#if defined(DEBUG_SUBPAGE)
2781 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2782 mmio, start, end, idx, eidx, memory);
2783#endif
2784 memory >>= IO_MEM_SHIFT;
2785 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002786 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002787 if (io_mem_read[memory][i]) {
2788 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2789 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002790 mmio->region_offset[idx][0][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002791 }
2792 if (io_mem_write[memory][i]) {
2793 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2794 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002795 mmio->region_offset[idx][1][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002796 }
blueswir14254fab2008-01-01 16:57:19 +00002797 }
blueswir1db7b5422007-05-26 17:36:03 +00002798 }
2799
2800 return 0;
2801}
2802
aurel3200f82b82008-04-27 21:12:55 +00002803static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002804 ram_addr_t orig_memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002805{
2806 subpage_t *mmio;
2807 int subpage_memory;
2808
2809 mmio = qemu_mallocz(sizeof(subpage_t));
aliguori1eec6142009-02-05 22:06:18 +00002810
2811 mmio->base = base;
2812 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
blueswir1db7b5422007-05-26 17:36:03 +00002813#if defined(DEBUG_SUBPAGE)
aliguori1eec6142009-02-05 22:06:18 +00002814 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2815 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002816#endif
aliguori1eec6142009-02-05 22:06:18 +00002817 *phys = subpage_memory | IO_MEM_SUBPAGE;
2818 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
pbrook8da3ff12008-12-01 18:59:50 +00002819 region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002820
2821 return mmio;
2822}
2823
aliguori88715652009-02-11 15:20:58 +00002824static int get_free_io_mem_idx(void)
2825{
2826 int i;
2827
2828 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2829 if (!io_mem_used[i]) {
2830 io_mem_used[i] = 1;
2831 return i;
2832 }
2833
2834 return -1;
2835}
2836
bellard33417e72003-08-10 21:47:01 +00002837static void io_mem_init(void)
2838{
aliguori88715652009-02-11 15:20:58 +00002839 int i;
2840
bellard3a7d9292005-08-21 09:26:42 +00002841 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002842 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002843 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
aliguori88715652009-02-11 15:20:58 +00002844 for (i=0; i<5; i++)
2845 io_mem_used[i] = 1;
bellard1ccde1c2004-02-06 19:46:14 +00002846
pbrook0f459d12008-06-09 00:20:13 +00002847 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002848 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002849 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002850 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002851 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002852}
2853
2854/* mem_read and mem_write are arrays of functions containing the
2855 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002856 2). Functions can be omitted with a NULL function pointer. The
2857 registered functions may be modified dynamically later.
2858 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002859 modified. If it is zero, a new io zone is allocated. The return
2860 value can be used with cpu_register_physical_memory(). (-1) is
2861 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002862int cpu_register_io_memory(int io_index,
2863 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002864 CPUWriteMemoryFunc **mem_write,
2865 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002866{
blueswir14254fab2008-01-01 16:57:19 +00002867 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002868
2869 if (io_index <= 0) {
aliguori88715652009-02-11 15:20:58 +00002870 io_index = get_free_io_mem_idx();
2871 if (io_index == -1)
2872 return io_index;
bellard33417e72003-08-10 21:47:01 +00002873 } else {
2874 if (io_index >= IO_MEM_NB_ENTRIES)
2875 return -1;
2876 }
bellardb5ff1b32005-11-26 10:38:39 +00002877
bellard33417e72003-08-10 21:47:01 +00002878 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002879 if (!mem_read[i] || !mem_write[i])
2880 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002881 io_mem_read[io_index][i] = mem_read[i];
2882 io_mem_write[io_index][i] = mem_write[i];
2883 }
bellarda4193c82004-06-03 14:01:43 +00002884 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002885 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002886}
bellard61382a52003-10-27 21:22:23 +00002887
aliguori88715652009-02-11 15:20:58 +00002888void cpu_unregister_io_memory(int io_table_address)
2889{
2890 int i;
2891 int io_index = io_table_address >> IO_MEM_SHIFT;
2892
2893 for (i=0;i < 3; i++) {
2894 io_mem_read[io_index][i] = unassigned_mem_read[i];
2895 io_mem_write[io_index][i] = unassigned_mem_write[i];
2896 }
2897 io_mem_opaque[io_index] = NULL;
2898 io_mem_used[io_index] = 0;
2899}
2900
bellard8926b512004-10-10 15:14:20 +00002901CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2902{
2903 return io_mem_write[io_index >> IO_MEM_SHIFT];
2904}
2905
2906CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2907{
2908 return io_mem_read[io_index >> IO_MEM_SHIFT];
2909}
2910
pbrooke2eef172008-06-08 01:09:01 +00002911#endif /* !defined(CONFIG_USER_ONLY) */
2912
bellard13eb76e2004-01-24 15:23:36 +00002913/* physical memory access (slow version, mainly for debug) */
2914#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002915void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002916 int len, int is_write)
2917{
2918 int l, flags;
2919 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002920 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002921
2922 while (len > 0) {
2923 page = addr & TARGET_PAGE_MASK;
2924 l = (page + TARGET_PAGE_SIZE) - addr;
2925 if (l > len)
2926 l = len;
2927 flags = page_get_flags(page);
2928 if (!(flags & PAGE_VALID))
2929 return;
2930 if (is_write) {
2931 if (!(flags & PAGE_WRITE))
2932 return;
bellard579a97f2007-11-11 14:26:47 +00002933 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002934 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002935 /* FIXME - should this return an error rather than just fail? */
2936 return;
aurel3272fb7da2008-04-27 23:53:45 +00002937 memcpy(p, buf, l);
2938 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002939 } else {
2940 if (!(flags & PAGE_READ))
2941 return;
bellard579a97f2007-11-11 14:26:47 +00002942 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002943 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002944 /* FIXME - should this return an error rather than just fail? */
2945 return;
aurel3272fb7da2008-04-27 23:53:45 +00002946 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002947 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002948 }
2949 len -= l;
2950 buf += l;
2951 addr += l;
2952 }
2953}
bellard8df1cd02005-01-28 22:37:22 +00002954
bellard13eb76e2004-01-24 15:23:36 +00002955#else
ths5fafdf22007-09-16 21:08:06 +00002956void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002957 int len, int is_write)
2958{
2959 int l, io_index;
2960 uint8_t *ptr;
2961 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002962 target_phys_addr_t page;
2963 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002964 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002965
bellard13eb76e2004-01-24 15:23:36 +00002966 while (len > 0) {
2967 page = addr & TARGET_PAGE_MASK;
2968 l = (page + TARGET_PAGE_SIZE) - addr;
2969 if (l > len)
2970 l = len;
bellard92e873b2004-05-21 14:52:29 +00002971 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002972 if (!p) {
2973 pd = IO_MEM_UNASSIGNED;
2974 } else {
2975 pd = p->phys_offset;
2976 }
ths3b46e622007-09-17 08:09:54 +00002977
bellard13eb76e2004-01-24 15:23:36 +00002978 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002979 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
aurel326c2934d2009-02-18 21:37:17 +00002980 target_phys_addr_t addr1 = addr;
bellard13eb76e2004-01-24 15:23:36 +00002981 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002982 if (p)
aurel326c2934d2009-02-18 21:37:17 +00002983 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard6a00d602005-11-21 23:25:50 +00002984 /* XXX: could force cpu_single_env to NULL to avoid
2985 potential bugs */
aurel326c2934d2009-02-18 21:37:17 +00002986 if (l >= 4 && ((addr1 & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002987 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002988 val = ldl_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002989 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00002990 l = 4;
aurel326c2934d2009-02-18 21:37:17 +00002991 } else if (l >= 2 && ((addr1 & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002992 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002993 val = lduw_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002994 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00002995 l = 2;
2996 } else {
bellard1c213d12005-09-03 10:49:04 +00002997 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002998 val = ldub_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002999 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00003000 l = 1;
3001 }
3002 } else {
bellardb448f2f2004-02-25 23:24:04 +00003003 unsigned long addr1;
3004 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00003005 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00003006 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00003007 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00003008 if (!cpu_physical_memory_is_dirty(addr1)) {
3009 /* invalidate code */
3010 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3011 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00003012 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00003013 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003014 }
bellard13eb76e2004-01-24 15:23:36 +00003015 }
3016 } else {
ths5fafdf22007-09-16 21:08:06 +00003017 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003018 !(pd & IO_MEM_ROMD)) {
aurel326c2934d2009-02-18 21:37:17 +00003019 target_phys_addr_t addr1 = addr;
bellard13eb76e2004-01-24 15:23:36 +00003020 /* I/O case */
3021 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003022 if (p)
aurel326c2934d2009-02-18 21:37:17 +00003023 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
3024 if (l >= 4 && ((addr1 & 3) == 0)) {
bellard13eb76e2004-01-24 15:23:36 +00003025 /* 32 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003026 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003027 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003028 l = 4;
aurel326c2934d2009-02-18 21:37:17 +00003029 } else if (l >= 2 && ((addr1 & 1) == 0)) {
bellard13eb76e2004-01-24 15:23:36 +00003030 /* 16 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003031 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003032 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003033 l = 2;
3034 } else {
bellard1c213d12005-09-03 10:49:04 +00003035 /* 8 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003036 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003037 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003038 l = 1;
3039 }
3040 } else {
3041 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003042 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00003043 (addr & ~TARGET_PAGE_MASK);
3044 memcpy(buf, ptr, l);
3045 }
3046 }
3047 len -= l;
3048 buf += l;
3049 addr += l;
3050 }
3051}
bellard8df1cd02005-01-28 22:37:22 +00003052
bellardd0ecd2a2006-04-23 17:14:48 +00003053/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00003054void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00003055 const uint8_t *buf, int len)
3056{
3057 int l;
3058 uint8_t *ptr;
3059 target_phys_addr_t page;
3060 unsigned long pd;
3061 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00003062
bellardd0ecd2a2006-04-23 17:14:48 +00003063 while (len > 0) {
3064 page = addr & TARGET_PAGE_MASK;
3065 l = (page + TARGET_PAGE_SIZE) - addr;
3066 if (l > len)
3067 l = len;
3068 p = phys_page_find(page >> TARGET_PAGE_BITS);
3069 if (!p) {
3070 pd = IO_MEM_UNASSIGNED;
3071 } else {
3072 pd = p->phys_offset;
3073 }
ths3b46e622007-09-17 08:09:54 +00003074
bellardd0ecd2a2006-04-23 17:14:48 +00003075 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00003076 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3077 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00003078 /* do nothing */
3079 } else {
3080 unsigned long addr1;
3081 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3082 /* ROM/RAM case */
3083 ptr = phys_ram_base + addr1;
3084 memcpy(ptr, buf, l);
3085 }
3086 len -= l;
3087 buf += l;
3088 addr += l;
3089 }
3090}
3091
aliguori6d16c2f2009-01-22 16:59:11 +00003092typedef struct {
3093 void *buffer;
3094 target_phys_addr_t addr;
3095 target_phys_addr_t len;
3096} BounceBuffer;
3097
3098static BounceBuffer bounce;
3099
aliguoriba223c22009-01-22 16:59:16 +00003100typedef struct MapClient {
3101 void *opaque;
3102 void (*callback)(void *opaque);
3103 LIST_ENTRY(MapClient) link;
3104} MapClient;
3105
3106static LIST_HEAD(map_client_list, MapClient) map_client_list
3107 = LIST_HEAD_INITIALIZER(map_client_list);
3108
3109void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
3110{
3111 MapClient *client = qemu_malloc(sizeof(*client));
3112
3113 client->opaque = opaque;
3114 client->callback = callback;
3115 LIST_INSERT_HEAD(&map_client_list, client, link);
3116 return client;
3117}
3118
3119void cpu_unregister_map_client(void *_client)
3120{
3121 MapClient *client = (MapClient *)_client;
3122
3123 LIST_REMOVE(client, link);
3124}
3125
3126static void cpu_notify_map_clients(void)
3127{
3128 MapClient *client;
3129
3130 while (!LIST_EMPTY(&map_client_list)) {
3131 client = LIST_FIRST(&map_client_list);
3132 client->callback(client->opaque);
3133 LIST_REMOVE(client, link);
3134 }
3135}
3136
aliguori6d16c2f2009-01-22 16:59:11 +00003137/* Map a physical memory region into a host virtual address.
3138 * May map a subset of the requested range, given by and returned in *plen.
3139 * May return NULL if resources needed to perform the mapping are exhausted.
3140 * Use only for reads OR writes - not for read-modify-write operations.
aliguoriba223c22009-01-22 16:59:16 +00003141 * Use cpu_register_map_client() to know when retrying the map operation is
3142 * likely to succeed.
aliguori6d16c2f2009-01-22 16:59:11 +00003143 */
3144void *cpu_physical_memory_map(target_phys_addr_t addr,
3145 target_phys_addr_t *plen,
3146 int is_write)
3147{
3148 target_phys_addr_t len = *plen;
3149 target_phys_addr_t done = 0;
3150 int l;
3151 uint8_t *ret = NULL;
3152 uint8_t *ptr;
3153 target_phys_addr_t page;
3154 unsigned long pd;
3155 PhysPageDesc *p;
3156 unsigned long addr1;
3157
3158 while (len > 0) {
3159 page = addr & TARGET_PAGE_MASK;
3160 l = (page + TARGET_PAGE_SIZE) - addr;
3161 if (l > len)
3162 l = len;
3163 p = phys_page_find(page >> TARGET_PAGE_BITS);
3164 if (!p) {
3165 pd = IO_MEM_UNASSIGNED;
3166 } else {
3167 pd = p->phys_offset;
3168 }
3169
3170 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3171 if (done || bounce.buffer) {
3172 break;
3173 }
3174 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
3175 bounce.addr = addr;
3176 bounce.len = l;
3177 if (!is_write) {
3178 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
3179 }
3180 ptr = bounce.buffer;
3181 } else {
3182 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3183 ptr = phys_ram_base + addr1;
3184 }
3185 if (!done) {
3186 ret = ptr;
3187 } else if (ret + done != ptr) {
3188 break;
3189 }
3190
3191 len -= l;
3192 addr += l;
3193 done += l;
3194 }
3195 *plen = done;
3196 return ret;
3197}
3198
3199/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
3200 * Will also mark the memory as dirty if is_write == 1. access_len gives
3201 * the amount of memory that was actually read or written by the caller.
3202 */
3203void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
3204 int is_write, target_phys_addr_t access_len)
3205{
3206 if (buffer != bounce.buffer) {
3207 if (is_write) {
3208 unsigned long addr1 = (uint8_t *)buffer - phys_ram_base;
3209 while (access_len) {
3210 unsigned l;
3211 l = TARGET_PAGE_SIZE;
3212 if (l > access_len)
3213 l = access_len;
3214 if (!cpu_physical_memory_is_dirty(addr1)) {
3215 /* invalidate code */
3216 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3217 /* set dirty bit */
3218 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3219 (0xff & ~CODE_DIRTY_FLAG);
3220 }
3221 addr1 += l;
3222 access_len -= l;
3223 }
3224 }
3225 return;
3226 }
3227 if (is_write) {
3228 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
3229 }
3230 qemu_free(bounce.buffer);
3231 bounce.buffer = NULL;
aliguoriba223c22009-01-22 16:59:16 +00003232 cpu_notify_map_clients();
aliguori6d16c2f2009-01-22 16:59:11 +00003233}
bellardd0ecd2a2006-04-23 17:14:48 +00003234
bellard8df1cd02005-01-28 22:37:22 +00003235/* warning: addr must be aligned */
3236uint32_t ldl_phys(target_phys_addr_t addr)
3237{
3238 int io_index;
3239 uint8_t *ptr;
3240 uint32_t val;
3241 unsigned long pd;
3242 PhysPageDesc *p;
3243
3244 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3245 if (!p) {
3246 pd = IO_MEM_UNASSIGNED;
3247 } else {
3248 pd = p->phys_offset;
3249 }
ths3b46e622007-09-17 08:09:54 +00003250
ths5fafdf22007-09-16 21:08:06 +00003251 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003252 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00003253 /* I/O case */
3254 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003255 if (p)
3256 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003257 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3258 } else {
3259 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003260 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00003261 (addr & ~TARGET_PAGE_MASK);
3262 val = ldl_p(ptr);
3263 }
3264 return val;
3265}
3266
bellard84b7b8e2005-11-28 21:19:04 +00003267/* warning: addr must be aligned */
3268uint64_t ldq_phys(target_phys_addr_t addr)
3269{
3270 int io_index;
3271 uint8_t *ptr;
3272 uint64_t val;
3273 unsigned long pd;
3274 PhysPageDesc *p;
3275
3276 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3277 if (!p) {
3278 pd = IO_MEM_UNASSIGNED;
3279 } else {
3280 pd = p->phys_offset;
3281 }
ths3b46e622007-09-17 08:09:54 +00003282
bellard2a4188a2006-06-25 21:54:59 +00003283 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3284 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00003285 /* I/O case */
3286 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003287 if (p)
3288 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard84b7b8e2005-11-28 21:19:04 +00003289#ifdef TARGET_WORDS_BIGENDIAN
3290 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3291 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3292#else
3293 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3294 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3295#endif
3296 } else {
3297 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003298 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00003299 (addr & ~TARGET_PAGE_MASK);
3300 val = ldq_p(ptr);
3301 }
3302 return val;
3303}
3304
bellardaab33092005-10-30 20:48:42 +00003305/* XXX: optimize */
3306uint32_t ldub_phys(target_phys_addr_t addr)
3307{
3308 uint8_t val;
3309 cpu_physical_memory_read(addr, &val, 1);
3310 return val;
3311}
3312
3313/* XXX: optimize */
3314uint32_t lduw_phys(target_phys_addr_t addr)
3315{
3316 uint16_t val;
3317 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3318 return tswap16(val);
3319}
3320
bellard8df1cd02005-01-28 22:37:22 +00003321/* warning: addr must be aligned. The ram page is not masked as dirty
3322 and the code inside is not invalidated. It is useful if the dirty
3323 bits are used to track modified PTEs */
3324void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
3325{
3326 int io_index;
3327 uint8_t *ptr;
3328 unsigned long pd;
3329 PhysPageDesc *p;
3330
3331 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3332 if (!p) {
3333 pd = IO_MEM_UNASSIGNED;
3334 } else {
3335 pd = p->phys_offset;
3336 }
ths3b46e622007-09-17 08:09:54 +00003337
bellard3a7d9292005-08-21 09:26:42 +00003338 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003339 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003340 if (p)
3341 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003342 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3343 } else {
aliguori74576192008-10-06 14:02:03 +00003344 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3345 ptr = phys_ram_base + addr1;
bellard8df1cd02005-01-28 22:37:22 +00003346 stl_p(ptr, val);
aliguori74576192008-10-06 14:02:03 +00003347
3348 if (unlikely(in_migration)) {
3349 if (!cpu_physical_memory_is_dirty(addr1)) {
3350 /* invalidate code */
3351 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3352 /* set dirty bit */
3353 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3354 (0xff & ~CODE_DIRTY_FLAG);
3355 }
3356 }
bellard8df1cd02005-01-28 22:37:22 +00003357 }
3358}
3359
j_mayerbc98a7e2007-04-04 07:55:12 +00003360void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
3361{
3362 int io_index;
3363 uint8_t *ptr;
3364 unsigned long pd;
3365 PhysPageDesc *p;
3366
3367 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3368 if (!p) {
3369 pd = IO_MEM_UNASSIGNED;
3370 } else {
3371 pd = p->phys_offset;
3372 }
ths3b46e622007-09-17 08:09:54 +00003373
j_mayerbc98a7e2007-04-04 07:55:12 +00003374 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3375 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003376 if (p)
3377 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
j_mayerbc98a7e2007-04-04 07:55:12 +00003378#ifdef TARGET_WORDS_BIGENDIAN
3379 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3380 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3381#else
3382 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3383 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3384#endif
3385 } else {
ths5fafdf22007-09-16 21:08:06 +00003386 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00003387 (addr & ~TARGET_PAGE_MASK);
3388 stq_p(ptr, val);
3389 }
3390}
3391
bellard8df1cd02005-01-28 22:37:22 +00003392/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00003393void stl_phys(target_phys_addr_t addr, uint32_t val)
3394{
3395 int io_index;
3396 uint8_t *ptr;
3397 unsigned long pd;
3398 PhysPageDesc *p;
3399
3400 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3401 if (!p) {
3402 pd = IO_MEM_UNASSIGNED;
3403 } else {
3404 pd = p->phys_offset;
3405 }
ths3b46e622007-09-17 08:09:54 +00003406
bellard3a7d9292005-08-21 09:26:42 +00003407 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003408 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003409 if (p)
3410 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003411 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3412 } else {
3413 unsigned long addr1;
3414 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3415 /* RAM case */
3416 ptr = phys_ram_base + addr1;
3417 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003418 if (!cpu_physical_memory_is_dirty(addr1)) {
3419 /* invalidate code */
3420 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3421 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003422 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3423 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003424 }
bellard8df1cd02005-01-28 22:37:22 +00003425 }
3426}
3427
bellardaab33092005-10-30 20:48:42 +00003428/* XXX: optimize */
3429void stb_phys(target_phys_addr_t addr, uint32_t val)
3430{
3431 uint8_t v = val;
3432 cpu_physical_memory_write(addr, &v, 1);
3433}
3434
3435/* XXX: optimize */
3436void stw_phys(target_phys_addr_t addr, uint32_t val)
3437{
3438 uint16_t v = tswap16(val);
3439 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3440}
3441
3442/* XXX: optimize */
3443void stq_phys(target_phys_addr_t addr, uint64_t val)
3444{
3445 val = tswap64(val);
3446 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3447}
3448
bellard13eb76e2004-01-24 15:23:36 +00003449#endif
3450
aliguori5e2972f2009-03-28 17:51:36 +00003451/* virtual memory access for debug (includes writing to ROM) */
ths5fafdf22007-09-16 21:08:06 +00003452int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003453 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003454{
3455 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003456 target_phys_addr_t phys_addr;
3457 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003458
3459 while (len > 0) {
3460 page = addr & TARGET_PAGE_MASK;
3461 phys_addr = cpu_get_phys_page_debug(env, page);
3462 /* if no physical page mapped, return an error */
3463 if (phys_addr == -1)
3464 return -1;
3465 l = (page + TARGET_PAGE_SIZE) - addr;
3466 if (l > len)
3467 l = len;
aliguori5e2972f2009-03-28 17:51:36 +00003468 phys_addr += (addr & ~TARGET_PAGE_MASK);
3469#if !defined(CONFIG_USER_ONLY)
3470 if (is_write)
3471 cpu_physical_memory_write_rom(phys_addr, buf, l);
3472 else
3473#endif
3474 cpu_physical_memory_rw(phys_addr, buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003475 len -= l;
3476 buf += l;
3477 addr += l;
3478 }
3479 return 0;
3480}
3481
pbrook2e70f6e2008-06-29 01:03:05 +00003482/* in deterministic execution mode, instructions doing device I/Os
3483 must be at the end of the TB */
3484void cpu_io_recompile(CPUState *env, void *retaddr)
3485{
3486 TranslationBlock *tb;
3487 uint32_t n, cflags;
3488 target_ulong pc, cs_base;
3489 uint64_t flags;
3490
3491 tb = tb_find_pc((unsigned long)retaddr);
3492 if (!tb) {
3493 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3494 retaddr);
3495 }
3496 n = env->icount_decr.u16.low + tb->icount;
3497 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3498 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003499 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003500 n = n - env->icount_decr.u16.low;
3501 /* Generate a new TB ending on the I/O insn. */
3502 n++;
3503 /* On MIPS and SH, delay slot instructions can only be restarted if
3504 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003505 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003506 branch. */
3507#if defined(TARGET_MIPS)
3508 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3509 env->active_tc.PC -= 4;
3510 env->icount_decr.u16.low++;
3511 env->hflags &= ~MIPS_HFLAG_BMASK;
3512 }
3513#elif defined(TARGET_SH4)
3514 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3515 && n > 1) {
3516 env->pc -= 2;
3517 env->icount_decr.u16.low++;
3518 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3519 }
3520#endif
3521 /* This should never happen. */
3522 if (n > CF_COUNT_MASK)
3523 cpu_abort(env, "TB too big during recompile");
3524
3525 cflags = n | CF_LAST_IO;
3526 pc = tb->pc;
3527 cs_base = tb->cs_base;
3528 flags = tb->flags;
3529 tb_phys_invalidate(tb, -1);
3530 /* FIXME: In theory this could raise an exception. In practice
3531 we have already translated the block once so it's probably ok. */
3532 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003533 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003534 the first in the TB) then we end up generating a whole new TB and
3535 repeating the fault, which is horribly inefficient.
3536 Better would be to execute just this insn uncached, or generate a
3537 second new TB. */
3538 cpu_resume_from_signal(env, NULL);
3539}
3540
bellarde3db7222005-01-26 22:00:47 +00003541void dump_exec_info(FILE *f,
3542 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3543{
3544 int i, target_code_size, max_target_code_size;
3545 int direct_jmp_count, direct_jmp2_count, cross_page;
3546 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003547
bellarde3db7222005-01-26 22:00:47 +00003548 target_code_size = 0;
3549 max_target_code_size = 0;
3550 cross_page = 0;
3551 direct_jmp_count = 0;
3552 direct_jmp2_count = 0;
3553 for(i = 0; i < nb_tbs; i++) {
3554 tb = &tbs[i];
3555 target_code_size += tb->size;
3556 if (tb->size > max_target_code_size)
3557 max_target_code_size = tb->size;
3558 if (tb->page_addr[1] != -1)
3559 cross_page++;
3560 if (tb->tb_next_offset[0] != 0xffff) {
3561 direct_jmp_count++;
3562 if (tb->tb_next_offset[1] != 0xffff) {
3563 direct_jmp2_count++;
3564 }
3565 }
3566 }
3567 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003568 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003569 cpu_fprintf(f, "gen code size %ld/%ld\n",
3570 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3571 cpu_fprintf(f, "TB count %d/%d\n",
3572 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003573 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003574 nb_tbs ? target_code_size / nb_tbs : 0,
3575 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003576 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003577 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3578 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003579 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3580 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003581 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3582 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003583 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003584 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3585 direct_jmp2_count,
3586 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003587 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003588 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3589 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3590 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003591 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003592}
3593
ths5fafdf22007-09-16 21:08:06 +00003594#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003595
3596#define MMUSUFFIX _cmmu
3597#define GETPC() NULL
3598#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003599#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003600
3601#define SHIFT 0
3602#include "softmmu_template.h"
3603
3604#define SHIFT 1
3605#include "softmmu_template.h"
3606
3607#define SHIFT 2
3608#include "softmmu_template.h"
3609
3610#define SHIFT 3
3611#include "softmmu_template.h"
3612
3613#undef env
3614
3615#endif