blob: ffe4cc9da170bbc417b78b2a4369eeb588407ceb [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrook53a59602006-03-25 19:31:22 +000040#if defined(CONFIG_USER_ONLY)
41#include <qemu.h>
42#endif
bellard54936002003-05-13 00:25:15 +000043
bellardfd6ce8f2003-05-14 19:00:11 +000044//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000045//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000046//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000047//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000048
49/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000050//#define DEBUG_TB_CHECK
51//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000052
ths1196be32007-03-17 15:17:58 +000053//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000054//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000055
pbrook99773bd2006-04-16 15:14:59 +000056#if !defined(CONFIG_USER_ONLY)
57/* TB consistency checks only implemented for usermode emulation. */
58#undef DEBUG_TB_CHECK
59#endif
60
bellard9fa3e852004-01-04 18:06:42 +000061#define SMC_BITMAP_USE_THRESHOLD 10
62
63#define MMAP_AREA_START 0x00000000
64#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000065
bellard108c49b2005-07-24 12:55:09 +000066#if defined(TARGET_SPARC64)
67#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000068#elif defined(TARGET_SPARC)
69#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000070#elif defined(TARGET_ALPHA)
71#define TARGET_PHYS_ADDR_SPACE_BITS 42
72#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000073#elif defined(TARGET_PPC64)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000075#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
76#define TARGET_PHYS_ADDR_SPACE_BITS 42
77#elif defined(TARGET_I386) && !defined(USE_KQEMU)
78#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000079#else
80/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
81#define TARGET_PHYS_ADDR_SPACE_BITS 32
82#endif
83
pbrookfab94c02008-05-24 13:56:15 +000084TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000085int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000086TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000087int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000088/* any access to the tbs or the page table must use this lock */
89spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000090
bellard7cb69ca2008-05-10 10:55:51 +000091uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellard26a5f132008-05-28 12:30:31 +000092uint8_t *code_gen_buffer;
93unsigned long code_gen_buffer_size;
94/* threshold to flush the translated code buffer */
95unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +000096uint8_t *code_gen_ptr;
97
aurel3200f82b82008-04-27 21:12:55 +000098ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +000099int phys_ram_fd;
100uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000101uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000102static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +0000103
bellard6a00d602005-11-21 23:25:50 +0000104CPUState *first_cpu;
105/* current CPU in the current thread. It is only valid inside
106 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000107CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000108
bellard54936002003-05-13 00:25:15 +0000109typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000110 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000111 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000112 /* in order to optimize self modifying code, we count the number
113 of lookups we do to a given page to use a bitmap */
114 unsigned int code_write_count;
115 uint8_t *code_bitmap;
116#if defined(CONFIG_USER_ONLY)
117 unsigned long flags;
118#endif
bellard54936002003-05-13 00:25:15 +0000119} PageDesc;
120
bellard92e873b2004-05-21 14:52:29 +0000121typedef struct PhysPageDesc {
122 /* offset in host memory of the page + io_index in the low 12 bits */
aurel3200f82b82008-04-27 21:12:55 +0000123 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000124} PhysPageDesc;
125
bellard54936002003-05-13 00:25:15 +0000126#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000127#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
128/* XXX: this is a temporary hack for alpha target.
129 * In the future, this is to be replaced by a multi-level table
130 * to actually be able to handle the complete 64 bits address space.
131 */
132#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
133#else
aurel3203875442008-04-22 20:45:18 +0000134#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000135#endif
bellard54936002003-05-13 00:25:15 +0000136
137#define L1_SIZE (1 << L1_BITS)
138#define L2_SIZE (1 << L2_BITS)
139
bellard33417e72003-08-10 21:47:01 +0000140static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000141
bellard83fb7ad2004-07-05 21:25:26 +0000142unsigned long qemu_real_host_page_size;
143unsigned long qemu_host_page_bits;
144unsigned long qemu_host_page_size;
145unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000146
bellard92e873b2004-05-21 14:52:29 +0000147/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000148static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000149PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000150
bellard33417e72003-08-10 21:47:01 +0000151/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000152CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
153CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000154void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000155static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000156#if defined(CONFIG_SOFTMMU)
157static int io_mem_watch;
158#endif
bellard33417e72003-08-10 21:47:01 +0000159
bellard34865132003-10-05 14:28:56 +0000160/* log support */
161char *logfilename = "/tmp/qemu.log";
162FILE *logfile;
163int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000164static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000165
bellarde3db7222005-01-26 22:00:47 +0000166/* statistics */
167static int tlb_flush_count;
168static int tb_flush_count;
169static int tb_phys_invalidate_count;
170
blueswir1db7b5422007-05-26 17:36:03 +0000171#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
172typedef struct subpage_t {
173 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000174 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
175 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
176 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000177} subpage_t;
178
bellard7cb69ca2008-05-10 10:55:51 +0000179#ifdef _WIN32
180static void map_exec(void *addr, long size)
181{
182 DWORD old_protect;
183 VirtualProtect(addr, size,
184 PAGE_EXECUTE_READWRITE, &old_protect);
185
186}
187#else
188static void map_exec(void *addr, long size)
189{
bellard43694152008-05-29 09:35:57 +0000190 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000191
bellard43694152008-05-29 09:35:57 +0000192 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000193 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000194 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000195
196 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000197 end += page_size - 1;
198 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000199
200 mprotect((void *)start, end - start,
201 PROT_READ | PROT_WRITE | PROT_EXEC);
202}
203#endif
204
bellardb346ff42003-06-15 20:05:50 +0000205static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000206{
bellard83fb7ad2004-07-05 21:25:26 +0000207 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000208 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000209#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000210 {
211 SYSTEM_INFO system_info;
212 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000213
bellardd5a8f072004-09-29 21:15:28 +0000214 GetSystemInfo(&system_info);
215 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000216 }
bellard67b915a2004-03-31 23:37:16 +0000217#else
bellard83fb7ad2004-07-05 21:25:26 +0000218 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000219#endif
bellard83fb7ad2004-07-05 21:25:26 +0000220 if (qemu_host_page_size == 0)
221 qemu_host_page_size = qemu_real_host_page_size;
222 if (qemu_host_page_size < TARGET_PAGE_SIZE)
223 qemu_host_page_size = TARGET_PAGE_SIZE;
224 qemu_host_page_bits = 0;
225 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
226 qemu_host_page_bits++;
227 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000228 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
229 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000230
231#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
232 {
233 long long startaddr, endaddr;
234 FILE *f;
235 int n;
236
pbrookc8a706f2008-06-02 16:16:42 +0000237 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000238 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000239 f = fopen("/proc/self/maps", "r");
240 if (f) {
241 do {
242 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
243 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000244 startaddr = MIN(startaddr,
245 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
246 endaddr = MIN(endaddr,
247 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000248 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000249 TARGET_PAGE_ALIGN(endaddr),
250 PAGE_RESERVED);
251 }
252 } while (!feof(f));
253 fclose(f);
254 }
pbrookc8a706f2008-06-02 16:16:42 +0000255 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000256 }
257#endif
bellard54936002003-05-13 00:25:15 +0000258}
259
aurel3200f82b82008-04-27 21:12:55 +0000260static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000261{
bellard54936002003-05-13 00:25:15 +0000262 PageDesc **lp, *p;
263
bellard54936002003-05-13 00:25:15 +0000264 lp = &l1_map[index >> L2_BITS];
265 p = *lp;
266 if (!p) {
267 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000268 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000269 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000270 *lp = p;
271 }
272 return p + (index & (L2_SIZE - 1));
273}
274
aurel3200f82b82008-04-27 21:12:55 +0000275static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000276{
bellard54936002003-05-13 00:25:15 +0000277 PageDesc *p;
278
bellard54936002003-05-13 00:25:15 +0000279 p = l1_map[index >> L2_BITS];
280 if (!p)
281 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000282 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000283}
284
bellard108c49b2005-07-24 12:55:09 +0000285static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000286{
bellard108c49b2005-07-24 12:55:09 +0000287 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000288 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000289
bellard108c49b2005-07-24 12:55:09 +0000290 p = (void **)l1_phys_map;
291#if TARGET_PHYS_ADDR_SPACE_BITS > 32
292
293#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
294#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
295#endif
296 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000297 p = *lp;
298 if (!p) {
299 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000300 if (!alloc)
301 return NULL;
302 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
303 memset(p, 0, sizeof(void *) * L1_SIZE);
304 *lp = p;
305 }
306#endif
307 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000308 pd = *lp;
309 if (!pd) {
310 int i;
bellard108c49b2005-07-24 12:55:09 +0000311 /* allocate if not found */
312 if (!alloc)
313 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000314 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
315 *lp = pd;
316 for (i = 0; i < L2_SIZE; i++)
317 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000318 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000319 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000320}
321
bellard108c49b2005-07-24 12:55:09 +0000322static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000323{
bellard108c49b2005-07-24 12:55:09 +0000324 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000325}
326
bellard9fa3e852004-01-04 18:06:42 +0000327#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000328static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000329static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000330 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000331#define mmap_lock() do { } while(0)
332#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000333#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000334
bellard43694152008-05-29 09:35:57 +0000335#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
336
337#if defined(CONFIG_USER_ONLY)
338/* Currently it is not recommanded to allocate big chunks of data in
339 user mode. It will change when a dedicated libc will be used */
340#define USE_STATIC_CODE_GEN_BUFFER
341#endif
342
343#ifdef USE_STATIC_CODE_GEN_BUFFER
344static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
345#endif
346
bellard26a5f132008-05-28 12:30:31 +0000347void code_gen_alloc(unsigned long tb_size)
348{
bellard43694152008-05-29 09:35:57 +0000349#ifdef USE_STATIC_CODE_GEN_BUFFER
350 code_gen_buffer = static_code_gen_buffer;
351 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
352 map_exec(code_gen_buffer, code_gen_buffer_size);
353#else
bellard26a5f132008-05-28 12:30:31 +0000354 code_gen_buffer_size = tb_size;
355 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000356#if defined(CONFIG_USER_ONLY)
357 /* in user mode, phys_ram_size is not meaningful */
358 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
359#else
bellard26a5f132008-05-28 12:30:31 +0000360 /* XXX: needs ajustments */
361 code_gen_buffer_size = (int)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000362#endif
bellard26a5f132008-05-28 12:30:31 +0000363 }
364 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
365 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
366 /* The code gen buffer location may have constraints depending on
367 the host cpu and OS */
368#if defined(__linux__)
369 {
370 int flags;
371 flags = MAP_PRIVATE | MAP_ANONYMOUS;
372#if defined(__x86_64__)
373 flags |= MAP_32BIT;
374 /* Cannot map more than that */
375 if (code_gen_buffer_size > (800 * 1024 * 1024))
376 code_gen_buffer_size = (800 * 1024 * 1024);
377#endif
378 code_gen_buffer = mmap(NULL, code_gen_buffer_size,
379 PROT_WRITE | PROT_READ | PROT_EXEC,
380 flags, -1, 0);
381 if (code_gen_buffer == MAP_FAILED) {
382 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
383 exit(1);
384 }
385 }
386#else
387 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
388 if (!code_gen_buffer) {
389 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
390 exit(1);
391 }
392 map_exec(code_gen_buffer, code_gen_buffer_size);
393#endif
bellard43694152008-05-29 09:35:57 +0000394#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000395 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
396 code_gen_buffer_max_size = code_gen_buffer_size -
397 code_gen_max_block_size();
398 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
399 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
400}
401
402/* Must be called before using the QEMU cpus. 'tb_size' is the size
403 (in bytes) allocated to the translation buffer. Zero means default
404 size. */
405void cpu_exec_init_all(unsigned long tb_size)
406{
bellard26a5f132008-05-28 12:30:31 +0000407 cpu_gen_init();
408 code_gen_alloc(tb_size);
409 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000410 page_init();
bellard26a5f132008-05-28 12:30:31 +0000411 io_mem_init();
412}
413
bellard6a00d602005-11-21 23:25:50 +0000414void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000415{
bellard6a00d602005-11-21 23:25:50 +0000416 CPUState **penv;
417 int cpu_index;
418
bellard6a00d602005-11-21 23:25:50 +0000419 env->next_cpu = NULL;
420 penv = &first_cpu;
421 cpu_index = 0;
422 while (*penv != NULL) {
423 penv = (CPUState **)&(*penv)->next_cpu;
424 cpu_index++;
425 }
426 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000427 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000428 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000429}
430
bellard9fa3e852004-01-04 18:06:42 +0000431static inline void invalidate_page_bitmap(PageDesc *p)
432{
433 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000434 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000435 p->code_bitmap = NULL;
436 }
437 p->code_write_count = 0;
438}
439
bellardfd6ce8f2003-05-14 19:00:11 +0000440/* set to NULL all the 'first_tb' fields in all PageDescs */
441static void page_flush_tb(void)
442{
443 int i, j;
444 PageDesc *p;
445
446 for(i = 0; i < L1_SIZE; i++) {
447 p = l1_map[i];
448 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000449 for(j = 0; j < L2_SIZE; j++) {
450 p->first_tb = NULL;
451 invalidate_page_bitmap(p);
452 p++;
453 }
bellardfd6ce8f2003-05-14 19:00:11 +0000454 }
455 }
456}
457
458/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000459/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000460void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000461{
bellard6a00d602005-11-21 23:25:50 +0000462 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000463#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000464 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
465 (unsigned long)(code_gen_ptr - code_gen_buffer),
466 nb_tbs, nb_tbs > 0 ?
467 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000468#endif
bellard26a5f132008-05-28 12:30:31 +0000469 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000470 cpu_abort(env1, "Internal error: code buffer overflow\n");
471
bellardfd6ce8f2003-05-14 19:00:11 +0000472 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000473
bellard6a00d602005-11-21 23:25:50 +0000474 for(env = first_cpu; env != NULL; env = env->next_cpu) {
475 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
476 }
bellard9fa3e852004-01-04 18:06:42 +0000477
bellard8a8a6082004-10-03 13:36:49 +0000478 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000479 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000480
bellardfd6ce8f2003-05-14 19:00:11 +0000481 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000482 /* XXX: flush processor icache at this point if cache flush is
483 expensive */
bellarde3db7222005-01-26 22:00:47 +0000484 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000485}
486
487#ifdef DEBUG_TB_CHECK
488
j_mayerbc98a7e2007-04-04 07:55:12 +0000489static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000490{
491 TranslationBlock *tb;
492 int i;
493 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000494 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
495 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000496 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
497 address >= tb->pc + tb->size)) {
498 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000499 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000500 }
501 }
502 }
503}
504
505/* verify that all the pages have correct rights for code */
506static void tb_page_check(void)
507{
508 TranslationBlock *tb;
509 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000510
pbrook99773bd2006-04-16 15:14:59 +0000511 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
512 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000513 flags1 = page_get_flags(tb->pc);
514 flags2 = page_get_flags(tb->pc + tb->size - 1);
515 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
516 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000517 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000518 }
519 }
520 }
521}
522
bellardd4e81642003-05-25 16:46:15 +0000523void tb_jmp_check(TranslationBlock *tb)
524{
525 TranslationBlock *tb1;
526 unsigned int n1;
527
528 /* suppress any remaining jumps to this TB */
529 tb1 = tb->jmp_first;
530 for(;;) {
531 n1 = (long)tb1 & 3;
532 tb1 = (TranslationBlock *)((long)tb1 & ~3);
533 if (n1 == 2)
534 break;
535 tb1 = tb1->jmp_next[n1];
536 }
537 /* check end of list */
538 if (tb1 != tb) {
539 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
540 }
541}
542
bellardfd6ce8f2003-05-14 19:00:11 +0000543#endif
544
545/* invalidate one TB */
546static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
547 int next_offset)
548{
549 TranslationBlock *tb1;
550 for(;;) {
551 tb1 = *ptb;
552 if (tb1 == tb) {
553 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
554 break;
555 }
556 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
557 }
558}
559
bellard9fa3e852004-01-04 18:06:42 +0000560static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
561{
562 TranslationBlock *tb1;
563 unsigned int n1;
564
565 for(;;) {
566 tb1 = *ptb;
567 n1 = (long)tb1 & 3;
568 tb1 = (TranslationBlock *)((long)tb1 & ~3);
569 if (tb1 == tb) {
570 *ptb = tb1->page_next[n1];
571 break;
572 }
573 ptb = &tb1->page_next[n1];
574 }
575}
576
bellardd4e81642003-05-25 16:46:15 +0000577static inline void tb_jmp_remove(TranslationBlock *tb, int n)
578{
579 TranslationBlock *tb1, **ptb;
580 unsigned int n1;
581
582 ptb = &tb->jmp_next[n];
583 tb1 = *ptb;
584 if (tb1) {
585 /* find tb(n) in circular list */
586 for(;;) {
587 tb1 = *ptb;
588 n1 = (long)tb1 & 3;
589 tb1 = (TranslationBlock *)((long)tb1 & ~3);
590 if (n1 == n && tb1 == tb)
591 break;
592 if (n1 == 2) {
593 ptb = &tb1->jmp_first;
594 } else {
595 ptb = &tb1->jmp_next[n1];
596 }
597 }
598 /* now we can suppress tb(n) from the list */
599 *ptb = tb->jmp_next[n];
600
601 tb->jmp_next[n] = NULL;
602 }
603}
604
605/* reset the jump entry 'n' of a TB so that it is not chained to
606 another TB */
607static inline void tb_reset_jump(TranslationBlock *tb, int n)
608{
609 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
610}
611
aurel3200f82b82008-04-27 21:12:55 +0000612static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000613{
bellard6a00d602005-11-21 23:25:50 +0000614 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000615 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000616 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000617 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000618 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000619
bellard9fa3e852004-01-04 18:06:42 +0000620 /* remove the TB from the hash list */
621 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
622 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000623 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000624 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000625
bellard9fa3e852004-01-04 18:06:42 +0000626 /* remove the TB from the page list */
627 if (tb->page_addr[0] != page_addr) {
628 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
629 tb_page_remove(&p->first_tb, tb);
630 invalidate_page_bitmap(p);
631 }
632 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
633 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
634 tb_page_remove(&p->first_tb, tb);
635 invalidate_page_bitmap(p);
636 }
637
bellard8a40a182005-11-20 10:35:40 +0000638 tb_invalidated_flag = 1;
639
640 /* remove the TB from the hash list */
641 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000642 for(env = first_cpu; env != NULL; env = env->next_cpu) {
643 if (env->tb_jmp_cache[h] == tb)
644 env->tb_jmp_cache[h] = NULL;
645 }
bellard8a40a182005-11-20 10:35:40 +0000646
647 /* suppress this TB from the two jump lists */
648 tb_jmp_remove(tb, 0);
649 tb_jmp_remove(tb, 1);
650
651 /* suppress any remaining jumps to this TB */
652 tb1 = tb->jmp_first;
653 for(;;) {
654 n1 = (long)tb1 & 3;
655 if (n1 == 2)
656 break;
657 tb1 = (TranslationBlock *)((long)tb1 & ~3);
658 tb2 = tb1->jmp_next[n1];
659 tb_reset_jump(tb1, n1);
660 tb1->jmp_next[n1] = NULL;
661 tb1 = tb2;
662 }
663 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
664
bellarde3db7222005-01-26 22:00:47 +0000665 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000666}
667
668static inline void set_bits(uint8_t *tab, int start, int len)
669{
670 int end, mask, end1;
671
672 end = start + len;
673 tab += start >> 3;
674 mask = 0xff << (start & 7);
675 if ((start & ~7) == (end & ~7)) {
676 if (start < end) {
677 mask &= ~(0xff << (end & 7));
678 *tab |= mask;
679 }
680 } else {
681 *tab++ |= mask;
682 start = (start + 8) & ~7;
683 end1 = end & ~7;
684 while (start < end1) {
685 *tab++ = 0xff;
686 start += 8;
687 }
688 if (start < end) {
689 mask = ~(0xff << (end & 7));
690 *tab |= mask;
691 }
692 }
693}
694
695static void build_page_bitmap(PageDesc *p)
696{
697 int n, tb_start, tb_end;
698 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000699
bellard59817cc2004-02-16 22:01:13 +0000700 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000701 if (!p->code_bitmap)
702 return;
703 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
704
705 tb = p->first_tb;
706 while (tb != NULL) {
707 n = (long)tb & 3;
708 tb = (TranslationBlock *)((long)tb & ~3);
709 /* NOTE: this is subtle as a TB may span two physical pages */
710 if (n == 0) {
711 /* NOTE: tb_end may be after the end of the page, but
712 it is not a problem */
713 tb_start = tb->pc & ~TARGET_PAGE_MASK;
714 tb_end = tb_start + tb->size;
715 if (tb_end > TARGET_PAGE_SIZE)
716 tb_end = TARGET_PAGE_SIZE;
717 } else {
718 tb_start = 0;
719 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
720 }
721 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
722 tb = tb->page_next[n];
723 }
724}
725
bellardd720b932004-04-25 17:57:43 +0000726#ifdef TARGET_HAS_PRECISE_SMC
727
ths5fafdf22007-09-16 21:08:06 +0000728static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000729 target_ulong pc, target_ulong cs_base, int flags,
730 int cflags)
731{
732 TranslationBlock *tb;
733 uint8_t *tc_ptr;
734 target_ulong phys_pc, phys_page2, virt_page2;
735 int code_gen_size;
736
bellardc27004e2005-01-03 23:35:10 +0000737 phys_pc = get_phys_addr_code(env, pc);
738 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000739 if (!tb) {
740 /* flush must be done */
741 tb_flush(env);
742 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000743 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000744 }
745 tc_ptr = code_gen_ptr;
746 tb->tc_ptr = tc_ptr;
747 tb->cs_base = cs_base;
748 tb->flags = flags;
749 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000750 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000751 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 +0000752
bellardd720b932004-04-25 17:57:43 +0000753 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000754 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000755 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000756 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000757 phys_page2 = get_phys_addr_code(env, virt_page2);
758 }
759 tb_link_phys(tb, phys_pc, phys_page2);
760}
761#endif
ths3b46e622007-09-17 08:09:54 +0000762
bellard9fa3e852004-01-04 18:06:42 +0000763/* invalidate all TBs which intersect with the target physical page
764 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000765 the same physical page. 'is_cpu_write_access' should be true if called
766 from a real cpu write access: the virtual CPU will exit the current
767 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000768void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000769 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000770{
bellardd720b932004-04-25 17:57:43 +0000771 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000772 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000773 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000774 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000775 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000776 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000777
778 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000779 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000780 return;
ths5fafdf22007-09-16 21:08:06 +0000781 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000782 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
783 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000784 /* build code bitmap */
785 build_page_bitmap(p);
786 }
787
788 /* we remove all the TBs in the range [start, end[ */
789 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000790 current_tb_not_found = is_cpu_write_access;
791 current_tb_modified = 0;
792 current_tb = NULL; /* avoid warning */
793 current_pc = 0; /* avoid warning */
794 current_cs_base = 0; /* avoid warning */
795 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000796 tb = p->first_tb;
797 while (tb != NULL) {
798 n = (long)tb & 3;
799 tb = (TranslationBlock *)((long)tb & ~3);
800 tb_next = tb->page_next[n];
801 /* NOTE: this is subtle as a TB may span two physical pages */
802 if (n == 0) {
803 /* NOTE: tb_end may be after the end of the page, but
804 it is not a problem */
805 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
806 tb_end = tb_start + tb->size;
807 } else {
808 tb_start = tb->page_addr[1];
809 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
810 }
811 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000812#ifdef TARGET_HAS_PRECISE_SMC
813 if (current_tb_not_found) {
814 current_tb_not_found = 0;
815 current_tb = NULL;
816 if (env->mem_write_pc) {
817 /* now we have a real cpu fault */
818 current_tb = tb_find_pc(env->mem_write_pc);
819 }
820 }
821 if (current_tb == tb &&
822 !(current_tb->cflags & CF_SINGLE_INSN)) {
823 /* If we are modifying the current TB, we must stop
824 its execution. We could be more precise by checking
825 that the modification is after the current PC, but it
826 would require a specialized function to partially
827 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000828
bellardd720b932004-04-25 17:57:43 +0000829 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000830 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000831 env->mem_write_pc, NULL);
832#if defined(TARGET_I386)
833 current_flags = env->hflags;
834 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
835 current_cs_base = (target_ulong)env->segs[R_CS].base;
836 current_pc = current_cs_base + env->eip;
837#else
838#error unsupported CPU
839#endif
840 }
841#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000842 /* we need to do that to handle the case where a signal
843 occurs while doing tb_phys_invalidate() */
844 saved_tb = NULL;
845 if (env) {
846 saved_tb = env->current_tb;
847 env->current_tb = NULL;
848 }
bellard9fa3e852004-01-04 18:06:42 +0000849 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000850 if (env) {
851 env->current_tb = saved_tb;
852 if (env->interrupt_request && env->current_tb)
853 cpu_interrupt(env, env->interrupt_request);
854 }
bellard9fa3e852004-01-04 18:06:42 +0000855 }
856 tb = tb_next;
857 }
858#if !defined(CONFIG_USER_ONLY)
859 /* if no code remaining, no need to continue to use slow writes */
860 if (!p->first_tb) {
861 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000862 if (is_cpu_write_access) {
863 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
864 }
865 }
866#endif
867#ifdef TARGET_HAS_PRECISE_SMC
868 if (current_tb_modified) {
869 /* we generate a block containing just the instruction
870 modifying the memory. It will ensure that it cannot modify
871 itself */
bellardea1c1802004-06-14 18:56:36 +0000872 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000873 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000874 CF_SINGLE_INSN);
875 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000876 }
877#endif
878}
879
880/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000881static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000882{
883 PageDesc *p;
884 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000885#if 0
bellarda4193c82004-06-03 14:01:43 +0000886 if (1) {
887 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000888 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
889 cpu_single_env->mem_write_vaddr, len,
890 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000891 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
892 }
bellard59817cc2004-02-16 22:01:13 +0000893 }
894#endif
bellard9fa3e852004-01-04 18:06:42 +0000895 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000896 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000897 return;
898 if (p->code_bitmap) {
899 offset = start & ~TARGET_PAGE_MASK;
900 b = p->code_bitmap[offset >> 3] >> (offset & 7);
901 if (b & ((1 << len) - 1))
902 goto do_invalidate;
903 } else {
904 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000905 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000906 }
907}
908
bellard9fa3e852004-01-04 18:06:42 +0000909#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000910static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000911 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000912{
bellardd720b932004-04-25 17:57:43 +0000913 int n, current_flags, current_tb_modified;
914 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000915 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000916 TranslationBlock *tb, *current_tb;
917#ifdef TARGET_HAS_PRECISE_SMC
918 CPUState *env = cpu_single_env;
919#endif
bellard9fa3e852004-01-04 18:06:42 +0000920
921 addr &= TARGET_PAGE_MASK;
922 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000923 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000924 return;
925 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000926 current_tb_modified = 0;
927 current_tb = NULL;
928 current_pc = 0; /* avoid warning */
929 current_cs_base = 0; /* avoid warning */
930 current_flags = 0; /* avoid warning */
931#ifdef TARGET_HAS_PRECISE_SMC
932 if (tb && pc != 0) {
933 current_tb = tb_find_pc(pc);
934 }
935#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000936 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000937 n = (long)tb & 3;
938 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000939#ifdef TARGET_HAS_PRECISE_SMC
940 if (current_tb == tb &&
941 !(current_tb->cflags & CF_SINGLE_INSN)) {
942 /* If we are modifying the current TB, we must stop
943 its execution. We could be more precise by checking
944 that the modification is after the current PC, but it
945 would require a specialized function to partially
946 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000947
bellardd720b932004-04-25 17:57:43 +0000948 current_tb_modified = 1;
949 cpu_restore_state(current_tb, env, pc, puc);
950#if defined(TARGET_I386)
951 current_flags = env->hflags;
952 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
953 current_cs_base = (target_ulong)env->segs[R_CS].base;
954 current_pc = current_cs_base + env->eip;
955#else
956#error unsupported CPU
957#endif
958 }
959#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000960 tb_phys_invalidate(tb, addr);
961 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000962 }
963 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000964#ifdef TARGET_HAS_PRECISE_SMC
965 if (current_tb_modified) {
966 /* we generate a block containing just the instruction
967 modifying the memory. It will ensure that it cannot modify
968 itself */
bellardea1c1802004-06-14 18:56:36 +0000969 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000970 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000971 CF_SINGLE_INSN);
972 cpu_resume_from_signal(env, puc);
973 }
974#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000975}
bellard9fa3e852004-01-04 18:06:42 +0000976#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000977
978/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000979static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000980 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000981{
982 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000983 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000984
bellard9fa3e852004-01-04 18:06:42 +0000985 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000986 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000987 tb->page_next[n] = p->first_tb;
988 last_first_tb = p->first_tb;
989 p->first_tb = (TranslationBlock *)((long)tb | n);
990 invalidate_page_bitmap(p);
991
bellard107db442004-06-22 18:48:46 +0000992#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000993
bellard9fa3e852004-01-04 18:06:42 +0000994#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000995 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000996 target_ulong addr;
997 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000998 int prot;
999
bellardfd6ce8f2003-05-14 19:00:11 +00001000 /* force the host page as non writable (writes will have a
1001 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001002 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001003 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001004 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1005 addr += TARGET_PAGE_SIZE) {
1006
1007 p2 = page_find (addr >> TARGET_PAGE_BITS);
1008 if (!p2)
1009 continue;
1010 prot |= p2->flags;
1011 p2->flags &= ~PAGE_WRITE;
1012 page_get_flags(addr);
1013 }
ths5fafdf22007-09-16 21:08:06 +00001014 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001015 (prot & PAGE_BITS) & ~PAGE_WRITE);
1016#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001017 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001018 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001019#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001020 }
bellard9fa3e852004-01-04 18:06:42 +00001021#else
1022 /* if some code is already present, then the pages are already
1023 protected. So we handle the case where only the first TB is
1024 allocated in a physical page */
1025 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001026 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001027 }
1028#endif
bellardd720b932004-04-25 17:57:43 +00001029
1030#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001031}
1032
1033/* Allocate a new translation block. Flush the translation buffer if
1034 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001035TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001036{
1037 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001038
bellard26a5f132008-05-28 12:30:31 +00001039 if (nb_tbs >= code_gen_max_blocks ||
1040 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001041 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001042 tb = &tbs[nb_tbs++];
1043 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001044 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001045 return tb;
1046}
1047
bellard9fa3e852004-01-04 18:06:42 +00001048/* add a new TB and link it to the physical page tables. phys_page2 is
1049 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001050void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001051 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001052{
bellard9fa3e852004-01-04 18:06:42 +00001053 unsigned int h;
1054 TranslationBlock **ptb;
1055
pbrookc8a706f2008-06-02 16:16:42 +00001056 /* Grab the mmap lock to stop another thread invalidating this TB
1057 before we are done. */
1058 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001059 /* add in the physical hash table */
1060 h = tb_phys_hash_func(phys_pc);
1061 ptb = &tb_phys_hash[h];
1062 tb->phys_hash_next = *ptb;
1063 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001064
1065 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001066 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1067 if (phys_page2 != -1)
1068 tb_alloc_page(tb, 1, phys_page2);
1069 else
1070 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001071
bellardd4e81642003-05-25 16:46:15 +00001072 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1073 tb->jmp_next[0] = NULL;
1074 tb->jmp_next[1] = NULL;
1075
1076 /* init original jump addresses */
1077 if (tb->tb_next_offset[0] != 0xffff)
1078 tb_reset_jump(tb, 0);
1079 if (tb->tb_next_offset[1] != 0xffff)
1080 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001081
1082#ifdef DEBUG_TB_CHECK
1083 tb_page_check();
1084#endif
pbrookc8a706f2008-06-02 16:16:42 +00001085 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001086}
1087
bellarda513fe12003-05-27 23:29:48 +00001088/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1089 tb[1].tc_ptr. Return NULL if not found */
1090TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1091{
1092 int m_min, m_max, m;
1093 unsigned long v;
1094 TranslationBlock *tb;
1095
1096 if (nb_tbs <= 0)
1097 return NULL;
1098 if (tc_ptr < (unsigned long)code_gen_buffer ||
1099 tc_ptr >= (unsigned long)code_gen_ptr)
1100 return NULL;
1101 /* binary search (cf Knuth) */
1102 m_min = 0;
1103 m_max = nb_tbs - 1;
1104 while (m_min <= m_max) {
1105 m = (m_min + m_max) >> 1;
1106 tb = &tbs[m];
1107 v = (unsigned long)tb->tc_ptr;
1108 if (v == tc_ptr)
1109 return tb;
1110 else if (tc_ptr < v) {
1111 m_max = m - 1;
1112 } else {
1113 m_min = m + 1;
1114 }
ths5fafdf22007-09-16 21:08:06 +00001115 }
bellarda513fe12003-05-27 23:29:48 +00001116 return &tbs[m_max];
1117}
bellard75012672003-06-21 13:11:07 +00001118
bellardea041c02003-06-25 16:16:50 +00001119static void tb_reset_jump_recursive(TranslationBlock *tb);
1120
1121static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1122{
1123 TranslationBlock *tb1, *tb_next, **ptb;
1124 unsigned int n1;
1125
1126 tb1 = tb->jmp_next[n];
1127 if (tb1 != NULL) {
1128 /* find head of list */
1129 for(;;) {
1130 n1 = (long)tb1 & 3;
1131 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1132 if (n1 == 2)
1133 break;
1134 tb1 = tb1->jmp_next[n1];
1135 }
1136 /* we are now sure now that tb jumps to tb1 */
1137 tb_next = tb1;
1138
1139 /* remove tb from the jmp_first list */
1140 ptb = &tb_next->jmp_first;
1141 for(;;) {
1142 tb1 = *ptb;
1143 n1 = (long)tb1 & 3;
1144 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1145 if (n1 == n && tb1 == tb)
1146 break;
1147 ptb = &tb1->jmp_next[n1];
1148 }
1149 *ptb = tb->jmp_next[n];
1150 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001151
bellardea041c02003-06-25 16:16:50 +00001152 /* suppress the jump to next tb in generated code */
1153 tb_reset_jump(tb, n);
1154
bellard01243112004-01-04 15:48:17 +00001155 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001156 tb_reset_jump_recursive(tb_next);
1157 }
1158}
1159
1160static void tb_reset_jump_recursive(TranslationBlock *tb)
1161{
1162 tb_reset_jump_recursive2(tb, 0);
1163 tb_reset_jump_recursive2(tb, 1);
1164}
1165
bellard1fddef42005-04-17 19:16:13 +00001166#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001167static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1168{
j_mayer9b3c35e2007-04-07 11:21:28 +00001169 target_phys_addr_t addr;
1170 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001171 ram_addr_t ram_addr;
1172 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001173
pbrookc2f07f82006-04-08 17:14:56 +00001174 addr = cpu_get_phys_page_debug(env, pc);
1175 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1176 if (!p) {
1177 pd = IO_MEM_UNASSIGNED;
1178 } else {
1179 pd = p->phys_offset;
1180 }
1181 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001182 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001183}
bellardc27004e2005-01-03 23:35:10 +00001184#endif
bellardd720b932004-04-25 17:57:43 +00001185
pbrook6658ffb2007-03-16 23:58:11 +00001186/* Add a watchpoint. */
1187int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1188{
1189 int i;
1190
1191 for (i = 0; i < env->nb_watchpoints; i++) {
1192 if (addr == env->watchpoint[i].vaddr)
1193 return 0;
1194 }
1195 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1196 return -1;
1197
1198 i = env->nb_watchpoints++;
1199 env->watchpoint[i].vaddr = addr;
1200 tlb_flush_page(env, addr);
1201 /* FIXME: This flush is needed because of the hack to make memory ops
1202 terminate the TB. It can be removed once the proper IO trap and
1203 re-execute bits are in. */
1204 tb_flush(env);
1205 return i;
1206}
1207
1208/* Remove a watchpoint. */
1209int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1210{
1211 int i;
1212
1213 for (i = 0; i < env->nb_watchpoints; i++) {
1214 if (addr == env->watchpoint[i].vaddr) {
1215 env->nb_watchpoints--;
1216 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1217 tlb_flush_page(env, addr);
1218 return 0;
1219 }
1220 }
1221 return -1;
1222}
1223
edgar_igl7d03f822008-05-17 18:58:29 +00001224/* Remove all watchpoints. */
1225void cpu_watchpoint_remove_all(CPUState *env) {
1226 int i;
1227
1228 for (i = 0; i < env->nb_watchpoints; i++) {
1229 tlb_flush_page(env, env->watchpoint[i].vaddr);
1230 }
1231 env->nb_watchpoints = 0;
1232}
1233
bellardc33a3462003-07-29 20:50:33 +00001234/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1235 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001236int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001237{
bellard1fddef42005-04-17 19:16:13 +00001238#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001239 int i;
ths3b46e622007-09-17 08:09:54 +00001240
bellard4c3a88a2003-07-26 12:06:08 +00001241 for(i = 0; i < env->nb_breakpoints; i++) {
1242 if (env->breakpoints[i] == pc)
1243 return 0;
1244 }
1245
1246 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1247 return -1;
1248 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001249
bellardd720b932004-04-25 17:57:43 +00001250 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001251 return 0;
1252#else
1253 return -1;
1254#endif
1255}
1256
edgar_igl7d03f822008-05-17 18:58:29 +00001257/* remove all breakpoints */
1258void cpu_breakpoint_remove_all(CPUState *env) {
1259#if defined(TARGET_HAS_ICE)
1260 int i;
1261 for(i = 0; i < env->nb_breakpoints; i++) {
1262 breakpoint_invalidate(env, env->breakpoints[i]);
1263 }
1264 env->nb_breakpoints = 0;
1265#endif
1266}
1267
bellard4c3a88a2003-07-26 12:06:08 +00001268/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001269int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001270{
bellard1fddef42005-04-17 19:16:13 +00001271#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001272 int i;
1273 for(i = 0; i < env->nb_breakpoints; i++) {
1274 if (env->breakpoints[i] == pc)
1275 goto found;
1276 }
1277 return -1;
1278 found:
bellard4c3a88a2003-07-26 12:06:08 +00001279 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001280 if (i < env->nb_breakpoints)
1281 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001282
1283 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001284 return 0;
1285#else
1286 return -1;
1287#endif
1288}
1289
bellardc33a3462003-07-29 20:50:33 +00001290/* enable or disable single step mode. EXCP_DEBUG is returned by the
1291 CPU loop after each instruction */
1292void cpu_single_step(CPUState *env, int enabled)
1293{
bellard1fddef42005-04-17 19:16:13 +00001294#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001295 if (env->singlestep_enabled != enabled) {
1296 env->singlestep_enabled = enabled;
1297 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001298 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001299 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001300 }
1301#endif
1302}
1303
bellard34865132003-10-05 14:28:56 +00001304/* enable or disable low levels log */
1305void cpu_set_log(int log_flags)
1306{
1307 loglevel = log_flags;
1308 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001309 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001310 if (!logfile) {
1311 perror(logfilename);
1312 _exit(1);
1313 }
bellard9fa3e852004-01-04 18:06:42 +00001314#if !defined(CONFIG_SOFTMMU)
1315 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1316 {
1317 static uint8_t logfile_buf[4096];
1318 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1319 }
1320#else
bellard34865132003-10-05 14:28:56 +00001321 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001322#endif
pbrooke735b912007-06-30 13:53:24 +00001323 log_append = 1;
1324 }
1325 if (!loglevel && logfile) {
1326 fclose(logfile);
1327 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001328 }
1329}
1330
1331void cpu_set_log_filename(const char *filename)
1332{
1333 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001334 if (logfile) {
1335 fclose(logfile);
1336 logfile = NULL;
1337 }
1338 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001339}
bellardc33a3462003-07-29 20:50:33 +00001340
bellard01243112004-01-04 15:48:17 +00001341/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001342void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001343{
pbrookd5975362008-06-07 20:50:51 +00001344#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001345 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001346 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001347#endif
bellard59817cc2004-02-16 22:01:13 +00001348
pbrookd5975362008-06-07 20:50:51 +00001349 /* FIXME: This is probably not threadsafe. A different thread could
1350 be in the mittle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001351 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001352#if defined(USE_NPTL)
1353 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1354 problem and hope the cpu will stop of its own accord. For userspace
1355 emulation this often isn't actually as bad as it sounds. Often
1356 signals are used primarily to interrupt blocking syscalls. */
1357#else
bellardea041c02003-06-25 16:16:50 +00001358 /* if the cpu is currently executing code, we must unlink it and
1359 all the potentially executing TB */
1360 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001361 if (tb && !testandset(&interrupt_lock)) {
1362 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001363 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001364 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001365 }
pbrookd5975362008-06-07 20:50:51 +00001366#endif
bellardea041c02003-06-25 16:16:50 +00001367}
1368
bellardb54ad042004-05-20 13:42:52 +00001369void cpu_reset_interrupt(CPUState *env, int mask)
1370{
1371 env->interrupt_request &= ~mask;
1372}
1373
bellardf193c792004-03-21 17:06:25 +00001374CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001375 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001376 "show generated host assembly code for each compiled TB" },
1377 { CPU_LOG_TB_IN_ASM, "in_asm",
1378 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001379 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001380 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001381 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001382 "show micro ops "
1383#ifdef TARGET_I386
1384 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001385#endif
blueswir1e01a1152008-03-14 17:37:11 +00001386 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001387 { CPU_LOG_INT, "int",
1388 "show interrupts/exceptions in short format" },
1389 { CPU_LOG_EXEC, "exec",
1390 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001391 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001392 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001393#ifdef TARGET_I386
1394 { CPU_LOG_PCALL, "pcall",
1395 "show protected mode far calls/returns/exceptions" },
1396#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001397#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001398 { CPU_LOG_IOPORT, "ioport",
1399 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001400#endif
bellardf193c792004-03-21 17:06:25 +00001401 { 0, NULL, NULL },
1402};
1403
1404static int cmp1(const char *s1, int n, const char *s2)
1405{
1406 if (strlen(s2) != n)
1407 return 0;
1408 return memcmp(s1, s2, n) == 0;
1409}
ths3b46e622007-09-17 08:09:54 +00001410
bellardf193c792004-03-21 17:06:25 +00001411/* takes a comma separated list of log masks. Return 0 if error. */
1412int cpu_str_to_log_mask(const char *str)
1413{
1414 CPULogItem *item;
1415 int mask;
1416 const char *p, *p1;
1417
1418 p = str;
1419 mask = 0;
1420 for(;;) {
1421 p1 = strchr(p, ',');
1422 if (!p1)
1423 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001424 if(cmp1(p,p1-p,"all")) {
1425 for(item = cpu_log_items; item->mask != 0; item++) {
1426 mask |= item->mask;
1427 }
1428 } else {
bellardf193c792004-03-21 17:06:25 +00001429 for(item = cpu_log_items; item->mask != 0; item++) {
1430 if (cmp1(p, p1 - p, item->name))
1431 goto found;
1432 }
1433 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001434 }
bellardf193c792004-03-21 17:06:25 +00001435 found:
1436 mask |= item->mask;
1437 if (*p1 != ',')
1438 break;
1439 p = p1 + 1;
1440 }
1441 return mask;
1442}
bellardea041c02003-06-25 16:16:50 +00001443
bellard75012672003-06-21 13:11:07 +00001444void cpu_abort(CPUState *env, const char *fmt, ...)
1445{
1446 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001447 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001448
1449 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001450 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001451 fprintf(stderr, "qemu: fatal: ");
1452 vfprintf(stderr, fmt, ap);
1453 fprintf(stderr, "\n");
1454#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001455 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1456#else
1457 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001458#endif
balrog924edca2007-06-10 14:07:13 +00001459 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001460 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001461 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001462 fprintf(logfile, "\n");
1463#ifdef TARGET_I386
1464 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1465#else
1466 cpu_dump_state(env, logfile, fprintf, 0);
1467#endif
balrog924edca2007-06-10 14:07:13 +00001468 fflush(logfile);
1469 fclose(logfile);
1470 }
pbrook493ae1f2007-11-23 16:53:59 +00001471 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001472 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001473 abort();
1474}
1475
thsc5be9f02007-02-28 20:20:53 +00001476CPUState *cpu_copy(CPUState *env)
1477{
ths01ba9812007-12-09 02:22:57 +00001478 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001479 /* preserve chaining and index */
1480 CPUState *next_cpu = new_env->next_cpu;
1481 int cpu_index = new_env->cpu_index;
1482 memcpy(new_env, env, sizeof(CPUState));
1483 new_env->next_cpu = next_cpu;
1484 new_env->cpu_index = cpu_index;
1485 return new_env;
1486}
1487
bellard01243112004-01-04 15:48:17 +00001488#if !defined(CONFIG_USER_ONLY)
1489
edgar_igl5c751e92008-05-06 08:44:21 +00001490static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1491{
1492 unsigned int i;
1493
1494 /* Discard jump cache entries for any tb which might potentially
1495 overlap the flushed page. */
1496 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1497 memset (&env->tb_jmp_cache[i], 0,
1498 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1499
1500 i = tb_jmp_cache_hash_page(addr);
1501 memset (&env->tb_jmp_cache[i], 0,
1502 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1503}
1504
bellardee8b7022004-02-03 23:35:10 +00001505/* NOTE: if flush_global is true, also flush global entries (not
1506 implemented yet) */
1507void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001508{
bellard33417e72003-08-10 21:47:01 +00001509 int i;
bellard01243112004-01-04 15:48:17 +00001510
bellard9fa3e852004-01-04 18:06:42 +00001511#if defined(DEBUG_TLB)
1512 printf("tlb_flush:\n");
1513#endif
bellard01243112004-01-04 15:48:17 +00001514 /* must reset current TB so that interrupts cannot modify the
1515 links while we are modifying them */
1516 env->current_tb = NULL;
1517
bellard33417e72003-08-10 21:47:01 +00001518 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001519 env->tlb_table[0][i].addr_read = -1;
1520 env->tlb_table[0][i].addr_write = -1;
1521 env->tlb_table[0][i].addr_code = -1;
1522 env->tlb_table[1][i].addr_read = -1;
1523 env->tlb_table[1][i].addr_write = -1;
1524 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001525#if (NB_MMU_MODES >= 3)
1526 env->tlb_table[2][i].addr_read = -1;
1527 env->tlb_table[2][i].addr_write = -1;
1528 env->tlb_table[2][i].addr_code = -1;
1529#if (NB_MMU_MODES == 4)
1530 env->tlb_table[3][i].addr_read = -1;
1531 env->tlb_table[3][i].addr_write = -1;
1532 env->tlb_table[3][i].addr_code = -1;
1533#endif
1534#endif
bellard33417e72003-08-10 21:47:01 +00001535 }
bellard9fa3e852004-01-04 18:06:42 +00001536
bellard8a40a182005-11-20 10:35:40 +00001537 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001538
1539#if !defined(CONFIG_SOFTMMU)
1540 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1541#endif
bellard0a962c02005-02-10 22:00:27 +00001542#ifdef USE_KQEMU
1543 if (env->kqemu_enabled) {
1544 kqemu_flush(env, flush_global);
1545 }
1546#endif
bellarde3db7222005-01-26 22:00:47 +00001547 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001548}
1549
bellard274da6b2004-05-20 21:56:27 +00001550static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001551{
ths5fafdf22007-09-16 21:08:06 +00001552 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001553 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001554 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001555 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001556 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001557 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1558 tlb_entry->addr_read = -1;
1559 tlb_entry->addr_write = -1;
1560 tlb_entry->addr_code = -1;
1561 }
bellard61382a52003-10-27 21:22:23 +00001562}
1563
bellard2e126692004-04-25 21:28:44 +00001564void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001565{
bellard8a40a182005-11-20 10:35:40 +00001566 int i;
bellard01243112004-01-04 15:48:17 +00001567
bellard9fa3e852004-01-04 18:06:42 +00001568#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001569 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001570#endif
bellard01243112004-01-04 15:48:17 +00001571 /* must reset current TB so that interrupts cannot modify the
1572 links while we are modifying them */
1573 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001574
bellard61382a52003-10-27 21:22:23 +00001575 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001576 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001577 tlb_flush_entry(&env->tlb_table[0][i], addr);
1578 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001579#if (NB_MMU_MODES >= 3)
1580 tlb_flush_entry(&env->tlb_table[2][i], addr);
1581#if (NB_MMU_MODES == 4)
1582 tlb_flush_entry(&env->tlb_table[3][i], addr);
1583#endif
1584#endif
bellard01243112004-01-04 15:48:17 +00001585
edgar_igl5c751e92008-05-06 08:44:21 +00001586 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001587
bellard01243112004-01-04 15:48:17 +00001588#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001589 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001590 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001591#endif
bellard0a962c02005-02-10 22:00:27 +00001592#ifdef USE_KQEMU
1593 if (env->kqemu_enabled) {
1594 kqemu_flush_page(env, addr);
1595 }
1596#endif
bellard9fa3e852004-01-04 18:06:42 +00001597}
1598
bellard9fa3e852004-01-04 18:06:42 +00001599/* update the TLBs so that writes to code in the virtual page 'addr'
1600 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001601static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001602{
ths5fafdf22007-09-16 21:08:06 +00001603 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001604 ram_addr + TARGET_PAGE_SIZE,
1605 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001606}
1607
bellard9fa3e852004-01-04 18:06:42 +00001608/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001609 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001610static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001611 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001612{
bellard3a7d9292005-08-21 09:26:42 +00001613 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001614}
1615
ths5fafdf22007-09-16 21:08:06 +00001616static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001617 unsigned long start, unsigned long length)
1618{
1619 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001620 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1621 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001622 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001623 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001624 }
1625 }
1626}
1627
bellard3a7d9292005-08-21 09:26:42 +00001628void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001629 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001630{
1631 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001632 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001633 int i, mask, len;
1634 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001635
1636 start &= TARGET_PAGE_MASK;
1637 end = TARGET_PAGE_ALIGN(end);
1638
1639 length = end - start;
1640 if (length == 0)
1641 return;
bellard0a962c02005-02-10 22:00:27 +00001642 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001643#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001644 /* XXX: should not depend on cpu context */
1645 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001646 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001647 ram_addr_t addr;
1648 addr = start;
1649 for(i = 0; i < len; i++) {
1650 kqemu_set_notdirty(env, addr);
1651 addr += TARGET_PAGE_SIZE;
1652 }
bellard3a7d9292005-08-21 09:26:42 +00001653 }
1654#endif
bellardf23db162005-08-21 19:12:28 +00001655 mask = ~dirty_flags;
1656 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1657 for(i = 0; i < len; i++)
1658 p[i] &= mask;
1659
bellard1ccde1c2004-02-06 19:46:14 +00001660 /* we modify the TLB cache so that the dirty bit will be set again
1661 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001662 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001663 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1664 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001665 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001666 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001667 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001668#if (NB_MMU_MODES >= 3)
1669 for(i = 0; i < CPU_TLB_SIZE; i++)
1670 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1671#if (NB_MMU_MODES == 4)
1672 for(i = 0; i < CPU_TLB_SIZE; i++)
1673 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1674#endif
1675#endif
bellard6a00d602005-11-21 23:25:50 +00001676 }
bellard59817cc2004-02-16 22:01:13 +00001677
1678#if !defined(CONFIG_SOFTMMU)
1679 /* XXX: this is expensive */
1680 {
1681 VirtPageDesc *p;
1682 int j;
1683 target_ulong addr;
1684
1685 for(i = 0; i < L1_SIZE; i++) {
1686 p = l1_virt_map[i];
1687 if (p) {
1688 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1689 for(j = 0; j < L2_SIZE; j++) {
1690 if (p->valid_tag == virt_valid_tag &&
1691 p->phys_addr >= start && p->phys_addr < end &&
1692 (p->prot & PROT_WRITE)) {
1693 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001694 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001695 p->prot & ~PROT_WRITE);
1696 }
1697 }
1698 addr += TARGET_PAGE_SIZE;
1699 p++;
1700 }
1701 }
1702 }
1703 }
1704#endif
bellard1ccde1c2004-02-06 19:46:14 +00001705}
1706
bellard3a7d9292005-08-21 09:26:42 +00001707static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1708{
1709 ram_addr_t ram_addr;
1710
bellard84b7b8e2005-11-28 21:19:04 +00001711 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001712 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001713 tlb_entry->addend - (unsigned long)phys_ram_base;
1714 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001715 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001716 }
1717 }
1718}
1719
1720/* update the TLB according to the current state of the dirty bits */
1721void cpu_tlb_update_dirty(CPUState *env)
1722{
1723 int i;
1724 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001725 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001726 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001727 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001728#if (NB_MMU_MODES >= 3)
1729 for(i = 0; i < CPU_TLB_SIZE; i++)
1730 tlb_update_dirty(&env->tlb_table[2][i]);
1731#if (NB_MMU_MODES == 4)
1732 for(i = 0; i < CPU_TLB_SIZE; i++)
1733 tlb_update_dirty(&env->tlb_table[3][i]);
1734#endif
1735#endif
bellard3a7d9292005-08-21 09:26:42 +00001736}
1737
ths5fafdf22007-09-16 21:08:06 +00001738static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001739 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001740{
1741 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001742 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1743 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001744 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001745 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001746 }
1747 }
1748}
1749
1750/* update the TLB corresponding to virtual page vaddr and phys addr
1751 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001752static inline void tlb_set_dirty(CPUState *env,
1753 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001754{
bellard1ccde1c2004-02-06 19:46:14 +00001755 int i;
1756
bellard1ccde1c2004-02-06 19:46:14 +00001757 addr &= TARGET_PAGE_MASK;
1758 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001759 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1760 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001761#if (NB_MMU_MODES >= 3)
1762 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1763#if (NB_MMU_MODES == 4)
1764 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1765#endif
1766#endif
bellard9fa3e852004-01-04 18:06:42 +00001767}
1768
bellard59817cc2004-02-16 22:01:13 +00001769/* add a new TLB entry. At most one entry for a given virtual address
1770 is permitted. Return 0 if OK or 2 if the page could not be mapped
1771 (can only happen in non SOFTMMU mode for I/O pages or pages
1772 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001773int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1774 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001775 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001776{
bellard92e873b2004-05-21 14:52:29 +00001777 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001778 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001779 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001780 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001781 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001782 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001783 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001784 int i;
bellard9fa3e852004-01-04 18:06:42 +00001785
bellard92e873b2004-05-21 14:52:29 +00001786 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001787 if (!p) {
1788 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001789 } else {
1790 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001791 }
1792#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001793 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1794 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001795#endif
1796
1797 ret = 0;
1798#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001799 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001800#endif
1801 {
bellard2a4188a2006-06-25 21:54:59 +00001802 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001803 /* IO memory case */
1804 address = vaddr | pd;
1805 addend = paddr;
1806 } else {
1807 /* standard memory */
1808 address = vaddr;
1809 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1810 }
pbrook6658ffb2007-03-16 23:58:11 +00001811
1812 /* Make accesses to pages with watchpoints go via the
1813 watchpoint trap routines. */
1814 for (i = 0; i < env->nb_watchpoints; i++) {
1815 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1816 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001817 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001818 address = vaddr | io_mem_watch;
1819 } else {
balrogd79acba2007-06-26 20:01:13 +00001820 env->watchpoint[i].addend = pd - paddr +
1821 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001822 /* TODO: Figure out how to make read watchpoints coexist
1823 with code. */
1824 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1825 }
1826 }
1827 }
balrogd79acba2007-06-26 20:01:13 +00001828
bellard90f18422005-07-24 10:17:31 +00001829 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001830 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001831 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001832 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001833 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001834 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001835 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001836 te->addr_read = -1;
1837 }
edgar_igl5c751e92008-05-06 08:44:21 +00001838
bellard84b7b8e2005-11-28 21:19:04 +00001839 if (prot & PAGE_EXEC) {
1840 te->addr_code = address;
1841 } else {
1842 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001843 }
bellard67b915a2004-03-31 23:37:16 +00001844 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001845 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001846 (pd & IO_MEM_ROMD)) {
1847 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001848 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001849 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001850 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001851 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001852 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001853 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001854 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001855 }
1856 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001857 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001858 }
1859 }
1860#if !defined(CONFIG_SOFTMMU)
1861 else {
1862 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1863 /* IO access: no mapping is done as it will be handled by the
1864 soft MMU */
1865 if (!(env->hflags & HF_SOFTMMU_MASK))
1866 ret = 2;
1867 } else {
1868 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001869
bellard59817cc2004-02-16 22:01:13 +00001870 if (vaddr >= MMAP_AREA_END) {
1871 ret = 2;
1872 } else {
1873 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001874 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001875#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001876 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001877#endif
ths5fafdf22007-09-16 21:08:06 +00001878 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001879 !cpu_physical_memory_is_dirty(pd))) {
1880 /* ROM: we do as if code was inside */
1881 /* if code is present, we only map as read only and save the
1882 original mapping */
1883 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001884
bellard90f18422005-07-24 10:17:31 +00001885 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001886 vp->phys_addr = pd;
1887 vp->prot = prot;
1888 vp->valid_tag = virt_valid_tag;
1889 prot &= ~PAGE_WRITE;
1890 }
bellard9fa3e852004-01-04 18:06:42 +00001891 }
ths5fafdf22007-09-16 21:08:06 +00001892 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001893 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1894 if (map_addr == MAP_FAILED) {
1895 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1896 paddr, vaddr);
1897 }
bellard9fa3e852004-01-04 18:06:42 +00001898 }
1899 }
1900 }
1901#endif
1902 return ret;
1903}
1904
1905/* called from signal handler: invalidate the code and unprotect the
1906 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001907int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001908{
1909#if !defined(CONFIG_SOFTMMU)
1910 VirtPageDesc *vp;
1911
1912#if defined(DEBUG_TLB)
1913 printf("page_unprotect: addr=0x%08x\n", addr);
1914#endif
1915 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001916
1917 /* if it is not mapped, no need to worry here */
1918 if (addr >= MMAP_AREA_END)
1919 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001920 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1921 if (!vp)
1922 return 0;
1923 /* NOTE: in this case, validate_tag is _not_ tested as it
1924 validates only the code TLB */
1925 if (vp->valid_tag != virt_valid_tag)
1926 return 0;
1927 if (!(vp->prot & PAGE_WRITE))
1928 return 0;
1929#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001930 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001931 addr, vp->phys_addr, vp->prot);
1932#endif
bellard59817cc2004-02-16 22:01:13 +00001933 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1934 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1935 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001936 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001937 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001938 /* flush the code inside */
1939 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001940 return 1;
1941#else
1942 return 0;
1943#endif
bellard33417e72003-08-10 21:47:01 +00001944}
1945
bellard01243112004-01-04 15:48:17 +00001946#else
1947
bellardee8b7022004-02-03 23:35:10 +00001948void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001949{
1950}
1951
bellard2e126692004-04-25 21:28:44 +00001952void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001953{
1954}
1955
ths5fafdf22007-09-16 21:08:06 +00001956int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1957 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001958 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001959{
bellard9fa3e852004-01-04 18:06:42 +00001960 return 0;
1961}
bellard33417e72003-08-10 21:47:01 +00001962
bellard9fa3e852004-01-04 18:06:42 +00001963/* dump memory mappings */
1964void page_dump(FILE *f)
1965{
1966 unsigned long start, end;
1967 int i, j, prot, prot1;
1968 PageDesc *p;
1969
1970 fprintf(f, "%-8s %-8s %-8s %s\n",
1971 "start", "end", "size", "prot");
1972 start = -1;
1973 end = -1;
1974 prot = 0;
1975 for(i = 0; i <= L1_SIZE; i++) {
1976 if (i < L1_SIZE)
1977 p = l1_map[i];
1978 else
1979 p = NULL;
1980 for(j = 0;j < L2_SIZE; j++) {
1981 if (!p)
1982 prot1 = 0;
1983 else
1984 prot1 = p[j].flags;
1985 if (prot1 != prot) {
1986 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1987 if (start != -1) {
1988 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001989 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001990 prot & PAGE_READ ? 'r' : '-',
1991 prot & PAGE_WRITE ? 'w' : '-',
1992 prot & PAGE_EXEC ? 'x' : '-');
1993 }
1994 if (prot1 != 0)
1995 start = end;
1996 else
1997 start = -1;
1998 prot = prot1;
1999 }
2000 if (!p)
2001 break;
2002 }
bellard33417e72003-08-10 21:47:01 +00002003 }
bellard33417e72003-08-10 21:47:01 +00002004}
2005
pbrook53a59602006-03-25 19:31:22 +00002006int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002007{
bellard9fa3e852004-01-04 18:06:42 +00002008 PageDesc *p;
2009
2010 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002011 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002012 return 0;
2013 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002014}
2015
bellard9fa3e852004-01-04 18:06:42 +00002016/* modify the flags of a page and invalidate the code if
2017 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2018 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002019void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002020{
2021 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002022 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002023
pbrookc8a706f2008-06-02 16:16:42 +00002024 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002025 start = start & TARGET_PAGE_MASK;
2026 end = TARGET_PAGE_ALIGN(end);
2027 if (flags & PAGE_WRITE)
2028 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002029 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2030 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
2031 /* if the write protection is set, then we invalidate the code
2032 inside */
ths5fafdf22007-09-16 21:08:06 +00002033 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002034 (flags & PAGE_WRITE) &&
2035 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002036 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002037 }
2038 p->flags = flags;
2039 }
bellard9fa3e852004-01-04 18:06:42 +00002040}
2041
ths3d97b402007-11-02 19:02:07 +00002042int page_check_range(target_ulong start, target_ulong len, int flags)
2043{
2044 PageDesc *p;
2045 target_ulong end;
2046 target_ulong addr;
2047
2048 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2049 start = start & TARGET_PAGE_MASK;
2050
2051 if( end < start )
2052 /* we've wrapped around */
2053 return -1;
2054 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2055 p = page_find(addr >> TARGET_PAGE_BITS);
2056 if( !p )
2057 return -1;
2058 if( !(p->flags & PAGE_VALID) )
2059 return -1;
2060
bellarddae32702007-11-14 10:51:00 +00002061 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002062 return -1;
bellarddae32702007-11-14 10:51:00 +00002063 if (flags & PAGE_WRITE) {
2064 if (!(p->flags & PAGE_WRITE_ORG))
2065 return -1;
2066 /* unprotect the page if it was put read-only because it
2067 contains translated code */
2068 if (!(p->flags & PAGE_WRITE)) {
2069 if (!page_unprotect(addr, 0, NULL))
2070 return -1;
2071 }
2072 return 0;
2073 }
ths3d97b402007-11-02 19:02:07 +00002074 }
2075 return 0;
2076}
2077
bellard9fa3e852004-01-04 18:06:42 +00002078/* called from signal handler: invalidate the code and unprotect the
2079 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002080int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002081{
2082 unsigned int page_index, prot, pindex;
2083 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002084 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002085
pbrookc8a706f2008-06-02 16:16:42 +00002086 /* Technically this isn't safe inside a signal handler. However we
2087 know this only ever happens in a synchronous SEGV handler, so in
2088 practice it seems to be ok. */
2089 mmap_lock();
2090
bellard83fb7ad2004-07-05 21:25:26 +00002091 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002092 page_index = host_start >> TARGET_PAGE_BITS;
2093 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002094 if (!p1) {
2095 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002096 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002097 }
bellard83fb7ad2004-07-05 21:25:26 +00002098 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002099 p = p1;
2100 prot = 0;
2101 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2102 prot |= p->flags;
2103 p++;
2104 }
2105 /* if the page was really writable, then we change its
2106 protection back to writable */
2107 if (prot & PAGE_WRITE_ORG) {
2108 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2109 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002110 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002111 (prot & PAGE_BITS) | PAGE_WRITE);
2112 p1[pindex].flags |= PAGE_WRITE;
2113 /* and since the content will be modified, we must invalidate
2114 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002115 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002116#ifdef DEBUG_TB_CHECK
2117 tb_invalidate_check(address);
2118#endif
pbrookc8a706f2008-06-02 16:16:42 +00002119 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002120 return 1;
2121 }
2122 }
pbrookc8a706f2008-06-02 16:16:42 +00002123 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002124 return 0;
2125}
2126
bellard6a00d602005-11-21 23:25:50 +00002127static inline void tlb_set_dirty(CPUState *env,
2128 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002129{
2130}
bellard9fa3e852004-01-04 18:06:42 +00002131#endif /* defined(CONFIG_USER_ONLY) */
2132
blueswir1db7b5422007-05-26 17:36:03 +00002133static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002134 ram_addr_t memory);
2135static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2136 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002137#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2138 need_subpage) \
2139 do { \
2140 if (addr > start_addr) \
2141 start_addr2 = 0; \
2142 else { \
2143 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2144 if (start_addr2 > 0) \
2145 need_subpage = 1; \
2146 } \
2147 \
blueswir149e9fba2007-05-30 17:25:06 +00002148 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002149 end_addr2 = TARGET_PAGE_SIZE - 1; \
2150 else { \
2151 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2152 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2153 need_subpage = 1; \
2154 } \
2155 } while (0)
2156
bellard33417e72003-08-10 21:47:01 +00002157/* register physical memory. 'size' must be a multiple of the target
2158 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2159 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002160void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002161 ram_addr_t size,
2162 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002163{
bellard108c49b2005-07-24 12:55:09 +00002164 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002165 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002166 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002167 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002168 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002169
bellardda260242008-05-30 20:48:25 +00002170#ifdef USE_KQEMU
2171 /* XXX: should not depend on cpu context */
2172 env = first_cpu;
2173 if (env->kqemu_enabled) {
2174 kqemu_set_phys_mem(start_addr, size, phys_offset);
2175 }
2176#endif
bellard5fd386f2004-05-23 21:11:22 +00002177 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002178 end_addr = start_addr + (target_phys_addr_t)size;
2179 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002180 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2181 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002182 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002183 target_phys_addr_t start_addr2, end_addr2;
2184 int need_subpage = 0;
2185
2186 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2187 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002188 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002189 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2190 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2191 &p->phys_offset, orig_memory);
2192 } else {
2193 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2194 >> IO_MEM_SHIFT];
2195 }
2196 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2197 } else {
2198 p->phys_offset = phys_offset;
2199 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2200 (phys_offset & IO_MEM_ROMD))
2201 phys_offset += TARGET_PAGE_SIZE;
2202 }
2203 } else {
2204 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2205 p->phys_offset = phys_offset;
2206 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2207 (phys_offset & IO_MEM_ROMD))
2208 phys_offset += TARGET_PAGE_SIZE;
2209 else {
2210 target_phys_addr_t start_addr2, end_addr2;
2211 int need_subpage = 0;
2212
2213 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2214 end_addr2, need_subpage);
2215
blueswir14254fab2008-01-01 16:57:19 +00002216 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002217 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2218 &p->phys_offset, IO_MEM_UNASSIGNED);
2219 subpage_register(subpage, start_addr2, end_addr2,
2220 phys_offset);
2221 }
2222 }
2223 }
bellard33417e72003-08-10 21:47:01 +00002224 }
ths3b46e622007-09-17 08:09:54 +00002225
bellard9d420372006-06-25 22:25:22 +00002226 /* since each CPU stores ram addresses in its TLB cache, we must
2227 reset the modified entries */
2228 /* XXX: slow ! */
2229 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2230 tlb_flush(env, 1);
2231 }
bellard33417e72003-08-10 21:47:01 +00002232}
2233
bellardba863452006-09-24 18:41:10 +00002234/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002235ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002236{
2237 PhysPageDesc *p;
2238
2239 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2240 if (!p)
2241 return IO_MEM_UNASSIGNED;
2242 return p->phys_offset;
2243}
2244
bellarde9a1ab12007-02-08 23:08:38 +00002245/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002246ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002247{
2248 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002249 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002250 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2251 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002252 abort();
2253 }
2254 addr = phys_ram_alloc_offset;
2255 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2256 return addr;
2257}
2258
2259void qemu_ram_free(ram_addr_t addr)
2260{
2261}
2262
bellarda4193c82004-06-03 14:01:43 +00002263static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002264{
pbrook67d3b952006-12-18 05:03:52 +00002265#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002266 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002267#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002268#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002269 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002270#elif TARGET_CRIS
2271 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002272#endif
bellard33417e72003-08-10 21:47:01 +00002273 return 0;
2274}
2275
bellarda4193c82004-06-03 14:01:43 +00002276static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002277{
pbrook67d3b952006-12-18 05:03:52 +00002278#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002279 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002280#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002281#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002282 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002283#elif TARGET_CRIS
2284 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002285#endif
bellard33417e72003-08-10 21:47:01 +00002286}
2287
2288static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2289 unassigned_mem_readb,
2290 unassigned_mem_readb,
2291 unassigned_mem_readb,
2292};
2293
2294static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2295 unassigned_mem_writeb,
2296 unassigned_mem_writeb,
2297 unassigned_mem_writeb,
2298};
2299
bellarda4193c82004-06-03 14:01:43 +00002300static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002301{
bellard3a7d9292005-08-21 09:26:42 +00002302 unsigned long ram_addr;
2303 int dirty_flags;
2304 ram_addr = addr - (unsigned long)phys_ram_base;
2305 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2306 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2307#if !defined(CONFIG_USER_ONLY)
2308 tb_invalidate_phys_page_fast(ram_addr, 1);
2309 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2310#endif
2311 }
bellardc27004e2005-01-03 23:35:10 +00002312 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002313#ifdef USE_KQEMU
2314 if (cpu_single_env->kqemu_enabled &&
2315 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2316 kqemu_modify_page(cpu_single_env, ram_addr);
2317#endif
bellardf23db162005-08-21 19:12:28 +00002318 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2319 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2320 /* we remove the notdirty callback only if the code has been
2321 flushed */
2322 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002323 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002324}
2325
bellarda4193c82004-06-03 14:01:43 +00002326static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002327{
bellard3a7d9292005-08-21 09:26:42 +00002328 unsigned long ram_addr;
2329 int dirty_flags;
2330 ram_addr = addr - (unsigned long)phys_ram_base;
2331 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2332 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2333#if !defined(CONFIG_USER_ONLY)
2334 tb_invalidate_phys_page_fast(ram_addr, 2);
2335 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2336#endif
2337 }
bellardc27004e2005-01-03 23:35:10 +00002338 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002339#ifdef USE_KQEMU
2340 if (cpu_single_env->kqemu_enabled &&
2341 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2342 kqemu_modify_page(cpu_single_env, ram_addr);
2343#endif
bellardf23db162005-08-21 19:12:28 +00002344 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2345 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2346 /* we remove the notdirty callback only if the code has been
2347 flushed */
2348 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002349 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002350}
2351
bellarda4193c82004-06-03 14:01:43 +00002352static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002353{
bellard3a7d9292005-08-21 09:26:42 +00002354 unsigned long ram_addr;
2355 int dirty_flags;
2356 ram_addr = addr - (unsigned long)phys_ram_base;
2357 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2358 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2359#if !defined(CONFIG_USER_ONLY)
2360 tb_invalidate_phys_page_fast(ram_addr, 4);
2361 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2362#endif
2363 }
bellardc27004e2005-01-03 23:35:10 +00002364 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002365#ifdef USE_KQEMU
2366 if (cpu_single_env->kqemu_enabled &&
2367 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2368 kqemu_modify_page(cpu_single_env, ram_addr);
2369#endif
bellardf23db162005-08-21 19:12:28 +00002370 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2371 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2372 /* we remove the notdirty callback only if the code has been
2373 flushed */
2374 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002375 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002376}
2377
bellard3a7d9292005-08-21 09:26:42 +00002378static CPUReadMemoryFunc *error_mem_read[3] = {
2379 NULL, /* never used */
2380 NULL, /* never used */
2381 NULL, /* never used */
2382};
2383
bellard1ccde1c2004-02-06 19:46:14 +00002384static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2385 notdirty_mem_writeb,
2386 notdirty_mem_writew,
2387 notdirty_mem_writel,
2388};
2389
pbrook6658ffb2007-03-16 23:58:11 +00002390#if defined(CONFIG_SOFTMMU)
2391/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2392 so these check for a hit then pass through to the normal out-of-line
2393 phys routines. */
2394static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2395{
2396 return ldub_phys(addr);
2397}
2398
2399static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2400{
2401 return lduw_phys(addr);
2402}
2403
2404static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2405{
2406 return ldl_phys(addr);
2407}
2408
2409/* Generate a debug exception if a watchpoint has been hit.
2410 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002411 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002412static target_ulong check_watchpoint(target_phys_addr_t addr)
2413{
2414 CPUState *env = cpu_single_env;
2415 target_ulong watch;
2416 target_ulong retaddr;
2417 int i;
2418
2419 retaddr = addr;
2420 for (i = 0; i < env->nb_watchpoints; i++) {
2421 watch = env->watchpoint[i].vaddr;
2422 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002423 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002424 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2425 cpu_single_env->watchpoint_hit = i + 1;
2426 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2427 break;
2428 }
2429 }
2430 }
2431 return retaddr;
2432}
2433
2434static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2435 uint32_t val)
2436{
2437 addr = check_watchpoint(addr);
2438 stb_phys(addr, val);
2439}
2440
2441static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2442 uint32_t val)
2443{
2444 addr = check_watchpoint(addr);
2445 stw_phys(addr, val);
2446}
2447
2448static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2449 uint32_t val)
2450{
2451 addr = check_watchpoint(addr);
2452 stl_phys(addr, val);
2453}
2454
2455static CPUReadMemoryFunc *watch_mem_read[3] = {
2456 watch_mem_readb,
2457 watch_mem_readw,
2458 watch_mem_readl,
2459};
2460
2461static CPUWriteMemoryFunc *watch_mem_write[3] = {
2462 watch_mem_writeb,
2463 watch_mem_writew,
2464 watch_mem_writel,
2465};
2466#endif
2467
blueswir1db7b5422007-05-26 17:36:03 +00002468static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2469 unsigned int len)
2470{
blueswir1db7b5422007-05-26 17:36:03 +00002471 uint32_t ret;
2472 unsigned int idx;
2473
2474 idx = SUBPAGE_IDX(addr - mmio->base);
2475#if defined(DEBUG_SUBPAGE)
2476 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2477 mmio, len, addr, idx);
2478#endif
blueswir13ee89922008-01-02 19:45:26 +00002479 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002480
2481 return ret;
2482}
2483
2484static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2485 uint32_t value, unsigned int len)
2486{
blueswir1db7b5422007-05-26 17:36:03 +00002487 unsigned int idx;
2488
2489 idx = SUBPAGE_IDX(addr - mmio->base);
2490#if defined(DEBUG_SUBPAGE)
2491 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2492 mmio, len, addr, idx, value);
2493#endif
blueswir13ee89922008-01-02 19:45:26 +00002494 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002495}
2496
2497static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2498{
2499#if defined(DEBUG_SUBPAGE)
2500 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2501#endif
2502
2503 return subpage_readlen(opaque, addr, 0);
2504}
2505
2506static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2507 uint32_t value)
2508{
2509#if defined(DEBUG_SUBPAGE)
2510 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2511#endif
2512 subpage_writelen(opaque, addr, value, 0);
2513}
2514
2515static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2516{
2517#if defined(DEBUG_SUBPAGE)
2518 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2519#endif
2520
2521 return subpage_readlen(opaque, addr, 1);
2522}
2523
2524static void subpage_writew (void *opaque, target_phys_addr_t addr,
2525 uint32_t value)
2526{
2527#if defined(DEBUG_SUBPAGE)
2528 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2529#endif
2530 subpage_writelen(opaque, addr, value, 1);
2531}
2532
2533static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2534{
2535#if defined(DEBUG_SUBPAGE)
2536 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2537#endif
2538
2539 return subpage_readlen(opaque, addr, 2);
2540}
2541
2542static void subpage_writel (void *opaque,
2543 target_phys_addr_t addr, uint32_t value)
2544{
2545#if defined(DEBUG_SUBPAGE)
2546 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2547#endif
2548 subpage_writelen(opaque, addr, value, 2);
2549}
2550
2551static CPUReadMemoryFunc *subpage_read[] = {
2552 &subpage_readb,
2553 &subpage_readw,
2554 &subpage_readl,
2555};
2556
2557static CPUWriteMemoryFunc *subpage_write[] = {
2558 &subpage_writeb,
2559 &subpage_writew,
2560 &subpage_writel,
2561};
2562
2563static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002564 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002565{
2566 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002567 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002568
2569 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2570 return -1;
2571 idx = SUBPAGE_IDX(start);
2572 eidx = SUBPAGE_IDX(end);
2573#if defined(DEBUG_SUBPAGE)
2574 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2575 mmio, start, end, idx, eidx, memory);
2576#endif
2577 memory >>= IO_MEM_SHIFT;
2578 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002579 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002580 if (io_mem_read[memory][i]) {
2581 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2582 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2583 }
2584 if (io_mem_write[memory][i]) {
2585 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2586 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2587 }
blueswir14254fab2008-01-01 16:57:19 +00002588 }
blueswir1db7b5422007-05-26 17:36:03 +00002589 }
2590
2591 return 0;
2592}
2593
aurel3200f82b82008-04-27 21:12:55 +00002594static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2595 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002596{
2597 subpage_t *mmio;
2598 int subpage_memory;
2599
2600 mmio = qemu_mallocz(sizeof(subpage_t));
2601 if (mmio != NULL) {
2602 mmio->base = base;
2603 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2604#if defined(DEBUG_SUBPAGE)
2605 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2606 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2607#endif
2608 *phys = subpage_memory | IO_MEM_SUBPAGE;
2609 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2610 }
2611
2612 return mmio;
2613}
2614
bellard33417e72003-08-10 21:47:01 +00002615static void io_mem_init(void)
2616{
bellard3a7d9292005-08-21 09:26:42 +00002617 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002618 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002619 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002620 io_mem_nb = 5;
2621
pbrook6658ffb2007-03-16 23:58:11 +00002622#if defined(CONFIG_SOFTMMU)
2623 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2624 watch_mem_write, NULL);
2625#endif
bellard1ccde1c2004-02-06 19:46:14 +00002626 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002627 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002628 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002629}
2630
2631/* mem_read and mem_write are arrays of functions containing the
2632 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002633 2). Functions can be omitted with a NULL function pointer. The
2634 registered functions may be modified dynamically later.
2635 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002636 modified. If it is zero, a new io zone is allocated. The return
2637 value can be used with cpu_register_physical_memory(). (-1) is
2638 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002639int cpu_register_io_memory(int io_index,
2640 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002641 CPUWriteMemoryFunc **mem_write,
2642 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002643{
blueswir14254fab2008-01-01 16:57:19 +00002644 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002645
2646 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002647 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002648 return -1;
2649 io_index = io_mem_nb++;
2650 } else {
2651 if (io_index >= IO_MEM_NB_ENTRIES)
2652 return -1;
2653 }
bellardb5ff1b32005-11-26 10:38:39 +00002654
bellard33417e72003-08-10 21:47:01 +00002655 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002656 if (!mem_read[i] || !mem_write[i])
2657 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002658 io_mem_read[io_index][i] = mem_read[i];
2659 io_mem_write[io_index][i] = mem_write[i];
2660 }
bellarda4193c82004-06-03 14:01:43 +00002661 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002662 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002663}
bellard61382a52003-10-27 21:22:23 +00002664
bellard8926b512004-10-10 15:14:20 +00002665CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2666{
2667 return io_mem_write[io_index >> IO_MEM_SHIFT];
2668}
2669
2670CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2671{
2672 return io_mem_read[io_index >> IO_MEM_SHIFT];
2673}
2674
bellard13eb76e2004-01-24 15:23:36 +00002675/* physical memory access (slow version, mainly for debug) */
2676#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002677void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002678 int len, int is_write)
2679{
2680 int l, flags;
2681 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002682 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002683
2684 while (len > 0) {
2685 page = addr & TARGET_PAGE_MASK;
2686 l = (page + TARGET_PAGE_SIZE) - addr;
2687 if (l > len)
2688 l = len;
2689 flags = page_get_flags(page);
2690 if (!(flags & PAGE_VALID))
2691 return;
2692 if (is_write) {
2693 if (!(flags & PAGE_WRITE))
2694 return;
bellard579a97f2007-11-11 14:26:47 +00002695 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002696 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002697 /* FIXME - should this return an error rather than just fail? */
2698 return;
aurel3272fb7da2008-04-27 23:53:45 +00002699 memcpy(p, buf, l);
2700 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002701 } else {
2702 if (!(flags & PAGE_READ))
2703 return;
bellard579a97f2007-11-11 14:26:47 +00002704 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002705 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002706 /* FIXME - should this return an error rather than just fail? */
2707 return;
aurel3272fb7da2008-04-27 23:53:45 +00002708 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002709 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002710 }
2711 len -= l;
2712 buf += l;
2713 addr += l;
2714 }
2715}
bellard8df1cd02005-01-28 22:37:22 +00002716
bellard13eb76e2004-01-24 15:23:36 +00002717#else
ths5fafdf22007-09-16 21:08:06 +00002718void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002719 int len, int is_write)
2720{
2721 int l, io_index;
2722 uint8_t *ptr;
2723 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002724 target_phys_addr_t page;
2725 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002726 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002727
bellard13eb76e2004-01-24 15:23:36 +00002728 while (len > 0) {
2729 page = addr & TARGET_PAGE_MASK;
2730 l = (page + TARGET_PAGE_SIZE) - addr;
2731 if (l > len)
2732 l = len;
bellard92e873b2004-05-21 14:52:29 +00002733 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002734 if (!p) {
2735 pd = IO_MEM_UNASSIGNED;
2736 } else {
2737 pd = p->phys_offset;
2738 }
ths3b46e622007-09-17 08:09:54 +00002739
bellard13eb76e2004-01-24 15:23:36 +00002740 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002741 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002742 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002743 /* XXX: could force cpu_single_env to NULL to avoid
2744 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002745 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002746 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002747 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002748 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002749 l = 4;
2750 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002751 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002752 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002753 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002754 l = 2;
2755 } else {
bellard1c213d12005-09-03 10:49:04 +00002756 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002757 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002758 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002759 l = 1;
2760 }
2761 } else {
bellardb448f2f2004-02-25 23:24:04 +00002762 unsigned long addr1;
2763 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002764 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002765 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002766 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002767 if (!cpu_physical_memory_is_dirty(addr1)) {
2768 /* invalidate code */
2769 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2770 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002771 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002772 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002773 }
bellard13eb76e2004-01-24 15:23:36 +00002774 }
2775 } else {
ths5fafdf22007-09-16 21:08:06 +00002776 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002777 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002778 /* I/O case */
2779 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2780 if (l >= 4 && ((addr & 3) == 0)) {
2781 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002782 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002783 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002784 l = 4;
2785 } else if (l >= 2 && ((addr & 1) == 0)) {
2786 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002787 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002788 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002789 l = 2;
2790 } else {
bellard1c213d12005-09-03 10:49:04 +00002791 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002792 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002793 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002794 l = 1;
2795 }
2796 } else {
2797 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002798 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002799 (addr & ~TARGET_PAGE_MASK);
2800 memcpy(buf, ptr, l);
2801 }
2802 }
2803 len -= l;
2804 buf += l;
2805 addr += l;
2806 }
2807}
bellard8df1cd02005-01-28 22:37:22 +00002808
bellardd0ecd2a2006-04-23 17:14:48 +00002809/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002810void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002811 const uint8_t *buf, int len)
2812{
2813 int l;
2814 uint8_t *ptr;
2815 target_phys_addr_t page;
2816 unsigned long pd;
2817 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002818
bellardd0ecd2a2006-04-23 17:14:48 +00002819 while (len > 0) {
2820 page = addr & TARGET_PAGE_MASK;
2821 l = (page + TARGET_PAGE_SIZE) - addr;
2822 if (l > len)
2823 l = len;
2824 p = phys_page_find(page >> TARGET_PAGE_BITS);
2825 if (!p) {
2826 pd = IO_MEM_UNASSIGNED;
2827 } else {
2828 pd = p->phys_offset;
2829 }
ths3b46e622007-09-17 08:09:54 +00002830
bellardd0ecd2a2006-04-23 17:14:48 +00002831 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002832 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2833 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002834 /* do nothing */
2835 } else {
2836 unsigned long addr1;
2837 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2838 /* ROM/RAM case */
2839 ptr = phys_ram_base + addr1;
2840 memcpy(ptr, buf, l);
2841 }
2842 len -= l;
2843 buf += l;
2844 addr += l;
2845 }
2846}
2847
2848
bellard8df1cd02005-01-28 22:37:22 +00002849/* warning: addr must be aligned */
2850uint32_t ldl_phys(target_phys_addr_t addr)
2851{
2852 int io_index;
2853 uint8_t *ptr;
2854 uint32_t val;
2855 unsigned long pd;
2856 PhysPageDesc *p;
2857
2858 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2859 if (!p) {
2860 pd = IO_MEM_UNASSIGNED;
2861 } else {
2862 pd = p->phys_offset;
2863 }
ths3b46e622007-09-17 08:09:54 +00002864
ths5fafdf22007-09-16 21:08:06 +00002865 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002866 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002867 /* I/O case */
2868 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2869 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2870 } else {
2871 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002872 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002873 (addr & ~TARGET_PAGE_MASK);
2874 val = ldl_p(ptr);
2875 }
2876 return val;
2877}
2878
bellard84b7b8e2005-11-28 21:19:04 +00002879/* warning: addr must be aligned */
2880uint64_t ldq_phys(target_phys_addr_t addr)
2881{
2882 int io_index;
2883 uint8_t *ptr;
2884 uint64_t val;
2885 unsigned long pd;
2886 PhysPageDesc *p;
2887
2888 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2889 if (!p) {
2890 pd = IO_MEM_UNASSIGNED;
2891 } else {
2892 pd = p->phys_offset;
2893 }
ths3b46e622007-09-17 08:09:54 +00002894
bellard2a4188a2006-06-25 21:54:59 +00002895 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2896 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002897 /* I/O case */
2898 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2899#ifdef TARGET_WORDS_BIGENDIAN
2900 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2901 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2902#else
2903 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2904 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2905#endif
2906 } else {
2907 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002908 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002909 (addr & ~TARGET_PAGE_MASK);
2910 val = ldq_p(ptr);
2911 }
2912 return val;
2913}
2914
bellardaab33092005-10-30 20:48:42 +00002915/* XXX: optimize */
2916uint32_t ldub_phys(target_phys_addr_t addr)
2917{
2918 uint8_t val;
2919 cpu_physical_memory_read(addr, &val, 1);
2920 return val;
2921}
2922
2923/* XXX: optimize */
2924uint32_t lduw_phys(target_phys_addr_t addr)
2925{
2926 uint16_t val;
2927 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2928 return tswap16(val);
2929}
2930
bellard8df1cd02005-01-28 22:37:22 +00002931/* warning: addr must be aligned. The ram page is not masked as dirty
2932 and the code inside is not invalidated. It is useful if the dirty
2933 bits are used to track modified PTEs */
2934void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2935{
2936 int io_index;
2937 uint8_t *ptr;
2938 unsigned long pd;
2939 PhysPageDesc *p;
2940
2941 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2942 if (!p) {
2943 pd = IO_MEM_UNASSIGNED;
2944 } else {
2945 pd = p->phys_offset;
2946 }
ths3b46e622007-09-17 08:09:54 +00002947
bellard3a7d9292005-08-21 09:26:42 +00002948 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002949 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2950 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2951 } else {
ths5fafdf22007-09-16 21:08:06 +00002952 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002953 (addr & ~TARGET_PAGE_MASK);
2954 stl_p(ptr, val);
2955 }
2956}
2957
j_mayerbc98a7e2007-04-04 07:55:12 +00002958void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2959{
2960 int io_index;
2961 uint8_t *ptr;
2962 unsigned long pd;
2963 PhysPageDesc *p;
2964
2965 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2966 if (!p) {
2967 pd = IO_MEM_UNASSIGNED;
2968 } else {
2969 pd = p->phys_offset;
2970 }
ths3b46e622007-09-17 08:09:54 +00002971
j_mayerbc98a7e2007-04-04 07:55:12 +00002972 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2973 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2974#ifdef TARGET_WORDS_BIGENDIAN
2975 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2976 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2977#else
2978 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2979 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2980#endif
2981 } else {
ths5fafdf22007-09-16 21:08:06 +00002982 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002983 (addr & ~TARGET_PAGE_MASK);
2984 stq_p(ptr, val);
2985 }
2986}
2987
bellard8df1cd02005-01-28 22:37:22 +00002988/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002989void stl_phys(target_phys_addr_t addr, uint32_t val)
2990{
2991 int io_index;
2992 uint8_t *ptr;
2993 unsigned long pd;
2994 PhysPageDesc *p;
2995
2996 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2997 if (!p) {
2998 pd = IO_MEM_UNASSIGNED;
2999 } else {
3000 pd = p->phys_offset;
3001 }
ths3b46e622007-09-17 08:09:54 +00003002
bellard3a7d9292005-08-21 09:26:42 +00003003 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003004 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
3005 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3006 } else {
3007 unsigned long addr1;
3008 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3009 /* RAM case */
3010 ptr = phys_ram_base + addr1;
3011 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003012 if (!cpu_physical_memory_is_dirty(addr1)) {
3013 /* invalidate code */
3014 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3015 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003016 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3017 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003018 }
bellard8df1cd02005-01-28 22:37:22 +00003019 }
3020}
3021
bellardaab33092005-10-30 20:48:42 +00003022/* XXX: optimize */
3023void stb_phys(target_phys_addr_t addr, uint32_t val)
3024{
3025 uint8_t v = val;
3026 cpu_physical_memory_write(addr, &v, 1);
3027}
3028
3029/* XXX: optimize */
3030void stw_phys(target_phys_addr_t addr, uint32_t val)
3031{
3032 uint16_t v = tswap16(val);
3033 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3034}
3035
3036/* XXX: optimize */
3037void stq_phys(target_phys_addr_t addr, uint64_t val)
3038{
3039 val = tswap64(val);
3040 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3041}
3042
bellard13eb76e2004-01-24 15:23:36 +00003043#endif
3044
3045/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00003046int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003047 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003048{
3049 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003050 target_phys_addr_t phys_addr;
3051 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003052
3053 while (len > 0) {
3054 page = addr & TARGET_PAGE_MASK;
3055 phys_addr = cpu_get_phys_page_debug(env, page);
3056 /* if no physical page mapped, return an error */
3057 if (phys_addr == -1)
3058 return -1;
3059 l = (page + TARGET_PAGE_SIZE) - addr;
3060 if (l > len)
3061 l = len;
ths5fafdf22007-09-16 21:08:06 +00003062 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00003063 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003064 len -= l;
3065 buf += l;
3066 addr += l;
3067 }
3068 return 0;
3069}
3070
bellarde3db7222005-01-26 22:00:47 +00003071void dump_exec_info(FILE *f,
3072 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3073{
3074 int i, target_code_size, max_target_code_size;
3075 int direct_jmp_count, direct_jmp2_count, cross_page;
3076 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003077
bellarde3db7222005-01-26 22:00:47 +00003078 target_code_size = 0;
3079 max_target_code_size = 0;
3080 cross_page = 0;
3081 direct_jmp_count = 0;
3082 direct_jmp2_count = 0;
3083 for(i = 0; i < nb_tbs; i++) {
3084 tb = &tbs[i];
3085 target_code_size += tb->size;
3086 if (tb->size > max_target_code_size)
3087 max_target_code_size = tb->size;
3088 if (tb->page_addr[1] != -1)
3089 cross_page++;
3090 if (tb->tb_next_offset[0] != 0xffff) {
3091 direct_jmp_count++;
3092 if (tb->tb_next_offset[1] != 0xffff) {
3093 direct_jmp2_count++;
3094 }
3095 }
3096 }
3097 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003098 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003099 cpu_fprintf(f, "gen code size %ld/%ld\n",
3100 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3101 cpu_fprintf(f, "TB count %d/%d\n",
3102 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003103 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003104 nb_tbs ? target_code_size / nb_tbs : 0,
3105 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003106 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003107 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3108 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003109 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3110 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003111 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3112 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003113 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003114 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3115 direct_jmp2_count,
3116 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003117 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003118 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3119 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3120 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003121 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003122}
3123
ths5fafdf22007-09-16 21:08:06 +00003124#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003125
3126#define MMUSUFFIX _cmmu
3127#define GETPC() NULL
3128#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003129#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003130
3131#define SHIFT 0
3132#include "softmmu_template.h"
3133
3134#define SHIFT 1
3135#include "softmmu_template.h"
3136
3137#define SHIFT 2
3138#include "softmmu_template.h"
3139
3140#define SHIFT 3
3141#include "softmmu_template.h"
3142
3143#undef env
3144
3145#endif