blob: 7ed7e3ed32654ca512f5482f6f5d156a692a1028 [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;
371 for (i = 0; i < L2_SIZE; i++)
372 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000373 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000374 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000375}
376
bellard108c49b2005-07-24 12:55:09 +0000377static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000378{
bellard108c49b2005-07-24 12:55:09 +0000379 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000380}
381
bellard9fa3e852004-01-04 18:06:42 +0000382#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000383static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000384static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000385 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000386#define mmap_lock() do { } while(0)
387#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000388#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000389
bellard43694152008-05-29 09:35:57 +0000390#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
391
392#if defined(CONFIG_USER_ONLY)
393/* Currently it is not recommanded to allocate big chunks of data in
394 user mode. It will change when a dedicated libc will be used */
395#define USE_STATIC_CODE_GEN_BUFFER
396#endif
397
398#ifdef USE_STATIC_CODE_GEN_BUFFER
399static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
400#endif
401
blueswir18fcd3692008-08-17 20:26:25 +0000402static void code_gen_alloc(unsigned long tb_size)
bellard26a5f132008-05-28 12:30:31 +0000403{
bellard43694152008-05-29 09:35:57 +0000404#ifdef USE_STATIC_CODE_GEN_BUFFER
405 code_gen_buffer = static_code_gen_buffer;
406 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
407 map_exec(code_gen_buffer, code_gen_buffer_size);
408#else
bellard26a5f132008-05-28 12:30:31 +0000409 code_gen_buffer_size = tb_size;
410 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000411#if defined(CONFIG_USER_ONLY)
412 /* in user mode, phys_ram_size is not meaningful */
413 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
414#else
bellard26a5f132008-05-28 12:30:31 +0000415 /* XXX: needs ajustments */
aliguori174a9a12008-09-24 14:10:36 +0000416 code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000417#endif
bellard26a5f132008-05-28 12:30:31 +0000418 }
419 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
420 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
421 /* The code gen buffer location may have constraints depending on
422 the host cpu and OS */
423#if defined(__linux__)
424 {
425 int flags;
blueswir1141ac462008-07-26 15:05:57 +0000426 void *start = NULL;
427
bellard26a5f132008-05-28 12:30:31 +0000428 flags = MAP_PRIVATE | MAP_ANONYMOUS;
429#if defined(__x86_64__)
430 flags |= MAP_32BIT;
431 /* Cannot map more than that */
432 if (code_gen_buffer_size > (800 * 1024 * 1024))
433 code_gen_buffer_size = (800 * 1024 * 1024);
blueswir1141ac462008-07-26 15:05:57 +0000434#elif defined(__sparc_v9__)
435 // Map the buffer below 2G, so we can use direct calls and branches
436 flags |= MAP_FIXED;
437 start = (void *) 0x60000000UL;
438 if (code_gen_buffer_size > (512 * 1024 * 1024))
439 code_gen_buffer_size = (512 * 1024 * 1024);
balrog1cb06612008-12-01 02:10:17 +0000440#elif defined(__arm__)
balrog63d41242008-12-01 02:19:41 +0000441 /* Map the buffer below 32M, so we can use direct calls and branches */
balrog1cb06612008-12-01 02:10:17 +0000442 flags |= MAP_FIXED;
443 start = (void *) 0x01000000UL;
444 if (code_gen_buffer_size > 16 * 1024 * 1024)
445 code_gen_buffer_size = 16 * 1024 * 1024;
bellard26a5f132008-05-28 12:30:31 +0000446#endif
blueswir1141ac462008-07-26 15:05:57 +0000447 code_gen_buffer = mmap(start, code_gen_buffer_size,
448 PROT_WRITE | PROT_READ | PROT_EXEC,
bellard26a5f132008-05-28 12:30:31 +0000449 flags, -1, 0);
450 if (code_gen_buffer == MAP_FAILED) {
451 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
452 exit(1);
453 }
454 }
aliguori06e67a82008-09-27 15:32:41 +0000455#elif defined(__FreeBSD__)
456 {
457 int flags;
458 void *addr = NULL;
459 flags = MAP_PRIVATE | MAP_ANONYMOUS;
460#if defined(__x86_64__)
461 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
462 * 0x40000000 is free */
463 flags |= MAP_FIXED;
464 addr = (void *)0x40000000;
465 /* Cannot map more than that */
466 if (code_gen_buffer_size > (800 * 1024 * 1024))
467 code_gen_buffer_size = (800 * 1024 * 1024);
468#endif
469 code_gen_buffer = mmap(addr, code_gen_buffer_size,
470 PROT_WRITE | PROT_READ | PROT_EXEC,
471 flags, -1, 0);
472 if (code_gen_buffer == MAP_FAILED) {
473 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
474 exit(1);
475 }
476 }
bellard26a5f132008-05-28 12:30:31 +0000477#else
478 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
bellard26a5f132008-05-28 12:30:31 +0000479 map_exec(code_gen_buffer, code_gen_buffer_size);
480#endif
bellard43694152008-05-29 09:35:57 +0000481#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000482 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
483 code_gen_buffer_max_size = code_gen_buffer_size -
484 code_gen_max_block_size();
485 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
486 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
487}
488
489/* Must be called before using the QEMU cpus. 'tb_size' is the size
490 (in bytes) allocated to the translation buffer. Zero means default
491 size. */
492void cpu_exec_init_all(unsigned long tb_size)
493{
bellard26a5f132008-05-28 12:30:31 +0000494 cpu_gen_init();
495 code_gen_alloc(tb_size);
496 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000497 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000498#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000499 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000500#endif
bellard26a5f132008-05-28 12:30:31 +0000501}
502
pbrook9656f322008-07-01 20:01:19 +0000503#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
504
505#define CPU_COMMON_SAVE_VERSION 1
506
507static void cpu_common_save(QEMUFile *f, void *opaque)
508{
509 CPUState *env = opaque;
510
511 qemu_put_be32s(f, &env->halted);
512 qemu_put_be32s(f, &env->interrupt_request);
513}
514
515static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
516{
517 CPUState *env = opaque;
518
519 if (version_id != CPU_COMMON_SAVE_VERSION)
520 return -EINVAL;
521
522 qemu_get_be32s(f, &env->halted);
pbrook75f482a2008-07-01 21:53:33 +0000523 qemu_get_be32s(f, &env->interrupt_request);
pbrook9656f322008-07-01 20:01:19 +0000524 tlb_flush(env, 1);
525
526 return 0;
527}
528#endif
529
bellard6a00d602005-11-21 23:25:50 +0000530void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000531{
bellard6a00d602005-11-21 23:25:50 +0000532 CPUState **penv;
533 int cpu_index;
534
bellard6a00d602005-11-21 23:25:50 +0000535 env->next_cpu = NULL;
536 penv = &first_cpu;
537 cpu_index = 0;
538 while (*penv != NULL) {
539 penv = (CPUState **)&(*penv)->next_cpu;
540 cpu_index++;
541 }
542 env->cpu_index = cpu_index;
aliguoric0ce9982008-11-25 22:13:57 +0000543 TAILQ_INIT(&env->breakpoints);
544 TAILQ_INIT(&env->watchpoints);
bellard6a00d602005-11-21 23:25:50 +0000545 *penv = env;
pbrookb3c77242008-06-30 16:31:04 +0000546#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
pbrook9656f322008-07-01 20:01:19 +0000547 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
548 cpu_common_save, cpu_common_load, env);
pbrookb3c77242008-06-30 16:31:04 +0000549 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
550 cpu_save, cpu_load, env);
551#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000552}
553
bellard9fa3e852004-01-04 18:06:42 +0000554static inline void invalidate_page_bitmap(PageDesc *p)
555{
556 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000557 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000558 p->code_bitmap = NULL;
559 }
560 p->code_write_count = 0;
561}
562
bellardfd6ce8f2003-05-14 19:00:11 +0000563/* set to NULL all the 'first_tb' fields in all PageDescs */
564static void page_flush_tb(void)
565{
566 int i, j;
567 PageDesc *p;
568
569 for(i = 0; i < L1_SIZE; i++) {
570 p = l1_map[i];
571 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000572 for(j = 0; j < L2_SIZE; j++) {
573 p->first_tb = NULL;
574 invalidate_page_bitmap(p);
575 p++;
576 }
bellardfd6ce8f2003-05-14 19:00:11 +0000577 }
578 }
579}
580
581/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000582/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000583void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000584{
bellard6a00d602005-11-21 23:25:50 +0000585 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000586#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000587 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
588 (unsigned long)(code_gen_ptr - code_gen_buffer),
589 nb_tbs, nb_tbs > 0 ?
590 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000591#endif
bellard26a5f132008-05-28 12:30:31 +0000592 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000593 cpu_abort(env1, "Internal error: code buffer overflow\n");
594
bellardfd6ce8f2003-05-14 19:00:11 +0000595 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000596
bellard6a00d602005-11-21 23:25:50 +0000597 for(env = first_cpu; env != NULL; env = env->next_cpu) {
598 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
599 }
bellard9fa3e852004-01-04 18:06:42 +0000600
bellard8a8a6082004-10-03 13:36:49 +0000601 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000602 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000603
bellardfd6ce8f2003-05-14 19:00:11 +0000604 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000605 /* XXX: flush processor icache at this point if cache flush is
606 expensive */
bellarde3db7222005-01-26 22:00:47 +0000607 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000608}
609
610#ifdef DEBUG_TB_CHECK
611
j_mayerbc98a7e2007-04-04 07:55:12 +0000612static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000613{
614 TranslationBlock *tb;
615 int i;
616 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000617 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
618 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000619 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
620 address >= tb->pc + tb->size)) {
621 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000622 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000623 }
624 }
625 }
626}
627
628/* verify that all the pages have correct rights for code */
629static void tb_page_check(void)
630{
631 TranslationBlock *tb;
632 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000633
pbrook99773bd2006-04-16 15:14:59 +0000634 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
635 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000636 flags1 = page_get_flags(tb->pc);
637 flags2 = page_get_flags(tb->pc + tb->size - 1);
638 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
639 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000640 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000641 }
642 }
643 }
644}
645
blueswir1bdaf78e2008-10-04 07:24:27 +0000646static void tb_jmp_check(TranslationBlock *tb)
bellardd4e81642003-05-25 16:46:15 +0000647{
648 TranslationBlock *tb1;
649 unsigned int n1;
650
651 /* suppress any remaining jumps to this TB */
652 tb1 = tb->jmp_first;
653 for(;;) {
654 n1 = (long)tb1 & 3;
655 tb1 = (TranslationBlock *)((long)tb1 & ~3);
656 if (n1 == 2)
657 break;
658 tb1 = tb1->jmp_next[n1];
659 }
660 /* check end of list */
661 if (tb1 != tb) {
662 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
663 }
664}
665
bellardfd6ce8f2003-05-14 19:00:11 +0000666#endif
667
668/* invalidate one TB */
669static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
670 int next_offset)
671{
672 TranslationBlock *tb1;
673 for(;;) {
674 tb1 = *ptb;
675 if (tb1 == tb) {
676 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
677 break;
678 }
679 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
680 }
681}
682
bellard9fa3e852004-01-04 18:06:42 +0000683static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
684{
685 TranslationBlock *tb1;
686 unsigned int n1;
687
688 for(;;) {
689 tb1 = *ptb;
690 n1 = (long)tb1 & 3;
691 tb1 = (TranslationBlock *)((long)tb1 & ~3);
692 if (tb1 == tb) {
693 *ptb = tb1->page_next[n1];
694 break;
695 }
696 ptb = &tb1->page_next[n1];
697 }
698}
699
bellardd4e81642003-05-25 16:46:15 +0000700static inline void tb_jmp_remove(TranslationBlock *tb, int n)
701{
702 TranslationBlock *tb1, **ptb;
703 unsigned int n1;
704
705 ptb = &tb->jmp_next[n];
706 tb1 = *ptb;
707 if (tb1) {
708 /* find tb(n) in circular list */
709 for(;;) {
710 tb1 = *ptb;
711 n1 = (long)tb1 & 3;
712 tb1 = (TranslationBlock *)((long)tb1 & ~3);
713 if (n1 == n && tb1 == tb)
714 break;
715 if (n1 == 2) {
716 ptb = &tb1->jmp_first;
717 } else {
718 ptb = &tb1->jmp_next[n1];
719 }
720 }
721 /* now we can suppress tb(n) from the list */
722 *ptb = tb->jmp_next[n];
723
724 tb->jmp_next[n] = NULL;
725 }
726}
727
728/* reset the jump entry 'n' of a TB so that it is not chained to
729 another TB */
730static inline void tb_reset_jump(TranslationBlock *tb, int n)
731{
732 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
733}
734
pbrook2e70f6e2008-06-29 01:03:05 +0000735void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000736{
bellard6a00d602005-11-21 23:25:50 +0000737 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000738 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000739 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000740 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000741 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000742
bellard9fa3e852004-01-04 18:06:42 +0000743 /* remove the TB from the hash list */
744 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
745 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000746 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000747 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000748
bellard9fa3e852004-01-04 18:06:42 +0000749 /* remove the TB from the page list */
750 if (tb->page_addr[0] != page_addr) {
751 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
752 tb_page_remove(&p->first_tb, tb);
753 invalidate_page_bitmap(p);
754 }
755 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
756 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
757 tb_page_remove(&p->first_tb, tb);
758 invalidate_page_bitmap(p);
759 }
760
bellard8a40a182005-11-20 10:35:40 +0000761 tb_invalidated_flag = 1;
762
763 /* remove the TB from the hash list */
764 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000765 for(env = first_cpu; env != NULL; env = env->next_cpu) {
766 if (env->tb_jmp_cache[h] == tb)
767 env->tb_jmp_cache[h] = NULL;
768 }
bellard8a40a182005-11-20 10:35:40 +0000769
770 /* suppress this TB from the two jump lists */
771 tb_jmp_remove(tb, 0);
772 tb_jmp_remove(tb, 1);
773
774 /* suppress any remaining jumps to this TB */
775 tb1 = tb->jmp_first;
776 for(;;) {
777 n1 = (long)tb1 & 3;
778 if (n1 == 2)
779 break;
780 tb1 = (TranslationBlock *)((long)tb1 & ~3);
781 tb2 = tb1->jmp_next[n1];
782 tb_reset_jump(tb1, n1);
783 tb1->jmp_next[n1] = NULL;
784 tb1 = tb2;
785 }
786 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
787
bellarde3db7222005-01-26 22:00:47 +0000788 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000789}
790
791static inline void set_bits(uint8_t *tab, int start, int len)
792{
793 int end, mask, end1;
794
795 end = start + len;
796 tab += start >> 3;
797 mask = 0xff << (start & 7);
798 if ((start & ~7) == (end & ~7)) {
799 if (start < end) {
800 mask &= ~(0xff << (end & 7));
801 *tab |= mask;
802 }
803 } else {
804 *tab++ |= mask;
805 start = (start + 8) & ~7;
806 end1 = end & ~7;
807 while (start < end1) {
808 *tab++ = 0xff;
809 start += 8;
810 }
811 if (start < end) {
812 mask = ~(0xff << (end & 7));
813 *tab |= mask;
814 }
815 }
816}
817
818static void build_page_bitmap(PageDesc *p)
819{
820 int n, tb_start, tb_end;
821 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000822
pbrookb2a70812008-06-09 13:57:23 +0000823 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000824
825 tb = p->first_tb;
826 while (tb != NULL) {
827 n = (long)tb & 3;
828 tb = (TranslationBlock *)((long)tb & ~3);
829 /* NOTE: this is subtle as a TB may span two physical pages */
830 if (n == 0) {
831 /* NOTE: tb_end may be after the end of the page, but
832 it is not a problem */
833 tb_start = tb->pc & ~TARGET_PAGE_MASK;
834 tb_end = tb_start + tb->size;
835 if (tb_end > TARGET_PAGE_SIZE)
836 tb_end = TARGET_PAGE_SIZE;
837 } else {
838 tb_start = 0;
839 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
840 }
841 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
842 tb = tb->page_next[n];
843 }
844}
845
pbrook2e70f6e2008-06-29 01:03:05 +0000846TranslationBlock *tb_gen_code(CPUState *env,
847 target_ulong pc, target_ulong cs_base,
848 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000849{
850 TranslationBlock *tb;
851 uint8_t *tc_ptr;
852 target_ulong phys_pc, phys_page2, virt_page2;
853 int code_gen_size;
854
bellardc27004e2005-01-03 23:35:10 +0000855 phys_pc = get_phys_addr_code(env, pc);
856 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000857 if (!tb) {
858 /* flush must be done */
859 tb_flush(env);
860 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000861 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000862 /* Don't forget to invalidate previous TB info. */
863 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000864 }
865 tc_ptr = code_gen_ptr;
866 tb->tc_ptr = tc_ptr;
867 tb->cs_base = cs_base;
868 tb->flags = flags;
869 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000870 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000871 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 +0000872
bellardd720b932004-04-25 17:57:43 +0000873 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000874 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000875 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000876 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000877 phys_page2 = get_phys_addr_code(env, virt_page2);
878 }
879 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000880 return tb;
bellardd720b932004-04-25 17:57:43 +0000881}
ths3b46e622007-09-17 08:09:54 +0000882
bellard9fa3e852004-01-04 18:06:42 +0000883/* invalidate all TBs which intersect with the target physical page
884 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000885 the same physical page. 'is_cpu_write_access' should be true if called
886 from a real cpu write access: the virtual CPU will exit the current
887 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000888void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000889 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000890{
aliguori6b917542008-11-18 19:46:41 +0000891 TranslationBlock *tb, *tb_next, *saved_tb;
bellardd720b932004-04-25 17:57:43 +0000892 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000893 target_ulong tb_start, tb_end;
aliguori6b917542008-11-18 19:46:41 +0000894 PageDesc *p;
895 int n;
896#ifdef TARGET_HAS_PRECISE_SMC
897 int current_tb_not_found = is_cpu_write_access;
898 TranslationBlock *current_tb = NULL;
899 int current_tb_modified = 0;
900 target_ulong current_pc = 0;
901 target_ulong current_cs_base = 0;
902 int current_flags = 0;
903#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000904
905 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000906 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000907 return;
ths5fafdf22007-09-16 21:08:06 +0000908 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000909 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
910 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000911 /* build code bitmap */
912 build_page_bitmap(p);
913 }
914
915 /* we remove all the TBs in the range [start, end[ */
916 /* XXX: see if in some cases it could be faster to invalidate all the code */
917 tb = p->first_tb;
918 while (tb != NULL) {
919 n = (long)tb & 3;
920 tb = (TranslationBlock *)((long)tb & ~3);
921 tb_next = tb->page_next[n];
922 /* NOTE: this is subtle as a TB may span two physical pages */
923 if (n == 0) {
924 /* NOTE: tb_end may be after the end of the page, but
925 it is not a problem */
926 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
927 tb_end = tb_start + tb->size;
928 } else {
929 tb_start = tb->page_addr[1];
930 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
931 }
932 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000933#ifdef TARGET_HAS_PRECISE_SMC
934 if (current_tb_not_found) {
935 current_tb_not_found = 0;
936 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000937 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000938 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000939 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000940 }
941 }
942 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000943 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000944 /* If we are modifying the current TB, we must stop
945 its execution. We could be more precise by checking
946 that the modification is after the current PC, but it
947 would require a specialized function to partially
948 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000949
bellardd720b932004-04-25 17:57:43 +0000950 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000951 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000952 env->mem_io_pc, NULL);
aliguori6b917542008-11-18 19:46:41 +0000953 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
954 &current_flags);
bellardd720b932004-04-25 17:57:43 +0000955 }
956#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000957 /* we need to do that to handle the case where a signal
958 occurs while doing tb_phys_invalidate() */
959 saved_tb = NULL;
960 if (env) {
961 saved_tb = env->current_tb;
962 env->current_tb = NULL;
963 }
bellard9fa3e852004-01-04 18:06:42 +0000964 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000965 if (env) {
966 env->current_tb = saved_tb;
967 if (env->interrupt_request && env->current_tb)
968 cpu_interrupt(env, env->interrupt_request);
969 }
bellard9fa3e852004-01-04 18:06:42 +0000970 }
971 tb = tb_next;
972 }
973#if !defined(CONFIG_USER_ONLY)
974 /* if no code remaining, no need to continue to use slow writes */
975 if (!p->first_tb) {
976 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000977 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000978 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000979 }
980 }
981#endif
982#ifdef TARGET_HAS_PRECISE_SMC
983 if (current_tb_modified) {
984 /* we generate a block containing just the instruction
985 modifying the memory. It will ensure that it cannot modify
986 itself */
bellardea1c1802004-06-14 18:56:36 +0000987 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000988 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000989 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000990 }
991#endif
992}
993
994/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000995static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000996{
997 PageDesc *p;
998 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000999#if 0
bellarda4193c82004-06-03 14:01:43 +00001000 if (1) {
aliguori93fcfe32009-01-15 22:34:14 +00001001 qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
1002 cpu_single_env->mem_io_vaddr, len,
1003 cpu_single_env->eip,
1004 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
bellard59817cc2004-02-16 22:01:13 +00001005 }
1006#endif
bellard9fa3e852004-01-04 18:06:42 +00001007 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001008 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001009 return;
1010 if (p->code_bitmap) {
1011 offset = start & ~TARGET_PAGE_MASK;
1012 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1013 if (b & ((1 << len) - 1))
1014 goto do_invalidate;
1015 } else {
1016 do_invalidate:
bellardd720b932004-04-25 17:57:43 +00001017 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +00001018 }
1019}
1020
bellard9fa3e852004-01-04 18:06:42 +00001021#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +00001022static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +00001023 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001024{
aliguori6b917542008-11-18 19:46:41 +00001025 TranslationBlock *tb;
bellard9fa3e852004-01-04 18:06:42 +00001026 PageDesc *p;
aliguori6b917542008-11-18 19:46:41 +00001027 int n;
bellardd720b932004-04-25 17:57:43 +00001028#ifdef TARGET_HAS_PRECISE_SMC
aliguori6b917542008-11-18 19:46:41 +00001029 TranslationBlock *current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001030 CPUState *env = cpu_single_env;
aliguori6b917542008-11-18 19:46:41 +00001031 int current_tb_modified = 0;
1032 target_ulong current_pc = 0;
1033 target_ulong current_cs_base = 0;
1034 int current_flags = 0;
bellardd720b932004-04-25 17:57:43 +00001035#endif
bellard9fa3e852004-01-04 18:06:42 +00001036
1037 addr &= TARGET_PAGE_MASK;
1038 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001039 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +00001040 return;
1041 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +00001042#ifdef TARGET_HAS_PRECISE_SMC
1043 if (tb && pc != 0) {
1044 current_tb = tb_find_pc(pc);
1045 }
1046#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001047 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +00001048 n = (long)tb & 3;
1049 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +00001050#ifdef TARGET_HAS_PRECISE_SMC
1051 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +00001052 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +00001053 /* If we are modifying the current TB, we must stop
1054 its execution. We could be more precise by checking
1055 that the modification is after the current PC, but it
1056 would require a specialized function to partially
1057 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +00001058
bellardd720b932004-04-25 17:57:43 +00001059 current_tb_modified = 1;
1060 cpu_restore_state(current_tb, env, pc, puc);
aliguori6b917542008-11-18 19:46:41 +00001061 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1062 &current_flags);
bellardd720b932004-04-25 17:57:43 +00001063 }
1064#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +00001065 tb_phys_invalidate(tb, addr);
1066 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +00001067 }
1068 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001069#ifdef TARGET_HAS_PRECISE_SMC
1070 if (current_tb_modified) {
1071 /* we generate a block containing just the instruction
1072 modifying the memory. It will ensure that it cannot modify
1073 itself */
bellardea1c1802004-06-14 18:56:36 +00001074 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001075 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001076 cpu_resume_from_signal(env, puc);
1077 }
1078#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001079}
bellard9fa3e852004-01-04 18:06:42 +00001080#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001081
1082/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001083static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001084 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001085{
1086 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001087 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001088
bellard9fa3e852004-01-04 18:06:42 +00001089 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001090 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001091 tb->page_next[n] = p->first_tb;
1092 last_first_tb = p->first_tb;
1093 p->first_tb = (TranslationBlock *)((long)tb | n);
1094 invalidate_page_bitmap(p);
1095
bellard107db442004-06-22 18:48:46 +00001096#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001097
bellard9fa3e852004-01-04 18:06:42 +00001098#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001099 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001100 target_ulong addr;
1101 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001102 int prot;
1103
bellardfd6ce8f2003-05-14 19:00:11 +00001104 /* force the host page as non writable (writes will have a
1105 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001106 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001107 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001108 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1109 addr += TARGET_PAGE_SIZE) {
1110
1111 p2 = page_find (addr >> TARGET_PAGE_BITS);
1112 if (!p2)
1113 continue;
1114 prot |= p2->flags;
1115 p2->flags &= ~PAGE_WRITE;
1116 page_get_flags(addr);
1117 }
ths5fafdf22007-09-16 21:08:06 +00001118 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001119 (prot & PAGE_BITS) & ~PAGE_WRITE);
1120#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001121 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001122 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001123#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001124 }
bellard9fa3e852004-01-04 18:06:42 +00001125#else
1126 /* if some code is already present, then the pages are already
1127 protected. So we handle the case where only the first TB is
1128 allocated in a physical page */
1129 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001130 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001131 }
1132#endif
bellardd720b932004-04-25 17:57:43 +00001133
1134#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001135}
1136
1137/* Allocate a new translation block. Flush the translation buffer if
1138 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001139TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001140{
1141 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001142
bellard26a5f132008-05-28 12:30:31 +00001143 if (nb_tbs >= code_gen_max_blocks ||
1144 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001145 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001146 tb = &tbs[nb_tbs++];
1147 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001148 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001149 return tb;
1150}
1151
pbrook2e70f6e2008-06-29 01:03:05 +00001152void tb_free(TranslationBlock *tb)
1153{
thsbf20dc02008-06-30 17:22:19 +00001154 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001155 Ignore the hard cases and just back up if this TB happens to
1156 be the last one generated. */
1157 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1158 code_gen_ptr = tb->tc_ptr;
1159 nb_tbs--;
1160 }
1161}
1162
bellard9fa3e852004-01-04 18:06:42 +00001163/* add a new TB and link it to the physical page tables. phys_page2 is
1164 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001165void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001166 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001167{
bellard9fa3e852004-01-04 18:06:42 +00001168 unsigned int h;
1169 TranslationBlock **ptb;
1170
pbrookc8a706f2008-06-02 16:16:42 +00001171 /* Grab the mmap lock to stop another thread invalidating this TB
1172 before we are done. */
1173 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001174 /* add in the physical hash table */
1175 h = tb_phys_hash_func(phys_pc);
1176 ptb = &tb_phys_hash[h];
1177 tb->phys_hash_next = *ptb;
1178 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001179
1180 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001181 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1182 if (phys_page2 != -1)
1183 tb_alloc_page(tb, 1, phys_page2);
1184 else
1185 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001186
bellardd4e81642003-05-25 16:46:15 +00001187 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1188 tb->jmp_next[0] = NULL;
1189 tb->jmp_next[1] = NULL;
1190
1191 /* init original jump addresses */
1192 if (tb->tb_next_offset[0] != 0xffff)
1193 tb_reset_jump(tb, 0);
1194 if (tb->tb_next_offset[1] != 0xffff)
1195 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001196
1197#ifdef DEBUG_TB_CHECK
1198 tb_page_check();
1199#endif
pbrookc8a706f2008-06-02 16:16:42 +00001200 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001201}
1202
bellarda513fe12003-05-27 23:29:48 +00001203/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1204 tb[1].tc_ptr. Return NULL if not found */
1205TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1206{
1207 int m_min, m_max, m;
1208 unsigned long v;
1209 TranslationBlock *tb;
1210
1211 if (nb_tbs <= 0)
1212 return NULL;
1213 if (tc_ptr < (unsigned long)code_gen_buffer ||
1214 tc_ptr >= (unsigned long)code_gen_ptr)
1215 return NULL;
1216 /* binary search (cf Knuth) */
1217 m_min = 0;
1218 m_max = nb_tbs - 1;
1219 while (m_min <= m_max) {
1220 m = (m_min + m_max) >> 1;
1221 tb = &tbs[m];
1222 v = (unsigned long)tb->tc_ptr;
1223 if (v == tc_ptr)
1224 return tb;
1225 else if (tc_ptr < v) {
1226 m_max = m - 1;
1227 } else {
1228 m_min = m + 1;
1229 }
ths5fafdf22007-09-16 21:08:06 +00001230 }
bellarda513fe12003-05-27 23:29:48 +00001231 return &tbs[m_max];
1232}
bellard75012672003-06-21 13:11:07 +00001233
bellardea041c02003-06-25 16:16:50 +00001234static void tb_reset_jump_recursive(TranslationBlock *tb);
1235
1236static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1237{
1238 TranslationBlock *tb1, *tb_next, **ptb;
1239 unsigned int n1;
1240
1241 tb1 = tb->jmp_next[n];
1242 if (tb1 != NULL) {
1243 /* find head of list */
1244 for(;;) {
1245 n1 = (long)tb1 & 3;
1246 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1247 if (n1 == 2)
1248 break;
1249 tb1 = tb1->jmp_next[n1];
1250 }
1251 /* we are now sure now that tb jumps to tb1 */
1252 tb_next = tb1;
1253
1254 /* remove tb from the jmp_first list */
1255 ptb = &tb_next->jmp_first;
1256 for(;;) {
1257 tb1 = *ptb;
1258 n1 = (long)tb1 & 3;
1259 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1260 if (n1 == n && tb1 == tb)
1261 break;
1262 ptb = &tb1->jmp_next[n1];
1263 }
1264 *ptb = tb->jmp_next[n];
1265 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001266
bellardea041c02003-06-25 16:16:50 +00001267 /* suppress the jump to next tb in generated code */
1268 tb_reset_jump(tb, n);
1269
bellard01243112004-01-04 15:48:17 +00001270 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001271 tb_reset_jump_recursive(tb_next);
1272 }
1273}
1274
1275static void tb_reset_jump_recursive(TranslationBlock *tb)
1276{
1277 tb_reset_jump_recursive2(tb, 0);
1278 tb_reset_jump_recursive2(tb, 1);
1279}
1280
bellard1fddef42005-04-17 19:16:13 +00001281#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001282static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1283{
j_mayer9b3c35e2007-04-07 11:21:28 +00001284 target_phys_addr_t addr;
1285 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001286 ram_addr_t ram_addr;
1287 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001288
pbrookc2f07f82006-04-08 17:14:56 +00001289 addr = cpu_get_phys_page_debug(env, pc);
1290 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1291 if (!p) {
1292 pd = IO_MEM_UNASSIGNED;
1293 } else {
1294 pd = p->phys_offset;
1295 }
1296 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001297 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001298}
bellardc27004e2005-01-03 23:35:10 +00001299#endif
bellardd720b932004-04-25 17:57:43 +00001300
pbrook6658ffb2007-03-16 23:58:11 +00001301/* Add a watchpoint. */
aliguoria1d1bb32008-11-18 20:07:32 +00001302int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
1303 int flags, CPUWatchpoint **watchpoint)
pbrook6658ffb2007-03-16 23:58:11 +00001304{
aliguorib4051332008-11-18 20:14:20 +00001305 target_ulong len_mask = ~(len - 1);
aliguoric0ce9982008-11-25 22:13:57 +00001306 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001307
aliguorib4051332008-11-18 20:14:20 +00001308 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1309 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1310 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1311 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1312 return -EINVAL;
1313 }
aliguoria1d1bb32008-11-18 20:07:32 +00001314 wp = qemu_malloc(sizeof(*wp));
pbrook6658ffb2007-03-16 23:58:11 +00001315
aliguoria1d1bb32008-11-18 20:07:32 +00001316 wp->vaddr = addr;
aliguorib4051332008-11-18 20:14:20 +00001317 wp->len_mask = len_mask;
aliguoria1d1bb32008-11-18 20:07:32 +00001318 wp->flags = flags;
1319
aliguori2dc9f412008-11-18 20:56:59 +00001320 /* keep all GDB-injected watchpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001321 if (flags & BP_GDB)
1322 TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
1323 else
1324 TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001325
pbrook6658ffb2007-03-16 23:58:11 +00001326 tlb_flush_page(env, addr);
aliguoria1d1bb32008-11-18 20:07:32 +00001327
1328 if (watchpoint)
1329 *watchpoint = wp;
1330 return 0;
pbrook6658ffb2007-03-16 23:58:11 +00001331}
1332
aliguoria1d1bb32008-11-18 20:07:32 +00001333/* Remove a specific watchpoint. */
1334int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
1335 int flags)
pbrook6658ffb2007-03-16 23:58:11 +00001336{
aliguorib4051332008-11-18 20:14:20 +00001337 target_ulong len_mask = ~(len - 1);
aliguoria1d1bb32008-11-18 20:07:32 +00001338 CPUWatchpoint *wp;
pbrook6658ffb2007-03-16 23:58:11 +00001339
aliguoric0ce9982008-11-25 22:13:57 +00001340 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00001341 if (addr == wp->vaddr && len_mask == wp->len_mask
aliguori6e140f22008-11-18 20:37:55 +00001342 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
aliguoria1d1bb32008-11-18 20:07:32 +00001343 cpu_watchpoint_remove_by_ref(env, wp);
pbrook6658ffb2007-03-16 23:58:11 +00001344 return 0;
1345 }
1346 }
aliguoria1d1bb32008-11-18 20:07:32 +00001347 return -ENOENT;
pbrook6658ffb2007-03-16 23:58:11 +00001348}
1349
aliguoria1d1bb32008-11-18 20:07:32 +00001350/* Remove a specific watchpoint by reference. */
1351void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
1352{
aliguoric0ce9982008-11-25 22:13:57 +00001353 TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
edgar_igl7d03f822008-05-17 18:58:29 +00001354
aliguoria1d1bb32008-11-18 20:07:32 +00001355 tlb_flush_page(env, watchpoint->vaddr);
1356
1357 qemu_free(watchpoint);
edgar_igl7d03f822008-05-17 18:58:29 +00001358}
1359
aliguoria1d1bb32008-11-18 20:07:32 +00001360/* Remove all matching watchpoints. */
1361void cpu_watchpoint_remove_all(CPUState *env, int mask)
1362{
aliguoric0ce9982008-11-25 22:13:57 +00001363 CPUWatchpoint *wp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001364
aliguoric0ce9982008-11-25 22:13:57 +00001365 TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001366 if (wp->flags & mask)
1367 cpu_watchpoint_remove_by_ref(env, wp);
aliguoric0ce9982008-11-25 22:13:57 +00001368 }
aliguoria1d1bb32008-11-18 20:07:32 +00001369}
1370
1371/* Add a breakpoint. */
1372int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
1373 CPUBreakpoint **breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001374{
bellard1fddef42005-04-17 19:16:13 +00001375#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001376 CPUBreakpoint *bp;
ths3b46e622007-09-17 08:09:54 +00001377
aliguoria1d1bb32008-11-18 20:07:32 +00001378 bp = qemu_malloc(sizeof(*bp));
aliguoria1d1bb32008-11-18 20:07:32 +00001379
1380 bp->pc = pc;
1381 bp->flags = flags;
1382
aliguori2dc9f412008-11-18 20:56:59 +00001383 /* keep all GDB-injected breakpoints in front */
aliguoric0ce9982008-11-25 22:13:57 +00001384 if (flags & BP_GDB)
1385 TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
1386 else
1387 TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
aliguoria1d1bb32008-11-18 20:07:32 +00001388
1389 breakpoint_invalidate(env, pc);
1390
1391 if (breakpoint)
1392 *breakpoint = bp;
1393 return 0;
1394#else
1395 return -ENOSYS;
1396#endif
1397}
1398
1399/* Remove a specific breakpoint. */
1400int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
1401{
1402#if defined(TARGET_HAS_ICE)
1403 CPUBreakpoint *bp;
1404
aliguoric0ce9982008-11-25 22:13:57 +00001405 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001406 if (bp->pc == pc && bp->flags == flags) {
1407 cpu_breakpoint_remove_by_ref(env, bp);
bellard4c3a88a2003-07-26 12:06:08 +00001408 return 0;
aliguoria1d1bb32008-11-18 20:07:32 +00001409 }
bellard4c3a88a2003-07-26 12:06:08 +00001410 }
aliguoria1d1bb32008-11-18 20:07:32 +00001411 return -ENOENT;
bellard4c3a88a2003-07-26 12:06:08 +00001412#else
aliguoria1d1bb32008-11-18 20:07:32 +00001413 return -ENOSYS;
bellard4c3a88a2003-07-26 12:06:08 +00001414#endif
1415}
1416
aliguoria1d1bb32008-11-18 20:07:32 +00001417/* Remove a specific breakpoint by reference. */
1418void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
bellard4c3a88a2003-07-26 12:06:08 +00001419{
bellard1fddef42005-04-17 19:16:13 +00001420#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001421 TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
bellardd720b932004-04-25 17:57:43 +00001422
aliguoria1d1bb32008-11-18 20:07:32 +00001423 breakpoint_invalidate(env, breakpoint->pc);
1424
1425 qemu_free(breakpoint);
1426#endif
1427}
1428
1429/* Remove all matching breakpoints. */
1430void cpu_breakpoint_remove_all(CPUState *env, int mask)
1431{
1432#if defined(TARGET_HAS_ICE)
aliguoric0ce9982008-11-25 22:13:57 +00001433 CPUBreakpoint *bp, *next;
aliguoria1d1bb32008-11-18 20:07:32 +00001434
aliguoric0ce9982008-11-25 22:13:57 +00001435 TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
aliguoria1d1bb32008-11-18 20:07:32 +00001436 if (bp->flags & mask)
1437 cpu_breakpoint_remove_by_ref(env, bp);
aliguoric0ce9982008-11-25 22:13:57 +00001438 }
bellard4c3a88a2003-07-26 12:06:08 +00001439#endif
1440}
1441
bellardc33a3462003-07-29 20:50:33 +00001442/* enable or disable single step mode. EXCP_DEBUG is returned by the
1443 CPU loop after each instruction */
1444void cpu_single_step(CPUState *env, int enabled)
1445{
bellard1fddef42005-04-17 19:16:13 +00001446#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001447 if (env->singlestep_enabled != enabled) {
1448 env->singlestep_enabled = enabled;
1449 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001450 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001451 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001452 }
1453#endif
1454}
1455
bellard34865132003-10-05 14:28:56 +00001456/* enable or disable low levels log */
1457void cpu_set_log(int log_flags)
1458{
1459 loglevel = log_flags;
1460 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001461 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001462 if (!logfile) {
1463 perror(logfilename);
1464 _exit(1);
1465 }
bellard9fa3e852004-01-04 18:06:42 +00001466#if !defined(CONFIG_SOFTMMU)
1467 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1468 {
blueswir1b55266b2008-09-20 08:07:15 +00001469 static char logfile_buf[4096];
bellard9fa3e852004-01-04 18:06:42 +00001470 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1471 }
1472#else
bellard34865132003-10-05 14:28:56 +00001473 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001474#endif
pbrooke735b912007-06-30 13:53:24 +00001475 log_append = 1;
1476 }
1477 if (!loglevel && logfile) {
1478 fclose(logfile);
1479 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001480 }
1481}
1482
1483void cpu_set_log_filename(const char *filename)
1484{
1485 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001486 if (logfile) {
1487 fclose(logfile);
1488 logfile = NULL;
1489 }
1490 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001491}
bellardc33a3462003-07-29 20:50:33 +00001492
bellard01243112004-01-04 15:48:17 +00001493/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001494void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001495{
pbrookd5975362008-06-07 20:50:51 +00001496#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001497 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001498 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001499#endif
pbrook2e70f6e2008-06-29 01:03:05 +00001500 int old_mask;
bellard59817cc2004-02-16 22:01:13 +00001501
pbrook2e70f6e2008-06-29 01:03:05 +00001502 old_mask = env->interrupt_request;
pbrookd5975362008-06-07 20:50:51 +00001503 /* FIXME: This is probably not threadsafe. A different thread could
thsbf20dc02008-06-30 17:22:19 +00001504 be in the middle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001505 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001506#if defined(USE_NPTL)
1507 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1508 problem and hope the cpu will stop of its own accord. For userspace
1509 emulation this often isn't actually as bad as it sounds. Often
1510 signals are used primarily to interrupt blocking syscalls. */
1511#else
pbrook2e70f6e2008-06-29 01:03:05 +00001512 if (use_icount) {
pbrook266910c2008-07-09 15:31:50 +00001513 env->icount_decr.u16.high = 0xffff;
pbrook2e70f6e2008-06-29 01:03:05 +00001514#ifndef CONFIG_USER_ONLY
1515 /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
1516 an async event happened and we need to process it. */
1517 if (!can_do_io(env)
1518 && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
1519 cpu_abort(env, "Raised interrupt while not in I/O function");
1520 }
1521#endif
1522 } else {
1523 tb = env->current_tb;
1524 /* if the cpu is currently executing code, we must unlink it and
1525 all the potentially executing TB */
1526 if (tb && !testandset(&interrupt_lock)) {
1527 env->current_tb = NULL;
1528 tb_reset_jump_recursive(tb);
1529 resetlock(&interrupt_lock);
1530 }
bellardea041c02003-06-25 16:16:50 +00001531 }
pbrookd5975362008-06-07 20:50:51 +00001532#endif
bellardea041c02003-06-25 16:16:50 +00001533}
1534
bellardb54ad042004-05-20 13:42:52 +00001535void cpu_reset_interrupt(CPUState *env, int mask)
1536{
1537 env->interrupt_request &= ~mask;
1538}
1539
blueswir1c7cd6a32008-10-02 18:27:46 +00001540const CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001541 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001542 "show generated host assembly code for each compiled TB" },
1543 { CPU_LOG_TB_IN_ASM, "in_asm",
1544 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001545 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001546 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001547 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001548 "show micro ops "
1549#ifdef TARGET_I386
1550 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001551#endif
blueswir1e01a1152008-03-14 17:37:11 +00001552 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001553 { CPU_LOG_INT, "int",
1554 "show interrupts/exceptions in short format" },
1555 { CPU_LOG_EXEC, "exec",
1556 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001557 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001558 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001559#ifdef TARGET_I386
1560 { CPU_LOG_PCALL, "pcall",
1561 "show protected mode far calls/returns/exceptions" },
aliguorieca1bdf2009-01-26 19:54:31 +00001562 { CPU_LOG_RESET, "cpu_reset",
1563 "show CPU state before CPU resets" },
bellardf193c792004-03-21 17:06:25 +00001564#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001565#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001566 { CPU_LOG_IOPORT, "ioport",
1567 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001568#endif
bellardf193c792004-03-21 17:06:25 +00001569 { 0, NULL, NULL },
1570};
1571
1572static int cmp1(const char *s1, int n, const char *s2)
1573{
1574 if (strlen(s2) != n)
1575 return 0;
1576 return memcmp(s1, s2, n) == 0;
1577}
ths3b46e622007-09-17 08:09:54 +00001578
bellardf193c792004-03-21 17:06:25 +00001579/* takes a comma separated list of log masks. Return 0 if error. */
1580int cpu_str_to_log_mask(const char *str)
1581{
blueswir1c7cd6a32008-10-02 18:27:46 +00001582 const CPULogItem *item;
bellardf193c792004-03-21 17:06:25 +00001583 int mask;
1584 const char *p, *p1;
1585
1586 p = str;
1587 mask = 0;
1588 for(;;) {
1589 p1 = strchr(p, ',');
1590 if (!p1)
1591 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001592 if(cmp1(p,p1-p,"all")) {
1593 for(item = cpu_log_items; item->mask != 0; item++) {
1594 mask |= item->mask;
1595 }
1596 } else {
bellardf193c792004-03-21 17:06:25 +00001597 for(item = cpu_log_items; item->mask != 0; item++) {
1598 if (cmp1(p, p1 - p, item->name))
1599 goto found;
1600 }
1601 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001602 }
bellardf193c792004-03-21 17:06:25 +00001603 found:
1604 mask |= item->mask;
1605 if (*p1 != ',')
1606 break;
1607 p = p1 + 1;
1608 }
1609 return mask;
1610}
bellardea041c02003-06-25 16:16:50 +00001611
bellard75012672003-06-21 13:11:07 +00001612void cpu_abort(CPUState *env, const char *fmt, ...)
1613{
1614 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001615 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001616
1617 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001618 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001619 fprintf(stderr, "qemu: fatal: ");
1620 vfprintf(stderr, fmt, ap);
1621 fprintf(stderr, "\n");
1622#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001623 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1624#else
1625 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001626#endif
aliguori93fcfe32009-01-15 22:34:14 +00001627 if (qemu_log_enabled()) {
1628 qemu_log("qemu: fatal: ");
1629 qemu_log_vprintf(fmt, ap2);
1630 qemu_log("\n");
j_mayerf9373292007-09-29 12:18:20 +00001631#ifdef TARGET_I386
aliguori93fcfe32009-01-15 22:34:14 +00001632 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
j_mayerf9373292007-09-29 12:18:20 +00001633#else
aliguori93fcfe32009-01-15 22:34:14 +00001634 log_cpu_state(env, 0);
j_mayerf9373292007-09-29 12:18:20 +00001635#endif
aliguori31b1a7b2009-01-15 22:35:09 +00001636 qemu_log_flush();
aliguori93fcfe32009-01-15 22:34:14 +00001637 qemu_log_close();
balrog924edca2007-06-10 14:07:13 +00001638 }
pbrook493ae1f2007-11-23 16:53:59 +00001639 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001640 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001641 abort();
1642}
1643
thsc5be9f02007-02-28 20:20:53 +00001644CPUState *cpu_copy(CPUState *env)
1645{
ths01ba9812007-12-09 02:22:57 +00001646 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001647 CPUState *next_cpu = new_env->next_cpu;
1648 int cpu_index = new_env->cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001649#if defined(TARGET_HAS_ICE)
1650 CPUBreakpoint *bp;
1651 CPUWatchpoint *wp;
1652#endif
1653
thsc5be9f02007-02-28 20:20:53 +00001654 memcpy(new_env, env, sizeof(CPUState));
aliguori5a38f082009-01-15 20:16:51 +00001655
1656 /* Preserve chaining and index. */
thsc5be9f02007-02-28 20:20:53 +00001657 new_env->next_cpu = next_cpu;
1658 new_env->cpu_index = cpu_index;
aliguori5a38f082009-01-15 20:16:51 +00001659
1660 /* Clone all break/watchpoints.
1661 Note: Once we support ptrace with hw-debug register access, make sure
1662 BP_CPU break/watchpoints are handled correctly on clone. */
1663 TAILQ_INIT(&env->breakpoints);
1664 TAILQ_INIT(&env->watchpoints);
1665#if defined(TARGET_HAS_ICE)
1666 TAILQ_FOREACH(bp, &env->breakpoints, entry) {
1667 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
1668 }
1669 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
1670 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
1671 wp->flags, NULL);
1672 }
1673#endif
1674
thsc5be9f02007-02-28 20:20:53 +00001675 return new_env;
1676}
1677
bellard01243112004-01-04 15:48:17 +00001678#if !defined(CONFIG_USER_ONLY)
1679
edgar_igl5c751e92008-05-06 08:44:21 +00001680static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1681{
1682 unsigned int i;
1683
1684 /* Discard jump cache entries for any tb which might potentially
1685 overlap the flushed page. */
1686 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1687 memset (&env->tb_jmp_cache[i], 0,
1688 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1689
1690 i = tb_jmp_cache_hash_page(addr);
1691 memset (&env->tb_jmp_cache[i], 0,
1692 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1693}
1694
bellardee8b7022004-02-03 23:35:10 +00001695/* NOTE: if flush_global is true, also flush global entries (not
1696 implemented yet) */
1697void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001698{
bellard33417e72003-08-10 21:47:01 +00001699 int i;
bellard01243112004-01-04 15:48:17 +00001700
bellard9fa3e852004-01-04 18:06:42 +00001701#if defined(DEBUG_TLB)
1702 printf("tlb_flush:\n");
1703#endif
bellard01243112004-01-04 15:48:17 +00001704 /* must reset current TB so that interrupts cannot modify the
1705 links while we are modifying them */
1706 env->current_tb = NULL;
1707
bellard33417e72003-08-10 21:47:01 +00001708 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001709 env->tlb_table[0][i].addr_read = -1;
1710 env->tlb_table[0][i].addr_write = -1;
1711 env->tlb_table[0][i].addr_code = -1;
1712 env->tlb_table[1][i].addr_read = -1;
1713 env->tlb_table[1][i].addr_write = -1;
1714 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001715#if (NB_MMU_MODES >= 3)
1716 env->tlb_table[2][i].addr_read = -1;
1717 env->tlb_table[2][i].addr_write = -1;
1718 env->tlb_table[2][i].addr_code = -1;
1719#if (NB_MMU_MODES == 4)
1720 env->tlb_table[3][i].addr_read = -1;
1721 env->tlb_table[3][i].addr_write = -1;
1722 env->tlb_table[3][i].addr_code = -1;
1723#endif
1724#endif
bellard33417e72003-08-10 21:47:01 +00001725 }
bellard9fa3e852004-01-04 18:06:42 +00001726
bellard8a40a182005-11-20 10:35:40 +00001727 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001728
bellard0a962c02005-02-10 22:00:27 +00001729#ifdef USE_KQEMU
1730 if (env->kqemu_enabled) {
1731 kqemu_flush(env, flush_global);
1732 }
1733#endif
bellarde3db7222005-01-26 22:00:47 +00001734 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001735}
1736
bellard274da6b2004-05-20 21:56:27 +00001737static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001738{
ths5fafdf22007-09-16 21:08:06 +00001739 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001740 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001741 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001742 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001743 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001744 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1745 tlb_entry->addr_read = -1;
1746 tlb_entry->addr_write = -1;
1747 tlb_entry->addr_code = -1;
1748 }
bellard61382a52003-10-27 21:22:23 +00001749}
1750
bellard2e126692004-04-25 21:28:44 +00001751void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001752{
bellard8a40a182005-11-20 10:35:40 +00001753 int i;
bellard01243112004-01-04 15:48:17 +00001754
bellard9fa3e852004-01-04 18:06:42 +00001755#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001756 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001757#endif
bellard01243112004-01-04 15:48:17 +00001758 /* must reset current TB so that interrupts cannot modify the
1759 links while we are modifying them */
1760 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001761
bellard61382a52003-10-27 21:22:23 +00001762 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001763 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001764 tlb_flush_entry(&env->tlb_table[0][i], addr);
1765 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001766#if (NB_MMU_MODES >= 3)
1767 tlb_flush_entry(&env->tlb_table[2][i], addr);
1768#if (NB_MMU_MODES == 4)
1769 tlb_flush_entry(&env->tlb_table[3][i], addr);
1770#endif
1771#endif
bellard01243112004-01-04 15:48:17 +00001772
edgar_igl5c751e92008-05-06 08:44:21 +00001773 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001774
bellard0a962c02005-02-10 22:00:27 +00001775#ifdef USE_KQEMU
1776 if (env->kqemu_enabled) {
1777 kqemu_flush_page(env, addr);
1778 }
1779#endif
bellard9fa3e852004-01-04 18:06:42 +00001780}
1781
bellard9fa3e852004-01-04 18:06:42 +00001782/* update the TLBs so that writes to code in the virtual page 'addr'
1783 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001784static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001785{
ths5fafdf22007-09-16 21:08:06 +00001786 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001787 ram_addr + TARGET_PAGE_SIZE,
1788 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001789}
1790
bellard9fa3e852004-01-04 18:06:42 +00001791/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001792 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001793static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001794 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001795{
bellard3a7d9292005-08-21 09:26:42 +00001796 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001797}
1798
ths5fafdf22007-09-16 21:08:06 +00001799static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001800 unsigned long start, unsigned long length)
1801{
1802 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001803 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1804 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001805 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001806 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001807 }
1808 }
1809}
1810
bellard3a7d9292005-08-21 09:26:42 +00001811void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001812 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001813{
1814 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001815 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001816 int i, mask, len;
1817 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001818
1819 start &= TARGET_PAGE_MASK;
1820 end = TARGET_PAGE_ALIGN(end);
1821
1822 length = end - start;
1823 if (length == 0)
1824 return;
bellard0a962c02005-02-10 22:00:27 +00001825 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001826#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001827 /* XXX: should not depend on cpu context */
1828 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001829 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001830 ram_addr_t addr;
1831 addr = start;
1832 for(i = 0; i < len; i++) {
1833 kqemu_set_notdirty(env, addr);
1834 addr += TARGET_PAGE_SIZE;
1835 }
bellard3a7d9292005-08-21 09:26:42 +00001836 }
1837#endif
bellardf23db162005-08-21 19:12:28 +00001838 mask = ~dirty_flags;
1839 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1840 for(i = 0; i < len; i++)
1841 p[i] &= mask;
1842
bellard1ccde1c2004-02-06 19:46:14 +00001843 /* we modify the TLB cache so that the dirty bit will be set again
1844 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001845 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001846 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1847 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001848 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001849 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001850 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001851#if (NB_MMU_MODES >= 3)
1852 for(i = 0; i < CPU_TLB_SIZE; i++)
1853 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1854#if (NB_MMU_MODES == 4)
1855 for(i = 0; i < CPU_TLB_SIZE; i++)
1856 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1857#endif
1858#endif
bellard6a00d602005-11-21 23:25:50 +00001859 }
bellard1ccde1c2004-02-06 19:46:14 +00001860}
1861
aliguori74576192008-10-06 14:02:03 +00001862int cpu_physical_memory_set_dirty_tracking(int enable)
1863{
1864 in_migration = enable;
1865 return 0;
1866}
1867
1868int cpu_physical_memory_get_dirty_tracking(void)
1869{
1870 return in_migration;
1871}
1872
aliguori2bec46d2008-11-24 20:21:41 +00001873void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
1874{
1875 if (kvm_enabled())
1876 kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1877}
1878
bellard3a7d9292005-08-21 09:26:42 +00001879static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1880{
1881 ram_addr_t ram_addr;
1882
bellard84b7b8e2005-11-28 21:19:04 +00001883 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001884 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001885 tlb_entry->addend - (unsigned long)phys_ram_base;
1886 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001887 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001888 }
1889 }
1890}
1891
1892/* update the TLB according to the current state of the dirty bits */
1893void cpu_tlb_update_dirty(CPUState *env)
1894{
1895 int i;
1896 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001897 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001898 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001899 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001900#if (NB_MMU_MODES >= 3)
1901 for(i = 0; i < CPU_TLB_SIZE; i++)
1902 tlb_update_dirty(&env->tlb_table[2][i]);
1903#if (NB_MMU_MODES == 4)
1904 for(i = 0; i < CPU_TLB_SIZE; i++)
1905 tlb_update_dirty(&env->tlb_table[3][i]);
1906#endif
1907#endif
bellard3a7d9292005-08-21 09:26:42 +00001908}
1909
pbrook0f459d12008-06-09 00:20:13 +00001910static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001911{
pbrook0f459d12008-06-09 00:20:13 +00001912 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1913 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001914}
1915
pbrook0f459d12008-06-09 00:20:13 +00001916/* update the TLB corresponding to virtual page vaddr
1917 so that it is no longer dirty */
1918static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001919{
bellard1ccde1c2004-02-06 19:46:14 +00001920 int i;
1921
pbrook0f459d12008-06-09 00:20:13 +00001922 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001923 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001924 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1925 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001926#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001927 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001928#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001929 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001930#endif
1931#endif
bellard9fa3e852004-01-04 18:06:42 +00001932}
1933
bellard59817cc2004-02-16 22:01:13 +00001934/* add a new TLB entry. At most one entry for a given virtual address
1935 is permitted. Return 0 if OK or 2 if the page could not be mapped
1936 (can only happen in non SOFTMMU mode for I/O pages or pages
1937 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001938int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1939 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001940 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001941{
bellard92e873b2004-05-21 14:52:29 +00001942 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001943 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001944 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001945 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001946 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001947 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001948 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001949 CPUTLBEntry *te;
aliguoria1d1bb32008-11-18 20:07:32 +00001950 CPUWatchpoint *wp;
pbrook0f459d12008-06-09 00:20:13 +00001951 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001952
bellard92e873b2004-05-21 14:52:29 +00001953 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001954 if (!p) {
1955 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001956 } else {
1957 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001958 }
1959#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001960 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1961 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001962#endif
1963
1964 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001965 address = vaddr;
1966 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1967 /* IO memory case (romd handled later) */
1968 address |= TLB_MMIO;
1969 }
1970 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1971 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1972 /* Normal RAM. */
1973 iotlb = pd & TARGET_PAGE_MASK;
1974 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1975 iotlb |= IO_MEM_NOTDIRTY;
1976 else
1977 iotlb |= IO_MEM_ROM;
1978 } else {
1979 /* IO handlers are currently passed a phsical address.
1980 It would be nice to pass an offset from the base address
1981 of that region. This would avoid having to special case RAM,
1982 and avoid full address decoding in every device.
1983 We can't use the high bits of pd for this because
1984 IO_MEM_ROMD uses these as a ram address. */
pbrook8da3ff12008-12-01 18:59:50 +00001985 iotlb = (pd & ~TARGET_PAGE_MASK);
1986 if (p) {
pbrook8da3ff12008-12-01 18:59:50 +00001987 iotlb += p->region_offset;
1988 } else {
1989 iotlb += paddr;
1990 }
pbrook0f459d12008-06-09 00:20:13 +00001991 }
pbrook6658ffb2007-03-16 23:58:11 +00001992
pbrook0f459d12008-06-09 00:20:13 +00001993 code_address = address;
1994 /* Make accesses to pages with watchpoints go via the
1995 watchpoint trap routines. */
aliguoric0ce9982008-11-25 22:13:57 +00001996 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001997 if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
pbrook0f459d12008-06-09 00:20:13 +00001998 iotlb = io_mem_watch + paddr;
1999 /* TODO: The memory case can be optimized by not trapping
2000 reads of pages with a write breakpoint. */
2001 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00002002 }
pbrook0f459d12008-06-09 00:20:13 +00002003 }
balrogd79acba2007-06-26 20:01:13 +00002004
pbrook0f459d12008-06-09 00:20:13 +00002005 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
2006 env->iotlb[mmu_idx][index] = iotlb - vaddr;
2007 te = &env->tlb_table[mmu_idx][index];
2008 te->addend = addend - vaddr;
2009 if (prot & PAGE_READ) {
2010 te->addr_read = address;
2011 } else {
2012 te->addr_read = -1;
2013 }
edgar_igl5c751e92008-05-06 08:44:21 +00002014
pbrook0f459d12008-06-09 00:20:13 +00002015 if (prot & PAGE_EXEC) {
2016 te->addr_code = code_address;
2017 } else {
2018 te->addr_code = -1;
2019 }
2020 if (prot & PAGE_WRITE) {
2021 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
2022 (pd & IO_MEM_ROMD)) {
2023 /* Write access calls the I/O callback. */
2024 te->addr_write = address | TLB_MMIO;
2025 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2026 !cpu_physical_memory_is_dirty(pd)) {
2027 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00002028 } else {
pbrook0f459d12008-06-09 00:20:13 +00002029 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00002030 }
pbrook0f459d12008-06-09 00:20:13 +00002031 } else {
2032 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00002033 }
bellard9fa3e852004-01-04 18:06:42 +00002034 return ret;
2035}
2036
bellard01243112004-01-04 15:48:17 +00002037#else
2038
bellardee8b7022004-02-03 23:35:10 +00002039void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00002040{
2041}
2042
bellard2e126692004-04-25 21:28:44 +00002043void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00002044{
2045}
2046
ths5fafdf22007-09-16 21:08:06 +00002047int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
2048 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00002049 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00002050{
bellard9fa3e852004-01-04 18:06:42 +00002051 return 0;
2052}
bellard33417e72003-08-10 21:47:01 +00002053
bellard9fa3e852004-01-04 18:06:42 +00002054/* dump memory mappings */
2055void page_dump(FILE *f)
2056{
2057 unsigned long start, end;
2058 int i, j, prot, prot1;
2059 PageDesc *p;
2060
2061 fprintf(f, "%-8s %-8s %-8s %s\n",
2062 "start", "end", "size", "prot");
2063 start = -1;
2064 end = -1;
2065 prot = 0;
2066 for(i = 0; i <= L1_SIZE; i++) {
2067 if (i < L1_SIZE)
2068 p = l1_map[i];
2069 else
2070 p = NULL;
2071 for(j = 0;j < L2_SIZE; j++) {
2072 if (!p)
2073 prot1 = 0;
2074 else
2075 prot1 = p[j].flags;
2076 if (prot1 != prot) {
2077 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2078 if (start != -1) {
2079 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00002080 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00002081 prot & PAGE_READ ? 'r' : '-',
2082 prot & PAGE_WRITE ? 'w' : '-',
2083 prot & PAGE_EXEC ? 'x' : '-');
2084 }
2085 if (prot1 != 0)
2086 start = end;
2087 else
2088 start = -1;
2089 prot = prot1;
2090 }
2091 if (!p)
2092 break;
2093 }
bellard33417e72003-08-10 21:47:01 +00002094 }
bellard33417e72003-08-10 21:47:01 +00002095}
2096
pbrook53a59602006-03-25 19:31:22 +00002097int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002098{
bellard9fa3e852004-01-04 18:06:42 +00002099 PageDesc *p;
2100
2101 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002102 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002103 return 0;
2104 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002105}
2106
bellard9fa3e852004-01-04 18:06:42 +00002107/* modify the flags of a page and invalidate the code if
2108 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2109 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002110void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002111{
2112 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002113 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002114
pbrookc8a706f2008-06-02 16:16:42 +00002115 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002116 start = start & TARGET_PAGE_MASK;
2117 end = TARGET_PAGE_ALIGN(end);
2118 if (flags & PAGE_WRITE)
2119 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002120 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2121 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00002122 /* We may be called for host regions that are outside guest
2123 address space. */
2124 if (!p)
2125 return;
bellard9fa3e852004-01-04 18:06:42 +00002126 /* if the write protection is set, then we invalidate the code
2127 inside */
ths5fafdf22007-09-16 21:08:06 +00002128 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002129 (flags & PAGE_WRITE) &&
2130 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002131 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002132 }
2133 p->flags = flags;
2134 }
bellard9fa3e852004-01-04 18:06:42 +00002135}
2136
ths3d97b402007-11-02 19:02:07 +00002137int page_check_range(target_ulong start, target_ulong len, int flags)
2138{
2139 PageDesc *p;
2140 target_ulong end;
2141 target_ulong addr;
2142
balrog55f280c2008-10-28 10:24:11 +00002143 if (start + len < start)
2144 /* we've wrapped around */
2145 return -1;
2146
ths3d97b402007-11-02 19:02:07 +00002147 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2148 start = start & TARGET_PAGE_MASK;
2149
ths3d97b402007-11-02 19:02:07 +00002150 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2151 p = page_find(addr >> TARGET_PAGE_BITS);
2152 if( !p )
2153 return -1;
2154 if( !(p->flags & PAGE_VALID) )
2155 return -1;
2156
bellarddae32702007-11-14 10:51:00 +00002157 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002158 return -1;
bellarddae32702007-11-14 10:51:00 +00002159 if (flags & PAGE_WRITE) {
2160 if (!(p->flags & PAGE_WRITE_ORG))
2161 return -1;
2162 /* unprotect the page if it was put read-only because it
2163 contains translated code */
2164 if (!(p->flags & PAGE_WRITE)) {
2165 if (!page_unprotect(addr, 0, NULL))
2166 return -1;
2167 }
2168 return 0;
2169 }
ths3d97b402007-11-02 19:02:07 +00002170 }
2171 return 0;
2172}
2173
bellard9fa3e852004-01-04 18:06:42 +00002174/* called from signal handler: invalidate the code and unprotect the
2175 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002176int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002177{
2178 unsigned int page_index, prot, pindex;
2179 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002180 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002181
pbrookc8a706f2008-06-02 16:16:42 +00002182 /* Technically this isn't safe inside a signal handler. However we
2183 know this only ever happens in a synchronous SEGV handler, so in
2184 practice it seems to be ok. */
2185 mmap_lock();
2186
bellard83fb7ad2004-07-05 21:25:26 +00002187 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002188 page_index = host_start >> TARGET_PAGE_BITS;
2189 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002190 if (!p1) {
2191 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002192 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002193 }
bellard83fb7ad2004-07-05 21:25:26 +00002194 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002195 p = p1;
2196 prot = 0;
2197 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2198 prot |= p->flags;
2199 p++;
2200 }
2201 /* if the page was really writable, then we change its
2202 protection back to writable */
2203 if (prot & PAGE_WRITE_ORG) {
2204 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2205 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002206 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002207 (prot & PAGE_BITS) | PAGE_WRITE);
2208 p1[pindex].flags |= PAGE_WRITE;
2209 /* and since the content will be modified, we must invalidate
2210 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002211 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002212#ifdef DEBUG_TB_CHECK
2213 tb_invalidate_check(address);
2214#endif
pbrookc8a706f2008-06-02 16:16:42 +00002215 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002216 return 1;
2217 }
2218 }
pbrookc8a706f2008-06-02 16:16:42 +00002219 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002220 return 0;
2221}
2222
bellard6a00d602005-11-21 23:25:50 +00002223static inline void tlb_set_dirty(CPUState *env,
2224 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002225{
2226}
bellard9fa3e852004-01-04 18:06:42 +00002227#endif /* defined(CONFIG_USER_ONLY) */
2228
pbrooke2eef172008-06-08 01:09:01 +00002229#if !defined(CONFIG_USER_ONLY)
pbrook8da3ff12008-12-01 18:59:50 +00002230
blueswir1db7b5422007-05-26 17:36:03 +00002231static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002232 ram_addr_t memory, ram_addr_t region_offset);
aurel3200f82b82008-04-27 21:12:55 +00002233static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002234 ram_addr_t orig_memory, ram_addr_t region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002235#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2236 need_subpage) \
2237 do { \
2238 if (addr > start_addr) \
2239 start_addr2 = 0; \
2240 else { \
2241 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2242 if (start_addr2 > 0) \
2243 need_subpage = 1; \
2244 } \
2245 \
blueswir149e9fba2007-05-30 17:25:06 +00002246 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002247 end_addr2 = TARGET_PAGE_SIZE - 1; \
2248 else { \
2249 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2250 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2251 need_subpage = 1; \
2252 } \
2253 } while (0)
2254
bellard33417e72003-08-10 21:47:01 +00002255/* register physical memory. 'size' must be a multiple of the target
2256 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
pbrook8da3ff12008-12-01 18:59:50 +00002257 io memory page. The address used when calling the IO function is
2258 the offset from the start of the region, plus region_offset. Both
2259 start_region and regon_offset are rounded down to a page boundary
2260 before calculating this offset. This should not be a problem unless
2261 the low bits of start_addr and region_offset differ. */
2262void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2263 ram_addr_t size,
2264 ram_addr_t phys_offset,
2265 ram_addr_t region_offset)
bellard33417e72003-08-10 21:47:01 +00002266{
bellard108c49b2005-07-24 12:55:09 +00002267 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002268 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002269 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002270 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002271 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002272
bellardda260242008-05-30 20:48:25 +00002273#ifdef USE_KQEMU
2274 /* XXX: should not depend on cpu context */
2275 env = first_cpu;
2276 if (env->kqemu_enabled) {
2277 kqemu_set_phys_mem(start_addr, size, phys_offset);
2278 }
2279#endif
aliguori7ba1e612008-11-05 16:04:33 +00002280 if (kvm_enabled())
2281 kvm_set_phys_mem(start_addr, size, phys_offset);
2282
pbrook8da3ff12008-12-01 18:59:50 +00002283 region_offset &= TARGET_PAGE_MASK;
bellard5fd386f2004-05-23 21:11:22 +00002284 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002285 end_addr = start_addr + (target_phys_addr_t)size;
2286 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002287 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2288 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002289 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002290 target_phys_addr_t start_addr2, end_addr2;
2291 int need_subpage = 0;
2292
2293 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2294 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002295 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002296 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2297 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002298 &p->phys_offset, orig_memory,
2299 p->region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002300 } else {
2301 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2302 >> IO_MEM_SHIFT];
2303 }
pbrook8da3ff12008-12-01 18:59:50 +00002304 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2305 region_offset);
2306 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002307 } else {
2308 p->phys_offset = phys_offset;
2309 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2310 (phys_offset & IO_MEM_ROMD))
2311 phys_offset += TARGET_PAGE_SIZE;
2312 }
2313 } else {
2314 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2315 p->phys_offset = phys_offset;
pbrook8da3ff12008-12-01 18:59:50 +00002316 p->region_offset = region_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002317 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
pbrook8da3ff12008-12-01 18:59:50 +00002318 (phys_offset & IO_MEM_ROMD)) {
blueswir1db7b5422007-05-26 17:36:03 +00002319 phys_offset += TARGET_PAGE_SIZE;
pbrook0e8f0962008-12-02 09:02:15 +00002320 } else {
blueswir1db7b5422007-05-26 17:36:03 +00002321 target_phys_addr_t start_addr2, end_addr2;
2322 int need_subpage = 0;
2323
2324 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2325 end_addr2, need_subpage);
2326
blueswir14254fab2008-01-01 16:57:19 +00002327 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002328 subpage = subpage_init((addr & TARGET_PAGE_MASK),
pbrook8da3ff12008-12-01 18:59:50 +00002329 &p->phys_offset, IO_MEM_UNASSIGNED,
2330 0);
blueswir1db7b5422007-05-26 17:36:03 +00002331 subpage_register(subpage, start_addr2, end_addr2,
pbrook8da3ff12008-12-01 18:59:50 +00002332 phys_offset, region_offset);
2333 p->region_offset = 0;
blueswir1db7b5422007-05-26 17:36:03 +00002334 }
2335 }
2336 }
pbrook8da3ff12008-12-01 18:59:50 +00002337 region_offset += TARGET_PAGE_SIZE;
bellard33417e72003-08-10 21:47:01 +00002338 }
ths3b46e622007-09-17 08:09:54 +00002339
bellard9d420372006-06-25 22:25:22 +00002340 /* since each CPU stores ram addresses in its TLB cache, we must
2341 reset the modified entries */
2342 /* XXX: slow ! */
2343 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2344 tlb_flush(env, 1);
2345 }
bellard33417e72003-08-10 21:47:01 +00002346}
2347
bellardba863452006-09-24 18:41:10 +00002348/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002349ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002350{
2351 PhysPageDesc *p;
2352
2353 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2354 if (!p)
2355 return IO_MEM_UNASSIGNED;
2356 return p->phys_offset;
2357}
2358
aliguorif65ed4c2008-12-09 20:09:57 +00002359void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2360{
2361 if (kvm_enabled())
2362 kvm_coalesce_mmio_region(addr, size);
2363}
2364
2365void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2366{
2367 if (kvm_enabled())
2368 kvm_uncoalesce_mmio_region(addr, size);
2369}
2370
bellarde9a1ab12007-02-08 23:08:38 +00002371/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002372ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002373{
2374 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002375 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
ths012a7042008-10-02 17:34:21 +00002376 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
bellarded441462008-05-23 11:56:45 +00002377 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002378 abort();
2379 }
2380 addr = phys_ram_alloc_offset;
2381 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2382 return addr;
2383}
2384
2385void qemu_ram_free(ram_addr_t addr)
2386{
2387}
2388
bellarda4193c82004-06-03 14:01:43 +00002389static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002390{
pbrook67d3b952006-12-18 05:03:52 +00002391#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002392 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002393#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002394#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002395 do_unassigned_access(addr, 0, 0, 0, 1);
2396#endif
2397 return 0;
2398}
2399
2400static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
2401{
2402#ifdef DEBUG_UNASSIGNED
2403 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2404#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002405#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002406 do_unassigned_access(addr, 0, 0, 0, 2);
2407#endif
2408 return 0;
2409}
2410
2411static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
2412{
2413#ifdef DEBUG_UNASSIGNED
2414 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2415#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002416#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002417 do_unassigned_access(addr, 0, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002418#endif
bellard33417e72003-08-10 21:47:01 +00002419 return 0;
2420}
2421
bellarda4193c82004-06-03 14:01:43 +00002422static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002423{
pbrook67d3b952006-12-18 05:03:52 +00002424#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002425 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002426#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002427#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002428 do_unassigned_access(addr, 1, 0, 0, 1);
2429#endif
2430}
2431
2432static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2433{
2434#ifdef DEBUG_UNASSIGNED
2435 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2436#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002437#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002438 do_unassigned_access(addr, 1, 0, 0, 2);
2439#endif
2440}
2441
2442static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2443{
2444#ifdef DEBUG_UNASSIGNED
2445 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2446#endif
edgar_igl0a6f8a62008-12-29 14:39:57 +00002447#if defined(TARGET_SPARC)
blueswir1e18231a2008-10-06 18:46:28 +00002448 do_unassigned_access(addr, 1, 0, 0, 4);
blueswir1b4f0a312007-05-06 17:59:24 +00002449#endif
bellard33417e72003-08-10 21:47:01 +00002450}
2451
2452static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2453 unassigned_mem_readb,
blueswir1e18231a2008-10-06 18:46:28 +00002454 unassigned_mem_readw,
2455 unassigned_mem_readl,
bellard33417e72003-08-10 21:47:01 +00002456};
2457
2458static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2459 unassigned_mem_writeb,
blueswir1e18231a2008-10-06 18:46:28 +00002460 unassigned_mem_writew,
2461 unassigned_mem_writel,
bellard33417e72003-08-10 21:47:01 +00002462};
2463
pbrook0f459d12008-06-09 00:20:13 +00002464static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2465 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002466{
bellard3a7d9292005-08-21 09:26:42 +00002467 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002468 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2469 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2470#if !defined(CONFIG_USER_ONLY)
2471 tb_invalidate_phys_page_fast(ram_addr, 1);
2472 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2473#endif
2474 }
pbrook0f459d12008-06-09 00:20:13 +00002475 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002476#ifdef USE_KQEMU
2477 if (cpu_single_env->kqemu_enabled &&
2478 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2479 kqemu_modify_page(cpu_single_env, ram_addr);
2480#endif
bellardf23db162005-08-21 19:12:28 +00002481 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2482 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2483 /* we remove the notdirty callback only if the code has been
2484 flushed */
2485 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002486 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002487}
2488
pbrook0f459d12008-06-09 00:20:13 +00002489static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2490 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002491{
bellard3a7d9292005-08-21 09:26:42 +00002492 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002493 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2494 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2495#if !defined(CONFIG_USER_ONLY)
2496 tb_invalidate_phys_page_fast(ram_addr, 2);
2497 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2498#endif
2499 }
pbrook0f459d12008-06-09 00:20:13 +00002500 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002501#ifdef USE_KQEMU
2502 if (cpu_single_env->kqemu_enabled &&
2503 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2504 kqemu_modify_page(cpu_single_env, ram_addr);
2505#endif
bellardf23db162005-08-21 19:12:28 +00002506 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2507 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2508 /* we remove the notdirty callback only if the code has been
2509 flushed */
2510 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002511 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002512}
2513
pbrook0f459d12008-06-09 00:20:13 +00002514static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2515 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002516{
bellard3a7d9292005-08-21 09:26:42 +00002517 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002518 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2519 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2520#if !defined(CONFIG_USER_ONLY)
2521 tb_invalidate_phys_page_fast(ram_addr, 4);
2522 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2523#endif
2524 }
pbrook0f459d12008-06-09 00:20:13 +00002525 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002526#ifdef USE_KQEMU
2527 if (cpu_single_env->kqemu_enabled &&
2528 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2529 kqemu_modify_page(cpu_single_env, ram_addr);
2530#endif
bellardf23db162005-08-21 19:12:28 +00002531 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2532 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2533 /* we remove the notdirty callback only if the code has been
2534 flushed */
2535 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002536 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002537}
2538
bellard3a7d9292005-08-21 09:26:42 +00002539static CPUReadMemoryFunc *error_mem_read[3] = {
2540 NULL, /* never used */
2541 NULL, /* never used */
2542 NULL, /* never used */
2543};
2544
bellard1ccde1c2004-02-06 19:46:14 +00002545static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2546 notdirty_mem_writeb,
2547 notdirty_mem_writew,
2548 notdirty_mem_writel,
2549};
2550
pbrook0f459d12008-06-09 00:20:13 +00002551/* Generate a debug exception if a watchpoint has been hit. */
aliguorib4051332008-11-18 20:14:20 +00002552static void check_watchpoint(int offset, int len_mask, int flags)
pbrook0f459d12008-06-09 00:20:13 +00002553{
2554 CPUState *env = cpu_single_env;
aliguori06d55cc2008-11-18 20:24:06 +00002555 target_ulong pc, cs_base;
2556 TranslationBlock *tb;
pbrook0f459d12008-06-09 00:20:13 +00002557 target_ulong vaddr;
aliguoria1d1bb32008-11-18 20:07:32 +00002558 CPUWatchpoint *wp;
aliguori06d55cc2008-11-18 20:24:06 +00002559 int cpu_flags;
pbrook0f459d12008-06-09 00:20:13 +00002560
aliguori06d55cc2008-11-18 20:24:06 +00002561 if (env->watchpoint_hit) {
2562 /* We re-entered the check after replacing the TB. Now raise
2563 * the debug interrupt so that is will trigger after the
2564 * current instruction. */
2565 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2566 return;
2567 }
pbrook2e70f6e2008-06-29 01:03:05 +00002568 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
aliguoric0ce9982008-11-25 22:13:57 +00002569 TAILQ_FOREACH(wp, &env->watchpoints, entry) {
aliguorib4051332008-11-18 20:14:20 +00002570 if ((vaddr == (wp->vaddr & len_mask) ||
2571 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
aliguori6e140f22008-11-18 20:37:55 +00002572 wp->flags |= BP_WATCHPOINT_HIT;
2573 if (!env->watchpoint_hit) {
2574 env->watchpoint_hit = wp;
2575 tb = tb_find_pc(env->mem_io_pc);
2576 if (!tb) {
2577 cpu_abort(env, "check_watchpoint: could not find TB for "
2578 "pc=%p", (void *)env->mem_io_pc);
2579 }
2580 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
2581 tb_phys_invalidate(tb, -1);
2582 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2583 env->exception_index = EXCP_DEBUG;
2584 } else {
2585 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2586 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2587 }
2588 cpu_resume_from_signal(env, NULL);
aliguori06d55cc2008-11-18 20:24:06 +00002589 }
aliguori6e140f22008-11-18 20:37:55 +00002590 } else {
2591 wp->flags &= ~BP_WATCHPOINT_HIT;
pbrook0f459d12008-06-09 00:20:13 +00002592 }
2593 }
2594}
2595
pbrook6658ffb2007-03-16 23:58:11 +00002596/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2597 so these check for a hit then pass through to the normal out-of-line
2598 phys routines. */
2599static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2600{
aliguorib4051332008-11-18 20:14:20 +00002601 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002602 return ldub_phys(addr);
2603}
2604
2605static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2606{
aliguorib4051332008-11-18 20:14:20 +00002607 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002608 return lduw_phys(addr);
2609}
2610
2611static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2612{
aliguorib4051332008-11-18 20:14:20 +00002613 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002614 return ldl_phys(addr);
2615}
2616
pbrook6658ffb2007-03-16 23:58:11 +00002617static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2618 uint32_t val)
2619{
aliguorib4051332008-11-18 20:14:20 +00002620 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002621 stb_phys(addr, val);
2622}
2623
2624static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2625 uint32_t val)
2626{
aliguorib4051332008-11-18 20:14:20 +00002627 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002628 stw_phys(addr, val);
2629}
2630
2631static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2632 uint32_t val)
2633{
aliguorib4051332008-11-18 20:14:20 +00002634 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002635 stl_phys(addr, val);
2636}
2637
2638static CPUReadMemoryFunc *watch_mem_read[3] = {
2639 watch_mem_readb,
2640 watch_mem_readw,
2641 watch_mem_readl,
2642};
2643
2644static CPUWriteMemoryFunc *watch_mem_write[3] = {
2645 watch_mem_writeb,
2646 watch_mem_writew,
2647 watch_mem_writel,
2648};
pbrook6658ffb2007-03-16 23:58:11 +00002649
blueswir1db7b5422007-05-26 17:36:03 +00002650static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2651 unsigned int len)
2652{
blueswir1db7b5422007-05-26 17:36:03 +00002653 uint32_t ret;
2654 unsigned int idx;
2655
pbrook8da3ff12008-12-01 18:59:50 +00002656 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002657#if defined(DEBUG_SUBPAGE)
2658 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2659 mmio, len, addr, idx);
2660#endif
pbrook8da3ff12008-12-01 18:59:50 +00002661 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2662 addr + mmio->region_offset[idx][0][len]);
blueswir1db7b5422007-05-26 17:36:03 +00002663
2664 return ret;
2665}
2666
2667static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2668 uint32_t value, unsigned int len)
2669{
blueswir1db7b5422007-05-26 17:36:03 +00002670 unsigned int idx;
2671
pbrook8da3ff12008-12-01 18:59:50 +00002672 idx = SUBPAGE_IDX(addr);
blueswir1db7b5422007-05-26 17:36:03 +00002673#if defined(DEBUG_SUBPAGE)
2674 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2675 mmio, len, addr, idx, value);
2676#endif
pbrook8da3ff12008-12-01 18:59:50 +00002677 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2678 addr + mmio->region_offset[idx][1][len],
2679 value);
blueswir1db7b5422007-05-26 17:36:03 +00002680}
2681
2682static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2683{
2684#if defined(DEBUG_SUBPAGE)
2685 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2686#endif
2687
2688 return subpage_readlen(opaque, addr, 0);
2689}
2690
2691static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2692 uint32_t value)
2693{
2694#if defined(DEBUG_SUBPAGE)
2695 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2696#endif
2697 subpage_writelen(opaque, addr, value, 0);
2698}
2699
2700static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2701{
2702#if defined(DEBUG_SUBPAGE)
2703 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2704#endif
2705
2706 return subpage_readlen(opaque, addr, 1);
2707}
2708
2709static void subpage_writew (void *opaque, target_phys_addr_t addr,
2710 uint32_t value)
2711{
2712#if defined(DEBUG_SUBPAGE)
2713 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2714#endif
2715 subpage_writelen(opaque, addr, value, 1);
2716}
2717
2718static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2719{
2720#if defined(DEBUG_SUBPAGE)
2721 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2722#endif
2723
2724 return subpage_readlen(opaque, addr, 2);
2725}
2726
2727static void subpage_writel (void *opaque,
2728 target_phys_addr_t addr, uint32_t value)
2729{
2730#if defined(DEBUG_SUBPAGE)
2731 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2732#endif
2733 subpage_writelen(opaque, addr, value, 2);
2734}
2735
2736static CPUReadMemoryFunc *subpage_read[] = {
2737 &subpage_readb,
2738 &subpage_readw,
2739 &subpage_readl,
2740};
2741
2742static CPUWriteMemoryFunc *subpage_write[] = {
2743 &subpage_writeb,
2744 &subpage_writew,
2745 &subpage_writel,
2746};
2747
2748static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
pbrook8da3ff12008-12-01 18:59:50 +00002749 ram_addr_t memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002750{
2751 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002752 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002753
2754 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2755 return -1;
2756 idx = SUBPAGE_IDX(start);
2757 eidx = SUBPAGE_IDX(end);
2758#if defined(DEBUG_SUBPAGE)
2759 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2760 mmio, start, end, idx, eidx, memory);
2761#endif
2762 memory >>= IO_MEM_SHIFT;
2763 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002764 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002765 if (io_mem_read[memory][i]) {
2766 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2767 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002768 mmio->region_offset[idx][0][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002769 }
2770 if (io_mem_write[memory][i]) {
2771 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2772 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
pbrook8da3ff12008-12-01 18:59:50 +00002773 mmio->region_offset[idx][1][i] = region_offset;
blueswir13ee89922008-01-02 19:45:26 +00002774 }
blueswir14254fab2008-01-01 16:57:19 +00002775 }
blueswir1db7b5422007-05-26 17:36:03 +00002776 }
2777
2778 return 0;
2779}
2780
aurel3200f82b82008-04-27 21:12:55 +00002781static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
pbrook8da3ff12008-12-01 18:59:50 +00002782 ram_addr_t orig_memory, ram_addr_t region_offset)
blueswir1db7b5422007-05-26 17:36:03 +00002783{
2784 subpage_t *mmio;
2785 int subpage_memory;
2786
2787 mmio = qemu_mallocz(sizeof(subpage_t));
aliguori1eec6142009-02-05 22:06:18 +00002788
2789 mmio->base = base;
2790 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
blueswir1db7b5422007-05-26 17:36:03 +00002791#if defined(DEBUG_SUBPAGE)
aliguori1eec6142009-02-05 22:06:18 +00002792 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2793 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002794#endif
aliguori1eec6142009-02-05 22:06:18 +00002795 *phys = subpage_memory | IO_MEM_SUBPAGE;
2796 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
pbrook8da3ff12008-12-01 18:59:50 +00002797 region_offset);
blueswir1db7b5422007-05-26 17:36:03 +00002798
2799 return mmio;
2800}
2801
aliguori88715652009-02-11 15:20:58 +00002802static int get_free_io_mem_idx(void)
2803{
2804 int i;
2805
2806 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2807 if (!io_mem_used[i]) {
2808 io_mem_used[i] = 1;
2809 return i;
2810 }
2811
2812 return -1;
2813}
2814
bellard33417e72003-08-10 21:47:01 +00002815static void io_mem_init(void)
2816{
aliguori88715652009-02-11 15:20:58 +00002817 int i;
2818
bellard3a7d9292005-08-21 09:26:42 +00002819 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002820 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002821 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
aliguori88715652009-02-11 15:20:58 +00002822 for (i=0; i<5; i++)
2823 io_mem_used[i] = 1;
bellard1ccde1c2004-02-06 19:46:14 +00002824
pbrook0f459d12008-06-09 00:20:13 +00002825 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002826 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002827 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002828 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002829 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002830}
2831
2832/* mem_read and mem_write are arrays of functions containing the
2833 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002834 2). Functions can be omitted with a NULL function pointer. The
2835 registered functions may be modified dynamically later.
2836 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002837 modified. If it is zero, a new io zone is allocated. The return
2838 value can be used with cpu_register_physical_memory(). (-1) is
2839 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002840int cpu_register_io_memory(int io_index,
2841 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002842 CPUWriteMemoryFunc **mem_write,
2843 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002844{
blueswir14254fab2008-01-01 16:57:19 +00002845 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002846
2847 if (io_index <= 0) {
aliguori88715652009-02-11 15:20:58 +00002848 io_index = get_free_io_mem_idx();
2849 if (io_index == -1)
2850 return io_index;
bellard33417e72003-08-10 21:47:01 +00002851 } else {
2852 if (io_index >= IO_MEM_NB_ENTRIES)
2853 return -1;
2854 }
bellardb5ff1b32005-11-26 10:38:39 +00002855
bellard33417e72003-08-10 21:47:01 +00002856 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002857 if (!mem_read[i] || !mem_write[i])
2858 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002859 io_mem_read[io_index][i] = mem_read[i];
2860 io_mem_write[io_index][i] = mem_write[i];
2861 }
bellarda4193c82004-06-03 14:01:43 +00002862 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002863 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002864}
bellard61382a52003-10-27 21:22:23 +00002865
aliguori88715652009-02-11 15:20:58 +00002866void cpu_unregister_io_memory(int io_table_address)
2867{
2868 int i;
2869 int io_index = io_table_address >> IO_MEM_SHIFT;
2870
2871 for (i=0;i < 3; i++) {
2872 io_mem_read[io_index][i] = unassigned_mem_read[i];
2873 io_mem_write[io_index][i] = unassigned_mem_write[i];
2874 }
2875 io_mem_opaque[io_index] = NULL;
2876 io_mem_used[io_index] = 0;
2877}
2878
bellard8926b512004-10-10 15:14:20 +00002879CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2880{
2881 return io_mem_write[io_index >> IO_MEM_SHIFT];
2882}
2883
2884CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2885{
2886 return io_mem_read[io_index >> IO_MEM_SHIFT];
2887}
2888
pbrooke2eef172008-06-08 01:09:01 +00002889#endif /* !defined(CONFIG_USER_ONLY) */
2890
bellard13eb76e2004-01-24 15:23:36 +00002891/* physical memory access (slow version, mainly for debug) */
2892#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002893void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002894 int len, int is_write)
2895{
2896 int l, flags;
2897 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002898 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002899
2900 while (len > 0) {
2901 page = addr & TARGET_PAGE_MASK;
2902 l = (page + TARGET_PAGE_SIZE) - addr;
2903 if (l > len)
2904 l = len;
2905 flags = page_get_flags(page);
2906 if (!(flags & PAGE_VALID))
2907 return;
2908 if (is_write) {
2909 if (!(flags & PAGE_WRITE))
2910 return;
bellard579a97f2007-11-11 14:26:47 +00002911 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002912 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002913 /* FIXME - should this return an error rather than just fail? */
2914 return;
aurel3272fb7da2008-04-27 23:53:45 +00002915 memcpy(p, buf, l);
2916 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002917 } else {
2918 if (!(flags & PAGE_READ))
2919 return;
bellard579a97f2007-11-11 14:26:47 +00002920 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002921 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002922 /* FIXME - should this return an error rather than just fail? */
2923 return;
aurel3272fb7da2008-04-27 23:53:45 +00002924 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002925 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002926 }
2927 len -= l;
2928 buf += l;
2929 addr += l;
2930 }
2931}
bellard8df1cd02005-01-28 22:37:22 +00002932
bellard13eb76e2004-01-24 15:23:36 +00002933#else
ths5fafdf22007-09-16 21:08:06 +00002934void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002935 int len, int is_write)
2936{
2937 int l, io_index;
2938 uint8_t *ptr;
2939 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002940 target_phys_addr_t page;
2941 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002942 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002943
bellard13eb76e2004-01-24 15:23:36 +00002944 while (len > 0) {
2945 page = addr & TARGET_PAGE_MASK;
2946 l = (page + TARGET_PAGE_SIZE) - addr;
2947 if (l > len)
2948 l = len;
bellard92e873b2004-05-21 14:52:29 +00002949 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002950 if (!p) {
2951 pd = IO_MEM_UNASSIGNED;
2952 } else {
2953 pd = p->phys_offset;
2954 }
ths3b46e622007-09-17 08:09:54 +00002955
bellard13eb76e2004-01-24 15:23:36 +00002956 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002957 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002958 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002959 if (p)
2960 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard6a00d602005-11-21 23:25:50 +00002961 /* XXX: could force cpu_single_env to NULL to avoid
2962 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002963 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002964 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002965 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002966 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002967 l = 4;
2968 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002969 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002970 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002971 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002972 l = 2;
2973 } else {
bellard1c213d12005-09-03 10:49:04 +00002974 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002975 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002976 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002977 l = 1;
2978 }
2979 } else {
bellardb448f2f2004-02-25 23:24:04 +00002980 unsigned long addr1;
2981 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002982 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002983 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002984 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002985 if (!cpu_physical_memory_is_dirty(addr1)) {
2986 /* invalidate code */
2987 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2988 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002989 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002990 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002991 }
bellard13eb76e2004-01-24 15:23:36 +00002992 }
2993 } else {
ths5fafdf22007-09-16 21:08:06 +00002994 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002995 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002996 /* I/O case */
2997 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00002998 if (p)
2999 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard13eb76e2004-01-24 15:23:36 +00003000 if (l >= 4 && ((addr & 3) == 0)) {
3001 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00003002 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00003003 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003004 l = 4;
3005 } else if (l >= 2 && ((addr & 1) == 0)) {
3006 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00003007 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00003008 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003009 l = 2;
3010 } else {
bellard1c213d12005-09-03 10:49:04 +00003011 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00003012 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00003013 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00003014 l = 1;
3015 }
3016 } else {
3017 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003018 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00003019 (addr & ~TARGET_PAGE_MASK);
3020 memcpy(buf, ptr, l);
3021 }
3022 }
3023 len -= l;
3024 buf += l;
3025 addr += l;
3026 }
3027}
bellard8df1cd02005-01-28 22:37:22 +00003028
bellardd0ecd2a2006-04-23 17:14:48 +00003029/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00003030void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00003031 const uint8_t *buf, int len)
3032{
3033 int l;
3034 uint8_t *ptr;
3035 target_phys_addr_t page;
3036 unsigned long pd;
3037 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00003038
bellardd0ecd2a2006-04-23 17:14:48 +00003039 while (len > 0) {
3040 page = addr & TARGET_PAGE_MASK;
3041 l = (page + TARGET_PAGE_SIZE) - addr;
3042 if (l > len)
3043 l = len;
3044 p = phys_page_find(page >> TARGET_PAGE_BITS);
3045 if (!p) {
3046 pd = IO_MEM_UNASSIGNED;
3047 } else {
3048 pd = p->phys_offset;
3049 }
ths3b46e622007-09-17 08:09:54 +00003050
bellardd0ecd2a2006-04-23 17:14:48 +00003051 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00003052 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3053 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00003054 /* do nothing */
3055 } else {
3056 unsigned long addr1;
3057 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3058 /* ROM/RAM case */
3059 ptr = phys_ram_base + addr1;
3060 memcpy(ptr, buf, l);
3061 }
3062 len -= l;
3063 buf += l;
3064 addr += l;
3065 }
3066}
3067
aliguori6d16c2f2009-01-22 16:59:11 +00003068typedef struct {
3069 void *buffer;
3070 target_phys_addr_t addr;
3071 target_phys_addr_t len;
3072} BounceBuffer;
3073
3074static BounceBuffer bounce;
3075
aliguoriba223c22009-01-22 16:59:16 +00003076typedef struct MapClient {
3077 void *opaque;
3078 void (*callback)(void *opaque);
3079 LIST_ENTRY(MapClient) link;
3080} MapClient;
3081
3082static LIST_HEAD(map_client_list, MapClient) map_client_list
3083 = LIST_HEAD_INITIALIZER(map_client_list);
3084
3085void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
3086{
3087 MapClient *client = qemu_malloc(sizeof(*client));
3088
3089 client->opaque = opaque;
3090 client->callback = callback;
3091 LIST_INSERT_HEAD(&map_client_list, client, link);
3092 return client;
3093}
3094
3095void cpu_unregister_map_client(void *_client)
3096{
3097 MapClient *client = (MapClient *)_client;
3098
3099 LIST_REMOVE(client, link);
3100}
3101
3102static void cpu_notify_map_clients(void)
3103{
3104 MapClient *client;
3105
3106 while (!LIST_EMPTY(&map_client_list)) {
3107 client = LIST_FIRST(&map_client_list);
3108 client->callback(client->opaque);
3109 LIST_REMOVE(client, link);
3110 }
3111}
3112
aliguori6d16c2f2009-01-22 16:59:11 +00003113/* Map a physical memory region into a host virtual address.
3114 * May map a subset of the requested range, given by and returned in *plen.
3115 * May return NULL if resources needed to perform the mapping are exhausted.
3116 * Use only for reads OR writes - not for read-modify-write operations.
aliguoriba223c22009-01-22 16:59:16 +00003117 * Use cpu_register_map_client() to know when retrying the map operation is
3118 * likely to succeed.
aliguori6d16c2f2009-01-22 16:59:11 +00003119 */
3120void *cpu_physical_memory_map(target_phys_addr_t addr,
3121 target_phys_addr_t *plen,
3122 int is_write)
3123{
3124 target_phys_addr_t len = *plen;
3125 target_phys_addr_t done = 0;
3126 int l;
3127 uint8_t *ret = NULL;
3128 uint8_t *ptr;
3129 target_phys_addr_t page;
3130 unsigned long pd;
3131 PhysPageDesc *p;
3132 unsigned long addr1;
3133
3134 while (len > 0) {
3135 page = addr & TARGET_PAGE_MASK;
3136 l = (page + TARGET_PAGE_SIZE) - addr;
3137 if (l > len)
3138 l = len;
3139 p = phys_page_find(page >> TARGET_PAGE_BITS);
3140 if (!p) {
3141 pd = IO_MEM_UNASSIGNED;
3142 } else {
3143 pd = p->phys_offset;
3144 }
3145
3146 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3147 if (done || bounce.buffer) {
3148 break;
3149 }
3150 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
3151 bounce.addr = addr;
3152 bounce.len = l;
3153 if (!is_write) {
3154 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
3155 }
3156 ptr = bounce.buffer;
3157 } else {
3158 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3159 ptr = phys_ram_base + addr1;
3160 }
3161 if (!done) {
3162 ret = ptr;
3163 } else if (ret + done != ptr) {
3164 break;
3165 }
3166
3167 len -= l;
3168 addr += l;
3169 done += l;
3170 }
3171 *plen = done;
3172 return ret;
3173}
3174
3175/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
3176 * Will also mark the memory as dirty if is_write == 1. access_len gives
3177 * the amount of memory that was actually read or written by the caller.
3178 */
3179void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
3180 int is_write, target_phys_addr_t access_len)
3181{
3182 if (buffer != bounce.buffer) {
3183 if (is_write) {
3184 unsigned long addr1 = (uint8_t *)buffer - phys_ram_base;
3185 while (access_len) {
3186 unsigned l;
3187 l = TARGET_PAGE_SIZE;
3188 if (l > access_len)
3189 l = access_len;
3190 if (!cpu_physical_memory_is_dirty(addr1)) {
3191 /* invalidate code */
3192 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3193 /* set dirty bit */
3194 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3195 (0xff & ~CODE_DIRTY_FLAG);
3196 }
3197 addr1 += l;
3198 access_len -= l;
3199 }
3200 }
3201 return;
3202 }
3203 if (is_write) {
3204 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
3205 }
3206 qemu_free(bounce.buffer);
3207 bounce.buffer = NULL;
aliguoriba223c22009-01-22 16:59:16 +00003208 cpu_notify_map_clients();
aliguori6d16c2f2009-01-22 16:59:11 +00003209}
bellardd0ecd2a2006-04-23 17:14:48 +00003210
bellard8df1cd02005-01-28 22:37:22 +00003211/* warning: addr must be aligned */
3212uint32_t ldl_phys(target_phys_addr_t addr)
3213{
3214 int io_index;
3215 uint8_t *ptr;
3216 uint32_t val;
3217 unsigned long pd;
3218 PhysPageDesc *p;
3219
3220 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3221 if (!p) {
3222 pd = IO_MEM_UNASSIGNED;
3223 } else {
3224 pd = p->phys_offset;
3225 }
ths3b46e622007-09-17 08:09:54 +00003226
ths5fafdf22007-09-16 21:08:06 +00003227 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00003228 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00003229 /* I/O case */
3230 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003231 if (p)
3232 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003233 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3234 } else {
3235 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003236 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00003237 (addr & ~TARGET_PAGE_MASK);
3238 val = ldl_p(ptr);
3239 }
3240 return val;
3241}
3242
bellard84b7b8e2005-11-28 21:19:04 +00003243/* warning: addr must be aligned */
3244uint64_t ldq_phys(target_phys_addr_t addr)
3245{
3246 int io_index;
3247 uint8_t *ptr;
3248 uint64_t val;
3249 unsigned long pd;
3250 PhysPageDesc *p;
3251
3252 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3253 if (!p) {
3254 pd = IO_MEM_UNASSIGNED;
3255 } else {
3256 pd = p->phys_offset;
3257 }
ths3b46e622007-09-17 08:09:54 +00003258
bellard2a4188a2006-06-25 21:54:59 +00003259 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3260 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00003261 /* I/O case */
3262 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003263 if (p)
3264 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard84b7b8e2005-11-28 21:19:04 +00003265#ifdef TARGET_WORDS_BIGENDIAN
3266 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3267 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3268#else
3269 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3270 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3271#endif
3272 } else {
3273 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00003274 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00003275 (addr & ~TARGET_PAGE_MASK);
3276 val = ldq_p(ptr);
3277 }
3278 return val;
3279}
3280
bellardaab33092005-10-30 20:48:42 +00003281/* XXX: optimize */
3282uint32_t ldub_phys(target_phys_addr_t addr)
3283{
3284 uint8_t val;
3285 cpu_physical_memory_read(addr, &val, 1);
3286 return val;
3287}
3288
3289/* XXX: optimize */
3290uint32_t lduw_phys(target_phys_addr_t addr)
3291{
3292 uint16_t val;
3293 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3294 return tswap16(val);
3295}
3296
bellard8df1cd02005-01-28 22:37:22 +00003297/* warning: addr must be aligned. The ram page is not masked as dirty
3298 and the code inside is not invalidated. It is useful if the dirty
3299 bits are used to track modified PTEs */
3300void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
3301{
3302 int io_index;
3303 uint8_t *ptr;
3304 unsigned long pd;
3305 PhysPageDesc *p;
3306
3307 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3308 if (!p) {
3309 pd = IO_MEM_UNASSIGNED;
3310 } else {
3311 pd = p->phys_offset;
3312 }
ths3b46e622007-09-17 08:09:54 +00003313
bellard3a7d9292005-08-21 09:26:42 +00003314 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003315 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003316 if (p)
3317 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003318 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3319 } else {
aliguori74576192008-10-06 14:02:03 +00003320 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3321 ptr = phys_ram_base + addr1;
bellard8df1cd02005-01-28 22:37:22 +00003322 stl_p(ptr, val);
aliguori74576192008-10-06 14:02:03 +00003323
3324 if (unlikely(in_migration)) {
3325 if (!cpu_physical_memory_is_dirty(addr1)) {
3326 /* invalidate code */
3327 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3328 /* set dirty bit */
3329 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3330 (0xff & ~CODE_DIRTY_FLAG);
3331 }
3332 }
bellard8df1cd02005-01-28 22:37:22 +00003333 }
3334}
3335
j_mayerbc98a7e2007-04-04 07:55:12 +00003336void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
3337{
3338 int io_index;
3339 uint8_t *ptr;
3340 unsigned long pd;
3341 PhysPageDesc *p;
3342
3343 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3344 if (!p) {
3345 pd = IO_MEM_UNASSIGNED;
3346 } else {
3347 pd = p->phys_offset;
3348 }
ths3b46e622007-09-17 08:09:54 +00003349
j_mayerbc98a7e2007-04-04 07:55:12 +00003350 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3351 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003352 if (p)
3353 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
j_mayerbc98a7e2007-04-04 07:55:12 +00003354#ifdef TARGET_WORDS_BIGENDIAN
3355 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3356 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3357#else
3358 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3359 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3360#endif
3361 } else {
ths5fafdf22007-09-16 21:08:06 +00003362 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00003363 (addr & ~TARGET_PAGE_MASK);
3364 stq_p(ptr, val);
3365 }
3366}
3367
bellard8df1cd02005-01-28 22:37:22 +00003368/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00003369void stl_phys(target_phys_addr_t addr, uint32_t val)
3370{
3371 int io_index;
3372 uint8_t *ptr;
3373 unsigned long pd;
3374 PhysPageDesc *p;
3375
3376 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3377 if (!p) {
3378 pd = IO_MEM_UNASSIGNED;
3379 } else {
3380 pd = p->phys_offset;
3381 }
ths3b46e622007-09-17 08:09:54 +00003382
bellard3a7d9292005-08-21 09:26:42 +00003383 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003384 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
pbrook8da3ff12008-12-01 18:59:50 +00003385 if (p)
3386 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
bellard8df1cd02005-01-28 22:37:22 +00003387 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3388 } else {
3389 unsigned long addr1;
3390 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3391 /* RAM case */
3392 ptr = phys_ram_base + addr1;
3393 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003394 if (!cpu_physical_memory_is_dirty(addr1)) {
3395 /* invalidate code */
3396 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3397 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003398 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3399 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003400 }
bellard8df1cd02005-01-28 22:37:22 +00003401 }
3402}
3403
bellardaab33092005-10-30 20:48:42 +00003404/* XXX: optimize */
3405void stb_phys(target_phys_addr_t addr, uint32_t val)
3406{
3407 uint8_t v = val;
3408 cpu_physical_memory_write(addr, &v, 1);
3409}
3410
3411/* XXX: optimize */
3412void stw_phys(target_phys_addr_t addr, uint32_t val)
3413{
3414 uint16_t v = tswap16(val);
3415 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3416}
3417
3418/* XXX: optimize */
3419void stq_phys(target_phys_addr_t addr, uint64_t val)
3420{
3421 val = tswap64(val);
3422 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3423}
3424
bellard13eb76e2004-01-24 15:23:36 +00003425#endif
3426
3427/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00003428int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003429 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003430{
3431 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003432 target_phys_addr_t phys_addr;
3433 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003434
3435 while (len > 0) {
3436 page = addr & TARGET_PAGE_MASK;
3437 phys_addr = cpu_get_phys_page_debug(env, page);
3438 /* if no physical page mapped, return an error */
3439 if (phys_addr == -1)
3440 return -1;
3441 l = (page + TARGET_PAGE_SIZE) - addr;
3442 if (l > len)
3443 l = len;
ths5fafdf22007-09-16 21:08:06 +00003444 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00003445 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003446 len -= l;
3447 buf += l;
3448 addr += l;
3449 }
3450 return 0;
3451}
3452
pbrook2e70f6e2008-06-29 01:03:05 +00003453/* in deterministic execution mode, instructions doing device I/Os
3454 must be at the end of the TB */
3455void cpu_io_recompile(CPUState *env, void *retaddr)
3456{
3457 TranslationBlock *tb;
3458 uint32_t n, cflags;
3459 target_ulong pc, cs_base;
3460 uint64_t flags;
3461
3462 tb = tb_find_pc((unsigned long)retaddr);
3463 if (!tb) {
3464 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3465 retaddr);
3466 }
3467 n = env->icount_decr.u16.low + tb->icount;
3468 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3469 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003470 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003471 n = n - env->icount_decr.u16.low;
3472 /* Generate a new TB ending on the I/O insn. */
3473 n++;
3474 /* On MIPS and SH, delay slot instructions can only be restarted if
3475 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003476 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003477 branch. */
3478#if defined(TARGET_MIPS)
3479 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3480 env->active_tc.PC -= 4;
3481 env->icount_decr.u16.low++;
3482 env->hflags &= ~MIPS_HFLAG_BMASK;
3483 }
3484#elif defined(TARGET_SH4)
3485 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3486 && n > 1) {
3487 env->pc -= 2;
3488 env->icount_decr.u16.low++;
3489 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3490 }
3491#endif
3492 /* This should never happen. */
3493 if (n > CF_COUNT_MASK)
3494 cpu_abort(env, "TB too big during recompile");
3495
3496 cflags = n | CF_LAST_IO;
3497 pc = tb->pc;
3498 cs_base = tb->cs_base;
3499 flags = tb->flags;
3500 tb_phys_invalidate(tb, -1);
3501 /* FIXME: In theory this could raise an exception. In practice
3502 we have already translated the block once so it's probably ok. */
3503 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003504 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003505 the first in the TB) then we end up generating a whole new TB and
3506 repeating the fault, which is horribly inefficient.
3507 Better would be to execute just this insn uncached, or generate a
3508 second new TB. */
3509 cpu_resume_from_signal(env, NULL);
3510}
3511
bellarde3db7222005-01-26 22:00:47 +00003512void dump_exec_info(FILE *f,
3513 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3514{
3515 int i, target_code_size, max_target_code_size;
3516 int direct_jmp_count, direct_jmp2_count, cross_page;
3517 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003518
bellarde3db7222005-01-26 22:00:47 +00003519 target_code_size = 0;
3520 max_target_code_size = 0;
3521 cross_page = 0;
3522 direct_jmp_count = 0;
3523 direct_jmp2_count = 0;
3524 for(i = 0; i < nb_tbs; i++) {
3525 tb = &tbs[i];
3526 target_code_size += tb->size;
3527 if (tb->size > max_target_code_size)
3528 max_target_code_size = tb->size;
3529 if (tb->page_addr[1] != -1)
3530 cross_page++;
3531 if (tb->tb_next_offset[0] != 0xffff) {
3532 direct_jmp_count++;
3533 if (tb->tb_next_offset[1] != 0xffff) {
3534 direct_jmp2_count++;
3535 }
3536 }
3537 }
3538 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003539 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003540 cpu_fprintf(f, "gen code size %ld/%ld\n",
3541 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3542 cpu_fprintf(f, "TB count %d/%d\n",
3543 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003544 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003545 nb_tbs ? target_code_size / nb_tbs : 0,
3546 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003547 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003548 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3549 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003550 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3551 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003552 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3553 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003554 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003555 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3556 direct_jmp2_count,
3557 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003558 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003559 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3560 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3561 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003562 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003563}
3564
ths5fafdf22007-09-16 21:08:06 +00003565#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003566
3567#define MMUSUFFIX _cmmu
3568#define GETPC() NULL
3569#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003570#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003571
3572#define SHIFT 0
3573#include "softmmu_template.h"
3574
3575#define SHIFT 1
3576#include "softmmu_template.h"
3577
3578#define SHIFT 2
3579#include "softmmu_template.h"
3580
3581#define SHIFT 3
3582#include "softmmu_template.h"
3583
3584#undef env
3585
3586#endif