blob: 64c87b31e847c97b0c90d32eb8775c28d7eac28a [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrookb3c77242008-06-30 16:31:04 +000040#include "hw/hw.h"
pbrook53a59602006-03-25 19:31:22 +000041#if defined(CONFIG_USER_ONLY)
42#include <qemu.h>
43#endif
bellard54936002003-05-13 00:25:15 +000044
bellardfd6ce8f2003-05-14 19:00:11 +000045//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000046//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000047//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000048//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000049
50/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000051//#define DEBUG_TB_CHECK
52//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000053
ths1196be32007-03-17 15:17:58 +000054//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000055//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000056
pbrook99773bd2006-04-16 15:14:59 +000057#if !defined(CONFIG_USER_ONLY)
58/* TB consistency checks only implemented for usermode emulation. */
59#undef DEBUG_TB_CHECK
60#endif
61
bellard9fa3e852004-01-04 18:06:42 +000062#define SMC_BITMAP_USE_THRESHOLD 10
63
64#define MMAP_AREA_START 0x00000000
65#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000066
bellard108c49b2005-07-24 12:55:09 +000067#if defined(TARGET_SPARC64)
68#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000069#elif defined(TARGET_SPARC)
70#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000071#elif defined(TARGET_ALPHA)
72#define TARGET_PHYS_ADDR_SPACE_BITS 42
73#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000074#elif defined(TARGET_PPC64)
75#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000076#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
77#define TARGET_PHYS_ADDR_SPACE_BITS 42
78#elif defined(TARGET_I386) && !defined(USE_KQEMU)
79#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000080#else
81/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
82#define TARGET_PHYS_ADDR_SPACE_BITS 32
83#endif
84
pbrookfab94c02008-05-24 13:56:15 +000085TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000086int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000087TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000088int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000089/* any access to the tbs or the page table must use this lock */
90spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000091
bellard7cb69ca2008-05-10 10:55:51 +000092uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellard26a5f132008-05-28 12:30:31 +000093uint8_t *code_gen_buffer;
94unsigned long code_gen_buffer_size;
95/* threshold to flush the translated code buffer */
96unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +000097uint8_t *code_gen_ptr;
98
pbrooke2eef172008-06-08 01:09:01 +000099#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +0000100ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000101int phys_ram_fd;
102uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000103uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000104static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000105#endif
bellard9fa3e852004-01-04 18:06:42 +0000106
bellard6a00d602005-11-21 23:25:50 +0000107CPUState *first_cpu;
108/* current CPU in the current thread. It is only valid inside
109 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000110CPUState *cpu_single_env;
pbrook2e70f6e2008-06-29 01:03:05 +0000111/* 0 = Do not count executed instructions.
thsbf20dc02008-06-30 17:22:19 +0000112 1 = Precise instruction counting.
pbrook2e70f6e2008-06-29 01:03:05 +0000113 2 = Adaptive rate instruction counting. */
114int use_icount = 0;
115/* Current instruction counter. While executing translated code this may
116 include some instructions that have not yet been executed. */
117int64_t qemu_icount;
bellard6a00d602005-11-21 23:25:50 +0000118
bellard54936002003-05-13 00:25:15 +0000119typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000120 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000121 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000122 /* in order to optimize self modifying code, we count the number
123 of lookups we do to a given page to use a bitmap */
124 unsigned int code_write_count;
125 uint8_t *code_bitmap;
126#if defined(CONFIG_USER_ONLY)
127 unsigned long flags;
128#endif
bellard54936002003-05-13 00:25:15 +0000129} PageDesc;
130
bellard92e873b2004-05-21 14:52:29 +0000131typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000132 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000133 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000134} PhysPageDesc;
135
bellard54936002003-05-13 00:25:15 +0000136#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000137#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
138/* XXX: this is a temporary hack for alpha target.
139 * In the future, this is to be replaced by a multi-level table
140 * to actually be able to handle the complete 64 bits address space.
141 */
142#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
143#else
aurel3203875442008-04-22 20:45:18 +0000144#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000145#endif
bellard54936002003-05-13 00:25:15 +0000146
147#define L1_SIZE (1 << L1_BITS)
148#define L2_SIZE (1 << L2_BITS)
149
bellard83fb7ad2004-07-05 21:25:26 +0000150unsigned long qemu_real_host_page_size;
151unsigned long qemu_host_page_bits;
152unsigned long qemu_host_page_size;
153unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000154
bellard92e873b2004-05-21 14:52:29 +0000155/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000156static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000157PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000158
pbrooke2eef172008-06-08 01:09:01 +0000159#if !defined(CONFIG_USER_ONLY)
160static void io_mem_init(void);
161
bellard33417e72003-08-10 21:47:01 +0000162/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000163CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
164CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000165void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000166static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000167static int io_mem_watch;
168#endif
bellard33417e72003-08-10 21:47:01 +0000169
bellard34865132003-10-05 14:28:56 +0000170/* log support */
171char *logfilename = "/tmp/qemu.log";
172FILE *logfile;
173int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000174static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000175
bellarde3db7222005-01-26 22:00:47 +0000176/* statistics */
177static int tlb_flush_count;
178static int tb_flush_count;
179static int tb_phys_invalidate_count;
180
blueswir1db7b5422007-05-26 17:36:03 +0000181#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
182typedef struct subpage_t {
183 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000184 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
185 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
186 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000187} subpage_t;
188
bellard7cb69ca2008-05-10 10:55:51 +0000189#ifdef _WIN32
190static void map_exec(void *addr, long size)
191{
192 DWORD old_protect;
193 VirtualProtect(addr, size,
194 PAGE_EXECUTE_READWRITE, &old_protect);
195
196}
197#else
198static void map_exec(void *addr, long size)
199{
bellard43694152008-05-29 09:35:57 +0000200 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000201
bellard43694152008-05-29 09:35:57 +0000202 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000203 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000204 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000205
206 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000207 end += page_size - 1;
208 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000209
210 mprotect((void *)start, end - start,
211 PROT_READ | PROT_WRITE | PROT_EXEC);
212}
213#endif
214
bellardb346ff42003-06-15 20:05:50 +0000215static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000216{
bellard83fb7ad2004-07-05 21:25:26 +0000217 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000218 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000219#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000220 {
221 SYSTEM_INFO system_info;
222 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000223
bellardd5a8f072004-09-29 21:15:28 +0000224 GetSystemInfo(&system_info);
225 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000226 }
bellard67b915a2004-03-31 23:37:16 +0000227#else
bellard83fb7ad2004-07-05 21:25:26 +0000228 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000229#endif
bellard83fb7ad2004-07-05 21:25:26 +0000230 if (qemu_host_page_size == 0)
231 qemu_host_page_size = qemu_real_host_page_size;
232 if (qemu_host_page_size < TARGET_PAGE_SIZE)
233 qemu_host_page_size = TARGET_PAGE_SIZE;
234 qemu_host_page_bits = 0;
235 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
236 qemu_host_page_bits++;
237 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000238 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
239 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000240
241#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
242 {
243 long long startaddr, endaddr;
244 FILE *f;
245 int n;
246
pbrookc8a706f2008-06-02 16:16:42 +0000247 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000248 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000249 f = fopen("/proc/self/maps", "r");
250 if (f) {
251 do {
252 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
253 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000254 startaddr = MIN(startaddr,
255 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
256 endaddr = MIN(endaddr,
257 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000258 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000259 TARGET_PAGE_ALIGN(endaddr),
260 PAGE_RESERVED);
261 }
262 } while (!feof(f));
263 fclose(f);
264 }
pbrookc8a706f2008-06-02 16:16:42 +0000265 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000266 }
267#endif
bellard54936002003-05-13 00:25:15 +0000268}
269
aurel3200f82b82008-04-27 21:12:55 +0000270static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000271{
bellard54936002003-05-13 00:25:15 +0000272 PageDesc **lp, *p;
273
pbrook17e23772008-06-09 13:47:45 +0000274#if TARGET_LONG_BITS > 32
275 /* Host memory outside guest VM. For 32-bit targets we have already
276 excluded high addresses. */
277 if (index > ((target_ulong)L2_SIZE * L1_SIZE * TARGET_PAGE_SIZE))
278 return NULL;
279#endif
bellard54936002003-05-13 00:25:15 +0000280 lp = &l1_map[index >> L2_BITS];
281 p = *lp;
282 if (!p) {
283 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000284#if defined(CONFIG_USER_ONLY)
285 unsigned long addr;
286 size_t len = sizeof(PageDesc) * L2_SIZE;
287 /* Don't use qemu_malloc because it may recurse. */
288 p = mmap(0, len, PROT_READ | PROT_WRITE,
289 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000290 *lp = p;
pbrook17e23772008-06-09 13:47:45 +0000291 addr = h2g(p);
292 if (addr == (target_ulong)addr) {
293 page_set_flags(addr & TARGET_PAGE_MASK,
294 TARGET_PAGE_ALIGN(addr + len),
295 PAGE_RESERVED);
296 }
297#else
298 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
299 *lp = p;
300#endif
bellard54936002003-05-13 00:25:15 +0000301 }
302 return p + (index & (L2_SIZE - 1));
303}
304
aurel3200f82b82008-04-27 21:12:55 +0000305static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000306{
bellard54936002003-05-13 00:25:15 +0000307 PageDesc *p;
308
bellard54936002003-05-13 00:25:15 +0000309 p = l1_map[index >> L2_BITS];
310 if (!p)
311 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000312 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000313}
314
bellard108c49b2005-07-24 12:55:09 +0000315static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000316{
bellard108c49b2005-07-24 12:55:09 +0000317 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000318 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000319
bellard108c49b2005-07-24 12:55:09 +0000320 p = (void **)l1_phys_map;
321#if TARGET_PHYS_ADDR_SPACE_BITS > 32
322
323#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
324#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
325#endif
326 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000327 p = *lp;
328 if (!p) {
329 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000330 if (!alloc)
331 return NULL;
332 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
333 memset(p, 0, sizeof(void *) * L1_SIZE);
334 *lp = p;
335 }
336#endif
337 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000338 pd = *lp;
339 if (!pd) {
340 int i;
bellard108c49b2005-07-24 12:55:09 +0000341 /* allocate if not found */
342 if (!alloc)
343 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000344 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
345 *lp = pd;
346 for (i = 0; i < L2_SIZE; i++)
347 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000348 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000349 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000350}
351
bellard108c49b2005-07-24 12:55:09 +0000352static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000353{
bellard108c49b2005-07-24 12:55:09 +0000354 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000355}
356
bellard9fa3e852004-01-04 18:06:42 +0000357#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000358static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000359static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000360 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000361#define mmap_lock() do { } while(0)
362#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000363#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000364
bellard43694152008-05-29 09:35:57 +0000365#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
366
367#if defined(CONFIG_USER_ONLY)
368/* Currently it is not recommanded to allocate big chunks of data in
369 user mode. It will change when a dedicated libc will be used */
370#define USE_STATIC_CODE_GEN_BUFFER
371#endif
372
373#ifdef USE_STATIC_CODE_GEN_BUFFER
374static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
375#endif
376
bellard26a5f132008-05-28 12:30:31 +0000377void code_gen_alloc(unsigned long tb_size)
378{
bellard43694152008-05-29 09:35:57 +0000379#ifdef USE_STATIC_CODE_GEN_BUFFER
380 code_gen_buffer = static_code_gen_buffer;
381 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
382 map_exec(code_gen_buffer, code_gen_buffer_size);
383#else
bellard26a5f132008-05-28 12:30:31 +0000384 code_gen_buffer_size = tb_size;
385 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000386#if defined(CONFIG_USER_ONLY)
387 /* in user mode, phys_ram_size is not meaningful */
388 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
389#else
bellard26a5f132008-05-28 12:30:31 +0000390 /* XXX: needs ajustments */
391 code_gen_buffer_size = (int)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000392#endif
bellard26a5f132008-05-28 12:30:31 +0000393 }
394 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
395 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
396 /* The code gen buffer location may have constraints depending on
397 the host cpu and OS */
398#if defined(__linux__)
399 {
400 int flags;
401 flags = MAP_PRIVATE | MAP_ANONYMOUS;
402#if defined(__x86_64__)
403 flags |= MAP_32BIT;
404 /* Cannot map more than that */
405 if (code_gen_buffer_size > (800 * 1024 * 1024))
406 code_gen_buffer_size = (800 * 1024 * 1024);
407#endif
408 code_gen_buffer = mmap(NULL, code_gen_buffer_size,
409 PROT_WRITE | PROT_READ | PROT_EXEC,
410 flags, -1, 0);
411 if (code_gen_buffer == MAP_FAILED) {
412 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
413 exit(1);
414 }
415 }
416#else
417 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
418 if (!code_gen_buffer) {
419 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
420 exit(1);
421 }
422 map_exec(code_gen_buffer, code_gen_buffer_size);
423#endif
bellard43694152008-05-29 09:35:57 +0000424#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000425 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
426 code_gen_buffer_max_size = code_gen_buffer_size -
427 code_gen_max_block_size();
428 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
429 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
430}
431
432/* Must be called before using the QEMU cpus. 'tb_size' is the size
433 (in bytes) allocated to the translation buffer. Zero means default
434 size. */
435void cpu_exec_init_all(unsigned long tb_size)
436{
bellard26a5f132008-05-28 12:30:31 +0000437 cpu_gen_init();
438 code_gen_alloc(tb_size);
439 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000440 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000441#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000442 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000443#endif
bellard26a5f132008-05-28 12:30:31 +0000444}
445
bellard6a00d602005-11-21 23:25:50 +0000446void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000447{
bellard6a00d602005-11-21 23:25:50 +0000448 CPUState **penv;
449 int cpu_index;
450
bellard6a00d602005-11-21 23:25:50 +0000451 env->next_cpu = NULL;
452 penv = &first_cpu;
453 cpu_index = 0;
454 while (*penv != NULL) {
455 penv = (CPUState **)&(*penv)->next_cpu;
456 cpu_index++;
457 }
458 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000459 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000460 *penv = env;
pbrookb3c77242008-06-30 16:31:04 +0000461#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
462 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
463 cpu_save, cpu_load, env);
464#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000465}
466
bellard9fa3e852004-01-04 18:06:42 +0000467static inline void invalidate_page_bitmap(PageDesc *p)
468{
469 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000470 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000471 p->code_bitmap = NULL;
472 }
473 p->code_write_count = 0;
474}
475
bellardfd6ce8f2003-05-14 19:00:11 +0000476/* set to NULL all the 'first_tb' fields in all PageDescs */
477static void page_flush_tb(void)
478{
479 int i, j;
480 PageDesc *p;
481
482 for(i = 0; i < L1_SIZE; i++) {
483 p = l1_map[i];
484 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000485 for(j = 0; j < L2_SIZE; j++) {
486 p->first_tb = NULL;
487 invalidate_page_bitmap(p);
488 p++;
489 }
bellardfd6ce8f2003-05-14 19:00:11 +0000490 }
491 }
492}
493
494/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000495/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000496void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000497{
bellard6a00d602005-11-21 23:25:50 +0000498 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000499#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000500 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
501 (unsigned long)(code_gen_ptr - code_gen_buffer),
502 nb_tbs, nb_tbs > 0 ?
503 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000504#endif
bellard26a5f132008-05-28 12:30:31 +0000505 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000506 cpu_abort(env1, "Internal error: code buffer overflow\n");
507
bellardfd6ce8f2003-05-14 19:00:11 +0000508 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000509
bellard6a00d602005-11-21 23:25:50 +0000510 for(env = first_cpu; env != NULL; env = env->next_cpu) {
511 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
512 }
bellard9fa3e852004-01-04 18:06:42 +0000513
bellard8a8a6082004-10-03 13:36:49 +0000514 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000515 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000516
bellardfd6ce8f2003-05-14 19:00:11 +0000517 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000518 /* XXX: flush processor icache at this point if cache flush is
519 expensive */
bellarde3db7222005-01-26 22:00:47 +0000520 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000521}
522
523#ifdef DEBUG_TB_CHECK
524
j_mayerbc98a7e2007-04-04 07:55:12 +0000525static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000526{
527 TranslationBlock *tb;
528 int i;
529 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000530 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
531 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000532 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
533 address >= tb->pc + tb->size)) {
534 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000535 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000536 }
537 }
538 }
539}
540
541/* verify that all the pages have correct rights for code */
542static void tb_page_check(void)
543{
544 TranslationBlock *tb;
545 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000546
pbrook99773bd2006-04-16 15:14:59 +0000547 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
548 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000549 flags1 = page_get_flags(tb->pc);
550 flags2 = page_get_flags(tb->pc + tb->size - 1);
551 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
552 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000553 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000554 }
555 }
556 }
557}
558
bellardd4e81642003-05-25 16:46:15 +0000559void tb_jmp_check(TranslationBlock *tb)
560{
561 TranslationBlock *tb1;
562 unsigned int n1;
563
564 /* suppress any remaining jumps to this TB */
565 tb1 = tb->jmp_first;
566 for(;;) {
567 n1 = (long)tb1 & 3;
568 tb1 = (TranslationBlock *)((long)tb1 & ~3);
569 if (n1 == 2)
570 break;
571 tb1 = tb1->jmp_next[n1];
572 }
573 /* check end of list */
574 if (tb1 != tb) {
575 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
576 }
577}
578
bellardfd6ce8f2003-05-14 19:00:11 +0000579#endif
580
581/* invalidate one TB */
582static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
583 int next_offset)
584{
585 TranslationBlock *tb1;
586 for(;;) {
587 tb1 = *ptb;
588 if (tb1 == tb) {
589 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
590 break;
591 }
592 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
593 }
594}
595
bellard9fa3e852004-01-04 18:06:42 +0000596static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
597{
598 TranslationBlock *tb1;
599 unsigned int n1;
600
601 for(;;) {
602 tb1 = *ptb;
603 n1 = (long)tb1 & 3;
604 tb1 = (TranslationBlock *)((long)tb1 & ~3);
605 if (tb1 == tb) {
606 *ptb = tb1->page_next[n1];
607 break;
608 }
609 ptb = &tb1->page_next[n1];
610 }
611}
612
bellardd4e81642003-05-25 16:46:15 +0000613static inline void tb_jmp_remove(TranslationBlock *tb, int n)
614{
615 TranslationBlock *tb1, **ptb;
616 unsigned int n1;
617
618 ptb = &tb->jmp_next[n];
619 tb1 = *ptb;
620 if (tb1) {
621 /* find tb(n) in circular list */
622 for(;;) {
623 tb1 = *ptb;
624 n1 = (long)tb1 & 3;
625 tb1 = (TranslationBlock *)((long)tb1 & ~3);
626 if (n1 == n && tb1 == tb)
627 break;
628 if (n1 == 2) {
629 ptb = &tb1->jmp_first;
630 } else {
631 ptb = &tb1->jmp_next[n1];
632 }
633 }
634 /* now we can suppress tb(n) from the list */
635 *ptb = tb->jmp_next[n];
636
637 tb->jmp_next[n] = NULL;
638 }
639}
640
641/* reset the jump entry 'n' of a TB so that it is not chained to
642 another TB */
643static inline void tb_reset_jump(TranslationBlock *tb, int n)
644{
645 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
646}
647
pbrook2e70f6e2008-06-29 01:03:05 +0000648void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000649{
bellard6a00d602005-11-21 23:25:50 +0000650 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000651 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000652 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000653 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000654 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000655
bellard9fa3e852004-01-04 18:06:42 +0000656 /* remove the TB from the hash list */
657 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
658 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000659 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000660 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000661
bellard9fa3e852004-01-04 18:06:42 +0000662 /* remove the TB from the page list */
663 if (tb->page_addr[0] != page_addr) {
664 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
665 tb_page_remove(&p->first_tb, tb);
666 invalidate_page_bitmap(p);
667 }
668 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
669 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
670 tb_page_remove(&p->first_tb, tb);
671 invalidate_page_bitmap(p);
672 }
673
bellard8a40a182005-11-20 10:35:40 +0000674 tb_invalidated_flag = 1;
675
676 /* remove the TB from the hash list */
677 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000678 for(env = first_cpu; env != NULL; env = env->next_cpu) {
679 if (env->tb_jmp_cache[h] == tb)
680 env->tb_jmp_cache[h] = NULL;
681 }
bellard8a40a182005-11-20 10:35:40 +0000682
683 /* suppress this TB from the two jump lists */
684 tb_jmp_remove(tb, 0);
685 tb_jmp_remove(tb, 1);
686
687 /* suppress any remaining jumps to this TB */
688 tb1 = tb->jmp_first;
689 for(;;) {
690 n1 = (long)tb1 & 3;
691 if (n1 == 2)
692 break;
693 tb1 = (TranslationBlock *)((long)tb1 & ~3);
694 tb2 = tb1->jmp_next[n1];
695 tb_reset_jump(tb1, n1);
696 tb1->jmp_next[n1] = NULL;
697 tb1 = tb2;
698 }
699 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
700
bellarde3db7222005-01-26 22:00:47 +0000701 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000702}
703
704static inline void set_bits(uint8_t *tab, int start, int len)
705{
706 int end, mask, end1;
707
708 end = start + len;
709 tab += start >> 3;
710 mask = 0xff << (start & 7);
711 if ((start & ~7) == (end & ~7)) {
712 if (start < end) {
713 mask &= ~(0xff << (end & 7));
714 *tab |= mask;
715 }
716 } else {
717 *tab++ |= mask;
718 start = (start + 8) & ~7;
719 end1 = end & ~7;
720 while (start < end1) {
721 *tab++ = 0xff;
722 start += 8;
723 }
724 if (start < end) {
725 mask = ~(0xff << (end & 7));
726 *tab |= mask;
727 }
728 }
729}
730
731static void build_page_bitmap(PageDesc *p)
732{
733 int n, tb_start, tb_end;
734 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000735
pbrookb2a70812008-06-09 13:57:23 +0000736 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000737 if (!p->code_bitmap)
738 return;
bellard9fa3e852004-01-04 18:06:42 +0000739
740 tb = p->first_tb;
741 while (tb != NULL) {
742 n = (long)tb & 3;
743 tb = (TranslationBlock *)((long)tb & ~3);
744 /* NOTE: this is subtle as a TB may span two physical pages */
745 if (n == 0) {
746 /* NOTE: tb_end may be after the end of the page, but
747 it is not a problem */
748 tb_start = tb->pc & ~TARGET_PAGE_MASK;
749 tb_end = tb_start + tb->size;
750 if (tb_end > TARGET_PAGE_SIZE)
751 tb_end = TARGET_PAGE_SIZE;
752 } else {
753 tb_start = 0;
754 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
755 }
756 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
757 tb = tb->page_next[n];
758 }
759}
760
pbrook2e70f6e2008-06-29 01:03:05 +0000761TranslationBlock *tb_gen_code(CPUState *env,
762 target_ulong pc, target_ulong cs_base,
763 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000764{
765 TranslationBlock *tb;
766 uint8_t *tc_ptr;
767 target_ulong phys_pc, phys_page2, virt_page2;
768 int code_gen_size;
769
bellardc27004e2005-01-03 23:35:10 +0000770 phys_pc = get_phys_addr_code(env, pc);
771 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000772 if (!tb) {
773 /* flush must be done */
774 tb_flush(env);
775 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000776 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000777 /* Don't forget to invalidate previous TB info. */
778 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000779 }
780 tc_ptr = code_gen_ptr;
781 tb->tc_ptr = tc_ptr;
782 tb->cs_base = cs_base;
783 tb->flags = flags;
784 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000785 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000786 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 +0000787
bellardd720b932004-04-25 17:57:43 +0000788 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000789 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000790 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000791 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000792 phys_page2 = get_phys_addr_code(env, virt_page2);
793 }
794 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000795 return tb;
bellardd720b932004-04-25 17:57:43 +0000796}
ths3b46e622007-09-17 08:09:54 +0000797
bellard9fa3e852004-01-04 18:06:42 +0000798/* invalidate all TBs which intersect with the target physical page
799 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000800 the same physical page. 'is_cpu_write_access' should be true if called
801 from a real cpu write access: the virtual CPU will exit the current
802 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000803void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000804 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000805{
bellardd720b932004-04-25 17:57:43 +0000806 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000807 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000808 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000809 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000810 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000811 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000812
813 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000814 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000815 return;
ths5fafdf22007-09-16 21:08:06 +0000816 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000817 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
818 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000819 /* build code bitmap */
820 build_page_bitmap(p);
821 }
822
823 /* we remove all the TBs in the range [start, end[ */
824 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000825 current_tb_not_found = is_cpu_write_access;
826 current_tb_modified = 0;
827 current_tb = NULL; /* avoid warning */
828 current_pc = 0; /* avoid warning */
829 current_cs_base = 0; /* avoid warning */
830 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000831 tb = p->first_tb;
832 while (tb != NULL) {
833 n = (long)tb & 3;
834 tb = (TranslationBlock *)((long)tb & ~3);
835 tb_next = tb->page_next[n];
836 /* NOTE: this is subtle as a TB may span two physical pages */
837 if (n == 0) {
838 /* NOTE: tb_end may be after the end of the page, but
839 it is not a problem */
840 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
841 tb_end = tb_start + tb->size;
842 } else {
843 tb_start = tb->page_addr[1];
844 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
845 }
846 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000847#ifdef TARGET_HAS_PRECISE_SMC
848 if (current_tb_not_found) {
849 current_tb_not_found = 0;
850 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000851 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000852 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000853 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000854 }
855 }
856 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000857 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000858 /* If we are modifying the current TB, we must stop
859 its execution. We could be more precise by checking
860 that the modification is after the current PC, but it
861 would require a specialized function to partially
862 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000863
bellardd720b932004-04-25 17:57:43 +0000864 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000865 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000866 env->mem_io_pc, NULL);
bellardd720b932004-04-25 17:57:43 +0000867#if defined(TARGET_I386)
868 current_flags = env->hflags;
869 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
870 current_cs_base = (target_ulong)env->segs[R_CS].base;
871 current_pc = current_cs_base + env->eip;
872#else
873#error unsupported CPU
874#endif
875 }
876#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000877 /* we need to do that to handle the case where a signal
878 occurs while doing tb_phys_invalidate() */
879 saved_tb = NULL;
880 if (env) {
881 saved_tb = env->current_tb;
882 env->current_tb = NULL;
883 }
bellard9fa3e852004-01-04 18:06:42 +0000884 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000885 if (env) {
886 env->current_tb = saved_tb;
887 if (env->interrupt_request && env->current_tb)
888 cpu_interrupt(env, env->interrupt_request);
889 }
bellard9fa3e852004-01-04 18:06:42 +0000890 }
891 tb = tb_next;
892 }
893#if !defined(CONFIG_USER_ONLY)
894 /* if no code remaining, no need to continue to use slow writes */
895 if (!p->first_tb) {
896 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000897 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000898 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000899 }
900 }
901#endif
902#ifdef TARGET_HAS_PRECISE_SMC
903 if (current_tb_modified) {
904 /* we generate a block containing just the instruction
905 modifying the memory. It will ensure that it cannot modify
906 itself */
bellardea1c1802004-06-14 18:56:36 +0000907 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000908 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000909 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000910 }
911#endif
912}
913
914/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000915static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000916{
917 PageDesc *p;
918 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000919#if 0
bellarda4193c82004-06-03 14:01:43 +0000920 if (1) {
921 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000922 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
pbrook2e70f6e2008-06-29 01:03:05 +0000923 cpu_single_env->mem_io_vaddr, len,
ths5fafdf22007-09-16 21:08:06 +0000924 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000925 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
926 }
bellard59817cc2004-02-16 22:01:13 +0000927 }
928#endif
bellard9fa3e852004-01-04 18:06:42 +0000929 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000930 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000931 return;
932 if (p->code_bitmap) {
933 offset = start & ~TARGET_PAGE_MASK;
934 b = p->code_bitmap[offset >> 3] >> (offset & 7);
935 if (b & ((1 << len) - 1))
936 goto do_invalidate;
937 } else {
938 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000939 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000940 }
941}
942
bellard9fa3e852004-01-04 18:06:42 +0000943#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000944static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000945 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000946{
bellardd720b932004-04-25 17:57:43 +0000947 int n, current_flags, current_tb_modified;
948 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000949 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000950 TranslationBlock *tb, *current_tb;
951#ifdef TARGET_HAS_PRECISE_SMC
952 CPUState *env = cpu_single_env;
953#endif
bellard9fa3e852004-01-04 18:06:42 +0000954
955 addr &= TARGET_PAGE_MASK;
956 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000957 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000958 return;
959 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000960 current_tb_modified = 0;
961 current_tb = NULL;
962 current_pc = 0; /* avoid warning */
963 current_cs_base = 0; /* avoid warning */
964 current_flags = 0; /* avoid warning */
965#ifdef TARGET_HAS_PRECISE_SMC
966 if (tb && pc != 0) {
967 current_tb = tb_find_pc(pc);
968 }
969#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000970 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000971 n = (long)tb & 3;
972 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000973#ifdef TARGET_HAS_PRECISE_SMC
974 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000975 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000976 /* If we are modifying the current TB, we must stop
977 its execution. We could be more precise by checking
978 that the modification is after the current PC, but it
979 would require a specialized function to partially
980 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000981
bellardd720b932004-04-25 17:57:43 +0000982 current_tb_modified = 1;
983 cpu_restore_state(current_tb, env, pc, puc);
984#if defined(TARGET_I386)
985 current_flags = env->hflags;
986 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
987 current_cs_base = (target_ulong)env->segs[R_CS].base;
988 current_pc = current_cs_base + env->eip;
989#else
990#error unsupported CPU
991#endif
992 }
993#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000994 tb_phys_invalidate(tb, addr);
995 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000996 }
997 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000998#ifdef TARGET_HAS_PRECISE_SMC
999 if (current_tb_modified) {
1000 /* we generate a block containing just the instruction
1001 modifying the memory. It will ensure that it cannot modify
1002 itself */
bellardea1c1802004-06-14 18:56:36 +00001003 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001004 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001005 cpu_resume_from_signal(env, puc);
1006 }
1007#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001008}
bellard9fa3e852004-01-04 18:06:42 +00001009#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001010
1011/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001012static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001013 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001014{
1015 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001016 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001017
bellard9fa3e852004-01-04 18:06:42 +00001018 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001019 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001020 tb->page_next[n] = p->first_tb;
1021 last_first_tb = p->first_tb;
1022 p->first_tb = (TranslationBlock *)((long)tb | n);
1023 invalidate_page_bitmap(p);
1024
bellard107db442004-06-22 18:48:46 +00001025#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001026
bellard9fa3e852004-01-04 18:06:42 +00001027#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001028 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001029 target_ulong addr;
1030 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001031 int prot;
1032
bellardfd6ce8f2003-05-14 19:00:11 +00001033 /* force the host page as non writable (writes will have a
1034 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001035 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001036 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001037 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1038 addr += TARGET_PAGE_SIZE) {
1039
1040 p2 = page_find (addr >> TARGET_PAGE_BITS);
1041 if (!p2)
1042 continue;
1043 prot |= p2->flags;
1044 p2->flags &= ~PAGE_WRITE;
1045 page_get_flags(addr);
1046 }
ths5fafdf22007-09-16 21:08:06 +00001047 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001048 (prot & PAGE_BITS) & ~PAGE_WRITE);
1049#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001050 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001051 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001052#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001053 }
bellard9fa3e852004-01-04 18:06:42 +00001054#else
1055 /* if some code is already present, then the pages are already
1056 protected. So we handle the case where only the first TB is
1057 allocated in a physical page */
1058 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001059 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001060 }
1061#endif
bellardd720b932004-04-25 17:57:43 +00001062
1063#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001064}
1065
1066/* Allocate a new translation block. Flush the translation buffer if
1067 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001068TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001069{
1070 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001071
bellard26a5f132008-05-28 12:30:31 +00001072 if (nb_tbs >= code_gen_max_blocks ||
1073 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001074 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001075 tb = &tbs[nb_tbs++];
1076 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001077 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001078 return tb;
1079}
1080
pbrook2e70f6e2008-06-29 01:03:05 +00001081void tb_free(TranslationBlock *tb)
1082{
thsbf20dc02008-06-30 17:22:19 +00001083 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001084 Ignore the hard cases and just back up if this TB happens to
1085 be the last one generated. */
1086 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1087 code_gen_ptr = tb->tc_ptr;
1088 nb_tbs--;
1089 }
1090}
1091
bellard9fa3e852004-01-04 18:06:42 +00001092/* add a new TB and link it to the physical page tables. phys_page2 is
1093 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001094void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001095 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001096{
bellard9fa3e852004-01-04 18:06:42 +00001097 unsigned int h;
1098 TranslationBlock **ptb;
1099
pbrookc8a706f2008-06-02 16:16:42 +00001100 /* Grab the mmap lock to stop another thread invalidating this TB
1101 before we are done. */
1102 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001103 /* add in the physical hash table */
1104 h = tb_phys_hash_func(phys_pc);
1105 ptb = &tb_phys_hash[h];
1106 tb->phys_hash_next = *ptb;
1107 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001108
1109 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001110 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1111 if (phys_page2 != -1)
1112 tb_alloc_page(tb, 1, phys_page2);
1113 else
1114 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001115
bellardd4e81642003-05-25 16:46:15 +00001116 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1117 tb->jmp_next[0] = NULL;
1118 tb->jmp_next[1] = NULL;
1119
1120 /* init original jump addresses */
1121 if (tb->tb_next_offset[0] != 0xffff)
1122 tb_reset_jump(tb, 0);
1123 if (tb->tb_next_offset[1] != 0xffff)
1124 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001125
1126#ifdef DEBUG_TB_CHECK
1127 tb_page_check();
1128#endif
pbrookc8a706f2008-06-02 16:16:42 +00001129 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001130}
1131
bellarda513fe12003-05-27 23:29:48 +00001132/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1133 tb[1].tc_ptr. Return NULL if not found */
1134TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1135{
1136 int m_min, m_max, m;
1137 unsigned long v;
1138 TranslationBlock *tb;
1139
1140 if (nb_tbs <= 0)
1141 return NULL;
1142 if (tc_ptr < (unsigned long)code_gen_buffer ||
1143 tc_ptr >= (unsigned long)code_gen_ptr)
1144 return NULL;
1145 /* binary search (cf Knuth) */
1146 m_min = 0;
1147 m_max = nb_tbs - 1;
1148 while (m_min <= m_max) {
1149 m = (m_min + m_max) >> 1;
1150 tb = &tbs[m];
1151 v = (unsigned long)tb->tc_ptr;
1152 if (v == tc_ptr)
1153 return tb;
1154 else if (tc_ptr < v) {
1155 m_max = m - 1;
1156 } else {
1157 m_min = m + 1;
1158 }
ths5fafdf22007-09-16 21:08:06 +00001159 }
bellarda513fe12003-05-27 23:29:48 +00001160 return &tbs[m_max];
1161}
bellard75012672003-06-21 13:11:07 +00001162
bellardea041c02003-06-25 16:16:50 +00001163static void tb_reset_jump_recursive(TranslationBlock *tb);
1164
1165static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1166{
1167 TranslationBlock *tb1, *tb_next, **ptb;
1168 unsigned int n1;
1169
1170 tb1 = tb->jmp_next[n];
1171 if (tb1 != NULL) {
1172 /* find head of list */
1173 for(;;) {
1174 n1 = (long)tb1 & 3;
1175 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1176 if (n1 == 2)
1177 break;
1178 tb1 = tb1->jmp_next[n1];
1179 }
1180 /* we are now sure now that tb jumps to tb1 */
1181 tb_next = tb1;
1182
1183 /* remove tb from the jmp_first list */
1184 ptb = &tb_next->jmp_first;
1185 for(;;) {
1186 tb1 = *ptb;
1187 n1 = (long)tb1 & 3;
1188 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1189 if (n1 == n && tb1 == tb)
1190 break;
1191 ptb = &tb1->jmp_next[n1];
1192 }
1193 *ptb = tb->jmp_next[n];
1194 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001195
bellardea041c02003-06-25 16:16:50 +00001196 /* suppress the jump to next tb in generated code */
1197 tb_reset_jump(tb, n);
1198
bellard01243112004-01-04 15:48:17 +00001199 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001200 tb_reset_jump_recursive(tb_next);
1201 }
1202}
1203
1204static void tb_reset_jump_recursive(TranslationBlock *tb)
1205{
1206 tb_reset_jump_recursive2(tb, 0);
1207 tb_reset_jump_recursive2(tb, 1);
1208}
1209
bellard1fddef42005-04-17 19:16:13 +00001210#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001211static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1212{
j_mayer9b3c35e2007-04-07 11:21:28 +00001213 target_phys_addr_t addr;
1214 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001215 ram_addr_t ram_addr;
1216 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001217
pbrookc2f07f82006-04-08 17:14:56 +00001218 addr = cpu_get_phys_page_debug(env, pc);
1219 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1220 if (!p) {
1221 pd = IO_MEM_UNASSIGNED;
1222 } else {
1223 pd = p->phys_offset;
1224 }
1225 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001226 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001227}
bellardc27004e2005-01-03 23:35:10 +00001228#endif
bellardd720b932004-04-25 17:57:43 +00001229
pbrook6658ffb2007-03-16 23:58:11 +00001230/* Add a watchpoint. */
pbrook0f459d12008-06-09 00:20:13 +00001231int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
pbrook6658ffb2007-03-16 23:58:11 +00001232{
1233 int i;
1234
1235 for (i = 0; i < env->nb_watchpoints; i++) {
1236 if (addr == env->watchpoint[i].vaddr)
1237 return 0;
1238 }
1239 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1240 return -1;
1241
1242 i = env->nb_watchpoints++;
1243 env->watchpoint[i].vaddr = addr;
pbrook0f459d12008-06-09 00:20:13 +00001244 env->watchpoint[i].type = type;
pbrook6658ffb2007-03-16 23:58:11 +00001245 tlb_flush_page(env, addr);
1246 /* FIXME: This flush is needed because of the hack to make memory ops
1247 terminate the TB. It can be removed once the proper IO trap and
1248 re-execute bits are in. */
1249 tb_flush(env);
1250 return i;
1251}
1252
1253/* Remove a watchpoint. */
1254int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1255{
1256 int i;
1257
1258 for (i = 0; i < env->nb_watchpoints; i++) {
1259 if (addr == env->watchpoint[i].vaddr) {
1260 env->nb_watchpoints--;
1261 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1262 tlb_flush_page(env, addr);
1263 return 0;
1264 }
1265 }
1266 return -1;
1267}
1268
edgar_igl7d03f822008-05-17 18:58:29 +00001269/* Remove all watchpoints. */
1270void cpu_watchpoint_remove_all(CPUState *env) {
1271 int i;
1272
1273 for (i = 0; i < env->nb_watchpoints; i++) {
1274 tlb_flush_page(env, env->watchpoint[i].vaddr);
1275 }
1276 env->nb_watchpoints = 0;
1277}
1278
bellardc33a3462003-07-29 20:50:33 +00001279/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1280 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001281int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001282{
bellard1fddef42005-04-17 19:16:13 +00001283#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001284 int i;
ths3b46e622007-09-17 08:09:54 +00001285
bellard4c3a88a2003-07-26 12:06:08 +00001286 for(i = 0; i < env->nb_breakpoints; i++) {
1287 if (env->breakpoints[i] == pc)
1288 return 0;
1289 }
1290
1291 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1292 return -1;
1293 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001294
bellardd720b932004-04-25 17:57:43 +00001295 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001296 return 0;
1297#else
1298 return -1;
1299#endif
1300}
1301
edgar_igl7d03f822008-05-17 18:58:29 +00001302/* remove all breakpoints */
1303void cpu_breakpoint_remove_all(CPUState *env) {
1304#if defined(TARGET_HAS_ICE)
1305 int i;
1306 for(i = 0; i < env->nb_breakpoints; i++) {
1307 breakpoint_invalidate(env, env->breakpoints[i]);
1308 }
1309 env->nb_breakpoints = 0;
1310#endif
1311}
1312
bellard4c3a88a2003-07-26 12:06:08 +00001313/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001314int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001315{
bellard1fddef42005-04-17 19:16:13 +00001316#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001317 int i;
1318 for(i = 0; i < env->nb_breakpoints; i++) {
1319 if (env->breakpoints[i] == pc)
1320 goto found;
1321 }
1322 return -1;
1323 found:
bellard4c3a88a2003-07-26 12:06:08 +00001324 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001325 if (i < env->nb_breakpoints)
1326 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001327
1328 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001329 return 0;
1330#else
1331 return -1;
1332#endif
1333}
1334
bellardc33a3462003-07-29 20:50:33 +00001335/* enable or disable single step mode. EXCP_DEBUG is returned by the
1336 CPU loop after each instruction */
1337void cpu_single_step(CPUState *env, int enabled)
1338{
bellard1fddef42005-04-17 19:16:13 +00001339#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001340 if (env->singlestep_enabled != enabled) {
1341 env->singlestep_enabled = enabled;
1342 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001343 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001344 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001345 }
1346#endif
1347}
1348
bellard34865132003-10-05 14:28:56 +00001349/* enable or disable low levels log */
1350void cpu_set_log(int log_flags)
1351{
1352 loglevel = log_flags;
1353 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001354 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001355 if (!logfile) {
1356 perror(logfilename);
1357 _exit(1);
1358 }
bellard9fa3e852004-01-04 18:06:42 +00001359#if !defined(CONFIG_SOFTMMU)
1360 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1361 {
1362 static uint8_t logfile_buf[4096];
1363 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1364 }
1365#else
bellard34865132003-10-05 14:28:56 +00001366 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001367#endif
pbrooke735b912007-06-30 13:53:24 +00001368 log_append = 1;
1369 }
1370 if (!loglevel && logfile) {
1371 fclose(logfile);
1372 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001373 }
1374}
1375
1376void cpu_set_log_filename(const char *filename)
1377{
1378 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001379 if (logfile) {
1380 fclose(logfile);
1381 logfile = NULL;
1382 }
1383 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001384}
bellardc33a3462003-07-29 20:50:33 +00001385
bellard01243112004-01-04 15:48:17 +00001386/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001387void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001388{
pbrookd5975362008-06-07 20:50:51 +00001389#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001390 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001391 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001392#endif
pbrook2e70f6e2008-06-29 01:03:05 +00001393 int old_mask;
bellard59817cc2004-02-16 22:01:13 +00001394
pbrook2e70f6e2008-06-29 01:03:05 +00001395 old_mask = env->interrupt_request;
pbrookd5975362008-06-07 20:50:51 +00001396 /* FIXME: This is probably not threadsafe. A different thread could
thsbf20dc02008-06-30 17:22:19 +00001397 be in the middle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001398 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001399#if defined(USE_NPTL)
1400 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1401 problem and hope the cpu will stop of its own accord. For userspace
1402 emulation this often isn't actually as bad as it sounds. Often
1403 signals are used primarily to interrupt blocking syscalls. */
1404#else
pbrook2e70f6e2008-06-29 01:03:05 +00001405 if (use_icount) {
1406 env->icount_decr.u16.high = 0x8000;
1407#ifndef CONFIG_USER_ONLY
1408 /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
1409 an async event happened and we need to process it. */
1410 if (!can_do_io(env)
1411 && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
1412 cpu_abort(env, "Raised interrupt while not in I/O function");
1413 }
1414#endif
1415 } else {
1416 tb = env->current_tb;
1417 /* if the cpu is currently executing code, we must unlink it and
1418 all the potentially executing TB */
1419 if (tb && !testandset(&interrupt_lock)) {
1420 env->current_tb = NULL;
1421 tb_reset_jump_recursive(tb);
1422 resetlock(&interrupt_lock);
1423 }
bellardea041c02003-06-25 16:16:50 +00001424 }
pbrookd5975362008-06-07 20:50:51 +00001425#endif
bellardea041c02003-06-25 16:16:50 +00001426}
1427
bellardb54ad042004-05-20 13:42:52 +00001428void cpu_reset_interrupt(CPUState *env, int mask)
1429{
1430 env->interrupt_request &= ~mask;
1431}
1432
bellardf193c792004-03-21 17:06:25 +00001433CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001434 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001435 "show generated host assembly code for each compiled TB" },
1436 { CPU_LOG_TB_IN_ASM, "in_asm",
1437 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001438 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001439 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001440 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001441 "show micro ops "
1442#ifdef TARGET_I386
1443 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001444#endif
blueswir1e01a1152008-03-14 17:37:11 +00001445 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001446 { CPU_LOG_INT, "int",
1447 "show interrupts/exceptions in short format" },
1448 { CPU_LOG_EXEC, "exec",
1449 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001450 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001451 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001452#ifdef TARGET_I386
1453 { CPU_LOG_PCALL, "pcall",
1454 "show protected mode far calls/returns/exceptions" },
1455#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001456#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001457 { CPU_LOG_IOPORT, "ioport",
1458 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001459#endif
bellardf193c792004-03-21 17:06:25 +00001460 { 0, NULL, NULL },
1461};
1462
1463static int cmp1(const char *s1, int n, const char *s2)
1464{
1465 if (strlen(s2) != n)
1466 return 0;
1467 return memcmp(s1, s2, n) == 0;
1468}
ths3b46e622007-09-17 08:09:54 +00001469
bellardf193c792004-03-21 17:06:25 +00001470/* takes a comma separated list of log masks. Return 0 if error. */
1471int cpu_str_to_log_mask(const char *str)
1472{
1473 CPULogItem *item;
1474 int mask;
1475 const char *p, *p1;
1476
1477 p = str;
1478 mask = 0;
1479 for(;;) {
1480 p1 = strchr(p, ',');
1481 if (!p1)
1482 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001483 if(cmp1(p,p1-p,"all")) {
1484 for(item = cpu_log_items; item->mask != 0; item++) {
1485 mask |= item->mask;
1486 }
1487 } else {
bellardf193c792004-03-21 17:06:25 +00001488 for(item = cpu_log_items; item->mask != 0; item++) {
1489 if (cmp1(p, p1 - p, item->name))
1490 goto found;
1491 }
1492 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001493 }
bellardf193c792004-03-21 17:06:25 +00001494 found:
1495 mask |= item->mask;
1496 if (*p1 != ',')
1497 break;
1498 p = p1 + 1;
1499 }
1500 return mask;
1501}
bellardea041c02003-06-25 16:16:50 +00001502
bellard75012672003-06-21 13:11:07 +00001503void cpu_abort(CPUState *env, const char *fmt, ...)
1504{
1505 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001506 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001507
1508 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001509 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001510 fprintf(stderr, "qemu: fatal: ");
1511 vfprintf(stderr, fmt, ap);
1512 fprintf(stderr, "\n");
1513#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001514 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1515#else
1516 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001517#endif
balrog924edca2007-06-10 14:07:13 +00001518 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001519 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001520 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001521 fprintf(logfile, "\n");
1522#ifdef TARGET_I386
1523 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1524#else
1525 cpu_dump_state(env, logfile, fprintf, 0);
1526#endif
balrog924edca2007-06-10 14:07:13 +00001527 fflush(logfile);
1528 fclose(logfile);
1529 }
pbrook493ae1f2007-11-23 16:53:59 +00001530 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001531 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001532 abort();
1533}
1534
thsc5be9f02007-02-28 20:20:53 +00001535CPUState *cpu_copy(CPUState *env)
1536{
ths01ba9812007-12-09 02:22:57 +00001537 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001538 /* preserve chaining and index */
1539 CPUState *next_cpu = new_env->next_cpu;
1540 int cpu_index = new_env->cpu_index;
1541 memcpy(new_env, env, sizeof(CPUState));
1542 new_env->next_cpu = next_cpu;
1543 new_env->cpu_index = cpu_index;
1544 return new_env;
1545}
1546
bellard01243112004-01-04 15:48:17 +00001547#if !defined(CONFIG_USER_ONLY)
1548
edgar_igl5c751e92008-05-06 08:44:21 +00001549static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1550{
1551 unsigned int i;
1552
1553 /* Discard jump cache entries for any tb which might potentially
1554 overlap the flushed page. */
1555 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1556 memset (&env->tb_jmp_cache[i], 0,
1557 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1558
1559 i = tb_jmp_cache_hash_page(addr);
1560 memset (&env->tb_jmp_cache[i], 0,
1561 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1562}
1563
bellardee8b7022004-02-03 23:35:10 +00001564/* NOTE: if flush_global is true, also flush global entries (not
1565 implemented yet) */
1566void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001567{
bellard33417e72003-08-10 21:47:01 +00001568 int i;
bellard01243112004-01-04 15:48:17 +00001569
bellard9fa3e852004-01-04 18:06:42 +00001570#if defined(DEBUG_TLB)
1571 printf("tlb_flush:\n");
1572#endif
bellard01243112004-01-04 15:48:17 +00001573 /* must reset current TB so that interrupts cannot modify the
1574 links while we are modifying them */
1575 env->current_tb = NULL;
1576
bellard33417e72003-08-10 21:47:01 +00001577 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001578 env->tlb_table[0][i].addr_read = -1;
1579 env->tlb_table[0][i].addr_write = -1;
1580 env->tlb_table[0][i].addr_code = -1;
1581 env->tlb_table[1][i].addr_read = -1;
1582 env->tlb_table[1][i].addr_write = -1;
1583 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001584#if (NB_MMU_MODES >= 3)
1585 env->tlb_table[2][i].addr_read = -1;
1586 env->tlb_table[2][i].addr_write = -1;
1587 env->tlb_table[2][i].addr_code = -1;
1588#if (NB_MMU_MODES == 4)
1589 env->tlb_table[3][i].addr_read = -1;
1590 env->tlb_table[3][i].addr_write = -1;
1591 env->tlb_table[3][i].addr_code = -1;
1592#endif
1593#endif
bellard33417e72003-08-10 21:47:01 +00001594 }
bellard9fa3e852004-01-04 18:06:42 +00001595
bellard8a40a182005-11-20 10:35:40 +00001596 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001597
bellard0a962c02005-02-10 22:00:27 +00001598#ifdef USE_KQEMU
1599 if (env->kqemu_enabled) {
1600 kqemu_flush(env, flush_global);
1601 }
1602#endif
bellarde3db7222005-01-26 22:00:47 +00001603 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001604}
1605
bellard274da6b2004-05-20 21:56:27 +00001606static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001607{
ths5fafdf22007-09-16 21:08:06 +00001608 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001609 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001610 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001611 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001612 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001613 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1614 tlb_entry->addr_read = -1;
1615 tlb_entry->addr_write = -1;
1616 tlb_entry->addr_code = -1;
1617 }
bellard61382a52003-10-27 21:22:23 +00001618}
1619
bellard2e126692004-04-25 21:28:44 +00001620void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001621{
bellard8a40a182005-11-20 10:35:40 +00001622 int i;
bellard01243112004-01-04 15:48:17 +00001623
bellard9fa3e852004-01-04 18:06:42 +00001624#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001625 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001626#endif
bellard01243112004-01-04 15:48:17 +00001627 /* must reset current TB so that interrupts cannot modify the
1628 links while we are modifying them */
1629 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001630
bellard61382a52003-10-27 21:22:23 +00001631 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001632 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001633 tlb_flush_entry(&env->tlb_table[0][i], addr);
1634 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001635#if (NB_MMU_MODES >= 3)
1636 tlb_flush_entry(&env->tlb_table[2][i], addr);
1637#if (NB_MMU_MODES == 4)
1638 tlb_flush_entry(&env->tlb_table[3][i], addr);
1639#endif
1640#endif
bellard01243112004-01-04 15:48:17 +00001641
edgar_igl5c751e92008-05-06 08:44:21 +00001642 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001643
bellard0a962c02005-02-10 22:00:27 +00001644#ifdef USE_KQEMU
1645 if (env->kqemu_enabled) {
1646 kqemu_flush_page(env, addr);
1647 }
1648#endif
bellard9fa3e852004-01-04 18:06:42 +00001649}
1650
bellard9fa3e852004-01-04 18:06:42 +00001651/* update the TLBs so that writes to code in the virtual page 'addr'
1652 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001653static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001654{
ths5fafdf22007-09-16 21:08:06 +00001655 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001656 ram_addr + TARGET_PAGE_SIZE,
1657 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001658}
1659
bellard9fa3e852004-01-04 18:06:42 +00001660/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001661 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001662static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001663 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001664{
bellard3a7d9292005-08-21 09:26:42 +00001665 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001666}
1667
ths5fafdf22007-09-16 21:08:06 +00001668static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001669 unsigned long start, unsigned long length)
1670{
1671 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001672 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1673 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001674 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001675 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001676 }
1677 }
1678}
1679
bellard3a7d9292005-08-21 09:26:42 +00001680void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001681 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001682{
1683 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001684 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001685 int i, mask, len;
1686 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001687
1688 start &= TARGET_PAGE_MASK;
1689 end = TARGET_PAGE_ALIGN(end);
1690
1691 length = end - start;
1692 if (length == 0)
1693 return;
bellard0a962c02005-02-10 22:00:27 +00001694 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001695#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001696 /* XXX: should not depend on cpu context */
1697 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001698 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001699 ram_addr_t addr;
1700 addr = start;
1701 for(i = 0; i < len; i++) {
1702 kqemu_set_notdirty(env, addr);
1703 addr += TARGET_PAGE_SIZE;
1704 }
bellard3a7d9292005-08-21 09:26:42 +00001705 }
1706#endif
bellardf23db162005-08-21 19:12:28 +00001707 mask = ~dirty_flags;
1708 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1709 for(i = 0; i < len; i++)
1710 p[i] &= mask;
1711
bellard1ccde1c2004-02-06 19:46:14 +00001712 /* we modify the TLB cache so that the dirty bit will be set again
1713 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001714 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001715 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1716 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001717 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001718 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001719 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001720#if (NB_MMU_MODES >= 3)
1721 for(i = 0; i < CPU_TLB_SIZE; i++)
1722 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1723#if (NB_MMU_MODES == 4)
1724 for(i = 0; i < CPU_TLB_SIZE; i++)
1725 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1726#endif
1727#endif
bellard6a00d602005-11-21 23:25:50 +00001728 }
bellard1ccde1c2004-02-06 19:46:14 +00001729}
1730
bellard3a7d9292005-08-21 09:26:42 +00001731static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1732{
1733 ram_addr_t ram_addr;
1734
bellard84b7b8e2005-11-28 21:19:04 +00001735 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001736 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001737 tlb_entry->addend - (unsigned long)phys_ram_base;
1738 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001739 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001740 }
1741 }
1742}
1743
1744/* update the TLB according to the current state of the dirty bits */
1745void cpu_tlb_update_dirty(CPUState *env)
1746{
1747 int i;
1748 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001749 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001750 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001751 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001752#if (NB_MMU_MODES >= 3)
1753 for(i = 0; i < CPU_TLB_SIZE; i++)
1754 tlb_update_dirty(&env->tlb_table[2][i]);
1755#if (NB_MMU_MODES == 4)
1756 for(i = 0; i < CPU_TLB_SIZE; i++)
1757 tlb_update_dirty(&env->tlb_table[3][i]);
1758#endif
1759#endif
bellard3a7d9292005-08-21 09:26:42 +00001760}
1761
pbrook0f459d12008-06-09 00:20:13 +00001762static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001763{
pbrook0f459d12008-06-09 00:20:13 +00001764 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1765 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001766}
1767
pbrook0f459d12008-06-09 00:20:13 +00001768/* update the TLB corresponding to virtual page vaddr
1769 so that it is no longer dirty */
1770static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001771{
bellard1ccde1c2004-02-06 19:46:14 +00001772 int i;
1773
pbrook0f459d12008-06-09 00:20:13 +00001774 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001775 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001776 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1777 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001778#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001779 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001780#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001781 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001782#endif
1783#endif
bellard9fa3e852004-01-04 18:06:42 +00001784}
1785
bellard59817cc2004-02-16 22:01:13 +00001786/* add a new TLB entry. At most one entry for a given virtual address
1787 is permitted. Return 0 if OK or 2 if the page could not be mapped
1788 (can only happen in non SOFTMMU mode for I/O pages or pages
1789 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001790int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1791 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001792 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001793{
bellard92e873b2004-05-21 14:52:29 +00001794 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001795 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001796 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001797 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001798 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001799 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001800 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001801 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001802 int i;
pbrook0f459d12008-06-09 00:20:13 +00001803 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001804
bellard92e873b2004-05-21 14:52:29 +00001805 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001806 if (!p) {
1807 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001808 } else {
1809 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001810 }
1811#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001812 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1813 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001814#endif
1815
1816 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001817 address = vaddr;
1818 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1819 /* IO memory case (romd handled later) */
1820 address |= TLB_MMIO;
1821 }
1822 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1823 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1824 /* Normal RAM. */
1825 iotlb = pd & TARGET_PAGE_MASK;
1826 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1827 iotlb |= IO_MEM_NOTDIRTY;
1828 else
1829 iotlb |= IO_MEM_ROM;
1830 } else {
1831 /* IO handlers are currently passed a phsical address.
1832 It would be nice to pass an offset from the base address
1833 of that region. This would avoid having to special case RAM,
1834 and avoid full address decoding in every device.
1835 We can't use the high bits of pd for this because
1836 IO_MEM_ROMD uses these as a ram address. */
1837 iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
1838 }
pbrook6658ffb2007-03-16 23:58:11 +00001839
pbrook0f459d12008-06-09 00:20:13 +00001840 code_address = address;
1841 /* Make accesses to pages with watchpoints go via the
1842 watchpoint trap routines. */
1843 for (i = 0; i < env->nb_watchpoints; i++) {
1844 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1845 iotlb = io_mem_watch + paddr;
1846 /* TODO: The memory case can be optimized by not trapping
1847 reads of pages with a write breakpoint. */
1848 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00001849 }
pbrook0f459d12008-06-09 00:20:13 +00001850 }
balrogd79acba2007-06-26 20:01:13 +00001851
pbrook0f459d12008-06-09 00:20:13 +00001852 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1853 env->iotlb[mmu_idx][index] = iotlb - vaddr;
1854 te = &env->tlb_table[mmu_idx][index];
1855 te->addend = addend - vaddr;
1856 if (prot & PAGE_READ) {
1857 te->addr_read = address;
1858 } else {
1859 te->addr_read = -1;
1860 }
edgar_igl5c751e92008-05-06 08:44:21 +00001861
pbrook0f459d12008-06-09 00:20:13 +00001862 if (prot & PAGE_EXEC) {
1863 te->addr_code = code_address;
1864 } else {
1865 te->addr_code = -1;
1866 }
1867 if (prot & PAGE_WRITE) {
1868 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1869 (pd & IO_MEM_ROMD)) {
1870 /* Write access calls the I/O callback. */
1871 te->addr_write = address | TLB_MMIO;
1872 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1873 !cpu_physical_memory_is_dirty(pd)) {
1874 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00001875 } else {
pbrook0f459d12008-06-09 00:20:13 +00001876 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001877 }
pbrook0f459d12008-06-09 00:20:13 +00001878 } else {
1879 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001880 }
bellard9fa3e852004-01-04 18:06:42 +00001881 return ret;
1882}
1883
bellard01243112004-01-04 15:48:17 +00001884#else
1885
bellardee8b7022004-02-03 23:35:10 +00001886void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001887{
1888}
1889
bellard2e126692004-04-25 21:28:44 +00001890void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001891{
1892}
1893
ths5fafdf22007-09-16 21:08:06 +00001894int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1895 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001896 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001897{
bellard9fa3e852004-01-04 18:06:42 +00001898 return 0;
1899}
bellard33417e72003-08-10 21:47:01 +00001900
bellard9fa3e852004-01-04 18:06:42 +00001901/* dump memory mappings */
1902void page_dump(FILE *f)
1903{
1904 unsigned long start, end;
1905 int i, j, prot, prot1;
1906 PageDesc *p;
1907
1908 fprintf(f, "%-8s %-8s %-8s %s\n",
1909 "start", "end", "size", "prot");
1910 start = -1;
1911 end = -1;
1912 prot = 0;
1913 for(i = 0; i <= L1_SIZE; i++) {
1914 if (i < L1_SIZE)
1915 p = l1_map[i];
1916 else
1917 p = NULL;
1918 for(j = 0;j < L2_SIZE; j++) {
1919 if (!p)
1920 prot1 = 0;
1921 else
1922 prot1 = p[j].flags;
1923 if (prot1 != prot) {
1924 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1925 if (start != -1) {
1926 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001927 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001928 prot & PAGE_READ ? 'r' : '-',
1929 prot & PAGE_WRITE ? 'w' : '-',
1930 prot & PAGE_EXEC ? 'x' : '-');
1931 }
1932 if (prot1 != 0)
1933 start = end;
1934 else
1935 start = -1;
1936 prot = prot1;
1937 }
1938 if (!p)
1939 break;
1940 }
bellard33417e72003-08-10 21:47:01 +00001941 }
bellard33417e72003-08-10 21:47:01 +00001942}
1943
pbrook53a59602006-03-25 19:31:22 +00001944int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001945{
bellard9fa3e852004-01-04 18:06:42 +00001946 PageDesc *p;
1947
1948 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001949 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001950 return 0;
1951 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001952}
1953
bellard9fa3e852004-01-04 18:06:42 +00001954/* modify the flags of a page and invalidate the code if
1955 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1956 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001957void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001958{
1959 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001960 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001961
pbrookc8a706f2008-06-02 16:16:42 +00001962 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00001963 start = start & TARGET_PAGE_MASK;
1964 end = TARGET_PAGE_ALIGN(end);
1965 if (flags & PAGE_WRITE)
1966 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00001967 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1968 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00001969 /* We may be called for host regions that are outside guest
1970 address space. */
1971 if (!p)
1972 return;
bellard9fa3e852004-01-04 18:06:42 +00001973 /* if the write protection is set, then we invalidate the code
1974 inside */
ths5fafdf22007-09-16 21:08:06 +00001975 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001976 (flags & PAGE_WRITE) &&
1977 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001978 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001979 }
1980 p->flags = flags;
1981 }
bellard9fa3e852004-01-04 18:06:42 +00001982}
1983
ths3d97b402007-11-02 19:02:07 +00001984int page_check_range(target_ulong start, target_ulong len, int flags)
1985{
1986 PageDesc *p;
1987 target_ulong end;
1988 target_ulong addr;
1989
1990 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1991 start = start & TARGET_PAGE_MASK;
1992
1993 if( end < start )
1994 /* we've wrapped around */
1995 return -1;
1996 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1997 p = page_find(addr >> TARGET_PAGE_BITS);
1998 if( !p )
1999 return -1;
2000 if( !(p->flags & PAGE_VALID) )
2001 return -1;
2002
bellarddae32702007-11-14 10:51:00 +00002003 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002004 return -1;
bellarddae32702007-11-14 10:51:00 +00002005 if (flags & PAGE_WRITE) {
2006 if (!(p->flags & PAGE_WRITE_ORG))
2007 return -1;
2008 /* unprotect the page if it was put read-only because it
2009 contains translated code */
2010 if (!(p->flags & PAGE_WRITE)) {
2011 if (!page_unprotect(addr, 0, NULL))
2012 return -1;
2013 }
2014 return 0;
2015 }
ths3d97b402007-11-02 19:02:07 +00002016 }
2017 return 0;
2018}
2019
bellard9fa3e852004-01-04 18:06:42 +00002020/* called from signal handler: invalidate the code and unprotect the
2021 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002022int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002023{
2024 unsigned int page_index, prot, pindex;
2025 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002026 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002027
pbrookc8a706f2008-06-02 16:16:42 +00002028 /* Technically this isn't safe inside a signal handler. However we
2029 know this only ever happens in a synchronous SEGV handler, so in
2030 practice it seems to be ok. */
2031 mmap_lock();
2032
bellard83fb7ad2004-07-05 21:25:26 +00002033 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002034 page_index = host_start >> TARGET_PAGE_BITS;
2035 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002036 if (!p1) {
2037 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002038 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002039 }
bellard83fb7ad2004-07-05 21:25:26 +00002040 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002041 p = p1;
2042 prot = 0;
2043 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2044 prot |= p->flags;
2045 p++;
2046 }
2047 /* if the page was really writable, then we change its
2048 protection back to writable */
2049 if (prot & PAGE_WRITE_ORG) {
2050 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2051 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002052 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002053 (prot & PAGE_BITS) | PAGE_WRITE);
2054 p1[pindex].flags |= PAGE_WRITE;
2055 /* and since the content will be modified, we must invalidate
2056 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002057 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002058#ifdef DEBUG_TB_CHECK
2059 tb_invalidate_check(address);
2060#endif
pbrookc8a706f2008-06-02 16:16:42 +00002061 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002062 return 1;
2063 }
2064 }
pbrookc8a706f2008-06-02 16:16:42 +00002065 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002066 return 0;
2067}
2068
bellard6a00d602005-11-21 23:25:50 +00002069static inline void tlb_set_dirty(CPUState *env,
2070 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002071{
2072}
bellard9fa3e852004-01-04 18:06:42 +00002073#endif /* defined(CONFIG_USER_ONLY) */
2074
pbrooke2eef172008-06-08 01:09:01 +00002075#if !defined(CONFIG_USER_ONLY)
blueswir1db7b5422007-05-26 17:36:03 +00002076static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002077 ram_addr_t memory);
2078static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2079 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002080#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2081 need_subpage) \
2082 do { \
2083 if (addr > start_addr) \
2084 start_addr2 = 0; \
2085 else { \
2086 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2087 if (start_addr2 > 0) \
2088 need_subpage = 1; \
2089 } \
2090 \
blueswir149e9fba2007-05-30 17:25:06 +00002091 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002092 end_addr2 = TARGET_PAGE_SIZE - 1; \
2093 else { \
2094 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2095 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2096 need_subpage = 1; \
2097 } \
2098 } while (0)
2099
bellard33417e72003-08-10 21:47:01 +00002100/* register physical memory. 'size' must be a multiple of the target
2101 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2102 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002103void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002104 ram_addr_t size,
2105 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002106{
bellard108c49b2005-07-24 12:55:09 +00002107 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002108 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002109 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002110 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002111 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002112
bellardda260242008-05-30 20:48:25 +00002113#ifdef USE_KQEMU
2114 /* XXX: should not depend on cpu context */
2115 env = first_cpu;
2116 if (env->kqemu_enabled) {
2117 kqemu_set_phys_mem(start_addr, size, phys_offset);
2118 }
2119#endif
bellard5fd386f2004-05-23 21:11:22 +00002120 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002121 end_addr = start_addr + (target_phys_addr_t)size;
2122 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002123 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2124 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002125 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002126 target_phys_addr_t start_addr2, end_addr2;
2127 int need_subpage = 0;
2128
2129 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2130 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002131 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002132 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2133 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2134 &p->phys_offset, orig_memory);
2135 } else {
2136 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2137 >> IO_MEM_SHIFT];
2138 }
2139 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2140 } else {
2141 p->phys_offset = phys_offset;
2142 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2143 (phys_offset & IO_MEM_ROMD))
2144 phys_offset += TARGET_PAGE_SIZE;
2145 }
2146 } else {
2147 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2148 p->phys_offset = phys_offset;
2149 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2150 (phys_offset & IO_MEM_ROMD))
2151 phys_offset += TARGET_PAGE_SIZE;
2152 else {
2153 target_phys_addr_t start_addr2, end_addr2;
2154 int need_subpage = 0;
2155
2156 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2157 end_addr2, need_subpage);
2158
blueswir14254fab2008-01-01 16:57:19 +00002159 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002160 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2161 &p->phys_offset, IO_MEM_UNASSIGNED);
2162 subpage_register(subpage, start_addr2, end_addr2,
2163 phys_offset);
2164 }
2165 }
2166 }
bellard33417e72003-08-10 21:47:01 +00002167 }
ths3b46e622007-09-17 08:09:54 +00002168
bellard9d420372006-06-25 22:25:22 +00002169 /* since each CPU stores ram addresses in its TLB cache, we must
2170 reset the modified entries */
2171 /* XXX: slow ! */
2172 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2173 tlb_flush(env, 1);
2174 }
bellard33417e72003-08-10 21:47:01 +00002175}
2176
bellardba863452006-09-24 18:41:10 +00002177/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002178ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002179{
2180 PhysPageDesc *p;
2181
2182 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2183 if (!p)
2184 return IO_MEM_UNASSIGNED;
2185 return p->phys_offset;
2186}
2187
bellarde9a1ab12007-02-08 23:08:38 +00002188/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002189ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002190{
2191 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002192 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002193 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2194 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002195 abort();
2196 }
2197 addr = phys_ram_alloc_offset;
2198 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2199 return addr;
2200}
2201
2202void qemu_ram_free(ram_addr_t addr)
2203{
2204}
2205
bellarda4193c82004-06-03 14:01:43 +00002206static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002207{
pbrook67d3b952006-12-18 05:03:52 +00002208#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002209 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002210#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002211#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002212 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002213#elif TARGET_CRIS
2214 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002215#endif
bellard33417e72003-08-10 21:47:01 +00002216 return 0;
2217}
2218
bellarda4193c82004-06-03 14:01:43 +00002219static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002220{
pbrook67d3b952006-12-18 05:03:52 +00002221#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002222 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002223#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002224#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002225 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002226#elif TARGET_CRIS
2227 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002228#endif
bellard33417e72003-08-10 21:47:01 +00002229}
2230
2231static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2232 unassigned_mem_readb,
2233 unassigned_mem_readb,
2234 unassigned_mem_readb,
2235};
2236
2237static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2238 unassigned_mem_writeb,
2239 unassigned_mem_writeb,
2240 unassigned_mem_writeb,
2241};
2242
pbrook0f459d12008-06-09 00:20:13 +00002243static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2244 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002245{
bellard3a7d9292005-08-21 09:26:42 +00002246 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002247 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2248 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2249#if !defined(CONFIG_USER_ONLY)
2250 tb_invalidate_phys_page_fast(ram_addr, 1);
2251 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2252#endif
2253 }
pbrook0f459d12008-06-09 00:20:13 +00002254 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002255#ifdef USE_KQEMU
2256 if (cpu_single_env->kqemu_enabled &&
2257 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2258 kqemu_modify_page(cpu_single_env, ram_addr);
2259#endif
bellardf23db162005-08-21 19:12:28 +00002260 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2261 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2262 /* we remove the notdirty callback only if the code has been
2263 flushed */
2264 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002265 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002266}
2267
pbrook0f459d12008-06-09 00:20:13 +00002268static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2269 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002270{
bellard3a7d9292005-08-21 09:26:42 +00002271 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002272 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2273 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2274#if !defined(CONFIG_USER_ONLY)
2275 tb_invalidate_phys_page_fast(ram_addr, 2);
2276 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2277#endif
2278 }
pbrook0f459d12008-06-09 00:20:13 +00002279 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002280#ifdef USE_KQEMU
2281 if (cpu_single_env->kqemu_enabled &&
2282 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2283 kqemu_modify_page(cpu_single_env, ram_addr);
2284#endif
bellardf23db162005-08-21 19:12:28 +00002285 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2286 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2287 /* we remove the notdirty callback only if the code has been
2288 flushed */
2289 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002290 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002291}
2292
pbrook0f459d12008-06-09 00:20:13 +00002293static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2294 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002295{
bellard3a7d9292005-08-21 09:26:42 +00002296 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002297 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2298 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2299#if !defined(CONFIG_USER_ONLY)
2300 tb_invalidate_phys_page_fast(ram_addr, 4);
2301 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2302#endif
2303 }
pbrook0f459d12008-06-09 00:20:13 +00002304 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002305#ifdef USE_KQEMU
2306 if (cpu_single_env->kqemu_enabled &&
2307 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2308 kqemu_modify_page(cpu_single_env, ram_addr);
2309#endif
bellardf23db162005-08-21 19:12:28 +00002310 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2311 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2312 /* we remove the notdirty callback only if the code has been
2313 flushed */
2314 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002315 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002316}
2317
bellard3a7d9292005-08-21 09:26:42 +00002318static CPUReadMemoryFunc *error_mem_read[3] = {
2319 NULL, /* never used */
2320 NULL, /* never used */
2321 NULL, /* never used */
2322};
2323
bellard1ccde1c2004-02-06 19:46:14 +00002324static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2325 notdirty_mem_writeb,
2326 notdirty_mem_writew,
2327 notdirty_mem_writel,
2328};
2329
pbrook0f459d12008-06-09 00:20:13 +00002330/* Generate a debug exception if a watchpoint has been hit. */
2331static void check_watchpoint(int offset, int flags)
2332{
2333 CPUState *env = cpu_single_env;
2334 target_ulong vaddr;
2335 int i;
2336
pbrook2e70f6e2008-06-29 01:03:05 +00002337 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
pbrook0f459d12008-06-09 00:20:13 +00002338 for (i = 0; i < env->nb_watchpoints; i++) {
2339 if (vaddr == env->watchpoint[i].vaddr
2340 && (env->watchpoint[i].type & flags)) {
2341 env->watchpoint_hit = i + 1;
2342 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2343 break;
2344 }
2345 }
2346}
2347
pbrook6658ffb2007-03-16 23:58:11 +00002348/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2349 so these check for a hit then pass through to the normal out-of-line
2350 phys routines. */
2351static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2352{
pbrook0f459d12008-06-09 00:20:13 +00002353 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002354 return ldub_phys(addr);
2355}
2356
2357static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2358{
pbrook0f459d12008-06-09 00:20:13 +00002359 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002360 return lduw_phys(addr);
2361}
2362
2363static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2364{
pbrook0f459d12008-06-09 00:20:13 +00002365 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002366 return ldl_phys(addr);
2367}
2368
pbrook6658ffb2007-03-16 23:58:11 +00002369static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2370 uint32_t val)
2371{
pbrook0f459d12008-06-09 00:20:13 +00002372 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002373 stb_phys(addr, val);
2374}
2375
2376static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2377 uint32_t val)
2378{
pbrook0f459d12008-06-09 00:20:13 +00002379 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002380 stw_phys(addr, val);
2381}
2382
2383static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2384 uint32_t val)
2385{
pbrook0f459d12008-06-09 00:20:13 +00002386 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002387 stl_phys(addr, val);
2388}
2389
2390static CPUReadMemoryFunc *watch_mem_read[3] = {
2391 watch_mem_readb,
2392 watch_mem_readw,
2393 watch_mem_readl,
2394};
2395
2396static CPUWriteMemoryFunc *watch_mem_write[3] = {
2397 watch_mem_writeb,
2398 watch_mem_writew,
2399 watch_mem_writel,
2400};
pbrook6658ffb2007-03-16 23:58:11 +00002401
blueswir1db7b5422007-05-26 17:36:03 +00002402static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2403 unsigned int len)
2404{
blueswir1db7b5422007-05-26 17:36:03 +00002405 uint32_t ret;
2406 unsigned int idx;
2407
2408 idx = SUBPAGE_IDX(addr - mmio->base);
2409#if defined(DEBUG_SUBPAGE)
2410 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2411 mmio, len, addr, idx);
2412#endif
blueswir13ee89922008-01-02 19:45:26 +00002413 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002414
2415 return ret;
2416}
2417
2418static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2419 uint32_t value, unsigned int len)
2420{
blueswir1db7b5422007-05-26 17:36:03 +00002421 unsigned int idx;
2422
2423 idx = SUBPAGE_IDX(addr - mmio->base);
2424#if defined(DEBUG_SUBPAGE)
2425 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2426 mmio, len, addr, idx, value);
2427#endif
blueswir13ee89922008-01-02 19:45:26 +00002428 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002429}
2430
2431static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2432{
2433#if defined(DEBUG_SUBPAGE)
2434 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2435#endif
2436
2437 return subpage_readlen(opaque, addr, 0);
2438}
2439
2440static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2441 uint32_t value)
2442{
2443#if defined(DEBUG_SUBPAGE)
2444 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2445#endif
2446 subpage_writelen(opaque, addr, value, 0);
2447}
2448
2449static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2450{
2451#if defined(DEBUG_SUBPAGE)
2452 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2453#endif
2454
2455 return subpage_readlen(opaque, addr, 1);
2456}
2457
2458static void subpage_writew (void *opaque, target_phys_addr_t addr,
2459 uint32_t value)
2460{
2461#if defined(DEBUG_SUBPAGE)
2462 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2463#endif
2464 subpage_writelen(opaque, addr, value, 1);
2465}
2466
2467static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2468{
2469#if defined(DEBUG_SUBPAGE)
2470 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2471#endif
2472
2473 return subpage_readlen(opaque, addr, 2);
2474}
2475
2476static void subpage_writel (void *opaque,
2477 target_phys_addr_t addr, uint32_t value)
2478{
2479#if defined(DEBUG_SUBPAGE)
2480 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2481#endif
2482 subpage_writelen(opaque, addr, value, 2);
2483}
2484
2485static CPUReadMemoryFunc *subpage_read[] = {
2486 &subpage_readb,
2487 &subpage_readw,
2488 &subpage_readl,
2489};
2490
2491static CPUWriteMemoryFunc *subpage_write[] = {
2492 &subpage_writeb,
2493 &subpage_writew,
2494 &subpage_writel,
2495};
2496
2497static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002498 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002499{
2500 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002501 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002502
2503 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2504 return -1;
2505 idx = SUBPAGE_IDX(start);
2506 eidx = SUBPAGE_IDX(end);
2507#if defined(DEBUG_SUBPAGE)
2508 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2509 mmio, start, end, idx, eidx, memory);
2510#endif
2511 memory >>= IO_MEM_SHIFT;
2512 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002513 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002514 if (io_mem_read[memory][i]) {
2515 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2516 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2517 }
2518 if (io_mem_write[memory][i]) {
2519 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2520 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2521 }
blueswir14254fab2008-01-01 16:57:19 +00002522 }
blueswir1db7b5422007-05-26 17:36:03 +00002523 }
2524
2525 return 0;
2526}
2527
aurel3200f82b82008-04-27 21:12:55 +00002528static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2529 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002530{
2531 subpage_t *mmio;
2532 int subpage_memory;
2533
2534 mmio = qemu_mallocz(sizeof(subpage_t));
2535 if (mmio != NULL) {
2536 mmio->base = base;
2537 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2538#if defined(DEBUG_SUBPAGE)
2539 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2540 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2541#endif
2542 *phys = subpage_memory | IO_MEM_SUBPAGE;
2543 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2544 }
2545
2546 return mmio;
2547}
2548
bellard33417e72003-08-10 21:47:01 +00002549static void io_mem_init(void)
2550{
bellard3a7d9292005-08-21 09:26:42 +00002551 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002552 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002553 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002554 io_mem_nb = 5;
2555
pbrook0f459d12008-06-09 00:20:13 +00002556 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002557 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002558 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002559 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002560 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002561}
2562
2563/* mem_read and mem_write are arrays of functions containing the
2564 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002565 2). Functions can be omitted with a NULL function pointer. The
2566 registered functions may be modified dynamically later.
2567 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002568 modified. If it is zero, a new io zone is allocated. The return
2569 value can be used with cpu_register_physical_memory(). (-1) is
2570 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002571int cpu_register_io_memory(int io_index,
2572 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002573 CPUWriteMemoryFunc **mem_write,
2574 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002575{
blueswir14254fab2008-01-01 16:57:19 +00002576 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002577
2578 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002579 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002580 return -1;
2581 io_index = io_mem_nb++;
2582 } else {
2583 if (io_index >= IO_MEM_NB_ENTRIES)
2584 return -1;
2585 }
bellardb5ff1b32005-11-26 10:38:39 +00002586
bellard33417e72003-08-10 21:47:01 +00002587 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002588 if (!mem_read[i] || !mem_write[i])
2589 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002590 io_mem_read[io_index][i] = mem_read[i];
2591 io_mem_write[io_index][i] = mem_write[i];
2592 }
bellarda4193c82004-06-03 14:01:43 +00002593 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002594 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002595}
bellard61382a52003-10-27 21:22:23 +00002596
bellard8926b512004-10-10 15:14:20 +00002597CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2598{
2599 return io_mem_write[io_index >> IO_MEM_SHIFT];
2600}
2601
2602CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2603{
2604 return io_mem_read[io_index >> IO_MEM_SHIFT];
2605}
2606
pbrooke2eef172008-06-08 01:09:01 +00002607#endif /* !defined(CONFIG_USER_ONLY) */
2608
bellard13eb76e2004-01-24 15:23:36 +00002609/* physical memory access (slow version, mainly for debug) */
2610#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002611void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002612 int len, int is_write)
2613{
2614 int l, flags;
2615 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002616 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002617
2618 while (len > 0) {
2619 page = addr & TARGET_PAGE_MASK;
2620 l = (page + TARGET_PAGE_SIZE) - addr;
2621 if (l > len)
2622 l = len;
2623 flags = page_get_flags(page);
2624 if (!(flags & PAGE_VALID))
2625 return;
2626 if (is_write) {
2627 if (!(flags & PAGE_WRITE))
2628 return;
bellard579a97f2007-11-11 14:26:47 +00002629 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002630 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002631 /* FIXME - should this return an error rather than just fail? */
2632 return;
aurel3272fb7da2008-04-27 23:53:45 +00002633 memcpy(p, buf, l);
2634 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002635 } else {
2636 if (!(flags & PAGE_READ))
2637 return;
bellard579a97f2007-11-11 14:26:47 +00002638 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002639 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002640 /* FIXME - should this return an error rather than just fail? */
2641 return;
aurel3272fb7da2008-04-27 23:53:45 +00002642 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002643 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002644 }
2645 len -= l;
2646 buf += l;
2647 addr += l;
2648 }
2649}
bellard8df1cd02005-01-28 22:37:22 +00002650
bellard13eb76e2004-01-24 15:23:36 +00002651#else
ths5fafdf22007-09-16 21:08:06 +00002652void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002653 int len, int is_write)
2654{
2655 int l, io_index;
2656 uint8_t *ptr;
2657 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002658 target_phys_addr_t page;
2659 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002660 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002661
bellard13eb76e2004-01-24 15:23:36 +00002662 while (len > 0) {
2663 page = addr & TARGET_PAGE_MASK;
2664 l = (page + TARGET_PAGE_SIZE) - addr;
2665 if (l > len)
2666 l = len;
bellard92e873b2004-05-21 14:52:29 +00002667 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002668 if (!p) {
2669 pd = IO_MEM_UNASSIGNED;
2670 } else {
2671 pd = p->phys_offset;
2672 }
ths3b46e622007-09-17 08:09:54 +00002673
bellard13eb76e2004-01-24 15:23:36 +00002674 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002675 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002676 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002677 /* XXX: could force cpu_single_env to NULL to avoid
2678 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002679 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002680 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002681 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002682 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002683 l = 4;
2684 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002685 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002686 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002687 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002688 l = 2;
2689 } else {
bellard1c213d12005-09-03 10:49:04 +00002690 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002691 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002692 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002693 l = 1;
2694 }
2695 } else {
bellardb448f2f2004-02-25 23:24:04 +00002696 unsigned long addr1;
2697 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002698 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002699 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002700 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002701 if (!cpu_physical_memory_is_dirty(addr1)) {
2702 /* invalidate code */
2703 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2704 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002705 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002706 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002707 }
bellard13eb76e2004-01-24 15:23:36 +00002708 }
2709 } else {
ths5fafdf22007-09-16 21:08:06 +00002710 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002711 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002712 /* I/O case */
2713 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2714 if (l >= 4 && ((addr & 3) == 0)) {
2715 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002716 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002717 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002718 l = 4;
2719 } else if (l >= 2 && ((addr & 1) == 0)) {
2720 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002721 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002722 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002723 l = 2;
2724 } else {
bellard1c213d12005-09-03 10:49:04 +00002725 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002726 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002727 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002728 l = 1;
2729 }
2730 } else {
2731 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002732 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002733 (addr & ~TARGET_PAGE_MASK);
2734 memcpy(buf, ptr, l);
2735 }
2736 }
2737 len -= l;
2738 buf += l;
2739 addr += l;
2740 }
2741}
bellard8df1cd02005-01-28 22:37:22 +00002742
bellardd0ecd2a2006-04-23 17:14:48 +00002743/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002744void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002745 const uint8_t *buf, int len)
2746{
2747 int l;
2748 uint8_t *ptr;
2749 target_phys_addr_t page;
2750 unsigned long pd;
2751 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002752
bellardd0ecd2a2006-04-23 17:14:48 +00002753 while (len > 0) {
2754 page = addr & TARGET_PAGE_MASK;
2755 l = (page + TARGET_PAGE_SIZE) - addr;
2756 if (l > len)
2757 l = len;
2758 p = phys_page_find(page >> TARGET_PAGE_BITS);
2759 if (!p) {
2760 pd = IO_MEM_UNASSIGNED;
2761 } else {
2762 pd = p->phys_offset;
2763 }
ths3b46e622007-09-17 08:09:54 +00002764
bellardd0ecd2a2006-04-23 17:14:48 +00002765 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002766 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2767 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002768 /* do nothing */
2769 } else {
2770 unsigned long addr1;
2771 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2772 /* ROM/RAM case */
2773 ptr = phys_ram_base + addr1;
2774 memcpy(ptr, buf, l);
2775 }
2776 len -= l;
2777 buf += l;
2778 addr += l;
2779 }
2780}
2781
2782
bellard8df1cd02005-01-28 22:37:22 +00002783/* warning: addr must be aligned */
2784uint32_t ldl_phys(target_phys_addr_t addr)
2785{
2786 int io_index;
2787 uint8_t *ptr;
2788 uint32_t val;
2789 unsigned long pd;
2790 PhysPageDesc *p;
2791
2792 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2793 if (!p) {
2794 pd = IO_MEM_UNASSIGNED;
2795 } else {
2796 pd = p->phys_offset;
2797 }
ths3b46e622007-09-17 08:09:54 +00002798
ths5fafdf22007-09-16 21:08:06 +00002799 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002800 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002801 /* I/O case */
2802 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2803 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2804 } else {
2805 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002806 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002807 (addr & ~TARGET_PAGE_MASK);
2808 val = ldl_p(ptr);
2809 }
2810 return val;
2811}
2812
bellard84b7b8e2005-11-28 21:19:04 +00002813/* warning: addr must be aligned */
2814uint64_t ldq_phys(target_phys_addr_t addr)
2815{
2816 int io_index;
2817 uint8_t *ptr;
2818 uint64_t val;
2819 unsigned long pd;
2820 PhysPageDesc *p;
2821
2822 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2823 if (!p) {
2824 pd = IO_MEM_UNASSIGNED;
2825 } else {
2826 pd = p->phys_offset;
2827 }
ths3b46e622007-09-17 08:09:54 +00002828
bellard2a4188a2006-06-25 21:54:59 +00002829 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2830 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002831 /* I/O case */
2832 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2833#ifdef TARGET_WORDS_BIGENDIAN
2834 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2835 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2836#else
2837 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2838 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2839#endif
2840 } else {
2841 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002842 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002843 (addr & ~TARGET_PAGE_MASK);
2844 val = ldq_p(ptr);
2845 }
2846 return val;
2847}
2848
bellardaab33092005-10-30 20:48:42 +00002849/* XXX: optimize */
2850uint32_t ldub_phys(target_phys_addr_t addr)
2851{
2852 uint8_t val;
2853 cpu_physical_memory_read(addr, &val, 1);
2854 return val;
2855}
2856
2857/* XXX: optimize */
2858uint32_t lduw_phys(target_phys_addr_t addr)
2859{
2860 uint16_t val;
2861 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2862 return tswap16(val);
2863}
2864
bellard8df1cd02005-01-28 22:37:22 +00002865/* warning: addr must be aligned. The ram page is not masked as dirty
2866 and the code inside is not invalidated. It is useful if the dirty
2867 bits are used to track modified PTEs */
2868void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2869{
2870 int io_index;
2871 uint8_t *ptr;
2872 unsigned long pd;
2873 PhysPageDesc *p;
2874
2875 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2876 if (!p) {
2877 pd = IO_MEM_UNASSIGNED;
2878 } else {
2879 pd = p->phys_offset;
2880 }
ths3b46e622007-09-17 08:09:54 +00002881
bellard3a7d9292005-08-21 09:26:42 +00002882 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002883 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2884 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2885 } else {
ths5fafdf22007-09-16 21:08:06 +00002886 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002887 (addr & ~TARGET_PAGE_MASK);
2888 stl_p(ptr, val);
2889 }
2890}
2891
j_mayerbc98a7e2007-04-04 07:55:12 +00002892void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2893{
2894 int io_index;
2895 uint8_t *ptr;
2896 unsigned long pd;
2897 PhysPageDesc *p;
2898
2899 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2900 if (!p) {
2901 pd = IO_MEM_UNASSIGNED;
2902 } else {
2903 pd = p->phys_offset;
2904 }
ths3b46e622007-09-17 08:09:54 +00002905
j_mayerbc98a7e2007-04-04 07:55:12 +00002906 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2907 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2908#ifdef TARGET_WORDS_BIGENDIAN
2909 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2910 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2911#else
2912 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2913 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2914#endif
2915 } else {
ths5fafdf22007-09-16 21:08:06 +00002916 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002917 (addr & ~TARGET_PAGE_MASK);
2918 stq_p(ptr, val);
2919 }
2920}
2921
bellard8df1cd02005-01-28 22:37:22 +00002922/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002923void stl_phys(target_phys_addr_t addr, uint32_t val)
2924{
2925 int io_index;
2926 uint8_t *ptr;
2927 unsigned long pd;
2928 PhysPageDesc *p;
2929
2930 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2931 if (!p) {
2932 pd = IO_MEM_UNASSIGNED;
2933 } else {
2934 pd = p->phys_offset;
2935 }
ths3b46e622007-09-17 08:09:54 +00002936
bellard3a7d9292005-08-21 09:26:42 +00002937 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002938 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2939 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2940 } else {
2941 unsigned long addr1;
2942 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2943 /* RAM case */
2944 ptr = phys_ram_base + addr1;
2945 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002946 if (!cpu_physical_memory_is_dirty(addr1)) {
2947 /* invalidate code */
2948 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2949 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002950 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2951 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002952 }
bellard8df1cd02005-01-28 22:37:22 +00002953 }
2954}
2955
bellardaab33092005-10-30 20:48:42 +00002956/* XXX: optimize */
2957void stb_phys(target_phys_addr_t addr, uint32_t val)
2958{
2959 uint8_t v = val;
2960 cpu_physical_memory_write(addr, &v, 1);
2961}
2962
2963/* XXX: optimize */
2964void stw_phys(target_phys_addr_t addr, uint32_t val)
2965{
2966 uint16_t v = tswap16(val);
2967 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2968}
2969
2970/* XXX: optimize */
2971void stq_phys(target_phys_addr_t addr, uint64_t val)
2972{
2973 val = tswap64(val);
2974 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2975}
2976
bellard13eb76e2004-01-24 15:23:36 +00002977#endif
2978
2979/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002980int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002981 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002982{
2983 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002984 target_phys_addr_t phys_addr;
2985 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002986
2987 while (len > 0) {
2988 page = addr & TARGET_PAGE_MASK;
2989 phys_addr = cpu_get_phys_page_debug(env, page);
2990 /* if no physical page mapped, return an error */
2991 if (phys_addr == -1)
2992 return -1;
2993 l = (page + TARGET_PAGE_SIZE) - addr;
2994 if (l > len)
2995 l = len;
ths5fafdf22007-09-16 21:08:06 +00002996 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002997 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002998 len -= l;
2999 buf += l;
3000 addr += l;
3001 }
3002 return 0;
3003}
3004
pbrook2e70f6e2008-06-29 01:03:05 +00003005/* in deterministic execution mode, instructions doing device I/Os
3006 must be at the end of the TB */
3007void cpu_io_recompile(CPUState *env, void *retaddr)
3008{
3009 TranslationBlock *tb;
3010 uint32_t n, cflags;
3011 target_ulong pc, cs_base;
3012 uint64_t flags;
3013
3014 tb = tb_find_pc((unsigned long)retaddr);
3015 if (!tb) {
3016 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3017 retaddr);
3018 }
3019 n = env->icount_decr.u16.low + tb->icount;
3020 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3021 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003022 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003023 n = n - env->icount_decr.u16.low;
3024 /* Generate a new TB ending on the I/O insn. */
3025 n++;
3026 /* On MIPS and SH, delay slot instructions can only be restarted if
3027 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003028 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003029 branch. */
3030#if defined(TARGET_MIPS)
3031 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3032 env->active_tc.PC -= 4;
3033 env->icount_decr.u16.low++;
3034 env->hflags &= ~MIPS_HFLAG_BMASK;
3035 }
3036#elif defined(TARGET_SH4)
3037 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3038 && n > 1) {
3039 env->pc -= 2;
3040 env->icount_decr.u16.low++;
3041 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3042 }
3043#endif
3044 /* This should never happen. */
3045 if (n > CF_COUNT_MASK)
3046 cpu_abort(env, "TB too big during recompile");
3047
3048 cflags = n | CF_LAST_IO;
3049 pc = tb->pc;
3050 cs_base = tb->cs_base;
3051 flags = tb->flags;
3052 tb_phys_invalidate(tb, -1);
3053 /* FIXME: In theory this could raise an exception. In practice
3054 we have already translated the block once so it's probably ok. */
3055 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003056 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003057 the first in the TB) then we end up generating a whole new TB and
3058 repeating the fault, which is horribly inefficient.
3059 Better would be to execute just this insn uncached, or generate a
3060 second new TB. */
3061 cpu_resume_from_signal(env, NULL);
3062}
3063
bellarde3db7222005-01-26 22:00:47 +00003064void dump_exec_info(FILE *f,
3065 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3066{
3067 int i, target_code_size, max_target_code_size;
3068 int direct_jmp_count, direct_jmp2_count, cross_page;
3069 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003070
bellarde3db7222005-01-26 22:00:47 +00003071 target_code_size = 0;
3072 max_target_code_size = 0;
3073 cross_page = 0;
3074 direct_jmp_count = 0;
3075 direct_jmp2_count = 0;
3076 for(i = 0; i < nb_tbs; i++) {
3077 tb = &tbs[i];
3078 target_code_size += tb->size;
3079 if (tb->size > max_target_code_size)
3080 max_target_code_size = tb->size;
3081 if (tb->page_addr[1] != -1)
3082 cross_page++;
3083 if (tb->tb_next_offset[0] != 0xffff) {
3084 direct_jmp_count++;
3085 if (tb->tb_next_offset[1] != 0xffff) {
3086 direct_jmp2_count++;
3087 }
3088 }
3089 }
3090 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003091 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003092 cpu_fprintf(f, "gen code size %ld/%ld\n",
3093 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3094 cpu_fprintf(f, "TB count %d/%d\n",
3095 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003096 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003097 nb_tbs ? target_code_size / nb_tbs : 0,
3098 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003099 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003100 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3101 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003102 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3103 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003104 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3105 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003106 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003107 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3108 direct_jmp2_count,
3109 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003110 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003111 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3112 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3113 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003114 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003115}
3116
ths5fafdf22007-09-16 21:08:06 +00003117#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003118
3119#define MMUSUFFIX _cmmu
3120#define GETPC() NULL
3121#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003122#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003123
3124#define SHIFT 0
3125#include "softmmu_template.h"
3126
3127#define SHIFT 1
3128#include "softmmu_template.h"
3129
3130#define SHIFT 2
3131#include "softmmu_template.h"
3132
3133#define SHIFT 3
3134#include "softmmu_template.h"
3135
3136#undef env
3137
3138#endif