blob: bf2d82b9f43074f899b0c5032f02bb44c08e7fef [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * 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
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
pbrook53a59602006-03-25 19:31:22 +000037#if defined(CONFIG_USER_ONLY)
38#include <qemu.h>
39#endif
bellard54936002003-05-13 00:25:15 +000040
bellardfd6ce8f2003-05-14 19:00:11 +000041//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000042//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000043//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000044//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* make various TB consistency checks */
47//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000048//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000049
ths1196be32007-03-17 15:17:58 +000050//#define DEBUG_IOPORT
51
pbrook99773bd2006-04-16 15:14:59 +000052#if !defined(CONFIG_USER_ONLY)
53/* TB consistency checks only implemented for usermode emulation. */
54#undef DEBUG_TB_CHECK
55#endif
56
bellardfd6ce8f2003-05-14 19:00:11 +000057/* threshold to flush the translated code buffer */
58#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
59
bellard9fa3e852004-01-04 18:06:42 +000060#define SMC_BITMAP_USE_THRESHOLD 10
61
62#define MMAP_AREA_START 0x00000000
63#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000064
bellard108c49b2005-07-24 12:55:09 +000065#if defined(TARGET_SPARC64)
66#define TARGET_PHYS_ADDR_SPACE_BITS 41
j_mayerbedb69e2007-04-05 20:08:21 +000067#elif defined(TARGET_ALPHA)
68#define TARGET_PHYS_ADDR_SPACE_BITS 42
69#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000070#elif defined(TARGET_PPC64)
71#define TARGET_PHYS_ADDR_SPACE_BITS 42
72#else
73/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
74#define TARGET_PHYS_ADDR_SPACE_BITS 32
75#endif
76
bellardfd6ce8f2003-05-14 19:00:11 +000077TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000078TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000079int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000080/* any access to the tbs or the page table must use this lock */
81spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000082
bellardb8076a72005-04-07 22:20:31 +000083uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000084uint8_t *code_gen_ptr;
85
bellard9fa3e852004-01-04 18:06:42 +000086int phys_ram_size;
87int phys_ram_fd;
88uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000089uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +000090static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000091
bellard6a00d602005-11-21 23:25:50 +000092CPUState *first_cpu;
93/* current CPU in the current thread. It is only valid inside
94 cpu_exec() */
95CPUState *cpu_single_env;
96
bellard54936002003-05-13 00:25:15 +000097typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000098 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000099 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000100 /* in order to optimize self modifying code, we count the number
101 of lookups we do to a given page to use a bitmap */
102 unsigned int code_write_count;
103 uint8_t *code_bitmap;
104#if defined(CONFIG_USER_ONLY)
105 unsigned long flags;
106#endif
bellard54936002003-05-13 00:25:15 +0000107} PageDesc;
108
bellard92e873b2004-05-21 14:52:29 +0000109typedef struct PhysPageDesc {
110 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000111 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000112} PhysPageDesc;
113
bellard54936002003-05-13 00:25:15 +0000114#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000115#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
116/* XXX: this is a temporary hack for alpha target.
117 * In the future, this is to be replaced by a multi-level table
118 * to actually be able to handle the complete 64 bits address space.
119 */
120#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
121#else
bellard54936002003-05-13 00:25:15 +0000122#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000123#endif
bellard54936002003-05-13 00:25:15 +0000124
125#define L1_SIZE (1 << L1_BITS)
126#define L2_SIZE (1 << L2_BITS)
127
bellard33417e72003-08-10 21:47:01 +0000128static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000129
bellard83fb7ad2004-07-05 21:25:26 +0000130unsigned long qemu_real_host_page_size;
131unsigned long qemu_host_page_bits;
132unsigned long qemu_host_page_size;
133unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000134
bellard92e873b2004-05-21 14:52:29 +0000135/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000136static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000137PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000138
bellard33417e72003-08-10 21:47:01 +0000139/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000140CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
141CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000142void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000143static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000144#if defined(CONFIG_SOFTMMU)
145static int io_mem_watch;
146#endif
bellard33417e72003-08-10 21:47:01 +0000147
bellard34865132003-10-05 14:28:56 +0000148/* log support */
149char *logfilename = "/tmp/qemu.log";
150FILE *logfile;
151int loglevel;
152
bellarde3db7222005-01-26 22:00:47 +0000153/* statistics */
154static int tlb_flush_count;
155static int tb_flush_count;
156static int tb_phys_invalidate_count;
157
bellardb346ff42003-06-15 20:05:50 +0000158static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000159{
bellard83fb7ad2004-07-05 21:25:26 +0000160 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000161 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000162#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000163 {
164 SYSTEM_INFO system_info;
165 DWORD old_protect;
166
167 GetSystemInfo(&system_info);
168 qemu_real_host_page_size = system_info.dwPageSize;
169
170 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
171 PAGE_EXECUTE_READWRITE, &old_protect);
172 }
bellard67b915a2004-03-31 23:37:16 +0000173#else
bellard83fb7ad2004-07-05 21:25:26 +0000174 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000175 {
176 unsigned long start, end;
177
178 start = (unsigned long)code_gen_buffer;
179 start &= ~(qemu_real_host_page_size - 1);
180
181 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
182 end += qemu_real_host_page_size - 1;
183 end &= ~(qemu_real_host_page_size - 1);
184
185 mprotect((void *)start, end - start,
186 PROT_READ | PROT_WRITE | PROT_EXEC);
187 }
bellard67b915a2004-03-31 23:37:16 +0000188#endif
bellardd5a8f072004-09-29 21:15:28 +0000189
bellard83fb7ad2004-07-05 21:25:26 +0000190 if (qemu_host_page_size == 0)
191 qemu_host_page_size = qemu_real_host_page_size;
192 if (qemu_host_page_size < TARGET_PAGE_SIZE)
193 qemu_host_page_size = TARGET_PAGE_SIZE;
194 qemu_host_page_bits = 0;
195 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
196 qemu_host_page_bits++;
197 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000198 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
199 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000200}
201
bellardfd6ce8f2003-05-14 19:00:11 +0000202static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000203{
bellard54936002003-05-13 00:25:15 +0000204 PageDesc **lp, *p;
205
bellard54936002003-05-13 00:25:15 +0000206 lp = &l1_map[index >> L2_BITS];
207 p = *lp;
208 if (!p) {
209 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000210 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000211 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000212 *lp = p;
213 }
214 return p + (index & (L2_SIZE - 1));
215}
216
bellardfd6ce8f2003-05-14 19:00:11 +0000217static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000218{
bellard54936002003-05-13 00:25:15 +0000219 PageDesc *p;
220
bellard54936002003-05-13 00:25:15 +0000221 p = l1_map[index >> L2_BITS];
222 if (!p)
223 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000224 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000225}
226
bellard108c49b2005-07-24 12:55:09 +0000227static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000228{
bellard108c49b2005-07-24 12:55:09 +0000229 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000230 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000231
bellard108c49b2005-07-24 12:55:09 +0000232 p = (void **)l1_phys_map;
233#if TARGET_PHYS_ADDR_SPACE_BITS > 32
234
235#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
236#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
237#endif
238 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000239 p = *lp;
240 if (!p) {
241 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000242 if (!alloc)
243 return NULL;
244 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
245 memset(p, 0, sizeof(void *) * L1_SIZE);
246 *lp = p;
247 }
248#endif
249 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000250 pd = *lp;
251 if (!pd) {
252 int i;
bellard108c49b2005-07-24 12:55:09 +0000253 /* allocate if not found */
254 if (!alloc)
255 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000256 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
257 *lp = pd;
258 for (i = 0; i < L2_SIZE; i++)
259 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000260 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000261 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000262}
263
bellard108c49b2005-07-24 12:55:09 +0000264static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000265{
bellard108c49b2005-07-24 12:55:09 +0000266 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000267}
268
bellard9fa3e852004-01-04 18:06:42 +0000269#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000270static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000271static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
272 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000273#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000274
bellard6a00d602005-11-21 23:25:50 +0000275void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000276{
bellard6a00d602005-11-21 23:25:50 +0000277 CPUState **penv;
278 int cpu_index;
279
bellardfd6ce8f2003-05-14 19:00:11 +0000280 if (!code_gen_ptr) {
281 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000282 page_init();
bellard33417e72003-08-10 21:47:01 +0000283 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000284 }
bellard6a00d602005-11-21 23:25:50 +0000285 env->next_cpu = NULL;
286 penv = &first_cpu;
287 cpu_index = 0;
288 while (*penv != NULL) {
289 penv = (CPUState **)&(*penv)->next_cpu;
290 cpu_index++;
291 }
292 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000293 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000294 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000295}
296
bellard9fa3e852004-01-04 18:06:42 +0000297static inline void invalidate_page_bitmap(PageDesc *p)
298{
299 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000300 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000301 p->code_bitmap = NULL;
302 }
303 p->code_write_count = 0;
304}
305
bellardfd6ce8f2003-05-14 19:00:11 +0000306/* set to NULL all the 'first_tb' fields in all PageDescs */
307static void page_flush_tb(void)
308{
309 int i, j;
310 PageDesc *p;
311
312 for(i = 0; i < L1_SIZE; i++) {
313 p = l1_map[i];
314 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000315 for(j = 0; j < L2_SIZE; j++) {
316 p->first_tb = NULL;
317 invalidate_page_bitmap(p);
318 p++;
319 }
bellardfd6ce8f2003-05-14 19:00:11 +0000320 }
321 }
322}
323
324/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000325/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000326void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000327{
bellard6a00d602005-11-21 23:25:50 +0000328 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000329#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000330 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
331 code_gen_ptr - code_gen_buffer,
332 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000333 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000334#endif
335 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000336
337 for(env = first_cpu; env != NULL; env = env->next_cpu) {
338 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
339 }
bellard9fa3e852004-01-04 18:06:42 +0000340
bellard8a8a6082004-10-03 13:36:49 +0000341 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000342 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000343
bellardfd6ce8f2003-05-14 19:00:11 +0000344 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000345 /* XXX: flush processor icache at this point if cache flush is
346 expensive */
bellarde3db7222005-01-26 22:00:47 +0000347 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000348}
349
350#ifdef DEBUG_TB_CHECK
351
j_mayerbc98a7e2007-04-04 07:55:12 +0000352static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000353{
354 TranslationBlock *tb;
355 int i;
356 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000357 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
358 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000359 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
360 address >= tb->pc + tb->size)) {
361 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000362 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000363 }
364 }
365 }
366}
367
368/* verify that all the pages have correct rights for code */
369static void tb_page_check(void)
370{
371 TranslationBlock *tb;
372 int i, flags1, flags2;
373
pbrook99773bd2006-04-16 15:14:59 +0000374 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
375 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000376 flags1 = page_get_flags(tb->pc);
377 flags2 = page_get_flags(tb->pc + tb->size - 1);
378 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
379 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000380 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000381 }
382 }
383 }
384}
385
bellardd4e81642003-05-25 16:46:15 +0000386void tb_jmp_check(TranslationBlock *tb)
387{
388 TranslationBlock *tb1;
389 unsigned int n1;
390
391 /* suppress any remaining jumps to this TB */
392 tb1 = tb->jmp_first;
393 for(;;) {
394 n1 = (long)tb1 & 3;
395 tb1 = (TranslationBlock *)((long)tb1 & ~3);
396 if (n1 == 2)
397 break;
398 tb1 = tb1->jmp_next[n1];
399 }
400 /* check end of list */
401 if (tb1 != tb) {
402 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
403 }
404}
405
bellardfd6ce8f2003-05-14 19:00:11 +0000406#endif
407
408/* invalidate one TB */
409static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
410 int next_offset)
411{
412 TranslationBlock *tb1;
413 for(;;) {
414 tb1 = *ptb;
415 if (tb1 == tb) {
416 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
417 break;
418 }
419 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
420 }
421}
422
bellard9fa3e852004-01-04 18:06:42 +0000423static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
424{
425 TranslationBlock *tb1;
426 unsigned int n1;
427
428 for(;;) {
429 tb1 = *ptb;
430 n1 = (long)tb1 & 3;
431 tb1 = (TranslationBlock *)((long)tb1 & ~3);
432 if (tb1 == tb) {
433 *ptb = tb1->page_next[n1];
434 break;
435 }
436 ptb = &tb1->page_next[n1];
437 }
438}
439
bellardd4e81642003-05-25 16:46:15 +0000440static inline void tb_jmp_remove(TranslationBlock *tb, int n)
441{
442 TranslationBlock *tb1, **ptb;
443 unsigned int n1;
444
445 ptb = &tb->jmp_next[n];
446 tb1 = *ptb;
447 if (tb1) {
448 /* find tb(n) in circular list */
449 for(;;) {
450 tb1 = *ptb;
451 n1 = (long)tb1 & 3;
452 tb1 = (TranslationBlock *)((long)tb1 & ~3);
453 if (n1 == n && tb1 == tb)
454 break;
455 if (n1 == 2) {
456 ptb = &tb1->jmp_first;
457 } else {
458 ptb = &tb1->jmp_next[n1];
459 }
460 }
461 /* now we can suppress tb(n) from the list */
462 *ptb = tb->jmp_next[n];
463
464 tb->jmp_next[n] = NULL;
465 }
466}
467
468/* reset the jump entry 'n' of a TB so that it is not chained to
469 another TB */
470static inline void tb_reset_jump(TranslationBlock *tb, int n)
471{
472 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
473}
474
bellard9fa3e852004-01-04 18:06:42 +0000475static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000476{
bellard6a00d602005-11-21 23:25:50 +0000477 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000478 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000479 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000480 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000481 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000482
483 /* remove the TB from the hash list */
484 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
485 h = tb_phys_hash_func(phys_pc);
486 tb_remove(&tb_phys_hash[h], tb,
487 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000488
bellard9fa3e852004-01-04 18:06:42 +0000489 /* remove the TB from the page list */
490 if (tb->page_addr[0] != page_addr) {
491 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
492 tb_page_remove(&p->first_tb, tb);
493 invalidate_page_bitmap(p);
494 }
495 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
496 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
497 tb_page_remove(&p->first_tb, tb);
498 invalidate_page_bitmap(p);
499 }
500
bellard8a40a182005-11-20 10:35:40 +0000501 tb_invalidated_flag = 1;
502
503 /* remove the TB from the hash list */
504 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000505 for(env = first_cpu; env != NULL; env = env->next_cpu) {
506 if (env->tb_jmp_cache[h] == tb)
507 env->tb_jmp_cache[h] = NULL;
508 }
bellard8a40a182005-11-20 10:35:40 +0000509
510 /* suppress this TB from the two jump lists */
511 tb_jmp_remove(tb, 0);
512 tb_jmp_remove(tb, 1);
513
514 /* suppress any remaining jumps to this TB */
515 tb1 = tb->jmp_first;
516 for(;;) {
517 n1 = (long)tb1 & 3;
518 if (n1 == 2)
519 break;
520 tb1 = (TranslationBlock *)((long)tb1 & ~3);
521 tb2 = tb1->jmp_next[n1];
522 tb_reset_jump(tb1, n1);
523 tb1->jmp_next[n1] = NULL;
524 tb1 = tb2;
525 }
526 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
527
bellarde3db7222005-01-26 22:00:47 +0000528 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000529}
530
531static inline void set_bits(uint8_t *tab, int start, int len)
532{
533 int end, mask, end1;
534
535 end = start + len;
536 tab += start >> 3;
537 mask = 0xff << (start & 7);
538 if ((start & ~7) == (end & ~7)) {
539 if (start < end) {
540 mask &= ~(0xff << (end & 7));
541 *tab |= mask;
542 }
543 } else {
544 *tab++ |= mask;
545 start = (start + 8) & ~7;
546 end1 = end & ~7;
547 while (start < end1) {
548 *tab++ = 0xff;
549 start += 8;
550 }
551 if (start < end) {
552 mask = ~(0xff << (end & 7));
553 *tab |= mask;
554 }
555 }
556}
557
558static void build_page_bitmap(PageDesc *p)
559{
560 int n, tb_start, tb_end;
561 TranslationBlock *tb;
562
bellard59817cc2004-02-16 22:01:13 +0000563 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000564 if (!p->code_bitmap)
565 return;
566 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
567
568 tb = p->first_tb;
569 while (tb != NULL) {
570 n = (long)tb & 3;
571 tb = (TranslationBlock *)((long)tb & ~3);
572 /* NOTE: this is subtle as a TB may span two physical pages */
573 if (n == 0) {
574 /* NOTE: tb_end may be after the end of the page, but
575 it is not a problem */
576 tb_start = tb->pc & ~TARGET_PAGE_MASK;
577 tb_end = tb_start + tb->size;
578 if (tb_end > TARGET_PAGE_SIZE)
579 tb_end = TARGET_PAGE_SIZE;
580 } else {
581 tb_start = 0;
582 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
583 }
584 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
585 tb = tb->page_next[n];
586 }
587}
588
bellardd720b932004-04-25 17:57:43 +0000589#ifdef TARGET_HAS_PRECISE_SMC
590
591static void tb_gen_code(CPUState *env,
592 target_ulong pc, target_ulong cs_base, int flags,
593 int cflags)
594{
595 TranslationBlock *tb;
596 uint8_t *tc_ptr;
597 target_ulong phys_pc, phys_page2, virt_page2;
598 int code_gen_size;
599
bellardc27004e2005-01-03 23:35:10 +0000600 phys_pc = get_phys_addr_code(env, pc);
601 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000602 if (!tb) {
603 /* flush must be done */
604 tb_flush(env);
605 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000606 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000607 }
608 tc_ptr = code_gen_ptr;
609 tb->tc_ptr = tc_ptr;
610 tb->cs_base = cs_base;
611 tb->flags = flags;
612 tb->cflags = cflags;
613 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
614 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
615
616 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000617 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000618 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000619 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000620 phys_page2 = get_phys_addr_code(env, virt_page2);
621 }
622 tb_link_phys(tb, phys_pc, phys_page2);
623}
624#endif
625
bellard9fa3e852004-01-04 18:06:42 +0000626/* invalidate all TBs which intersect with the target physical page
627 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000628 the same physical page. 'is_cpu_write_access' should be true if called
629 from a real cpu write access: the virtual CPU will exit the current
630 TB if code is modified inside this TB. */
631void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
632 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000633{
bellardd720b932004-04-25 17:57:43 +0000634 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000635 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000636 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000637 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000638 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000639 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000640
641 p = page_find(start >> TARGET_PAGE_BITS);
642 if (!p)
643 return;
644 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000645 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
646 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000647 /* build code bitmap */
648 build_page_bitmap(p);
649 }
650
651 /* we remove all the TBs in the range [start, end[ */
652 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000653 current_tb_not_found = is_cpu_write_access;
654 current_tb_modified = 0;
655 current_tb = NULL; /* avoid warning */
656 current_pc = 0; /* avoid warning */
657 current_cs_base = 0; /* avoid warning */
658 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000659 tb = p->first_tb;
660 while (tb != NULL) {
661 n = (long)tb & 3;
662 tb = (TranslationBlock *)((long)tb & ~3);
663 tb_next = tb->page_next[n];
664 /* NOTE: this is subtle as a TB may span two physical pages */
665 if (n == 0) {
666 /* NOTE: tb_end may be after the end of the page, but
667 it is not a problem */
668 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
669 tb_end = tb_start + tb->size;
670 } else {
671 tb_start = tb->page_addr[1];
672 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
673 }
674 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000675#ifdef TARGET_HAS_PRECISE_SMC
676 if (current_tb_not_found) {
677 current_tb_not_found = 0;
678 current_tb = NULL;
679 if (env->mem_write_pc) {
680 /* now we have a real cpu fault */
681 current_tb = tb_find_pc(env->mem_write_pc);
682 }
683 }
684 if (current_tb == tb &&
685 !(current_tb->cflags & CF_SINGLE_INSN)) {
686 /* If we are modifying the current TB, we must stop
687 its execution. We could be more precise by checking
688 that the modification is after the current PC, but it
689 would require a specialized function to partially
690 restore the CPU state */
691
692 current_tb_modified = 1;
693 cpu_restore_state(current_tb, env,
694 env->mem_write_pc, NULL);
695#if defined(TARGET_I386)
696 current_flags = env->hflags;
697 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
698 current_cs_base = (target_ulong)env->segs[R_CS].base;
699 current_pc = current_cs_base + env->eip;
700#else
701#error unsupported CPU
702#endif
703 }
704#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000705 /* we need to do that to handle the case where a signal
706 occurs while doing tb_phys_invalidate() */
707 saved_tb = NULL;
708 if (env) {
709 saved_tb = env->current_tb;
710 env->current_tb = NULL;
711 }
bellard9fa3e852004-01-04 18:06:42 +0000712 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000713 if (env) {
714 env->current_tb = saved_tb;
715 if (env->interrupt_request && env->current_tb)
716 cpu_interrupt(env, env->interrupt_request);
717 }
bellard9fa3e852004-01-04 18:06:42 +0000718 }
719 tb = tb_next;
720 }
721#if !defined(CONFIG_USER_ONLY)
722 /* if no code remaining, no need to continue to use slow writes */
723 if (!p->first_tb) {
724 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000725 if (is_cpu_write_access) {
726 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
727 }
728 }
729#endif
730#ifdef TARGET_HAS_PRECISE_SMC
731 if (current_tb_modified) {
732 /* we generate a block containing just the instruction
733 modifying the memory. It will ensure that it cannot modify
734 itself */
bellardea1c1802004-06-14 18:56:36 +0000735 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000736 tb_gen_code(env, current_pc, current_cs_base, current_flags,
737 CF_SINGLE_INSN);
738 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000739 }
740#endif
741}
742
743/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000744static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000745{
746 PageDesc *p;
747 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000748#if 0
bellarda4193c82004-06-03 14:01:43 +0000749 if (1) {
750 if (loglevel) {
751 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
752 cpu_single_env->mem_write_vaddr, len,
753 cpu_single_env->eip,
754 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
755 }
bellard59817cc2004-02-16 22:01:13 +0000756 }
757#endif
bellard9fa3e852004-01-04 18:06:42 +0000758 p = page_find(start >> TARGET_PAGE_BITS);
759 if (!p)
760 return;
761 if (p->code_bitmap) {
762 offset = start & ~TARGET_PAGE_MASK;
763 b = p->code_bitmap[offset >> 3] >> (offset & 7);
764 if (b & ((1 << len) - 1))
765 goto do_invalidate;
766 } else {
767 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000768 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000769 }
770}
771
bellard9fa3e852004-01-04 18:06:42 +0000772#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000773static void tb_invalidate_phys_page(target_ulong addr,
774 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000775{
bellardd720b932004-04-25 17:57:43 +0000776 int n, current_flags, current_tb_modified;
777 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000778 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000779 TranslationBlock *tb, *current_tb;
780#ifdef TARGET_HAS_PRECISE_SMC
781 CPUState *env = cpu_single_env;
782#endif
bellard9fa3e852004-01-04 18:06:42 +0000783
784 addr &= TARGET_PAGE_MASK;
785 p = page_find(addr >> TARGET_PAGE_BITS);
786 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000787 return;
788 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000789 current_tb_modified = 0;
790 current_tb = NULL;
791 current_pc = 0; /* avoid warning */
792 current_cs_base = 0; /* avoid warning */
793 current_flags = 0; /* avoid warning */
794#ifdef TARGET_HAS_PRECISE_SMC
795 if (tb && pc != 0) {
796 current_tb = tb_find_pc(pc);
797 }
798#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000799 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000800 n = (long)tb & 3;
801 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000802#ifdef TARGET_HAS_PRECISE_SMC
803 if (current_tb == tb &&
804 !(current_tb->cflags & CF_SINGLE_INSN)) {
805 /* If we are modifying the current TB, we must stop
806 its execution. We could be more precise by checking
807 that the modification is after the current PC, but it
808 would require a specialized function to partially
809 restore the CPU state */
810
811 current_tb_modified = 1;
812 cpu_restore_state(current_tb, env, pc, puc);
813#if defined(TARGET_I386)
814 current_flags = env->hflags;
815 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
816 current_cs_base = (target_ulong)env->segs[R_CS].base;
817 current_pc = current_cs_base + env->eip;
818#else
819#error unsupported CPU
820#endif
821 }
822#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000823 tb_phys_invalidate(tb, addr);
824 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000825 }
826 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000827#ifdef TARGET_HAS_PRECISE_SMC
828 if (current_tb_modified) {
829 /* we generate a block containing just the instruction
830 modifying the memory. It will ensure that it cannot modify
831 itself */
bellardea1c1802004-06-14 18:56:36 +0000832 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000833 tb_gen_code(env, current_pc, current_cs_base, current_flags,
834 CF_SINGLE_INSN);
835 cpu_resume_from_signal(env, puc);
836 }
837#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000838}
bellard9fa3e852004-01-04 18:06:42 +0000839#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000840
841/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000842static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000843 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000844{
845 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000846 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000847
bellard9fa3e852004-01-04 18:06:42 +0000848 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000849 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000850 tb->page_next[n] = p->first_tb;
851 last_first_tb = p->first_tb;
852 p->first_tb = (TranslationBlock *)((long)tb | n);
853 invalidate_page_bitmap(p);
854
bellard107db442004-06-22 18:48:46 +0000855#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000856
bellard9fa3e852004-01-04 18:06:42 +0000857#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000858 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000859 target_ulong addr;
860 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000861 int prot;
862
bellardfd6ce8f2003-05-14 19:00:11 +0000863 /* force the host page as non writable (writes will have a
864 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000865 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000866 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000867 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
868 addr += TARGET_PAGE_SIZE) {
869
870 p2 = page_find (addr >> TARGET_PAGE_BITS);
871 if (!p2)
872 continue;
873 prot |= p2->flags;
874 p2->flags &= ~PAGE_WRITE;
875 page_get_flags(addr);
876 }
877 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000878 (prot & PAGE_BITS) & ~PAGE_WRITE);
879#ifdef DEBUG_TB_INVALIDATE
880 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000881 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000882#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000883 }
bellard9fa3e852004-01-04 18:06:42 +0000884#else
885 /* if some code is already present, then the pages are already
886 protected. So we handle the case where only the first TB is
887 allocated in a physical page */
888 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000889 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000890 }
891#endif
bellardd720b932004-04-25 17:57:43 +0000892
893#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000894}
895
896/* Allocate a new translation block. Flush the translation buffer if
897 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000898TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000899{
900 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000901
902 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
903 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000904 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000905 tb = &tbs[nb_tbs++];
906 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000907 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000908 return tb;
909}
910
bellard9fa3e852004-01-04 18:06:42 +0000911/* add a new TB and link it to the physical page tables. phys_page2 is
912 (-1) to indicate that only one page contains the TB. */
913void tb_link_phys(TranslationBlock *tb,
914 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000915{
bellard9fa3e852004-01-04 18:06:42 +0000916 unsigned int h;
917 TranslationBlock **ptb;
918
919 /* add in the physical hash table */
920 h = tb_phys_hash_func(phys_pc);
921 ptb = &tb_phys_hash[h];
922 tb->phys_hash_next = *ptb;
923 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000924
925 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000926 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
927 if (phys_page2 != -1)
928 tb_alloc_page(tb, 1, phys_page2);
929 else
930 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000931
bellardd4e81642003-05-25 16:46:15 +0000932 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
933 tb->jmp_next[0] = NULL;
934 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000935#ifdef USE_CODE_COPY
936 tb->cflags &= ~CF_FP_USED;
937 if (tb->cflags & CF_TB_FP_USED)
938 tb->cflags |= CF_FP_USED;
939#endif
bellardd4e81642003-05-25 16:46:15 +0000940
941 /* init original jump addresses */
942 if (tb->tb_next_offset[0] != 0xffff)
943 tb_reset_jump(tb, 0);
944 if (tb->tb_next_offset[1] != 0xffff)
945 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000946
947#ifdef DEBUG_TB_CHECK
948 tb_page_check();
949#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000950}
951
bellarda513fe12003-05-27 23:29:48 +0000952/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
953 tb[1].tc_ptr. Return NULL if not found */
954TranslationBlock *tb_find_pc(unsigned long tc_ptr)
955{
956 int m_min, m_max, m;
957 unsigned long v;
958 TranslationBlock *tb;
959
960 if (nb_tbs <= 0)
961 return NULL;
962 if (tc_ptr < (unsigned long)code_gen_buffer ||
963 tc_ptr >= (unsigned long)code_gen_ptr)
964 return NULL;
965 /* binary search (cf Knuth) */
966 m_min = 0;
967 m_max = nb_tbs - 1;
968 while (m_min <= m_max) {
969 m = (m_min + m_max) >> 1;
970 tb = &tbs[m];
971 v = (unsigned long)tb->tc_ptr;
972 if (v == tc_ptr)
973 return tb;
974 else if (tc_ptr < v) {
975 m_max = m - 1;
976 } else {
977 m_min = m + 1;
978 }
979 }
980 return &tbs[m_max];
981}
bellard75012672003-06-21 13:11:07 +0000982
bellardea041c02003-06-25 16:16:50 +0000983static void tb_reset_jump_recursive(TranslationBlock *tb);
984
985static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
986{
987 TranslationBlock *tb1, *tb_next, **ptb;
988 unsigned int n1;
989
990 tb1 = tb->jmp_next[n];
991 if (tb1 != NULL) {
992 /* find head of list */
993 for(;;) {
994 n1 = (long)tb1 & 3;
995 tb1 = (TranslationBlock *)((long)tb1 & ~3);
996 if (n1 == 2)
997 break;
998 tb1 = tb1->jmp_next[n1];
999 }
1000 /* we are now sure now that tb jumps to tb1 */
1001 tb_next = tb1;
1002
1003 /* remove tb from the jmp_first list */
1004 ptb = &tb_next->jmp_first;
1005 for(;;) {
1006 tb1 = *ptb;
1007 n1 = (long)tb1 & 3;
1008 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1009 if (n1 == n && tb1 == tb)
1010 break;
1011 ptb = &tb1->jmp_next[n1];
1012 }
1013 *ptb = tb->jmp_next[n];
1014 tb->jmp_next[n] = NULL;
1015
1016 /* suppress the jump to next tb in generated code */
1017 tb_reset_jump(tb, n);
1018
bellard01243112004-01-04 15:48:17 +00001019 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001020 tb_reset_jump_recursive(tb_next);
1021 }
1022}
1023
1024static void tb_reset_jump_recursive(TranslationBlock *tb)
1025{
1026 tb_reset_jump_recursive2(tb, 0);
1027 tb_reset_jump_recursive2(tb, 1);
1028}
1029
bellard1fddef42005-04-17 19:16:13 +00001030#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001031static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1032{
j_mayer9b3c35e2007-04-07 11:21:28 +00001033 target_phys_addr_t addr;
1034 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001035 ram_addr_t ram_addr;
1036 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001037
pbrookc2f07f82006-04-08 17:14:56 +00001038 addr = cpu_get_phys_page_debug(env, pc);
1039 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1040 if (!p) {
1041 pd = IO_MEM_UNASSIGNED;
1042 } else {
1043 pd = p->phys_offset;
1044 }
1045 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001046 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001047}
bellardc27004e2005-01-03 23:35:10 +00001048#endif
bellardd720b932004-04-25 17:57:43 +00001049
pbrook6658ffb2007-03-16 23:58:11 +00001050/* Add a watchpoint. */
1051int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1052{
1053 int i;
1054
1055 for (i = 0; i < env->nb_watchpoints; i++) {
1056 if (addr == env->watchpoint[i].vaddr)
1057 return 0;
1058 }
1059 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1060 return -1;
1061
1062 i = env->nb_watchpoints++;
1063 env->watchpoint[i].vaddr = addr;
1064 tlb_flush_page(env, addr);
1065 /* FIXME: This flush is needed because of the hack to make memory ops
1066 terminate the TB. It can be removed once the proper IO trap and
1067 re-execute bits are in. */
1068 tb_flush(env);
1069 return i;
1070}
1071
1072/* Remove a watchpoint. */
1073int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1074{
1075 int i;
1076
1077 for (i = 0; i < env->nb_watchpoints; i++) {
1078 if (addr == env->watchpoint[i].vaddr) {
1079 env->nb_watchpoints--;
1080 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1081 tlb_flush_page(env, addr);
1082 return 0;
1083 }
1084 }
1085 return -1;
1086}
1087
bellardc33a3462003-07-29 20:50:33 +00001088/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1089 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001090int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001091{
bellard1fddef42005-04-17 19:16:13 +00001092#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001093 int i;
bellardd720b932004-04-25 17:57:43 +00001094
bellard4c3a88a2003-07-26 12:06:08 +00001095 for(i = 0; i < env->nb_breakpoints; i++) {
1096 if (env->breakpoints[i] == pc)
1097 return 0;
1098 }
1099
1100 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1101 return -1;
1102 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001103
1104 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001105 return 0;
1106#else
1107 return -1;
1108#endif
1109}
1110
1111/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001112int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001113{
bellard1fddef42005-04-17 19:16:13 +00001114#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001115 int i;
1116 for(i = 0; i < env->nb_breakpoints; i++) {
1117 if (env->breakpoints[i] == pc)
1118 goto found;
1119 }
1120 return -1;
1121 found:
bellard4c3a88a2003-07-26 12:06:08 +00001122 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001123 if (i < env->nb_breakpoints)
1124 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001125
1126 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001127 return 0;
1128#else
1129 return -1;
1130#endif
1131}
1132
bellardc33a3462003-07-29 20:50:33 +00001133/* enable or disable single step mode. EXCP_DEBUG is returned by the
1134 CPU loop after each instruction */
1135void cpu_single_step(CPUState *env, int enabled)
1136{
bellard1fddef42005-04-17 19:16:13 +00001137#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001138 if (env->singlestep_enabled != enabled) {
1139 env->singlestep_enabled = enabled;
1140 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001141 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001142 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001143 }
1144#endif
1145}
1146
bellard34865132003-10-05 14:28:56 +00001147/* enable or disable low levels log */
1148void cpu_set_log(int log_flags)
1149{
1150 loglevel = log_flags;
1151 if (loglevel && !logfile) {
1152 logfile = fopen(logfilename, "w");
1153 if (!logfile) {
1154 perror(logfilename);
1155 _exit(1);
1156 }
bellard9fa3e852004-01-04 18:06:42 +00001157#if !defined(CONFIG_SOFTMMU)
1158 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1159 {
1160 static uint8_t logfile_buf[4096];
1161 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1162 }
1163#else
bellard34865132003-10-05 14:28:56 +00001164 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001165#endif
bellard34865132003-10-05 14:28:56 +00001166 }
1167}
1168
1169void cpu_set_log_filename(const char *filename)
1170{
1171 logfilename = strdup(filename);
1172}
bellardc33a3462003-07-29 20:50:33 +00001173
bellard01243112004-01-04 15:48:17 +00001174/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001175void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001176{
1177 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001178 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001179
bellard68a79312003-06-30 13:12:32 +00001180 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001181 /* if the cpu is currently executing code, we must unlink it and
1182 all the potentially executing TB */
1183 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001184 if (tb && !testandset(&interrupt_lock)) {
1185 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001186 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001187 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001188 }
1189}
1190
bellardb54ad042004-05-20 13:42:52 +00001191void cpu_reset_interrupt(CPUState *env, int mask)
1192{
1193 env->interrupt_request &= ~mask;
1194}
1195
bellardf193c792004-03-21 17:06:25 +00001196CPULogItem cpu_log_items[] = {
1197 { CPU_LOG_TB_OUT_ASM, "out_asm",
1198 "show generated host assembly code for each compiled TB" },
1199 { CPU_LOG_TB_IN_ASM, "in_asm",
1200 "show target assembly code for each compiled TB" },
1201 { CPU_LOG_TB_OP, "op",
1202 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1203#ifdef TARGET_I386
1204 { CPU_LOG_TB_OP_OPT, "op_opt",
1205 "show micro ops after optimization for each compiled TB" },
1206#endif
1207 { CPU_LOG_INT, "int",
1208 "show interrupts/exceptions in short format" },
1209 { CPU_LOG_EXEC, "exec",
1210 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001211 { CPU_LOG_TB_CPU, "cpu",
1212 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001213#ifdef TARGET_I386
1214 { CPU_LOG_PCALL, "pcall",
1215 "show protected mode far calls/returns/exceptions" },
1216#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001217#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001218 { CPU_LOG_IOPORT, "ioport",
1219 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001220#endif
bellardf193c792004-03-21 17:06:25 +00001221 { 0, NULL, NULL },
1222};
1223
1224static int cmp1(const char *s1, int n, const char *s2)
1225{
1226 if (strlen(s2) != n)
1227 return 0;
1228 return memcmp(s1, s2, n) == 0;
1229}
1230
1231/* takes a comma separated list of log masks. Return 0 if error. */
1232int cpu_str_to_log_mask(const char *str)
1233{
1234 CPULogItem *item;
1235 int mask;
1236 const char *p, *p1;
1237
1238 p = str;
1239 mask = 0;
1240 for(;;) {
1241 p1 = strchr(p, ',');
1242 if (!p1)
1243 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001244 if(cmp1(p,p1-p,"all")) {
1245 for(item = cpu_log_items; item->mask != 0; item++) {
1246 mask |= item->mask;
1247 }
1248 } else {
bellardf193c792004-03-21 17:06:25 +00001249 for(item = cpu_log_items; item->mask != 0; item++) {
1250 if (cmp1(p, p1 - p, item->name))
1251 goto found;
1252 }
1253 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001254 }
bellardf193c792004-03-21 17:06:25 +00001255 found:
1256 mask |= item->mask;
1257 if (*p1 != ',')
1258 break;
1259 p = p1 + 1;
1260 }
1261 return mask;
1262}
bellardea041c02003-06-25 16:16:50 +00001263
bellard75012672003-06-21 13:11:07 +00001264void cpu_abort(CPUState *env, const char *fmt, ...)
1265{
1266 va_list ap;
1267
1268 va_start(ap, fmt);
1269 fprintf(stderr, "qemu: fatal: ");
1270 vfprintf(stderr, fmt, ap);
1271 fprintf(stderr, "\n");
1272#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001273 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1274#else
1275 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001276#endif
1277 va_end(ap);
1278 abort();
1279}
1280
thsc5be9f02007-02-28 20:20:53 +00001281CPUState *cpu_copy(CPUState *env)
1282{
1283 CPUState *new_env = cpu_init();
1284 /* preserve chaining and index */
1285 CPUState *next_cpu = new_env->next_cpu;
1286 int cpu_index = new_env->cpu_index;
1287 memcpy(new_env, env, sizeof(CPUState));
1288 new_env->next_cpu = next_cpu;
1289 new_env->cpu_index = cpu_index;
1290 return new_env;
1291}
1292
bellard01243112004-01-04 15:48:17 +00001293#if !defined(CONFIG_USER_ONLY)
1294
bellardee8b7022004-02-03 23:35:10 +00001295/* NOTE: if flush_global is true, also flush global entries (not
1296 implemented yet) */
1297void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001298{
bellard33417e72003-08-10 21:47:01 +00001299 int i;
bellard01243112004-01-04 15:48:17 +00001300
bellard9fa3e852004-01-04 18:06:42 +00001301#if defined(DEBUG_TLB)
1302 printf("tlb_flush:\n");
1303#endif
bellard01243112004-01-04 15:48:17 +00001304 /* must reset current TB so that interrupts cannot modify the
1305 links while we are modifying them */
1306 env->current_tb = NULL;
1307
bellard33417e72003-08-10 21:47:01 +00001308 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001309 env->tlb_table[0][i].addr_read = -1;
1310 env->tlb_table[0][i].addr_write = -1;
1311 env->tlb_table[0][i].addr_code = -1;
1312 env->tlb_table[1][i].addr_read = -1;
1313 env->tlb_table[1][i].addr_write = -1;
1314 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001315#if (NB_MMU_MODES >= 3)
1316 env->tlb_table[2][i].addr_read = -1;
1317 env->tlb_table[2][i].addr_write = -1;
1318 env->tlb_table[2][i].addr_code = -1;
1319#if (NB_MMU_MODES == 4)
1320 env->tlb_table[3][i].addr_read = -1;
1321 env->tlb_table[3][i].addr_write = -1;
1322 env->tlb_table[3][i].addr_code = -1;
1323#endif
1324#endif
bellard33417e72003-08-10 21:47:01 +00001325 }
bellard9fa3e852004-01-04 18:06:42 +00001326
bellard8a40a182005-11-20 10:35:40 +00001327 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001328
1329#if !defined(CONFIG_SOFTMMU)
1330 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1331#endif
bellard0a962c02005-02-10 22:00:27 +00001332#ifdef USE_KQEMU
1333 if (env->kqemu_enabled) {
1334 kqemu_flush(env, flush_global);
1335 }
1336#endif
bellarde3db7222005-01-26 22:00:47 +00001337 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001338}
1339
bellard274da6b2004-05-20 21:56:27 +00001340static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001341{
bellard84b7b8e2005-11-28 21:19:04 +00001342 if (addr == (tlb_entry->addr_read &
1343 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1344 addr == (tlb_entry->addr_write &
1345 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1346 addr == (tlb_entry->addr_code &
1347 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1348 tlb_entry->addr_read = -1;
1349 tlb_entry->addr_write = -1;
1350 tlb_entry->addr_code = -1;
1351 }
bellard61382a52003-10-27 21:22:23 +00001352}
1353
bellard2e126692004-04-25 21:28:44 +00001354void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001355{
bellard8a40a182005-11-20 10:35:40 +00001356 int i;
bellard9fa3e852004-01-04 18:06:42 +00001357 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001358
bellard9fa3e852004-01-04 18:06:42 +00001359#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001360 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001361#endif
bellard01243112004-01-04 15:48:17 +00001362 /* must reset current TB so that interrupts cannot modify the
1363 links while we are modifying them */
1364 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001365
bellard61382a52003-10-27 21:22:23 +00001366 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001367 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001368 tlb_flush_entry(&env->tlb_table[0][i], addr);
1369 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001370#if (NB_MMU_MODES >= 3)
1371 tlb_flush_entry(&env->tlb_table[2][i], addr);
1372#if (NB_MMU_MODES == 4)
1373 tlb_flush_entry(&env->tlb_table[3][i], addr);
1374#endif
1375#endif
bellard01243112004-01-04 15:48:17 +00001376
pbrookb362e5e2006-11-12 20:40:55 +00001377 /* Discard jump cache entries for any tb which might potentially
1378 overlap the flushed page. */
1379 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1380 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1381
1382 i = tb_jmp_cache_hash_page(addr);
1383 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001384
bellard01243112004-01-04 15:48:17 +00001385#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001386 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001387 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001388#endif
bellard0a962c02005-02-10 22:00:27 +00001389#ifdef USE_KQEMU
1390 if (env->kqemu_enabled) {
1391 kqemu_flush_page(env, addr);
1392 }
1393#endif
bellard9fa3e852004-01-04 18:06:42 +00001394}
1395
bellard9fa3e852004-01-04 18:06:42 +00001396/* update the TLBs so that writes to code in the virtual page 'addr'
1397 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001398static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001399{
bellard6a00d602005-11-21 23:25:50 +00001400 cpu_physical_memory_reset_dirty(ram_addr,
1401 ram_addr + TARGET_PAGE_SIZE,
1402 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001403}
1404
bellard9fa3e852004-01-04 18:06:42 +00001405/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001406 tested for self modifying code */
1407static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1408 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001409{
bellard3a7d9292005-08-21 09:26:42 +00001410 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001411}
1412
1413static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1414 unsigned long start, unsigned long length)
1415{
1416 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001417 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1418 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001419 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001420 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001421 }
1422 }
1423}
1424
bellard3a7d9292005-08-21 09:26:42 +00001425void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001426 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001427{
1428 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001429 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001430 int i, mask, len;
1431 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001432
1433 start &= TARGET_PAGE_MASK;
1434 end = TARGET_PAGE_ALIGN(end);
1435
1436 length = end - start;
1437 if (length == 0)
1438 return;
bellard0a962c02005-02-10 22:00:27 +00001439 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001440#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001441 /* XXX: should not depend on cpu context */
1442 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001443 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001444 ram_addr_t addr;
1445 addr = start;
1446 for(i = 0; i < len; i++) {
1447 kqemu_set_notdirty(env, addr);
1448 addr += TARGET_PAGE_SIZE;
1449 }
bellard3a7d9292005-08-21 09:26:42 +00001450 }
1451#endif
bellardf23db162005-08-21 19:12:28 +00001452 mask = ~dirty_flags;
1453 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1454 for(i = 0; i < len; i++)
1455 p[i] &= mask;
1456
bellard1ccde1c2004-02-06 19:46:14 +00001457 /* we modify the TLB cache so that the dirty bit will be set again
1458 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001459 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001460 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1461 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001462 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001463 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001464 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001465#if (NB_MMU_MODES >= 3)
1466 for(i = 0; i < CPU_TLB_SIZE; i++)
1467 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1468#if (NB_MMU_MODES == 4)
1469 for(i = 0; i < CPU_TLB_SIZE; i++)
1470 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1471#endif
1472#endif
bellard6a00d602005-11-21 23:25:50 +00001473 }
bellard59817cc2004-02-16 22:01:13 +00001474
1475#if !defined(CONFIG_SOFTMMU)
1476 /* XXX: this is expensive */
1477 {
1478 VirtPageDesc *p;
1479 int j;
1480 target_ulong addr;
1481
1482 for(i = 0; i < L1_SIZE; i++) {
1483 p = l1_virt_map[i];
1484 if (p) {
1485 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1486 for(j = 0; j < L2_SIZE; j++) {
1487 if (p->valid_tag == virt_valid_tag &&
1488 p->phys_addr >= start && p->phys_addr < end &&
1489 (p->prot & PROT_WRITE)) {
1490 if (addr < MMAP_AREA_END) {
1491 mprotect((void *)addr, TARGET_PAGE_SIZE,
1492 p->prot & ~PROT_WRITE);
1493 }
1494 }
1495 addr += TARGET_PAGE_SIZE;
1496 p++;
1497 }
1498 }
1499 }
1500 }
1501#endif
bellard1ccde1c2004-02-06 19:46:14 +00001502}
1503
bellard3a7d9292005-08-21 09:26:42 +00001504static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1505{
1506 ram_addr_t ram_addr;
1507
bellard84b7b8e2005-11-28 21:19:04 +00001508 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1509 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001510 tlb_entry->addend - (unsigned long)phys_ram_base;
1511 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001512 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001513 }
1514 }
1515}
1516
1517/* update the TLB according to the current state of the dirty bits */
1518void cpu_tlb_update_dirty(CPUState *env)
1519{
1520 int i;
1521 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001522 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001523 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001524 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001525#if (NB_MMU_MODES >= 3)
1526 for(i = 0; i < CPU_TLB_SIZE; i++)
1527 tlb_update_dirty(&env->tlb_table[2][i]);
1528#if (NB_MMU_MODES == 4)
1529 for(i = 0; i < CPU_TLB_SIZE; i++)
1530 tlb_update_dirty(&env->tlb_table[3][i]);
1531#endif
1532#endif
bellard3a7d9292005-08-21 09:26:42 +00001533}
1534
bellard1ccde1c2004-02-06 19:46:14 +00001535static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001536 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001537{
1538 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001539 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1540 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001541 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001542 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001543 }
1544 }
1545}
1546
1547/* update the TLB corresponding to virtual page vaddr and phys addr
1548 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001549static inline void tlb_set_dirty(CPUState *env,
1550 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001551{
bellard1ccde1c2004-02-06 19:46:14 +00001552 int i;
1553
bellard1ccde1c2004-02-06 19:46:14 +00001554 addr &= TARGET_PAGE_MASK;
1555 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001556 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1557 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001558#if (NB_MMU_MODES >= 3)
1559 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1560#if (NB_MMU_MODES == 4)
1561 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1562#endif
1563#endif
bellard9fa3e852004-01-04 18:06:42 +00001564}
1565
bellard59817cc2004-02-16 22:01:13 +00001566/* add a new TLB entry. At most one entry for a given virtual address
1567 is permitted. Return 0 if OK or 2 if the page could not be mapped
1568 (can only happen in non SOFTMMU mode for I/O pages or pages
1569 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001570int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1571 target_phys_addr_t paddr, int prot,
1572 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001573{
bellard92e873b2004-05-21 14:52:29 +00001574 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001575 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001576 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001577 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001578 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001579 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001580 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001581 int i;
bellard9fa3e852004-01-04 18:06:42 +00001582
bellard92e873b2004-05-21 14:52:29 +00001583 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001584 if (!p) {
1585 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001586 } else {
1587 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001588 }
1589#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001590 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
bellard84b7b8e2005-11-28 21:19:04 +00001591 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001592#endif
1593
1594 ret = 0;
1595#if !defined(CONFIG_SOFTMMU)
1596 if (is_softmmu)
1597#endif
1598 {
bellard2a4188a2006-06-25 21:54:59 +00001599 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001600 /* IO memory case */
1601 address = vaddr | pd;
1602 addend = paddr;
1603 } else {
1604 /* standard memory */
1605 address = vaddr;
1606 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1607 }
pbrook6658ffb2007-03-16 23:58:11 +00001608
1609 /* Make accesses to pages with watchpoints go via the
1610 watchpoint trap routines. */
1611 for (i = 0; i < env->nb_watchpoints; i++) {
1612 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1613 if (address & ~TARGET_PAGE_MASK) {
1614 env->watchpoint[i].is_ram = 0;
1615 address = vaddr | io_mem_watch;
1616 } else {
1617 env->watchpoint[i].is_ram = 1;
1618 /* TODO: Figure out how to make read watchpoints coexist
1619 with code. */
1620 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1621 }
1622 }
1623 }
bellard9fa3e852004-01-04 18:06:42 +00001624
bellard90f18422005-07-24 10:17:31 +00001625 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001626 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001627 te = &env->tlb_table[is_user][index];
1628 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001629 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001630 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001631 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001632 te->addr_read = -1;
1633 }
1634 if (prot & PAGE_EXEC) {
1635 te->addr_code = address;
1636 } else {
1637 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001638 }
bellard67b915a2004-03-31 23:37:16 +00001639 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001640 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1641 (pd & IO_MEM_ROMD)) {
1642 /* write access calls the I/O callback */
1643 te->addr_write = vaddr |
1644 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001645 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001646 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001647 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001648 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001649 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001650 }
1651 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001652 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001653 }
1654 }
1655#if !defined(CONFIG_SOFTMMU)
1656 else {
1657 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1658 /* IO access: no mapping is done as it will be handled by the
1659 soft MMU */
1660 if (!(env->hflags & HF_SOFTMMU_MASK))
1661 ret = 2;
1662 } else {
1663 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001664
bellard59817cc2004-02-16 22:01:13 +00001665 if (vaddr >= MMAP_AREA_END) {
1666 ret = 2;
1667 } else {
1668 if (prot & PROT_WRITE) {
1669 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001670#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001671 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001672#endif
bellard59817cc2004-02-16 22:01:13 +00001673 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1674 !cpu_physical_memory_is_dirty(pd))) {
1675 /* ROM: we do as if code was inside */
1676 /* if code is present, we only map as read only and save the
1677 original mapping */
1678 VirtPageDesc *vp;
1679
bellard90f18422005-07-24 10:17:31 +00001680 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001681 vp->phys_addr = pd;
1682 vp->prot = prot;
1683 vp->valid_tag = virt_valid_tag;
1684 prot &= ~PAGE_WRITE;
1685 }
bellard9fa3e852004-01-04 18:06:42 +00001686 }
bellard59817cc2004-02-16 22:01:13 +00001687 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1688 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1689 if (map_addr == MAP_FAILED) {
1690 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1691 paddr, vaddr);
1692 }
bellard9fa3e852004-01-04 18:06:42 +00001693 }
1694 }
1695 }
1696#endif
1697 return ret;
1698}
1699
1700/* called from signal handler: invalidate the code and unprotect the
1701 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001702int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001703{
1704#if !defined(CONFIG_SOFTMMU)
1705 VirtPageDesc *vp;
1706
1707#if defined(DEBUG_TLB)
1708 printf("page_unprotect: addr=0x%08x\n", addr);
1709#endif
1710 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001711
1712 /* if it is not mapped, no need to worry here */
1713 if (addr >= MMAP_AREA_END)
1714 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001715 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1716 if (!vp)
1717 return 0;
1718 /* NOTE: in this case, validate_tag is _not_ tested as it
1719 validates only the code TLB */
1720 if (vp->valid_tag != virt_valid_tag)
1721 return 0;
1722 if (!(vp->prot & PAGE_WRITE))
1723 return 0;
1724#if defined(DEBUG_TLB)
1725 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1726 addr, vp->phys_addr, vp->prot);
1727#endif
bellard59817cc2004-02-16 22:01:13 +00001728 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1729 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1730 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001731 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001732 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001733 /* flush the code inside */
1734 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001735 return 1;
1736#else
1737 return 0;
1738#endif
bellard33417e72003-08-10 21:47:01 +00001739}
1740
bellard01243112004-01-04 15:48:17 +00001741#else
1742
bellardee8b7022004-02-03 23:35:10 +00001743void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001744{
1745}
1746
bellard2e126692004-04-25 21:28:44 +00001747void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001748{
1749}
1750
bellard84b7b8e2005-11-28 21:19:04 +00001751int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1752 target_phys_addr_t paddr, int prot,
1753 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001754{
bellard9fa3e852004-01-04 18:06:42 +00001755 return 0;
1756}
bellard33417e72003-08-10 21:47:01 +00001757
bellard9fa3e852004-01-04 18:06:42 +00001758/* dump memory mappings */
1759void page_dump(FILE *f)
1760{
1761 unsigned long start, end;
1762 int i, j, prot, prot1;
1763 PageDesc *p;
1764
1765 fprintf(f, "%-8s %-8s %-8s %s\n",
1766 "start", "end", "size", "prot");
1767 start = -1;
1768 end = -1;
1769 prot = 0;
1770 for(i = 0; i <= L1_SIZE; i++) {
1771 if (i < L1_SIZE)
1772 p = l1_map[i];
1773 else
1774 p = NULL;
1775 for(j = 0;j < L2_SIZE; j++) {
1776 if (!p)
1777 prot1 = 0;
1778 else
1779 prot1 = p[j].flags;
1780 if (prot1 != prot) {
1781 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1782 if (start != -1) {
1783 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1784 start, end, end - start,
1785 prot & PAGE_READ ? 'r' : '-',
1786 prot & PAGE_WRITE ? 'w' : '-',
1787 prot & PAGE_EXEC ? 'x' : '-');
1788 }
1789 if (prot1 != 0)
1790 start = end;
1791 else
1792 start = -1;
1793 prot = prot1;
1794 }
1795 if (!p)
1796 break;
1797 }
bellard33417e72003-08-10 21:47:01 +00001798 }
bellard33417e72003-08-10 21:47:01 +00001799}
1800
pbrook53a59602006-03-25 19:31:22 +00001801int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001802{
bellard9fa3e852004-01-04 18:06:42 +00001803 PageDesc *p;
1804
1805 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001806 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001807 return 0;
1808 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001809}
1810
bellard9fa3e852004-01-04 18:06:42 +00001811/* modify the flags of a page and invalidate the code if
1812 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1813 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001814void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001815{
1816 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001817 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001818
1819 start = start & TARGET_PAGE_MASK;
1820 end = TARGET_PAGE_ALIGN(end);
1821 if (flags & PAGE_WRITE)
1822 flags |= PAGE_WRITE_ORG;
1823 spin_lock(&tb_lock);
1824 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1825 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1826 /* if the write protection is set, then we invalidate the code
1827 inside */
1828 if (!(p->flags & PAGE_WRITE) &&
1829 (flags & PAGE_WRITE) &&
1830 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001831 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001832 }
1833 p->flags = flags;
1834 }
1835 spin_unlock(&tb_lock);
1836}
1837
1838/* called from signal handler: invalidate the code and unprotect the
1839 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001840int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001841{
1842 unsigned int page_index, prot, pindex;
1843 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001844 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001845
bellard83fb7ad2004-07-05 21:25:26 +00001846 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001847 page_index = host_start >> TARGET_PAGE_BITS;
1848 p1 = page_find(page_index);
1849 if (!p1)
1850 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001851 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001852 p = p1;
1853 prot = 0;
1854 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1855 prot |= p->flags;
1856 p++;
1857 }
1858 /* if the page was really writable, then we change its
1859 protection back to writable */
1860 if (prot & PAGE_WRITE_ORG) {
1861 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1862 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001863 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001864 (prot & PAGE_BITS) | PAGE_WRITE);
1865 p1[pindex].flags |= PAGE_WRITE;
1866 /* and since the content will be modified, we must invalidate
1867 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001868 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001869#ifdef DEBUG_TB_CHECK
1870 tb_invalidate_check(address);
1871#endif
1872 return 1;
1873 }
1874 }
1875 return 0;
1876}
1877
1878/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001879/* ??? This should be redundant now we have lock_user. */
1880void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001881{
pbrook53a59602006-03-25 19:31:22 +00001882 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001883
pbrook53a59602006-03-25 19:31:22 +00001884 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001885 end = start + data_size;
1886 start &= TARGET_PAGE_MASK;
1887 end = TARGET_PAGE_ALIGN(end);
1888 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001889 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001890 }
1891}
1892
bellard6a00d602005-11-21 23:25:50 +00001893static inline void tlb_set_dirty(CPUState *env,
1894 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001895{
1896}
bellard9fa3e852004-01-04 18:06:42 +00001897#endif /* defined(CONFIG_USER_ONLY) */
1898
bellard33417e72003-08-10 21:47:01 +00001899/* register physical memory. 'size' must be a multiple of the target
1900 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1901 io memory page */
bellard2e126692004-04-25 21:28:44 +00001902void cpu_register_physical_memory(target_phys_addr_t start_addr,
1903 unsigned long size,
1904 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001905{
bellard108c49b2005-07-24 12:55:09 +00001906 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001907 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001908 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001909
bellard5fd386f2004-05-23 21:11:22 +00001910 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001911 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001912 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001913 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001914 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001915 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1916 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001917 phys_offset += TARGET_PAGE_SIZE;
1918 }
bellard9d420372006-06-25 22:25:22 +00001919
1920 /* since each CPU stores ram addresses in its TLB cache, we must
1921 reset the modified entries */
1922 /* XXX: slow ! */
1923 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1924 tlb_flush(env, 1);
1925 }
bellard33417e72003-08-10 21:47:01 +00001926}
1927
bellardba863452006-09-24 18:41:10 +00001928/* XXX: temporary until new memory mapping API */
1929uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1930{
1931 PhysPageDesc *p;
1932
1933 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1934 if (!p)
1935 return IO_MEM_UNASSIGNED;
1936 return p->phys_offset;
1937}
1938
bellarde9a1ab12007-02-08 23:08:38 +00001939/* XXX: better than nothing */
1940ram_addr_t qemu_ram_alloc(unsigned int size)
1941{
1942 ram_addr_t addr;
1943 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1944 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
1945 size, phys_ram_size);
1946 abort();
1947 }
1948 addr = phys_ram_alloc_offset;
1949 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1950 return addr;
1951}
1952
1953void qemu_ram_free(ram_addr_t addr)
1954{
1955}
1956
bellarda4193c82004-06-03 14:01:43 +00001957static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001958{
pbrook67d3b952006-12-18 05:03:52 +00001959#ifdef DEBUG_UNASSIGNED
blueswir16c36d3f2007-05-17 19:30:10 +00001960 printf("Unassigned mem read " TARGET_FMT_lx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00001961#endif
blueswir1b4f0a312007-05-06 17:59:24 +00001962#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00001963 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00001964#endif
bellard33417e72003-08-10 21:47:01 +00001965 return 0;
1966}
1967
bellarda4193c82004-06-03 14:01:43 +00001968static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001969{
pbrook67d3b952006-12-18 05:03:52 +00001970#ifdef DEBUG_UNASSIGNED
blueswir16c36d3f2007-05-17 19:30:10 +00001971 printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00001972#endif
blueswir1b4f0a312007-05-06 17:59:24 +00001973#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00001974 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00001975#endif
bellard33417e72003-08-10 21:47:01 +00001976}
1977
1978static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1979 unassigned_mem_readb,
1980 unassigned_mem_readb,
1981 unassigned_mem_readb,
1982};
1983
1984static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1985 unassigned_mem_writeb,
1986 unassigned_mem_writeb,
1987 unassigned_mem_writeb,
1988};
1989
bellarda4193c82004-06-03 14:01:43 +00001990static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001991{
bellard3a7d9292005-08-21 09:26:42 +00001992 unsigned long ram_addr;
1993 int dirty_flags;
1994 ram_addr = addr - (unsigned long)phys_ram_base;
1995 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1996 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1997#if !defined(CONFIG_USER_ONLY)
1998 tb_invalidate_phys_page_fast(ram_addr, 1);
1999 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2000#endif
2001 }
bellardc27004e2005-01-03 23:35:10 +00002002 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002003#ifdef USE_KQEMU
2004 if (cpu_single_env->kqemu_enabled &&
2005 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2006 kqemu_modify_page(cpu_single_env, ram_addr);
2007#endif
bellardf23db162005-08-21 19:12:28 +00002008 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2009 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2010 /* we remove the notdirty callback only if the code has been
2011 flushed */
2012 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002013 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002014}
2015
bellarda4193c82004-06-03 14:01:43 +00002016static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002017{
bellard3a7d9292005-08-21 09:26:42 +00002018 unsigned long ram_addr;
2019 int dirty_flags;
2020 ram_addr = addr - (unsigned long)phys_ram_base;
2021 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2022 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2023#if !defined(CONFIG_USER_ONLY)
2024 tb_invalidate_phys_page_fast(ram_addr, 2);
2025 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2026#endif
2027 }
bellardc27004e2005-01-03 23:35:10 +00002028 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002029#ifdef USE_KQEMU
2030 if (cpu_single_env->kqemu_enabled &&
2031 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2032 kqemu_modify_page(cpu_single_env, ram_addr);
2033#endif
bellardf23db162005-08-21 19:12:28 +00002034 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2035 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2036 /* we remove the notdirty callback only if the code has been
2037 flushed */
2038 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002039 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002040}
2041
bellarda4193c82004-06-03 14:01:43 +00002042static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002043{
bellard3a7d9292005-08-21 09:26:42 +00002044 unsigned long ram_addr;
2045 int dirty_flags;
2046 ram_addr = addr - (unsigned long)phys_ram_base;
2047 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2048 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2049#if !defined(CONFIG_USER_ONLY)
2050 tb_invalidate_phys_page_fast(ram_addr, 4);
2051 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2052#endif
2053 }
bellardc27004e2005-01-03 23:35:10 +00002054 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002055#ifdef USE_KQEMU
2056 if (cpu_single_env->kqemu_enabled &&
2057 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2058 kqemu_modify_page(cpu_single_env, ram_addr);
2059#endif
bellardf23db162005-08-21 19:12:28 +00002060 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2061 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2062 /* we remove the notdirty callback only if the code has been
2063 flushed */
2064 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002065 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002066}
2067
bellard3a7d9292005-08-21 09:26:42 +00002068static CPUReadMemoryFunc *error_mem_read[3] = {
2069 NULL, /* never used */
2070 NULL, /* never used */
2071 NULL, /* never used */
2072};
2073
bellard1ccde1c2004-02-06 19:46:14 +00002074static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2075 notdirty_mem_writeb,
2076 notdirty_mem_writew,
2077 notdirty_mem_writel,
2078};
2079
pbrook6658ffb2007-03-16 23:58:11 +00002080#if defined(CONFIG_SOFTMMU)
2081/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2082 so these check for a hit then pass through to the normal out-of-line
2083 phys routines. */
2084static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2085{
2086 return ldub_phys(addr);
2087}
2088
2089static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2090{
2091 return lduw_phys(addr);
2092}
2093
2094static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2095{
2096 return ldl_phys(addr);
2097}
2098
2099/* Generate a debug exception if a watchpoint has been hit.
2100 Returns the real physical address of the access. addr will be a host
2101 address in the is_ram case. */
2102static target_ulong check_watchpoint(target_phys_addr_t addr)
2103{
2104 CPUState *env = cpu_single_env;
2105 target_ulong watch;
2106 target_ulong retaddr;
2107 int i;
2108
2109 retaddr = addr;
2110 for (i = 0; i < env->nb_watchpoints; i++) {
2111 watch = env->watchpoint[i].vaddr;
2112 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
2113 if (env->watchpoint[i].is_ram)
2114 retaddr = addr - (unsigned long)phys_ram_base;
2115 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2116 cpu_single_env->watchpoint_hit = i + 1;
2117 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2118 break;
2119 }
2120 }
2121 }
2122 return retaddr;
2123}
2124
2125static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2126 uint32_t val)
2127{
2128 addr = check_watchpoint(addr);
2129 stb_phys(addr, val);
2130}
2131
2132static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2133 uint32_t val)
2134{
2135 addr = check_watchpoint(addr);
2136 stw_phys(addr, val);
2137}
2138
2139static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2140 uint32_t val)
2141{
2142 addr = check_watchpoint(addr);
2143 stl_phys(addr, val);
2144}
2145
2146static CPUReadMemoryFunc *watch_mem_read[3] = {
2147 watch_mem_readb,
2148 watch_mem_readw,
2149 watch_mem_readl,
2150};
2151
2152static CPUWriteMemoryFunc *watch_mem_write[3] = {
2153 watch_mem_writeb,
2154 watch_mem_writew,
2155 watch_mem_writel,
2156};
2157#endif
2158
bellard33417e72003-08-10 21:47:01 +00002159static void io_mem_init(void)
2160{
bellard3a7d9292005-08-21 09:26:42 +00002161 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002162 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002163 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002164 io_mem_nb = 5;
2165
pbrook6658ffb2007-03-16 23:58:11 +00002166#if defined(CONFIG_SOFTMMU)
2167 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2168 watch_mem_write, NULL);
2169#endif
bellard1ccde1c2004-02-06 19:46:14 +00002170 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002171 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002172 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002173}
2174
2175/* mem_read and mem_write are arrays of functions containing the
2176 function to access byte (index 0), word (index 1) and dword (index
2177 2). All functions must be supplied. If io_index is non zero, the
2178 corresponding io zone is modified. If it is zero, a new io zone is
2179 allocated. The return value can be used with
2180 cpu_register_physical_memory(). (-1) is returned if error. */
2181int cpu_register_io_memory(int io_index,
2182 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002183 CPUWriteMemoryFunc **mem_write,
2184 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002185{
2186 int i;
2187
2188 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002189 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002190 return -1;
2191 io_index = io_mem_nb++;
2192 } else {
2193 if (io_index >= IO_MEM_NB_ENTRIES)
2194 return -1;
2195 }
bellardb5ff1b32005-11-26 10:38:39 +00002196
bellard33417e72003-08-10 21:47:01 +00002197 for(i = 0;i < 3; i++) {
2198 io_mem_read[io_index][i] = mem_read[i];
2199 io_mem_write[io_index][i] = mem_write[i];
2200 }
bellarda4193c82004-06-03 14:01:43 +00002201 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002202 return io_index << IO_MEM_SHIFT;
2203}
bellard61382a52003-10-27 21:22:23 +00002204
bellard8926b512004-10-10 15:14:20 +00002205CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2206{
2207 return io_mem_write[io_index >> IO_MEM_SHIFT];
2208}
2209
2210CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2211{
2212 return io_mem_read[io_index >> IO_MEM_SHIFT];
2213}
2214
bellard13eb76e2004-01-24 15:23:36 +00002215/* physical memory access (slow version, mainly for debug) */
2216#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002217void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002218 int len, int is_write)
2219{
2220 int l, flags;
2221 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002222 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002223
2224 while (len > 0) {
2225 page = addr & TARGET_PAGE_MASK;
2226 l = (page + TARGET_PAGE_SIZE) - addr;
2227 if (l > len)
2228 l = len;
2229 flags = page_get_flags(page);
2230 if (!(flags & PAGE_VALID))
2231 return;
2232 if (is_write) {
2233 if (!(flags & PAGE_WRITE))
2234 return;
pbrook53a59602006-03-25 19:31:22 +00002235 p = lock_user(addr, len, 0);
2236 memcpy(p, buf, len);
2237 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002238 } else {
2239 if (!(flags & PAGE_READ))
2240 return;
pbrook53a59602006-03-25 19:31:22 +00002241 p = lock_user(addr, len, 1);
2242 memcpy(buf, p, len);
2243 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002244 }
2245 len -= l;
2246 buf += l;
2247 addr += l;
2248 }
2249}
bellard8df1cd02005-01-28 22:37:22 +00002250
bellard13eb76e2004-01-24 15:23:36 +00002251#else
bellard2e126692004-04-25 21:28:44 +00002252void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002253 int len, int is_write)
2254{
2255 int l, io_index;
2256 uint8_t *ptr;
2257 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002258 target_phys_addr_t page;
2259 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002260 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002261
2262 while (len > 0) {
2263 page = addr & TARGET_PAGE_MASK;
2264 l = (page + TARGET_PAGE_SIZE) - addr;
2265 if (l > len)
2266 l = len;
bellard92e873b2004-05-21 14:52:29 +00002267 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002268 if (!p) {
2269 pd = IO_MEM_UNASSIGNED;
2270 } else {
2271 pd = p->phys_offset;
2272 }
2273
2274 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002275 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002276 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002277 /* XXX: could force cpu_single_env to NULL to avoid
2278 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002279 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002280 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002281 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002282 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002283 l = 4;
2284 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002285 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002286 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002287 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002288 l = 2;
2289 } else {
bellard1c213d12005-09-03 10:49:04 +00002290 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002291 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002292 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002293 l = 1;
2294 }
2295 } else {
bellardb448f2f2004-02-25 23:24:04 +00002296 unsigned long addr1;
2297 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002298 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002299 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002300 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002301 if (!cpu_physical_memory_is_dirty(addr1)) {
2302 /* invalidate code */
2303 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2304 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002305 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2306 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002307 }
bellard13eb76e2004-01-24 15:23:36 +00002308 }
2309 } else {
bellard2a4188a2006-06-25 21:54:59 +00002310 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2311 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002312 /* I/O case */
2313 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2314 if (l >= 4 && ((addr & 3) == 0)) {
2315 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002316 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002317 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002318 l = 4;
2319 } else if (l >= 2 && ((addr & 1) == 0)) {
2320 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002321 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002322 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002323 l = 2;
2324 } else {
bellard1c213d12005-09-03 10:49:04 +00002325 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002326 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002327 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002328 l = 1;
2329 }
2330 } else {
2331 /* RAM case */
2332 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2333 (addr & ~TARGET_PAGE_MASK);
2334 memcpy(buf, ptr, l);
2335 }
2336 }
2337 len -= l;
2338 buf += l;
2339 addr += l;
2340 }
2341}
bellard8df1cd02005-01-28 22:37:22 +00002342
bellardd0ecd2a2006-04-23 17:14:48 +00002343/* used for ROM loading : can write in RAM and ROM */
2344void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2345 const uint8_t *buf, int len)
2346{
2347 int l;
2348 uint8_t *ptr;
2349 target_phys_addr_t page;
2350 unsigned long pd;
2351 PhysPageDesc *p;
2352
2353 while (len > 0) {
2354 page = addr & TARGET_PAGE_MASK;
2355 l = (page + TARGET_PAGE_SIZE) - addr;
2356 if (l > len)
2357 l = len;
2358 p = phys_page_find(page >> TARGET_PAGE_BITS);
2359 if (!p) {
2360 pd = IO_MEM_UNASSIGNED;
2361 } else {
2362 pd = p->phys_offset;
2363 }
2364
2365 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002366 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2367 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002368 /* do nothing */
2369 } else {
2370 unsigned long addr1;
2371 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2372 /* ROM/RAM case */
2373 ptr = phys_ram_base + addr1;
2374 memcpy(ptr, buf, l);
2375 }
2376 len -= l;
2377 buf += l;
2378 addr += l;
2379 }
2380}
2381
2382
bellard8df1cd02005-01-28 22:37:22 +00002383/* warning: addr must be aligned */
2384uint32_t ldl_phys(target_phys_addr_t addr)
2385{
2386 int io_index;
2387 uint8_t *ptr;
2388 uint32_t val;
2389 unsigned long pd;
2390 PhysPageDesc *p;
2391
2392 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2393 if (!p) {
2394 pd = IO_MEM_UNASSIGNED;
2395 } else {
2396 pd = p->phys_offset;
2397 }
2398
bellard2a4188a2006-06-25 21:54:59 +00002399 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2400 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002401 /* I/O case */
2402 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2403 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2404 } else {
2405 /* RAM case */
2406 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2407 (addr & ~TARGET_PAGE_MASK);
2408 val = ldl_p(ptr);
2409 }
2410 return val;
2411}
2412
bellard84b7b8e2005-11-28 21:19:04 +00002413/* warning: addr must be aligned */
2414uint64_t ldq_phys(target_phys_addr_t addr)
2415{
2416 int io_index;
2417 uint8_t *ptr;
2418 uint64_t val;
2419 unsigned long pd;
2420 PhysPageDesc *p;
2421
2422 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2423 if (!p) {
2424 pd = IO_MEM_UNASSIGNED;
2425 } else {
2426 pd = p->phys_offset;
2427 }
2428
bellard2a4188a2006-06-25 21:54:59 +00002429 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2430 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002431 /* I/O case */
2432 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2433#ifdef TARGET_WORDS_BIGENDIAN
2434 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2435 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2436#else
2437 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2438 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2439#endif
2440 } else {
2441 /* RAM case */
2442 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2443 (addr & ~TARGET_PAGE_MASK);
2444 val = ldq_p(ptr);
2445 }
2446 return val;
2447}
2448
bellardaab33092005-10-30 20:48:42 +00002449/* XXX: optimize */
2450uint32_t ldub_phys(target_phys_addr_t addr)
2451{
2452 uint8_t val;
2453 cpu_physical_memory_read(addr, &val, 1);
2454 return val;
2455}
2456
2457/* XXX: optimize */
2458uint32_t lduw_phys(target_phys_addr_t addr)
2459{
2460 uint16_t val;
2461 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2462 return tswap16(val);
2463}
2464
bellard8df1cd02005-01-28 22:37:22 +00002465/* warning: addr must be aligned. The ram page is not masked as dirty
2466 and the code inside is not invalidated. It is useful if the dirty
2467 bits are used to track modified PTEs */
2468void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2469{
2470 int io_index;
2471 uint8_t *ptr;
2472 unsigned long pd;
2473 PhysPageDesc *p;
2474
2475 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2476 if (!p) {
2477 pd = IO_MEM_UNASSIGNED;
2478 } else {
2479 pd = p->phys_offset;
2480 }
2481
bellard3a7d9292005-08-21 09:26:42 +00002482 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002483 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2484 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2485 } else {
2486 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2487 (addr & ~TARGET_PAGE_MASK);
2488 stl_p(ptr, val);
2489 }
2490}
2491
j_mayerbc98a7e2007-04-04 07:55:12 +00002492void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2493{
2494 int io_index;
2495 uint8_t *ptr;
2496 unsigned long pd;
2497 PhysPageDesc *p;
2498
2499 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2500 if (!p) {
2501 pd = IO_MEM_UNASSIGNED;
2502 } else {
2503 pd = p->phys_offset;
2504 }
2505
2506 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2507 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2508#ifdef TARGET_WORDS_BIGENDIAN
2509 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2510 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2511#else
2512 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2513 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2514#endif
2515 } else {
2516 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2517 (addr & ~TARGET_PAGE_MASK);
2518 stq_p(ptr, val);
2519 }
2520}
2521
bellard8df1cd02005-01-28 22:37:22 +00002522/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002523void stl_phys(target_phys_addr_t addr, uint32_t val)
2524{
2525 int io_index;
2526 uint8_t *ptr;
2527 unsigned long pd;
2528 PhysPageDesc *p;
2529
2530 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2531 if (!p) {
2532 pd = IO_MEM_UNASSIGNED;
2533 } else {
2534 pd = p->phys_offset;
2535 }
2536
bellard3a7d9292005-08-21 09:26:42 +00002537 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002538 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2539 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2540 } else {
2541 unsigned long addr1;
2542 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2543 /* RAM case */
2544 ptr = phys_ram_base + addr1;
2545 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002546 if (!cpu_physical_memory_is_dirty(addr1)) {
2547 /* invalidate code */
2548 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2549 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002550 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2551 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002552 }
bellard8df1cd02005-01-28 22:37:22 +00002553 }
2554}
2555
bellardaab33092005-10-30 20:48:42 +00002556/* XXX: optimize */
2557void stb_phys(target_phys_addr_t addr, uint32_t val)
2558{
2559 uint8_t v = val;
2560 cpu_physical_memory_write(addr, &v, 1);
2561}
2562
2563/* XXX: optimize */
2564void stw_phys(target_phys_addr_t addr, uint32_t val)
2565{
2566 uint16_t v = tswap16(val);
2567 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2568}
2569
2570/* XXX: optimize */
2571void stq_phys(target_phys_addr_t addr, uint64_t val)
2572{
2573 val = tswap64(val);
2574 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2575}
2576
bellard13eb76e2004-01-24 15:23:36 +00002577#endif
2578
2579/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002580int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2581 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002582{
2583 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002584 target_phys_addr_t phys_addr;
2585 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002586
2587 while (len > 0) {
2588 page = addr & TARGET_PAGE_MASK;
2589 phys_addr = cpu_get_phys_page_debug(env, page);
2590 /* if no physical page mapped, return an error */
2591 if (phys_addr == -1)
2592 return -1;
2593 l = (page + TARGET_PAGE_SIZE) - addr;
2594 if (l > len)
2595 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002596 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2597 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002598 len -= l;
2599 buf += l;
2600 addr += l;
2601 }
2602 return 0;
2603}
2604
bellarde3db7222005-01-26 22:00:47 +00002605void dump_exec_info(FILE *f,
2606 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2607{
2608 int i, target_code_size, max_target_code_size;
2609 int direct_jmp_count, direct_jmp2_count, cross_page;
2610 TranslationBlock *tb;
2611
2612 target_code_size = 0;
2613 max_target_code_size = 0;
2614 cross_page = 0;
2615 direct_jmp_count = 0;
2616 direct_jmp2_count = 0;
2617 for(i = 0; i < nb_tbs; i++) {
2618 tb = &tbs[i];
2619 target_code_size += tb->size;
2620 if (tb->size > max_target_code_size)
2621 max_target_code_size = tb->size;
2622 if (tb->page_addr[1] != -1)
2623 cross_page++;
2624 if (tb->tb_next_offset[0] != 0xffff) {
2625 direct_jmp_count++;
2626 if (tb->tb_next_offset[1] != 0xffff) {
2627 direct_jmp2_count++;
2628 }
2629 }
2630 }
2631 /* XXX: avoid using doubles ? */
2632 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2633 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2634 nb_tbs ? target_code_size / nb_tbs : 0,
2635 max_target_code_size);
2636 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2637 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2638 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2639 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2640 cross_page,
2641 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2642 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2643 direct_jmp_count,
2644 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2645 direct_jmp2_count,
2646 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2647 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2648 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2649 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2650}
2651
bellard61382a52003-10-27 21:22:23 +00002652#if !defined(CONFIG_USER_ONLY)
2653
2654#define MMUSUFFIX _cmmu
2655#define GETPC() NULL
2656#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002657#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002658
2659#define SHIFT 0
2660#include "softmmu_template.h"
2661
2662#define SHIFT 1
2663#include "softmmu_template.h"
2664
2665#define SHIFT 2
2666#include "softmmu_template.h"
2667
2668#define SHIFT 3
2669#include "softmmu_template.h"
2670
2671#undef env
2672
2673#endif