blob: 2e09b4bc3e9a9269f80c708f4b413b643541c8f9 [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
pbrook99773bd2006-04-16 15:14:59 +000050#if !defined(CONFIG_USER_ONLY)
51/* TB consistency checks only implemented for usermode emulation. */
52#undef DEBUG_TB_CHECK
53#endif
54
bellardfd6ce8f2003-05-14 19:00:11 +000055/* threshold to flush the translated code buffer */
56#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
57
bellard9fa3e852004-01-04 18:06:42 +000058#define SMC_BITMAP_USE_THRESHOLD 10
59
60#define MMAP_AREA_START 0x00000000
61#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000062
bellard108c49b2005-07-24 12:55:09 +000063#if defined(TARGET_SPARC64)
64#define TARGET_PHYS_ADDR_SPACE_BITS 41
65#elif defined(TARGET_PPC64)
66#define TARGET_PHYS_ADDR_SPACE_BITS 42
67#else
68/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
69#define TARGET_PHYS_ADDR_SPACE_BITS 32
70#endif
71
bellardfd6ce8f2003-05-14 19:00:11 +000072TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
bellard9fa3e852004-01-04 18:06:42 +000073TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000074int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000075/* any access to the tbs or the page table must use this lock */
76spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000077
bellardb8076a72005-04-07 22:20:31 +000078uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
bellardfd6ce8f2003-05-14 19:00:11 +000079uint8_t *code_gen_ptr;
80
bellard9fa3e852004-01-04 18:06:42 +000081int phys_ram_size;
82int phys_ram_fd;
83uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000084uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +000085static ram_addr_t phys_ram_alloc_offset = 0;
bellard9fa3e852004-01-04 18:06:42 +000086
bellard6a00d602005-11-21 23:25:50 +000087CPUState *first_cpu;
88/* current CPU in the current thread. It is only valid inside
89 cpu_exec() */
90CPUState *cpu_single_env;
91
bellard54936002003-05-13 00:25:15 +000092typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000093 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000094 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000095 /* in order to optimize self modifying code, we count the number
96 of lookups we do to a given page to use a bitmap */
97 unsigned int code_write_count;
98 uint8_t *code_bitmap;
99#if defined(CONFIG_USER_ONLY)
100 unsigned long flags;
101#endif
bellard54936002003-05-13 00:25:15 +0000102} PageDesc;
103
bellard92e873b2004-05-21 14:52:29 +0000104typedef struct PhysPageDesc {
105 /* offset in host memory of the page + io_index in the low 12 bits */
bellarde04f40b2005-04-24 18:02:38 +0000106 uint32_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000107} PhysPageDesc;
108
bellard54936002003-05-13 00:25:15 +0000109#define L2_BITS 10
110#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
111
112#define L1_SIZE (1 << L1_BITS)
113#define L2_SIZE (1 << L2_BITS)
114
bellard33417e72003-08-10 21:47:01 +0000115static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000116
bellard83fb7ad2004-07-05 21:25:26 +0000117unsigned long qemu_real_host_page_size;
118unsigned long qemu_host_page_bits;
119unsigned long qemu_host_page_size;
120unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000121
bellard92e873b2004-05-21 14:52:29 +0000122/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000123static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000124PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000125
bellard33417e72003-08-10 21:47:01 +0000126/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000127CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
128CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000129void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000130static int io_mem_nb;
131
bellard34865132003-10-05 14:28:56 +0000132/* log support */
133char *logfilename = "/tmp/qemu.log";
134FILE *logfile;
135int loglevel;
136
bellarde3db7222005-01-26 22:00:47 +0000137/* statistics */
138static int tlb_flush_count;
139static int tb_flush_count;
140static int tb_phys_invalidate_count;
141
bellardb346ff42003-06-15 20:05:50 +0000142static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000143{
bellard83fb7ad2004-07-05 21:25:26 +0000144 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000145 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000146#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000147 {
148 SYSTEM_INFO system_info;
149 DWORD old_protect;
150
151 GetSystemInfo(&system_info);
152 qemu_real_host_page_size = system_info.dwPageSize;
153
154 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
155 PAGE_EXECUTE_READWRITE, &old_protect);
156 }
bellard67b915a2004-03-31 23:37:16 +0000157#else
bellard83fb7ad2004-07-05 21:25:26 +0000158 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000159 {
160 unsigned long start, end;
161
162 start = (unsigned long)code_gen_buffer;
163 start &= ~(qemu_real_host_page_size - 1);
164
165 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
166 end += qemu_real_host_page_size - 1;
167 end &= ~(qemu_real_host_page_size - 1);
168
169 mprotect((void *)start, end - start,
170 PROT_READ | PROT_WRITE | PROT_EXEC);
171 }
bellard67b915a2004-03-31 23:37:16 +0000172#endif
bellardd5a8f072004-09-29 21:15:28 +0000173
bellard83fb7ad2004-07-05 21:25:26 +0000174 if (qemu_host_page_size == 0)
175 qemu_host_page_size = qemu_real_host_page_size;
176 if (qemu_host_page_size < TARGET_PAGE_SIZE)
177 qemu_host_page_size = TARGET_PAGE_SIZE;
178 qemu_host_page_bits = 0;
179 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
180 qemu_host_page_bits++;
181 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000182 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
183 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
bellard54936002003-05-13 00:25:15 +0000184}
185
bellardfd6ce8f2003-05-14 19:00:11 +0000186static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000187{
bellard54936002003-05-13 00:25:15 +0000188 PageDesc **lp, *p;
189
bellard54936002003-05-13 00:25:15 +0000190 lp = &l1_map[index >> L2_BITS];
191 p = *lp;
192 if (!p) {
193 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000194 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000195 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000196 *lp = p;
197 }
198 return p + (index & (L2_SIZE - 1));
199}
200
bellardfd6ce8f2003-05-14 19:00:11 +0000201static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000202{
bellard54936002003-05-13 00:25:15 +0000203 PageDesc *p;
204
bellard54936002003-05-13 00:25:15 +0000205 p = l1_map[index >> L2_BITS];
206 if (!p)
207 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000208 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000209}
210
bellard108c49b2005-07-24 12:55:09 +0000211static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000212{
bellard108c49b2005-07-24 12:55:09 +0000213 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000214 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000215
bellard108c49b2005-07-24 12:55:09 +0000216 p = (void **)l1_phys_map;
217#if TARGET_PHYS_ADDR_SPACE_BITS > 32
218
219#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
220#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
221#endif
222 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000223 p = *lp;
224 if (!p) {
225 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000226 if (!alloc)
227 return NULL;
228 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
229 memset(p, 0, sizeof(void *) * L1_SIZE);
230 *lp = p;
231 }
232#endif
233 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000234 pd = *lp;
235 if (!pd) {
236 int i;
bellard108c49b2005-07-24 12:55:09 +0000237 /* allocate if not found */
238 if (!alloc)
239 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000240 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
241 *lp = pd;
242 for (i = 0; i < L2_SIZE; i++)
243 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000244 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000245 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000246}
247
bellard108c49b2005-07-24 12:55:09 +0000248static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000249{
bellard108c49b2005-07-24 12:55:09 +0000250 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000251}
252
bellard9fa3e852004-01-04 18:06:42 +0000253#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000254static void tlb_protect_code(ram_addr_t ram_addr);
bellard3a7d9292005-08-21 09:26:42 +0000255static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
256 target_ulong vaddr);
bellard9fa3e852004-01-04 18:06:42 +0000257#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000258
bellard6a00d602005-11-21 23:25:50 +0000259void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000260{
bellard6a00d602005-11-21 23:25:50 +0000261 CPUState **penv;
262 int cpu_index;
263
bellardfd6ce8f2003-05-14 19:00:11 +0000264 if (!code_gen_ptr) {
265 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000266 page_init();
bellard33417e72003-08-10 21:47:01 +0000267 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000268 }
bellard6a00d602005-11-21 23:25:50 +0000269 env->next_cpu = NULL;
270 penv = &first_cpu;
271 cpu_index = 0;
272 while (*penv != NULL) {
273 penv = (CPUState **)&(*penv)->next_cpu;
274 cpu_index++;
275 }
276 env->cpu_index = cpu_index;
277 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000278}
279
bellard9fa3e852004-01-04 18:06:42 +0000280static inline void invalidate_page_bitmap(PageDesc *p)
281{
282 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000283 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000284 p->code_bitmap = NULL;
285 }
286 p->code_write_count = 0;
287}
288
bellardfd6ce8f2003-05-14 19:00:11 +0000289/* set to NULL all the 'first_tb' fields in all PageDescs */
290static void page_flush_tb(void)
291{
292 int i, j;
293 PageDesc *p;
294
295 for(i = 0; i < L1_SIZE; i++) {
296 p = l1_map[i];
297 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000298 for(j = 0; j < L2_SIZE; j++) {
299 p->first_tb = NULL;
300 invalidate_page_bitmap(p);
301 p++;
302 }
bellardfd6ce8f2003-05-14 19:00:11 +0000303 }
304 }
305}
306
307/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000308/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000309void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000310{
bellard6a00d602005-11-21 23:25:50 +0000311 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000312#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000313 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
314 code_gen_ptr - code_gen_buffer,
315 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000316 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000317#endif
318 nb_tbs = 0;
bellard6a00d602005-11-21 23:25:50 +0000319
320 for(env = first_cpu; env != NULL; env = env->next_cpu) {
321 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
322 }
bellard9fa3e852004-01-04 18:06:42 +0000323
bellard8a8a6082004-10-03 13:36:49 +0000324 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000325 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000326
bellardfd6ce8f2003-05-14 19:00:11 +0000327 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000328 /* XXX: flush processor icache at this point if cache flush is
329 expensive */
bellarde3db7222005-01-26 22:00:47 +0000330 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000331}
332
333#ifdef DEBUG_TB_CHECK
334
335static void tb_invalidate_check(unsigned long address)
336{
337 TranslationBlock *tb;
338 int i;
339 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000340 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
341 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000342 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
343 address >= tb->pc + tb->size)) {
344 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000345 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000346 }
347 }
348 }
349}
350
351/* verify that all the pages have correct rights for code */
352static void tb_page_check(void)
353{
354 TranslationBlock *tb;
355 int i, flags1, flags2;
356
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 flags1 = page_get_flags(tb->pc);
360 flags2 = page_get_flags(tb->pc + tb->size - 1);
361 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
362 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000363 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000364 }
365 }
366 }
367}
368
bellardd4e81642003-05-25 16:46:15 +0000369void tb_jmp_check(TranslationBlock *tb)
370{
371 TranslationBlock *tb1;
372 unsigned int n1;
373
374 /* suppress any remaining jumps to this TB */
375 tb1 = tb->jmp_first;
376 for(;;) {
377 n1 = (long)tb1 & 3;
378 tb1 = (TranslationBlock *)((long)tb1 & ~3);
379 if (n1 == 2)
380 break;
381 tb1 = tb1->jmp_next[n1];
382 }
383 /* check end of list */
384 if (tb1 != tb) {
385 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
386 }
387}
388
bellardfd6ce8f2003-05-14 19:00:11 +0000389#endif
390
391/* invalidate one TB */
392static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
393 int next_offset)
394{
395 TranslationBlock *tb1;
396 for(;;) {
397 tb1 = *ptb;
398 if (tb1 == tb) {
399 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
400 break;
401 }
402 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
403 }
404}
405
bellard9fa3e852004-01-04 18:06:42 +0000406static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
407{
408 TranslationBlock *tb1;
409 unsigned int n1;
410
411 for(;;) {
412 tb1 = *ptb;
413 n1 = (long)tb1 & 3;
414 tb1 = (TranslationBlock *)((long)tb1 & ~3);
415 if (tb1 == tb) {
416 *ptb = tb1->page_next[n1];
417 break;
418 }
419 ptb = &tb1->page_next[n1];
420 }
421}
422
bellardd4e81642003-05-25 16:46:15 +0000423static inline void tb_jmp_remove(TranslationBlock *tb, int n)
424{
425 TranslationBlock *tb1, **ptb;
426 unsigned int n1;
427
428 ptb = &tb->jmp_next[n];
429 tb1 = *ptb;
430 if (tb1) {
431 /* find tb(n) in circular list */
432 for(;;) {
433 tb1 = *ptb;
434 n1 = (long)tb1 & 3;
435 tb1 = (TranslationBlock *)((long)tb1 & ~3);
436 if (n1 == n && tb1 == tb)
437 break;
438 if (n1 == 2) {
439 ptb = &tb1->jmp_first;
440 } else {
441 ptb = &tb1->jmp_next[n1];
442 }
443 }
444 /* now we can suppress tb(n) from the list */
445 *ptb = tb->jmp_next[n];
446
447 tb->jmp_next[n] = NULL;
448 }
449}
450
451/* reset the jump entry 'n' of a TB so that it is not chained to
452 another TB */
453static inline void tb_reset_jump(TranslationBlock *tb, int n)
454{
455 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
456}
457
bellard9fa3e852004-01-04 18:06:42 +0000458static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000459{
bellard6a00d602005-11-21 23:25:50 +0000460 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000461 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000462 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000463 target_ulong phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000464 TranslationBlock *tb1, *tb2;
bellard9fa3e852004-01-04 18:06:42 +0000465
466 /* remove the TB from the hash list */
467 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
468 h = tb_phys_hash_func(phys_pc);
469 tb_remove(&tb_phys_hash[h], tb,
470 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000471
bellard9fa3e852004-01-04 18:06:42 +0000472 /* remove the TB from the page list */
473 if (tb->page_addr[0] != page_addr) {
474 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
475 tb_page_remove(&p->first_tb, tb);
476 invalidate_page_bitmap(p);
477 }
478 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
479 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
480 tb_page_remove(&p->first_tb, tb);
481 invalidate_page_bitmap(p);
482 }
483
bellard8a40a182005-11-20 10:35:40 +0000484 tb_invalidated_flag = 1;
485
486 /* remove the TB from the hash list */
487 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000488 for(env = first_cpu; env != NULL; env = env->next_cpu) {
489 if (env->tb_jmp_cache[h] == tb)
490 env->tb_jmp_cache[h] = NULL;
491 }
bellard8a40a182005-11-20 10:35:40 +0000492
493 /* suppress this TB from the two jump lists */
494 tb_jmp_remove(tb, 0);
495 tb_jmp_remove(tb, 1);
496
497 /* suppress any remaining jumps to this TB */
498 tb1 = tb->jmp_first;
499 for(;;) {
500 n1 = (long)tb1 & 3;
501 if (n1 == 2)
502 break;
503 tb1 = (TranslationBlock *)((long)tb1 & ~3);
504 tb2 = tb1->jmp_next[n1];
505 tb_reset_jump(tb1, n1);
506 tb1->jmp_next[n1] = NULL;
507 tb1 = tb2;
508 }
509 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
510
bellarde3db7222005-01-26 22:00:47 +0000511 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000512}
513
514static inline void set_bits(uint8_t *tab, int start, int len)
515{
516 int end, mask, end1;
517
518 end = start + len;
519 tab += start >> 3;
520 mask = 0xff << (start & 7);
521 if ((start & ~7) == (end & ~7)) {
522 if (start < end) {
523 mask &= ~(0xff << (end & 7));
524 *tab |= mask;
525 }
526 } else {
527 *tab++ |= mask;
528 start = (start + 8) & ~7;
529 end1 = end & ~7;
530 while (start < end1) {
531 *tab++ = 0xff;
532 start += 8;
533 }
534 if (start < end) {
535 mask = ~(0xff << (end & 7));
536 *tab |= mask;
537 }
538 }
539}
540
541static void build_page_bitmap(PageDesc *p)
542{
543 int n, tb_start, tb_end;
544 TranslationBlock *tb;
545
bellard59817cc2004-02-16 22:01:13 +0000546 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000547 if (!p->code_bitmap)
548 return;
549 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
550
551 tb = p->first_tb;
552 while (tb != NULL) {
553 n = (long)tb & 3;
554 tb = (TranslationBlock *)((long)tb & ~3);
555 /* NOTE: this is subtle as a TB may span two physical pages */
556 if (n == 0) {
557 /* NOTE: tb_end may be after the end of the page, but
558 it is not a problem */
559 tb_start = tb->pc & ~TARGET_PAGE_MASK;
560 tb_end = tb_start + tb->size;
561 if (tb_end > TARGET_PAGE_SIZE)
562 tb_end = TARGET_PAGE_SIZE;
563 } else {
564 tb_start = 0;
565 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
566 }
567 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
568 tb = tb->page_next[n];
569 }
570}
571
bellardd720b932004-04-25 17:57:43 +0000572#ifdef TARGET_HAS_PRECISE_SMC
573
574static void tb_gen_code(CPUState *env,
575 target_ulong pc, target_ulong cs_base, int flags,
576 int cflags)
577{
578 TranslationBlock *tb;
579 uint8_t *tc_ptr;
580 target_ulong phys_pc, phys_page2, virt_page2;
581 int code_gen_size;
582
bellardc27004e2005-01-03 23:35:10 +0000583 phys_pc = get_phys_addr_code(env, pc);
584 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000585 if (!tb) {
586 /* flush must be done */
587 tb_flush(env);
588 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000589 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000590 }
591 tc_ptr = code_gen_ptr;
592 tb->tc_ptr = tc_ptr;
593 tb->cs_base = cs_base;
594 tb->flags = flags;
595 tb->cflags = cflags;
596 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
597 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
598
599 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000600 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000601 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000602 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000603 phys_page2 = get_phys_addr_code(env, virt_page2);
604 }
605 tb_link_phys(tb, phys_pc, phys_page2);
606}
607#endif
608
bellard9fa3e852004-01-04 18:06:42 +0000609/* invalidate all TBs which intersect with the target physical page
610 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000611 the same physical page. 'is_cpu_write_access' should be true if called
612 from a real cpu write access: the virtual CPU will exit the current
613 TB if code is modified inside this TB. */
614void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
615 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000616{
bellardd720b932004-04-25 17:57:43 +0000617 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000618 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000619 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000620 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000621 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000622 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000623
624 p = page_find(start >> TARGET_PAGE_BITS);
625 if (!p)
626 return;
627 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000628 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
629 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000630 /* build code bitmap */
631 build_page_bitmap(p);
632 }
633
634 /* we remove all the TBs in the range [start, end[ */
635 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000636 current_tb_not_found = is_cpu_write_access;
637 current_tb_modified = 0;
638 current_tb = NULL; /* avoid warning */
639 current_pc = 0; /* avoid warning */
640 current_cs_base = 0; /* avoid warning */
641 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000642 tb = p->first_tb;
643 while (tb != NULL) {
644 n = (long)tb & 3;
645 tb = (TranslationBlock *)((long)tb & ~3);
646 tb_next = tb->page_next[n];
647 /* NOTE: this is subtle as a TB may span two physical pages */
648 if (n == 0) {
649 /* NOTE: tb_end may be after the end of the page, but
650 it is not a problem */
651 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
652 tb_end = tb_start + tb->size;
653 } else {
654 tb_start = tb->page_addr[1];
655 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
656 }
657 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000658#ifdef TARGET_HAS_PRECISE_SMC
659 if (current_tb_not_found) {
660 current_tb_not_found = 0;
661 current_tb = NULL;
662 if (env->mem_write_pc) {
663 /* now we have a real cpu fault */
664 current_tb = tb_find_pc(env->mem_write_pc);
665 }
666 }
667 if (current_tb == tb &&
668 !(current_tb->cflags & CF_SINGLE_INSN)) {
669 /* If we are modifying the current TB, we must stop
670 its execution. We could be more precise by checking
671 that the modification is after the current PC, but it
672 would require a specialized function to partially
673 restore the CPU state */
674
675 current_tb_modified = 1;
676 cpu_restore_state(current_tb, env,
677 env->mem_write_pc, NULL);
678#if defined(TARGET_I386)
679 current_flags = env->hflags;
680 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
681 current_cs_base = (target_ulong)env->segs[R_CS].base;
682 current_pc = current_cs_base + env->eip;
683#else
684#error unsupported CPU
685#endif
686 }
687#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000688 /* we need to do that to handle the case where a signal
689 occurs while doing tb_phys_invalidate() */
690 saved_tb = NULL;
691 if (env) {
692 saved_tb = env->current_tb;
693 env->current_tb = NULL;
694 }
bellard9fa3e852004-01-04 18:06:42 +0000695 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000696 if (env) {
697 env->current_tb = saved_tb;
698 if (env->interrupt_request && env->current_tb)
699 cpu_interrupt(env, env->interrupt_request);
700 }
bellard9fa3e852004-01-04 18:06:42 +0000701 }
702 tb = tb_next;
703 }
704#if !defined(CONFIG_USER_ONLY)
705 /* if no code remaining, no need to continue to use slow writes */
706 if (!p->first_tb) {
707 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000708 if (is_cpu_write_access) {
709 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
710 }
711 }
712#endif
713#ifdef TARGET_HAS_PRECISE_SMC
714 if (current_tb_modified) {
715 /* we generate a block containing just the instruction
716 modifying the memory. It will ensure that it cannot modify
717 itself */
bellardea1c1802004-06-14 18:56:36 +0000718 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000719 tb_gen_code(env, current_pc, current_cs_base, current_flags,
720 CF_SINGLE_INSN);
721 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000722 }
723#endif
724}
725
726/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000727static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000728{
729 PageDesc *p;
730 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000731#if 0
bellarda4193c82004-06-03 14:01:43 +0000732 if (1) {
733 if (loglevel) {
734 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
735 cpu_single_env->mem_write_vaddr, len,
736 cpu_single_env->eip,
737 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
738 }
bellard59817cc2004-02-16 22:01:13 +0000739 }
740#endif
bellard9fa3e852004-01-04 18:06:42 +0000741 p = page_find(start >> TARGET_PAGE_BITS);
742 if (!p)
743 return;
744 if (p->code_bitmap) {
745 offset = start & ~TARGET_PAGE_MASK;
746 b = p->code_bitmap[offset >> 3] >> (offset & 7);
747 if (b & ((1 << len) - 1))
748 goto do_invalidate;
749 } else {
750 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000751 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000752 }
753}
754
bellard9fa3e852004-01-04 18:06:42 +0000755#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000756static void tb_invalidate_phys_page(target_ulong addr,
757 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000758{
bellardd720b932004-04-25 17:57:43 +0000759 int n, current_flags, current_tb_modified;
760 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000761 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000762 TranslationBlock *tb, *current_tb;
763#ifdef TARGET_HAS_PRECISE_SMC
764 CPUState *env = cpu_single_env;
765#endif
bellard9fa3e852004-01-04 18:06:42 +0000766
767 addr &= TARGET_PAGE_MASK;
768 p = page_find(addr >> TARGET_PAGE_BITS);
769 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000770 return;
771 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000772 current_tb_modified = 0;
773 current_tb = NULL;
774 current_pc = 0; /* avoid warning */
775 current_cs_base = 0; /* avoid warning */
776 current_flags = 0; /* avoid warning */
777#ifdef TARGET_HAS_PRECISE_SMC
778 if (tb && pc != 0) {
779 current_tb = tb_find_pc(pc);
780 }
781#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000782 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000783 n = (long)tb & 3;
784 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000785#ifdef TARGET_HAS_PRECISE_SMC
786 if (current_tb == tb &&
787 !(current_tb->cflags & CF_SINGLE_INSN)) {
788 /* If we are modifying the current TB, we must stop
789 its execution. We could be more precise by checking
790 that the modification is after the current PC, but it
791 would require a specialized function to partially
792 restore the CPU state */
793
794 current_tb_modified = 1;
795 cpu_restore_state(current_tb, env, pc, puc);
796#if defined(TARGET_I386)
797 current_flags = env->hflags;
798 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
799 current_cs_base = (target_ulong)env->segs[R_CS].base;
800 current_pc = current_cs_base + env->eip;
801#else
802#error unsupported CPU
803#endif
804 }
805#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000806 tb_phys_invalidate(tb, addr);
807 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000808 }
809 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000810#ifdef TARGET_HAS_PRECISE_SMC
811 if (current_tb_modified) {
812 /* we generate a block containing just the instruction
813 modifying the memory. It will ensure that it cannot modify
814 itself */
bellardea1c1802004-06-14 18:56:36 +0000815 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000816 tb_gen_code(env, current_pc, current_cs_base, current_flags,
817 CF_SINGLE_INSN);
818 cpu_resume_from_signal(env, puc);
819 }
820#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000821}
bellard9fa3e852004-01-04 18:06:42 +0000822#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000823
824/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000825static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000826 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000827{
828 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000829 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000830
bellard9fa3e852004-01-04 18:06:42 +0000831 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000832 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000833 tb->page_next[n] = p->first_tb;
834 last_first_tb = p->first_tb;
835 p->first_tb = (TranslationBlock *)((long)tb | n);
836 invalidate_page_bitmap(p);
837
bellard107db442004-06-22 18:48:46 +0000838#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000839
bellard9fa3e852004-01-04 18:06:42 +0000840#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000841 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +0000842 target_ulong addr;
843 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +0000844 int prot;
845
bellardfd6ce8f2003-05-14 19:00:11 +0000846 /* force the host page as non writable (writes will have a
847 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +0000848 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +0000849 prot = 0;
pbrook53a59602006-03-25 19:31:22 +0000850 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
851 addr += TARGET_PAGE_SIZE) {
852
853 p2 = page_find (addr >> TARGET_PAGE_BITS);
854 if (!p2)
855 continue;
856 prot |= p2->flags;
857 p2->flags &= ~PAGE_WRITE;
858 page_get_flags(addr);
859 }
860 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000861 (prot & PAGE_BITS) & ~PAGE_WRITE);
862#ifdef DEBUG_TB_INVALIDATE
863 printf("protecting code page: 0x%08lx\n",
pbrook53a59602006-03-25 19:31:22 +0000864 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +0000865#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000866 }
bellard9fa3e852004-01-04 18:06:42 +0000867#else
868 /* if some code is already present, then the pages are already
869 protected. So we handle the case where only the first TB is
870 allocated in a physical page */
871 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +0000872 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +0000873 }
874#endif
bellardd720b932004-04-25 17:57:43 +0000875
876#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000877}
878
879/* Allocate a new translation block. Flush the translation buffer if
880 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000881TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000882{
883 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000884
885 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
886 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000887 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000888 tb = &tbs[nb_tbs++];
889 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000890 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000891 return tb;
892}
893
bellard9fa3e852004-01-04 18:06:42 +0000894/* add a new TB and link it to the physical page tables. phys_page2 is
895 (-1) to indicate that only one page contains the TB. */
896void tb_link_phys(TranslationBlock *tb,
897 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000898{
bellard9fa3e852004-01-04 18:06:42 +0000899 unsigned int h;
900 TranslationBlock **ptb;
901
902 /* add in the physical hash table */
903 h = tb_phys_hash_func(phys_pc);
904 ptb = &tb_phys_hash[h];
905 tb->phys_hash_next = *ptb;
906 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000907
908 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000909 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
910 if (phys_page2 != -1)
911 tb_alloc_page(tb, 1, phys_page2);
912 else
913 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +0000914
bellardd4e81642003-05-25 16:46:15 +0000915 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
916 tb->jmp_next[0] = NULL;
917 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000918#ifdef USE_CODE_COPY
919 tb->cflags &= ~CF_FP_USED;
920 if (tb->cflags & CF_TB_FP_USED)
921 tb->cflags |= CF_FP_USED;
922#endif
bellardd4e81642003-05-25 16:46:15 +0000923
924 /* init original jump addresses */
925 if (tb->tb_next_offset[0] != 0xffff)
926 tb_reset_jump(tb, 0);
927 if (tb->tb_next_offset[1] != 0xffff)
928 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +0000929
930#ifdef DEBUG_TB_CHECK
931 tb_page_check();
932#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000933}
934
bellarda513fe12003-05-27 23:29:48 +0000935/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
936 tb[1].tc_ptr. Return NULL if not found */
937TranslationBlock *tb_find_pc(unsigned long tc_ptr)
938{
939 int m_min, m_max, m;
940 unsigned long v;
941 TranslationBlock *tb;
942
943 if (nb_tbs <= 0)
944 return NULL;
945 if (tc_ptr < (unsigned long)code_gen_buffer ||
946 tc_ptr >= (unsigned long)code_gen_ptr)
947 return NULL;
948 /* binary search (cf Knuth) */
949 m_min = 0;
950 m_max = nb_tbs - 1;
951 while (m_min <= m_max) {
952 m = (m_min + m_max) >> 1;
953 tb = &tbs[m];
954 v = (unsigned long)tb->tc_ptr;
955 if (v == tc_ptr)
956 return tb;
957 else if (tc_ptr < v) {
958 m_max = m - 1;
959 } else {
960 m_min = m + 1;
961 }
962 }
963 return &tbs[m_max];
964}
bellard75012672003-06-21 13:11:07 +0000965
bellardea041c02003-06-25 16:16:50 +0000966static void tb_reset_jump_recursive(TranslationBlock *tb);
967
968static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
969{
970 TranslationBlock *tb1, *tb_next, **ptb;
971 unsigned int n1;
972
973 tb1 = tb->jmp_next[n];
974 if (tb1 != NULL) {
975 /* find head of list */
976 for(;;) {
977 n1 = (long)tb1 & 3;
978 tb1 = (TranslationBlock *)((long)tb1 & ~3);
979 if (n1 == 2)
980 break;
981 tb1 = tb1->jmp_next[n1];
982 }
983 /* we are now sure now that tb jumps to tb1 */
984 tb_next = tb1;
985
986 /* remove tb from the jmp_first list */
987 ptb = &tb_next->jmp_first;
988 for(;;) {
989 tb1 = *ptb;
990 n1 = (long)tb1 & 3;
991 tb1 = (TranslationBlock *)((long)tb1 & ~3);
992 if (n1 == n && tb1 == tb)
993 break;
994 ptb = &tb1->jmp_next[n1];
995 }
996 *ptb = tb->jmp_next[n];
997 tb->jmp_next[n] = NULL;
998
999 /* suppress the jump to next tb in generated code */
1000 tb_reset_jump(tb, n);
1001
bellard01243112004-01-04 15:48:17 +00001002 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001003 tb_reset_jump_recursive(tb_next);
1004 }
1005}
1006
1007static void tb_reset_jump_recursive(TranslationBlock *tb)
1008{
1009 tb_reset_jump_recursive2(tb, 0);
1010 tb_reset_jump_recursive2(tb, 1);
1011}
1012
bellard1fddef42005-04-17 19:16:13 +00001013#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001014static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1015{
pbrookc2f07f82006-04-08 17:14:56 +00001016 target_ulong addr, pd;
1017 ram_addr_t ram_addr;
1018 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001019
pbrookc2f07f82006-04-08 17:14:56 +00001020 addr = cpu_get_phys_page_debug(env, pc);
1021 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1022 if (!p) {
1023 pd = IO_MEM_UNASSIGNED;
1024 } else {
1025 pd = p->phys_offset;
1026 }
1027 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001028 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001029}
bellardc27004e2005-01-03 23:35:10 +00001030#endif
bellardd720b932004-04-25 17:57:43 +00001031
bellardc33a3462003-07-29 20:50:33 +00001032/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1033 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001034int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001035{
bellard1fddef42005-04-17 19:16:13 +00001036#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001037 int i;
bellardd720b932004-04-25 17:57:43 +00001038
bellard4c3a88a2003-07-26 12:06:08 +00001039 for(i = 0; i < env->nb_breakpoints; i++) {
1040 if (env->breakpoints[i] == pc)
1041 return 0;
1042 }
1043
1044 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1045 return -1;
1046 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001047
1048 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001049 return 0;
1050#else
1051 return -1;
1052#endif
1053}
1054
1055/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001056int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001057{
bellard1fddef42005-04-17 19:16:13 +00001058#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001059 int i;
1060 for(i = 0; i < env->nb_breakpoints; i++) {
1061 if (env->breakpoints[i] == pc)
1062 goto found;
1063 }
1064 return -1;
1065 found:
bellard4c3a88a2003-07-26 12:06:08 +00001066 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001067 if (i < env->nb_breakpoints)
1068 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001069
1070 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001071 return 0;
1072#else
1073 return -1;
1074#endif
1075}
1076
bellardc33a3462003-07-29 20:50:33 +00001077/* enable or disable single step mode. EXCP_DEBUG is returned by the
1078 CPU loop after each instruction */
1079void cpu_single_step(CPUState *env, int enabled)
1080{
bellard1fddef42005-04-17 19:16:13 +00001081#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001082 if (env->singlestep_enabled != enabled) {
1083 env->singlestep_enabled = enabled;
1084 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001085 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001086 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001087 }
1088#endif
1089}
1090
bellard34865132003-10-05 14:28:56 +00001091/* enable or disable low levels log */
1092void cpu_set_log(int log_flags)
1093{
1094 loglevel = log_flags;
1095 if (loglevel && !logfile) {
1096 logfile = fopen(logfilename, "w");
1097 if (!logfile) {
1098 perror(logfilename);
1099 _exit(1);
1100 }
bellard9fa3e852004-01-04 18:06:42 +00001101#if !defined(CONFIG_SOFTMMU)
1102 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1103 {
1104 static uint8_t logfile_buf[4096];
1105 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1106 }
1107#else
bellard34865132003-10-05 14:28:56 +00001108 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001109#endif
bellard34865132003-10-05 14:28:56 +00001110 }
1111}
1112
1113void cpu_set_log_filename(const char *filename)
1114{
1115 logfilename = strdup(filename);
1116}
bellardc33a3462003-07-29 20:50:33 +00001117
bellard01243112004-01-04 15:48:17 +00001118/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001119void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001120{
1121 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001122 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001123
bellard68a79312003-06-30 13:12:32 +00001124 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001125 /* if the cpu is currently executing code, we must unlink it and
1126 all the potentially executing TB */
1127 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001128 if (tb && !testandset(&interrupt_lock)) {
1129 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001130 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001131 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001132 }
1133}
1134
bellardb54ad042004-05-20 13:42:52 +00001135void cpu_reset_interrupt(CPUState *env, int mask)
1136{
1137 env->interrupt_request &= ~mask;
1138}
1139
bellardf193c792004-03-21 17:06:25 +00001140CPULogItem cpu_log_items[] = {
1141 { CPU_LOG_TB_OUT_ASM, "out_asm",
1142 "show generated host assembly code for each compiled TB" },
1143 { CPU_LOG_TB_IN_ASM, "in_asm",
1144 "show target assembly code for each compiled TB" },
1145 { CPU_LOG_TB_OP, "op",
1146 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1147#ifdef TARGET_I386
1148 { CPU_LOG_TB_OP_OPT, "op_opt",
1149 "show micro ops after optimization for each compiled TB" },
1150#endif
1151 { CPU_LOG_INT, "int",
1152 "show interrupts/exceptions in short format" },
1153 { CPU_LOG_EXEC, "exec",
1154 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001155 { CPU_LOG_TB_CPU, "cpu",
1156 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001157#ifdef TARGET_I386
1158 { CPU_LOG_PCALL, "pcall",
1159 "show protected mode far calls/returns/exceptions" },
1160#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001161#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001162 { CPU_LOG_IOPORT, "ioport",
1163 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001164#endif
bellardf193c792004-03-21 17:06:25 +00001165 { 0, NULL, NULL },
1166};
1167
1168static int cmp1(const char *s1, int n, const char *s2)
1169{
1170 if (strlen(s2) != n)
1171 return 0;
1172 return memcmp(s1, s2, n) == 0;
1173}
1174
1175/* takes a comma separated list of log masks. Return 0 if error. */
1176int cpu_str_to_log_mask(const char *str)
1177{
1178 CPULogItem *item;
1179 int mask;
1180 const char *p, *p1;
1181
1182 p = str;
1183 mask = 0;
1184 for(;;) {
1185 p1 = strchr(p, ',');
1186 if (!p1)
1187 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001188 if(cmp1(p,p1-p,"all")) {
1189 for(item = cpu_log_items; item->mask != 0; item++) {
1190 mask |= item->mask;
1191 }
1192 } else {
bellardf193c792004-03-21 17:06:25 +00001193 for(item = cpu_log_items; item->mask != 0; item++) {
1194 if (cmp1(p, p1 - p, item->name))
1195 goto found;
1196 }
1197 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001198 }
bellardf193c792004-03-21 17:06:25 +00001199 found:
1200 mask |= item->mask;
1201 if (*p1 != ',')
1202 break;
1203 p = p1 + 1;
1204 }
1205 return mask;
1206}
bellardea041c02003-06-25 16:16:50 +00001207
bellard75012672003-06-21 13:11:07 +00001208void cpu_abort(CPUState *env, const char *fmt, ...)
1209{
1210 va_list ap;
1211
1212 va_start(ap, fmt);
1213 fprintf(stderr, "qemu: fatal: ");
1214 vfprintf(stderr, fmt, ap);
1215 fprintf(stderr, "\n");
1216#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001217 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1218#else
1219 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001220#endif
1221 va_end(ap);
1222 abort();
1223}
1224
bellard01243112004-01-04 15:48:17 +00001225#if !defined(CONFIG_USER_ONLY)
1226
bellardee8b7022004-02-03 23:35:10 +00001227/* NOTE: if flush_global is true, also flush global entries (not
1228 implemented yet) */
1229void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001230{
bellard33417e72003-08-10 21:47:01 +00001231 int i;
bellard01243112004-01-04 15:48:17 +00001232
bellard9fa3e852004-01-04 18:06:42 +00001233#if defined(DEBUG_TLB)
1234 printf("tlb_flush:\n");
1235#endif
bellard01243112004-01-04 15:48:17 +00001236 /* must reset current TB so that interrupts cannot modify the
1237 links while we are modifying them */
1238 env->current_tb = NULL;
1239
bellard33417e72003-08-10 21:47:01 +00001240 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001241 env->tlb_table[0][i].addr_read = -1;
1242 env->tlb_table[0][i].addr_write = -1;
1243 env->tlb_table[0][i].addr_code = -1;
1244 env->tlb_table[1][i].addr_read = -1;
1245 env->tlb_table[1][i].addr_write = -1;
1246 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001247 }
bellard9fa3e852004-01-04 18:06:42 +00001248
bellard8a40a182005-11-20 10:35:40 +00001249 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001250
1251#if !defined(CONFIG_SOFTMMU)
1252 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1253#endif
bellard0a962c02005-02-10 22:00:27 +00001254#ifdef USE_KQEMU
1255 if (env->kqemu_enabled) {
1256 kqemu_flush(env, flush_global);
1257 }
1258#endif
bellarde3db7222005-01-26 22:00:47 +00001259 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001260}
1261
bellard274da6b2004-05-20 21:56:27 +00001262static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001263{
bellard84b7b8e2005-11-28 21:19:04 +00001264 if (addr == (tlb_entry->addr_read &
1265 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1266 addr == (tlb_entry->addr_write &
1267 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1268 addr == (tlb_entry->addr_code &
1269 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1270 tlb_entry->addr_read = -1;
1271 tlb_entry->addr_write = -1;
1272 tlb_entry->addr_code = -1;
1273 }
bellard61382a52003-10-27 21:22:23 +00001274}
1275
bellard2e126692004-04-25 21:28:44 +00001276void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001277{
bellard8a40a182005-11-20 10:35:40 +00001278 int i;
bellard9fa3e852004-01-04 18:06:42 +00001279 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001280
bellard9fa3e852004-01-04 18:06:42 +00001281#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001282 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001283#endif
bellard01243112004-01-04 15:48:17 +00001284 /* must reset current TB so that interrupts cannot modify the
1285 links while we are modifying them */
1286 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001287
bellard61382a52003-10-27 21:22:23 +00001288 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001289 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001290 tlb_flush_entry(&env->tlb_table[0][i], addr);
1291 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001292
pbrookb362e5e2006-11-12 20:40:55 +00001293 /* Discard jump cache entries for any tb which might potentially
1294 overlap the flushed page. */
1295 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1296 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1297
1298 i = tb_jmp_cache_hash_page(addr);
1299 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001300
bellard01243112004-01-04 15:48:17 +00001301#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001302 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001303 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001304#endif
bellard0a962c02005-02-10 22:00:27 +00001305#ifdef USE_KQEMU
1306 if (env->kqemu_enabled) {
1307 kqemu_flush_page(env, addr);
1308 }
1309#endif
bellard9fa3e852004-01-04 18:06:42 +00001310}
1311
bellard9fa3e852004-01-04 18:06:42 +00001312/* update the TLBs so that writes to code in the virtual page 'addr'
1313 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001314static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001315{
bellard6a00d602005-11-21 23:25:50 +00001316 cpu_physical_memory_reset_dirty(ram_addr,
1317 ram_addr + TARGET_PAGE_SIZE,
1318 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001319}
1320
bellard9fa3e852004-01-04 18:06:42 +00001321/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001322 tested for self modifying code */
1323static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1324 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001325{
bellard3a7d9292005-08-21 09:26:42 +00001326 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001327}
1328
1329static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1330 unsigned long start, unsigned long length)
1331{
1332 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001333 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1334 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001335 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001336 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001337 }
1338 }
1339}
1340
bellard3a7d9292005-08-21 09:26:42 +00001341void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001342 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001343{
1344 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001345 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001346 int i, mask, len;
1347 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001348
1349 start &= TARGET_PAGE_MASK;
1350 end = TARGET_PAGE_ALIGN(end);
1351
1352 length = end - start;
1353 if (length == 0)
1354 return;
bellard0a962c02005-02-10 22:00:27 +00001355 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001356#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001357 /* XXX: should not depend on cpu context */
1358 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001359 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001360 ram_addr_t addr;
1361 addr = start;
1362 for(i = 0; i < len; i++) {
1363 kqemu_set_notdirty(env, addr);
1364 addr += TARGET_PAGE_SIZE;
1365 }
bellard3a7d9292005-08-21 09:26:42 +00001366 }
1367#endif
bellardf23db162005-08-21 19:12:28 +00001368 mask = ~dirty_flags;
1369 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1370 for(i = 0; i < len; i++)
1371 p[i] &= mask;
1372
bellard1ccde1c2004-02-06 19:46:14 +00001373 /* we modify the TLB cache so that the dirty bit will be set again
1374 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001375 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001376 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1377 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001378 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001379 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001380 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001381 }
bellard59817cc2004-02-16 22:01:13 +00001382
1383#if !defined(CONFIG_SOFTMMU)
1384 /* XXX: this is expensive */
1385 {
1386 VirtPageDesc *p;
1387 int j;
1388 target_ulong addr;
1389
1390 for(i = 0; i < L1_SIZE; i++) {
1391 p = l1_virt_map[i];
1392 if (p) {
1393 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1394 for(j = 0; j < L2_SIZE; j++) {
1395 if (p->valid_tag == virt_valid_tag &&
1396 p->phys_addr >= start && p->phys_addr < end &&
1397 (p->prot & PROT_WRITE)) {
1398 if (addr < MMAP_AREA_END) {
1399 mprotect((void *)addr, TARGET_PAGE_SIZE,
1400 p->prot & ~PROT_WRITE);
1401 }
1402 }
1403 addr += TARGET_PAGE_SIZE;
1404 p++;
1405 }
1406 }
1407 }
1408 }
1409#endif
bellard1ccde1c2004-02-06 19:46:14 +00001410}
1411
bellard3a7d9292005-08-21 09:26:42 +00001412static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1413{
1414 ram_addr_t ram_addr;
1415
bellard84b7b8e2005-11-28 21:19:04 +00001416 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1417 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001418 tlb_entry->addend - (unsigned long)phys_ram_base;
1419 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001420 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001421 }
1422 }
1423}
1424
1425/* update the TLB according to the current state of the dirty bits */
1426void cpu_tlb_update_dirty(CPUState *env)
1427{
1428 int i;
1429 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001430 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001431 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001432 tlb_update_dirty(&env->tlb_table[1][i]);
bellard3a7d9292005-08-21 09:26:42 +00001433}
1434
bellard1ccde1c2004-02-06 19:46:14 +00001435static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001436 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001437{
1438 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001439 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1440 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001441 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001442 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001443 }
1444 }
1445}
1446
1447/* update the TLB corresponding to virtual page vaddr and phys addr
1448 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001449static inline void tlb_set_dirty(CPUState *env,
1450 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001451{
bellard1ccde1c2004-02-06 19:46:14 +00001452 int i;
1453
bellard1ccde1c2004-02-06 19:46:14 +00001454 addr &= TARGET_PAGE_MASK;
1455 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001456 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1457 tlb_set_dirty1(&env->tlb_table[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001458}
1459
bellard59817cc2004-02-16 22:01:13 +00001460/* add a new TLB entry. At most one entry for a given virtual address
1461 is permitted. Return 0 if OK or 2 if the page could not be mapped
1462 (can only happen in non SOFTMMU mode for I/O pages or pages
1463 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001464int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1465 target_phys_addr_t paddr, int prot,
1466 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001467{
bellard92e873b2004-05-21 14:52:29 +00001468 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001469 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001470 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001471 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001472 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001473 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001474 CPUTLBEntry *te;
bellard9fa3e852004-01-04 18:06:42 +00001475
bellard92e873b2004-05-21 14:52:29 +00001476 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001477 if (!p) {
1478 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001479 } else {
1480 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001481 }
1482#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001483 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 +00001484 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001485#endif
1486
1487 ret = 0;
1488#if !defined(CONFIG_SOFTMMU)
1489 if (is_softmmu)
1490#endif
1491 {
bellard2a4188a2006-06-25 21:54:59 +00001492 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001493 /* IO memory case */
1494 address = vaddr | pd;
1495 addend = paddr;
1496 } else {
1497 /* standard memory */
1498 address = vaddr;
1499 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1500 }
1501
bellard90f18422005-07-24 10:17:31 +00001502 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001503 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001504 te = &env->tlb_table[is_user][index];
1505 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001506 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001507 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001508 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001509 te->addr_read = -1;
1510 }
1511 if (prot & PAGE_EXEC) {
1512 te->addr_code = address;
1513 } else {
1514 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001515 }
bellard67b915a2004-03-31 23:37:16 +00001516 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001517 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1518 (pd & IO_MEM_ROMD)) {
1519 /* write access calls the I/O callback */
1520 te->addr_write = vaddr |
1521 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001522 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001523 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001524 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001525 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001526 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001527 }
1528 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001529 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001530 }
1531 }
1532#if !defined(CONFIG_SOFTMMU)
1533 else {
1534 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1535 /* IO access: no mapping is done as it will be handled by the
1536 soft MMU */
1537 if (!(env->hflags & HF_SOFTMMU_MASK))
1538 ret = 2;
1539 } else {
1540 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001541
bellard59817cc2004-02-16 22:01:13 +00001542 if (vaddr >= MMAP_AREA_END) {
1543 ret = 2;
1544 } else {
1545 if (prot & PROT_WRITE) {
1546 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001547#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001548 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001549#endif
bellard59817cc2004-02-16 22:01:13 +00001550 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1551 !cpu_physical_memory_is_dirty(pd))) {
1552 /* ROM: we do as if code was inside */
1553 /* if code is present, we only map as read only and save the
1554 original mapping */
1555 VirtPageDesc *vp;
1556
bellard90f18422005-07-24 10:17:31 +00001557 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001558 vp->phys_addr = pd;
1559 vp->prot = prot;
1560 vp->valid_tag = virt_valid_tag;
1561 prot &= ~PAGE_WRITE;
1562 }
bellard9fa3e852004-01-04 18:06:42 +00001563 }
bellard59817cc2004-02-16 22:01:13 +00001564 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1565 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1566 if (map_addr == MAP_FAILED) {
1567 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1568 paddr, vaddr);
1569 }
bellard9fa3e852004-01-04 18:06:42 +00001570 }
1571 }
1572 }
1573#endif
1574 return ret;
1575}
1576
1577/* called from signal handler: invalidate the code and unprotect the
1578 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001579int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001580{
1581#if !defined(CONFIG_SOFTMMU)
1582 VirtPageDesc *vp;
1583
1584#if defined(DEBUG_TLB)
1585 printf("page_unprotect: addr=0x%08x\n", addr);
1586#endif
1587 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001588
1589 /* if it is not mapped, no need to worry here */
1590 if (addr >= MMAP_AREA_END)
1591 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001592 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1593 if (!vp)
1594 return 0;
1595 /* NOTE: in this case, validate_tag is _not_ tested as it
1596 validates only the code TLB */
1597 if (vp->valid_tag != virt_valid_tag)
1598 return 0;
1599 if (!(vp->prot & PAGE_WRITE))
1600 return 0;
1601#if defined(DEBUG_TLB)
1602 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1603 addr, vp->phys_addr, vp->prot);
1604#endif
bellard59817cc2004-02-16 22:01:13 +00001605 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1606 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1607 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001608 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001609 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001610 /* flush the code inside */
1611 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001612 return 1;
1613#else
1614 return 0;
1615#endif
bellard33417e72003-08-10 21:47:01 +00001616}
1617
bellard01243112004-01-04 15:48:17 +00001618#else
1619
bellardee8b7022004-02-03 23:35:10 +00001620void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001621{
1622}
1623
bellard2e126692004-04-25 21:28:44 +00001624void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001625{
1626}
1627
bellard84b7b8e2005-11-28 21:19:04 +00001628int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1629 target_phys_addr_t paddr, int prot,
1630 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001631{
bellard9fa3e852004-01-04 18:06:42 +00001632 return 0;
1633}
bellard33417e72003-08-10 21:47:01 +00001634
bellard9fa3e852004-01-04 18:06:42 +00001635/* dump memory mappings */
1636void page_dump(FILE *f)
1637{
1638 unsigned long start, end;
1639 int i, j, prot, prot1;
1640 PageDesc *p;
1641
1642 fprintf(f, "%-8s %-8s %-8s %s\n",
1643 "start", "end", "size", "prot");
1644 start = -1;
1645 end = -1;
1646 prot = 0;
1647 for(i = 0; i <= L1_SIZE; i++) {
1648 if (i < L1_SIZE)
1649 p = l1_map[i];
1650 else
1651 p = NULL;
1652 for(j = 0;j < L2_SIZE; j++) {
1653 if (!p)
1654 prot1 = 0;
1655 else
1656 prot1 = p[j].flags;
1657 if (prot1 != prot) {
1658 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1659 if (start != -1) {
1660 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1661 start, end, end - start,
1662 prot & PAGE_READ ? 'r' : '-',
1663 prot & PAGE_WRITE ? 'w' : '-',
1664 prot & PAGE_EXEC ? 'x' : '-');
1665 }
1666 if (prot1 != 0)
1667 start = end;
1668 else
1669 start = -1;
1670 prot = prot1;
1671 }
1672 if (!p)
1673 break;
1674 }
bellard33417e72003-08-10 21:47:01 +00001675 }
bellard33417e72003-08-10 21:47:01 +00001676}
1677
pbrook53a59602006-03-25 19:31:22 +00001678int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001679{
bellard9fa3e852004-01-04 18:06:42 +00001680 PageDesc *p;
1681
1682 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001683 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001684 return 0;
1685 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001686}
1687
bellard9fa3e852004-01-04 18:06:42 +00001688/* modify the flags of a page and invalidate the code if
1689 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1690 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001691void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001692{
1693 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001694 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001695
1696 start = start & TARGET_PAGE_MASK;
1697 end = TARGET_PAGE_ALIGN(end);
1698 if (flags & PAGE_WRITE)
1699 flags |= PAGE_WRITE_ORG;
1700 spin_lock(&tb_lock);
1701 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1702 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1703 /* if the write protection is set, then we invalidate the code
1704 inside */
1705 if (!(p->flags & PAGE_WRITE) &&
1706 (flags & PAGE_WRITE) &&
1707 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001708 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001709 }
1710 p->flags = flags;
1711 }
1712 spin_unlock(&tb_lock);
1713}
1714
1715/* called from signal handler: invalidate the code and unprotect the
1716 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001717int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001718{
1719 unsigned int page_index, prot, pindex;
1720 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001721 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001722
bellard83fb7ad2004-07-05 21:25:26 +00001723 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001724 page_index = host_start >> TARGET_PAGE_BITS;
1725 p1 = page_find(page_index);
1726 if (!p1)
1727 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001728 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001729 p = p1;
1730 prot = 0;
1731 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1732 prot |= p->flags;
1733 p++;
1734 }
1735 /* if the page was really writable, then we change its
1736 protection back to writable */
1737 if (prot & PAGE_WRITE_ORG) {
1738 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1739 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001740 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001741 (prot & PAGE_BITS) | PAGE_WRITE);
1742 p1[pindex].flags |= PAGE_WRITE;
1743 /* and since the content will be modified, we must invalidate
1744 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001745 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001746#ifdef DEBUG_TB_CHECK
1747 tb_invalidate_check(address);
1748#endif
1749 return 1;
1750 }
1751 }
1752 return 0;
1753}
1754
1755/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001756/* ??? This should be redundant now we have lock_user. */
1757void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001758{
pbrook53a59602006-03-25 19:31:22 +00001759 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001760
pbrook53a59602006-03-25 19:31:22 +00001761 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001762 end = start + data_size;
1763 start &= TARGET_PAGE_MASK;
1764 end = TARGET_PAGE_ALIGN(end);
1765 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001766 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001767 }
1768}
1769
bellard6a00d602005-11-21 23:25:50 +00001770static inline void tlb_set_dirty(CPUState *env,
1771 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001772{
1773}
bellard9fa3e852004-01-04 18:06:42 +00001774#endif /* defined(CONFIG_USER_ONLY) */
1775
bellard33417e72003-08-10 21:47:01 +00001776/* register physical memory. 'size' must be a multiple of the target
1777 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1778 io memory page */
bellard2e126692004-04-25 21:28:44 +00001779void cpu_register_physical_memory(target_phys_addr_t start_addr,
1780 unsigned long size,
1781 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001782{
bellard108c49b2005-07-24 12:55:09 +00001783 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001784 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001785 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001786
bellard5fd386f2004-05-23 21:11:22 +00001787 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001788 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001789 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001790 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001791 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001792 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1793 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001794 phys_offset += TARGET_PAGE_SIZE;
1795 }
bellard9d420372006-06-25 22:25:22 +00001796
1797 /* since each CPU stores ram addresses in its TLB cache, we must
1798 reset the modified entries */
1799 /* XXX: slow ! */
1800 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1801 tlb_flush(env, 1);
1802 }
bellard33417e72003-08-10 21:47:01 +00001803}
1804
bellardba863452006-09-24 18:41:10 +00001805/* XXX: temporary until new memory mapping API */
1806uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1807{
1808 PhysPageDesc *p;
1809
1810 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1811 if (!p)
1812 return IO_MEM_UNASSIGNED;
1813 return p->phys_offset;
1814}
1815
bellarde9a1ab12007-02-08 23:08:38 +00001816/* XXX: better than nothing */
1817ram_addr_t qemu_ram_alloc(unsigned int size)
1818{
1819 ram_addr_t addr;
1820 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1821 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
1822 size, phys_ram_size);
1823 abort();
1824 }
1825 addr = phys_ram_alloc_offset;
1826 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1827 return addr;
1828}
1829
1830void qemu_ram_free(ram_addr_t addr)
1831{
1832}
1833
bellarda4193c82004-06-03 14:01:43 +00001834static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001835{
pbrook67d3b952006-12-18 05:03:52 +00001836#ifdef DEBUG_UNASSIGNED
1837 printf("Unassigned mem read 0x%08x\n", (int)addr);
1838#endif
bellard33417e72003-08-10 21:47:01 +00001839 return 0;
1840}
1841
bellarda4193c82004-06-03 14:01:43 +00001842static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001843{
pbrook67d3b952006-12-18 05:03:52 +00001844#ifdef DEBUG_UNASSIGNED
1845 printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
1846#endif
bellard33417e72003-08-10 21:47:01 +00001847}
1848
1849static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1850 unassigned_mem_readb,
1851 unassigned_mem_readb,
1852 unassigned_mem_readb,
1853};
1854
1855static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1856 unassigned_mem_writeb,
1857 unassigned_mem_writeb,
1858 unassigned_mem_writeb,
1859};
1860
bellarda4193c82004-06-03 14:01:43 +00001861static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001862{
bellard3a7d9292005-08-21 09:26:42 +00001863 unsigned long ram_addr;
1864 int dirty_flags;
1865 ram_addr = addr - (unsigned long)phys_ram_base;
1866 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1867 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1868#if !defined(CONFIG_USER_ONLY)
1869 tb_invalidate_phys_page_fast(ram_addr, 1);
1870 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1871#endif
1872 }
bellardc27004e2005-01-03 23:35:10 +00001873 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001874#ifdef USE_KQEMU
1875 if (cpu_single_env->kqemu_enabled &&
1876 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1877 kqemu_modify_page(cpu_single_env, ram_addr);
1878#endif
bellardf23db162005-08-21 19:12:28 +00001879 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1880 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1881 /* we remove the notdirty callback only if the code has been
1882 flushed */
1883 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001884 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001885}
1886
bellarda4193c82004-06-03 14:01:43 +00001887static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001888{
bellard3a7d9292005-08-21 09:26:42 +00001889 unsigned long ram_addr;
1890 int dirty_flags;
1891 ram_addr = addr - (unsigned long)phys_ram_base;
1892 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1893 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1894#if !defined(CONFIG_USER_ONLY)
1895 tb_invalidate_phys_page_fast(ram_addr, 2);
1896 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1897#endif
1898 }
bellardc27004e2005-01-03 23:35:10 +00001899 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001900#ifdef USE_KQEMU
1901 if (cpu_single_env->kqemu_enabled &&
1902 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1903 kqemu_modify_page(cpu_single_env, ram_addr);
1904#endif
bellardf23db162005-08-21 19:12:28 +00001905 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1906 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1907 /* we remove the notdirty callback only if the code has been
1908 flushed */
1909 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001910 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001911}
1912
bellarda4193c82004-06-03 14:01:43 +00001913static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001914{
bellard3a7d9292005-08-21 09:26:42 +00001915 unsigned long ram_addr;
1916 int dirty_flags;
1917 ram_addr = addr - (unsigned long)phys_ram_base;
1918 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1919 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1920#if !defined(CONFIG_USER_ONLY)
1921 tb_invalidate_phys_page_fast(ram_addr, 4);
1922 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1923#endif
1924 }
bellardc27004e2005-01-03 23:35:10 +00001925 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001926#ifdef USE_KQEMU
1927 if (cpu_single_env->kqemu_enabled &&
1928 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1929 kqemu_modify_page(cpu_single_env, ram_addr);
1930#endif
bellardf23db162005-08-21 19:12:28 +00001931 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1932 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1933 /* we remove the notdirty callback only if the code has been
1934 flushed */
1935 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001936 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001937}
1938
bellard3a7d9292005-08-21 09:26:42 +00001939static CPUReadMemoryFunc *error_mem_read[3] = {
1940 NULL, /* never used */
1941 NULL, /* never used */
1942 NULL, /* never used */
1943};
1944
bellard1ccde1c2004-02-06 19:46:14 +00001945static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1946 notdirty_mem_writeb,
1947 notdirty_mem_writew,
1948 notdirty_mem_writel,
1949};
1950
bellard33417e72003-08-10 21:47:01 +00001951static void io_mem_init(void)
1952{
bellard3a7d9292005-08-21 09:26:42 +00001953 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001954 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001955 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001956 io_mem_nb = 5;
1957
1958 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001959 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001960 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001961}
1962
1963/* mem_read and mem_write are arrays of functions containing the
1964 function to access byte (index 0), word (index 1) and dword (index
1965 2). All functions must be supplied. If io_index is non zero, the
1966 corresponding io zone is modified. If it is zero, a new io zone is
1967 allocated. The return value can be used with
1968 cpu_register_physical_memory(). (-1) is returned if error. */
1969int cpu_register_io_memory(int io_index,
1970 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001971 CPUWriteMemoryFunc **mem_write,
1972 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001973{
1974 int i;
1975
1976 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00001977 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00001978 return -1;
1979 io_index = io_mem_nb++;
1980 } else {
1981 if (io_index >= IO_MEM_NB_ENTRIES)
1982 return -1;
1983 }
bellardb5ff1b32005-11-26 10:38:39 +00001984
bellard33417e72003-08-10 21:47:01 +00001985 for(i = 0;i < 3; i++) {
1986 io_mem_read[io_index][i] = mem_read[i];
1987 io_mem_write[io_index][i] = mem_write[i];
1988 }
bellarda4193c82004-06-03 14:01:43 +00001989 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001990 return io_index << IO_MEM_SHIFT;
1991}
bellard61382a52003-10-27 21:22:23 +00001992
bellard8926b512004-10-10 15:14:20 +00001993CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1994{
1995 return io_mem_write[io_index >> IO_MEM_SHIFT];
1996}
1997
1998CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
1999{
2000 return io_mem_read[io_index >> IO_MEM_SHIFT];
2001}
2002
bellard13eb76e2004-01-24 15:23:36 +00002003/* physical memory access (slow version, mainly for debug) */
2004#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002005void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002006 int len, int is_write)
2007{
2008 int l, flags;
2009 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002010 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002011
2012 while (len > 0) {
2013 page = addr & TARGET_PAGE_MASK;
2014 l = (page + TARGET_PAGE_SIZE) - addr;
2015 if (l > len)
2016 l = len;
2017 flags = page_get_flags(page);
2018 if (!(flags & PAGE_VALID))
2019 return;
2020 if (is_write) {
2021 if (!(flags & PAGE_WRITE))
2022 return;
pbrook53a59602006-03-25 19:31:22 +00002023 p = lock_user(addr, len, 0);
2024 memcpy(p, buf, len);
2025 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002026 } else {
2027 if (!(flags & PAGE_READ))
2028 return;
pbrook53a59602006-03-25 19:31:22 +00002029 p = lock_user(addr, len, 1);
2030 memcpy(buf, p, len);
2031 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002032 }
2033 len -= l;
2034 buf += l;
2035 addr += l;
2036 }
2037}
bellard8df1cd02005-01-28 22:37:22 +00002038
bellard13eb76e2004-01-24 15:23:36 +00002039#else
bellard2e126692004-04-25 21:28:44 +00002040void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002041 int len, int is_write)
2042{
2043 int l, io_index;
2044 uint8_t *ptr;
2045 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002046 target_phys_addr_t page;
2047 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002048 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002049
2050 while (len > 0) {
2051 page = addr & TARGET_PAGE_MASK;
2052 l = (page + TARGET_PAGE_SIZE) - addr;
2053 if (l > len)
2054 l = len;
bellard92e873b2004-05-21 14:52:29 +00002055 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002056 if (!p) {
2057 pd = IO_MEM_UNASSIGNED;
2058 } else {
2059 pd = p->phys_offset;
2060 }
2061
2062 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002063 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002064 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002065 /* XXX: could force cpu_single_env to NULL to avoid
2066 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002067 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002068 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002069 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002070 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002071 l = 4;
2072 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002073 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002074 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002075 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002076 l = 2;
2077 } else {
bellard1c213d12005-09-03 10:49:04 +00002078 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002079 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002080 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002081 l = 1;
2082 }
2083 } else {
bellardb448f2f2004-02-25 23:24:04 +00002084 unsigned long addr1;
2085 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002086 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002087 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002088 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002089 if (!cpu_physical_memory_is_dirty(addr1)) {
2090 /* invalidate code */
2091 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2092 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002093 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2094 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002095 }
bellard13eb76e2004-01-24 15:23:36 +00002096 }
2097 } else {
bellard2a4188a2006-06-25 21:54:59 +00002098 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2099 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002100 /* I/O case */
2101 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2102 if (l >= 4 && ((addr & 3) == 0)) {
2103 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002104 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002105 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002106 l = 4;
2107 } else if (l >= 2 && ((addr & 1) == 0)) {
2108 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002109 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002110 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002111 l = 2;
2112 } else {
bellard1c213d12005-09-03 10:49:04 +00002113 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002114 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002115 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002116 l = 1;
2117 }
2118 } else {
2119 /* RAM case */
2120 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2121 (addr & ~TARGET_PAGE_MASK);
2122 memcpy(buf, ptr, l);
2123 }
2124 }
2125 len -= l;
2126 buf += l;
2127 addr += l;
2128 }
2129}
bellard8df1cd02005-01-28 22:37:22 +00002130
bellardd0ecd2a2006-04-23 17:14:48 +00002131/* used for ROM loading : can write in RAM and ROM */
2132void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2133 const uint8_t *buf, int len)
2134{
2135 int l;
2136 uint8_t *ptr;
2137 target_phys_addr_t page;
2138 unsigned long pd;
2139 PhysPageDesc *p;
2140
2141 while (len > 0) {
2142 page = addr & TARGET_PAGE_MASK;
2143 l = (page + TARGET_PAGE_SIZE) - addr;
2144 if (l > len)
2145 l = len;
2146 p = phys_page_find(page >> TARGET_PAGE_BITS);
2147 if (!p) {
2148 pd = IO_MEM_UNASSIGNED;
2149 } else {
2150 pd = p->phys_offset;
2151 }
2152
2153 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002154 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2155 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002156 /* do nothing */
2157 } else {
2158 unsigned long addr1;
2159 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2160 /* ROM/RAM case */
2161 ptr = phys_ram_base + addr1;
2162 memcpy(ptr, buf, l);
2163 }
2164 len -= l;
2165 buf += l;
2166 addr += l;
2167 }
2168}
2169
2170
bellard8df1cd02005-01-28 22:37:22 +00002171/* warning: addr must be aligned */
2172uint32_t ldl_phys(target_phys_addr_t addr)
2173{
2174 int io_index;
2175 uint8_t *ptr;
2176 uint32_t val;
2177 unsigned long pd;
2178 PhysPageDesc *p;
2179
2180 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2181 if (!p) {
2182 pd = IO_MEM_UNASSIGNED;
2183 } else {
2184 pd = p->phys_offset;
2185 }
2186
bellard2a4188a2006-06-25 21:54:59 +00002187 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2188 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002189 /* I/O case */
2190 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2191 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2192 } else {
2193 /* RAM case */
2194 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2195 (addr & ~TARGET_PAGE_MASK);
2196 val = ldl_p(ptr);
2197 }
2198 return val;
2199}
2200
bellard84b7b8e2005-11-28 21:19:04 +00002201/* warning: addr must be aligned */
2202uint64_t ldq_phys(target_phys_addr_t addr)
2203{
2204 int io_index;
2205 uint8_t *ptr;
2206 uint64_t val;
2207 unsigned long pd;
2208 PhysPageDesc *p;
2209
2210 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2211 if (!p) {
2212 pd = IO_MEM_UNASSIGNED;
2213 } else {
2214 pd = p->phys_offset;
2215 }
2216
bellard2a4188a2006-06-25 21:54:59 +00002217 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2218 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002219 /* I/O case */
2220 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2221#ifdef TARGET_WORDS_BIGENDIAN
2222 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2223 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2224#else
2225 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2226 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2227#endif
2228 } else {
2229 /* RAM case */
2230 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2231 (addr & ~TARGET_PAGE_MASK);
2232 val = ldq_p(ptr);
2233 }
2234 return val;
2235}
2236
bellardaab33092005-10-30 20:48:42 +00002237/* XXX: optimize */
2238uint32_t ldub_phys(target_phys_addr_t addr)
2239{
2240 uint8_t val;
2241 cpu_physical_memory_read(addr, &val, 1);
2242 return val;
2243}
2244
2245/* XXX: optimize */
2246uint32_t lduw_phys(target_phys_addr_t addr)
2247{
2248 uint16_t val;
2249 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2250 return tswap16(val);
2251}
2252
bellard8df1cd02005-01-28 22:37:22 +00002253/* warning: addr must be aligned. The ram page is not masked as dirty
2254 and the code inside is not invalidated. It is useful if the dirty
2255 bits are used to track modified PTEs */
2256void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2257{
2258 int io_index;
2259 uint8_t *ptr;
2260 unsigned long pd;
2261 PhysPageDesc *p;
2262
2263 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2264 if (!p) {
2265 pd = IO_MEM_UNASSIGNED;
2266 } else {
2267 pd = p->phys_offset;
2268 }
2269
bellard3a7d9292005-08-21 09:26:42 +00002270 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002271 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2272 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2273 } else {
2274 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2275 (addr & ~TARGET_PAGE_MASK);
2276 stl_p(ptr, val);
2277 }
2278}
2279
2280/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002281void stl_phys(target_phys_addr_t addr, uint32_t val)
2282{
2283 int io_index;
2284 uint8_t *ptr;
2285 unsigned long pd;
2286 PhysPageDesc *p;
2287
2288 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2289 if (!p) {
2290 pd = IO_MEM_UNASSIGNED;
2291 } else {
2292 pd = p->phys_offset;
2293 }
2294
bellard3a7d9292005-08-21 09:26:42 +00002295 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002296 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2297 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2298 } else {
2299 unsigned long addr1;
2300 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2301 /* RAM case */
2302 ptr = phys_ram_base + addr1;
2303 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002304 if (!cpu_physical_memory_is_dirty(addr1)) {
2305 /* invalidate code */
2306 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2307 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002308 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2309 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002310 }
bellard8df1cd02005-01-28 22:37:22 +00002311 }
2312}
2313
bellardaab33092005-10-30 20:48:42 +00002314/* XXX: optimize */
2315void stb_phys(target_phys_addr_t addr, uint32_t val)
2316{
2317 uint8_t v = val;
2318 cpu_physical_memory_write(addr, &v, 1);
2319}
2320
2321/* XXX: optimize */
2322void stw_phys(target_phys_addr_t addr, uint32_t val)
2323{
2324 uint16_t v = tswap16(val);
2325 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2326}
2327
2328/* XXX: optimize */
2329void stq_phys(target_phys_addr_t addr, uint64_t val)
2330{
2331 val = tswap64(val);
2332 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2333}
2334
bellard13eb76e2004-01-24 15:23:36 +00002335#endif
2336
2337/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002338int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2339 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002340{
2341 int l;
2342 target_ulong page, phys_addr;
2343
2344 while (len > 0) {
2345 page = addr & TARGET_PAGE_MASK;
2346 phys_addr = cpu_get_phys_page_debug(env, page);
2347 /* if no physical page mapped, return an error */
2348 if (phys_addr == -1)
2349 return -1;
2350 l = (page + TARGET_PAGE_SIZE) - addr;
2351 if (l > len)
2352 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002353 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2354 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002355 len -= l;
2356 buf += l;
2357 addr += l;
2358 }
2359 return 0;
2360}
2361
bellarde3db7222005-01-26 22:00:47 +00002362void dump_exec_info(FILE *f,
2363 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2364{
2365 int i, target_code_size, max_target_code_size;
2366 int direct_jmp_count, direct_jmp2_count, cross_page;
2367 TranslationBlock *tb;
2368
2369 target_code_size = 0;
2370 max_target_code_size = 0;
2371 cross_page = 0;
2372 direct_jmp_count = 0;
2373 direct_jmp2_count = 0;
2374 for(i = 0; i < nb_tbs; i++) {
2375 tb = &tbs[i];
2376 target_code_size += tb->size;
2377 if (tb->size > max_target_code_size)
2378 max_target_code_size = tb->size;
2379 if (tb->page_addr[1] != -1)
2380 cross_page++;
2381 if (tb->tb_next_offset[0] != 0xffff) {
2382 direct_jmp_count++;
2383 if (tb->tb_next_offset[1] != 0xffff) {
2384 direct_jmp2_count++;
2385 }
2386 }
2387 }
2388 /* XXX: avoid using doubles ? */
2389 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2390 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2391 nb_tbs ? target_code_size / nb_tbs : 0,
2392 max_target_code_size);
2393 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2394 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2395 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2396 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2397 cross_page,
2398 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2399 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2400 direct_jmp_count,
2401 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2402 direct_jmp2_count,
2403 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2404 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2405 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2406 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2407}
2408
bellard61382a52003-10-27 21:22:23 +00002409#if !defined(CONFIG_USER_ONLY)
2410
2411#define MMUSUFFIX _cmmu
2412#define GETPC() NULL
2413#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002414#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002415
2416#define SHIFT 0
2417#include "softmmu_template.h"
2418
2419#define SHIFT 1
2420#include "softmmu_template.h"
2421
2422#define SHIFT 2
2423#include "softmmu_template.h"
2424
2425#define SHIFT 3
2426#include "softmmu_template.h"
2427
2428#undef env
2429
2430#endif