blob: 4fb3aee452f244bf93a12cab4f01ceedd7bcd81d [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrookb3c77242008-06-30 16:31:04 +000040#include "hw/hw.h"
pbrook53a59602006-03-25 19:31:22 +000041#if defined(CONFIG_USER_ONLY)
42#include <qemu.h>
43#endif
bellard54936002003-05-13 00:25:15 +000044
bellardfd6ce8f2003-05-14 19:00:11 +000045//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000046//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000047//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000048//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000049
50/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000051//#define DEBUG_TB_CHECK
52//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000053
ths1196be32007-03-17 15:17:58 +000054//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000055//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000056
pbrook99773bd2006-04-16 15:14:59 +000057#if !defined(CONFIG_USER_ONLY)
58/* TB consistency checks only implemented for usermode emulation. */
59#undef DEBUG_TB_CHECK
60#endif
61
bellard9fa3e852004-01-04 18:06:42 +000062#define SMC_BITMAP_USE_THRESHOLD 10
63
64#define MMAP_AREA_START 0x00000000
65#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000066
bellard108c49b2005-07-24 12:55:09 +000067#if defined(TARGET_SPARC64)
68#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000069#elif defined(TARGET_SPARC)
70#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000071#elif defined(TARGET_ALPHA)
72#define TARGET_PHYS_ADDR_SPACE_BITS 42
73#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000074#elif defined(TARGET_PPC64)
75#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000076#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
77#define TARGET_PHYS_ADDR_SPACE_BITS 42
78#elif defined(TARGET_I386) && !defined(USE_KQEMU)
79#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000080#else
81/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
82#define TARGET_PHYS_ADDR_SPACE_BITS 32
83#endif
84
pbrookfab94c02008-05-24 13:56:15 +000085TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000086int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000087TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000088int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000089/* any access to the tbs or the page table must use this lock */
90spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000091
blueswir1141ac462008-07-26 15:05:57 +000092#if defined(__arm__) || defined(__sparc_v9__)
93/* The prologue must be reachable with a direct jump. ARM and Sparc64
94 have limited branch ranges (possibly also PPC) so place it in a
blueswir1d03d8602008-07-10 17:21:31 +000095 section close to code segment. */
96#define code_gen_section \
97 __attribute__((__section__(".gen_code"))) \
98 __attribute__((aligned (32)))
99#else
100#define code_gen_section \
101 __attribute__((aligned (32)))
102#endif
103
104uint8_t code_gen_prologue[1024] code_gen_section;
bellard26a5f132008-05-28 12:30:31 +0000105uint8_t *code_gen_buffer;
106unsigned long code_gen_buffer_size;
107/* threshold to flush the translated code buffer */
108unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000109uint8_t *code_gen_ptr;
110
pbrooke2eef172008-06-08 01:09:01 +0000111#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +0000112ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000113int phys_ram_fd;
114uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000115uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000116static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000117#endif
bellard9fa3e852004-01-04 18:06:42 +0000118
bellard6a00d602005-11-21 23:25:50 +0000119CPUState *first_cpu;
120/* current CPU in the current thread. It is only valid inside
121 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000122CPUState *cpu_single_env;
pbrook2e70f6e2008-06-29 01:03:05 +0000123/* 0 = Do not count executed instructions.
thsbf20dc02008-06-30 17:22:19 +0000124 1 = Precise instruction counting.
pbrook2e70f6e2008-06-29 01:03:05 +0000125 2 = Adaptive rate instruction counting. */
126int use_icount = 0;
127/* Current instruction counter. While executing translated code this may
128 include some instructions that have not yet been executed. */
129int64_t qemu_icount;
bellard6a00d602005-11-21 23:25:50 +0000130
bellard54936002003-05-13 00:25:15 +0000131typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000132 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000133 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000134 /* in order to optimize self modifying code, we count the number
135 of lookups we do to a given page to use a bitmap */
136 unsigned int code_write_count;
137 uint8_t *code_bitmap;
138#if defined(CONFIG_USER_ONLY)
139 unsigned long flags;
140#endif
bellard54936002003-05-13 00:25:15 +0000141} PageDesc;
142
bellard92e873b2004-05-21 14:52:29 +0000143typedef struct PhysPageDesc {
pbrook0f459d12008-06-09 00:20:13 +0000144 /* offset in host memory of the page + io_index in the low bits */
aurel3200f82b82008-04-27 21:12:55 +0000145 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000146} PhysPageDesc;
147
bellard54936002003-05-13 00:25:15 +0000148#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000149#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
150/* XXX: this is a temporary hack for alpha target.
151 * In the future, this is to be replaced by a multi-level table
152 * to actually be able to handle the complete 64 bits address space.
153 */
154#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
155#else
aurel3203875442008-04-22 20:45:18 +0000156#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000157#endif
bellard54936002003-05-13 00:25:15 +0000158
159#define L1_SIZE (1 << L1_BITS)
160#define L2_SIZE (1 << L2_BITS)
161
bellard83fb7ad2004-07-05 21:25:26 +0000162unsigned long qemu_real_host_page_size;
163unsigned long qemu_host_page_bits;
164unsigned long qemu_host_page_size;
165unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000166
bellard92e873b2004-05-21 14:52:29 +0000167/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000168static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000169PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000170
pbrooke2eef172008-06-08 01:09:01 +0000171#if !defined(CONFIG_USER_ONLY)
172static void io_mem_init(void);
173
bellard33417e72003-08-10 21:47:01 +0000174/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000175CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
176CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000177void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000178static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000179static int io_mem_watch;
180#endif
bellard33417e72003-08-10 21:47:01 +0000181
bellard34865132003-10-05 14:28:56 +0000182/* log support */
blueswir17ccfb2e2008-09-14 06:45:34 +0000183const char *logfilename = "/tmp/qemu.log";
bellard34865132003-10-05 14:28:56 +0000184FILE *logfile;
185int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000186static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000187
bellarde3db7222005-01-26 22:00:47 +0000188/* statistics */
189static int tlb_flush_count;
190static int tb_flush_count;
191static int tb_phys_invalidate_count;
192
blueswir1db7b5422007-05-26 17:36:03 +0000193#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
194typedef struct subpage_t {
195 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000196 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
197 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
198 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000199} subpage_t;
200
bellard7cb69ca2008-05-10 10:55:51 +0000201#ifdef _WIN32
202static void map_exec(void *addr, long size)
203{
204 DWORD old_protect;
205 VirtualProtect(addr, size,
206 PAGE_EXECUTE_READWRITE, &old_protect);
207
208}
209#else
210static void map_exec(void *addr, long size)
211{
bellard43694152008-05-29 09:35:57 +0000212 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000213
bellard43694152008-05-29 09:35:57 +0000214 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000215 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000216 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000217
218 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000219 end += page_size - 1;
220 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000221
222 mprotect((void *)start, end - start,
223 PROT_READ | PROT_WRITE | PROT_EXEC);
224}
225#endif
226
bellardb346ff42003-06-15 20:05:50 +0000227static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000228{
bellard83fb7ad2004-07-05 21:25:26 +0000229 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000230 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000231#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000232 {
233 SYSTEM_INFO system_info;
234 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000235
bellardd5a8f072004-09-29 21:15:28 +0000236 GetSystemInfo(&system_info);
237 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000238 }
bellard67b915a2004-03-31 23:37:16 +0000239#else
bellard83fb7ad2004-07-05 21:25:26 +0000240 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000241#endif
bellard83fb7ad2004-07-05 21:25:26 +0000242 if (qemu_host_page_size == 0)
243 qemu_host_page_size = qemu_real_host_page_size;
244 if (qemu_host_page_size < TARGET_PAGE_SIZE)
245 qemu_host_page_size = TARGET_PAGE_SIZE;
246 qemu_host_page_bits = 0;
247 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
248 qemu_host_page_bits++;
249 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000250 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
251 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000252
253#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
254 {
255 long long startaddr, endaddr;
256 FILE *f;
257 int n;
258
pbrookc8a706f2008-06-02 16:16:42 +0000259 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000260 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000261 f = fopen("/proc/self/maps", "r");
262 if (f) {
263 do {
264 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
265 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000266 startaddr = MIN(startaddr,
267 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
268 endaddr = MIN(endaddr,
269 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000270 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000271 TARGET_PAGE_ALIGN(endaddr),
272 PAGE_RESERVED);
273 }
274 } while (!feof(f));
275 fclose(f);
276 }
pbrookc8a706f2008-06-02 16:16:42 +0000277 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000278 }
279#endif
bellard54936002003-05-13 00:25:15 +0000280}
281
aliguori434929b2008-09-15 15:56:30 +0000282static inline PageDesc **page_l1_map(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000283{
pbrook17e23772008-06-09 13:47:45 +0000284#if TARGET_LONG_BITS > 32
285 /* Host memory outside guest VM. For 32-bit targets we have already
286 excluded high addresses. */
thsd8173e02008-08-29 13:10:00 +0000287 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
pbrook17e23772008-06-09 13:47:45 +0000288 return NULL;
289#endif
aliguori434929b2008-09-15 15:56:30 +0000290 return &l1_map[index >> L2_BITS];
291}
292
293static inline PageDesc *page_find_alloc(target_ulong index)
294{
295 PageDesc **lp, *p;
296 lp = page_l1_map(index);
297 if (!lp)
298 return NULL;
299
bellard54936002003-05-13 00:25:15 +0000300 p = *lp;
301 if (!p) {
302 /* allocate if not found */
pbrook17e23772008-06-09 13:47:45 +0000303#if defined(CONFIG_USER_ONLY)
304 unsigned long addr;
305 size_t len = sizeof(PageDesc) * L2_SIZE;
306 /* Don't use qemu_malloc because it may recurse. */
307 p = mmap(0, len, PROT_READ | PROT_WRITE,
308 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bellard54936002003-05-13 00:25:15 +0000309 *lp = p;
pbrook17e23772008-06-09 13:47:45 +0000310 addr = h2g(p);
311 if (addr == (target_ulong)addr) {
312 page_set_flags(addr & TARGET_PAGE_MASK,
313 TARGET_PAGE_ALIGN(addr + len),
314 PAGE_RESERVED);
315 }
316#else
317 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
318 *lp = p;
319#endif
bellard54936002003-05-13 00:25:15 +0000320 }
321 return p + (index & (L2_SIZE - 1));
322}
323
aurel3200f82b82008-04-27 21:12:55 +0000324static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000325{
aliguori434929b2008-09-15 15:56:30 +0000326 PageDesc **lp, *p;
327 lp = page_l1_map(index);
328 if (!lp)
329 return NULL;
bellard54936002003-05-13 00:25:15 +0000330
aliguori434929b2008-09-15 15:56:30 +0000331 p = *lp;
bellard54936002003-05-13 00:25:15 +0000332 if (!p)
333 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000334 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000335}
336
bellard108c49b2005-07-24 12:55:09 +0000337static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000338{
bellard108c49b2005-07-24 12:55:09 +0000339 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000340 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000341
bellard108c49b2005-07-24 12:55:09 +0000342 p = (void **)l1_phys_map;
343#if TARGET_PHYS_ADDR_SPACE_BITS > 32
344
345#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
346#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
347#endif
348 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000349 p = *lp;
350 if (!p) {
351 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000352 if (!alloc)
353 return NULL;
354 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
355 memset(p, 0, sizeof(void *) * L1_SIZE);
356 *lp = p;
357 }
358#endif
359 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000360 pd = *lp;
361 if (!pd) {
362 int i;
bellard108c49b2005-07-24 12:55:09 +0000363 /* allocate if not found */
364 if (!alloc)
365 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000366 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
367 *lp = pd;
368 for (i = 0; i < L2_SIZE; i++)
369 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000370 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000371 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000372}
373
bellard108c49b2005-07-24 12:55:09 +0000374static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000375{
bellard108c49b2005-07-24 12:55:09 +0000376 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000377}
378
bellard9fa3e852004-01-04 18:06:42 +0000379#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000380static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000381static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000382 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000383#define mmap_lock() do { } while(0)
384#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000385#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000386
bellard43694152008-05-29 09:35:57 +0000387#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
388
389#if defined(CONFIG_USER_ONLY)
390/* Currently it is not recommanded to allocate big chunks of data in
391 user mode. It will change when a dedicated libc will be used */
392#define USE_STATIC_CODE_GEN_BUFFER
393#endif
394
395#ifdef USE_STATIC_CODE_GEN_BUFFER
396static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
397#endif
398
blueswir18fcd3692008-08-17 20:26:25 +0000399static void code_gen_alloc(unsigned long tb_size)
bellard26a5f132008-05-28 12:30:31 +0000400{
bellard43694152008-05-29 09:35:57 +0000401#ifdef USE_STATIC_CODE_GEN_BUFFER
402 code_gen_buffer = static_code_gen_buffer;
403 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
404 map_exec(code_gen_buffer, code_gen_buffer_size);
405#else
bellard26a5f132008-05-28 12:30:31 +0000406 code_gen_buffer_size = tb_size;
407 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000408#if defined(CONFIG_USER_ONLY)
409 /* in user mode, phys_ram_size is not meaningful */
410 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
411#else
bellard26a5f132008-05-28 12:30:31 +0000412 /* XXX: needs ajustments */
aliguori174a9a12008-09-24 14:10:36 +0000413 code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000414#endif
bellard26a5f132008-05-28 12:30:31 +0000415 }
416 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
417 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
418 /* The code gen buffer location may have constraints depending on
419 the host cpu and OS */
420#if defined(__linux__)
421 {
422 int flags;
blueswir1141ac462008-07-26 15:05:57 +0000423 void *start = NULL;
424
bellard26a5f132008-05-28 12:30:31 +0000425 flags = MAP_PRIVATE | MAP_ANONYMOUS;
426#if defined(__x86_64__)
427 flags |= MAP_32BIT;
428 /* Cannot map more than that */
429 if (code_gen_buffer_size > (800 * 1024 * 1024))
430 code_gen_buffer_size = (800 * 1024 * 1024);
blueswir1141ac462008-07-26 15:05:57 +0000431#elif defined(__sparc_v9__)
432 // Map the buffer below 2G, so we can use direct calls and branches
433 flags |= MAP_FIXED;
434 start = (void *) 0x60000000UL;
435 if (code_gen_buffer_size > (512 * 1024 * 1024))
436 code_gen_buffer_size = (512 * 1024 * 1024);
bellard26a5f132008-05-28 12:30:31 +0000437#endif
blueswir1141ac462008-07-26 15:05:57 +0000438 code_gen_buffer = mmap(start, code_gen_buffer_size,
439 PROT_WRITE | PROT_READ | PROT_EXEC,
bellard26a5f132008-05-28 12:30:31 +0000440 flags, -1, 0);
441 if (code_gen_buffer == MAP_FAILED) {
442 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
443 exit(1);
444 }
445 }
aliguori06e67a82008-09-27 15:32:41 +0000446#elif defined(__FreeBSD__)
447 {
448 int flags;
449 void *addr = NULL;
450 flags = MAP_PRIVATE | MAP_ANONYMOUS;
451#if defined(__x86_64__)
452 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
453 * 0x40000000 is free */
454 flags |= MAP_FIXED;
455 addr = (void *)0x40000000;
456 /* Cannot map more than that */
457 if (code_gen_buffer_size > (800 * 1024 * 1024))
458 code_gen_buffer_size = (800 * 1024 * 1024);
459#endif
460 code_gen_buffer = mmap(addr, code_gen_buffer_size,
461 PROT_WRITE | PROT_READ | PROT_EXEC,
462 flags, -1, 0);
463 if (code_gen_buffer == MAP_FAILED) {
464 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
465 exit(1);
466 }
467 }
bellard26a5f132008-05-28 12:30:31 +0000468#else
469 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
470 if (!code_gen_buffer) {
471 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
472 exit(1);
473 }
474 map_exec(code_gen_buffer, code_gen_buffer_size);
475#endif
bellard43694152008-05-29 09:35:57 +0000476#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000477 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
478 code_gen_buffer_max_size = code_gen_buffer_size -
479 code_gen_max_block_size();
480 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
481 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
482}
483
484/* Must be called before using the QEMU cpus. 'tb_size' is the size
485 (in bytes) allocated to the translation buffer. Zero means default
486 size. */
487void cpu_exec_init_all(unsigned long tb_size)
488{
bellard26a5f132008-05-28 12:30:31 +0000489 cpu_gen_init();
490 code_gen_alloc(tb_size);
491 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000492 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000493#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000494 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000495#endif
bellard26a5f132008-05-28 12:30:31 +0000496}
497
pbrook9656f322008-07-01 20:01:19 +0000498#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
499
500#define CPU_COMMON_SAVE_VERSION 1
501
502static void cpu_common_save(QEMUFile *f, void *opaque)
503{
504 CPUState *env = opaque;
505
506 qemu_put_be32s(f, &env->halted);
507 qemu_put_be32s(f, &env->interrupt_request);
508}
509
510static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
511{
512 CPUState *env = opaque;
513
514 if (version_id != CPU_COMMON_SAVE_VERSION)
515 return -EINVAL;
516
517 qemu_get_be32s(f, &env->halted);
pbrook75f482a2008-07-01 21:53:33 +0000518 qemu_get_be32s(f, &env->interrupt_request);
pbrook9656f322008-07-01 20:01:19 +0000519 tlb_flush(env, 1);
520
521 return 0;
522}
523#endif
524
bellard6a00d602005-11-21 23:25:50 +0000525void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000526{
bellard6a00d602005-11-21 23:25:50 +0000527 CPUState **penv;
528 int cpu_index;
529
bellard6a00d602005-11-21 23:25:50 +0000530 env->next_cpu = NULL;
531 penv = &first_cpu;
532 cpu_index = 0;
533 while (*penv != NULL) {
534 penv = (CPUState **)&(*penv)->next_cpu;
535 cpu_index++;
536 }
537 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000538 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000539 *penv = env;
pbrookb3c77242008-06-30 16:31:04 +0000540#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
pbrook9656f322008-07-01 20:01:19 +0000541 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
542 cpu_common_save, cpu_common_load, env);
pbrookb3c77242008-06-30 16:31:04 +0000543 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
544 cpu_save, cpu_load, env);
545#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000546}
547
bellard9fa3e852004-01-04 18:06:42 +0000548static inline void invalidate_page_bitmap(PageDesc *p)
549{
550 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000551 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000552 p->code_bitmap = NULL;
553 }
554 p->code_write_count = 0;
555}
556
bellardfd6ce8f2003-05-14 19:00:11 +0000557/* set to NULL all the 'first_tb' fields in all PageDescs */
558static void page_flush_tb(void)
559{
560 int i, j;
561 PageDesc *p;
562
563 for(i = 0; i < L1_SIZE; i++) {
564 p = l1_map[i];
565 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000566 for(j = 0; j < L2_SIZE; j++) {
567 p->first_tb = NULL;
568 invalidate_page_bitmap(p);
569 p++;
570 }
bellardfd6ce8f2003-05-14 19:00:11 +0000571 }
572 }
573}
574
575/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000576/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000577void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000578{
bellard6a00d602005-11-21 23:25:50 +0000579 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000580#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000581 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
582 (unsigned long)(code_gen_ptr - code_gen_buffer),
583 nb_tbs, nb_tbs > 0 ?
584 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000585#endif
bellard26a5f132008-05-28 12:30:31 +0000586 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000587 cpu_abort(env1, "Internal error: code buffer overflow\n");
588
bellardfd6ce8f2003-05-14 19:00:11 +0000589 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000590
bellard6a00d602005-11-21 23:25:50 +0000591 for(env = first_cpu; env != NULL; env = env->next_cpu) {
592 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
593 }
bellard9fa3e852004-01-04 18:06:42 +0000594
bellard8a8a6082004-10-03 13:36:49 +0000595 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000596 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000597
bellardfd6ce8f2003-05-14 19:00:11 +0000598 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000599 /* XXX: flush processor icache at this point if cache flush is
600 expensive */
bellarde3db7222005-01-26 22:00:47 +0000601 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000602}
603
604#ifdef DEBUG_TB_CHECK
605
j_mayerbc98a7e2007-04-04 07:55:12 +0000606static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000607{
608 TranslationBlock *tb;
609 int i;
610 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000611 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
612 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000613 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
614 address >= tb->pc + tb->size)) {
615 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000616 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000617 }
618 }
619 }
620}
621
622/* verify that all the pages have correct rights for code */
623static void tb_page_check(void)
624{
625 TranslationBlock *tb;
626 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000627
pbrook99773bd2006-04-16 15:14:59 +0000628 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
629 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000630 flags1 = page_get_flags(tb->pc);
631 flags2 = page_get_flags(tb->pc + tb->size - 1);
632 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
633 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000634 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000635 }
636 }
637 }
638}
639
bellardd4e81642003-05-25 16:46:15 +0000640void tb_jmp_check(TranslationBlock *tb)
641{
642 TranslationBlock *tb1;
643 unsigned int n1;
644
645 /* suppress any remaining jumps to this TB */
646 tb1 = tb->jmp_first;
647 for(;;) {
648 n1 = (long)tb1 & 3;
649 tb1 = (TranslationBlock *)((long)tb1 & ~3);
650 if (n1 == 2)
651 break;
652 tb1 = tb1->jmp_next[n1];
653 }
654 /* check end of list */
655 if (tb1 != tb) {
656 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
657 }
658}
659
bellardfd6ce8f2003-05-14 19:00:11 +0000660#endif
661
662/* invalidate one TB */
663static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
664 int next_offset)
665{
666 TranslationBlock *tb1;
667 for(;;) {
668 tb1 = *ptb;
669 if (tb1 == tb) {
670 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
671 break;
672 }
673 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
674 }
675}
676
bellard9fa3e852004-01-04 18:06:42 +0000677static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
678{
679 TranslationBlock *tb1;
680 unsigned int n1;
681
682 for(;;) {
683 tb1 = *ptb;
684 n1 = (long)tb1 & 3;
685 tb1 = (TranslationBlock *)((long)tb1 & ~3);
686 if (tb1 == tb) {
687 *ptb = tb1->page_next[n1];
688 break;
689 }
690 ptb = &tb1->page_next[n1];
691 }
692}
693
bellardd4e81642003-05-25 16:46:15 +0000694static inline void tb_jmp_remove(TranslationBlock *tb, int n)
695{
696 TranslationBlock *tb1, **ptb;
697 unsigned int n1;
698
699 ptb = &tb->jmp_next[n];
700 tb1 = *ptb;
701 if (tb1) {
702 /* find tb(n) in circular list */
703 for(;;) {
704 tb1 = *ptb;
705 n1 = (long)tb1 & 3;
706 tb1 = (TranslationBlock *)((long)tb1 & ~3);
707 if (n1 == n && tb1 == tb)
708 break;
709 if (n1 == 2) {
710 ptb = &tb1->jmp_first;
711 } else {
712 ptb = &tb1->jmp_next[n1];
713 }
714 }
715 /* now we can suppress tb(n) from the list */
716 *ptb = tb->jmp_next[n];
717
718 tb->jmp_next[n] = NULL;
719 }
720}
721
722/* reset the jump entry 'n' of a TB so that it is not chained to
723 another TB */
724static inline void tb_reset_jump(TranslationBlock *tb, int n)
725{
726 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
727}
728
pbrook2e70f6e2008-06-29 01:03:05 +0000729void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000730{
bellard6a00d602005-11-21 23:25:50 +0000731 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000732 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000733 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000734 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000735 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000736
bellard9fa3e852004-01-04 18:06:42 +0000737 /* remove the TB from the hash list */
738 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
739 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000740 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000741 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000742
bellard9fa3e852004-01-04 18:06:42 +0000743 /* remove the TB from the page list */
744 if (tb->page_addr[0] != page_addr) {
745 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
746 tb_page_remove(&p->first_tb, tb);
747 invalidate_page_bitmap(p);
748 }
749 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
750 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
751 tb_page_remove(&p->first_tb, tb);
752 invalidate_page_bitmap(p);
753 }
754
bellard8a40a182005-11-20 10:35:40 +0000755 tb_invalidated_flag = 1;
756
757 /* remove the TB from the hash list */
758 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000759 for(env = first_cpu; env != NULL; env = env->next_cpu) {
760 if (env->tb_jmp_cache[h] == tb)
761 env->tb_jmp_cache[h] = NULL;
762 }
bellard8a40a182005-11-20 10:35:40 +0000763
764 /* suppress this TB from the two jump lists */
765 tb_jmp_remove(tb, 0);
766 tb_jmp_remove(tb, 1);
767
768 /* suppress any remaining jumps to this TB */
769 tb1 = tb->jmp_first;
770 for(;;) {
771 n1 = (long)tb1 & 3;
772 if (n1 == 2)
773 break;
774 tb1 = (TranslationBlock *)((long)tb1 & ~3);
775 tb2 = tb1->jmp_next[n1];
776 tb_reset_jump(tb1, n1);
777 tb1->jmp_next[n1] = NULL;
778 tb1 = tb2;
779 }
780 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
781
bellarde3db7222005-01-26 22:00:47 +0000782 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000783}
784
785static inline void set_bits(uint8_t *tab, int start, int len)
786{
787 int end, mask, end1;
788
789 end = start + len;
790 tab += start >> 3;
791 mask = 0xff << (start & 7);
792 if ((start & ~7) == (end & ~7)) {
793 if (start < end) {
794 mask &= ~(0xff << (end & 7));
795 *tab |= mask;
796 }
797 } else {
798 *tab++ |= mask;
799 start = (start + 8) & ~7;
800 end1 = end & ~7;
801 while (start < end1) {
802 *tab++ = 0xff;
803 start += 8;
804 }
805 if (start < end) {
806 mask = ~(0xff << (end & 7));
807 *tab |= mask;
808 }
809 }
810}
811
812static void build_page_bitmap(PageDesc *p)
813{
814 int n, tb_start, tb_end;
815 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000816
pbrookb2a70812008-06-09 13:57:23 +0000817 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000818 if (!p->code_bitmap)
819 return;
bellard9fa3e852004-01-04 18:06:42 +0000820
821 tb = p->first_tb;
822 while (tb != NULL) {
823 n = (long)tb & 3;
824 tb = (TranslationBlock *)((long)tb & ~3);
825 /* NOTE: this is subtle as a TB may span two physical pages */
826 if (n == 0) {
827 /* NOTE: tb_end may be after the end of the page, but
828 it is not a problem */
829 tb_start = tb->pc & ~TARGET_PAGE_MASK;
830 tb_end = tb_start + tb->size;
831 if (tb_end > TARGET_PAGE_SIZE)
832 tb_end = TARGET_PAGE_SIZE;
833 } else {
834 tb_start = 0;
835 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
836 }
837 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
838 tb = tb->page_next[n];
839 }
840}
841
pbrook2e70f6e2008-06-29 01:03:05 +0000842TranslationBlock *tb_gen_code(CPUState *env,
843 target_ulong pc, target_ulong cs_base,
844 int flags, int cflags)
bellardd720b932004-04-25 17:57:43 +0000845{
846 TranslationBlock *tb;
847 uint8_t *tc_ptr;
848 target_ulong phys_pc, phys_page2, virt_page2;
849 int code_gen_size;
850
bellardc27004e2005-01-03 23:35:10 +0000851 phys_pc = get_phys_addr_code(env, pc);
852 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000853 if (!tb) {
854 /* flush must be done */
855 tb_flush(env);
856 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000857 tb = tb_alloc(pc);
pbrook2e70f6e2008-06-29 01:03:05 +0000858 /* Don't forget to invalidate previous TB info. */
859 tb_invalidated_flag = 1;
bellardd720b932004-04-25 17:57:43 +0000860 }
861 tc_ptr = code_gen_ptr;
862 tb->tc_ptr = tc_ptr;
863 tb->cs_base = cs_base;
864 tb->flags = flags;
865 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000866 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000867 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 +0000868
bellardd720b932004-04-25 17:57:43 +0000869 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000870 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000871 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000872 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000873 phys_page2 = get_phys_addr_code(env, virt_page2);
874 }
875 tb_link_phys(tb, phys_pc, phys_page2);
pbrook2e70f6e2008-06-29 01:03:05 +0000876 return tb;
bellardd720b932004-04-25 17:57:43 +0000877}
ths3b46e622007-09-17 08:09:54 +0000878
bellard9fa3e852004-01-04 18:06:42 +0000879/* invalidate all TBs which intersect with the target physical page
880 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000881 the same physical page. 'is_cpu_write_access' should be true if called
882 from a real cpu write access: the virtual CPU will exit the current
883 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000884void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000885 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000886{
bellardd720b932004-04-25 17:57:43 +0000887 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000888 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000889 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000890 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000891 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000892 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000893
894 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000895 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000896 return;
ths5fafdf22007-09-16 21:08:06 +0000897 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000898 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
899 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000900 /* build code bitmap */
901 build_page_bitmap(p);
902 }
903
904 /* we remove all the TBs in the range [start, end[ */
905 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000906 current_tb_not_found = is_cpu_write_access;
907 current_tb_modified = 0;
908 current_tb = NULL; /* avoid warning */
909 current_pc = 0; /* avoid warning */
910 current_cs_base = 0; /* avoid warning */
911 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000912 tb = p->first_tb;
913 while (tb != NULL) {
914 n = (long)tb & 3;
915 tb = (TranslationBlock *)((long)tb & ~3);
916 tb_next = tb->page_next[n];
917 /* NOTE: this is subtle as a TB may span two physical pages */
918 if (n == 0) {
919 /* NOTE: tb_end may be after the end of the page, but
920 it is not a problem */
921 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
922 tb_end = tb_start + tb->size;
923 } else {
924 tb_start = tb->page_addr[1];
925 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
926 }
927 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000928#ifdef TARGET_HAS_PRECISE_SMC
929 if (current_tb_not_found) {
930 current_tb_not_found = 0;
931 current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000932 if (env->mem_io_pc) {
bellardd720b932004-04-25 17:57:43 +0000933 /* now we have a real cpu fault */
pbrook2e70f6e2008-06-29 01:03:05 +0000934 current_tb = tb_find_pc(env->mem_io_pc);
bellardd720b932004-04-25 17:57:43 +0000935 }
936 }
937 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +0000938 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +0000939 /* If we are modifying the current TB, we must stop
940 its execution. We could be more precise by checking
941 that the modification is after the current PC, but it
942 would require a specialized function to partially
943 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000944
bellardd720b932004-04-25 17:57:43 +0000945 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000946 cpu_restore_state(current_tb, env,
pbrook2e70f6e2008-06-29 01:03:05 +0000947 env->mem_io_pc, NULL);
bellardd720b932004-04-25 17:57:43 +0000948#if defined(TARGET_I386)
949 current_flags = env->hflags;
950 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
951 current_cs_base = (target_ulong)env->segs[R_CS].base;
952 current_pc = current_cs_base + env->eip;
953#else
954#error unsupported CPU
955#endif
956 }
957#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000958 /* we need to do that to handle the case where a signal
959 occurs while doing tb_phys_invalidate() */
960 saved_tb = NULL;
961 if (env) {
962 saved_tb = env->current_tb;
963 env->current_tb = NULL;
964 }
bellard9fa3e852004-01-04 18:06:42 +0000965 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000966 if (env) {
967 env->current_tb = saved_tb;
968 if (env->interrupt_request && env->current_tb)
969 cpu_interrupt(env, env->interrupt_request);
970 }
bellard9fa3e852004-01-04 18:06:42 +0000971 }
972 tb = tb_next;
973 }
974#if !defined(CONFIG_USER_ONLY)
975 /* if no code remaining, no need to continue to use slow writes */
976 if (!p->first_tb) {
977 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000978 if (is_cpu_write_access) {
pbrook2e70f6e2008-06-29 01:03:05 +0000979 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
bellardd720b932004-04-25 17:57:43 +0000980 }
981 }
982#endif
983#ifdef TARGET_HAS_PRECISE_SMC
984 if (current_tb_modified) {
985 /* we generate a block containing just the instruction
986 modifying the memory. It will ensure that it cannot modify
987 itself */
bellardea1c1802004-06-14 18:56:36 +0000988 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000989 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +0000990 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000991 }
992#endif
993}
994
995/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000996static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000997{
998 PageDesc *p;
999 int offset, b;
bellard59817cc2004-02-16 22:01:13 +00001000#if 0
bellarda4193c82004-06-03 14:01:43 +00001001 if (1) {
1002 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +00001003 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
pbrook2e70f6e2008-06-29 01:03:05 +00001004 cpu_single_env->mem_io_vaddr, len,
ths5fafdf22007-09-16 21:08:06 +00001005 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +00001006 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
1007 }
bellard59817cc2004-02-16 22:01:13 +00001008 }
1009#endif
bellard9fa3e852004-01-04 18:06:42 +00001010 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001011 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001012 return;
1013 if (p->code_bitmap) {
1014 offset = start & ~TARGET_PAGE_MASK;
1015 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1016 if (b & ((1 << len) - 1))
1017 goto do_invalidate;
1018 } else {
1019 do_invalidate:
bellardd720b932004-04-25 17:57:43 +00001020 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +00001021 }
1022}
1023
bellard9fa3e852004-01-04 18:06:42 +00001024#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +00001025static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +00001026 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001027{
bellardd720b932004-04-25 17:57:43 +00001028 int n, current_flags, current_tb_modified;
1029 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +00001030 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001031 TranslationBlock *tb, *current_tb;
1032#ifdef TARGET_HAS_PRECISE_SMC
1033 CPUState *env = cpu_single_env;
1034#endif
bellard9fa3e852004-01-04 18:06:42 +00001035
1036 addr &= TARGET_PAGE_MASK;
1037 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +00001038 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +00001039 return;
1040 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +00001041 current_tb_modified = 0;
1042 current_tb = NULL;
1043 current_pc = 0; /* avoid warning */
1044 current_cs_base = 0; /* avoid warning */
1045 current_flags = 0; /* avoid warning */
1046#ifdef TARGET_HAS_PRECISE_SMC
1047 if (tb && pc != 0) {
1048 current_tb = tb_find_pc(pc);
1049 }
1050#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001051 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +00001052 n = (long)tb & 3;
1053 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +00001054#ifdef TARGET_HAS_PRECISE_SMC
1055 if (current_tb == tb &&
pbrook2e70f6e2008-06-29 01:03:05 +00001056 (current_tb->cflags & CF_COUNT_MASK) != 1) {
bellardd720b932004-04-25 17:57:43 +00001057 /* If we are modifying the current TB, we must stop
1058 its execution. We could be more precise by checking
1059 that the modification is after the current PC, but it
1060 would require a specialized function to partially
1061 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +00001062
bellardd720b932004-04-25 17:57:43 +00001063 current_tb_modified = 1;
1064 cpu_restore_state(current_tb, env, pc, puc);
1065#if defined(TARGET_I386)
1066 current_flags = env->hflags;
1067 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
1068 current_cs_base = (target_ulong)env->segs[R_CS].base;
1069 current_pc = current_cs_base + env->eip;
1070#else
1071#error unsupported CPU
1072#endif
1073 }
1074#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +00001075 tb_phys_invalidate(tb, addr);
1076 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +00001077 }
1078 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +00001079#ifdef TARGET_HAS_PRECISE_SMC
1080 if (current_tb_modified) {
1081 /* we generate a block containing just the instruction
1082 modifying the memory. It will ensure that it cannot modify
1083 itself */
bellardea1c1802004-06-14 18:56:36 +00001084 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +00001085 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
bellardd720b932004-04-25 17:57:43 +00001086 cpu_resume_from_signal(env, puc);
1087 }
1088#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001089}
bellard9fa3e852004-01-04 18:06:42 +00001090#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001091
1092/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +00001093static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +00001094 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +00001095{
1096 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +00001097 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001098
bellard9fa3e852004-01-04 18:06:42 +00001099 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +00001100 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001101 tb->page_next[n] = p->first_tb;
1102 last_first_tb = p->first_tb;
1103 p->first_tb = (TranslationBlock *)((long)tb | n);
1104 invalidate_page_bitmap(p);
1105
bellard107db442004-06-22 18:48:46 +00001106#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +00001107
bellard9fa3e852004-01-04 18:06:42 +00001108#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +00001109 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001110 target_ulong addr;
1111 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001112 int prot;
1113
bellardfd6ce8f2003-05-14 19:00:11 +00001114 /* force the host page as non writable (writes will have a
1115 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001116 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001117 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001118 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1119 addr += TARGET_PAGE_SIZE) {
1120
1121 p2 = page_find (addr >> TARGET_PAGE_BITS);
1122 if (!p2)
1123 continue;
1124 prot |= p2->flags;
1125 p2->flags &= ~PAGE_WRITE;
1126 page_get_flags(addr);
1127 }
ths5fafdf22007-09-16 21:08:06 +00001128 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001129 (prot & PAGE_BITS) & ~PAGE_WRITE);
1130#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001131 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001132 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001133#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001134 }
bellard9fa3e852004-01-04 18:06:42 +00001135#else
1136 /* if some code is already present, then the pages are already
1137 protected. So we handle the case where only the first TB is
1138 allocated in a physical page */
1139 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001140 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001141 }
1142#endif
bellardd720b932004-04-25 17:57:43 +00001143
1144#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001145}
1146
1147/* Allocate a new translation block. Flush the translation buffer if
1148 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001149TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001150{
1151 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001152
bellard26a5f132008-05-28 12:30:31 +00001153 if (nb_tbs >= code_gen_max_blocks ||
1154 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001155 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001156 tb = &tbs[nb_tbs++];
1157 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001158 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001159 return tb;
1160}
1161
pbrook2e70f6e2008-06-29 01:03:05 +00001162void tb_free(TranslationBlock *tb)
1163{
thsbf20dc02008-06-30 17:22:19 +00001164 /* In practice this is mostly used for single use temporary TB
pbrook2e70f6e2008-06-29 01:03:05 +00001165 Ignore the hard cases and just back up if this TB happens to
1166 be the last one generated. */
1167 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1168 code_gen_ptr = tb->tc_ptr;
1169 nb_tbs--;
1170 }
1171}
1172
bellard9fa3e852004-01-04 18:06:42 +00001173/* add a new TB and link it to the physical page tables. phys_page2 is
1174 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001175void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001176 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001177{
bellard9fa3e852004-01-04 18:06:42 +00001178 unsigned int h;
1179 TranslationBlock **ptb;
1180
pbrookc8a706f2008-06-02 16:16:42 +00001181 /* Grab the mmap lock to stop another thread invalidating this TB
1182 before we are done. */
1183 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001184 /* add in the physical hash table */
1185 h = tb_phys_hash_func(phys_pc);
1186 ptb = &tb_phys_hash[h];
1187 tb->phys_hash_next = *ptb;
1188 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001189
1190 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001191 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1192 if (phys_page2 != -1)
1193 tb_alloc_page(tb, 1, phys_page2);
1194 else
1195 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001196
bellardd4e81642003-05-25 16:46:15 +00001197 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1198 tb->jmp_next[0] = NULL;
1199 tb->jmp_next[1] = NULL;
1200
1201 /* init original jump addresses */
1202 if (tb->tb_next_offset[0] != 0xffff)
1203 tb_reset_jump(tb, 0);
1204 if (tb->tb_next_offset[1] != 0xffff)
1205 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001206
1207#ifdef DEBUG_TB_CHECK
1208 tb_page_check();
1209#endif
pbrookc8a706f2008-06-02 16:16:42 +00001210 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001211}
1212
bellarda513fe12003-05-27 23:29:48 +00001213/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1214 tb[1].tc_ptr. Return NULL if not found */
1215TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1216{
1217 int m_min, m_max, m;
1218 unsigned long v;
1219 TranslationBlock *tb;
1220
1221 if (nb_tbs <= 0)
1222 return NULL;
1223 if (tc_ptr < (unsigned long)code_gen_buffer ||
1224 tc_ptr >= (unsigned long)code_gen_ptr)
1225 return NULL;
1226 /* binary search (cf Knuth) */
1227 m_min = 0;
1228 m_max = nb_tbs - 1;
1229 while (m_min <= m_max) {
1230 m = (m_min + m_max) >> 1;
1231 tb = &tbs[m];
1232 v = (unsigned long)tb->tc_ptr;
1233 if (v == tc_ptr)
1234 return tb;
1235 else if (tc_ptr < v) {
1236 m_max = m - 1;
1237 } else {
1238 m_min = m + 1;
1239 }
ths5fafdf22007-09-16 21:08:06 +00001240 }
bellarda513fe12003-05-27 23:29:48 +00001241 return &tbs[m_max];
1242}
bellard75012672003-06-21 13:11:07 +00001243
bellardea041c02003-06-25 16:16:50 +00001244static void tb_reset_jump_recursive(TranslationBlock *tb);
1245
1246static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1247{
1248 TranslationBlock *tb1, *tb_next, **ptb;
1249 unsigned int n1;
1250
1251 tb1 = tb->jmp_next[n];
1252 if (tb1 != NULL) {
1253 /* find head of list */
1254 for(;;) {
1255 n1 = (long)tb1 & 3;
1256 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1257 if (n1 == 2)
1258 break;
1259 tb1 = tb1->jmp_next[n1];
1260 }
1261 /* we are now sure now that tb jumps to tb1 */
1262 tb_next = tb1;
1263
1264 /* remove tb from the jmp_first list */
1265 ptb = &tb_next->jmp_first;
1266 for(;;) {
1267 tb1 = *ptb;
1268 n1 = (long)tb1 & 3;
1269 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1270 if (n1 == n && tb1 == tb)
1271 break;
1272 ptb = &tb1->jmp_next[n1];
1273 }
1274 *ptb = tb->jmp_next[n];
1275 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001276
bellardea041c02003-06-25 16:16:50 +00001277 /* suppress the jump to next tb in generated code */
1278 tb_reset_jump(tb, n);
1279
bellard01243112004-01-04 15:48:17 +00001280 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001281 tb_reset_jump_recursive(tb_next);
1282 }
1283}
1284
1285static void tb_reset_jump_recursive(TranslationBlock *tb)
1286{
1287 tb_reset_jump_recursive2(tb, 0);
1288 tb_reset_jump_recursive2(tb, 1);
1289}
1290
bellard1fddef42005-04-17 19:16:13 +00001291#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001292static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1293{
j_mayer9b3c35e2007-04-07 11:21:28 +00001294 target_phys_addr_t addr;
1295 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001296 ram_addr_t ram_addr;
1297 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001298
pbrookc2f07f82006-04-08 17:14:56 +00001299 addr = cpu_get_phys_page_debug(env, pc);
1300 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1301 if (!p) {
1302 pd = IO_MEM_UNASSIGNED;
1303 } else {
1304 pd = p->phys_offset;
1305 }
1306 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001307 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001308}
bellardc27004e2005-01-03 23:35:10 +00001309#endif
bellardd720b932004-04-25 17:57:43 +00001310
pbrook6658ffb2007-03-16 23:58:11 +00001311/* Add a watchpoint. */
pbrook0f459d12008-06-09 00:20:13 +00001312int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
pbrook6658ffb2007-03-16 23:58:11 +00001313{
1314 int i;
1315
1316 for (i = 0; i < env->nb_watchpoints; i++) {
1317 if (addr == env->watchpoint[i].vaddr)
1318 return 0;
1319 }
1320 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1321 return -1;
1322
1323 i = env->nb_watchpoints++;
1324 env->watchpoint[i].vaddr = addr;
pbrook0f459d12008-06-09 00:20:13 +00001325 env->watchpoint[i].type = type;
pbrook6658ffb2007-03-16 23:58:11 +00001326 tlb_flush_page(env, addr);
1327 /* FIXME: This flush is needed because of the hack to make memory ops
1328 terminate the TB. It can be removed once the proper IO trap and
1329 re-execute bits are in. */
1330 tb_flush(env);
1331 return i;
1332}
1333
1334/* Remove a watchpoint. */
1335int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1336{
1337 int i;
1338
1339 for (i = 0; i < env->nb_watchpoints; i++) {
1340 if (addr == env->watchpoint[i].vaddr) {
1341 env->nb_watchpoints--;
1342 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1343 tlb_flush_page(env, addr);
1344 return 0;
1345 }
1346 }
1347 return -1;
1348}
1349
edgar_igl7d03f822008-05-17 18:58:29 +00001350/* Remove all watchpoints. */
1351void cpu_watchpoint_remove_all(CPUState *env) {
1352 int i;
1353
1354 for (i = 0; i < env->nb_watchpoints; i++) {
1355 tlb_flush_page(env, env->watchpoint[i].vaddr);
1356 }
1357 env->nb_watchpoints = 0;
1358}
1359
bellardc33a3462003-07-29 20:50:33 +00001360/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1361 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001362int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001363{
bellard1fddef42005-04-17 19:16:13 +00001364#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001365 int i;
ths3b46e622007-09-17 08:09:54 +00001366
bellard4c3a88a2003-07-26 12:06:08 +00001367 for(i = 0; i < env->nb_breakpoints; i++) {
1368 if (env->breakpoints[i] == pc)
1369 return 0;
1370 }
1371
1372 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1373 return -1;
1374 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001375
bellardd720b932004-04-25 17:57:43 +00001376 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001377 return 0;
1378#else
1379 return -1;
1380#endif
1381}
1382
edgar_igl7d03f822008-05-17 18:58:29 +00001383/* remove all breakpoints */
1384void cpu_breakpoint_remove_all(CPUState *env) {
1385#if defined(TARGET_HAS_ICE)
1386 int i;
1387 for(i = 0; i < env->nb_breakpoints; i++) {
1388 breakpoint_invalidate(env, env->breakpoints[i]);
1389 }
1390 env->nb_breakpoints = 0;
1391#endif
1392}
1393
bellard4c3a88a2003-07-26 12:06:08 +00001394/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001395int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001396{
bellard1fddef42005-04-17 19:16:13 +00001397#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001398 int i;
1399 for(i = 0; i < env->nb_breakpoints; i++) {
1400 if (env->breakpoints[i] == pc)
1401 goto found;
1402 }
1403 return -1;
1404 found:
bellard4c3a88a2003-07-26 12:06:08 +00001405 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001406 if (i < env->nb_breakpoints)
1407 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001408
1409 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001410 return 0;
1411#else
1412 return -1;
1413#endif
1414}
1415
bellardc33a3462003-07-29 20:50:33 +00001416/* enable or disable single step mode. EXCP_DEBUG is returned by the
1417 CPU loop after each instruction */
1418void cpu_single_step(CPUState *env, int enabled)
1419{
bellard1fddef42005-04-17 19:16:13 +00001420#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001421 if (env->singlestep_enabled != enabled) {
1422 env->singlestep_enabled = enabled;
1423 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001424 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001425 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001426 }
1427#endif
1428}
1429
bellard34865132003-10-05 14:28:56 +00001430/* enable or disable low levels log */
1431void cpu_set_log(int log_flags)
1432{
1433 loglevel = log_flags;
1434 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001435 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001436 if (!logfile) {
1437 perror(logfilename);
1438 _exit(1);
1439 }
bellard9fa3e852004-01-04 18:06:42 +00001440#if !defined(CONFIG_SOFTMMU)
1441 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1442 {
blueswir1b55266b2008-09-20 08:07:15 +00001443 static char logfile_buf[4096];
bellard9fa3e852004-01-04 18:06:42 +00001444 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1445 }
1446#else
bellard34865132003-10-05 14:28:56 +00001447 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001448#endif
pbrooke735b912007-06-30 13:53:24 +00001449 log_append = 1;
1450 }
1451 if (!loglevel && logfile) {
1452 fclose(logfile);
1453 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001454 }
1455}
1456
1457void cpu_set_log_filename(const char *filename)
1458{
1459 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001460 if (logfile) {
1461 fclose(logfile);
1462 logfile = NULL;
1463 }
1464 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001465}
bellardc33a3462003-07-29 20:50:33 +00001466
bellard01243112004-01-04 15:48:17 +00001467/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001468void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001469{
pbrookd5975362008-06-07 20:50:51 +00001470#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001471 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001472 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001473#endif
pbrook2e70f6e2008-06-29 01:03:05 +00001474 int old_mask;
bellard59817cc2004-02-16 22:01:13 +00001475
pbrook2e70f6e2008-06-29 01:03:05 +00001476 old_mask = env->interrupt_request;
pbrookd5975362008-06-07 20:50:51 +00001477 /* FIXME: This is probably not threadsafe. A different thread could
thsbf20dc02008-06-30 17:22:19 +00001478 be in the middle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001479 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001480#if defined(USE_NPTL)
1481 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1482 problem and hope the cpu will stop of its own accord. For userspace
1483 emulation this often isn't actually as bad as it sounds. Often
1484 signals are used primarily to interrupt blocking syscalls. */
1485#else
pbrook2e70f6e2008-06-29 01:03:05 +00001486 if (use_icount) {
pbrook266910c2008-07-09 15:31:50 +00001487 env->icount_decr.u16.high = 0xffff;
pbrook2e70f6e2008-06-29 01:03:05 +00001488#ifndef CONFIG_USER_ONLY
1489 /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
1490 an async event happened and we need to process it. */
1491 if (!can_do_io(env)
1492 && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
1493 cpu_abort(env, "Raised interrupt while not in I/O function");
1494 }
1495#endif
1496 } else {
1497 tb = env->current_tb;
1498 /* if the cpu is currently executing code, we must unlink it and
1499 all the potentially executing TB */
1500 if (tb && !testandset(&interrupt_lock)) {
1501 env->current_tb = NULL;
1502 tb_reset_jump_recursive(tb);
1503 resetlock(&interrupt_lock);
1504 }
bellardea041c02003-06-25 16:16:50 +00001505 }
pbrookd5975362008-06-07 20:50:51 +00001506#endif
bellardea041c02003-06-25 16:16:50 +00001507}
1508
bellardb54ad042004-05-20 13:42:52 +00001509void cpu_reset_interrupt(CPUState *env, int mask)
1510{
1511 env->interrupt_request &= ~mask;
1512}
1513
bellardf193c792004-03-21 17:06:25 +00001514CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001515 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001516 "show generated host assembly code for each compiled TB" },
1517 { CPU_LOG_TB_IN_ASM, "in_asm",
1518 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001519 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001520 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001521 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001522 "show micro ops "
1523#ifdef TARGET_I386
1524 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001525#endif
blueswir1e01a1152008-03-14 17:37:11 +00001526 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001527 { CPU_LOG_INT, "int",
1528 "show interrupts/exceptions in short format" },
1529 { CPU_LOG_EXEC, "exec",
1530 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001531 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001532 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001533#ifdef TARGET_I386
1534 { CPU_LOG_PCALL, "pcall",
1535 "show protected mode far calls/returns/exceptions" },
1536#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001537#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001538 { CPU_LOG_IOPORT, "ioport",
1539 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001540#endif
bellardf193c792004-03-21 17:06:25 +00001541 { 0, NULL, NULL },
1542};
1543
1544static int cmp1(const char *s1, int n, const char *s2)
1545{
1546 if (strlen(s2) != n)
1547 return 0;
1548 return memcmp(s1, s2, n) == 0;
1549}
ths3b46e622007-09-17 08:09:54 +00001550
bellardf193c792004-03-21 17:06:25 +00001551/* takes a comma separated list of log masks. Return 0 if error. */
1552int cpu_str_to_log_mask(const char *str)
1553{
1554 CPULogItem *item;
1555 int mask;
1556 const char *p, *p1;
1557
1558 p = str;
1559 mask = 0;
1560 for(;;) {
1561 p1 = strchr(p, ',');
1562 if (!p1)
1563 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001564 if(cmp1(p,p1-p,"all")) {
1565 for(item = cpu_log_items; item->mask != 0; item++) {
1566 mask |= item->mask;
1567 }
1568 } else {
bellardf193c792004-03-21 17:06:25 +00001569 for(item = cpu_log_items; item->mask != 0; item++) {
1570 if (cmp1(p, p1 - p, item->name))
1571 goto found;
1572 }
1573 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001574 }
bellardf193c792004-03-21 17:06:25 +00001575 found:
1576 mask |= item->mask;
1577 if (*p1 != ',')
1578 break;
1579 p = p1 + 1;
1580 }
1581 return mask;
1582}
bellardea041c02003-06-25 16:16:50 +00001583
bellard75012672003-06-21 13:11:07 +00001584void cpu_abort(CPUState *env, const char *fmt, ...)
1585{
1586 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001587 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001588
1589 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001590 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001591 fprintf(stderr, "qemu: fatal: ");
1592 vfprintf(stderr, fmt, ap);
1593 fprintf(stderr, "\n");
1594#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001595 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1596#else
1597 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001598#endif
balrog924edca2007-06-10 14:07:13 +00001599 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001600 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001601 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001602 fprintf(logfile, "\n");
1603#ifdef TARGET_I386
1604 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1605#else
1606 cpu_dump_state(env, logfile, fprintf, 0);
1607#endif
balrog924edca2007-06-10 14:07:13 +00001608 fflush(logfile);
1609 fclose(logfile);
1610 }
pbrook493ae1f2007-11-23 16:53:59 +00001611 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001612 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001613 abort();
1614}
1615
thsc5be9f02007-02-28 20:20:53 +00001616CPUState *cpu_copy(CPUState *env)
1617{
ths01ba9812007-12-09 02:22:57 +00001618 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001619 /* preserve chaining and index */
1620 CPUState *next_cpu = new_env->next_cpu;
1621 int cpu_index = new_env->cpu_index;
1622 memcpy(new_env, env, sizeof(CPUState));
1623 new_env->next_cpu = next_cpu;
1624 new_env->cpu_index = cpu_index;
1625 return new_env;
1626}
1627
bellard01243112004-01-04 15:48:17 +00001628#if !defined(CONFIG_USER_ONLY)
1629
edgar_igl5c751e92008-05-06 08:44:21 +00001630static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1631{
1632 unsigned int i;
1633
1634 /* Discard jump cache entries for any tb which might potentially
1635 overlap the flushed page. */
1636 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1637 memset (&env->tb_jmp_cache[i], 0,
1638 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1639
1640 i = tb_jmp_cache_hash_page(addr);
1641 memset (&env->tb_jmp_cache[i], 0,
1642 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1643}
1644
bellardee8b7022004-02-03 23:35:10 +00001645/* NOTE: if flush_global is true, also flush global entries (not
1646 implemented yet) */
1647void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001648{
bellard33417e72003-08-10 21:47:01 +00001649 int i;
bellard01243112004-01-04 15:48:17 +00001650
bellard9fa3e852004-01-04 18:06:42 +00001651#if defined(DEBUG_TLB)
1652 printf("tlb_flush:\n");
1653#endif
bellard01243112004-01-04 15:48:17 +00001654 /* must reset current TB so that interrupts cannot modify the
1655 links while we are modifying them */
1656 env->current_tb = NULL;
1657
bellard33417e72003-08-10 21:47:01 +00001658 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001659 env->tlb_table[0][i].addr_read = -1;
1660 env->tlb_table[0][i].addr_write = -1;
1661 env->tlb_table[0][i].addr_code = -1;
1662 env->tlb_table[1][i].addr_read = -1;
1663 env->tlb_table[1][i].addr_write = -1;
1664 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001665#if (NB_MMU_MODES >= 3)
1666 env->tlb_table[2][i].addr_read = -1;
1667 env->tlb_table[2][i].addr_write = -1;
1668 env->tlb_table[2][i].addr_code = -1;
1669#if (NB_MMU_MODES == 4)
1670 env->tlb_table[3][i].addr_read = -1;
1671 env->tlb_table[3][i].addr_write = -1;
1672 env->tlb_table[3][i].addr_code = -1;
1673#endif
1674#endif
bellard33417e72003-08-10 21:47:01 +00001675 }
bellard9fa3e852004-01-04 18:06:42 +00001676
bellard8a40a182005-11-20 10:35:40 +00001677 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001678
bellard0a962c02005-02-10 22:00:27 +00001679#ifdef USE_KQEMU
1680 if (env->kqemu_enabled) {
1681 kqemu_flush(env, flush_global);
1682 }
1683#endif
bellarde3db7222005-01-26 22:00:47 +00001684 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001685}
1686
bellard274da6b2004-05-20 21:56:27 +00001687static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001688{
ths5fafdf22007-09-16 21:08:06 +00001689 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001690 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001691 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001692 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001693 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001694 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1695 tlb_entry->addr_read = -1;
1696 tlb_entry->addr_write = -1;
1697 tlb_entry->addr_code = -1;
1698 }
bellard61382a52003-10-27 21:22:23 +00001699}
1700
bellard2e126692004-04-25 21:28:44 +00001701void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001702{
bellard8a40a182005-11-20 10:35:40 +00001703 int i;
bellard01243112004-01-04 15:48:17 +00001704
bellard9fa3e852004-01-04 18:06:42 +00001705#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001706 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001707#endif
bellard01243112004-01-04 15:48:17 +00001708 /* must reset current TB so that interrupts cannot modify the
1709 links while we are modifying them */
1710 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001711
bellard61382a52003-10-27 21:22:23 +00001712 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001713 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001714 tlb_flush_entry(&env->tlb_table[0][i], addr);
1715 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001716#if (NB_MMU_MODES >= 3)
1717 tlb_flush_entry(&env->tlb_table[2][i], addr);
1718#if (NB_MMU_MODES == 4)
1719 tlb_flush_entry(&env->tlb_table[3][i], addr);
1720#endif
1721#endif
bellard01243112004-01-04 15:48:17 +00001722
edgar_igl5c751e92008-05-06 08:44:21 +00001723 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001724
bellard0a962c02005-02-10 22:00:27 +00001725#ifdef USE_KQEMU
1726 if (env->kqemu_enabled) {
1727 kqemu_flush_page(env, addr);
1728 }
1729#endif
bellard9fa3e852004-01-04 18:06:42 +00001730}
1731
bellard9fa3e852004-01-04 18:06:42 +00001732/* update the TLBs so that writes to code in the virtual page 'addr'
1733 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001734static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001735{
ths5fafdf22007-09-16 21:08:06 +00001736 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001737 ram_addr + TARGET_PAGE_SIZE,
1738 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001739}
1740
bellard9fa3e852004-01-04 18:06:42 +00001741/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001742 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001743static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001744 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001745{
bellard3a7d9292005-08-21 09:26:42 +00001746 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001747}
1748
ths5fafdf22007-09-16 21:08:06 +00001749static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001750 unsigned long start, unsigned long length)
1751{
1752 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001753 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1754 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001755 if ((addr - start) < length) {
pbrook0f459d12008-06-09 00:20:13 +00001756 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001757 }
1758 }
1759}
1760
bellard3a7d9292005-08-21 09:26:42 +00001761void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001762 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001763{
1764 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001765 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001766 int i, mask, len;
1767 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001768
1769 start &= TARGET_PAGE_MASK;
1770 end = TARGET_PAGE_ALIGN(end);
1771
1772 length = end - start;
1773 if (length == 0)
1774 return;
bellard0a962c02005-02-10 22:00:27 +00001775 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001776#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001777 /* XXX: should not depend on cpu context */
1778 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001779 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001780 ram_addr_t addr;
1781 addr = start;
1782 for(i = 0; i < len; i++) {
1783 kqemu_set_notdirty(env, addr);
1784 addr += TARGET_PAGE_SIZE;
1785 }
bellard3a7d9292005-08-21 09:26:42 +00001786 }
1787#endif
bellardf23db162005-08-21 19:12:28 +00001788 mask = ~dirty_flags;
1789 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1790 for(i = 0; i < len; i++)
1791 p[i] &= mask;
1792
bellard1ccde1c2004-02-06 19:46:14 +00001793 /* we modify the TLB cache so that the dirty bit will be set again
1794 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001795 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001796 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1797 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001798 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001799 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001800 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001801#if (NB_MMU_MODES >= 3)
1802 for(i = 0; i < CPU_TLB_SIZE; i++)
1803 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1804#if (NB_MMU_MODES == 4)
1805 for(i = 0; i < CPU_TLB_SIZE; i++)
1806 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1807#endif
1808#endif
bellard6a00d602005-11-21 23:25:50 +00001809 }
bellard1ccde1c2004-02-06 19:46:14 +00001810}
1811
bellard3a7d9292005-08-21 09:26:42 +00001812static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1813{
1814 ram_addr_t ram_addr;
1815
bellard84b7b8e2005-11-28 21:19:04 +00001816 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001817 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001818 tlb_entry->addend - (unsigned long)phys_ram_base;
1819 if (!cpu_physical_memory_is_dirty(ram_addr)) {
pbrook0f459d12008-06-09 00:20:13 +00001820 tlb_entry->addr_write |= TLB_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001821 }
1822 }
1823}
1824
1825/* update the TLB according to the current state of the dirty bits */
1826void cpu_tlb_update_dirty(CPUState *env)
1827{
1828 int i;
1829 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001830 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001831 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001832 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001833#if (NB_MMU_MODES >= 3)
1834 for(i = 0; i < CPU_TLB_SIZE; i++)
1835 tlb_update_dirty(&env->tlb_table[2][i]);
1836#if (NB_MMU_MODES == 4)
1837 for(i = 0; i < CPU_TLB_SIZE; i++)
1838 tlb_update_dirty(&env->tlb_table[3][i]);
1839#endif
1840#endif
bellard3a7d9292005-08-21 09:26:42 +00001841}
1842
pbrook0f459d12008-06-09 00:20:13 +00001843static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001844{
pbrook0f459d12008-06-09 00:20:13 +00001845 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1846 tlb_entry->addr_write = vaddr;
bellard1ccde1c2004-02-06 19:46:14 +00001847}
1848
pbrook0f459d12008-06-09 00:20:13 +00001849/* update the TLB corresponding to virtual page vaddr
1850 so that it is no longer dirty */
1851static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001852{
bellard1ccde1c2004-02-06 19:46:14 +00001853 int i;
1854
pbrook0f459d12008-06-09 00:20:13 +00001855 vaddr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001856 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
pbrook0f459d12008-06-09 00:20:13 +00001857 tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
1858 tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001859#if (NB_MMU_MODES >= 3)
pbrook0f459d12008-06-09 00:20:13 +00001860 tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001861#if (NB_MMU_MODES == 4)
pbrook0f459d12008-06-09 00:20:13 +00001862 tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001863#endif
1864#endif
bellard9fa3e852004-01-04 18:06:42 +00001865}
1866
bellard59817cc2004-02-16 22:01:13 +00001867/* add a new TLB entry. At most one entry for a given virtual address
1868 is permitted. Return 0 if OK or 2 if the page could not be mapped
1869 (can only happen in non SOFTMMU mode for I/O pages or pages
1870 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001871int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1872 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001873 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001874{
bellard92e873b2004-05-21 14:52:29 +00001875 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001876 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001877 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001878 target_ulong address;
pbrook0f459d12008-06-09 00:20:13 +00001879 target_ulong code_address;
bellard108c49b2005-07-24 12:55:09 +00001880 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001881 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001882 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001883 int i;
pbrook0f459d12008-06-09 00:20:13 +00001884 target_phys_addr_t iotlb;
bellard9fa3e852004-01-04 18:06:42 +00001885
bellard92e873b2004-05-21 14:52:29 +00001886 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001887 if (!p) {
1888 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001889 } else {
1890 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001891 }
1892#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001893 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1894 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001895#endif
1896
1897 ret = 0;
pbrook0f459d12008-06-09 00:20:13 +00001898 address = vaddr;
1899 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1900 /* IO memory case (romd handled later) */
1901 address |= TLB_MMIO;
1902 }
1903 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1904 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1905 /* Normal RAM. */
1906 iotlb = pd & TARGET_PAGE_MASK;
1907 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
1908 iotlb |= IO_MEM_NOTDIRTY;
1909 else
1910 iotlb |= IO_MEM_ROM;
1911 } else {
1912 /* IO handlers are currently passed a phsical address.
1913 It would be nice to pass an offset from the base address
1914 of that region. This would avoid having to special case RAM,
1915 and avoid full address decoding in every device.
1916 We can't use the high bits of pd for this because
1917 IO_MEM_ROMD uses these as a ram address. */
1918 iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
1919 }
pbrook6658ffb2007-03-16 23:58:11 +00001920
pbrook0f459d12008-06-09 00:20:13 +00001921 code_address = address;
1922 /* Make accesses to pages with watchpoints go via the
1923 watchpoint trap routines. */
1924 for (i = 0; i < env->nb_watchpoints; i++) {
1925 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1926 iotlb = io_mem_watch + paddr;
1927 /* TODO: The memory case can be optimized by not trapping
1928 reads of pages with a write breakpoint. */
1929 address |= TLB_MMIO;
pbrook6658ffb2007-03-16 23:58:11 +00001930 }
pbrook0f459d12008-06-09 00:20:13 +00001931 }
balrogd79acba2007-06-26 20:01:13 +00001932
pbrook0f459d12008-06-09 00:20:13 +00001933 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1934 env->iotlb[mmu_idx][index] = iotlb - vaddr;
1935 te = &env->tlb_table[mmu_idx][index];
1936 te->addend = addend - vaddr;
1937 if (prot & PAGE_READ) {
1938 te->addr_read = address;
1939 } else {
1940 te->addr_read = -1;
1941 }
edgar_igl5c751e92008-05-06 08:44:21 +00001942
pbrook0f459d12008-06-09 00:20:13 +00001943 if (prot & PAGE_EXEC) {
1944 te->addr_code = code_address;
1945 } else {
1946 te->addr_code = -1;
1947 }
1948 if (prot & PAGE_WRITE) {
1949 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1950 (pd & IO_MEM_ROMD)) {
1951 /* Write access calls the I/O callback. */
1952 te->addr_write = address | TLB_MMIO;
1953 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1954 !cpu_physical_memory_is_dirty(pd)) {
1955 te->addr_write = address | TLB_NOTDIRTY;
bellard84b7b8e2005-11-28 21:19:04 +00001956 } else {
pbrook0f459d12008-06-09 00:20:13 +00001957 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001958 }
pbrook0f459d12008-06-09 00:20:13 +00001959 } else {
1960 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001961 }
bellard9fa3e852004-01-04 18:06:42 +00001962 return ret;
1963}
1964
bellard01243112004-01-04 15:48:17 +00001965#else
1966
bellardee8b7022004-02-03 23:35:10 +00001967void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001968{
1969}
1970
bellard2e126692004-04-25 21:28:44 +00001971void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001972{
1973}
1974
ths5fafdf22007-09-16 21:08:06 +00001975int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1976 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001977 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001978{
bellard9fa3e852004-01-04 18:06:42 +00001979 return 0;
1980}
bellard33417e72003-08-10 21:47:01 +00001981
bellard9fa3e852004-01-04 18:06:42 +00001982/* dump memory mappings */
1983void page_dump(FILE *f)
1984{
1985 unsigned long start, end;
1986 int i, j, prot, prot1;
1987 PageDesc *p;
1988
1989 fprintf(f, "%-8s %-8s %-8s %s\n",
1990 "start", "end", "size", "prot");
1991 start = -1;
1992 end = -1;
1993 prot = 0;
1994 for(i = 0; i <= L1_SIZE; i++) {
1995 if (i < L1_SIZE)
1996 p = l1_map[i];
1997 else
1998 p = NULL;
1999 for(j = 0;j < L2_SIZE; j++) {
2000 if (!p)
2001 prot1 = 0;
2002 else
2003 prot1 = p[j].flags;
2004 if (prot1 != prot) {
2005 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2006 if (start != -1) {
2007 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00002008 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00002009 prot & PAGE_READ ? 'r' : '-',
2010 prot & PAGE_WRITE ? 'w' : '-',
2011 prot & PAGE_EXEC ? 'x' : '-');
2012 }
2013 if (prot1 != 0)
2014 start = end;
2015 else
2016 start = -1;
2017 prot = prot1;
2018 }
2019 if (!p)
2020 break;
2021 }
bellard33417e72003-08-10 21:47:01 +00002022 }
bellard33417e72003-08-10 21:47:01 +00002023}
2024
pbrook53a59602006-03-25 19:31:22 +00002025int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00002026{
bellard9fa3e852004-01-04 18:06:42 +00002027 PageDesc *p;
2028
2029 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002030 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00002031 return 0;
2032 return p->flags;
bellard33417e72003-08-10 21:47:01 +00002033}
2034
bellard9fa3e852004-01-04 18:06:42 +00002035/* modify the flags of a page and invalidate the code if
2036 necessary. The flag PAGE_WRITE_ORG is positionned automatically
2037 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00002038void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00002039{
2040 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00002041 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00002042
pbrookc8a706f2008-06-02 16:16:42 +00002043 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00002044 start = start & TARGET_PAGE_MASK;
2045 end = TARGET_PAGE_ALIGN(end);
2046 if (flags & PAGE_WRITE)
2047 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00002048 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2049 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
pbrook17e23772008-06-09 13:47:45 +00002050 /* We may be called for host regions that are outside guest
2051 address space. */
2052 if (!p)
2053 return;
bellard9fa3e852004-01-04 18:06:42 +00002054 /* if the write protection is set, then we invalidate the code
2055 inside */
ths5fafdf22007-09-16 21:08:06 +00002056 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00002057 (flags & PAGE_WRITE) &&
2058 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00002059 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00002060 }
2061 p->flags = flags;
2062 }
bellard9fa3e852004-01-04 18:06:42 +00002063}
2064
ths3d97b402007-11-02 19:02:07 +00002065int page_check_range(target_ulong start, target_ulong len, int flags)
2066{
2067 PageDesc *p;
2068 target_ulong end;
2069 target_ulong addr;
2070
2071 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2072 start = start & TARGET_PAGE_MASK;
2073
2074 if( end < start )
2075 /* we've wrapped around */
2076 return -1;
2077 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2078 p = page_find(addr >> TARGET_PAGE_BITS);
2079 if( !p )
2080 return -1;
2081 if( !(p->flags & PAGE_VALID) )
2082 return -1;
2083
bellarddae32702007-11-14 10:51:00 +00002084 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00002085 return -1;
bellarddae32702007-11-14 10:51:00 +00002086 if (flags & PAGE_WRITE) {
2087 if (!(p->flags & PAGE_WRITE_ORG))
2088 return -1;
2089 /* unprotect the page if it was put read-only because it
2090 contains translated code */
2091 if (!(p->flags & PAGE_WRITE)) {
2092 if (!page_unprotect(addr, 0, NULL))
2093 return -1;
2094 }
2095 return 0;
2096 }
ths3d97b402007-11-02 19:02:07 +00002097 }
2098 return 0;
2099}
2100
bellard9fa3e852004-01-04 18:06:42 +00002101/* called from signal handler: invalidate the code and unprotect the
2102 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00002103int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00002104{
2105 unsigned int page_index, prot, pindex;
2106 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00002107 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00002108
pbrookc8a706f2008-06-02 16:16:42 +00002109 /* Technically this isn't safe inside a signal handler. However we
2110 know this only ever happens in a synchronous SEGV handler, so in
2111 practice it seems to be ok. */
2112 mmap_lock();
2113
bellard83fb7ad2004-07-05 21:25:26 +00002114 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00002115 page_index = host_start >> TARGET_PAGE_BITS;
2116 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00002117 if (!p1) {
2118 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002119 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00002120 }
bellard83fb7ad2004-07-05 21:25:26 +00002121 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00002122 p = p1;
2123 prot = 0;
2124 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2125 prot |= p->flags;
2126 p++;
2127 }
2128 /* if the page was really writable, then we change its
2129 protection back to writable */
2130 if (prot & PAGE_WRITE_ORG) {
2131 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2132 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00002133 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00002134 (prot & PAGE_BITS) | PAGE_WRITE);
2135 p1[pindex].flags |= PAGE_WRITE;
2136 /* and since the content will be modified, we must invalidate
2137 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00002138 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00002139#ifdef DEBUG_TB_CHECK
2140 tb_invalidate_check(address);
2141#endif
pbrookc8a706f2008-06-02 16:16:42 +00002142 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002143 return 1;
2144 }
2145 }
pbrookc8a706f2008-06-02 16:16:42 +00002146 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002147 return 0;
2148}
2149
bellard6a00d602005-11-21 23:25:50 +00002150static inline void tlb_set_dirty(CPUState *env,
2151 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002152{
2153}
bellard9fa3e852004-01-04 18:06:42 +00002154#endif /* defined(CONFIG_USER_ONLY) */
2155
pbrooke2eef172008-06-08 01:09:01 +00002156#if !defined(CONFIG_USER_ONLY)
blueswir1db7b5422007-05-26 17:36:03 +00002157static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002158 ram_addr_t memory);
2159static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2160 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002161#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2162 need_subpage) \
2163 do { \
2164 if (addr > start_addr) \
2165 start_addr2 = 0; \
2166 else { \
2167 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2168 if (start_addr2 > 0) \
2169 need_subpage = 1; \
2170 } \
2171 \
blueswir149e9fba2007-05-30 17:25:06 +00002172 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002173 end_addr2 = TARGET_PAGE_SIZE - 1; \
2174 else { \
2175 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2176 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2177 need_subpage = 1; \
2178 } \
2179 } while (0)
2180
bellard33417e72003-08-10 21:47:01 +00002181/* register physical memory. 'size' must be a multiple of the target
2182 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2183 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002184void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002185 ram_addr_t size,
2186 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002187{
bellard108c49b2005-07-24 12:55:09 +00002188 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002189 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002190 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002191 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002192 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002193
bellardda260242008-05-30 20:48:25 +00002194#ifdef USE_KQEMU
2195 /* XXX: should not depend on cpu context */
2196 env = first_cpu;
2197 if (env->kqemu_enabled) {
2198 kqemu_set_phys_mem(start_addr, size, phys_offset);
2199 }
2200#endif
bellard5fd386f2004-05-23 21:11:22 +00002201 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002202 end_addr = start_addr + (target_phys_addr_t)size;
2203 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002204 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2205 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002206 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002207 target_phys_addr_t start_addr2, end_addr2;
2208 int need_subpage = 0;
2209
2210 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2211 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002212 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002213 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2214 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2215 &p->phys_offset, orig_memory);
2216 } else {
2217 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2218 >> IO_MEM_SHIFT];
2219 }
2220 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2221 } else {
2222 p->phys_offset = phys_offset;
2223 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2224 (phys_offset & IO_MEM_ROMD))
2225 phys_offset += TARGET_PAGE_SIZE;
2226 }
2227 } else {
2228 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2229 p->phys_offset = phys_offset;
2230 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2231 (phys_offset & IO_MEM_ROMD))
2232 phys_offset += TARGET_PAGE_SIZE;
2233 else {
2234 target_phys_addr_t start_addr2, end_addr2;
2235 int need_subpage = 0;
2236
2237 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2238 end_addr2, need_subpage);
2239
blueswir14254fab2008-01-01 16:57:19 +00002240 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002241 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2242 &p->phys_offset, IO_MEM_UNASSIGNED);
2243 subpage_register(subpage, start_addr2, end_addr2,
2244 phys_offset);
2245 }
2246 }
2247 }
bellard33417e72003-08-10 21:47:01 +00002248 }
ths3b46e622007-09-17 08:09:54 +00002249
bellard9d420372006-06-25 22:25:22 +00002250 /* since each CPU stores ram addresses in its TLB cache, we must
2251 reset the modified entries */
2252 /* XXX: slow ! */
2253 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2254 tlb_flush(env, 1);
2255 }
bellard33417e72003-08-10 21:47:01 +00002256}
2257
bellardba863452006-09-24 18:41:10 +00002258/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002259ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002260{
2261 PhysPageDesc *p;
2262
2263 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2264 if (!p)
2265 return IO_MEM_UNASSIGNED;
2266 return p->phys_offset;
2267}
2268
bellarde9a1ab12007-02-08 23:08:38 +00002269/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002270ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002271{
2272 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002273 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002274 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2275 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002276 abort();
2277 }
2278 addr = phys_ram_alloc_offset;
2279 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2280 return addr;
2281}
2282
2283void qemu_ram_free(ram_addr_t addr)
2284{
2285}
2286
bellarda4193c82004-06-03 14:01:43 +00002287static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002288{
pbrook67d3b952006-12-18 05:03:52 +00002289#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002290 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002291#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002292#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002293 do_unassigned_access(addr, 0, 0, 0);
blueswir1eb38c522008-09-06 17:47:39 +00002294#elif defined(TARGET_CRIS)
thsf1ccf902007-10-08 13:16:14 +00002295 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002296#endif
bellard33417e72003-08-10 21:47:01 +00002297 return 0;
2298}
2299
bellarda4193c82004-06-03 14:01:43 +00002300static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002301{
pbrook67d3b952006-12-18 05:03:52 +00002302#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002303 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002304#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002305#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002306 do_unassigned_access(addr, 1, 0, 0);
blueswir1eb38c522008-09-06 17:47:39 +00002307#elif defined(TARGET_CRIS)
thsf1ccf902007-10-08 13:16:14 +00002308 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002309#endif
bellard33417e72003-08-10 21:47:01 +00002310}
2311
2312static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2313 unassigned_mem_readb,
2314 unassigned_mem_readb,
2315 unassigned_mem_readb,
2316};
2317
2318static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2319 unassigned_mem_writeb,
2320 unassigned_mem_writeb,
2321 unassigned_mem_writeb,
2322};
2323
pbrook0f459d12008-06-09 00:20:13 +00002324static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2325 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002326{
bellard3a7d9292005-08-21 09:26:42 +00002327 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002328 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2329 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2330#if !defined(CONFIG_USER_ONLY)
2331 tb_invalidate_phys_page_fast(ram_addr, 1);
2332 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2333#endif
2334 }
pbrook0f459d12008-06-09 00:20:13 +00002335 stb_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002336#ifdef USE_KQEMU
2337 if (cpu_single_env->kqemu_enabled &&
2338 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2339 kqemu_modify_page(cpu_single_env, ram_addr);
2340#endif
bellardf23db162005-08-21 19:12:28 +00002341 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2342 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2343 /* we remove the notdirty callback only if the code has been
2344 flushed */
2345 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002346 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002347}
2348
pbrook0f459d12008-06-09 00:20:13 +00002349static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2350 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002351{
bellard3a7d9292005-08-21 09:26:42 +00002352 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002353 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2354 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2355#if !defined(CONFIG_USER_ONLY)
2356 tb_invalidate_phys_page_fast(ram_addr, 2);
2357 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2358#endif
2359 }
pbrook0f459d12008-06-09 00:20:13 +00002360 stw_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002361#ifdef USE_KQEMU
2362 if (cpu_single_env->kqemu_enabled &&
2363 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2364 kqemu_modify_page(cpu_single_env, ram_addr);
2365#endif
bellardf23db162005-08-21 19:12:28 +00002366 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2367 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2368 /* we remove the notdirty callback only if the code has been
2369 flushed */
2370 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002371 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002372}
2373
pbrook0f459d12008-06-09 00:20:13 +00002374static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2375 uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002376{
bellard3a7d9292005-08-21 09:26:42 +00002377 int dirty_flags;
bellard3a7d9292005-08-21 09:26:42 +00002378 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2379 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2380#if !defined(CONFIG_USER_ONLY)
2381 tb_invalidate_phys_page_fast(ram_addr, 4);
2382 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2383#endif
2384 }
pbrook0f459d12008-06-09 00:20:13 +00002385 stl_p(phys_ram_base + ram_addr, val);
bellardf32fc642006-02-08 22:43:39 +00002386#ifdef USE_KQEMU
2387 if (cpu_single_env->kqemu_enabled &&
2388 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2389 kqemu_modify_page(cpu_single_env, ram_addr);
2390#endif
bellardf23db162005-08-21 19:12:28 +00002391 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2392 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2393 /* we remove the notdirty callback only if the code has been
2394 flushed */
2395 if (dirty_flags == 0xff)
pbrook2e70f6e2008-06-29 01:03:05 +00002396 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002397}
2398
bellard3a7d9292005-08-21 09:26:42 +00002399static CPUReadMemoryFunc *error_mem_read[3] = {
2400 NULL, /* never used */
2401 NULL, /* never used */
2402 NULL, /* never used */
2403};
2404
bellard1ccde1c2004-02-06 19:46:14 +00002405static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2406 notdirty_mem_writeb,
2407 notdirty_mem_writew,
2408 notdirty_mem_writel,
2409};
2410
pbrook0f459d12008-06-09 00:20:13 +00002411/* Generate a debug exception if a watchpoint has been hit. */
2412static void check_watchpoint(int offset, int flags)
2413{
2414 CPUState *env = cpu_single_env;
2415 target_ulong vaddr;
2416 int i;
2417
pbrook2e70f6e2008-06-29 01:03:05 +00002418 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
pbrook0f459d12008-06-09 00:20:13 +00002419 for (i = 0; i < env->nb_watchpoints; i++) {
2420 if (vaddr == env->watchpoint[i].vaddr
2421 && (env->watchpoint[i].type & flags)) {
2422 env->watchpoint_hit = i + 1;
2423 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2424 break;
2425 }
2426 }
2427}
2428
pbrook6658ffb2007-03-16 23:58:11 +00002429/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2430 so these check for a hit then pass through to the normal out-of-line
2431 phys routines. */
2432static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2433{
pbrook0f459d12008-06-09 00:20:13 +00002434 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002435 return ldub_phys(addr);
2436}
2437
2438static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2439{
pbrook0f459d12008-06-09 00:20:13 +00002440 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002441 return lduw_phys(addr);
2442}
2443
2444static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2445{
pbrook0f459d12008-06-09 00:20:13 +00002446 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
pbrook6658ffb2007-03-16 23:58:11 +00002447 return ldl_phys(addr);
2448}
2449
pbrook6658ffb2007-03-16 23:58:11 +00002450static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2451 uint32_t val)
2452{
pbrook0f459d12008-06-09 00:20:13 +00002453 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002454 stb_phys(addr, val);
2455}
2456
2457static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2458 uint32_t val)
2459{
pbrook0f459d12008-06-09 00:20:13 +00002460 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002461 stw_phys(addr, val);
2462}
2463
2464static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2465 uint32_t val)
2466{
pbrook0f459d12008-06-09 00:20:13 +00002467 check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
pbrook6658ffb2007-03-16 23:58:11 +00002468 stl_phys(addr, val);
2469}
2470
2471static CPUReadMemoryFunc *watch_mem_read[3] = {
2472 watch_mem_readb,
2473 watch_mem_readw,
2474 watch_mem_readl,
2475};
2476
2477static CPUWriteMemoryFunc *watch_mem_write[3] = {
2478 watch_mem_writeb,
2479 watch_mem_writew,
2480 watch_mem_writel,
2481};
pbrook6658ffb2007-03-16 23:58:11 +00002482
blueswir1db7b5422007-05-26 17:36:03 +00002483static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2484 unsigned int len)
2485{
blueswir1db7b5422007-05-26 17:36:03 +00002486 uint32_t ret;
2487 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\n", __func__,
2492 mmio, len, addr, idx);
2493#endif
blueswir13ee89922008-01-02 19:45:26 +00002494 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002495
2496 return ret;
2497}
2498
2499static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2500 uint32_t value, unsigned int len)
2501{
blueswir1db7b5422007-05-26 17:36:03 +00002502 unsigned int idx;
2503
2504 idx = SUBPAGE_IDX(addr - mmio->base);
2505#if defined(DEBUG_SUBPAGE)
2506 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2507 mmio, len, addr, idx, value);
2508#endif
blueswir13ee89922008-01-02 19:45:26 +00002509 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002510}
2511
2512static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2513{
2514#if defined(DEBUG_SUBPAGE)
2515 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2516#endif
2517
2518 return subpage_readlen(opaque, addr, 0);
2519}
2520
2521static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2522 uint32_t value)
2523{
2524#if defined(DEBUG_SUBPAGE)
2525 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2526#endif
2527 subpage_writelen(opaque, addr, value, 0);
2528}
2529
2530static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2531{
2532#if defined(DEBUG_SUBPAGE)
2533 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2534#endif
2535
2536 return subpage_readlen(opaque, addr, 1);
2537}
2538
2539static void subpage_writew (void *opaque, target_phys_addr_t addr,
2540 uint32_t value)
2541{
2542#if defined(DEBUG_SUBPAGE)
2543 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2544#endif
2545 subpage_writelen(opaque, addr, value, 1);
2546}
2547
2548static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2549{
2550#if defined(DEBUG_SUBPAGE)
2551 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2552#endif
2553
2554 return subpage_readlen(opaque, addr, 2);
2555}
2556
2557static void subpage_writel (void *opaque,
2558 target_phys_addr_t addr, uint32_t value)
2559{
2560#if defined(DEBUG_SUBPAGE)
2561 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2562#endif
2563 subpage_writelen(opaque, addr, value, 2);
2564}
2565
2566static CPUReadMemoryFunc *subpage_read[] = {
2567 &subpage_readb,
2568 &subpage_readw,
2569 &subpage_readl,
2570};
2571
2572static CPUWriteMemoryFunc *subpage_write[] = {
2573 &subpage_writeb,
2574 &subpage_writew,
2575 &subpage_writel,
2576};
2577
2578static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002579 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002580{
2581 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002582 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002583
2584 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2585 return -1;
2586 idx = SUBPAGE_IDX(start);
2587 eidx = SUBPAGE_IDX(end);
2588#if defined(DEBUG_SUBPAGE)
2589 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2590 mmio, start, end, idx, eidx, memory);
2591#endif
2592 memory >>= IO_MEM_SHIFT;
2593 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002594 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002595 if (io_mem_read[memory][i]) {
2596 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2597 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2598 }
2599 if (io_mem_write[memory][i]) {
2600 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2601 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2602 }
blueswir14254fab2008-01-01 16:57:19 +00002603 }
blueswir1db7b5422007-05-26 17:36:03 +00002604 }
2605
2606 return 0;
2607}
2608
aurel3200f82b82008-04-27 21:12:55 +00002609static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2610 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002611{
2612 subpage_t *mmio;
2613 int subpage_memory;
2614
2615 mmio = qemu_mallocz(sizeof(subpage_t));
2616 if (mmio != NULL) {
2617 mmio->base = base;
2618 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2619#if defined(DEBUG_SUBPAGE)
2620 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2621 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2622#endif
2623 *phys = subpage_memory | IO_MEM_SUBPAGE;
2624 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2625 }
2626
2627 return mmio;
2628}
2629
bellard33417e72003-08-10 21:47:01 +00002630static void io_mem_init(void)
2631{
bellard3a7d9292005-08-21 09:26:42 +00002632 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002633 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002634 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002635 io_mem_nb = 5;
2636
pbrook0f459d12008-06-09 00:20:13 +00002637 io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
pbrook6658ffb2007-03-16 23:58:11 +00002638 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002639 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002640 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002641 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002642}
2643
2644/* mem_read and mem_write are arrays of functions containing the
2645 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002646 2). Functions can be omitted with a NULL function pointer. The
2647 registered functions may be modified dynamically later.
2648 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002649 modified. If it is zero, a new io zone is allocated. The return
2650 value can be used with cpu_register_physical_memory(). (-1) is
2651 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002652int cpu_register_io_memory(int io_index,
2653 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002654 CPUWriteMemoryFunc **mem_write,
2655 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002656{
blueswir14254fab2008-01-01 16:57:19 +00002657 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002658
2659 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002660 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002661 return -1;
2662 io_index = io_mem_nb++;
2663 } else {
2664 if (io_index >= IO_MEM_NB_ENTRIES)
2665 return -1;
2666 }
bellardb5ff1b32005-11-26 10:38:39 +00002667
bellard33417e72003-08-10 21:47:01 +00002668 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002669 if (!mem_read[i] || !mem_write[i])
2670 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002671 io_mem_read[io_index][i] = mem_read[i];
2672 io_mem_write[io_index][i] = mem_write[i];
2673 }
bellarda4193c82004-06-03 14:01:43 +00002674 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002675 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002676}
bellard61382a52003-10-27 21:22:23 +00002677
bellard8926b512004-10-10 15:14:20 +00002678CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2679{
2680 return io_mem_write[io_index >> IO_MEM_SHIFT];
2681}
2682
2683CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2684{
2685 return io_mem_read[io_index >> IO_MEM_SHIFT];
2686}
2687
pbrooke2eef172008-06-08 01:09:01 +00002688#endif /* !defined(CONFIG_USER_ONLY) */
2689
bellard13eb76e2004-01-24 15:23:36 +00002690/* physical memory access (slow version, mainly for debug) */
2691#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002692void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002693 int len, int is_write)
2694{
2695 int l, flags;
2696 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002697 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002698
2699 while (len > 0) {
2700 page = addr & TARGET_PAGE_MASK;
2701 l = (page + TARGET_PAGE_SIZE) - addr;
2702 if (l > len)
2703 l = len;
2704 flags = page_get_flags(page);
2705 if (!(flags & PAGE_VALID))
2706 return;
2707 if (is_write) {
2708 if (!(flags & PAGE_WRITE))
2709 return;
bellard579a97f2007-11-11 14:26:47 +00002710 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002711 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002712 /* FIXME - should this return an error rather than just fail? */
2713 return;
aurel3272fb7da2008-04-27 23:53:45 +00002714 memcpy(p, buf, l);
2715 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002716 } else {
2717 if (!(flags & PAGE_READ))
2718 return;
bellard579a97f2007-11-11 14:26:47 +00002719 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002720 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002721 /* FIXME - should this return an error rather than just fail? */
2722 return;
aurel3272fb7da2008-04-27 23:53:45 +00002723 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002724 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002725 }
2726 len -= l;
2727 buf += l;
2728 addr += l;
2729 }
2730}
bellard8df1cd02005-01-28 22:37:22 +00002731
bellard13eb76e2004-01-24 15:23:36 +00002732#else
ths5fafdf22007-09-16 21:08:06 +00002733void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002734 int len, int is_write)
2735{
2736 int l, io_index;
2737 uint8_t *ptr;
2738 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002739 target_phys_addr_t page;
2740 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002741 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002742
bellard13eb76e2004-01-24 15:23:36 +00002743 while (len > 0) {
2744 page = addr & TARGET_PAGE_MASK;
2745 l = (page + TARGET_PAGE_SIZE) - addr;
2746 if (l > len)
2747 l = len;
bellard92e873b2004-05-21 14:52:29 +00002748 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002749 if (!p) {
2750 pd = IO_MEM_UNASSIGNED;
2751 } else {
2752 pd = p->phys_offset;
2753 }
ths3b46e622007-09-17 08:09:54 +00002754
bellard13eb76e2004-01-24 15:23:36 +00002755 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002756 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002757 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002758 /* XXX: could force cpu_single_env to NULL to avoid
2759 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002760 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002761 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002762 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002763 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002764 l = 4;
2765 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002766 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002767 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002768 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002769 l = 2;
2770 } else {
bellard1c213d12005-09-03 10:49:04 +00002771 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002772 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002773 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002774 l = 1;
2775 }
2776 } else {
bellardb448f2f2004-02-25 23:24:04 +00002777 unsigned long addr1;
2778 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002779 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002780 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002781 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002782 if (!cpu_physical_memory_is_dirty(addr1)) {
2783 /* invalidate code */
2784 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2785 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002786 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002787 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002788 }
bellard13eb76e2004-01-24 15:23:36 +00002789 }
2790 } else {
ths5fafdf22007-09-16 21:08:06 +00002791 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002792 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002793 /* I/O case */
2794 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2795 if (l >= 4 && ((addr & 3) == 0)) {
2796 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002797 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002798 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002799 l = 4;
2800 } else if (l >= 2 && ((addr & 1) == 0)) {
2801 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002802 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002803 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002804 l = 2;
2805 } else {
bellard1c213d12005-09-03 10:49:04 +00002806 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002807 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002808 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002809 l = 1;
2810 }
2811 } else {
2812 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002813 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002814 (addr & ~TARGET_PAGE_MASK);
2815 memcpy(buf, ptr, l);
2816 }
2817 }
2818 len -= l;
2819 buf += l;
2820 addr += l;
2821 }
2822}
bellard8df1cd02005-01-28 22:37:22 +00002823
bellardd0ecd2a2006-04-23 17:14:48 +00002824/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002825void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002826 const uint8_t *buf, int len)
2827{
2828 int l;
2829 uint8_t *ptr;
2830 target_phys_addr_t page;
2831 unsigned long pd;
2832 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002833
bellardd0ecd2a2006-04-23 17:14:48 +00002834 while (len > 0) {
2835 page = addr & TARGET_PAGE_MASK;
2836 l = (page + TARGET_PAGE_SIZE) - addr;
2837 if (l > len)
2838 l = len;
2839 p = phys_page_find(page >> TARGET_PAGE_BITS);
2840 if (!p) {
2841 pd = IO_MEM_UNASSIGNED;
2842 } else {
2843 pd = p->phys_offset;
2844 }
ths3b46e622007-09-17 08:09:54 +00002845
bellardd0ecd2a2006-04-23 17:14:48 +00002846 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002847 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2848 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002849 /* do nothing */
2850 } else {
2851 unsigned long addr1;
2852 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2853 /* ROM/RAM case */
2854 ptr = phys_ram_base + addr1;
2855 memcpy(ptr, buf, l);
2856 }
2857 len -= l;
2858 buf += l;
2859 addr += l;
2860 }
2861}
2862
2863
bellard8df1cd02005-01-28 22:37:22 +00002864/* warning: addr must be aligned */
2865uint32_t ldl_phys(target_phys_addr_t addr)
2866{
2867 int io_index;
2868 uint8_t *ptr;
2869 uint32_t val;
2870 unsigned long pd;
2871 PhysPageDesc *p;
2872
2873 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2874 if (!p) {
2875 pd = IO_MEM_UNASSIGNED;
2876 } else {
2877 pd = p->phys_offset;
2878 }
ths3b46e622007-09-17 08:09:54 +00002879
ths5fafdf22007-09-16 21:08:06 +00002880 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002881 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002882 /* I/O case */
2883 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2884 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2885 } else {
2886 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002887 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002888 (addr & ~TARGET_PAGE_MASK);
2889 val = ldl_p(ptr);
2890 }
2891 return val;
2892}
2893
bellard84b7b8e2005-11-28 21:19:04 +00002894/* warning: addr must be aligned */
2895uint64_t ldq_phys(target_phys_addr_t addr)
2896{
2897 int io_index;
2898 uint8_t *ptr;
2899 uint64_t val;
2900 unsigned long pd;
2901 PhysPageDesc *p;
2902
2903 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2904 if (!p) {
2905 pd = IO_MEM_UNASSIGNED;
2906 } else {
2907 pd = p->phys_offset;
2908 }
ths3b46e622007-09-17 08:09:54 +00002909
bellard2a4188a2006-06-25 21:54:59 +00002910 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2911 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002912 /* I/O case */
2913 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2914#ifdef TARGET_WORDS_BIGENDIAN
2915 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2916 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2917#else
2918 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2919 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2920#endif
2921 } else {
2922 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002923 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002924 (addr & ~TARGET_PAGE_MASK);
2925 val = ldq_p(ptr);
2926 }
2927 return val;
2928}
2929
bellardaab33092005-10-30 20:48:42 +00002930/* XXX: optimize */
2931uint32_t ldub_phys(target_phys_addr_t addr)
2932{
2933 uint8_t val;
2934 cpu_physical_memory_read(addr, &val, 1);
2935 return val;
2936}
2937
2938/* XXX: optimize */
2939uint32_t lduw_phys(target_phys_addr_t addr)
2940{
2941 uint16_t val;
2942 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2943 return tswap16(val);
2944}
2945
bellard8df1cd02005-01-28 22:37:22 +00002946/* warning: addr must be aligned. The ram page is not masked as dirty
2947 and the code inside is not invalidated. It is useful if the dirty
2948 bits are used to track modified PTEs */
2949void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2950{
2951 int io_index;
2952 uint8_t *ptr;
2953 unsigned long pd;
2954 PhysPageDesc *p;
2955
2956 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2957 if (!p) {
2958 pd = IO_MEM_UNASSIGNED;
2959 } else {
2960 pd = p->phys_offset;
2961 }
ths3b46e622007-09-17 08:09:54 +00002962
bellard3a7d9292005-08-21 09:26:42 +00002963 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002964 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2965 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2966 } else {
ths5fafdf22007-09-16 21:08:06 +00002967 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002968 (addr & ~TARGET_PAGE_MASK);
2969 stl_p(ptr, val);
2970 }
2971}
2972
j_mayerbc98a7e2007-04-04 07:55:12 +00002973void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2974{
2975 int io_index;
2976 uint8_t *ptr;
2977 unsigned long pd;
2978 PhysPageDesc *p;
2979
2980 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2981 if (!p) {
2982 pd = IO_MEM_UNASSIGNED;
2983 } else {
2984 pd = p->phys_offset;
2985 }
ths3b46e622007-09-17 08:09:54 +00002986
j_mayerbc98a7e2007-04-04 07:55:12 +00002987 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2988 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2989#ifdef TARGET_WORDS_BIGENDIAN
2990 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2991 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2992#else
2993 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2994 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2995#endif
2996 } else {
ths5fafdf22007-09-16 21:08:06 +00002997 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002998 (addr & ~TARGET_PAGE_MASK);
2999 stq_p(ptr, val);
3000 }
3001}
3002
bellard8df1cd02005-01-28 22:37:22 +00003003/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00003004void stl_phys(target_phys_addr_t addr, uint32_t val)
3005{
3006 int io_index;
3007 uint8_t *ptr;
3008 unsigned long pd;
3009 PhysPageDesc *p;
3010
3011 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3012 if (!p) {
3013 pd = IO_MEM_UNASSIGNED;
3014 } else {
3015 pd = p->phys_offset;
3016 }
ths3b46e622007-09-17 08:09:54 +00003017
bellard3a7d9292005-08-21 09:26:42 +00003018 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00003019 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
3020 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3021 } else {
3022 unsigned long addr1;
3023 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3024 /* RAM case */
3025 ptr = phys_ram_base + addr1;
3026 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00003027 if (!cpu_physical_memory_is_dirty(addr1)) {
3028 /* invalidate code */
3029 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3030 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00003031 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3032 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00003033 }
bellard8df1cd02005-01-28 22:37:22 +00003034 }
3035}
3036
bellardaab33092005-10-30 20:48:42 +00003037/* XXX: optimize */
3038void stb_phys(target_phys_addr_t addr, uint32_t val)
3039{
3040 uint8_t v = val;
3041 cpu_physical_memory_write(addr, &v, 1);
3042}
3043
3044/* XXX: optimize */
3045void stw_phys(target_phys_addr_t addr, uint32_t val)
3046{
3047 uint16_t v = tswap16(val);
3048 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3049}
3050
3051/* XXX: optimize */
3052void stq_phys(target_phys_addr_t addr, uint64_t val)
3053{
3054 val = tswap64(val);
3055 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3056}
3057
bellard13eb76e2004-01-24 15:23:36 +00003058#endif
3059
3060/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00003061int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00003062 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00003063{
3064 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00003065 target_phys_addr_t phys_addr;
3066 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00003067
3068 while (len > 0) {
3069 page = addr & TARGET_PAGE_MASK;
3070 phys_addr = cpu_get_phys_page_debug(env, page);
3071 /* if no physical page mapped, return an error */
3072 if (phys_addr == -1)
3073 return -1;
3074 l = (page + TARGET_PAGE_SIZE) - addr;
3075 if (l > len)
3076 l = len;
ths5fafdf22007-09-16 21:08:06 +00003077 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00003078 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00003079 len -= l;
3080 buf += l;
3081 addr += l;
3082 }
3083 return 0;
3084}
3085
pbrook2e70f6e2008-06-29 01:03:05 +00003086/* in deterministic execution mode, instructions doing device I/Os
3087 must be at the end of the TB */
3088void cpu_io_recompile(CPUState *env, void *retaddr)
3089{
3090 TranslationBlock *tb;
3091 uint32_t n, cflags;
3092 target_ulong pc, cs_base;
3093 uint64_t flags;
3094
3095 tb = tb_find_pc((unsigned long)retaddr);
3096 if (!tb) {
3097 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
3098 retaddr);
3099 }
3100 n = env->icount_decr.u16.low + tb->icount;
3101 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3102 /* Calculate how many instructions had been executed before the fault
thsbf20dc02008-06-30 17:22:19 +00003103 occurred. */
pbrook2e70f6e2008-06-29 01:03:05 +00003104 n = n - env->icount_decr.u16.low;
3105 /* Generate a new TB ending on the I/O insn. */
3106 n++;
3107 /* On MIPS and SH, delay slot instructions can only be restarted if
3108 they were already the first instruction in the TB. If this is not
thsbf20dc02008-06-30 17:22:19 +00003109 the first instruction in a TB then re-execute the preceding
pbrook2e70f6e2008-06-29 01:03:05 +00003110 branch. */
3111#if defined(TARGET_MIPS)
3112 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3113 env->active_tc.PC -= 4;
3114 env->icount_decr.u16.low++;
3115 env->hflags &= ~MIPS_HFLAG_BMASK;
3116 }
3117#elif defined(TARGET_SH4)
3118 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3119 && n > 1) {
3120 env->pc -= 2;
3121 env->icount_decr.u16.low++;
3122 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3123 }
3124#endif
3125 /* This should never happen. */
3126 if (n > CF_COUNT_MASK)
3127 cpu_abort(env, "TB too big during recompile");
3128
3129 cflags = n | CF_LAST_IO;
3130 pc = tb->pc;
3131 cs_base = tb->cs_base;
3132 flags = tb->flags;
3133 tb_phys_invalidate(tb, -1);
3134 /* FIXME: In theory this could raise an exception. In practice
3135 we have already translated the block once so it's probably ok. */
3136 tb_gen_code(env, pc, cs_base, flags, cflags);
thsbf20dc02008-06-30 17:22:19 +00003137 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
pbrook2e70f6e2008-06-29 01:03:05 +00003138 the first in the TB) then we end up generating a whole new TB and
3139 repeating the fault, which is horribly inefficient.
3140 Better would be to execute just this insn uncached, or generate a
3141 second new TB. */
3142 cpu_resume_from_signal(env, NULL);
3143}
3144
bellarde3db7222005-01-26 22:00:47 +00003145void dump_exec_info(FILE *f,
3146 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3147{
3148 int i, target_code_size, max_target_code_size;
3149 int direct_jmp_count, direct_jmp2_count, cross_page;
3150 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00003151
bellarde3db7222005-01-26 22:00:47 +00003152 target_code_size = 0;
3153 max_target_code_size = 0;
3154 cross_page = 0;
3155 direct_jmp_count = 0;
3156 direct_jmp2_count = 0;
3157 for(i = 0; i < nb_tbs; i++) {
3158 tb = &tbs[i];
3159 target_code_size += tb->size;
3160 if (tb->size > max_target_code_size)
3161 max_target_code_size = tb->size;
3162 if (tb->page_addr[1] != -1)
3163 cross_page++;
3164 if (tb->tb_next_offset[0] != 0xffff) {
3165 direct_jmp_count++;
3166 if (tb->tb_next_offset[1] != 0xffff) {
3167 direct_jmp2_count++;
3168 }
3169 }
3170 }
3171 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00003172 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00003173 cpu_fprintf(f, "gen code size %ld/%ld\n",
3174 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
3175 cpu_fprintf(f, "TB count %d/%d\n",
3176 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00003177 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00003178 nb_tbs ? target_code_size / nb_tbs : 0,
3179 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00003180 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00003181 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3182 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00003183 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3184 cross_page,
bellarde3db7222005-01-26 22:00:47 +00003185 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3186 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00003187 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00003188 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3189 direct_jmp2_count,
3190 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00003191 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003192 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3193 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3194 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003195 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003196}
3197
ths5fafdf22007-09-16 21:08:06 +00003198#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003199
3200#define MMUSUFFIX _cmmu
3201#define GETPC() NULL
3202#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003203#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003204
3205#define SHIFT 0
3206#include "softmmu_template.h"
3207
3208#define SHIFT 1
3209#include "softmmu_template.h"
3210
3211#define SHIFT 2
3212#include "softmmu_template.h"
3213
3214#define SHIFT 3
3215#include "softmmu_template.h"
3216
3217#undef env
3218
3219#endif