blob: 902031c48dfeab4ddfbd09b607a97b6be8c64779 [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
66#define MMAP_AREA_START 0x00000000
67#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000068
bellard108c49b2005-07-24 12:55:09 +000069#if defined(TARGET_SPARC64)
70#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000071#elif defined(TARGET_SPARC)
72#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000073#elif defined(TARGET_ALPHA)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
75#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000076#elif defined(TARGET_PPC64)
77#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000078#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
79#define TARGET_PHYS_ADDR_SPACE_BITS 42
80#elif defined(TARGET_I386) && !defined(USE_KQEMU)
81#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000082#else
83/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
84#define TARGET_PHYS_ADDR_SPACE_BITS 32
85#endif
86
blueswir1bdaf78e2008-10-04 07:24:27 +000087static TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000088int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000089TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
blueswir1bdaf78e2008-10-04 07:24:27 +000090static int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000091/* any access to the tbs or the page table must use this lock */
92spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000093
blueswir1141ac462008-07-26 15:05:57 +000094#if defined(__arm__) || defined(__sparc_v9__)
95/* The prologue must be reachable with a direct jump. ARM and Sparc64
96 have limited branch ranges (possibly also PPC) so place it in a
blueswir1d03d8602008-07-10 17:21:31 +000097 section close to code segment. */
98#define code_gen_section \
99 __attribute__((__section__(".gen_code"))) \
100 __attribute__((aligned (32)))
101#else
102#define code_gen_section \
103 __attribute__((aligned (32)))
104#endif
105
106uint8_t code_gen_prologue[1024] code_gen_section;
blueswir1bdaf78e2008-10-04 07:24:27 +0000107static uint8_t *code_gen_buffer;
108static unsigned long code_gen_buffer_size;
bellard26a5f132008-05-28 12:30:31 +0000109/* threshold to flush the translated code buffer */
blueswir1bdaf78e2008-10-04 07:24:27 +0000110static unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000111uint8_t *code_gen_ptr;
112
pbrooke2eef172008-06-08 01:09:01 +0000113#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +0000114ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000115int phys_ram_fd;
116uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000117uint8_t *phys_ram_dirty;
aliguori74576192008-10-06 14:02:03 +0000118static int in_migration;
bellarde9a1ab12007-02-08 23:08:38 +0000119static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000120#endif
bellard9fa3e852004-01-04 18:06:42 +0000121
bellard6a00d602005-11-21 23:25:50 +0000122CPUState *first_cpu;
123/* current CPU in the current thread. It is only valid inside
124 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000125CPUState *cpu_single_env;
pbrook2e70f6e2008-06-29 01:03:05 +0000126/* 0 = Do not count executed instructions.
thsbf20dc02008-06-30 17:22:19 +0000127 1 = Precise instruction counting.
pbrook2e70f6e2008-06-29 01:03:05 +0000128 2 = Adaptive rate instruction counting. */
129int use_icount = 0;
130/* Current instruction counter. While executing translated code this may
131 include some instructions that have not yet been executed. */
132int64_t qemu_icount;
bellard6a00d602005-11-21 23:25:50 +0000133
bellard54936002003-05-13 00:25:15 +0000134typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000135 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000136 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000137 /* in order to optimize self modifying code, we count the number
138 of lookups we do to a given page to use a bitmap */
139 unsigned int code_write_count;
140 uint8_t *code_bitmap;
141#if defined(CONFIG_USER_ONLY)
142 unsigned long flags;
143#endif
bellard54936002003-05-13 00:25:15 +0000144} PageDesc;
145
bellard92e873b2004-05-21 14:52:29 +0000146typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000147 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000148 ram_addr_t phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +0000149 ram_addr_t region_offset;
bellard92e873b2004-05-21 14:52:29 +0000150} PhysPageDesc;
151
bellard54936002003-05-13 00:25:15 +0000152#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000153#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
154/* XXX: this is a temporary hack for alpha target.
155 * In the future, this is to be replaced by a multi-level table
156 * to actually be able to handle the complete 64 bits address space.
157 */
158#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
159#else
aurel3203875442008-04-22 20:45:18 +0000160#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000161#endif
bellard54936002003-05-13 00:25:15 +0000162
163#define L1_SIZE (1 << L1_BITS)
164#define L2_SIZE (1 << L2_BITS)
165
bellard83fb7ad2004-07-05 21:25:26 +0000166unsigned long qemu_real_host_page_size;
167unsigned long qemu_host_page_bits;
168unsigned long qemu_host_page_size;
169unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000170
bellard92e873b2004-05-21 14:52:29 +0000171/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000172static PageDesc *l1_map[L1_SIZE];
blueswir1bdaf78e2008-10-04 07:24:27 +0000173static PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000174
pbrooke2eef172008-06-08 01:09:01 +0000175#if !defined(CONFIG_USER_ONLY)
176static void io_mem_init(void);
177
bellard33417e72003-08-10 21:47:01 +0000178/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000179CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
180CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000181void *io_mem_opaque[IO_MEM_NB_ENTRIES];
aliguori88715652009-02-11 15:20:58 +0000182char io_mem_used[IO_MEM_NB_ENTRIES];
pbrook6658ffb2007-03-16 23:58:11 +0000183static int io_mem_watch;
184#endif
bellard33417e72003-08-10 21:47:01 +0000185
bellard34865132003-10-05 14:28:56 +0000186/* log support */
blueswir1d9b630f2008-10-05 09:57:08 +0000187static const char *logfilename = "/tmp/qemu.log";
bellard34865132003-10-05 14:28:56 +0000188FILE *logfile;
189int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000190static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000191
bellarde3db7222005-01-26 22:00:47 +0000192/* statistics */
193static int tlb_flush_count;
194static int tb_flush_count;
195static int tb_phys_invalidate_count;
196
blueswir1db7b5422007-05-26 17:36:03 +0000197#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
198typedef struct subpage_t {
199 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000200 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
201 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
202 void *opaque[TARGET_PAGE_SIZE][2][4];
pbrook8da3ff12008-12-01 18:59:50 +0000203 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000204} subpage_t;
205
bellard7cb69ca2008-05-10 10:55:51 +0000206#ifdef _WIN32
207static void map_exec(void *addr, long size)
208{
209 DWORD old_protect;
210 VirtualProtect(addr, size,
211 PAGE_EXECUTE_READWRITE, &old_protect);
212
213}
214#else
215static void map_exec(void *addr, long size)
216{
bellard43694152008-05-29 09:35:57 +0000217 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000218
bellard43694152008-05-29 09:35:57 +0000219 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000220 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000221 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000222
223 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000224 end += page_size - 1;
225 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000226
227 mprotect((void *)start, end - start,
228 PROT_READ | PROT_WRITE | PROT_EXEC);
229}
230#endif
231
bellardb346ff42003-06-15 20:05:50 +0000232static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000233{
bellard83fb7ad2004-07-05 21:25:26 +0000234 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000235 TARGET_PAGE_SIZE */
aliguoric2b48b62008-11-11 22:06:42 +0000236#ifdef _WIN32
237 {
238 SYSTEM_INFO system_info;
239
240 GetSystemInfo(&system_info);
241 qemu_real_host_page_size = system_info.dwPageSize;
242 }
243#else
244 qemu_real_host_page_size = getpagesize();
245#endif
bellard83fb7ad2004-07-05 21:25:26 +0000246 if (qemu_host_page_size == 0)
247 qemu_host_page_size = qemu_real_host_page_size;
248 if (qemu_host_page_size < TARGET_PAGE_SIZE)
249 qemu_host_page_size = TARGET_PAGE_SIZE;
250 qemu_host_page_bits = 0;
251 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
252 qemu_host_page_bits++;
253 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000254 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
255 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000256
257#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
258 {
259 long long startaddr, endaddr;
260 FILE *f;
261 int n;
262
pbrookc8a706f2008-06-02 16:16:42 +0000263 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000264 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000265 f = fopen("/proc/self/maps", "r");
266 if (f) {
267 do {
268 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
269 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000270 startaddr = MIN(startaddr,
271 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
272 endaddr = MIN(endaddr,
273 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000274 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000275 TARGET_PAGE_ALIGN(endaddr),
276 PAGE_RESERVED);
277 }
278 } while (!feof(f));
279 fclose(f);
280 }
pbrookc8a706f2008-06-02 16:16:42 +0000281 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000282 }
283#endif
bellard54936002003-05-13 00:25:15 +0000284}
285
aliguori434929b2008-09-15 15:56:30 +0000286static inline PageDesc **page_l1_map(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000287{
pbrook17e23772008-06-09 13:47:45 +0000288#if TARGET_LONG_BITS > 32
289 /* Host memory outside guest VM. For 32-bit targets we have already
290 excluded high addresses. */
thsd8173e02008-08-29 13:10:00 +0000291 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
pbrook17e23772008-06-09 13:47:45 +0000292 return NULL;
293#endif
aliguori434929b2008-09-15 15:56:30 +0000294 return &l1_map[index >> L2_BITS];
295}
296
297static inline PageDesc *page_find_alloc(target_ulong index)
298{
299 PageDesc **lp, *p;
300 lp = page_l1_map(index);
301 if (!lp)
302 return NULL;
303
bellard54936002003-05-13 00:25:15 +0000304 p = *lp;
305 if (!p) {
306 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000307#if defined(CONFIG_USER_ONLY)
pbrook17e23772008-06-09 13:47:45 +0000308 size_t len = sizeof(PageDesc) * L2_SIZE;
309 /* Don't use qemu_malloc because it may recurse. */
310 p = mmap(0, len, PROT_READ | PROT_WRITE,
311 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000312 *lp = p;
aurel32fb1c2cd2008-12-08 18:12:26 +0000313 if (h2g_valid(p)) {
314 unsigned long addr = h2g(p);
pbrook17e23772008-06-09 13:47:45 +0000315 page_set_flags(addr & TARGET_PAGE_MASK,
316 TARGET_PAGE_ALIGN(addr + len),
317 PAGE_RESERVED);
318 }
319#else
320 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
321 *lp = p;
322#endif
bellard54936002003-05-13 00:25:15 +0000323 }
324 return p + (index & (L2_SIZE - 1));
325}
326
aurel3200f82b82008-04-27 21:12:55 +0000327static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000328{
aliguori434929b2008-09-15 15:56:30 +0000329 PageDesc **lp, *p;
330 lp = page_l1_map(index);
331 if (!lp)
332 return NULL;
bellard54936002003-05-13 00:25:15 +0000333
aliguori434929b2008-09-15 15:56:30 +0000334 p = *lp;
bellard54936002003-05-13 00:25:15 +0000335 if (!p)
336 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000337 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000338}
339
bellard108c49b2005-07-24 12:55:09 +0000340static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000341{
bellard108c49b2005-07-24 12:55:09 +0000342 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000343 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000344
bellard108c49b2005-07-24 12:55:09 +0000345 p = (void **)l1_phys_map;
346#if TARGET_PHYS_ADDR_SPACE_BITS > 32
347
348#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
349#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
350#endif
351 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000352 p = *lp;
353 if (!p) {
354 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000355 if (!alloc)
356 return NULL;
357 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
358 memset(p, 0, sizeof(void *) * L1_SIZE);
359 *lp = p;
360 }
361#endif
362 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000363 pd = *lp;
364 if (!pd) {
365 int i;
bellard108c49b2005-07-24 12:55:09 +0000366 /* allocate if not found */
367 if (!alloc)
368 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000369 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
370 *lp = pd;
pbrook67c4d232009-02-23 13:16:07 +0000371 for (i = 0; i < L2_SIZE; i++) {
pbrooke3f4e2a2006-04-08 20:02:06 +0000372 pd[i].phys_offset = IO_MEM_UNASSIGNED;
pbrook67c4d232009-02-23 13:16:07 +0000373 pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
374 }
bellard92e873b2004-05-21 14:52:29 +0000375 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000376 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000377}
378
bellard108c49b2005-07-24 12:55:09 +0000379static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000380{
bellard108c49b2005-07-24 12:55:09 +0000381 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000382}
383
bellard9fa3e852004-01-04 18:06:42 +0000384#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000385static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000386static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000387 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000388#define mmap_lock() do { } while(0)
389#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000390#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000391
bellard43694152008-05-29 09:35:57 +0000392#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
393
394#if defined(CONFIG_USER_ONLY)
395/* Currently it is not recommanded to allocate big chunks of data in
396 user mode. It will change when a dedicated libc will be used */
397#define USE_STATIC_CODE_GEN_BUFFER
398#endif
399
400#ifdef USE_STATIC_CODE_GEN_BUFFER
401static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
402#endif
403
blueswir18fcd3692008-08-17 20:26:25 +0000404static void code_gen_alloc(unsigned long tb_size)
bellard26a5f132008-05-28 12:30:31 +0000405{
bellard43694152008-05-29 09:35:57 +0000406#ifdef USE_STATIC_CODE_GEN_BUFFER
407 code_gen_buffer = static_code_gen_buffer;
408 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
409 map_exec(code_gen_buffer, code_gen_buffer_size);
410#else
bellard26a5f132008-05-28 12:30:31 +0000411 code_gen_buffer_size = tb_size;
412 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000413#if defined(CONFIG_USER_ONLY)
414 /* in user mode, phys_ram_size is not meaningful */
415 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
416#else
bellard26a5f132008-05-28 12:30:31 +0000417 /* XXX: needs ajustments */
aliguori174a9a12008-09-24 14:10:36 +0000418 code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000419#endif
bellard26a5f132008-05-28 12:30:31 +0000420 }
421 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
422 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
423 /* The code gen buffer location may have constraints depending on
424 the host cpu and OS */
425#if defined(__linux__)
426 {
427 int flags;
blueswir1141ac462008-07-26 15:05:57 +0000428 void *start = NULL;
429
bellard26a5f132008-05-28 12:30:31 +0000430 flags = MAP_PRIVATE | MAP_ANONYMOUS;
431#if defined(__x86_64__)
432 flags |= MAP_32BIT;
433 /* Cannot map more than that */
434 if (code_gen_buffer_size > (800 * 1024 * 1024))
435 code_gen_buffer_size = (800 * 1024 * 1024);
blueswir1141ac462008-07-26 15:05:57 +0000436#elif defined(__sparc_v9__)
437 // Map the buffer below 2G, so we can use direct calls and branches
438 flags |= MAP_FIXED;
439 start = (void *) 0x60000000UL;
440 if (code_gen_buffer_size > (512 * 1024 * 1024))
441 code_gen_buffer_size = (512 * 1024 * 1024);
balrog1cb06612008-12-01 02:10:17 +0000442#elif defined(__arm__)
balrog63d41242008-12-01 02:19:41 +0000443 /* Map the buffer below 32M, so we can use direct calls and branches */
balrog1cb06612008-12-01 02:10:17 +0000444 flags |= MAP_FIXED;
445 start = (void *) 0x01000000UL;
446 if (code_gen_buffer_size > 16 * 1024 * 1024)
447 code_gen_buffer_size = 16 * 1024 * 1024;
bellard26a5f132008-05-28 12:30:31 +0000448#endif
blueswir1141ac462008-07-26 15:05:57 +0000449 code_gen_buffer = mmap(start, code_gen_buffer_size,
450 PROT_WRITE | PROT_READ | PROT_EXEC,
bellard26a5f132008-05-28 12:30:31 +0000451 flags, -1, 0);
452 if (code_gen_buffer == MAP_FAILED) {
453 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
454 exit(1);
455 }
456 }
aliguori06e67a82008-09-27 15:32:41 +0000457#elif defined(__FreeBSD__)
458 {
459 int flags;
460 void *addr = NULL;
461 flags = MAP_PRIVATE | MAP_ANONYMOUS;
462#if defined(__x86_64__)
463 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
464 * 0x40000000 is free */
465 flags |= MAP_FIXED;
466 addr = (void *)0x40000000;
467 /* Cannot map more than that */
468 if (code_gen_buffer_size > (800 * 1024 * 1024))
469 code_gen_buffer_size = (800 * 1024 * 1024);
470#endif
471 code_gen_buffer = mmap(addr, code_gen_buffer_size,
472 PROT_WRITE | PROT_READ | PROT_EXEC,
473 flags, -1, 0);
474 if (code_gen_buffer == MAP_FAILED) {
475 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
476 exit(1);
477 }
478 }
bellard26a5f132008-05-28 12:30:31 +0000479#else
480 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
bellard26a5f132008-05-28 12:30:31 +0000481 map_exec(code_gen_buffer, code_gen_buffer_size);
482#endif
bellard43694152008-05-29 09:35:57 +0000483#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000484 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
485 code_gen_buffer_max_size = code_gen_buffer_size -
486 code_gen_max_block_size();
487 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
488 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
489}
490
491/* Must be called before using the QEMU cpus. 'tb_size' is the size
492 (in bytes) allocated to the translation buffer. Zero means default
493 size. */
494void cpu_exec_init_all(unsigned long tb_size)
495{
bellard26a5f132008-05-28 12:30:31 +0000496 cpu_gen_init();
497 code_gen_alloc(tb_size);
498 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000499 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000500#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000501 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000502#endif
bellard26a5f132008-05-28 12:30:31 +0000503}
504
pbrook9656f322008-07-01 20:01:19 +0000505#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
506
507#define CPU_COMMON_SAVE_VERSION 1
508
509static void cpu_common_save(QEMUFile *f, void *opaque)
510{
511 CPUState *env = opaque;
512
513 qemu_put_be32s(f, &env->halted);
514 qemu_put_be32s(f, &env->interrupt_request);
515}
516
517static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
518{
519 CPUState *env = opaque;
520
521 if (version_id != CPU_COMMON_SAVE_VERSION)
522 return -EINVAL;
523
524 qemu_get_be32s(f, &env->halted);
pbrook75f482a2008-07-01 21:53:33 +0000525 qemu_get_be32s(f, &env->interrupt_request);
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
bellard6a00d602005-11-21 23:25:50 +0000537 env->next_cpu = NULL;
538 penv = &first_cpu;
539 cpu_index = 0;
540 while (*penv != NULL) {
541 penv = (CPUState **)&(*penv)->next_cpu;
542 cpu_index++;
543 }
544 env->cpu_index = cpu_index;
aliguoric0ce9982008-11-25 22:13:57 +0000545 TAILQ_INIT(&env->breakpoints);
546 TAILQ_INIT(&env->watchpoints);
bellard6a00d602005-11-21 23:25:50 +0000547 *penv = env;
pbrookb3c77242008-06-30 16:31:04 +0000548#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
pbrook9656f322008-07-01 20:01:19 +0000549 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
550 cpu_common_save, cpu_common_load, env);
pbrookb3c77242008-06-30 16:31:04 +0000551 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
552 cpu_save, cpu_load, env);
553#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000554}
555
bellard9fa3e852004-01-04 18:06:42 +0000556static inline void invalidate_page_bitmap(PageDesc *p)
557{
558 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000559 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000560 p->code_bitmap = NULL;
561 }
562 p->code_write_count = 0;
563}
564
bellardfd6ce8f2003-05-14 19:00:11 +0000565/* set to NULL all the 'first_tb' fields in all PageDescs */
566static void page_flush_tb(void)
567{
568 int i, j;
569 PageDesc *p;
570
571 for(i = 0; i < L1_SIZE; i++) {
572 p = l1_map[i];
573 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000574 for(j = 0; j < L2_SIZE; j++) {
575 p->first_tb = NULL;
576 invalidate_page_bitmap(p);
577 p++;
578 }
bellardfd6ce8f2003-05-14 19:00:11 +0000579 }
580 }
581}
582
583/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000584/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000585void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000586{
bellard6a00d602005-11-21 23:25:50 +0000587 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000588#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000589 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
590 (unsigned long)(code_gen_ptr - code_gen_buffer),
591 nb_tbs, nb_tbs > 0 ?
592 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000593#endif
bellard26a5f132008-05-28 12:30:31 +0000594 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000595 cpu_abort(env1, "Internal error: code buffer overflow\n");
596
bellardfd6ce8f2003-05-14 19:00:11 +0000597 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000598
bellard6a00d602005-11-21 23:25:50 +0000599 for(env = first_cpu; env != NULL; env = env->next_cpu) {
600 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
601 }
bellard9fa3e852004-01-04 18:06:42 +0000602
bellard8a8a6082004-10-03 13:36:49 +0000603 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000604 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000605
bellardfd6ce8f2003-05-14 19:00:11 +0000606 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000607 /* XXX: flush processor icache at this point if cache flush is
608 expensive */
bellarde3db7222005-01-26 22:00:47 +0000609 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000610}
611
612#ifdef DEBUG_TB_CHECK
613
j_mayerbc98a7e2007-04-04 07:55:12 +0000614static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000615{
616 TranslationBlock *tb;
617 int i;
618 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000619 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
620 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000621 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
622 address >= tb->pc + tb->size)) {
623 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000624 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000625 }
626 }
627 }
628}
629
630/* verify that all the pages have correct rights for code */
631static void tb_page_check(void)
632{
633 TranslationBlock *tb;
634 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000635
pbrook99773bd2006-04-16 15:14:59 +0000636 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
637 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000638 flags1 = page_get_flags(tb->pc);
639 flags2 = page_get_flags(tb->pc + tb->size - 1);
640 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
641 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000642 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000643 }
644 }
645 }
646}
647
blueswir1bdaf78e2008-10-04 07:24:27 +0000648static void tb_jmp_check(TranslationBlock *tb)
bellardd4e81642003-05-25 16:46:15 +0000649{
650 TranslationBlock *tb1;
651 unsigned int n1;
652
653 /* suppress any remaining jumps to this TB */
654 tb1 = tb->jmp_first;
655 for(;;) {
656 n1 = (long)tb1 & 3;
657 tb1 = (TranslationBlock *)((long)tb1 & ~3);
658 if (n1 == 2)
659 break;
660 tb1 = tb1->jmp_next[n1];
661 }
662 /* check end of list */
663 if (tb1 != tb) {
664 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
665 }
666}
667
bellardfd6ce8f2003-05-14 19:00:11 +0000668#endif
669
670/* invalidate one TB */
671static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
672 int next_offset)
673{
674 TranslationBlock *tb1;
675 for(;;) {
676 tb1 = *ptb;
677 if (tb1 == tb) {
678 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
679 break;
680 }
681 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
682 }
683}
684
bellard9fa3e852004-01-04 18:06:42 +0000685static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
686{
687 TranslationBlock *tb1;
688 unsigned int n1;
689
690 for(;;) {
691 tb1 = *ptb;
692 n1 = (long)tb1 & 3;
693 tb1 = (TranslationBlock *)((long)tb1 & ~3);
694 if (tb1 == tb) {
695 *ptb = tb1->page_next[n1];
696 break;
697 }
698 ptb = &tb1->page_next[n1];
699 }
700}
701
bellardd4e81642003-05-25 16:46:15 +0000702static inline void tb_jmp_remove(TranslationBlock *tb, int n)
703{
704 TranslationBlock *tb1, **ptb;
705 unsigned int n1;
706
707 ptb = &tb->jmp_next[n];
708 tb1 = *ptb;
709 if (tb1) {
710 /* find tb(n) in circular list */
711 for(;;) {
712 tb1 = *ptb;
713 n1 = (long)tb1 & 3;
714 tb1 = (TranslationBlock *)((long)tb1 & ~3);
715 if (n1 == n && tb1 == tb)
716 break;
717 if (n1 == 2) {
718 ptb = &tb1->jmp_first;
719 } else {
720 ptb = &tb1->jmp_next[n1];
721 }
722 }
723 /* now we can suppress tb(n) from the list */
724 *ptb = tb->jmp_next[n];
725
726 tb->jmp_next[n] = NULL;
727 }
728}
729
730/* reset the jump entry 'n' of a TB so that it is not chained to
731 another TB */
732static inline void tb_reset_jump(TranslationBlock *tb, int n)
733{
734 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
735}
736
pbrook2e70f6e2008-06-29 01:03:05 +0000737void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000738{
bellard6a00d602005-11-21 23:25:50 +0000739 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000740 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000741 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000742 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000743 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000744
bellard9fa3e852004-01-04 18:06:42 +0000745 /* remove the TB from the hash list */
746 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
747 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000748 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000749 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000750
bellard9fa3e852004-01-04 18:06:42 +0000751 /* remove the TB from the page list */
752 if (tb->page_addr[0] != page_addr) {
753 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
754 tb_page_remove(&p->first_tb, tb);
755 invalidate_page_bitmap(p);
756 }
757 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
758 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
759 tb_page_remove(&p->first_tb, tb);
760 invalidate_page_bitmap(p);
761 }
762
bellard8a40a182005-11-20 10:35:40 +0000763 tb_invalidated_flag = 1;
764
765 /* remove the TB from the hash list */
766 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000767 for(env = first_cpu; env != NULL; env = env->next_cpu) {
768 if (env->tb_jmp_cache[h] == tb)
769 env->tb_jmp_cache[h] = NULL;
770 }
bellard8a40a182005-11-20 10:35:40 +0000771
772 /* suppress this TB from the two jump lists */
773 tb_jmp_remove(tb, 0);
774 tb_jmp_remove(tb, 1);
775
776 /* suppress any remaining jumps to this TB */
777 tb1 = tb->jmp_first;
778 for(;;) {
779 n1 = (long)tb1 & 3;
780 if (n1 == 2)
781 break;
782 tb1 = (TranslationBlock *)((long)tb1 & ~3);
783 tb2 = tb1->jmp_next[n1];
784 tb_reset_jump(tb1, n1);
785 tb1->jmp_next[n1] = NULL;
786 tb1 = tb2;
787 }
788 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
789
bellarde3db7222005-01-26 22:00:47 +0000790 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000791}
792
793static inline void set_bits(uint8_t *tab, int start, int len)
794{
795 int end, mask, end1;
796
797 end = start + len;
798 tab += start >> 3;
799 mask = 0xff << (start & 7);
800 if ((start & ~7) == (end & ~7)) {
801 if (start < end) {
802 mask &= ~(0xff << (end & 7));
803 *tab |= mask;
804 }
805 } else {
806 *tab++ |= mask;
807 start = (start + 8) & ~7;
808 end1 = end & ~7;
809 while (start < end1) {
810 *tab++ = 0xff;
811 start += 8;
812 }
813 if (start < end) {
814 mask = ~(0xff << (end & 7));
815 *tab |= mask;
816 }
817 }
818}
819
820static void build_page_bitmap(PageDesc *p)
821{
822 int n, tb_start, tb_end;
823 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000824
pbrookb2a70812008-06-09 13:57:23 +0000825 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000826
827 tb = p->first_tb;
828 while (tb != NULL) {
829 n = (long)tb & 3;
830 tb = (TranslationBlock *)((long)tb & ~3);
831 /* NOTE: this is subtle as a TB may span two physical pages */
832 if (n == 0) {
833 /* NOTE: tb_end may be after the end of the page, but
834 it is not a problem */
835 tb_start = tb->pc & ~TARGET_PAGE_MASK;
836 tb_end = tb_start + tb->size;
837 if (tb_end > TARGET_PAGE_SIZE)
838 tb_end = TARGET_PAGE_SIZE;
839 } else {
840 tb_start = 0;
841 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
842 }
843 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
844 tb = tb->page_next[n];
845 }
846}
847
pbrook2e70f6e2008-06-29 01:03:05 +0000848TranslationBlock *tb_gen_code(CPUState *env,
849 target_ulong pc, target_ulong cs_base,
850 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000851{
852 TranslationBlock *tb;
853 uint8_t *tc_ptr;
854 target_ulong phys_pc, phys_page2, virt_page2;
855 int code_gen_size;
856
bellardc27004e2005-01-03 23:35:10 +0000857 phys_pc = get_phys_addr_code(env, pc);
858 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000859 if (!tb) {
860 /* flush must be done */
861 tb_flush(env);
862 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000863 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000864 /* Don't forget to invalidate previous TB info. */
865 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000866 }
867 tc_ptr = code_gen_ptr;
868 tb->tc_ptr = tc_ptr;
869 tb->cs_base = cs_base;
870 tb->flags = flags;
871 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000872 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000873 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 +0000874
bellardd720b932004-04-25 17:57:43 +0000875 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000876 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000877 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000878 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000879 phys_page2 = get_phys_addr_code(env, virt_page2);
880 }
881 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000882 return tb;
bellardd720b932004-04-25 17:57:43 +0000883}
ths3b46e622007-09-17 08:09:54 +0000884
bellard9fa3e852004-01-04 18:06:42 +0000885/* invalidate all TBs which intersect with the target physical page
886 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000887 the same physical page. 'is_cpu_write_access' should be true if called
888 from a real cpu write access: the virtual CPU will exit the current
889 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000890void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000891 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000892{
aliguori6b917542008-11-18 19:46:41 +0000893 TranslationBlock *tb, *tb_next, *saved_tb;
bellardd720b932004-04-25 17:57:43 +0000894 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000895 target_ulong tb_start, tb_end;
aliguori6b917542008-11-18 19:46:41 +0000896 PageDesc *p;
897 int n;
898#ifdef TARGET_HAS_PRECISE_SMC
899 int current_tb_not_found = is_cpu_write_access;
900 TranslationBlock *current_tb = NULL;
901 int current_tb_modified = 0;
902 target_ulong current_pc = 0;
903 target_ulong current_cs_base = 0;
904 int current_flags = 0;
905#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000906
907 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000908 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000909 return;
ths5fafdf22007-09-16 21:08:06 +0000910 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000911 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
912 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000913 /* build code bitmap */
914 build_page_bitmap(p);
915 }
916
917 /* we remove all the TBs in the range [start, end[ */
918 /* XXX: see if in some cases it could be faster to invalidate all the code */
919 tb = p->first_tb;
920 while (tb != NULL) {
921 n = (long)tb & 3;
922 tb = (TranslationBlock *)((long)tb & ~3);
923 tb_next = tb->page_next[n];
924 /* NOTE: this is subtle as a TB may span two physical pages */
925 if (n == 0) {
926 /* NOTE: tb_end may be after the end of the page, but
927 it is not a problem */
928 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
929 tb_end = tb_start + tb->size;
930 } else {
931 tb_start = tb->page_addr[1];
932 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
933 }
934 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000935#ifdef TARGET_HAS_PRECISE_SMC
936 if (current_tb_not_found) {
937 current_tb_not_found = 0;
938 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000939 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000940 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000941 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000942 }
943 }
944 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000945 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000946 /* If we are modifying the current TB, we must stop
947 its execution. We could be more precise by checking
948 that the modification is after the current PC, but it
949 would require a specialized function to partially
950 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000951
bellardd720b932004-04-25 17:57:43 +0000952 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000953 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000954 env->mem_io_pc, NULL);
aliguori6b917542008-11-18 19:46:41 +0000955 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
956 &current_flags);
bellardd720b932004-04-25 17:57:43 +0000957 }
958#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000959 /* we need to do that to handle the case where a signal
960 occurs while doing tb_phys_invalidate() */
961 saved_tb = NULL;
962 if (env) {
963 saved_tb = env->current_tb;
964 env->current_tb = NULL;
965 }
bellard9fa3e852004-01-04 18:06:42 +0000966 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000967 if (env) {
968 env->current_tb = saved_tb;
969 if (env->interrupt_request && env->current_tb)
970 cpu_interrupt(env, env->interrupt_request);
971 }
bellard9fa3e852004-01-04 18:06:42 +0000972 }
973 tb = tb_next;
974 }
975#if !defined(CONFIG_USER_ONLY)
976 /* if no code remaining, no need to continue to use slow writes */
977 if (!p->first_tb) {
978 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000979 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000980 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000981 }
982 }
983#endif
984#ifdef TARGET_HAS_PRECISE_SMC
985 if (current_tb_modified) {
986 /* we generate a block containing just the instruction
987 modifying the memory. It will ensure that it cannot modify
988 itself */
bellardea1c1802004-06-14 18:56:36 +0000989 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000990 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000991 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000992 }
993#endif
994}
995
996/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000997static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000998{
999 PageDesc *p;
1000 int offset, b;
bellard59817cc2004-02-16 22:01:13 +00001001#if 0
bellarda4193c82004-06-03 14:01:43 +00001002 if (1) {
aliguori93fcfe32009-01-15 22:34:14 +00001003 qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
1004 cpu_single_env->mem_io_vaddr, len,
1005 cpu_single_env->eip,
1006 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
bellard59817cc2004-02-16 22:01:13 +00001007 }
1008#endif
bellard9fa3e852004-01-04 18:06:42 +00001009 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001010 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001011 return;
1012 if (p->code_bitmap) {
1013 offset = start & ~TARGET_PAGE_MASK;
1014 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1015 if (b & ((1 << len) - 1))
1016 goto do_invalidate;
1017 } else {
1018 do_invalidate:
bellardd720b932004-04-25 17:57:43 +00001019 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +00001020 }
1021}
1022
bellard9fa3e852004-01-04 18:06:42 +00001023#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +00001024static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +00001025 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001026{
aliguori6b917542008-11-18 19:46:41 +00001027 TranslationBlock *tb;
bellard9fa3e852004-01-04 18:06:42 +00001028 PageDesc *p;
aliguori6b917542008-11-18 19:46:41 +00001029 int n;
bellardd720b932004-04-25 17:57:43 +00001030#ifdef TARGET_HAS_PRECISE_SMC
aliguori6b917542008-11-18 19:46:41 +00001031 TranslationBlock *current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001032 CPUState *env = cpu_single_env;
aliguori6b917542008-11-18 19:46:41 +00001033 int current_tb_modified = 0;
1034 target_ulong current_pc = 0;
1035 target_ulong current_cs_base = 0;
1036 int current_flags = 0;
bellardd720b932004-04-25 17:57:43 +00001037#endif
bellard9fa3e852004-01-04 18:06:42 +00001038
1039 addr &= TARGET_PAGE_MASK;
1040 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001041 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +00001042 return;
1043 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +00001044#ifdef TARGET_HAS_PRECISE_SMC
1045 if (tb && pc != 0) {
1046 current_tb = tb_find_pc(pc);
1047 }
1048#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001049 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +00001050 n = (long)tb & 3;
1051 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +00001052#ifdef TARGET_HAS_PRECISE_SMC
1053 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +00001054 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +00001055 /* If we are modifying the current TB, we must stop
1056 its execution. We could be more precise by checking
1057 that the modification is after the current PC, but it
1058 would require a specialized function to partially
1059 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +00001060
bellardd720b932004-04-25 17:57:43 +00001061 current_tb_modified = 1;
1062 cpu_restore_state(current_tb, env, pc, puc);
aliguori6b917542008-11-18 19:46:41 +00001063 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1064 &current_flags);
bellardd720b932004-04-25 17:57:43 +00001065 }
1066#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +00001067 tb_phys_invalidate(tb, addr);
1068 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +00001069 }
1070 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001071#ifdef TARGET_HAS_PRECISE_SMC
1072 if (current_tb_modified) {
1073 /* we generate a block containing just the instruction
1074 modifying the memory. It will ensure that it cannot modify
1075 itself */
bellardea1c1802004-06-14 18:56:36 +00001076 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001077 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001078 cpu_resume_from_signal(env, puc);
1079 }
1080#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001081}
bellard9fa3e852004-01-04 18:06:42 +00001082#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001083
1084/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001085static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001086 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001087{
1088 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001089 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001090
bellard9fa3e852004-01-04 18:06:42 +00001091 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001092 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001093 tb->page_next[n] = p->first_tb;
1094 last_first_tb = p->first_tb;
1095 p->first_tb = (TranslationBlock *)((long)tb | n);
1096 invalidate_page_bitmap(p);
1097
bellard107db442004-06-22 18:48:46 +00001098#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001099
bellard9fa3e852004-01-04 18:06:42 +00001100#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001101 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001102 target_ulong addr;
1103 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001104 int prot;
1105
bellardfd6ce8f2003-05-14 19:00:11 +00001106 /* force the host page as non writable (writes will have a
1107 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001108 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001109 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001110 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1111 addr += TARGET_PAGE_SIZE) {
1112
1113 p2 = page_find (addr >> TARGET_PAGE_BITS);
1114 if (!p2)
1115 continue;
1116 prot |= p2->flags;
1117 p2->flags &= ~PAGE_WRITE;
1118 page_get_flags(addr);
1119 }
ths5fafdf22007-09-16 21:08:06 +00001120 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001121 (prot & PAGE_BITS) & ~PAGE_WRITE);
1122#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001123 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001124 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001125#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001126 }
bellard9fa3e852004-01-04 18:06:42 +00001127#else
1128 /* if some code is already present, then the pages are already
1129 protected. So we handle the case where only the first TB is
1130 allocated in a physical page */
1131 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001132 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001133 }
1134#endif
bellardd720b932004-04-25 17:57:43 +00001135
1136#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001137}
1138
1139/* Allocate a new translation block. Flush the translation buffer if
1140 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001141TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001142{
1143 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001144
bellard26a5f132008-05-28 12:30:31 +00001145 if (nb_tbs >= code_gen_max_blocks ||
1146 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001147 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001148 tb = &tbs[nb_tbs++];
1149 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001150 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001151 return tb;
1152}
1153
pbrook2e70f6e2008-06-29 01:03:05 +00001154void tb_free(TranslationBlock *tb)
1155{
thsbf20dc02008-06-30 17:22:19 +00001156 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001157 Ignore the hard cases and just back up if this TB happens to
1158 be the last one generated. */
1159 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1160 code_gen_ptr = tb->tc_ptr;
1161 nb_tbs--;
1162 }
1163}
1164
bellard9fa3e852004-01-04 18:06:42 +00001165/* add a new TB and link it to the physical page tables. phys_page2 is
1166 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001167void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001168 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001169{
bellard9fa3e852004-01-04 18:06:42 +00001170 unsigned int h;
1171 TranslationBlock **ptb;
1172
pbrookc8a706f2008-06-02 16:16:42 +00001173 /* Grab the mmap lock to stop another thread invalidating this TB
1174 before we are done. */
1175 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001176 /* add in the physical hash table */
1177 h = tb_phys_hash_func(phys_pc);
1178 ptb = &tb_phys_hash[h];
1179 tb->phys_hash_next = *ptb;
1180 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001181
1182 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001183 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1184 if (phys_page2 != -1)
1185 tb_alloc_page(tb, 1, phys_page2);
1186 else
1187 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001188
bellardd4e81642003-05-25 16:46:15 +00001189 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1190 tb->jmp_next[0] = NULL;
1191 tb->jmp_next[1] = NULL;
1192
1193 /* init original jump addresses */
1194 if (tb->tb_next_offset[0] != 0xffff)
1195 tb_reset_jump(tb, 0);
1196 if (tb->tb_next_offset[1] != 0xffff)
1197 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001198
1199#ifdef DEBUG_TB_CHECK
1200 tb_page_check();
1201#endif
pbrookc8a706f2008-06-02 16:16:42 +00001202 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001203}
1204
bellarda513fe12003-05-27 23:29:48 +00001205/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1206 tb[1].tc_ptr. Return NULL if not found */
1207TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1208{
1209 int m_min, m_max, m;
1210 unsigned long v;
1211 TranslationBlock *tb;
1212
1213 if (nb_tbs <= 0)
1214 return NULL;
1215 if (tc_ptr < (unsigned long)code_gen_buffer ||
1216 tc_ptr >= (unsigned long)code_gen_ptr)
1217 return NULL;
1218 /* binary search (cf Knuth) */
1219 m_min = 0;
1220 m_max = nb_tbs - 1;
1221 while (m_min <= m_max) {
1222 m = (m_min + m_max) >> 1;
1223 tb = &tbs[m];
1224 v = (unsigned long)tb->tc_ptr;
1225 if (v == tc_ptr)
1226 return tb;
1227 else if (tc_ptr < v) {
1228 m_max = m - 1;
1229 } else {
1230 m_min = m + 1;
1231 }
ths5fafdf22007-09-16 21:08:06 +00001232 }
bellarda513fe12003-05-27 23:29:48 +00001233 return &tbs[m_max];
1234}
bellard75012672003-06-21 13:11:07 +00001235
bellardea041c02003-06-25 16:16:50 +00001236static void tb_reset_jump_recursive(TranslationBlock *tb);
1237
1238static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1239{
1240 TranslationBlock *tb1, *tb_next, **ptb;
1241 unsigned int n1;
1242
1243 tb1 = tb->jmp_next[n];
1244 if (tb1 != NULL) {
1245 /* find head of list */
1246 for(;;) {
1247 n1 = (long)tb1 & 3;
1248 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1249 if (n1 == 2)
1250 break;
1251 tb1 = tb1->jmp_next[n1];
1252 }
1253 /* we are now sure now that tb jumps to tb1 */
1254 tb_next = tb1;
1255
1256 /* remove tb from the jmp_first list */
1257 ptb = &tb_next->jmp_first;
1258 for(;;) {
1259 tb1 = *ptb;
1260 n1 = (long)tb1 & 3;
1261 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1262 if (n1 == n && tb1 == tb)
1263 break;
1264 ptb = &tb1->jmp_next[n1];
1265 }
1266 *ptb = tb->jmp_next[n];
1267 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001268
bellardea041c02003-06-25 16:16:50 +00001269 /* suppress the jump to next tb in generated code */
1270 tb_reset_jump(tb, n);
1271
bellard01243112004-01-04 15:48:17 +00001272 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001273 tb_reset_jump_recursive(tb_next);
1274 }
1275}
1276
1277static void tb_reset_jump_recursive(TranslationBlock *tb)
1278{
1279 tb_reset_jump_recursive2(tb, 0);
1280 tb_reset_jump_recursive2(tb, 1);
1281}
1282
bellard1fddef42005-04-17 19:16:13 +00001283#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001284static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1285{
j_mayer9b3c35e2007-04-07 11:21:28 +00001286 target_phys_addr_t addr;
1287 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001288 ram_addr_t ram_addr;
1289 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001290
pbrookc2f07f82006-04-08 17:14:56 +00001291 addr = cpu_get_phys_page_debug(env, pc);
1292 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1293 if (!p) {
1294 pd = IO_MEM_UNASSIGNED;
1295 } else {
1296 pd = p->phys_offset;
1297 }
1298 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001299 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001300}
bellardc27004e2005-01-03 23:35:10 +00001301#endif
bellardd720b932004-04-25 17:57:43 +00001302
pbrook6658ffb2007-03-16 23:58:11 +00001303/* Add a watchpoint. */
aliguoria1d1bb32008-11-18 20:07:32 +00001304int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
1305 int flags, CPUWatchpoint **watchpoint)
pbrook6658ffb2007-03-16 23:58:11 +00001306{
aliguorib4051332008-11-18 20:14:20 +00001307 target_ulong len_mask = ~(len - 1);
aliguoric0ce9982008-11-25 22:13:57 +00001308 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001309
aliguorib4051332008-11-18 20:14:20 +00001310 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1311 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1312 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1313 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1314 return -EINVAL;
1315 }
aliguoria1d1bb32008-11-18 20:07:32 +00001316 wp = qemu_malloc(sizeof(*wp));
pbrook6658ffb2007-03-16 23:58:11 +00001317
aliguoria1d1bb32008-11-18 20:07:32 +00001318 wp->vaddr = addr;
aliguorib4051332008-11-18 20:14:20 +00001319 wp->len_mask = len_mask;
aliguoria1d1bb32008-11-18 20:07:32 +00001320 wp->flags = flags;
1321
aliguori2dc9f412008-11-18 20:56:59 +00001322 /* keep all GDB-injected watchpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001323 if (flags & BP_GDB)
1324 TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
1325 else
1326 TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001327
pbrook6658ffb2007-03-16 23:58:11 +00001328 tlb_flush_page(env, addr);
aliguoria1d1bb32008-11-18 20:07:32 +00001329
1330 if (watchpoint)
1331 *watchpoint = wp;
1332 return 0;
pbrook6658ffb2007-03-16 23:58:11 +00001333}
1334
aliguoria1d1bb32008-11-18 20:07:32 +00001335/* Remove a specific watchpoint. */
1336int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
1337 int flags)
pbrook6658ffb2007-03-16 23:58:11 +00001338{
aliguorib4051332008-11-18 20:14:20 +00001339 target_ulong len_mask = ~(len - 1);
aliguoria1d1bb32008-11-18 20:07:32 +00001340 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001341
aliguoric0ce9982008-11-25 22:13:57 +00001342 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00001343 if (addr == wp->vaddr && len_mask == wp->len_mask
aliguori6e140f22008-11-18 20:37:55 +00001344 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
aliguoria1d1bb32008-11-18 20:07:32 +00001345 cpu_watchpoint_remove_by_ref(env, wp);
pbrook6658ffb2007-03-16 23:58:11 +00001346 return 0;
1347 }
1348 }
aliguoria1d1bb32008-11-18 20:07:32 +00001349 return -ENOENT;
pbrook6658ffb2007-03-16 23:58:11 +00001350}
1351
aliguoria1d1bb32008-11-18 20:07:32 +00001352/* Remove a specific watchpoint by reference. */
1353void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
1354{
aliguoric0ce9982008-11-25 22:13:57 +00001355 TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
edgar_igl7d03f822008-05-17 18:58:29 +00001356
aliguoria1d1bb32008-11-18 20:07:32 +00001357 tlb_flush_page(env, watchpoint->vaddr);
1358
1359 qemu_free(watchpoint);
edgar_igl7d03f822008-05-17 18:58:29 +00001360}
1361
aliguoria1d1bb32008-11-18 20:07:32 +00001362/* Remove all matching watchpoints. */
1363void cpu_watchpoint_remove_all(CPUState *env, int mask)
1364{
aliguoric0ce9982008-11-25 22:13:57 +00001365 CPUWatchpoint *wp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001366
aliguoric0ce9982008-11-25 22:13:57 +00001367 TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001368 if (wp->flags & mask)
1369 cpu_watchpoint_remove_by_ref(env, wp);
aliguoric0ce9982008-11-25 22:13:57 +00001370 }
aliguoria1d1bb32008-11-18 20:07:32 +00001371}
1372
1373/* Add a breakpoint. */
1374int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
1375 CPUBreakpoint **breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001376{
bellard1fddef42005-04-17 19:16:13 +00001377#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001378 CPUBreakpoint *bp;
ths3b46e622007-09-17 08:09:54 +00001379
aliguoria1d1bb32008-11-18 20:07:32 +00001380 bp = qemu_malloc(sizeof(*bp));
aliguoria1d1bb32008-11-18 20:07:32 +00001381
1382 bp->pc = pc;
1383 bp->flags = flags;
1384
aliguori2dc9f412008-11-18 20:56:59 +00001385 /* keep all GDB-injected breakpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001386 if (flags & BP_GDB)
1387 TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
1388 else
1389 TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001390
1391 breakpoint_invalidate(env, pc);
1392
1393 if (breakpoint)
1394 *breakpoint = bp;
1395 return 0;
1396#else
1397 return -ENOSYS;
1398#endif
1399}
1400
1401/* Remove a specific breakpoint. */
1402int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
1403{
1404#if defined(TARGET_HAS_ICE)
1405 CPUBreakpoint *bp;
1406
aliguoric0ce9982008-11-25 22:13:57 +00001407 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001408 if (bp->pc == pc && bp->flags == flags) {
1409 cpu_breakpoint_remove_by_ref(env, bp);
bellard4c3a88a2003-07-26 12:06:08 +00001410 return 0;
aliguoria1d1bb32008-11-18 20:07:32 +00001411 }
bellard4c3a88a2003-07-26 12:06:08 +00001412 }
aliguoria1d1bb32008-11-18 20:07:32 +00001413 return -ENOENT;
bellard4c3a88a2003-07-26 12:06:08 +00001414#else
aliguoria1d1bb32008-11-18 20:07:32 +00001415 return -ENOSYS;
bellard4c3a88a2003-07-26 12:06:08 +00001416#endif
1417}
1418
aliguoria1d1bb32008-11-18 20:07:32 +00001419/* Remove a specific breakpoint by reference. */
1420void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001421{
bellard1fddef42005-04-17 19:16:13 +00001422#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001423 TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
bellardd720b932004-04-25 17:57:43 +00001424
aliguoria1d1bb32008-11-18 20:07:32 +00001425 breakpoint_invalidate(env, breakpoint->pc);
1426
1427 qemu_free(breakpoint);
1428#endif
1429}
1430
1431/* Remove all matching breakpoints. */
1432void cpu_breakpoint_remove_all(CPUState *env, int mask)
1433{
1434#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001435 CPUBreakpoint *bp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001436
aliguoric0ce9982008-11-25 22:13:57 +00001437 TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001438 if (bp->flags & mask)
1439 cpu_breakpoint_remove_by_ref(env, bp);
aliguoric0ce9982008-11-25 22:13:57 +00001440 }
bellard4c3a88a2003-07-26 12:06:08 +00001441#endif
1442}
1443
bellardc33a3462003-07-29 20:50:33 +00001444/* enable or disable single step mode. EXCP_DEBUG is returned by the
1445 CPU loop after each instruction */
1446void cpu_single_step(CPUState *env, int enabled)
1447{
bellard1fddef42005-04-17 19:16:13 +00001448#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001449 if (env->singlestep_enabled != enabled) {
1450 env->singlestep_enabled = enabled;
1451 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001452 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001453 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001454 }
1455#endif
1456}
1457
bellard34865132003-10-05 14:28:56 +00001458/* enable or disable low levels log */
1459void cpu_set_log(int log_flags)
1460{
1461 loglevel = log_flags;
1462 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001463 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001464 if (!logfile) {
1465 perror(logfilename);
1466 _exit(1);
1467 }
bellard9fa3e852004-01-04 18:06:42 +00001468#if !defined(CONFIG_SOFTMMU)
1469 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1470 {
blueswir1b55266b2008-09-20 08:07:15 +00001471 static char logfile_buf[4096];
bellard9fa3e852004-01-04 18:06:42 +00001472 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1473 }
1474#else
bellard34865132003-10-05 14:28:56 +00001475 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001476#endif
pbrooke735b912007-06-30 13:53:24 +00001477 log_append = 1;
1478 }
1479 if (!loglevel && logfile) {
1480 fclose(logfile);
1481 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001482 }
1483}
1484
1485void cpu_set_log_filename(const char *filename)
1486{
1487 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001488 if (logfile) {
1489 fclose(logfile);
1490 logfile = NULL;
1491 }
1492 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001493}
bellardc33a3462003-07-29 20:50:33 +00001494
bellard01243112004-01-04 15:48:17 +00001495/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001496void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001497{
pbrookd5975362008-06-07 20:50:51 +00001498#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001499 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001500 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001501#endif
pbrook2e70f6e2008-06-29 01:03:05 +00001502 int old_mask;
bellard59817cc2004-02-16 22:01:13 +00001503
aurel32be214e62009-03-06 21:48:00 +00001504 if (mask & CPU_INTERRUPT_EXIT) {
1505 env->exit_request = 1;
1506 mask &= ~CPU_INTERRUPT_EXIT;
1507 }
1508
pbrook2e70f6e2008-06-29 01:03:05 +00001509 old_mask = env->interrupt_request;
bellard68a79312003-06-30 13:12:32 +00001510 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001511#if defined(USE_NPTL)
1512 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1513 problem and hope the cpu will stop of its own accord. For userspace
1514 emulation this often isn't actually as bad as it sounds. Often
1515 signals are used primarily to interrupt blocking syscalls. */
1516#else
pbrook2e70f6e2008-06-29 01:03:05 +00001517 if (use_icount) {
pbrook266910c2008-07-09 15:31:50 +00001518 env->icount_decr.u16.high = 0xffff;
pbrook2e70f6e2008-06-29 01:03:05 +00001519#ifndef CONFIG_USER_ONLY
pbrook2e70f6e2008-06-29 01:03:05 +00001520 if (!can_do_io(env)
aurel32be214e62009-03-06 21:48:00 +00001521 && (mask & ~old_mask) != 0) {
pbrook2e70f6e2008-06-29 01:03:05 +00001522 cpu_abort(env, "Raised interrupt while not in I/O function");
1523 }
1524#endif
1525 } else {
1526 tb = env->current_tb;
1527 /* if the cpu is currently executing code, we must unlink it and
1528 all the potentially executing TB */
1529 if (tb && !testandset(&interrupt_lock)) {
1530 env->current_tb = NULL;
1531 tb_reset_jump_recursive(tb);
1532 resetlock(&interrupt_lock);
1533 }
bellardea041c02003-06-25 16:16:50 +00001534 }
pbrookd5975362008-06-07 20:50:51 +00001535#endif
bellardea041c02003-06-25 16:16:50 +00001536}
1537
bellardb54ad042004-05-20 13:42:52 +00001538void cpu_reset_interrupt(CPUState *env, int mask)
1539{
1540 env->interrupt_request &= ~mask;
1541}
1542
blueswir1c7cd6a32008-10-02 18:27:46 +00001543const CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001544 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001545 "show generated host assembly code for each compiled TB" },
1546 { CPU_LOG_TB_IN_ASM, "in_asm",
1547 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001548 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001549 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001550 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001551 "show micro ops "
1552#ifdef TARGET_I386
1553 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001554#endif
blueswir1e01a1152008-03-14 17:37:11 +00001555 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001556 { CPU_LOG_INT, "int",
1557 "show interrupts/exceptions in short format" },
1558 { CPU_LOG_EXEC, "exec",
1559 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001560 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001561 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001562#ifdef TARGET_I386
1563 { CPU_LOG_PCALL, "pcall",
1564 "show protected mode far calls/returns/exceptions" },
aliguorieca1bdf2009-01-26 19:54:31 +00001565 { CPU_LOG_RESET, "cpu_reset",
1566 "show CPU state before CPU resets" },
bellardf193c792004-03-21 17:06:25 +00001567#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001568#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001569 { CPU_LOG_IOPORT, "ioport",
1570 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001571#endif
bellardf193c792004-03-21 17:06:25 +00001572 { 0, NULL, NULL },
1573};
1574
1575static int cmp1(const char *s1, int n, const char *s2)
1576{
1577 if (strlen(s2) != n)
1578 return 0;
1579 return memcmp(s1, s2, n) == 0;
1580}
ths3b46e622007-09-17 08:09:54 +00001581
bellardf193c792004-03-21 17:06:25 +00001582/* takes a comma separated list of log masks. Return 0 if error. */
1583int cpu_str_to_log_mask(const char *str)
1584{
blueswir1c7cd6a32008-10-02 18:27:46 +00001585 const CPULogItem *item;
bellardf193c792004-03-21 17:06:25 +00001586 int mask;
1587 const char *p, *p1;
1588
1589 p = str;
1590 mask = 0;
1591 for(;;) {
1592 p1 = strchr(p, ',');
1593 if (!p1)
1594 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001595 if(cmp1(p,p1-p,"all")) {
1596 for(item = cpu_log_items; item->mask != 0; item++) {
1597 mask |= item->mask;
1598 }
1599 } else {
bellardf193c792004-03-21 17:06:25 +00001600 for(item = cpu_log_items; item->mask != 0; item++) {
1601 if (cmp1(p, p1 - p, item->name))
1602 goto found;
1603 }
1604 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001605 }
bellardf193c792004-03-21 17:06:25 +00001606 found:
1607 mask |= item->mask;
1608 if (*p1 != ',')
1609 break;
1610 p = p1 + 1;
1611 }
1612 return mask;
1613}
bellardea041c02003-06-25 16:16:50 +00001614
bellard75012672003-06-21 13:11:07 +00001615void cpu_abort(CPUState *env, const char *fmt, ...)
1616{
1617 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001618 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001619
1620 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001621 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001622 fprintf(stderr, "qemu: fatal: ");
1623 vfprintf(stderr, fmt, ap);
1624 fprintf(stderr, "\n");
1625#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001626 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1627#else
1628 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001629#endif
aliguori93fcfe32009-01-15 22:34:14 +00001630 if (qemu_log_enabled()) {
1631 qemu_log("qemu: fatal: ");
1632 qemu_log_vprintf(fmt, ap2);
1633 qemu_log("\n");
j_mayerf9373292007-09-29 12:18:20 +00001634#ifdef TARGET_I386
aliguori93fcfe32009-01-15 22:34:14 +00001635 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
j_mayerf9373292007-09-29 12:18:20 +00001636#else
aliguori93fcfe32009-01-15 22:34:14 +00001637 log_cpu_state(env, 0);
j_mayerf9373292007-09-29 12:18:20 +00001638#endif
aliguori31b1a7b2009-01-15 22:35:09 +00001639 qemu_log_flush();
aliguori93fcfe32009-01-15 22:34:14 +00001640 qemu_log_close();
balrog924edca2007-06-10 14:07:13 +00001641 }
pbrook493ae1f2007-11-23 16:53:59 +00001642 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001643 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001644 abort();
1645}
1646
thsc5be9f02007-02-28 20:20:53 +00001647CPUState *cpu_copy(CPUState *env)
1648{
ths01ba9812007-12-09 02:22:57 +00001649 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001650 CPUState *next_cpu = new_env->next_cpu;
1651 int cpu_index = new_env->cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001652#if defined(TARGET_HAS_ICE)
1653 CPUBreakpoint *bp;
1654 CPUWatchpoint *wp;
1655#endif
1656
thsc5be9f02007-02-28 20:20:53 +00001657 memcpy(new_env, env, sizeof(CPUState));
aliguori5a38f082009-01-15 20:16:51 +00001658
1659 /* Preserve chaining and index. */
thsc5be9f02007-02-28 20:20:53 +00001660 new_env->next_cpu = next_cpu;
1661 new_env->cpu_index = cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001662
1663 /* Clone all break/watchpoints.
1664 Note: Once we support ptrace with hw-debug register access, make sure
1665 BP_CPU break/watchpoints are handled correctly on clone. */
1666 TAILQ_INIT(&env->breakpoints);
1667 TAILQ_INIT(&env->watchpoints);
1668#if defined(TARGET_HAS_ICE)
1669 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
1670 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
1671 }
1672 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
1673 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
1674 wp->flags, NULL);
1675 }
1676#endif
1677
thsc5be9f02007-02-28 20:20:53 +00001678 return new_env;
1679}
1680
bellard01243112004-01-04 15:48:17 +00001681#if !defined(CONFIG_USER_ONLY)
1682
edgar_igl5c751e92008-05-06 08:44:21 +00001683static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1684{
1685 unsigned int i;
1686
1687 /* Discard jump cache entries for any tb which might potentially
1688 overlap the flushed page. */
1689 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1690 memset (&env->tb_jmp_cache[i], 0,
1691 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1692
1693 i = tb_jmp_cache_hash_page(addr);
1694 memset (&env->tb_jmp_cache[i], 0,
1695 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1696}
1697
bellardee8b7022004-02-03 23:35:10 +00001698/* NOTE: if flush_global is true, also flush global entries (not
1699 implemented yet) */
1700void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001701{
bellard33417e72003-08-10 21:47:01 +00001702 int i;
bellard01243112004-01-04 15:48:17 +00001703
bellard9fa3e852004-01-04 18:06:42 +00001704#if defined(DEBUG_TLB)
1705 printf("tlb_flush:\n");
1706#endif
bellard01243112004-01-04 15:48:17 +00001707 /* must reset current TB so that interrupts cannot modify the
1708 links while we are modifying them */
1709 env->current_tb = NULL;
1710
bellard33417e72003-08-10 21:47:01 +00001711 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001712 env->tlb_table[0][i].addr_read = -1;
1713 env->tlb_table[0][i].addr_write = -1;
1714 env->tlb_table[0][i].addr_code = -1;
1715 env->tlb_table[1][i].addr_read = -1;
1716 env->tlb_table[1][i].addr_write = -1;
1717 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001718#if (NB_MMU_MODES >= 3)
1719 env->tlb_table[2][i].addr_read = -1;
1720 env->tlb_table[2][i].addr_write = -1;
1721 env->tlb_table[2][i].addr_code = -1;
1722#if (NB_MMU_MODES == 4)
1723 env->tlb_table[3][i].addr_read = -1;
1724 env->tlb_table[3][i].addr_write = -1;
1725 env->tlb_table[3][i].addr_code = -1;
1726#endif
1727#endif
bellard33417e72003-08-10 21:47:01 +00001728 }
bellard9fa3e852004-01-04 18:06:42 +00001729
bellard8a40a182005-11-20 10:35:40 +00001730 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001731
bellard0a962c02005-02-10 22:00:27 +00001732#ifdef USE_KQEMU
1733 if (env->kqemu_enabled) {
1734 kqemu_flush(env, flush_global);
1735 }
1736#endif
bellarde3db7222005-01-26 22:00:47 +00001737 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001738}
1739
bellard274da6b2004-05-20 21:56:27 +00001740static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001741{
ths5fafdf22007-09-16 21:08:06 +00001742 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001743 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001744 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001745 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001746 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001747 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1748 tlb_entry->addr_read = -1;
1749 tlb_entry->addr_write = -1;
1750 tlb_entry->addr_code = -1;
1751 }
bellard61382a52003-10-27 21:22:23 +00001752}
1753
bellard2e126692004-04-25 21:28:44 +00001754void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001755{
bellard8a40a182005-11-20 10:35:40 +00001756 int i;
bellard01243112004-01-04 15:48:17 +00001757
bellard9fa3e852004-01-04 18:06:42 +00001758#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001759 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001760#endif
bellard01243112004-01-04 15:48:17 +00001761 /* must reset current TB so that interrupts cannot modify the
1762 links while we are modifying them */
1763 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001764
bellard61382a52003-10-27 21:22:23 +00001765 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001766 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001767 tlb_flush_entry(&env->tlb_table[0][i], addr);
1768 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001769#if (NB_MMU_MODES >= 3)
1770 tlb_flush_entry(&env->tlb_table[2][i], addr);
1771#if (NB_MMU_MODES == 4)
1772 tlb_flush_entry(&env->tlb_table[3][i], addr);
1773#endif
1774#endif
bellard01243112004-01-04 15:48:17 +00001775
edgar_igl5c751e92008-05-06 08:44:21 +00001776 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001777
bellard0a962c02005-02-10 22:00:27 +00001778#ifdef USE_KQEMU
1779 if (env->kqemu_enabled) {
1780 kqemu_flush_page(env, addr);
1781 }
1782#endif
bellard9fa3e852004-01-04 18:06:42 +00001783}
1784
bellard9fa3e852004-01-04 18:06:42 +00001785/* update the TLBs so that writes to code in the virtual page 'addr'
1786 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001787static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001788{
ths5fafdf22007-09-16 21:08:06 +00001789 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001790 ram_addr + TARGET_PAGE_SIZE,
1791 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001792}
1793
bellard9fa3e852004-01-04 18:06:42 +00001794/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001795 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001796static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001797 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001798{
bellard3a7d9292005-08-21 09:26:42 +00001799 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001800}
1801
ths5fafdf22007-09-16 21:08:06 +00001802static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001803 unsigned long start, unsigned long length)
1804{
1805 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001806 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1807 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001808 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001809 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001810 }
1811 }
1812}
1813
bellard3a7d9292005-08-21 09:26:42 +00001814void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001815 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001816{
1817 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001818 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001819 int i, mask, len;
1820 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001821
1822 start &= TARGET_PAGE_MASK;
1823 end = TARGET_PAGE_ALIGN(end);
1824
1825 length = end - start;
1826 if (length == 0)
1827 return;
bellard0a962c02005-02-10 22:00:27 +00001828 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001829#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001830 /* XXX: should not depend on cpu context */
1831 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001832 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001833 ram_addr_t addr;
1834 addr = start;
1835 for(i = 0; i < len; i++) {
1836 kqemu_set_notdirty(env, addr);
1837 addr += TARGET_PAGE_SIZE;
1838 }
bellard3a7d9292005-08-21 09:26:42 +00001839 }
1840#endif
bellardf23db162005-08-21 19:12:28 +00001841 mask = ~dirty_flags;
1842 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1843 for(i = 0; i < len; i++)
1844 p[i] &= mask;
1845
bellard1ccde1c2004-02-06 19:46:14 +00001846 /* we modify the TLB cache so that the dirty bit will be set again
1847 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001848 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001849 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1850 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001851 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001852 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001853 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001854#if (NB_MMU_MODES >= 3)
1855 for(i = 0; i < CPU_TLB_SIZE; i++)
1856 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1857#if (NB_MMU_MODES == 4)
1858 for(i = 0; i < CPU_TLB_SIZE; i++)
1859 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1860#endif
1861#endif
bellard6a00d602005-11-21 23:25:50 +00001862 }
bellard1ccde1c2004-02-06 19:46:14 +00001863}
1864
aliguori74576192008-10-06 14:02:03 +00001865int cpu_physical_memory_set_dirty_tracking(int enable)
1866{
1867 in_migration = enable;
1868 return 0;
1869}
1870
1871int cpu_physical_memory_get_dirty_tracking(void)
1872{
1873 return in_migration;
1874}
1875
aliguori2bec46d2008-11-24 20:21:41 +00001876void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
1877{
1878 if (kvm_enabled())
1879 kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1880}
1881
bellard3a7d9292005-08-21 09:26:42 +00001882static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1883{
1884 ram_addr_t ram_addr;
1885
bellard84b7b8e2005-11-28 21:19:04 +00001886 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001887 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001888 tlb_entry->addend - (unsigned long)phys_ram_base;
1889 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001890 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001891 }
1892 }
1893}
1894
1895/* update the TLB according to the current state of the dirty bits */
1896void cpu_tlb_update_dirty(CPUState *env)
1897{
1898 int i;
1899 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001900 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001901 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001902 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001903#if (NB_MMU_MODES >= 3)
1904 for(i = 0; i < CPU_TLB_SIZE; i++)
1905 tlb_update_dirty(&env->tlb_table[2][i]);
1906#if (NB_MMU_MODES == 4)
1907 for(i = 0; i < CPU_TLB_SIZE; i++)
1908 tlb_update_dirty(&env->tlb_table[3][i]);
1909#endif
1910#endif
bellard3a7d9292005-08-21 09:26:42 +00001911}
1912
pbrook0f459d12008-06-09 00:20:13 +00001913static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001914{
pbrook0f459d12008-06-09 00:20:13 +00001915 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1916 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001917}
1918
pbrook0f459d12008-06-09 00:20:13 +00001919/* update the TLB corresponding to virtual page vaddr
1920 so that it is no longer dirty */
1921static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001922{
bellard1ccde1c2004-02-06 19:46:14 +00001923 int i;
1924
pbrook0f459d12008-06-09 00:20:13 +00001925 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001926 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001927 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1928 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001929#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001930 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001931#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001932 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001933#endif
1934#endif
bellard9fa3e852004-01-04 18:06:42 +00001935}
1936
bellard59817cc2004-02-16 22:01:13 +00001937/* add a new TLB entry. At most one entry for a given virtual address
1938 is permitted. Return 0 if OK or 2 if the page could not be mapped
1939 (can only happen in non SOFTMMU mode for I/O pages or pages
1940 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001941int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1942 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001943 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001944{
bellard92e873b2004-05-21 14:52:29 +00001945 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001946 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001947 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001948 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001949 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001950 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001951 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001952 CPUTLBEntry *te;
aliguoria1d1bb32008-11-18 20:07:32 +00001953 CPUWatchpoint *wp;
pbrook0f459d12008-06-09 00:20:13 +00001954 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001955
bellard92e873b2004-05-21 14:52:29 +00001956 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001957 if (!p) {
1958 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001959 } else {
1960 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001961 }
1962#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001963 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1964 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001965#endif
1966
1967 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001968 address = vaddr;
1969 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1970 /* IO memory case (romd handled later) */
1971 address |= TLB_MMIO;
1972 }
1973 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1974 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1975 /* Normal RAM. */
1976 iotlb = pd & TARGET_PAGE_MASK;
1977 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1978 iotlb |= IO_MEM_NOTDIRTY;
1979 else
1980 iotlb |= IO_MEM_ROM;
1981 } else {
1982 /* IO handlers are currently passed a phsical address.
1983 It would be nice to pass an offset from the base address
1984 of that region. This would avoid having to special case RAM,
1985 and avoid full address decoding in every device.
1986 We can't use the high bits of pd for this because
1987 IO_MEM_ROMD uses these as a ram address. */
pbrook8da3ff12008-12-01 18:59:50 +00001988 iotlb = (pd & ~TARGET_PAGE_MASK);
1989 if (p) {
pbrook8da3ff12008-12-01 18:59:50 +00001990 iotlb += p->region_offset;
1991 } else {
1992 iotlb += paddr;
1993 }
pbrook0f459d12008-06-09 00:20:13 +00001994 }
pbrook6658ffb2007-03-16 23:58:11 +00001995
pbrook0f459d12008-06-09 00:20:13 +00001996 code_address = address;
1997 /* Make accesses to pages with watchpoints go via the
1998 watchpoint trap routines. */
aliguoric0ce9982008-11-25 22:13:57 +00001999 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00002000 if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
pbrook0f459d12008-06-09 00:20:13 +00002001 iotlb = io_mem_watch + paddr;
2002 /* TODO: The memory case can be optimized by not trapping
2003 reads of pages with a write breakpoint. */
2004 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00002005 }
pbrook0f459d12008-06-09 00:20:13 +00002006 }
balrogd79acba2007-06-26 20:01:13 +00002007
pbrook0f459d12008-06-09 00:20:13 +00002008 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
2009 env->iotlb[mmu_idx][index] = iotlb - vaddr;
2010 te = &env->tlb_table[mmu_idx][index];
2011 te->addend = addend - vaddr;
2012 if (prot & PAGE_READ) {
2013 te->addr_read = address;
2014 } else {
2015 te->addr_read = -1;
2016 }
edgar_igl5c751e92008-05-06 08:44:21 +00002017
pbrook0f459d12008-06-09 00:20:13 +00002018 if (prot & PAGE_EXEC) {
2019 te->addr_code = code_address;
2020 } else {
2021 te->addr_code = -1;
2022 }
2023 if (prot & PAGE_WRITE) {
2024 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
2025 (pd & IO_MEM_ROMD)) {
2026 /* Write access calls the I/O callback. */
2027 te->addr_write = address | TLB_MMIO;
2028 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2029 !cpu_physical_memory_is_dirty(pd)) {
2030 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00002031 } else {
pbrook0f459d12008-06-09 00:20:13 +00002032 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00002033 }
pbrook0f459d12008-06-09 00:20:13 +00002034 } else {
2035 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00002036 }
bellard9fa3e852004-01-04 18:06:42 +00002037 return ret;
2038}
2039
bellard01243112004-01-04 15:48:17 +00002040#else
2041
bellardee8b7022004-02-03 23:35:10 +00002042void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00002043{
2044}
2045
bellard2e126692004-04-25 21:28:44 +00002046void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00002047{
2048}
2049
ths5fafdf22007-09-16 21:08:06 +00002050int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
2051 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00002052 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00002053{
bellard9fa3e852004-01-04 18:06:42 +00002054 return 0;
2055}
bellard33417e72003-08-10 21:47:01 +00002056
bellard9fa3e852004-01-04 18:06:42 +00002057/* dump memory mappings */
2058void page_dump(FILE *f)
2059{
2060 unsigned long start, end;
2061 int i, j, prot, prot1;
2062 PageDesc *p;
2063
2064 fprintf(f, "%-8s %-8s %-8s %s\n",
2065 "start", "end", "size", "prot");
2066 start = -1;
2067 end = -1;
2068 prot = 0;
2069 for(i = 0; i <= L1_SIZE; i++) {
2070 if (i < L1_SIZE)
2071 p = l1_map[i];
2072 else
2073 p = NULL;
2074 for(j = 0;j < L2_SIZE; j++) {
2075 if (!p)
2076 prot1 = 0;
2077 else
2078 prot1 = p[j].flags;
2079 if (prot1 != prot) {
2080 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2081 if (start != -1) {
2082 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00002083 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00002084 prot & PAGE_READ ? 'r' : '-',
2085 prot & PAGE_WRITE ? 'w' : '-',
2086 prot & PAGE_EXEC ? 'x' : '-');
2087 }
2088 if (prot1 != 0)
2089 start = end;
2090 else
2091 start = -1;
2092 prot = prot1;
2093 }
2094 if (!p)
2095 break;
2096 }
bellard33417e72003-08-10 21:47:01 +00002097 }
bellard33417e72003-08-10 21:47:01 +00002098}
2099
pbrook53a59602006-03-25 19:31:22 +00002100int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002101{
bellard9fa3e852004-01-04 18:06:42 +00002102 PageDesc *p;
2103
2104 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002105 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002106 return 0;
2107 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002108}
2109
bellard9fa3e852004-01-04 18:06:42 +00002110/* modify the flags of a page and invalidate the code if
2111 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2112 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002113void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002114{
2115 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002116 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002117
pbrookc8a706f2008-06-02 16:16:42 +00002118 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002119 start = start & TARGET_PAGE_MASK;
2120 end = TARGET_PAGE_ALIGN(end);
2121 if (flags & PAGE_WRITE)
2122 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002123 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2124 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00002125 /* We may be called for host regions that are outside guest
2126 address space. */
2127 if (!p)
2128 return;
bellard9fa3e852004-01-04 18:06:42 +00002129 /* if the write protection is set, then we invalidate the code
2130 inside */
ths5fafdf22007-09-16 21:08:06 +00002131 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002132 (flags & PAGE_WRITE) &&
2133 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002134 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002135 }
2136 p->flags = flags;
2137 }
bellard9fa3e852004-01-04 18:06:42 +00002138}
2139
ths3d97b402007-11-02 19:02:07 +00002140int page_check_range(target_ulong start, target_ulong len, int flags)
2141{
2142 PageDesc *p;
2143 target_ulong end;
2144 target_ulong addr;
2145
balrog55f280c2008-10-28 10:24:11 +00002146 if (start + len < start)
2147 /* we've wrapped around */
2148 return -1;
2149
ths3d97b402007-11-02 19:02:07 +00002150 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2151 start = start & TARGET_PAGE_MASK;
2152
ths3d97b402007-11-02 19:02:07 +00002153 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2154 p = page_find(addr >> TARGET_PAGE_BITS);
2155 if( !p )
2156 return -1;
2157 if( !(p->flags & PAGE_VALID) )
2158 return -1;
2159
bellarddae32702007-11-14 10:51:00 +00002160 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002161 return -1;
bellarddae32702007-11-14 10:51:00 +00002162 if (flags & PAGE_WRITE) {
2163 if (!(p->flags & PAGE_WRITE_ORG))
2164 return -1;
2165 /* unprotect the page if it was put read-only because it
2166 contains translated code */
2167 if (!(p->flags & PAGE_WRITE)) {
2168 if (!page_unprotect(addr, 0, NULL))
2169 return -1;
2170 }
2171 return 0;
2172 }
ths3d97b402007-11-02 19:02:07 +00002173 }
2174 return 0;
2175}
2176
bellard9fa3e852004-01-04 18:06:42 +00002177/* called from signal handler: invalidate the code and unprotect the
2178 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002179int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002180{
2181 unsigned int page_index, prot, pindex;
2182 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002183 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002184
pbrookc8a706f2008-06-02 16:16:42 +00002185 /* Technically this isn't safe inside a signal handler. However we
2186 know this only ever happens in a synchronous SEGV handler, so in
2187 practice it seems to be ok. */
2188 mmap_lock();
2189
bellard83fb7ad2004-07-05 21:25:26 +00002190 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002191 page_index = host_start >> TARGET_PAGE_BITS;
2192 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002193 if (!p1) {
2194 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002195 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002196 }
bellard83fb7ad2004-07-05 21:25:26 +00002197 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002198 p = p1;
2199 prot = 0;
2200 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2201 prot |= p->flags;
2202 p++;
2203 }
2204 /* if the page was really writable, then we change its
2205 protection back to writable */
2206 if (prot & PAGE_WRITE_ORG) {
2207 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2208 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002209 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002210 (prot & PAGE_BITS) | PAGE_WRITE);
2211 p1[pindex].flags |= PAGE_WRITE;
2212 /* and since the content will be modified, we must invalidate
2213 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002214 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002215#ifdef DEBUG_TB_CHECK
2216 tb_invalidate_check(address);
2217#endif
pbrookc8a706f2008-06-02 16:16:42 +00002218 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002219 return 1;
2220 }
2221 }
pbrookc8a706f2008-06-02 16:16:42 +00002222 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002223 return 0;
2224}
2225
bellard6a00d602005-11-21 23:25:50 +00002226static inline void tlb_set_dirty(CPUState *env,
2227 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002228{
2229}
bellard9fa3e852004-01-04 18:06:42 +00002230#endif /* defined(CONFIG_USER_ONLY) */
2231
pbrooke2eef172008-06-08 01:09:01 +00002232#if !defined(CONFIG_USER_ONLY)
pbrook8da3ff12008-12-01 18:59:50 +00002233
blueswir1db7b5422007-05-26 17:36:03 +00002234static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002235 ram_addr_t memory, ram_addr_t region_offset);
aurel3200f82b82008-04-27 21:12:55 +00002236static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002237 ram_addr_t orig_memory, ram_addr_t region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002238#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2239 need_subpage) \
2240 do { \
2241 if (addr > start_addr) \
2242 start_addr2 = 0; \
2243 else { \
2244 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2245 if (start_addr2 > 0) \
2246 need_subpage = 1; \
2247 } \
2248 \
blueswir149e9fba2007-05-30 17:25:06 +00002249 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002250 end_addr2 = TARGET_PAGE_SIZE - 1; \
2251 else { \
2252 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2253 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2254 need_subpage = 1; \
2255 } \
2256 } while (0)
2257
bellard33417e72003-08-10 21:47:01 +00002258/* register physical memory. 'size' must be a multiple of the target
2259 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
pbrook8da3ff12008-12-01 18:59:50 +00002260 io memory page. The address used when calling the IO function is
2261 the offset from the start of the region, plus region_offset. Both
2262 start_region and regon_offset are rounded down to a page boundary
2263 before calculating this offset. This should not be a problem unless
2264 the low bits of start_addr and region_offset differ. */
2265void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2266 ram_addr_t size,
2267 ram_addr_t phys_offset,
2268 ram_addr_t region_offset)
bellard33417e72003-08-10 21:47:01 +00002269{
bellard108c49b2005-07-24 12:55:09 +00002270 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002271 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002272 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002273 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002274 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002275
bellardda260242008-05-30 20:48:25 +00002276#ifdef USE_KQEMU
2277 /* XXX: should not depend on cpu context */
2278 env = first_cpu;
2279 if (env->kqemu_enabled) {
2280 kqemu_set_phys_mem(start_addr, size, phys_offset);
2281 }
2282#endif
aliguori7ba1e612008-11-05 16:04:33 +00002283 if (kvm_enabled())
2284 kvm_set_phys_mem(start_addr, size, phys_offset);
2285
pbrook67c4d232009-02-23 13:16:07 +00002286 if (phys_offset == IO_MEM_UNASSIGNED) {
2287 region_offset = start_addr;
2288 }
pbrook8da3ff12008-12-01 18:59:50 +00002289 region_offset &= TARGET_PAGE_MASK;
bellard5fd386f2004-05-23 21:11:22 +00002290 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002291 end_addr = start_addr + (target_phys_addr_t)size;
2292 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002293 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2294 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002295 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002296 target_phys_addr_t start_addr2, end_addr2;
2297 int need_subpage = 0;
2298
2299 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2300 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002301 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002302 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2303 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002304 &p->phys_offset, orig_memory,
2305 p->region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002306 } else {
2307 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2308 >> IO_MEM_SHIFT];
2309 }
pbrook8da3ff12008-12-01 18:59:50 +00002310 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2311 region_offset);
2312 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002313 } else {
2314 p->phys_offset = phys_offset;
2315 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2316 (phys_offset & IO_MEM_ROMD))
2317 phys_offset += TARGET_PAGE_SIZE;
2318 }
2319 } else {
2320 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2321 p->phys_offset = phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +00002322 p->region_offset = region_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002323 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
pbrook8da3ff12008-12-01 18:59:50 +00002324 (phys_offset & IO_MEM_ROMD)) {
blueswir1db7b5422007-05-26 17:36:03 +00002325 phys_offset += TARGET_PAGE_SIZE;
pbrook0e8f0962008-12-02 09:02:15 +00002326 } else {
blueswir1db7b5422007-05-26 17:36:03 +00002327 target_phys_addr_t start_addr2, end_addr2;
2328 int need_subpage = 0;
2329
2330 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2331 end_addr2, need_subpage);
2332
blueswir14254fab2008-01-01 16:57:19 +00002333 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002334 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002335 &p->phys_offset, IO_MEM_UNASSIGNED,
pbrook67c4d232009-02-23 13:16:07 +00002336 addr & TARGET_PAGE_MASK);
blueswir1db7b5422007-05-26 17:36:03 +00002337 subpage_register(subpage, start_addr2, end_addr2,
pbrook8da3ff12008-12-01 18:59:50 +00002338 phys_offset, region_offset);
2339 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002340 }
2341 }
2342 }
pbrook8da3ff12008-12-01 18:59:50 +00002343 region_offset += TARGET_PAGE_SIZE;
bellard33417e72003-08-10 21:47:01 +00002344 }
ths3b46e622007-09-17 08:09:54 +00002345
bellard9d420372006-06-25 22:25:22 +00002346 /* since each CPU stores ram addresses in its TLB cache, we must
2347 reset the modified entries */
2348 /* XXX: slow ! */
2349 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2350 tlb_flush(env, 1);
2351 }
bellard33417e72003-08-10 21:47:01 +00002352}
2353
bellardba863452006-09-24 18:41:10 +00002354/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002355ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002356{
2357 PhysPageDesc *p;
2358
2359 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2360 if (!p)
2361 return IO_MEM_UNASSIGNED;
2362 return p->phys_offset;
2363}
2364
aliguorif65ed4c2008-12-09 20:09:57 +00002365void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2366{
2367 if (kvm_enabled())
2368 kvm_coalesce_mmio_region(addr, size);
2369}
2370
2371void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2372{
2373 if (kvm_enabled())
2374 kvm_uncoalesce_mmio_region(addr, size);
2375}
2376
bellarde9a1ab12007-02-08 23:08:38 +00002377/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002378ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002379{
2380 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002381 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
ths012a7042008-10-02 17:34:21 +00002382 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
bellarded441462008-05-23 11:56:45 +00002383 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002384 abort();
2385 }
2386 addr = phys_ram_alloc_offset;
2387 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2388 return addr;
2389}
2390
2391void qemu_ram_free(ram_addr_t addr)
2392{
2393}
2394
bellarda4193c82004-06-03 14:01:43 +00002395static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002396{
pbrook67d3b952006-12-18 05:03:52 +00002397#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002398 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002399#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002400#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002401 do_unassigned_access(addr, 0, 0, 0, 1);
2402#endif
2403 return 0;
2404}
2405
2406static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
2407{
2408#ifdef DEBUG_UNASSIGNED
2409 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2410#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002411#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002412 do_unassigned_access(addr, 0, 0, 0, 2);
2413#endif
2414 return 0;
2415}
2416
2417static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
2418{
2419#ifdef DEBUG_UNASSIGNED
2420 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2421#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002422#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002423 do_unassigned_access(addr, 0, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002424#endif
bellard33417e72003-08-10 21:47:01 +00002425 return 0;
2426}
2427
bellarda4193c82004-06-03 14:01:43 +00002428static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002429{
pbrook67d3b952006-12-18 05:03:52 +00002430#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002431 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002432#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002433#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002434 do_unassigned_access(addr, 1, 0, 0, 1);
2435#endif
2436}
2437
2438static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2439{
2440#ifdef DEBUG_UNASSIGNED
2441 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2442#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002443#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002444 do_unassigned_access(addr, 1, 0, 0, 2);
2445#endif
2446}
2447
2448static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2449{
2450#ifdef DEBUG_UNASSIGNED
2451 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2452#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002453#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002454 do_unassigned_access(addr, 1, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002455#endif
bellard33417e72003-08-10 21:47:01 +00002456}
2457
2458static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2459 unassigned_mem_readb,
blueswir1e18231a2008-10-06 18:46:28 +00002460 unassigned_mem_readw,
2461 unassigned_mem_readl,
bellard33417e72003-08-10 21:47:01 +00002462};
2463
2464static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2465 unassigned_mem_writeb,
blueswir1e18231a2008-10-06 18:46:28 +00002466 unassigned_mem_writew,
2467 unassigned_mem_writel,
bellard33417e72003-08-10 21:47:01 +00002468};
2469
pbrook0f459d12008-06-09 00:20:13 +00002470static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2471 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002472{
bellard3a7d9292005-08-21 09:26:42 +00002473 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002474 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2475 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2476#if !defined(CONFIG_USER_ONLY)
2477 tb_invalidate_phys_page_fast(ram_addr, 1);
2478 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2479#endif
2480 }
pbrook0f459d12008-06-09 00:20:13 +00002481 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002482#ifdef USE_KQEMU
2483 if (cpu_single_env->kqemu_enabled &&
2484 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2485 kqemu_modify_page(cpu_single_env, ram_addr);
2486#endif
bellardf23db162005-08-21 19:12:28 +00002487 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2488 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2489 /* we remove the notdirty callback only if the code has been
2490 flushed */
2491 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002492 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002493}
2494
pbrook0f459d12008-06-09 00:20:13 +00002495static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2496 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002497{
bellard3a7d9292005-08-21 09:26:42 +00002498 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002499 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2500 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2501#if !defined(CONFIG_USER_ONLY)
2502 tb_invalidate_phys_page_fast(ram_addr, 2);
2503 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2504#endif
2505 }
pbrook0f459d12008-06-09 00:20:13 +00002506 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002507#ifdef USE_KQEMU
2508 if (cpu_single_env->kqemu_enabled &&
2509 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2510 kqemu_modify_page(cpu_single_env, ram_addr);
2511#endif
bellardf23db162005-08-21 19:12:28 +00002512 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2513 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2514 /* we remove the notdirty callback only if the code has been
2515 flushed */
2516 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002517 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002518}
2519
pbrook0f459d12008-06-09 00:20:13 +00002520static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2521 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002522{
bellard3a7d9292005-08-21 09:26:42 +00002523 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002524 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2525 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2526#if !defined(CONFIG_USER_ONLY)
2527 tb_invalidate_phys_page_fast(ram_addr, 4);
2528 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2529#endif
2530 }
pbrook0f459d12008-06-09 00:20:13 +00002531 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002532#ifdef USE_KQEMU
2533 if (cpu_single_env->kqemu_enabled &&
2534 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2535 kqemu_modify_page(cpu_single_env, ram_addr);
2536#endif
bellardf23db162005-08-21 19:12:28 +00002537 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2538 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2539 /* we remove the notdirty callback only if the code has been
2540 flushed */
2541 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002542 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002543}
2544
bellard3a7d9292005-08-21 09:26:42 +00002545static CPUReadMemoryFunc *error_mem_read[3] = {
2546 NULL, /* never used */
2547 NULL, /* never used */
2548 NULL, /* never used */
2549};
2550
bellard1ccde1c2004-02-06 19:46:14 +00002551static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2552 notdirty_mem_writeb,
2553 notdirty_mem_writew,
2554 notdirty_mem_writel,
2555};
2556
pbrook0f459d12008-06-09 00:20:13 +00002557/* Generate a debug exception if a watchpoint has been hit. */
aliguorib4051332008-11-18 20:14:20 +00002558static void check_watchpoint(int offset, int len_mask, int flags)
pbrook0f459d12008-06-09 00:20:13 +00002559{
2560 CPUState *env = cpu_single_env;
aliguori06d55cc2008-11-18 20:24:06 +00002561 target_ulong pc, cs_base;
2562 TranslationBlock *tb;
pbrook0f459d12008-06-09 00:20:13 +00002563 target_ulong vaddr;
aliguoria1d1bb32008-11-18 20:07:32 +00002564 CPUWatchpoint *wp;
aliguori06d55cc2008-11-18 20:24:06 +00002565 int cpu_flags;
pbrook0f459d12008-06-09 00:20:13 +00002566
aliguori06d55cc2008-11-18 20:24:06 +00002567 if (env->watchpoint_hit) {
2568 /* We re-entered the check after replacing the TB. Now raise
2569 * the debug interrupt so that is will trigger after the
2570 * current instruction. */
2571 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2572 return;
2573 }
pbrook2e70f6e2008-06-29 01:03:05 +00002574 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
aliguoric0ce9982008-11-25 22:13:57 +00002575 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00002576 if ((vaddr == (wp->vaddr & len_mask) ||
2577 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
aliguori6e140f22008-11-18 20:37:55 +00002578 wp->flags |= BP_WATCHPOINT_HIT;
2579 if (!env->watchpoint_hit) {
2580 env->watchpoint_hit = wp;
2581 tb = tb_find_pc(env->mem_io_pc);
2582 if (!tb) {
2583 cpu_abort(env, "check_watchpoint: could not find TB for "
2584 "pc=%p", (void *)env->mem_io_pc);
2585 }
2586 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
2587 tb_phys_invalidate(tb, -1);
2588 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2589 env->exception_index = EXCP_DEBUG;
2590 } else {
2591 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2592 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2593 }
2594 cpu_resume_from_signal(env, NULL);
aliguori06d55cc2008-11-18 20:24:06 +00002595 }
aliguori6e140f22008-11-18 20:37:55 +00002596 } else {
2597 wp->flags &= ~BP_WATCHPOINT_HIT;
pbrook0f459d12008-06-09 00:20:13 +00002598 }
2599 }
2600}
2601
pbrook6658ffb2007-03-16 23:58:11 +00002602/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2603 so these check for a hit then pass through to the normal out-of-line
2604 phys routines. */
2605static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2606{
aliguorib4051332008-11-18 20:14:20 +00002607 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002608 return ldub_phys(addr);
2609}
2610
2611static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2612{
aliguorib4051332008-11-18 20:14:20 +00002613 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002614 return lduw_phys(addr);
2615}
2616
2617static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2618{
aliguorib4051332008-11-18 20:14:20 +00002619 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002620 return ldl_phys(addr);
2621}
2622
pbrook6658ffb2007-03-16 23:58:11 +00002623static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2624 uint32_t val)
2625{
aliguorib4051332008-11-18 20:14:20 +00002626 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002627 stb_phys(addr, val);
2628}
2629
2630static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2631 uint32_t val)
2632{
aliguorib4051332008-11-18 20:14:20 +00002633 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002634 stw_phys(addr, val);
2635}
2636
2637static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2638 uint32_t val)
2639{
aliguorib4051332008-11-18 20:14:20 +00002640 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002641 stl_phys(addr, val);
2642}
2643
2644static CPUReadMemoryFunc *watch_mem_read[3] = {
2645 watch_mem_readb,
2646 watch_mem_readw,
2647 watch_mem_readl,
2648};
2649
2650static CPUWriteMemoryFunc *watch_mem_write[3] = {
2651 watch_mem_writeb,
2652 watch_mem_writew,
2653 watch_mem_writel,
2654};
pbrook6658ffb2007-03-16 23:58:11 +00002655
blueswir1db7b5422007-05-26 17:36:03 +00002656static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2657 unsigned int len)
2658{
blueswir1db7b5422007-05-26 17:36:03 +00002659 uint32_t ret;
2660 unsigned int idx;
2661
pbrook8da3ff12008-12-01 18:59:50 +00002662 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002663#if defined(DEBUG_SUBPAGE)
2664 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2665 mmio, len, addr, idx);
2666#endif
pbrook8da3ff12008-12-01 18:59:50 +00002667 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2668 addr + mmio->region_offset[idx][0][len]);
blueswir1db7b5422007-05-26 17:36:03 +00002669
2670 return ret;
2671}
2672
2673static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2674 uint32_t value, unsigned int len)
2675{
blueswir1db7b5422007-05-26 17:36:03 +00002676 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 value %08x\n", __func__,
2681 mmio, len, addr, idx, value);
2682#endif
pbrook8da3ff12008-12-01 18:59:50 +00002683 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2684 addr + mmio->region_offset[idx][1][len],
2685 value);
blueswir1db7b5422007-05-26 17:36:03 +00002686}
2687
2688static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2689{
2690#if defined(DEBUG_SUBPAGE)
2691 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2692#endif
2693
2694 return subpage_readlen(opaque, addr, 0);
2695}
2696
2697static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2698 uint32_t value)
2699{
2700#if defined(DEBUG_SUBPAGE)
2701 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2702#endif
2703 subpage_writelen(opaque, addr, value, 0);
2704}
2705
2706static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2707{
2708#if defined(DEBUG_SUBPAGE)
2709 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2710#endif
2711
2712 return subpage_readlen(opaque, addr, 1);
2713}
2714
2715static void subpage_writew (void *opaque, target_phys_addr_t addr,
2716 uint32_t value)
2717{
2718#if defined(DEBUG_SUBPAGE)
2719 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2720#endif
2721 subpage_writelen(opaque, addr, value, 1);
2722}
2723
2724static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2725{
2726#if defined(DEBUG_SUBPAGE)
2727 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2728#endif
2729
2730 return subpage_readlen(opaque, addr, 2);
2731}
2732
2733static void subpage_writel (void *opaque,
2734 target_phys_addr_t addr, uint32_t value)
2735{
2736#if defined(DEBUG_SUBPAGE)
2737 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2738#endif
2739 subpage_writelen(opaque, addr, value, 2);
2740}
2741
2742static CPUReadMemoryFunc *subpage_read[] = {
2743 &subpage_readb,
2744 &subpage_readw,
2745 &subpage_readl,
2746};
2747
2748static CPUWriteMemoryFunc *subpage_write[] = {
2749 &subpage_writeb,
2750 &subpage_writew,
2751 &subpage_writel,
2752};
2753
2754static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002755 ram_addr_t memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002756{
2757 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002758 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002759
2760 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2761 return -1;
2762 idx = SUBPAGE_IDX(start);
2763 eidx = SUBPAGE_IDX(end);
2764#if defined(DEBUG_SUBPAGE)
2765 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2766 mmio, start, end, idx, eidx, memory);
2767#endif
2768 memory >>= IO_MEM_SHIFT;
2769 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002770 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002771 if (io_mem_read[memory][i]) {
2772 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2773 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002774 mmio->region_offset[idx][0][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002775 }
2776 if (io_mem_write[memory][i]) {
2777 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2778 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002779 mmio->region_offset[idx][1][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002780 }
blueswir14254fab2008-01-01 16:57:19 +00002781 }
blueswir1db7b5422007-05-26 17:36:03 +00002782 }
2783
2784 return 0;
2785}
2786
aurel3200f82b82008-04-27 21:12:55 +00002787static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002788 ram_addr_t orig_memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002789{
2790 subpage_t *mmio;
2791 int subpage_memory;
2792
2793 mmio = qemu_mallocz(sizeof(subpage_t));
aliguori1eec6142009-02-05 22:06:18 +00002794
2795 mmio->base = base;
2796 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
blueswir1db7b5422007-05-26 17:36:03 +00002797#if defined(DEBUG_SUBPAGE)
aliguori1eec6142009-02-05 22:06:18 +00002798 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2799 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002800#endif
aliguori1eec6142009-02-05 22:06:18 +00002801 *phys = subpage_memory | IO_MEM_SUBPAGE;
2802 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
pbrook8da3ff12008-12-01 18:59:50 +00002803 region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002804
2805 return mmio;
2806}
2807
aliguori88715652009-02-11 15:20:58 +00002808static int get_free_io_mem_idx(void)
2809{
2810 int i;
2811
2812 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2813 if (!io_mem_used[i]) {
2814 io_mem_used[i] = 1;
2815 return i;
2816 }
2817
2818 return -1;
2819}
2820
bellard33417e72003-08-10 21:47:01 +00002821static void io_mem_init(void)
2822{
aliguori88715652009-02-11 15:20:58 +00002823 int i;
2824
bellard3a7d9292005-08-21 09:26:42 +00002825 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002826 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002827 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
aliguori88715652009-02-11 15:20:58 +00002828 for (i=0; i<5; i++)
2829 io_mem_used[i] = 1;
bellard1ccde1c2004-02-06 19:46:14 +00002830
pbrook0f459d12008-06-09 00:20:13 +00002831 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002832 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002833 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002834 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002835 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002836}
2837
2838/* mem_read and mem_write are arrays of functions containing the
2839 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002840 2). Functions can be omitted with a NULL function pointer. The
2841 registered functions may be modified dynamically later.
2842 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002843 modified. If it is zero, a new io zone is allocated. The return
2844 value can be used with cpu_register_physical_memory(). (-1) is
2845 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002846int cpu_register_io_memory(int io_index,
2847 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002848 CPUWriteMemoryFunc **mem_write,
2849 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002850{
blueswir14254fab2008-01-01 16:57:19 +00002851 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002852
2853 if (io_index <= 0) {
aliguori88715652009-02-11 15:20:58 +00002854 io_index = get_free_io_mem_idx();
2855 if (io_index == -1)
2856 return io_index;
bellard33417e72003-08-10 21:47:01 +00002857 } else {
2858 if (io_index >= IO_MEM_NB_ENTRIES)
2859 return -1;
2860 }
bellardb5ff1b32005-11-26 10:38:39 +00002861
bellard33417e72003-08-10 21:47:01 +00002862 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002863 if (!mem_read[i] || !mem_write[i])
2864 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002865 io_mem_read[io_index][i] = mem_read[i];
2866 io_mem_write[io_index][i] = mem_write[i];
2867 }
bellarda4193c82004-06-03 14:01:43 +00002868 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002869 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002870}
bellard61382a52003-10-27 21:22:23 +00002871
aliguori88715652009-02-11 15:20:58 +00002872void cpu_unregister_io_memory(int io_table_address)
2873{
2874 int i;
2875 int io_index = io_table_address >> IO_MEM_SHIFT;
2876
2877 for (i=0;i < 3; i++) {
2878 io_mem_read[io_index][i] = unassigned_mem_read[i];
2879 io_mem_write[io_index][i] = unassigned_mem_write[i];
2880 }
2881 io_mem_opaque[io_index] = NULL;
2882 io_mem_used[io_index] = 0;
2883}
2884
bellard8926b512004-10-10 15:14:20 +00002885CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2886{
2887 return io_mem_write[io_index >> IO_MEM_SHIFT];
2888}
2889
2890CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2891{
2892 return io_mem_read[io_index >> IO_MEM_SHIFT];
2893}
2894
pbrooke2eef172008-06-08 01:09:01 +00002895#endif /* !defined(CONFIG_USER_ONLY) */
2896
bellard13eb76e2004-01-24 15:23:36 +00002897/* physical memory access (slow version, mainly for debug) */
2898#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002899void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002900 int len, int is_write)
2901{
2902 int l, flags;
2903 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002904 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002905
2906 while (len > 0) {
2907 page = addr & TARGET_PAGE_MASK;
2908 l = (page + TARGET_PAGE_SIZE) - addr;
2909 if (l > len)
2910 l = len;
2911 flags = page_get_flags(page);
2912 if (!(flags & PAGE_VALID))
2913 return;
2914 if (is_write) {
2915 if (!(flags & PAGE_WRITE))
2916 return;
bellard579a97f2007-11-11 14:26:47 +00002917 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002918 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002919 /* FIXME - should this return an error rather than just fail? */
2920 return;
aurel3272fb7da2008-04-27 23:53:45 +00002921 memcpy(p, buf, l);
2922 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002923 } else {
2924 if (!(flags & PAGE_READ))
2925 return;
bellard579a97f2007-11-11 14:26:47 +00002926 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002927 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002928 /* FIXME - should this return an error rather than just fail? */
2929 return;
aurel3272fb7da2008-04-27 23:53:45 +00002930 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002931 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002932 }
2933 len -= l;
2934 buf += l;
2935 addr += l;
2936 }
2937}
bellard8df1cd02005-01-28 22:37:22 +00002938
bellard13eb76e2004-01-24 15:23:36 +00002939#else
ths5fafdf22007-09-16 21:08:06 +00002940void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002941 int len, int is_write)
2942{
2943 int l, io_index;
2944 uint8_t *ptr;
2945 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002946 target_phys_addr_t page;
2947 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002948 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002949
bellard13eb76e2004-01-24 15:23:36 +00002950 while (len > 0) {
2951 page = addr & TARGET_PAGE_MASK;
2952 l = (page + TARGET_PAGE_SIZE) - addr;
2953 if (l > len)
2954 l = len;
bellard92e873b2004-05-21 14:52:29 +00002955 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002956 if (!p) {
2957 pd = IO_MEM_UNASSIGNED;
2958 } else {
2959 pd = p->phys_offset;
2960 }
ths3b46e622007-09-17 08:09:54 +00002961
bellard13eb76e2004-01-24 15:23:36 +00002962 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002963 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
aurel326c2934d2009-02-18 21:37:17 +00002964 target_phys_addr_t addr1 = addr;
bellard13eb76e2004-01-24 15:23:36 +00002965 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002966 if (p)
aurel326c2934d2009-02-18 21:37:17 +00002967 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard6a00d602005-11-21 23:25:50 +00002968 /* XXX: could force cpu_single_env to NULL to avoid
2969 potential bugs */
aurel326c2934d2009-02-18 21:37:17 +00002970 if (l >= 4 && ((addr1 & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002971 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002972 val = ldl_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002973 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00002974 l = 4;
aurel326c2934d2009-02-18 21:37:17 +00002975 } else if (l >= 2 && ((addr1 & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002976 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002977 val = lduw_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002978 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00002979 l = 2;
2980 } else {
bellard1c213d12005-09-03 10:49:04 +00002981 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002982 val = ldub_p(buf);
aurel326c2934d2009-02-18 21:37:17 +00002983 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
bellard13eb76e2004-01-24 15:23:36 +00002984 l = 1;
2985 }
2986 } else {
bellardb448f2f2004-02-25 23:24:04 +00002987 unsigned long addr1;
2988 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002989 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002990 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002991 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002992 if (!cpu_physical_memory_is_dirty(addr1)) {
2993 /* invalidate code */
2994 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2995 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002996 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002997 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002998 }
bellard13eb76e2004-01-24 15:23:36 +00002999 }
3000 } else {
ths5fafdf22007-09-16 21:08:06 +00003001 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003002 !(pd & IO_MEM_ROMD)) {
aurel326c2934d2009-02-18 21:37:17 +00003003 target_phys_addr_t addr1 = addr;
bellard13eb76e2004-01-24 15:23:36 +00003004 /* I/O case */
3005 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003006 if (p)
aurel326c2934d2009-02-18 21:37:17 +00003007 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
3008 if (l >= 4 && ((addr1 & 3) == 0)) {
bellard13eb76e2004-01-24 15:23:36 +00003009 /* 32 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003010 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003011 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003012 l = 4;
aurel326c2934d2009-02-18 21:37:17 +00003013 } else if (l >= 2 && ((addr1 & 1) == 0)) {
bellard13eb76e2004-01-24 15:23:36 +00003014 /* 16 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003015 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003016 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003017 l = 2;
3018 } else {
bellard1c213d12005-09-03 10:49:04 +00003019 /* 8 bit read access */
aurel326c2934d2009-02-18 21:37:17 +00003020 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
bellardc27004e2005-01-03 23:35:10 +00003021 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003022 l = 1;
3023 }
3024 } else {
3025 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003026 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00003027 (addr & ~TARGET_PAGE_MASK);
3028 memcpy(buf, ptr, l);
3029 }
3030 }
3031 len -= l;
3032 buf += l;
3033 addr += l;
3034 }
3035}
bellard8df1cd02005-01-28 22:37:22 +00003036
bellardd0ecd2a2006-04-23 17:14:48 +00003037/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00003038void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00003039 const uint8_t *buf, int len)
3040{
3041 int l;
3042 uint8_t *ptr;
3043 target_phys_addr_t page;
3044 unsigned long pd;
3045 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00003046
bellardd0ecd2a2006-04-23 17:14:48 +00003047 while (len > 0) {
3048 page = addr & TARGET_PAGE_MASK;
3049 l = (page + TARGET_PAGE_SIZE) - addr;
3050 if (l > len)
3051 l = len;
3052 p = phys_page_find(page >> TARGET_PAGE_BITS);
3053 if (!p) {
3054 pd = IO_MEM_UNASSIGNED;
3055 } else {
3056 pd = p->phys_offset;
3057 }
ths3b46e622007-09-17 08:09:54 +00003058
bellardd0ecd2a2006-04-23 17:14:48 +00003059 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00003060 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3061 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00003062 /* do nothing */
3063 } else {
3064 unsigned long addr1;
3065 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3066 /* ROM/RAM case */
3067 ptr = phys_ram_base + addr1;
3068 memcpy(ptr, buf, l);
3069 }
3070 len -= l;
3071 buf += l;
3072 addr += l;
3073 }
3074}
3075
aliguori6d16c2f2009-01-22 16:59:11 +00003076typedef struct {
3077 void *buffer;
3078 target_phys_addr_t addr;
3079 target_phys_addr_t len;
3080} BounceBuffer;
3081
3082static BounceBuffer bounce;
3083
aliguoriba223c22009-01-22 16:59:16 +00003084typedef struct MapClient {
3085 void *opaque;
3086 void (*callback)(void *opaque);
3087 LIST_ENTRY(MapClient) link;
3088} MapClient;
3089
3090static LIST_HEAD(map_client_list, MapClient) map_client_list
3091 = LIST_HEAD_INITIALIZER(map_client_list);
3092
3093void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
3094{
3095 MapClient *client = qemu_malloc(sizeof(*client));
3096
3097 client->opaque = opaque;
3098 client->callback = callback;
3099 LIST_INSERT_HEAD(&map_client_list, client, link);
3100 return client;
3101}
3102
3103void cpu_unregister_map_client(void *_client)
3104{
3105 MapClient *client = (MapClient *)_client;
3106
3107 LIST_REMOVE(client, link);
3108}
3109
3110static void cpu_notify_map_clients(void)
3111{
3112 MapClient *client;
3113
3114 while (!LIST_EMPTY(&map_client_list)) {
3115 client = LIST_FIRST(&map_client_list);
3116 client->callback(client->opaque);
3117 LIST_REMOVE(client, link);
3118 }
3119}
3120
aliguori6d16c2f2009-01-22 16:59:11 +00003121/* Map a physical memory region into a host virtual address.
3122 * May map a subset of the requested range, given by and returned in *plen.
3123 * May return NULL if resources needed to perform the mapping are exhausted.
3124 * Use only for reads OR writes - not for read-modify-write operations.
aliguoriba223c22009-01-22 16:59:16 +00003125 * Use cpu_register_map_client() to know when retrying the map operation is
3126 * likely to succeed.
aliguori6d16c2f2009-01-22 16:59:11 +00003127 */
3128void *cpu_physical_memory_map(target_phys_addr_t addr,
3129 target_phys_addr_t *plen,
3130 int is_write)
3131{
3132 target_phys_addr_t len = *plen;
3133 target_phys_addr_t done = 0;
3134 int l;
3135 uint8_t *ret = NULL;
3136 uint8_t *ptr;
3137 target_phys_addr_t page;
3138 unsigned long pd;
3139 PhysPageDesc *p;
3140 unsigned long addr1;
3141
3142 while (len > 0) {
3143 page = addr & TARGET_PAGE_MASK;
3144 l = (page + TARGET_PAGE_SIZE) - addr;
3145 if (l > len)
3146 l = len;
3147 p = phys_page_find(page >> TARGET_PAGE_BITS);
3148 if (!p) {
3149 pd = IO_MEM_UNASSIGNED;
3150 } else {
3151 pd = p->phys_offset;
3152 }
3153
3154 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3155 if (done || bounce.buffer) {
3156 break;
3157 }
3158 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
3159 bounce.addr = addr;
3160 bounce.len = l;
3161 if (!is_write) {
3162 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
3163 }
3164 ptr = bounce.buffer;
3165 } else {
3166 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3167 ptr = phys_ram_base + addr1;
3168 }
3169 if (!done) {
3170 ret = ptr;
3171 } else if (ret + done != ptr) {
3172 break;
3173 }
3174
3175 len -= l;
3176 addr += l;
3177 done += l;
3178 }
3179 *plen = done;
3180 return ret;
3181}
3182
3183/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
3184 * Will also mark the memory as dirty if is_write == 1. access_len gives
3185 * the amount of memory that was actually read or written by the caller.
3186 */
3187void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
3188 int is_write, target_phys_addr_t access_len)
3189{
3190 if (buffer != bounce.buffer) {
3191 if (is_write) {
3192 unsigned long addr1 = (uint8_t *)buffer - phys_ram_base;
3193 while (access_len) {
3194 unsigned l;
3195 l = TARGET_PAGE_SIZE;
3196 if (l > access_len)
3197 l = access_len;
3198 if (!cpu_physical_memory_is_dirty(addr1)) {
3199 /* invalidate code */
3200 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3201 /* set dirty bit */
3202 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3203 (0xff & ~CODE_DIRTY_FLAG);
3204 }
3205 addr1 += l;
3206 access_len -= l;
3207 }
3208 }
3209 return;
3210 }
3211 if (is_write) {
3212 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
3213 }
3214 qemu_free(bounce.buffer);
3215 bounce.buffer = NULL;
aliguoriba223c22009-01-22 16:59:16 +00003216 cpu_notify_map_clients();
aliguori6d16c2f2009-01-22 16:59:11 +00003217}
bellardd0ecd2a2006-04-23 17:14:48 +00003218
bellard8df1cd02005-01-28 22:37:22 +00003219/* warning: addr must be aligned */
3220uint32_t ldl_phys(target_phys_addr_t addr)
3221{
3222 int io_index;
3223 uint8_t *ptr;
3224 uint32_t val;
3225 unsigned long pd;
3226 PhysPageDesc *p;
3227
3228 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3229 if (!p) {
3230 pd = IO_MEM_UNASSIGNED;
3231 } else {
3232 pd = p->phys_offset;
3233 }
ths3b46e622007-09-17 08:09:54 +00003234
ths5fafdf22007-09-16 21:08:06 +00003235 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003236 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00003237 /* I/O case */
3238 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003239 if (p)
3240 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003241 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3242 } else {
3243 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003244 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00003245 (addr & ~TARGET_PAGE_MASK);
3246 val = ldl_p(ptr);
3247 }
3248 return val;
3249}
3250
bellard84b7b8e2005-11-28 21:19:04 +00003251/* warning: addr must be aligned */
3252uint64_t ldq_phys(target_phys_addr_t addr)
3253{
3254 int io_index;
3255 uint8_t *ptr;
3256 uint64_t val;
3257 unsigned long pd;
3258 PhysPageDesc *p;
3259
3260 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3261 if (!p) {
3262 pd = IO_MEM_UNASSIGNED;
3263 } else {
3264 pd = p->phys_offset;
3265 }
ths3b46e622007-09-17 08:09:54 +00003266
bellard2a4188a2006-06-25 21:54:59 +00003267 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3268 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00003269 /* I/O case */
3270 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003271 if (p)
3272 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard84b7b8e2005-11-28 21:19:04 +00003273#ifdef TARGET_WORDS_BIGENDIAN
3274 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3275 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3276#else
3277 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3278 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3279#endif
3280 } else {
3281 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003282 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00003283 (addr & ~TARGET_PAGE_MASK);
3284 val = ldq_p(ptr);
3285 }
3286 return val;
3287}
3288
bellardaab33092005-10-30 20:48:42 +00003289/* XXX: optimize */
3290uint32_t ldub_phys(target_phys_addr_t addr)
3291{
3292 uint8_t val;
3293 cpu_physical_memory_read(addr, &val, 1);
3294 return val;
3295}
3296
3297/* XXX: optimize */
3298uint32_t lduw_phys(target_phys_addr_t addr)
3299{
3300 uint16_t val;
3301 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3302 return tswap16(val);
3303}
3304
bellard8df1cd02005-01-28 22:37:22 +00003305/* warning: addr must be aligned. The ram page is not masked as dirty
3306 and the code inside is not invalidated. It is useful if the dirty
3307 bits are used to track modified PTEs */
3308void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
3309{
3310 int io_index;
3311 uint8_t *ptr;
3312 unsigned long pd;
3313 PhysPageDesc *p;
3314
3315 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3316 if (!p) {
3317 pd = IO_MEM_UNASSIGNED;
3318 } else {
3319 pd = p->phys_offset;
3320 }
ths3b46e622007-09-17 08:09:54 +00003321
bellard3a7d9292005-08-21 09:26:42 +00003322 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003323 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003324 if (p)
3325 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003326 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3327 } else {
aliguori74576192008-10-06 14:02:03 +00003328 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3329 ptr = phys_ram_base + addr1;
bellard8df1cd02005-01-28 22:37:22 +00003330 stl_p(ptr, val);
aliguori74576192008-10-06 14:02:03 +00003331
3332 if (unlikely(in_migration)) {
3333 if (!cpu_physical_memory_is_dirty(addr1)) {
3334 /* invalidate code */
3335 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3336 /* set dirty bit */
3337 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3338 (0xff & ~CODE_DIRTY_FLAG);
3339 }
3340 }
bellard8df1cd02005-01-28 22:37:22 +00003341 }
3342}
3343
j_mayerbc98a7e2007-04-04 07:55:12 +00003344void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
3345{
3346 int io_index;
3347 uint8_t *ptr;
3348 unsigned long pd;
3349 PhysPageDesc *p;
3350
3351 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3352 if (!p) {
3353 pd = IO_MEM_UNASSIGNED;
3354 } else {
3355 pd = p->phys_offset;
3356 }
ths3b46e622007-09-17 08:09:54 +00003357
j_mayerbc98a7e2007-04-04 07:55:12 +00003358 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3359 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003360 if (p)
3361 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
j_mayerbc98a7e2007-04-04 07:55:12 +00003362#ifdef TARGET_WORDS_BIGENDIAN
3363 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3364 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3365#else
3366 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3367 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3368#endif
3369 } else {
ths5fafdf22007-09-16 21:08:06 +00003370 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00003371 (addr & ~TARGET_PAGE_MASK);
3372 stq_p(ptr, val);
3373 }
3374}
3375
bellard8df1cd02005-01-28 22:37:22 +00003376/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00003377void stl_phys(target_phys_addr_t addr, uint32_t val)
3378{
3379 int io_index;
3380 uint8_t *ptr;
3381 unsigned long pd;
3382 PhysPageDesc *p;
3383
3384 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3385 if (!p) {
3386 pd = IO_MEM_UNASSIGNED;
3387 } else {
3388 pd = p->phys_offset;
3389 }
ths3b46e622007-09-17 08:09:54 +00003390
bellard3a7d9292005-08-21 09:26:42 +00003391 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003392 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003393 if (p)
3394 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003395 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3396 } else {
3397 unsigned long addr1;
3398 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3399 /* RAM case */
3400 ptr = phys_ram_base + addr1;
3401 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003402 if (!cpu_physical_memory_is_dirty(addr1)) {
3403 /* invalidate code */
3404 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3405 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003406 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3407 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003408 }
bellard8df1cd02005-01-28 22:37:22 +00003409 }
3410}
3411
bellardaab33092005-10-30 20:48:42 +00003412/* XXX: optimize */
3413void stb_phys(target_phys_addr_t addr, uint32_t val)
3414{
3415 uint8_t v = val;
3416 cpu_physical_memory_write(addr, &v, 1);
3417}
3418
3419/* XXX: optimize */
3420void stw_phys(target_phys_addr_t addr, uint32_t val)
3421{
3422 uint16_t v = tswap16(val);
3423 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3424}
3425
3426/* XXX: optimize */
3427void stq_phys(target_phys_addr_t addr, uint64_t val)
3428{
3429 val = tswap64(val);
3430 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3431}
3432
bellard13eb76e2004-01-24 15:23:36 +00003433#endif
3434
3435/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00003436int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003437 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003438{
3439 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003440 target_phys_addr_t phys_addr;
3441 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003442
3443 while (len > 0) {
3444 page = addr & TARGET_PAGE_MASK;
3445 phys_addr = cpu_get_phys_page_debug(env, page);
3446 /* if no physical page mapped, return an error */
3447 if (phys_addr == -1)
3448 return -1;
3449 l = (page + TARGET_PAGE_SIZE) - addr;
3450 if (l > len)
3451 l = len;
ths5fafdf22007-09-16 21:08:06 +00003452 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00003453 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003454 len -= l;
3455 buf += l;
3456 addr += l;
3457 }
3458 return 0;
3459}
3460
pbrook2e70f6e2008-06-29 01:03:05 +00003461/* in deterministic execution mode, instructions doing device I/Os
3462 must be at the end of the TB */
3463void cpu_io_recompile(CPUState *env, void *retaddr)
3464{
3465 TranslationBlock *tb;
3466 uint32_t n, cflags;
3467 target_ulong pc, cs_base;
3468 uint64_t flags;
3469
3470 tb = tb_find_pc((unsigned long)retaddr);
3471 if (!tb) {
3472 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3473 retaddr);
3474 }
3475 n = env->icount_decr.u16.low + tb->icount;
3476 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3477 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003478 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003479 n = n - env->icount_decr.u16.low;
3480 /* Generate a new TB ending on the I/O insn. */
3481 n++;
3482 /* On MIPS and SH, delay slot instructions can only be restarted if
3483 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003484 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003485 branch. */
3486#if defined(TARGET_MIPS)
3487 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3488 env->active_tc.PC -= 4;
3489 env->icount_decr.u16.low++;
3490 env->hflags &= ~MIPS_HFLAG_BMASK;
3491 }
3492#elif defined(TARGET_SH4)
3493 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3494 && n > 1) {
3495 env->pc -= 2;
3496 env->icount_decr.u16.low++;
3497 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3498 }
3499#endif
3500 /* This should never happen. */
3501 if (n > CF_COUNT_MASK)
3502 cpu_abort(env, "TB too big during recompile");
3503
3504 cflags = n | CF_LAST_IO;
3505 pc = tb->pc;
3506 cs_base = tb->cs_base;
3507 flags = tb->flags;
3508 tb_phys_invalidate(tb, -1);
3509 /* FIXME: In theory this could raise an exception. In practice
3510 we have already translated the block once so it's probably ok. */
3511 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003512 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003513 the first in the TB) then we end up generating a whole new TB and
3514 repeating the fault, which is horribly inefficient.
3515 Better would be to execute just this insn uncached, or generate a
3516 second new TB. */
3517 cpu_resume_from_signal(env, NULL);
3518}
3519
bellarde3db7222005-01-26 22:00:47 +00003520void dump_exec_info(FILE *f,
3521 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3522{
3523 int i, target_code_size, max_target_code_size;
3524 int direct_jmp_count, direct_jmp2_count, cross_page;
3525 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003526
bellarde3db7222005-01-26 22:00:47 +00003527 target_code_size = 0;
3528 max_target_code_size = 0;
3529 cross_page = 0;
3530 direct_jmp_count = 0;
3531 direct_jmp2_count = 0;
3532 for(i = 0; i < nb_tbs; i++) {
3533 tb = &tbs[i];
3534 target_code_size += tb->size;
3535 if (tb->size > max_target_code_size)
3536 max_target_code_size = tb->size;
3537 if (tb->page_addr[1] != -1)
3538 cross_page++;
3539 if (tb->tb_next_offset[0] != 0xffff) {
3540 direct_jmp_count++;
3541 if (tb->tb_next_offset[1] != 0xffff) {
3542 direct_jmp2_count++;
3543 }
3544 }
3545 }
3546 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003547 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003548 cpu_fprintf(f, "gen code size %ld/%ld\n",
3549 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3550 cpu_fprintf(f, "TB count %d/%d\n",
3551 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003552 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003553 nb_tbs ? target_code_size / nb_tbs : 0,
3554 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003555 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003556 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3557 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003558 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3559 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003560 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3561 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003562 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003563 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3564 direct_jmp2_count,
3565 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003566 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003567 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3568 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3569 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003570 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003571}
3572
ths5fafdf22007-09-16 21:08:06 +00003573#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003574
3575#define MMUSUFFIX _cmmu
3576#define GETPC() NULL
3577#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003578#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003579
3580#define SHIFT 0
3581#include "softmmu_template.h"
3582
3583#define SHIFT 1
3584#include "softmmu_template.h"
3585
3586#define SHIFT 2
3587#include "softmmu_template.h"
3588
3589#define SHIFT 3
3590#include "softmmu_template.h"
3591
3592#undef env
3593
3594#endif