blob: ab3f9c117d5082ea6e48b8bcb137674b09e8028e [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"
pbrook53a59602006-03-25 19:31:22 +000038#if defined(CONFIG_USER_ONLY)
39#include <qemu.h>
40#endif
bellard54936002003-05-13 00:25:15 +000041
bellardfd6ce8f2003-05-14 19:00:11 +000042//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000043//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000044//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000045//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000046
47/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000048//#define DEBUG_TB_CHECK
49//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000050
ths1196be32007-03-17 15:17:58 +000051//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000052//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000053
pbrook99773bd2006-04-16 15:14:59 +000054#if !defined(CONFIG_USER_ONLY)
55/* TB consistency checks only implemented for usermode emulation. */
56#undef DEBUG_TB_CHECK
57#endif
58
bellardfd6ce8f2003-05-14 19:00:11 +000059/* threshold to flush the translated code buffer */
blueswir1d07bde82007-12-11 19:35:45 +000060#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
bellardfd6ce8f2003-05-14 19:00:11 +000061
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
76#else
77/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
78#define TARGET_PHYS_ADDR_SPACE_BITS 32
79#endif
80
bellardfd6ce8f2003-05-14 19:00:11 +000081TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000082TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000083int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000084/* any access to the tbs or the page table must use this lock */
85spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000086
bellardb8076a72005-04-07 22:20:31 +000087uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000088uint8_t *code_gen_ptr;
89
bellard9fa3e852004-01-04 18:06:42 +000090int phys_ram_size;
91int phys_ram_fd;
92uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000093uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +000094static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000095
bellard6a00d602005-11-21 23:25:50 +000096CPUState *first_cpu;
97/* current CPU in the current thread. It is only valid inside
98 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +000099CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000100
bellard54936002003-05-13 00:25:15 +0000101typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000102 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000103 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000104 /* in order to optimize self modifying code, we count the number
105 of lookups we do to a given page to use a bitmap */
106 unsigned int code_write_count;
107 uint8_t *code_bitmap;
108#if defined(CONFIG_USER_ONLY)
109 unsigned long flags;
110#endif
bellard54936002003-05-13 00:25:15 +0000111} PageDesc;
112
bellard92e873b2004-05-21 14:52:29 +0000113typedef struct PhysPageDesc {
114 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000115 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000116} PhysPageDesc;
117
bellard54936002003-05-13 00:25:15 +0000118#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000119#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
120/* XXX: this is a temporary hack for alpha target.
121 * In the future, this is to be replaced by a multi-level table
122 * to actually be able to handle the complete 64 bits address space.
123 */
124#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
125#else
bellard54936002003-05-13 00:25:15 +0000126#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000127#endif
bellard54936002003-05-13 00:25:15 +0000128
129#define L1_SIZE (1 << L1_BITS)
130#define L2_SIZE (1 << L2_BITS)
131
bellard33417e72003-08-10 21:47:01 +0000132static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000133
bellard83fb7ad2004-07-05 21:25:26 +0000134unsigned long qemu_real_host_page_size;
135unsigned long qemu_host_page_bits;
136unsigned long qemu_host_page_size;
137unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000138
bellard92e873b2004-05-21 14:52:29 +0000139/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000140static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000141PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000142
bellard33417e72003-08-10 21:47:01 +0000143/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000144CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
145CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000146void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000147static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000148#if defined(CONFIG_SOFTMMU)
149static int io_mem_watch;
150#endif
bellard33417e72003-08-10 21:47:01 +0000151
bellard34865132003-10-05 14:28:56 +0000152/* log support */
153char *logfilename = "/tmp/qemu.log";
154FILE *logfile;
155int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000156static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000157
bellarde3db7222005-01-26 22:00:47 +0000158/* statistics */
159static int tlb_flush_count;
160static int tb_flush_count;
161static int tb_phys_invalidate_count;
162
blueswir1db7b5422007-05-26 17:36:03 +0000163#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
164typedef struct subpage_t {
165 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000166 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
167 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
168 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000169} subpage_t;
170
bellardb346ff42003-06-15 20:05:50 +0000171static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000172{
bellard83fb7ad2004-07-05 21:25:26 +0000173 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000174 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000175#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000176 {
177 SYSTEM_INFO system_info;
178 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000179
bellardd5a8f072004-09-29 21:15:28 +0000180 GetSystemInfo(&system_info);
181 qemu_real_host_page_size = system_info.dwPageSize;
ths3b46e622007-09-17 08:09:54 +0000182
bellardd5a8f072004-09-29 21:15:28 +0000183 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
184 PAGE_EXECUTE_READWRITE, &old_protect);
185 }
bellard67b915a2004-03-31 23:37:16 +0000186#else
bellard83fb7ad2004-07-05 21:25:26 +0000187 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000188 {
189 unsigned long start, end;
190
191 start = (unsigned long)code_gen_buffer;
192 start &= ~(qemu_real_host_page_size - 1);
ths3b46e622007-09-17 08:09:54 +0000193
bellardd5a8f072004-09-29 21:15:28 +0000194 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
195 end += qemu_real_host_page_size - 1;
196 end &= ~(qemu_real_host_page_size - 1);
ths3b46e622007-09-17 08:09:54 +0000197
ths5fafdf22007-09-16 21:08:06 +0000198 mprotect((void *)start, end - start,
bellardd5a8f072004-09-29 21:15:28 +0000199 PROT_READ | PROT_WRITE | PROT_EXEC);
200 }
bellard67b915a2004-03-31 23:37:16 +0000201#endif
bellardd5a8f072004-09-29 21:15:28 +0000202
bellard83fb7ad2004-07-05 21:25:26 +0000203 if (qemu_host_page_size == 0)
204 qemu_host_page_size = qemu_real_host_page_size;
205 if (qemu_host_page_size < TARGET_PAGE_SIZE)
206 qemu_host_page_size = TARGET_PAGE_SIZE;
207 qemu_host_page_bits = 0;
208 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
209 qemu_host_page_bits++;
210 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000211 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
212 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000213
214#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
215 {
216 long long startaddr, endaddr;
217 FILE *f;
218 int n;
219
220 f = fopen("/proc/self/maps", "r");
221 if (f) {
222 do {
223 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
224 if (n == 2) {
225 page_set_flags(TARGET_PAGE_ALIGN(startaddr),
226 TARGET_PAGE_ALIGN(endaddr),
227 PAGE_RESERVED);
228 }
229 } while (!feof(f));
230 fclose(f);
231 }
232 }
233#endif
bellard54936002003-05-13 00:25:15 +0000234}
235
bellardfd6ce8f2003-05-14 19:00:11 +0000236static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000237{
bellard54936002003-05-13 00:25:15 +0000238 PageDesc **lp, *p;
239
bellard54936002003-05-13 00:25:15 +0000240 lp = &l1_map[index >> L2_BITS];
241 p = *lp;
242 if (!p) {
243 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000244 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000245 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000246 *lp = p;
247 }
248 return p + (index & (L2_SIZE - 1));
249}
250
bellardfd6ce8f2003-05-14 19:00:11 +0000251static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000252{
bellard54936002003-05-13 00:25:15 +0000253 PageDesc *p;
254
bellard54936002003-05-13 00:25:15 +0000255 p = l1_map[index >> L2_BITS];
256 if (!p)
257 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000258 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000259}
260
bellard108c49b2005-07-24 12:55:09 +0000261static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000262{
bellard108c49b2005-07-24 12:55:09 +0000263 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000264 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000265
bellard108c49b2005-07-24 12:55:09 +0000266 p = (void **)l1_phys_map;
267#if TARGET_PHYS_ADDR_SPACE_BITS > 32
268
269#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
270#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
271#endif
272 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000273 p = *lp;
274 if (!p) {
275 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000276 if (!alloc)
277 return NULL;
278 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
279 memset(p, 0, sizeof(void *) * L1_SIZE);
280 *lp = p;
281 }
282#endif
283 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000284 pd = *lp;
285 if (!pd) {
286 int i;
bellard108c49b2005-07-24 12:55:09 +0000287 /* allocate if not found */
288 if (!alloc)
289 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000290 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
291 *lp = pd;
292 for (i = 0; i < L2_SIZE; i++)
293 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000294 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000295 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000296}
297
bellard108c49b2005-07-24 12:55:09 +0000298static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000299{
bellard108c49b2005-07-24 12:55:09 +0000300 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000301}
302
bellard9fa3e852004-01-04 18:06:42 +0000303#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000304static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000305static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000306 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000307#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000308
bellard6a00d602005-11-21 23:25:50 +0000309void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000310{
bellard6a00d602005-11-21 23:25:50 +0000311 CPUState **penv;
312 int cpu_index;
313
bellardfd6ce8f2003-05-14 19:00:11 +0000314 if (!code_gen_ptr) {
315 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000316 page_init();
bellard33417e72003-08-10 21:47:01 +0000317 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000318 }
bellard6a00d602005-11-21 23:25:50 +0000319 env->next_cpu = NULL;
320 penv = &first_cpu;
321 cpu_index = 0;
322 while (*penv != NULL) {
323 penv = (CPUState **)&(*penv)->next_cpu;
324 cpu_index++;
325 }
326 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000327 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000328 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000329}
330
bellard9fa3e852004-01-04 18:06:42 +0000331static inline void invalidate_page_bitmap(PageDesc *p)
332{
333 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000334 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000335 p->code_bitmap = NULL;
336 }
337 p->code_write_count = 0;
338}
339
bellardfd6ce8f2003-05-14 19:00:11 +0000340/* set to NULL all the 'first_tb' fields in all PageDescs */
341static void page_flush_tb(void)
342{
343 int i, j;
344 PageDesc *p;
345
346 for(i = 0; i < L1_SIZE; i++) {
347 p = l1_map[i];
348 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000349 for(j = 0; j < L2_SIZE; j++) {
350 p->first_tb = NULL;
351 invalidate_page_bitmap(p);
352 p++;
353 }
bellardfd6ce8f2003-05-14 19:00:11 +0000354 }
355 }
356}
357
358/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000359/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000360void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000361{
bellard6a00d602005-11-21 23:25:50 +0000362 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000363#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000364 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
365 (unsigned long)(code_gen_ptr - code_gen_buffer),
366 nb_tbs, nb_tbs > 0 ?
367 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000368#endif
369 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000370
bellard6a00d602005-11-21 23:25:50 +0000371 for(env = first_cpu; env != NULL; env = env->next_cpu) {
372 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
373 }
bellard9fa3e852004-01-04 18:06:42 +0000374
bellard8a8a6082004-10-03 13:36:49 +0000375 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000376 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000377
bellardfd6ce8f2003-05-14 19:00:11 +0000378 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000379 /* XXX: flush processor icache at this point if cache flush is
380 expensive */
bellarde3db7222005-01-26 22:00:47 +0000381 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000382}
383
384#ifdef DEBUG_TB_CHECK
385
j_mayerbc98a7e2007-04-04 07:55:12 +0000386static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000387{
388 TranslationBlock *tb;
389 int i;
390 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000391 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
392 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000393 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
394 address >= tb->pc + tb->size)) {
395 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000396 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000397 }
398 }
399 }
400}
401
402/* verify that all the pages have correct rights for code */
403static void tb_page_check(void)
404{
405 TranslationBlock *tb;
406 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000407
pbrook99773bd2006-04-16 15:14:59 +0000408 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
409 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000410 flags1 = page_get_flags(tb->pc);
411 flags2 = page_get_flags(tb->pc + tb->size - 1);
412 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
413 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000414 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000415 }
416 }
417 }
418}
419
bellardd4e81642003-05-25 16:46:15 +0000420void tb_jmp_check(TranslationBlock *tb)
421{
422 TranslationBlock *tb1;
423 unsigned int n1;
424
425 /* suppress any remaining jumps to this TB */
426 tb1 = tb->jmp_first;
427 for(;;) {
428 n1 = (long)tb1 & 3;
429 tb1 = (TranslationBlock *)((long)tb1 & ~3);
430 if (n1 == 2)
431 break;
432 tb1 = tb1->jmp_next[n1];
433 }
434 /* check end of list */
435 if (tb1 != tb) {
436 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
437 }
438}
439
bellardfd6ce8f2003-05-14 19:00:11 +0000440#endif
441
442/* invalidate one TB */
443static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
444 int next_offset)
445{
446 TranslationBlock *tb1;
447 for(;;) {
448 tb1 = *ptb;
449 if (tb1 == tb) {
450 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
451 break;
452 }
453 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
454 }
455}
456
bellard9fa3e852004-01-04 18:06:42 +0000457static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
458{
459 TranslationBlock *tb1;
460 unsigned int n1;
461
462 for(;;) {
463 tb1 = *ptb;
464 n1 = (long)tb1 & 3;
465 tb1 = (TranslationBlock *)((long)tb1 & ~3);
466 if (tb1 == tb) {
467 *ptb = tb1->page_next[n1];
468 break;
469 }
470 ptb = &tb1->page_next[n1];
471 }
472}
473
bellardd4e81642003-05-25 16:46:15 +0000474static inline void tb_jmp_remove(TranslationBlock *tb, int n)
475{
476 TranslationBlock *tb1, **ptb;
477 unsigned int n1;
478
479 ptb = &tb->jmp_next[n];
480 tb1 = *ptb;
481 if (tb1) {
482 /* find tb(n) in circular list */
483 for(;;) {
484 tb1 = *ptb;
485 n1 = (long)tb1 & 3;
486 tb1 = (TranslationBlock *)((long)tb1 & ~3);
487 if (n1 == n && tb1 == tb)
488 break;
489 if (n1 == 2) {
490 ptb = &tb1->jmp_first;
491 } else {
492 ptb = &tb1->jmp_next[n1];
493 }
494 }
495 /* now we can suppress tb(n) from the list */
496 *ptb = tb->jmp_next[n];
497
498 tb->jmp_next[n] = NULL;
499 }
500}
501
502/* reset the jump entry 'n' of a TB so that it is not chained to
503 another TB */
504static inline void tb_reset_jump(TranslationBlock *tb, int n)
505{
506 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
507}
508
bellard9fa3e852004-01-04 18:06:42 +0000509static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000510{
bellard6a00d602005-11-21 23:25:50 +0000511 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000512 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000513 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000514 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000515 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000516
bellard9fa3e852004-01-04 18:06:42 +0000517 /* remove the TB from the hash list */
518 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
519 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000520 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000521 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000522
bellard9fa3e852004-01-04 18:06:42 +0000523 /* remove the TB from the page list */
524 if (tb->page_addr[0] != page_addr) {
525 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
526 tb_page_remove(&p->first_tb, tb);
527 invalidate_page_bitmap(p);
528 }
529 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
530 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
531 tb_page_remove(&p->first_tb, tb);
532 invalidate_page_bitmap(p);
533 }
534
bellard8a40a182005-11-20 10:35:40 +0000535 tb_invalidated_flag = 1;
536
537 /* remove the TB from the hash list */
538 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000539 for(env = first_cpu; env != NULL; env = env->next_cpu) {
540 if (env->tb_jmp_cache[h] == tb)
541 env->tb_jmp_cache[h] = NULL;
542 }
bellard8a40a182005-11-20 10:35:40 +0000543
544 /* suppress this TB from the two jump lists */
545 tb_jmp_remove(tb, 0);
546 tb_jmp_remove(tb, 1);
547
548 /* suppress any remaining jumps to this TB */
549 tb1 = tb->jmp_first;
550 for(;;) {
551 n1 = (long)tb1 & 3;
552 if (n1 == 2)
553 break;
554 tb1 = (TranslationBlock *)((long)tb1 & ~3);
555 tb2 = tb1->jmp_next[n1];
556 tb_reset_jump(tb1, n1);
557 tb1->jmp_next[n1] = NULL;
558 tb1 = tb2;
559 }
560 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
561
bellarde3db7222005-01-26 22:00:47 +0000562 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000563}
564
565static inline void set_bits(uint8_t *tab, int start, int len)
566{
567 int end, mask, end1;
568
569 end = start + len;
570 tab += start >> 3;
571 mask = 0xff << (start & 7);
572 if ((start & ~7) == (end & ~7)) {
573 if (start < end) {
574 mask &= ~(0xff << (end & 7));
575 *tab |= mask;
576 }
577 } else {
578 *tab++ |= mask;
579 start = (start + 8) & ~7;
580 end1 = end & ~7;
581 while (start < end1) {
582 *tab++ = 0xff;
583 start += 8;
584 }
585 if (start < end) {
586 mask = ~(0xff << (end & 7));
587 *tab |= mask;
588 }
589 }
590}
591
592static void build_page_bitmap(PageDesc *p)
593{
594 int n, tb_start, tb_end;
595 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000596
bellard59817cc2004-02-16 22:01:13 +0000597 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000598 if (!p->code_bitmap)
599 return;
600 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
601
602 tb = p->first_tb;
603 while (tb != NULL) {
604 n = (long)tb & 3;
605 tb = (TranslationBlock *)((long)tb & ~3);
606 /* NOTE: this is subtle as a TB may span two physical pages */
607 if (n == 0) {
608 /* NOTE: tb_end may be after the end of the page, but
609 it is not a problem */
610 tb_start = tb->pc & ~TARGET_PAGE_MASK;
611 tb_end = tb_start + tb->size;
612 if (tb_end > TARGET_PAGE_SIZE)
613 tb_end = TARGET_PAGE_SIZE;
614 } else {
615 tb_start = 0;
616 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
617 }
618 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
619 tb = tb->page_next[n];
620 }
621}
622
bellardd720b932004-04-25 17:57:43 +0000623#ifdef TARGET_HAS_PRECISE_SMC
624
ths5fafdf22007-09-16 21:08:06 +0000625static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000626 target_ulong pc, target_ulong cs_base, int flags,
627 int cflags)
628{
629 TranslationBlock *tb;
630 uint8_t *tc_ptr;
631 target_ulong phys_pc, phys_page2, virt_page2;
632 int code_gen_size;
633
bellardc27004e2005-01-03 23:35:10 +0000634 phys_pc = get_phys_addr_code(env, pc);
635 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000636 if (!tb) {
637 /* flush must be done */
638 tb_flush(env);
639 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000640 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000641 }
642 tc_ptr = code_gen_ptr;
643 tb->tc_ptr = tc_ptr;
644 tb->cs_base = cs_base;
645 tb->flags = flags;
646 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000647 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000648 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 +0000649
bellardd720b932004-04-25 17:57:43 +0000650 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000651 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000652 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000653 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000654 phys_page2 = get_phys_addr_code(env, virt_page2);
655 }
656 tb_link_phys(tb, phys_pc, phys_page2);
657}
658#endif
ths3b46e622007-09-17 08:09:54 +0000659
bellard9fa3e852004-01-04 18:06:42 +0000660/* invalidate all TBs which intersect with the target physical page
661 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000662 the same physical page. 'is_cpu_write_access' should be true if called
663 from a real cpu write access: the virtual CPU will exit the current
664 TB if code is modified inside this TB. */
ths5fafdf22007-09-16 21:08:06 +0000665void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
bellardd720b932004-04-25 17:57:43 +0000666 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000667{
bellardd720b932004-04-25 17:57:43 +0000668 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000669 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000670 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000671 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000672 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000673 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000674
675 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000676 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000677 return;
ths5fafdf22007-09-16 21:08:06 +0000678 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000679 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
680 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000681 /* build code bitmap */
682 build_page_bitmap(p);
683 }
684
685 /* we remove all the TBs in the range [start, end[ */
686 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000687 current_tb_not_found = is_cpu_write_access;
688 current_tb_modified = 0;
689 current_tb = NULL; /* avoid warning */
690 current_pc = 0; /* avoid warning */
691 current_cs_base = 0; /* avoid warning */
692 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000693 tb = p->first_tb;
694 while (tb != NULL) {
695 n = (long)tb & 3;
696 tb = (TranslationBlock *)((long)tb & ~3);
697 tb_next = tb->page_next[n];
698 /* NOTE: this is subtle as a TB may span two physical pages */
699 if (n == 0) {
700 /* NOTE: tb_end may be after the end of the page, but
701 it is not a problem */
702 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
703 tb_end = tb_start + tb->size;
704 } else {
705 tb_start = tb->page_addr[1];
706 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
707 }
708 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000709#ifdef TARGET_HAS_PRECISE_SMC
710 if (current_tb_not_found) {
711 current_tb_not_found = 0;
712 current_tb = NULL;
713 if (env->mem_write_pc) {
714 /* now we have a real cpu fault */
715 current_tb = tb_find_pc(env->mem_write_pc);
716 }
717 }
718 if (current_tb == tb &&
719 !(current_tb->cflags & CF_SINGLE_INSN)) {
720 /* If we are modifying the current TB, we must stop
721 its execution. We could be more precise by checking
722 that the modification is after the current PC, but it
723 would require a specialized function to partially
724 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000725
bellardd720b932004-04-25 17:57:43 +0000726 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000727 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000728 env->mem_write_pc, NULL);
729#if defined(TARGET_I386)
730 current_flags = env->hflags;
731 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
732 current_cs_base = (target_ulong)env->segs[R_CS].base;
733 current_pc = current_cs_base + env->eip;
734#else
735#error unsupported CPU
736#endif
737 }
738#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000739 /* we need to do that to handle the case where a signal
740 occurs while doing tb_phys_invalidate() */
741 saved_tb = NULL;
742 if (env) {
743 saved_tb = env->current_tb;
744 env->current_tb = NULL;
745 }
bellard9fa3e852004-01-04 18:06:42 +0000746 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000747 if (env) {
748 env->current_tb = saved_tb;
749 if (env->interrupt_request && env->current_tb)
750 cpu_interrupt(env, env->interrupt_request);
751 }
bellard9fa3e852004-01-04 18:06:42 +0000752 }
753 tb = tb_next;
754 }
755#if !defined(CONFIG_USER_ONLY)
756 /* if no code remaining, no need to continue to use slow writes */
757 if (!p->first_tb) {
758 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000759 if (is_cpu_write_access) {
760 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
761 }
762 }
763#endif
764#ifdef TARGET_HAS_PRECISE_SMC
765 if (current_tb_modified) {
766 /* we generate a block containing just the instruction
767 modifying the memory. It will ensure that it cannot modify
768 itself */
bellardea1c1802004-06-14 18:56:36 +0000769 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000770 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000771 CF_SINGLE_INSN);
772 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000773 }
774#endif
775}
776
777/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000778static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000779{
780 PageDesc *p;
781 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000782#if 0
bellarda4193c82004-06-03 14:01:43 +0000783 if (1) {
784 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000785 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
786 cpu_single_env->mem_write_vaddr, len,
787 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000788 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
789 }
bellard59817cc2004-02-16 22:01:13 +0000790 }
791#endif
bellard9fa3e852004-01-04 18:06:42 +0000792 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000793 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000794 return;
795 if (p->code_bitmap) {
796 offset = start & ~TARGET_PAGE_MASK;
797 b = p->code_bitmap[offset >> 3] >> (offset & 7);
798 if (b & ((1 << len) - 1))
799 goto do_invalidate;
800 } else {
801 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000802 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000803 }
804}
805
bellard9fa3e852004-01-04 18:06:42 +0000806#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +0000807static void tb_invalidate_phys_page(target_ulong addr,
bellardd720b932004-04-25 17:57:43 +0000808 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000809{
bellardd720b932004-04-25 17:57:43 +0000810 int n, current_flags, current_tb_modified;
811 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000812 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000813 TranslationBlock *tb, *current_tb;
814#ifdef TARGET_HAS_PRECISE_SMC
815 CPUState *env = cpu_single_env;
816#endif
bellard9fa3e852004-01-04 18:06:42 +0000817
818 addr &= TARGET_PAGE_MASK;
819 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000820 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000821 return;
822 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000823 current_tb_modified = 0;
824 current_tb = NULL;
825 current_pc = 0; /* avoid warning */
826 current_cs_base = 0; /* avoid warning */
827 current_flags = 0; /* avoid warning */
828#ifdef TARGET_HAS_PRECISE_SMC
829 if (tb && pc != 0) {
830 current_tb = tb_find_pc(pc);
831 }
832#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000833 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000834 n = (long)tb & 3;
835 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000836#ifdef TARGET_HAS_PRECISE_SMC
837 if (current_tb == tb &&
838 !(current_tb->cflags & CF_SINGLE_INSN)) {
839 /* If we are modifying the current TB, we must stop
840 its execution. We could be more precise by checking
841 that the modification is after the current PC, but it
842 would require a specialized function to partially
843 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000844
bellardd720b932004-04-25 17:57:43 +0000845 current_tb_modified = 1;
846 cpu_restore_state(current_tb, env, pc, puc);
847#if defined(TARGET_I386)
848 current_flags = env->hflags;
849 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
850 current_cs_base = (target_ulong)env->segs[R_CS].base;
851 current_pc = current_cs_base + env->eip;
852#else
853#error unsupported CPU
854#endif
855 }
856#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000857 tb_phys_invalidate(tb, addr);
858 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000859 }
860 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000861#ifdef TARGET_HAS_PRECISE_SMC
862 if (current_tb_modified) {
863 /* we generate a block containing just the instruction
864 modifying the memory. It will ensure that it cannot modify
865 itself */
bellardea1c1802004-06-14 18:56:36 +0000866 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000867 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000868 CF_SINGLE_INSN);
869 cpu_resume_from_signal(env, puc);
870 }
871#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000872}
bellard9fa3e852004-01-04 18:06:42 +0000873#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000874
875/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000876static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000877 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000878{
879 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000880 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000881
bellard9fa3e852004-01-04 18:06:42 +0000882 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000883 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000884 tb->page_next[n] = p->first_tb;
885 last_first_tb = p->first_tb;
886 p->first_tb = (TranslationBlock *)((long)tb | n);
887 invalidate_page_bitmap(p);
888
bellard107db442004-06-22 18:48:46 +0000889#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000890
bellard9fa3e852004-01-04 18:06:42 +0000891#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000892 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000893 target_ulong addr;
894 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000895 int prot;
896
bellardfd6ce8f2003-05-14 19:00:11 +0000897 /* force the host page as non writable (writes will have a
898 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000899 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000900 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000901 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
902 addr += TARGET_PAGE_SIZE) {
903
904 p2 = page_find (addr >> TARGET_PAGE_BITS);
905 if (!p2)
906 continue;
907 prot |= p2->flags;
908 p2->flags &= ~PAGE_WRITE;
909 page_get_flags(addr);
910 }
ths5fafdf22007-09-16 21:08:06 +0000911 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000912 (prot & PAGE_BITS) & ~PAGE_WRITE);
913#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +0000914 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +0000915 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000916#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000917 }
bellard9fa3e852004-01-04 18:06:42 +0000918#else
919 /* if some code is already present, then the pages are already
920 protected. So we handle the case where only the first TB is
921 allocated in a physical page */
922 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000923 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000924 }
925#endif
bellardd720b932004-04-25 17:57:43 +0000926
927#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000928}
929
930/* Allocate a new translation block. Flush the translation buffer if
931 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000932TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000933{
934 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000935
ths5fafdf22007-09-16 21:08:06 +0000936 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
bellardfd6ce8f2003-05-14 19:00:11 +0000937 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000938 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000939 tb = &tbs[nb_tbs++];
940 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000941 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000942 return tb;
943}
944
bellard9fa3e852004-01-04 18:06:42 +0000945/* add a new TB and link it to the physical page tables. phys_page2 is
946 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +0000947void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +0000948 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000949{
bellard9fa3e852004-01-04 18:06:42 +0000950 unsigned int h;
951 TranslationBlock **ptb;
952
953 /* add in the physical hash table */
954 h = tb_phys_hash_func(phys_pc);
955 ptb = &tb_phys_hash[h];
956 tb->phys_hash_next = *ptb;
957 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000958
959 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000960 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
961 if (phys_page2 != -1)
962 tb_alloc_page(tb, 1, phys_page2);
963 else
964 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000965
bellardd4e81642003-05-25 16:46:15 +0000966 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
967 tb->jmp_next[0] = NULL;
968 tb->jmp_next[1] = NULL;
969
970 /* init original jump addresses */
971 if (tb->tb_next_offset[0] != 0xffff)
972 tb_reset_jump(tb, 0);
973 if (tb->tb_next_offset[1] != 0xffff)
974 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000975
976#ifdef DEBUG_TB_CHECK
977 tb_page_check();
978#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000979}
980
bellarda513fe12003-05-27 23:29:48 +0000981/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
982 tb[1].tc_ptr. Return NULL if not found */
983TranslationBlock *tb_find_pc(unsigned long tc_ptr)
984{
985 int m_min, m_max, m;
986 unsigned long v;
987 TranslationBlock *tb;
988
989 if (nb_tbs <= 0)
990 return NULL;
991 if (tc_ptr < (unsigned long)code_gen_buffer ||
992 tc_ptr >= (unsigned long)code_gen_ptr)
993 return NULL;
994 /* binary search (cf Knuth) */
995 m_min = 0;
996 m_max = nb_tbs - 1;
997 while (m_min <= m_max) {
998 m = (m_min + m_max) >> 1;
999 tb = &tbs[m];
1000 v = (unsigned long)tb->tc_ptr;
1001 if (v == tc_ptr)
1002 return tb;
1003 else if (tc_ptr < v) {
1004 m_max = m - 1;
1005 } else {
1006 m_min = m + 1;
1007 }
ths5fafdf22007-09-16 21:08:06 +00001008 }
bellarda513fe12003-05-27 23:29:48 +00001009 return &tbs[m_max];
1010}
bellard75012672003-06-21 13:11:07 +00001011
bellardea041c02003-06-25 16:16:50 +00001012static void tb_reset_jump_recursive(TranslationBlock *tb);
1013
1014static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1015{
1016 TranslationBlock *tb1, *tb_next, **ptb;
1017 unsigned int n1;
1018
1019 tb1 = tb->jmp_next[n];
1020 if (tb1 != NULL) {
1021 /* find head of list */
1022 for(;;) {
1023 n1 = (long)tb1 & 3;
1024 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1025 if (n1 == 2)
1026 break;
1027 tb1 = tb1->jmp_next[n1];
1028 }
1029 /* we are now sure now that tb jumps to tb1 */
1030 tb_next = tb1;
1031
1032 /* remove tb from the jmp_first list */
1033 ptb = &tb_next->jmp_first;
1034 for(;;) {
1035 tb1 = *ptb;
1036 n1 = (long)tb1 & 3;
1037 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1038 if (n1 == n && tb1 == tb)
1039 break;
1040 ptb = &tb1->jmp_next[n1];
1041 }
1042 *ptb = tb->jmp_next[n];
1043 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001044
bellardea041c02003-06-25 16:16:50 +00001045 /* suppress the jump to next tb in generated code */
1046 tb_reset_jump(tb, n);
1047
bellard01243112004-01-04 15:48:17 +00001048 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001049 tb_reset_jump_recursive(tb_next);
1050 }
1051}
1052
1053static void tb_reset_jump_recursive(TranslationBlock *tb)
1054{
1055 tb_reset_jump_recursive2(tb, 0);
1056 tb_reset_jump_recursive2(tb, 1);
1057}
1058
bellard1fddef42005-04-17 19:16:13 +00001059#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001060static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1061{
j_mayer9b3c35e2007-04-07 11:21:28 +00001062 target_phys_addr_t addr;
1063 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001064 ram_addr_t ram_addr;
1065 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001066
pbrookc2f07f82006-04-08 17:14:56 +00001067 addr = cpu_get_phys_page_debug(env, pc);
1068 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1069 if (!p) {
1070 pd = IO_MEM_UNASSIGNED;
1071 } else {
1072 pd = p->phys_offset;
1073 }
1074 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001075 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001076}
bellardc27004e2005-01-03 23:35:10 +00001077#endif
bellardd720b932004-04-25 17:57:43 +00001078
pbrook6658ffb2007-03-16 23:58:11 +00001079/* Add a watchpoint. */
1080int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1081{
1082 int i;
1083
1084 for (i = 0; i < env->nb_watchpoints; i++) {
1085 if (addr == env->watchpoint[i].vaddr)
1086 return 0;
1087 }
1088 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1089 return -1;
1090
1091 i = env->nb_watchpoints++;
1092 env->watchpoint[i].vaddr = addr;
1093 tlb_flush_page(env, addr);
1094 /* FIXME: This flush is needed because of the hack to make memory ops
1095 terminate the TB. It can be removed once the proper IO trap and
1096 re-execute bits are in. */
1097 tb_flush(env);
1098 return i;
1099}
1100
1101/* Remove a watchpoint. */
1102int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1103{
1104 int i;
1105
1106 for (i = 0; i < env->nb_watchpoints; i++) {
1107 if (addr == env->watchpoint[i].vaddr) {
1108 env->nb_watchpoints--;
1109 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1110 tlb_flush_page(env, addr);
1111 return 0;
1112 }
1113 }
1114 return -1;
1115}
1116
bellardc33a3462003-07-29 20:50:33 +00001117/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1118 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001119int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001120{
bellard1fddef42005-04-17 19:16:13 +00001121#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001122 int i;
ths3b46e622007-09-17 08:09:54 +00001123
bellard4c3a88a2003-07-26 12:06:08 +00001124 for(i = 0; i < env->nb_breakpoints; i++) {
1125 if (env->breakpoints[i] == pc)
1126 return 0;
1127 }
1128
1129 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1130 return -1;
1131 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001132
bellardd720b932004-04-25 17:57:43 +00001133 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001134 return 0;
1135#else
1136 return -1;
1137#endif
1138}
1139
1140/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001141int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001142{
bellard1fddef42005-04-17 19:16:13 +00001143#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001144 int i;
1145 for(i = 0; i < env->nb_breakpoints; i++) {
1146 if (env->breakpoints[i] == pc)
1147 goto found;
1148 }
1149 return -1;
1150 found:
bellard4c3a88a2003-07-26 12:06:08 +00001151 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001152 if (i < env->nb_breakpoints)
1153 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001154
1155 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001156 return 0;
1157#else
1158 return -1;
1159#endif
1160}
1161
bellardc33a3462003-07-29 20:50:33 +00001162/* enable or disable single step mode. EXCP_DEBUG is returned by the
1163 CPU loop after each instruction */
1164void cpu_single_step(CPUState *env, int enabled)
1165{
bellard1fddef42005-04-17 19:16:13 +00001166#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001167 if (env->singlestep_enabled != enabled) {
1168 env->singlestep_enabled = enabled;
1169 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001170 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001171 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001172 }
1173#endif
1174}
1175
bellard34865132003-10-05 14:28:56 +00001176/* enable or disable low levels log */
1177void cpu_set_log(int log_flags)
1178{
1179 loglevel = log_flags;
1180 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001181 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001182 if (!logfile) {
1183 perror(logfilename);
1184 _exit(1);
1185 }
bellard9fa3e852004-01-04 18:06:42 +00001186#if !defined(CONFIG_SOFTMMU)
1187 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1188 {
1189 static uint8_t logfile_buf[4096];
1190 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1191 }
1192#else
bellard34865132003-10-05 14:28:56 +00001193 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001194#endif
pbrooke735b912007-06-30 13:53:24 +00001195 log_append = 1;
1196 }
1197 if (!loglevel && logfile) {
1198 fclose(logfile);
1199 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001200 }
1201}
1202
1203void cpu_set_log_filename(const char *filename)
1204{
1205 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001206 if (logfile) {
1207 fclose(logfile);
1208 logfile = NULL;
1209 }
1210 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001211}
bellardc33a3462003-07-29 20:50:33 +00001212
bellard01243112004-01-04 15:48:17 +00001213/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001214void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001215{
1216 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001217 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001218
bellard68a79312003-06-30 13:12:32 +00001219 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001220 /* if the cpu is currently executing code, we must unlink it and
1221 all the potentially executing TB */
1222 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001223 if (tb && !testandset(&interrupt_lock)) {
1224 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001225 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001226 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001227 }
1228}
1229
bellardb54ad042004-05-20 13:42:52 +00001230void cpu_reset_interrupt(CPUState *env, int mask)
1231{
1232 env->interrupt_request &= ~mask;
1233}
1234
bellardf193c792004-03-21 17:06:25 +00001235CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001236 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001237 "show generated host assembly code for each compiled TB" },
1238 { CPU_LOG_TB_IN_ASM, "in_asm",
1239 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001240 { CPU_LOG_TB_OP, "op",
bellardf193c792004-03-21 17:06:25 +00001241 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1242#ifdef TARGET_I386
1243 { CPU_LOG_TB_OP_OPT, "op_opt",
1244 "show micro ops after optimization for each compiled TB" },
1245#endif
1246 { CPU_LOG_INT, "int",
1247 "show interrupts/exceptions in short format" },
1248 { CPU_LOG_EXEC, "exec",
1249 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001250 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001251 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001252#ifdef TARGET_I386
1253 { CPU_LOG_PCALL, "pcall",
1254 "show protected mode far calls/returns/exceptions" },
1255#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001256#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001257 { CPU_LOG_IOPORT, "ioport",
1258 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001259#endif
bellardf193c792004-03-21 17:06:25 +00001260 { 0, NULL, NULL },
1261};
1262
1263static int cmp1(const char *s1, int n, const char *s2)
1264{
1265 if (strlen(s2) != n)
1266 return 0;
1267 return memcmp(s1, s2, n) == 0;
1268}
ths3b46e622007-09-17 08:09:54 +00001269
bellardf193c792004-03-21 17:06:25 +00001270/* takes a comma separated list of log masks. Return 0 if error. */
1271int cpu_str_to_log_mask(const char *str)
1272{
1273 CPULogItem *item;
1274 int mask;
1275 const char *p, *p1;
1276
1277 p = str;
1278 mask = 0;
1279 for(;;) {
1280 p1 = strchr(p, ',');
1281 if (!p1)
1282 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001283 if(cmp1(p,p1-p,"all")) {
1284 for(item = cpu_log_items; item->mask != 0; item++) {
1285 mask |= item->mask;
1286 }
1287 } else {
bellardf193c792004-03-21 17:06:25 +00001288 for(item = cpu_log_items; item->mask != 0; item++) {
1289 if (cmp1(p, p1 - p, item->name))
1290 goto found;
1291 }
1292 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001293 }
bellardf193c792004-03-21 17:06:25 +00001294 found:
1295 mask |= item->mask;
1296 if (*p1 != ',')
1297 break;
1298 p = p1 + 1;
1299 }
1300 return mask;
1301}
bellardea041c02003-06-25 16:16:50 +00001302
bellard75012672003-06-21 13:11:07 +00001303void cpu_abort(CPUState *env, const char *fmt, ...)
1304{
1305 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001306 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001307
1308 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001309 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001310 fprintf(stderr, "qemu: fatal: ");
1311 vfprintf(stderr, fmt, ap);
1312 fprintf(stderr, "\n");
1313#ifdef TARGET_I386
ths0573fbf2007-09-23 15:28:04 +00001314 if(env->intercept & INTERCEPT_SVM_MASK) {
1315 /* most probably the virtual machine should not
1316 be shut down but rather caught by the VMM */
1317 vmexit(SVM_EXIT_SHUTDOWN, 0);
1318 }
bellard7fe48482004-10-09 18:08:01 +00001319 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1320#else
1321 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001322#endif
balrog924edca2007-06-10 14:07:13 +00001323 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001324 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001325 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001326 fprintf(logfile, "\n");
1327#ifdef TARGET_I386
1328 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1329#else
1330 cpu_dump_state(env, logfile, fprintf, 0);
1331#endif
balrog924edca2007-06-10 14:07:13 +00001332 fflush(logfile);
1333 fclose(logfile);
1334 }
pbrook493ae1f2007-11-23 16:53:59 +00001335 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001336 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001337 abort();
1338}
1339
thsc5be9f02007-02-28 20:20:53 +00001340CPUState *cpu_copy(CPUState *env)
1341{
ths01ba9812007-12-09 02:22:57 +00001342 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001343 /* preserve chaining and index */
1344 CPUState *next_cpu = new_env->next_cpu;
1345 int cpu_index = new_env->cpu_index;
1346 memcpy(new_env, env, sizeof(CPUState));
1347 new_env->next_cpu = next_cpu;
1348 new_env->cpu_index = cpu_index;
1349 return new_env;
thsc5be9f02007-02-28 20:20:53 +00001350}
1351
bellard01243112004-01-04 15:48:17 +00001352#if !defined(CONFIG_USER_ONLY)
1353
bellardee8b7022004-02-03 23:35:10 +00001354/* NOTE: if flush_global is true, also flush global entries (not
1355 implemented yet) */
1356void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001357{
bellard33417e72003-08-10 21:47:01 +00001358 int i;
bellard01243112004-01-04 15:48:17 +00001359
bellard9fa3e852004-01-04 18:06:42 +00001360#if defined(DEBUG_TLB)
1361 printf("tlb_flush:\n");
1362#endif
bellard01243112004-01-04 15:48:17 +00001363 /* must reset current TB so that interrupts cannot modify the
1364 links while we are modifying them */
1365 env->current_tb = NULL;
1366
bellard33417e72003-08-10 21:47:01 +00001367 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001368 env->tlb_table[0][i].addr_read = -1;
1369 env->tlb_table[0][i].addr_write = -1;
1370 env->tlb_table[0][i].addr_code = -1;
1371 env->tlb_table[1][i].addr_read = -1;
1372 env->tlb_table[1][i].addr_write = -1;
1373 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001374#if (NB_MMU_MODES >= 3)
1375 env->tlb_table[2][i].addr_read = -1;
1376 env->tlb_table[2][i].addr_write = -1;
1377 env->tlb_table[2][i].addr_code = -1;
1378#if (NB_MMU_MODES == 4)
1379 env->tlb_table[3][i].addr_read = -1;
1380 env->tlb_table[3][i].addr_write = -1;
1381 env->tlb_table[3][i].addr_code = -1;
1382#endif
1383#endif
bellard33417e72003-08-10 21:47:01 +00001384 }
bellard9fa3e852004-01-04 18:06:42 +00001385
bellard8a40a182005-11-20 10:35:40 +00001386 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001387
1388#if !defined(CONFIG_SOFTMMU)
1389 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1390#endif
bellard0a962c02005-02-10 22:00:27 +00001391#ifdef USE_KQEMU
1392 if (env->kqemu_enabled) {
1393 kqemu_flush(env, flush_global);
1394 }
1395#endif
bellarde3db7222005-01-26 22:00:47 +00001396 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001397}
1398
bellard274da6b2004-05-20 21:56:27 +00001399static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001400{
ths5fafdf22007-09-16 21:08:06 +00001401 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001402 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001403 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001404 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001405 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001406 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1407 tlb_entry->addr_read = -1;
1408 tlb_entry->addr_write = -1;
1409 tlb_entry->addr_code = -1;
1410 }
bellard61382a52003-10-27 21:22:23 +00001411}
1412
bellard2e126692004-04-25 21:28:44 +00001413void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001414{
bellard8a40a182005-11-20 10:35:40 +00001415 int i;
bellard9fa3e852004-01-04 18:06:42 +00001416 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001417
bellard9fa3e852004-01-04 18:06:42 +00001418#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001419 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001420#endif
bellard01243112004-01-04 15:48:17 +00001421 /* must reset current TB so that interrupts cannot modify the
1422 links while we are modifying them */
1423 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001424
bellard61382a52003-10-27 21:22:23 +00001425 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001426 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001427 tlb_flush_entry(&env->tlb_table[0][i], addr);
1428 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001429#if (NB_MMU_MODES >= 3)
1430 tlb_flush_entry(&env->tlb_table[2][i], addr);
1431#if (NB_MMU_MODES == 4)
1432 tlb_flush_entry(&env->tlb_table[3][i], addr);
1433#endif
1434#endif
bellard01243112004-01-04 15:48:17 +00001435
pbrookb362e5e2006-11-12 20:40:55 +00001436 /* Discard jump cache entries for any tb which might potentially
1437 overlap the flushed page. */
1438 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1439 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1440
1441 i = tb_jmp_cache_hash_page(addr);
1442 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001443
bellard01243112004-01-04 15:48:17 +00001444#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001445 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001446 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001447#endif
bellard0a962c02005-02-10 22:00:27 +00001448#ifdef USE_KQEMU
1449 if (env->kqemu_enabled) {
1450 kqemu_flush_page(env, addr);
1451 }
1452#endif
bellard9fa3e852004-01-04 18:06:42 +00001453}
1454
bellard9fa3e852004-01-04 18:06:42 +00001455/* update the TLBs so that writes to code in the virtual page 'addr'
1456 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001457static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001458{
ths5fafdf22007-09-16 21:08:06 +00001459 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001460 ram_addr + TARGET_PAGE_SIZE,
1461 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001462}
1463
bellard9fa3e852004-01-04 18:06:42 +00001464/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001465 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001466static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001467 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001468{
bellard3a7d9292005-08-21 09:26:42 +00001469 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001470}
1471
ths5fafdf22007-09-16 21:08:06 +00001472static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001473 unsigned long start, unsigned long length)
1474{
1475 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001476 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1477 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001478 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001479 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001480 }
1481 }
1482}
1483
bellard3a7d9292005-08-21 09:26:42 +00001484void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001485 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001486{
1487 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001488 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001489 int i, mask, len;
1490 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001491
1492 start &= TARGET_PAGE_MASK;
1493 end = TARGET_PAGE_ALIGN(end);
1494
1495 length = end - start;
1496 if (length == 0)
1497 return;
bellard0a962c02005-02-10 22:00:27 +00001498 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001499#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001500 /* XXX: should not depend on cpu context */
1501 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001502 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001503 ram_addr_t addr;
1504 addr = start;
1505 for(i = 0; i < len; i++) {
1506 kqemu_set_notdirty(env, addr);
1507 addr += TARGET_PAGE_SIZE;
1508 }
bellard3a7d9292005-08-21 09:26:42 +00001509 }
1510#endif
bellardf23db162005-08-21 19:12:28 +00001511 mask = ~dirty_flags;
1512 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1513 for(i = 0; i < len; i++)
1514 p[i] &= mask;
1515
bellard1ccde1c2004-02-06 19:46:14 +00001516 /* we modify the TLB cache so that the dirty bit will be set again
1517 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001518 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001519 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1520 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001521 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001522 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001523 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001524#if (NB_MMU_MODES >= 3)
1525 for(i = 0; i < CPU_TLB_SIZE; i++)
1526 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1527#if (NB_MMU_MODES == 4)
1528 for(i = 0; i < CPU_TLB_SIZE; i++)
1529 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1530#endif
1531#endif
bellard6a00d602005-11-21 23:25:50 +00001532 }
bellard59817cc2004-02-16 22:01:13 +00001533
1534#if !defined(CONFIG_SOFTMMU)
1535 /* XXX: this is expensive */
1536 {
1537 VirtPageDesc *p;
1538 int j;
1539 target_ulong addr;
1540
1541 for(i = 0; i < L1_SIZE; i++) {
1542 p = l1_virt_map[i];
1543 if (p) {
1544 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1545 for(j = 0; j < L2_SIZE; j++) {
1546 if (p->valid_tag == virt_valid_tag &&
1547 p->phys_addr >= start && p->phys_addr < end &&
1548 (p->prot & PROT_WRITE)) {
1549 if (addr < MMAP_AREA_END) {
ths5fafdf22007-09-16 21:08:06 +00001550 mprotect((void *)addr, TARGET_PAGE_SIZE,
bellard59817cc2004-02-16 22:01:13 +00001551 p->prot & ~PROT_WRITE);
1552 }
1553 }
1554 addr += TARGET_PAGE_SIZE;
1555 p++;
1556 }
1557 }
1558 }
1559 }
1560#endif
bellard1ccde1c2004-02-06 19:46:14 +00001561}
1562
bellard3a7d9292005-08-21 09:26:42 +00001563static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1564{
1565 ram_addr_t ram_addr;
1566
bellard84b7b8e2005-11-28 21:19:04 +00001567 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001568 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001569 tlb_entry->addend - (unsigned long)phys_ram_base;
1570 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001571 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001572 }
1573 }
1574}
1575
1576/* update the TLB according to the current state of the dirty bits */
1577void cpu_tlb_update_dirty(CPUState *env)
1578{
1579 int i;
1580 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001581 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001582 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001583 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001584#if (NB_MMU_MODES >= 3)
1585 for(i = 0; i < CPU_TLB_SIZE; i++)
1586 tlb_update_dirty(&env->tlb_table[2][i]);
1587#if (NB_MMU_MODES == 4)
1588 for(i = 0; i < CPU_TLB_SIZE; i++)
1589 tlb_update_dirty(&env->tlb_table[3][i]);
1590#endif
1591#endif
bellard3a7d9292005-08-21 09:26:42 +00001592}
1593
ths5fafdf22007-09-16 21:08:06 +00001594static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001595 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001596{
1597 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001598 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1599 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001600 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001601 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001602 }
1603 }
1604}
1605
1606/* update the TLB corresponding to virtual page vaddr and phys addr
1607 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001608static inline void tlb_set_dirty(CPUState *env,
1609 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001610{
bellard1ccde1c2004-02-06 19:46:14 +00001611 int i;
1612
bellard1ccde1c2004-02-06 19:46:14 +00001613 addr &= TARGET_PAGE_MASK;
1614 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001615 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1616 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001617#if (NB_MMU_MODES >= 3)
1618 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1619#if (NB_MMU_MODES == 4)
1620 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1621#endif
1622#endif
bellard9fa3e852004-01-04 18:06:42 +00001623}
1624
bellard59817cc2004-02-16 22:01:13 +00001625/* add a new TLB entry. At most one entry for a given virtual address
1626 is permitted. Return 0 if OK or 2 if the page could not be mapped
1627 (can only happen in non SOFTMMU mode for I/O pages or pages
1628 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001629int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1630 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001631 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001632{
bellard92e873b2004-05-21 14:52:29 +00001633 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001634 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001635 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001636 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001637 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001638 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001639 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001640 int i;
bellard9fa3e852004-01-04 18:06:42 +00001641
bellard92e873b2004-05-21 14:52:29 +00001642 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001643 if (!p) {
1644 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001645 } else {
1646 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001647 }
1648#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001649 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1650 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001651#endif
1652
1653 ret = 0;
1654#if !defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +00001655 if (is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001656#endif
1657 {
bellard2a4188a2006-06-25 21:54:59 +00001658 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001659 /* IO memory case */
1660 address = vaddr | pd;
1661 addend = paddr;
1662 } else {
1663 /* standard memory */
1664 address = vaddr;
1665 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1666 }
pbrook6658ffb2007-03-16 23:58:11 +00001667
1668 /* Make accesses to pages with watchpoints go via the
1669 watchpoint trap routines. */
1670 for (i = 0; i < env->nb_watchpoints; i++) {
1671 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1672 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001673 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001674 address = vaddr | io_mem_watch;
1675 } else {
balrogd79acba2007-06-26 20:01:13 +00001676 env->watchpoint[i].addend = pd - paddr +
1677 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001678 /* TODO: Figure out how to make read watchpoints coexist
1679 with code. */
1680 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1681 }
1682 }
1683 }
balrogd79acba2007-06-26 20:01:13 +00001684
bellard90f18422005-07-24 10:17:31 +00001685 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001686 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001687 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001688 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001689 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001690 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001691 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001692 te->addr_read = -1;
1693 }
1694 if (prot & PAGE_EXEC) {
1695 te->addr_code = address;
1696 } else {
1697 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001698 }
bellard67b915a2004-03-31 23:37:16 +00001699 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001700 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001701 (pd & IO_MEM_ROMD)) {
1702 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001703 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001704 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001705 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001706 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001707 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001708 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001709 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001710 }
1711 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001712 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001713 }
1714 }
1715#if !defined(CONFIG_SOFTMMU)
1716 else {
1717 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1718 /* IO access: no mapping is done as it will be handled by the
1719 soft MMU */
1720 if (!(env->hflags & HF_SOFTMMU_MASK))
1721 ret = 2;
1722 } else {
1723 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001724
bellard59817cc2004-02-16 22:01:13 +00001725 if (vaddr >= MMAP_AREA_END) {
1726 ret = 2;
1727 } else {
1728 if (prot & PROT_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001729 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001730#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001731 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001732#endif
ths5fafdf22007-09-16 21:08:06 +00001733 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard59817cc2004-02-16 22:01:13 +00001734 !cpu_physical_memory_is_dirty(pd))) {
1735 /* ROM: we do as if code was inside */
1736 /* if code is present, we only map as read only and save the
1737 original mapping */
1738 VirtPageDesc *vp;
ths3b46e622007-09-17 08:09:54 +00001739
bellard90f18422005-07-24 10:17:31 +00001740 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001741 vp->phys_addr = pd;
1742 vp->prot = prot;
1743 vp->valid_tag = virt_valid_tag;
1744 prot &= ~PAGE_WRITE;
1745 }
bellard9fa3e852004-01-04 18:06:42 +00001746 }
ths5fafdf22007-09-16 21:08:06 +00001747 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
bellard59817cc2004-02-16 22:01:13 +00001748 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1749 if (map_addr == MAP_FAILED) {
1750 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1751 paddr, vaddr);
1752 }
bellard9fa3e852004-01-04 18:06:42 +00001753 }
1754 }
1755 }
1756#endif
1757 return ret;
1758}
1759
1760/* called from signal handler: invalidate the code and unprotect the
1761 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001762int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001763{
1764#if !defined(CONFIG_SOFTMMU)
1765 VirtPageDesc *vp;
1766
1767#if defined(DEBUG_TLB)
1768 printf("page_unprotect: addr=0x%08x\n", addr);
1769#endif
1770 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001771
1772 /* if it is not mapped, no need to worry here */
1773 if (addr >= MMAP_AREA_END)
1774 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001775 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1776 if (!vp)
1777 return 0;
1778 /* NOTE: in this case, validate_tag is _not_ tested as it
1779 validates only the code TLB */
1780 if (vp->valid_tag != virt_valid_tag)
1781 return 0;
1782 if (!(vp->prot & PAGE_WRITE))
1783 return 0;
1784#if defined(DEBUG_TLB)
ths5fafdf22007-09-16 21:08:06 +00001785 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
bellard9fa3e852004-01-04 18:06:42 +00001786 addr, vp->phys_addr, vp->prot);
1787#endif
bellard59817cc2004-02-16 22:01:13 +00001788 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1789 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1790 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001791 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001792 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001793 /* flush the code inside */
1794 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001795 return 1;
1796#else
1797 return 0;
1798#endif
bellard33417e72003-08-10 21:47:01 +00001799}
1800
bellard01243112004-01-04 15:48:17 +00001801#else
1802
bellardee8b7022004-02-03 23:35:10 +00001803void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001804{
1805}
1806
bellard2e126692004-04-25 21:28:44 +00001807void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001808{
1809}
1810
ths5fafdf22007-09-16 21:08:06 +00001811int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1812 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001813 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001814{
bellard9fa3e852004-01-04 18:06:42 +00001815 return 0;
1816}
bellard33417e72003-08-10 21:47:01 +00001817
bellard9fa3e852004-01-04 18:06:42 +00001818/* dump memory mappings */
1819void page_dump(FILE *f)
1820{
1821 unsigned long start, end;
1822 int i, j, prot, prot1;
1823 PageDesc *p;
1824
1825 fprintf(f, "%-8s %-8s %-8s %s\n",
1826 "start", "end", "size", "prot");
1827 start = -1;
1828 end = -1;
1829 prot = 0;
1830 for(i = 0; i <= L1_SIZE; i++) {
1831 if (i < L1_SIZE)
1832 p = l1_map[i];
1833 else
1834 p = NULL;
1835 for(j = 0;j < L2_SIZE; j++) {
1836 if (!p)
1837 prot1 = 0;
1838 else
1839 prot1 = p[j].flags;
1840 if (prot1 != prot) {
1841 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1842 if (start != -1) {
1843 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001844 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001845 prot & PAGE_READ ? 'r' : '-',
1846 prot & PAGE_WRITE ? 'w' : '-',
1847 prot & PAGE_EXEC ? 'x' : '-');
1848 }
1849 if (prot1 != 0)
1850 start = end;
1851 else
1852 start = -1;
1853 prot = prot1;
1854 }
1855 if (!p)
1856 break;
1857 }
bellard33417e72003-08-10 21:47:01 +00001858 }
bellard33417e72003-08-10 21:47:01 +00001859}
1860
pbrook53a59602006-03-25 19:31:22 +00001861int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001862{
bellard9fa3e852004-01-04 18:06:42 +00001863 PageDesc *p;
1864
1865 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001866 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001867 return 0;
1868 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001869}
1870
bellard9fa3e852004-01-04 18:06:42 +00001871/* modify the flags of a page and invalidate the code if
1872 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1873 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001874void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001875{
1876 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001877 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001878
1879 start = start & TARGET_PAGE_MASK;
1880 end = TARGET_PAGE_ALIGN(end);
1881 if (flags & PAGE_WRITE)
1882 flags |= PAGE_WRITE_ORG;
1883 spin_lock(&tb_lock);
1884 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1885 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1886 /* if the write protection is set, then we invalidate the code
1887 inside */
ths5fafdf22007-09-16 21:08:06 +00001888 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001889 (flags & PAGE_WRITE) &&
1890 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001891 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001892 }
1893 p->flags = flags;
1894 }
1895 spin_unlock(&tb_lock);
1896}
1897
ths3d97b402007-11-02 19:02:07 +00001898int page_check_range(target_ulong start, target_ulong len, int flags)
1899{
1900 PageDesc *p;
1901 target_ulong end;
1902 target_ulong addr;
1903
1904 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1905 start = start & TARGET_PAGE_MASK;
1906
1907 if( end < start )
1908 /* we've wrapped around */
1909 return -1;
1910 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1911 p = page_find(addr >> TARGET_PAGE_BITS);
1912 if( !p )
1913 return -1;
1914 if( !(p->flags & PAGE_VALID) )
1915 return -1;
1916
bellarddae32702007-11-14 10:51:00 +00001917 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001918 return -1;
bellarddae32702007-11-14 10:51:00 +00001919 if (flags & PAGE_WRITE) {
1920 if (!(p->flags & PAGE_WRITE_ORG))
1921 return -1;
1922 /* unprotect the page if it was put read-only because it
1923 contains translated code */
1924 if (!(p->flags & PAGE_WRITE)) {
1925 if (!page_unprotect(addr, 0, NULL))
1926 return -1;
1927 }
1928 return 0;
1929 }
ths3d97b402007-11-02 19:02:07 +00001930 }
1931 return 0;
1932}
1933
bellard9fa3e852004-01-04 18:06:42 +00001934/* called from signal handler: invalidate the code and unprotect the
1935 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001936int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001937{
1938 unsigned int page_index, prot, pindex;
1939 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001940 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001941
bellard83fb7ad2004-07-05 21:25:26 +00001942 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001943 page_index = host_start >> TARGET_PAGE_BITS;
1944 p1 = page_find(page_index);
1945 if (!p1)
1946 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001947 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001948 p = p1;
1949 prot = 0;
1950 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1951 prot |= p->flags;
1952 p++;
1953 }
1954 /* if the page was really writable, then we change its
1955 protection back to writable */
1956 if (prot & PAGE_WRITE_ORG) {
1957 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1958 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00001959 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001960 (prot & PAGE_BITS) | PAGE_WRITE);
1961 p1[pindex].flags |= PAGE_WRITE;
1962 /* and since the content will be modified, we must invalidate
1963 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001964 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001965#ifdef DEBUG_TB_CHECK
1966 tb_invalidate_check(address);
1967#endif
1968 return 1;
1969 }
1970 }
1971 return 0;
1972}
1973
bellard6a00d602005-11-21 23:25:50 +00001974static inline void tlb_set_dirty(CPUState *env,
1975 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001976{
1977}
bellard9fa3e852004-01-04 18:06:42 +00001978#endif /* defined(CONFIG_USER_ONLY) */
1979
blueswir1db7b5422007-05-26 17:36:03 +00001980static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
1981 int memory);
1982static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
1983 int orig_memory);
1984#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
1985 need_subpage) \
1986 do { \
1987 if (addr > start_addr) \
1988 start_addr2 = 0; \
1989 else { \
1990 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
1991 if (start_addr2 > 0) \
1992 need_subpage = 1; \
1993 } \
1994 \
blueswir149e9fba2007-05-30 17:25:06 +00001995 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00001996 end_addr2 = TARGET_PAGE_SIZE - 1; \
1997 else { \
1998 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
1999 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2000 need_subpage = 1; \
2001 } \
2002 } while (0)
2003
bellard33417e72003-08-10 21:47:01 +00002004/* register physical memory. 'size' must be a multiple of the target
2005 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2006 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002007void cpu_register_physical_memory(target_phys_addr_t start_addr,
bellard2e126692004-04-25 21:28:44 +00002008 unsigned long size,
2009 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00002010{
bellard108c49b2005-07-24 12:55:09 +00002011 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002012 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002013 CPUState *env;
blueswir1db7b5422007-05-26 17:36:03 +00002014 unsigned long orig_size = size;
2015 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002016
bellard5fd386f2004-05-23 21:11:22 +00002017 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002018 end_addr = start_addr + (target_phys_addr_t)size;
2019 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002020 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2021 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
2022 unsigned long orig_memory = p->phys_offset;
2023 target_phys_addr_t start_addr2, end_addr2;
2024 int need_subpage = 0;
2025
2026 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2027 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002028 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002029 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2030 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2031 &p->phys_offset, orig_memory);
2032 } else {
2033 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2034 >> IO_MEM_SHIFT];
2035 }
2036 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2037 } else {
2038 p->phys_offset = phys_offset;
2039 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2040 (phys_offset & IO_MEM_ROMD))
2041 phys_offset += TARGET_PAGE_SIZE;
2042 }
2043 } else {
2044 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2045 p->phys_offset = phys_offset;
2046 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2047 (phys_offset & IO_MEM_ROMD))
2048 phys_offset += TARGET_PAGE_SIZE;
2049 else {
2050 target_phys_addr_t start_addr2, end_addr2;
2051 int need_subpage = 0;
2052
2053 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2054 end_addr2, need_subpage);
2055
blueswir14254fab2008-01-01 16:57:19 +00002056 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002057 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2058 &p->phys_offset, IO_MEM_UNASSIGNED);
2059 subpage_register(subpage, start_addr2, end_addr2,
2060 phys_offset);
2061 }
2062 }
2063 }
bellard33417e72003-08-10 21:47:01 +00002064 }
ths3b46e622007-09-17 08:09:54 +00002065
bellard9d420372006-06-25 22:25:22 +00002066 /* since each CPU stores ram addresses in its TLB cache, we must
2067 reset the modified entries */
2068 /* XXX: slow ! */
2069 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2070 tlb_flush(env, 1);
2071 }
bellard33417e72003-08-10 21:47:01 +00002072}
2073
bellardba863452006-09-24 18:41:10 +00002074/* XXX: temporary until new memory mapping API */
2075uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
2076{
2077 PhysPageDesc *p;
2078
2079 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2080 if (!p)
2081 return IO_MEM_UNASSIGNED;
2082 return p->phys_offset;
2083}
2084
bellarde9a1ab12007-02-08 23:08:38 +00002085/* XXX: better than nothing */
2086ram_addr_t qemu_ram_alloc(unsigned int size)
2087{
2088 ram_addr_t addr;
2089 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
ths5fafdf22007-09-16 21:08:06 +00002090 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
bellarde9a1ab12007-02-08 23:08:38 +00002091 size, phys_ram_size);
2092 abort();
2093 }
2094 addr = phys_ram_alloc_offset;
2095 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2096 return addr;
2097}
2098
2099void qemu_ram_free(ram_addr_t addr)
2100{
2101}
2102
bellarda4193c82004-06-03 14:01:43 +00002103static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002104{
pbrook67d3b952006-12-18 05:03:52 +00002105#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002106 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002107#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002108#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002109 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002110#elif TARGET_CRIS
2111 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002112#endif
bellard33417e72003-08-10 21:47:01 +00002113 return 0;
2114}
2115
bellarda4193c82004-06-03 14:01:43 +00002116static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002117{
pbrook67d3b952006-12-18 05:03:52 +00002118#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002119 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002120#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002121#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002122 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002123#elif TARGET_CRIS
2124 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002125#endif
bellard33417e72003-08-10 21:47:01 +00002126}
2127
2128static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2129 unassigned_mem_readb,
2130 unassigned_mem_readb,
2131 unassigned_mem_readb,
2132};
2133
2134static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2135 unassigned_mem_writeb,
2136 unassigned_mem_writeb,
2137 unassigned_mem_writeb,
2138};
2139
bellarda4193c82004-06-03 14:01:43 +00002140static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002141{
bellard3a7d9292005-08-21 09:26:42 +00002142 unsigned long ram_addr;
2143 int dirty_flags;
2144 ram_addr = addr - (unsigned long)phys_ram_base;
2145 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2146 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2147#if !defined(CONFIG_USER_ONLY)
2148 tb_invalidate_phys_page_fast(ram_addr, 1);
2149 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2150#endif
2151 }
bellardc27004e2005-01-03 23:35:10 +00002152 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002153#ifdef USE_KQEMU
2154 if (cpu_single_env->kqemu_enabled &&
2155 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2156 kqemu_modify_page(cpu_single_env, ram_addr);
2157#endif
bellardf23db162005-08-21 19:12:28 +00002158 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2159 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2160 /* we remove the notdirty callback only if the code has been
2161 flushed */
2162 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002163 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002164}
2165
bellarda4193c82004-06-03 14:01:43 +00002166static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002167{
bellard3a7d9292005-08-21 09:26:42 +00002168 unsigned long ram_addr;
2169 int dirty_flags;
2170 ram_addr = addr - (unsigned long)phys_ram_base;
2171 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2172 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2173#if !defined(CONFIG_USER_ONLY)
2174 tb_invalidate_phys_page_fast(ram_addr, 2);
2175 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2176#endif
2177 }
bellardc27004e2005-01-03 23:35:10 +00002178 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002179#ifdef USE_KQEMU
2180 if (cpu_single_env->kqemu_enabled &&
2181 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2182 kqemu_modify_page(cpu_single_env, ram_addr);
2183#endif
bellardf23db162005-08-21 19:12:28 +00002184 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2185 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2186 /* we remove the notdirty callback only if the code has been
2187 flushed */
2188 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002189 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002190}
2191
bellarda4193c82004-06-03 14:01:43 +00002192static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002193{
bellard3a7d9292005-08-21 09:26:42 +00002194 unsigned long ram_addr;
2195 int dirty_flags;
2196 ram_addr = addr - (unsigned long)phys_ram_base;
2197 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2198 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2199#if !defined(CONFIG_USER_ONLY)
2200 tb_invalidate_phys_page_fast(ram_addr, 4);
2201 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2202#endif
2203 }
bellardc27004e2005-01-03 23:35:10 +00002204 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002205#ifdef USE_KQEMU
2206 if (cpu_single_env->kqemu_enabled &&
2207 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2208 kqemu_modify_page(cpu_single_env, ram_addr);
2209#endif
bellardf23db162005-08-21 19:12:28 +00002210 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2211 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2212 /* we remove the notdirty callback only if the code has been
2213 flushed */
2214 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002215 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002216}
2217
bellard3a7d9292005-08-21 09:26:42 +00002218static CPUReadMemoryFunc *error_mem_read[3] = {
2219 NULL, /* never used */
2220 NULL, /* never used */
2221 NULL, /* never used */
2222};
2223
bellard1ccde1c2004-02-06 19:46:14 +00002224static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2225 notdirty_mem_writeb,
2226 notdirty_mem_writew,
2227 notdirty_mem_writel,
2228};
2229
pbrook6658ffb2007-03-16 23:58:11 +00002230#if defined(CONFIG_SOFTMMU)
2231/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2232 so these check for a hit then pass through to the normal out-of-line
2233 phys routines. */
2234static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2235{
2236 return ldub_phys(addr);
2237}
2238
2239static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2240{
2241 return lduw_phys(addr);
2242}
2243
2244static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2245{
2246 return ldl_phys(addr);
2247}
2248
2249/* Generate a debug exception if a watchpoint has been hit.
2250 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002251 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002252static target_ulong check_watchpoint(target_phys_addr_t addr)
2253{
2254 CPUState *env = cpu_single_env;
2255 target_ulong watch;
2256 target_ulong retaddr;
2257 int i;
2258
2259 retaddr = addr;
2260 for (i = 0; i < env->nb_watchpoints; i++) {
2261 watch = env->watchpoint[i].vaddr;
2262 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002263 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002264 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2265 cpu_single_env->watchpoint_hit = i + 1;
2266 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2267 break;
2268 }
2269 }
2270 }
2271 return retaddr;
2272}
2273
2274static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2275 uint32_t val)
2276{
2277 addr = check_watchpoint(addr);
2278 stb_phys(addr, val);
2279}
2280
2281static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2282 uint32_t val)
2283{
2284 addr = check_watchpoint(addr);
2285 stw_phys(addr, val);
2286}
2287
2288static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2289 uint32_t val)
2290{
2291 addr = check_watchpoint(addr);
2292 stl_phys(addr, val);
2293}
2294
2295static CPUReadMemoryFunc *watch_mem_read[3] = {
2296 watch_mem_readb,
2297 watch_mem_readw,
2298 watch_mem_readl,
2299};
2300
2301static CPUWriteMemoryFunc *watch_mem_write[3] = {
2302 watch_mem_writeb,
2303 watch_mem_writew,
2304 watch_mem_writel,
2305};
2306#endif
2307
blueswir1db7b5422007-05-26 17:36:03 +00002308static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2309 unsigned int len)
2310{
blueswir1db7b5422007-05-26 17:36:03 +00002311 uint32_t ret;
2312 unsigned int idx;
2313
2314 idx = SUBPAGE_IDX(addr - mmio->base);
2315#if defined(DEBUG_SUBPAGE)
2316 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2317 mmio, len, addr, idx);
2318#endif
blueswir13ee89922008-01-02 19:45:26 +00002319 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002320
2321 return ret;
2322}
2323
2324static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2325 uint32_t value, unsigned int len)
2326{
blueswir1db7b5422007-05-26 17:36:03 +00002327 unsigned int idx;
2328
2329 idx = SUBPAGE_IDX(addr - mmio->base);
2330#if defined(DEBUG_SUBPAGE)
2331 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2332 mmio, len, addr, idx, value);
2333#endif
blueswir13ee89922008-01-02 19:45:26 +00002334 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002335}
2336
2337static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2338{
2339#if defined(DEBUG_SUBPAGE)
2340 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2341#endif
2342
2343 return subpage_readlen(opaque, addr, 0);
2344}
2345
2346static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2347 uint32_t value)
2348{
2349#if defined(DEBUG_SUBPAGE)
2350 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2351#endif
2352 subpage_writelen(opaque, addr, value, 0);
2353}
2354
2355static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2356{
2357#if defined(DEBUG_SUBPAGE)
2358 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2359#endif
2360
2361 return subpage_readlen(opaque, addr, 1);
2362}
2363
2364static void subpage_writew (void *opaque, target_phys_addr_t addr,
2365 uint32_t value)
2366{
2367#if defined(DEBUG_SUBPAGE)
2368 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2369#endif
2370 subpage_writelen(opaque, addr, value, 1);
2371}
2372
2373static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2374{
2375#if defined(DEBUG_SUBPAGE)
2376 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2377#endif
2378
2379 return subpage_readlen(opaque, addr, 2);
2380}
2381
2382static void subpage_writel (void *opaque,
2383 target_phys_addr_t addr, uint32_t value)
2384{
2385#if defined(DEBUG_SUBPAGE)
2386 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2387#endif
2388 subpage_writelen(opaque, addr, value, 2);
2389}
2390
2391static CPUReadMemoryFunc *subpage_read[] = {
2392 &subpage_readb,
2393 &subpage_readw,
2394 &subpage_readl,
2395};
2396
2397static CPUWriteMemoryFunc *subpage_write[] = {
2398 &subpage_writeb,
2399 &subpage_writew,
2400 &subpage_writel,
2401};
2402
2403static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
2404 int memory)
2405{
2406 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002407 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002408
2409 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2410 return -1;
2411 idx = SUBPAGE_IDX(start);
2412 eidx = SUBPAGE_IDX(end);
2413#if defined(DEBUG_SUBPAGE)
2414 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2415 mmio, start, end, idx, eidx, memory);
2416#endif
2417 memory >>= IO_MEM_SHIFT;
2418 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002419 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002420 if (io_mem_read[memory][i]) {
2421 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2422 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2423 }
2424 if (io_mem_write[memory][i]) {
2425 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2426 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2427 }
blueswir14254fab2008-01-01 16:57:19 +00002428 }
blueswir1db7b5422007-05-26 17:36:03 +00002429 }
2430
2431 return 0;
2432}
2433
2434static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
2435 int orig_memory)
2436{
2437 subpage_t *mmio;
2438 int subpage_memory;
2439
2440 mmio = qemu_mallocz(sizeof(subpage_t));
2441 if (mmio != NULL) {
2442 mmio->base = base;
2443 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2444#if defined(DEBUG_SUBPAGE)
2445 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2446 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2447#endif
2448 *phys = subpage_memory | IO_MEM_SUBPAGE;
2449 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2450 }
2451
2452 return mmio;
2453}
2454
bellard33417e72003-08-10 21:47:01 +00002455static void io_mem_init(void)
2456{
bellard3a7d9292005-08-21 09:26:42 +00002457 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002458 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002459 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002460 io_mem_nb = 5;
2461
pbrook6658ffb2007-03-16 23:58:11 +00002462#if defined(CONFIG_SOFTMMU)
2463 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2464 watch_mem_write, NULL);
2465#endif
bellard1ccde1c2004-02-06 19:46:14 +00002466 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002467 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002468 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002469}
2470
2471/* mem_read and mem_write are arrays of functions containing the
2472 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002473 2). Functions can be omitted with a NULL function pointer. The
2474 registered functions may be modified dynamically later.
2475 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002476 modified. If it is zero, a new io zone is allocated. The return
2477 value can be used with cpu_register_physical_memory(). (-1) is
2478 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002479int cpu_register_io_memory(int io_index,
2480 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002481 CPUWriteMemoryFunc **mem_write,
2482 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002483{
blueswir14254fab2008-01-01 16:57:19 +00002484 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002485
2486 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002487 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002488 return -1;
2489 io_index = io_mem_nb++;
2490 } else {
2491 if (io_index >= IO_MEM_NB_ENTRIES)
2492 return -1;
2493 }
bellardb5ff1b32005-11-26 10:38:39 +00002494
bellard33417e72003-08-10 21:47:01 +00002495 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002496 if (!mem_read[i] || !mem_write[i])
2497 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002498 io_mem_read[io_index][i] = mem_read[i];
2499 io_mem_write[io_index][i] = mem_write[i];
2500 }
bellarda4193c82004-06-03 14:01:43 +00002501 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002502 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002503}
bellard61382a52003-10-27 21:22:23 +00002504
bellard8926b512004-10-10 15:14:20 +00002505CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2506{
2507 return io_mem_write[io_index >> IO_MEM_SHIFT];
2508}
2509
2510CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2511{
2512 return io_mem_read[io_index >> IO_MEM_SHIFT];
2513}
2514
bellard13eb76e2004-01-24 15:23:36 +00002515/* physical memory access (slow version, mainly for debug) */
2516#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002517void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002518 int len, int is_write)
2519{
2520 int l, flags;
2521 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002522 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002523
2524 while (len > 0) {
2525 page = addr & TARGET_PAGE_MASK;
2526 l = (page + TARGET_PAGE_SIZE) - addr;
2527 if (l > len)
2528 l = len;
2529 flags = page_get_flags(page);
2530 if (!(flags & PAGE_VALID))
2531 return;
2532 if (is_write) {
2533 if (!(flags & PAGE_WRITE))
2534 return;
bellard579a97f2007-11-11 14:26:47 +00002535 /* XXX: this code should not depend on lock_user */
2536 if (!(p = lock_user(VERIFY_WRITE, addr, len, 0)))
2537 /* FIXME - should this return an error rather than just fail? */
2538 return;
pbrook53a59602006-03-25 19:31:22 +00002539 memcpy(p, buf, len);
2540 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002541 } else {
2542 if (!(flags & PAGE_READ))
2543 return;
bellard579a97f2007-11-11 14:26:47 +00002544 /* XXX: this code should not depend on lock_user */
2545 if (!(p = lock_user(VERIFY_READ, addr, len, 1)))
2546 /* FIXME - should this return an error rather than just fail? */
2547 return;
pbrook53a59602006-03-25 19:31:22 +00002548 memcpy(buf, p, len);
2549 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002550 }
2551 len -= l;
2552 buf += l;
2553 addr += l;
2554 }
2555}
bellard8df1cd02005-01-28 22:37:22 +00002556
bellard13eb76e2004-01-24 15:23:36 +00002557#else
ths5fafdf22007-09-16 21:08:06 +00002558void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002559 int len, int is_write)
2560{
2561 int l, io_index;
2562 uint8_t *ptr;
2563 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002564 target_phys_addr_t page;
2565 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002566 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002567
bellard13eb76e2004-01-24 15:23:36 +00002568 while (len > 0) {
2569 page = addr & TARGET_PAGE_MASK;
2570 l = (page + TARGET_PAGE_SIZE) - addr;
2571 if (l > len)
2572 l = len;
bellard92e873b2004-05-21 14:52:29 +00002573 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002574 if (!p) {
2575 pd = IO_MEM_UNASSIGNED;
2576 } else {
2577 pd = p->phys_offset;
2578 }
ths3b46e622007-09-17 08:09:54 +00002579
bellard13eb76e2004-01-24 15:23:36 +00002580 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002581 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002582 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002583 /* XXX: could force cpu_single_env to NULL to avoid
2584 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002585 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002586 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002587 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002588 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002589 l = 4;
2590 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002591 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002592 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002593 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002594 l = 2;
2595 } else {
bellard1c213d12005-09-03 10:49:04 +00002596 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002597 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002598 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002599 l = 1;
2600 }
2601 } else {
bellardb448f2f2004-02-25 23:24:04 +00002602 unsigned long addr1;
2603 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002604 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002605 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002606 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002607 if (!cpu_physical_memory_is_dirty(addr1)) {
2608 /* invalidate code */
2609 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2610 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002611 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002612 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002613 }
bellard13eb76e2004-01-24 15:23:36 +00002614 }
2615 } else {
ths5fafdf22007-09-16 21:08:06 +00002616 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002617 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002618 /* I/O case */
2619 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2620 if (l >= 4 && ((addr & 3) == 0)) {
2621 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002622 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002623 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002624 l = 4;
2625 } else if (l >= 2 && ((addr & 1) == 0)) {
2626 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002627 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002628 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002629 l = 2;
2630 } else {
bellard1c213d12005-09-03 10:49:04 +00002631 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002632 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002633 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002634 l = 1;
2635 }
2636 } else {
2637 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002638 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002639 (addr & ~TARGET_PAGE_MASK);
2640 memcpy(buf, ptr, l);
2641 }
2642 }
2643 len -= l;
2644 buf += l;
2645 addr += l;
2646 }
2647}
bellard8df1cd02005-01-28 22:37:22 +00002648
bellardd0ecd2a2006-04-23 17:14:48 +00002649/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002650void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002651 const uint8_t *buf, int len)
2652{
2653 int l;
2654 uint8_t *ptr;
2655 target_phys_addr_t page;
2656 unsigned long pd;
2657 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002658
bellardd0ecd2a2006-04-23 17:14:48 +00002659 while (len > 0) {
2660 page = addr & TARGET_PAGE_MASK;
2661 l = (page + TARGET_PAGE_SIZE) - addr;
2662 if (l > len)
2663 l = len;
2664 p = phys_page_find(page >> TARGET_PAGE_BITS);
2665 if (!p) {
2666 pd = IO_MEM_UNASSIGNED;
2667 } else {
2668 pd = p->phys_offset;
2669 }
ths3b46e622007-09-17 08:09:54 +00002670
bellardd0ecd2a2006-04-23 17:14:48 +00002671 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002672 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2673 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002674 /* do nothing */
2675 } else {
2676 unsigned long addr1;
2677 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2678 /* ROM/RAM case */
2679 ptr = phys_ram_base + addr1;
2680 memcpy(ptr, buf, l);
2681 }
2682 len -= l;
2683 buf += l;
2684 addr += l;
2685 }
2686}
2687
2688
bellard8df1cd02005-01-28 22:37:22 +00002689/* warning: addr must be aligned */
2690uint32_t ldl_phys(target_phys_addr_t addr)
2691{
2692 int io_index;
2693 uint8_t *ptr;
2694 uint32_t val;
2695 unsigned long pd;
2696 PhysPageDesc *p;
2697
2698 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2699 if (!p) {
2700 pd = IO_MEM_UNASSIGNED;
2701 } else {
2702 pd = p->phys_offset;
2703 }
ths3b46e622007-09-17 08:09:54 +00002704
ths5fafdf22007-09-16 21:08:06 +00002705 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002706 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002707 /* I/O case */
2708 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2709 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2710 } else {
2711 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002712 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002713 (addr & ~TARGET_PAGE_MASK);
2714 val = ldl_p(ptr);
2715 }
2716 return val;
2717}
2718
bellard84b7b8e2005-11-28 21:19:04 +00002719/* warning: addr must be aligned */
2720uint64_t ldq_phys(target_phys_addr_t addr)
2721{
2722 int io_index;
2723 uint8_t *ptr;
2724 uint64_t val;
2725 unsigned long pd;
2726 PhysPageDesc *p;
2727
2728 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2729 if (!p) {
2730 pd = IO_MEM_UNASSIGNED;
2731 } else {
2732 pd = p->phys_offset;
2733 }
ths3b46e622007-09-17 08:09:54 +00002734
bellard2a4188a2006-06-25 21:54:59 +00002735 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2736 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002737 /* I/O case */
2738 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2739#ifdef TARGET_WORDS_BIGENDIAN
2740 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2741 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2742#else
2743 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2744 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2745#endif
2746 } else {
2747 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002748 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002749 (addr & ~TARGET_PAGE_MASK);
2750 val = ldq_p(ptr);
2751 }
2752 return val;
2753}
2754
bellardaab33092005-10-30 20:48:42 +00002755/* XXX: optimize */
2756uint32_t ldub_phys(target_phys_addr_t addr)
2757{
2758 uint8_t val;
2759 cpu_physical_memory_read(addr, &val, 1);
2760 return val;
2761}
2762
2763/* XXX: optimize */
2764uint32_t lduw_phys(target_phys_addr_t addr)
2765{
2766 uint16_t val;
2767 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2768 return tswap16(val);
2769}
2770
bellard8df1cd02005-01-28 22:37:22 +00002771/* warning: addr must be aligned. The ram page is not masked as dirty
2772 and the code inside is not invalidated. It is useful if the dirty
2773 bits are used to track modified PTEs */
2774void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2775{
2776 int io_index;
2777 uint8_t *ptr;
2778 unsigned long pd;
2779 PhysPageDesc *p;
2780
2781 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2782 if (!p) {
2783 pd = IO_MEM_UNASSIGNED;
2784 } else {
2785 pd = p->phys_offset;
2786 }
ths3b46e622007-09-17 08:09:54 +00002787
bellard3a7d9292005-08-21 09:26:42 +00002788 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002789 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2790 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2791 } else {
ths5fafdf22007-09-16 21:08:06 +00002792 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002793 (addr & ~TARGET_PAGE_MASK);
2794 stl_p(ptr, val);
2795 }
2796}
2797
j_mayerbc98a7e2007-04-04 07:55:12 +00002798void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2799{
2800 int io_index;
2801 uint8_t *ptr;
2802 unsigned long pd;
2803 PhysPageDesc *p;
2804
2805 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2806 if (!p) {
2807 pd = IO_MEM_UNASSIGNED;
2808 } else {
2809 pd = p->phys_offset;
2810 }
ths3b46e622007-09-17 08:09:54 +00002811
j_mayerbc98a7e2007-04-04 07:55:12 +00002812 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2813 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2814#ifdef TARGET_WORDS_BIGENDIAN
2815 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2816 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2817#else
2818 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2819 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2820#endif
2821 } else {
ths5fafdf22007-09-16 21:08:06 +00002822 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002823 (addr & ~TARGET_PAGE_MASK);
2824 stq_p(ptr, val);
2825 }
2826}
2827
bellard8df1cd02005-01-28 22:37:22 +00002828/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002829void stl_phys(target_phys_addr_t addr, uint32_t val)
2830{
2831 int io_index;
2832 uint8_t *ptr;
2833 unsigned long pd;
2834 PhysPageDesc *p;
2835
2836 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2837 if (!p) {
2838 pd = IO_MEM_UNASSIGNED;
2839 } else {
2840 pd = p->phys_offset;
2841 }
ths3b46e622007-09-17 08:09:54 +00002842
bellard3a7d9292005-08-21 09:26:42 +00002843 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002844 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2845 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2846 } else {
2847 unsigned long addr1;
2848 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2849 /* RAM case */
2850 ptr = phys_ram_base + addr1;
2851 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002852 if (!cpu_physical_memory_is_dirty(addr1)) {
2853 /* invalidate code */
2854 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2855 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002856 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2857 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002858 }
bellard8df1cd02005-01-28 22:37:22 +00002859 }
2860}
2861
bellardaab33092005-10-30 20:48:42 +00002862/* XXX: optimize */
2863void stb_phys(target_phys_addr_t addr, uint32_t val)
2864{
2865 uint8_t v = val;
2866 cpu_physical_memory_write(addr, &v, 1);
2867}
2868
2869/* XXX: optimize */
2870void stw_phys(target_phys_addr_t addr, uint32_t val)
2871{
2872 uint16_t v = tswap16(val);
2873 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2874}
2875
2876/* XXX: optimize */
2877void stq_phys(target_phys_addr_t addr, uint64_t val)
2878{
2879 val = tswap64(val);
2880 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2881}
2882
bellard13eb76e2004-01-24 15:23:36 +00002883#endif
2884
2885/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002886int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002887 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002888{
2889 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002890 target_phys_addr_t phys_addr;
2891 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002892
2893 while (len > 0) {
2894 page = addr & TARGET_PAGE_MASK;
2895 phys_addr = cpu_get_phys_page_debug(env, page);
2896 /* if no physical page mapped, return an error */
2897 if (phys_addr == -1)
2898 return -1;
2899 l = (page + TARGET_PAGE_SIZE) - addr;
2900 if (l > len)
2901 l = len;
ths5fafdf22007-09-16 21:08:06 +00002902 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002903 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002904 len -= l;
2905 buf += l;
2906 addr += l;
2907 }
2908 return 0;
2909}
2910
bellarde3db7222005-01-26 22:00:47 +00002911void dump_exec_info(FILE *f,
2912 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2913{
2914 int i, target_code_size, max_target_code_size;
2915 int direct_jmp_count, direct_jmp2_count, cross_page;
2916 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002917
bellarde3db7222005-01-26 22:00:47 +00002918 target_code_size = 0;
2919 max_target_code_size = 0;
2920 cross_page = 0;
2921 direct_jmp_count = 0;
2922 direct_jmp2_count = 0;
2923 for(i = 0; i < nb_tbs; i++) {
2924 tb = &tbs[i];
2925 target_code_size += tb->size;
2926 if (tb->size > max_target_code_size)
2927 max_target_code_size = tb->size;
2928 if (tb->page_addr[1] != -1)
2929 cross_page++;
2930 if (tb->tb_next_offset[0] != 0xffff) {
2931 direct_jmp_count++;
2932 if (tb->tb_next_offset[1] != 0xffff) {
2933 direct_jmp2_count++;
2934 }
2935 }
2936 }
2937 /* XXX: avoid using doubles ? */
2938 cpu_fprintf(f, "TB count %d\n", nb_tbs);
ths5fafdf22007-09-16 21:08:06 +00002939 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002940 nb_tbs ? target_code_size / nb_tbs : 0,
2941 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00002942 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00002943 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2944 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00002945 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2946 cross_page,
bellarde3db7222005-01-26 22:00:47 +00002947 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2948 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00002949 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00002950 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2951 direct_jmp2_count,
2952 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2953 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2954 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2955 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2956}
2957
ths5fafdf22007-09-16 21:08:06 +00002958#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00002959
2960#define MMUSUFFIX _cmmu
2961#define GETPC() NULL
2962#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002963#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002964
2965#define SHIFT 0
2966#include "softmmu_template.h"
2967
2968#define SHIFT 1
2969#include "softmmu_template.h"
2970
2971#define SHIFT 2
2972#include "softmmu_template.h"
2973
2974#define SHIFT 3
2975#include "softmmu_template.h"
2976
2977#undef env
2978
2979#endif