blob: 37d58a43ea2ee5f161a57669ec639be6324ad4e3 [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
thsc5be9f02007-02-28 20:20:53 +00001225CPUState *cpu_copy(CPUState *env)
1226{
1227 CPUState *new_env = cpu_init();
1228 /* preserve chaining and index */
1229 CPUState *next_cpu = new_env->next_cpu;
1230 int cpu_index = new_env->cpu_index;
1231 memcpy(new_env, env, sizeof(CPUState));
1232 new_env->next_cpu = next_cpu;
1233 new_env->cpu_index = cpu_index;
1234 return new_env;
1235}
1236
bellard01243112004-01-04 15:48:17 +00001237#if !defined(CONFIG_USER_ONLY)
1238
bellardee8b7022004-02-03 23:35:10 +00001239/* NOTE: if flush_global is true, also flush global entries (not
1240 implemented yet) */
1241void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001242{
bellard33417e72003-08-10 21:47:01 +00001243 int i;
bellard01243112004-01-04 15:48:17 +00001244
bellard9fa3e852004-01-04 18:06:42 +00001245#if defined(DEBUG_TLB)
1246 printf("tlb_flush:\n");
1247#endif
bellard01243112004-01-04 15:48:17 +00001248 /* must reset current TB so that interrupts cannot modify the
1249 links while we are modifying them */
1250 env->current_tb = NULL;
1251
bellard33417e72003-08-10 21:47:01 +00001252 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001253 env->tlb_table[0][i].addr_read = -1;
1254 env->tlb_table[0][i].addr_write = -1;
1255 env->tlb_table[0][i].addr_code = -1;
1256 env->tlb_table[1][i].addr_read = -1;
1257 env->tlb_table[1][i].addr_write = -1;
1258 env->tlb_table[1][i].addr_code = -1;
bellard33417e72003-08-10 21:47:01 +00001259 }
bellard9fa3e852004-01-04 18:06:42 +00001260
bellard8a40a182005-11-20 10:35:40 +00001261 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001262
1263#if !defined(CONFIG_SOFTMMU)
1264 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1265#endif
bellard0a962c02005-02-10 22:00:27 +00001266#ifdef USE_KQEMU
1267 if (env->kqemu_enabled) {
1268 kqemu_flush(env, flush_global);
1269 }
1270#endif
bellarde3db7222005-01-26 22:00:47 +00001271 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001272}
1273
bellard274da6b2004-05-20 21:56:27 +00001274static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001275{
bellard84b7b8e2005-11-28 21:19:04 +00001276 if (addr == (tlb_entry->addr_read &
1277 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1278 addr == (tlb_entry->addr_write &
1279 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1280 addr == (tlb_entry->addr_code &
1281 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1282 tlb_entry->addr_read = -1;
1283 tlb_entry->addr_write = -1;
1284 tlb_entry->addr_code = -1;
1285 }
bellard61382a52003-10-27 21:22:23 +00001286}
1287
bellard2e126692004-04-25 21:28:44 +00001288void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001289{
bellard8a40a182005-11-20 10:35:40 +00001290 int i;
bellard9fa3e852004-01-04 18:06:42 +00001291 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001292
bellard9fa3e852004-01-04 18:06:42 +00001293#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001294 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001295#endif
bellard01243112004-01-04 15:48:17 +00001296 /* must reset current TB so that interrupts cannot modify the
1297 links while we are modifying them */
1298 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001299
bellard61382a52003-10-27 21:22:23 +00001300 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001301 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001302 tlb_flush_entry(&env->tlb_table[0][i], addr);
1303 tlb_flush_entry(&env->tlb_table[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001304
pbrookb362e5e2006-11-12 20:40:55 +00001305 /* Discard jump cache entries for any tb which might potentially
1306 overlap the flushed page. */
1307 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1308 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1309
1310 i = tb_jmp_cache_hash_page(addr);
1311 memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
bellard9fa3e852004-01-04 18:06:42 +00001312
bellard01243112004-01-04 15:48:17 +00001313#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001314 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001315 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001316#endif
bellard0a962c02005-02-10 22:00:27 +00001317#ifdef USE_KQEMU
1318 if (env->kqemu_enabled) {
1319 kqemu_flush_page(env, addr);
1320 }
1321#endif
bellard9fa3e852004-01-04 18:06:42 +00001322}
1323
bellard9fa3e852004-01-04 18:06:42 +00001324/* update the TLBs so that writes to code in the virtual page 'addr'
1325 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001326static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001327{
bellard6a00d602005-11-21 23:25:50 +00001328 cpu_physical_memory_reset_dirty(ram_addr,
1329 ram_addr + TARGET_PAGE_SIZE,
1330 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001331}
1332
bellard9fa3e852004-01-04 18:06:42 +00001333/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001334 tested for self modifying code */
1335static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1336 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001337{
bellard3a7d9292005-08-21 09:26:42 +00001338 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001339}
1340
1341static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1342 unsigned long start, unsigned long length)
1343{
1344 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001345 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1346 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001347 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001348 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001349 }
1350 }
1351}
1352
bellard3a7d9292005-08-21 09:26:42 +00001353void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001354 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001355{
1356 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001357 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001358 int i, mask, len;
1359 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001360
1361 start &= TARGET_PAGE_MASK;
1362 end = TARGET_PAGE_ALIGN(end);
1363
1364 length = end - start;
1365 if (length == 0)
1366 return;
bellard0a962c02005-02-10 22:00:27 +00001367 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001368#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001369 /* XXX: should not depend on cpu context */
1370 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001371 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001372 ram_addr_t addr;
1373 addr = start;
1374 for(i = 0; i < len; i++) {
1375 kqemu_set_notdirty(env, addr);
1376 addr += TARGET_PAGE_SIZE;
1377 }
bellard3a7d9292005-08-21 09:26:42 +00001378 }
1379#endif
bellardf23db162005-08-21 19:12:28 +00001380 mask = ~dirty_flags;
1381 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1382 for(i = 0; i < len; i++)
1383 p[i] &= mask;
1384
bellard1ccde1c2004-02-06 19:46:14 +00001385 /* we modify the TLB cache so that the dirty bit will be set again
1386 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001387 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001388 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1389 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001390 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001391 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001392 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001393 }
bellard59817cc2004-02-16 22:01:13 +00001394
1395#if !defined(CONFIG_SOFTMMU)
1396 /* XXX: this is expensive */
1397 {
1398 VirtPageDesc *p;
1399 int j;
1400 target_ulong addr;
1401
1402 for(i = 0; i < L1_SIZE; i++) {
1403 p = l1_virt_map[i];
1404 if (p) {
1405 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1406 for(j = 0; j < L2_SIZE; j++) {
1407 if (p->valid_tag == virt_valid_tag &&
1408 p->phys_addr >= start && p->phys_addr < end &&
1409 (p->prot & PROT_WRITE)) {
1410 if (addr < MMAP_AREA_END) {
1411 mprotect((void *)addr, TARGET_PAGE_SIZE,
1412 p->prot & ~PROT_WRITE);
1413 }
1414 }
1415 addr += TARGET_PAGE_SIZE;
1416 p++;
1417 }
1418 }
1419 }
1420 }
1421#endif
bellard1ccde1c2004-02-06 19:46:14 +00001422}
1423
bellard3a7d9292005-08-21 09:26:42 +00001424static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1425{
1426 ram_addr_t ram_addr;
1427
bellard84b7b8e2005-11-28 21:19:04 +00001428 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1429 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001430 tlb_entry->addend - (unsigned long)phys_ram_base;
1431 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001432 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001433 }
1434 }
1435}
1436
1437/* update the TLB according to the current state of the dirty bits */
1438void cpu_tlb_update_dirty(CPUState *env)
1439{
1440 int i;
1441 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001442 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001443 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001444 tlb_update_dirty(&env->tlb_table[1][i]);
bellard3a7d9292005-08-21 09:26:42 +00001445}
1446
bellard1ccde1c2004-02-06 19:46:14 +00001447static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001448 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001449{
1450 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001451 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1452 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001453 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001454 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001455 }
1456 }
1457}
1458
1459/* update the TLB corresponding to virtual page vaddr and phys addr
1460 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001461static inline void tlb_set_dirty(CPUState *env,
1462 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001463{
bellard1ccde1c2004-02-06 19:46:14 +00001464 int i;
1465
bellard1ccde1c2004-02-06 19:46:14 +00001466 addr &= TARGET_PAGE_MASK;
1467 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001468 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1469 tlb_set_dirty1(&env->tlb_table[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001470}
1471
bellard59817cc2004-02-16 22:01:13 +00001472/* add a new TLB entry. At most one entry for a given virtual address
1473 is permitted. Return 0 if OK or 2 if the page could not be mapped
1474 (can only happen in non SOFTMMU mode for I/O pages or pages
1475 conflicting with the host address space). */
bellard84b7b8e2005-11-28 21:19:04 +00001476int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1477 target_phys_addr_t paddr, int prot,
1478 int is_user, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001479{
bellard92e873b2004-05-21 14:52:29 +00001480 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001481 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001482 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001483 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001484 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001485 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001486 CPUTLBEntry *te;
bellard9fa3e852004-01-04 18:06:42 +00001487
bellard92e873b2004-05-21 14:52:29 +00001488 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001489 if (!p) {
1490 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001491 } else {
1492 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001493 }
1494#if defined(DEBUG_TLB)
bellard3a7d9292005-08-21 09:26:42 +00001495 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 +00001496 vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001497#endif
1498
1499 ret = 0;
1500#if !defined(CONFIG_SOFTMMU)
1501 if (is_softmmu)
1502#endif
1503 {
bellard2a4188a2006-06-25 21:54:59 +00001504 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001505 /* IO memory case */
1506 address = vaddr | pd;
1507 addend = paddr;
1508 } else {
1509 /* standard memory */
1510 address = vaddr;
1511 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1512 }
1513
bellard90f18422005-07-24 10:17:31 +00001514 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001515 addend -= vaddr;
bellard84b7b8e2005-11-28 21:19:04 +00001516 te = &env->tlb_table[is_user][index];
1517 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001518 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001519 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001520 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001521 te->addr_read = -1;
1522 }
1523 if (prot & PAGE_EXEC) {
1524 te->addr_code = address;
1525 } else {
1526 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001527 }
bellard67b915a2004-03-31 23:37:16 +00001528 if (prot & PAGE_WRITE) {
bellard856074e2006-07-04 09:47:34 +00001529 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1530 (pd & IO_MEM_ROMD)) {
1531 /* write access calls the I/O callback */
1532 te->addr_write = vaddr |
1533 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
bellard3a7d9292005-08-21 09:26:42 +00001534 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001535 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001536 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001537 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001538 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001539 }
1540 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001541 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001542 }
1543 }
1544#if !defined(CONFIG_SOFTMMU)
1545 else {
1546 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1547 /* IO access: no mapping is done as it will be handled by the
1548 soft MMU */
1549 if (!(env->hflags & HF_SOFTMMU_MASK))
1550 ret = 2;
1551 } else {
1552 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001553
bellard59817cc2004-02-16 22:01:13 +00001554 if (vaddr >= MMAP_AREA_END) {
1555 ret = 2;
1556 } else {
1557 if (prot & PROT_WRITE) {
1558 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001559#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001560 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001561#endif
bellard59817cc2004-02-16 22:01:13 +00001562 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1563 !cpu_physical_memory_is_dirty(pd))) {
1564 /* ROM: we do as if code was inside */
1565 /* if code is present, we only map as read only and save the
1566 original mapping */
1567 VirtPageDesc *vp;
1568
bellard90f18422005-07-24 10:17:31 +00001569 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
bellard59817cc2004-02-16 22:01:13 +00001570 vp->phys_addr = pd;
1571 vp->prot = prot;
1572 vp->valid_tag = virt_valid_tag;
1573 prot &= ~PAGE_WRITE;
1574 }
bellard9fa3e852004-01-04 18:06:42 +00001575 }
bellard59817cc2004-02-16 22:01:13 +00001576 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1577 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1578 if (map_addr == MAP_FAILED) {
1579 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1580 paddr, vaddr);
1581 }
bellard9fa3e852004-01-04 18:06:42 +00001582 }
1583 }
1584 }
1585#endif
1586 return ret;
1587}
1588
1589/* called from signal handler: invalidate the code and unprotect the
1590 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001591int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001592{
1593#if !defined(CONFIG_SOFTMMU)
1594 VirtPageDesc *vp;
1595
1596#if defined(DEBUG_TLB)
1597 printf("page_unprotect: addr=0x%08x\n", addr);
1598#endif
1599 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001600
1601 /* if it is not mapped, no need to worry here */
1602 if (addr >= MMAP_AREA_END)
1603 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001604 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1605 if (!vp)
1606 return 0;
1607 /* NOTE: in this case, validate_tag is _not_ tested as it
1608 validates only the code TLB */
1609 if (vp->valid_tag != virt_valid_tag)
1610 return 0;
1611 if (!(vp->prot & PAGE_WRITE))
1612 return 0;
1613#if defined(DEBUG_TLB)
1614 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1615 addr, vp->phys_addr, vp->prot);
1616#endif
bellard59817cc2004-02-16 22:01:13 +00001617 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1618 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1619 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001620 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001621 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001622 /* flush the code inside */
1623 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001624 return 1;
1625#else
1626 return 0;
1627#endif
bellard33417e72003-08-10 21:47:01 +00001628}
1629
bellard01243112004-01-04 15:48:17 +00001630#else
1631
bellardee8b7022004-02-03 23:35:10 +00001632void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001633{
1634}
1635
bellard2e126692004-04-25 21:28:44 +00001636void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001637{
1638}
1639
bellard84b7b8e2005-11-28 21:19:04 +00001640int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1641 target_phys_addr_t paddr, int prot,
1642 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001643{
bellard9fa3e852004-01-04 18:06:42 +00001644 return 0;
1645}
bellard33417e72003-08-10 21:47:01 +00001646
bellard9fa3e852004-01-04 18:06:42 +00001647/* dump memory mappings */
1648void page_dump(FILE *f)
1649{
1650 unsigned long start, end;
1651 int i, j, prot, prot1;
1652 PageDesc *p;
1653
1654 fprintf(f, "%-8s %-8s %-8s %s\n",
1655 "start", "end", "size", "prot");
1656 start = -1;
1657 end = -1;
1658 prot = 0;
1659 for(i = 0; i <= L1_SIZE; i++) {
1660 if (i < L1_SIZE)
1661 p = l1_map[i];
1662 else
1663 p = NULL;
1664 for(j = 0;j < L2_SIZE; j++) {
1665 if (!p)
1666 prot1 = 0;
1667 else
1668 prot1 = p[j].flags;
1669 if (prot1 != prot) {
1670 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1671 if (start != -1) {
1672 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1673 start, end, end - start,
1674 prot & PAGE_READ ? 'r' : '-',
1675 prot & PAGE_WRITE ? 'w' : '-',
1676 prot & PAGE_EXEC ? 'x' : '-');
1677 }
1678 if (prot1 != 0)
1679 start = end;
1680 else
1681 start = -1;
1682 prot = prot1;
1683 }
1684 if (!p)
1685 break;
1686 }
bellard33417e72003-08-10 21:47:01 +00001687 }
bellard33417e72003-08-10 21:47:01 +00001688}
1689
pbrook53a59602006-03-25 19:31:22 +00001690int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001691{
bellard9fa3e852004-01-04 18:06:42 +00001692 PageDesc *p;
1693
1694 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001695 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001696 return 0;
1697 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001698}
1699
bellard9fa3e852004-01-04 18:06:42 +00001700/* modify the flags of a page and invalidate the code if
1701 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1702 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001703void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001704{
1705 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001706 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001707
1708 start = start & TARGET_PAGE_MASK;
1709 end = TARGET_PAGE_ALIGN(end);
1710 if (flags & PAGE_WRITE)
1711 flags |= PAGE_WRITE_ORG;
1712 spin_lock(&tb_lock);
1713 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1714 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1715 /* if the write protection is set, then we invalidate the code
1716 inside */
1717 if (!(p->flags & PAGE_WRITE) &&
1718 (flags & PAGE_WRITE) &&
1719 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001720 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001721 }
1722 p->flags = flags;
1723 }
1724 spin_unlock(&tb_lock);
1725}
1726
1727/* called from signal handler: invalidate the code and unprotect the
1728 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001729int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001730{
1731 unsigned int page_index, prot, pindex;
1732 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001733 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001734
bellard83fb7ad2004-07-05 21:25:26 +00001735 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001736 page_index = host_start >> TARGET_PAGE_BITS;
1737 p1 = page_find(page_index);
1738 if (!p1)
1739 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001740 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001741 p = p1;
1742 prot = 0;
1743 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1744 prot |= p->flags;
1745 p++;
1746 }
1747 /* if the page was really writable, then we change its
1748 protection back to writable */
1749 if (prot & PAGE_WRITE_ORG) {
1750 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1751 if (!(p1[pindex].flags & PAGE_WRITE)) {
pbrook53a59602006-03-25 19:31:22 +00001752 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001753 (prot & PAGE_BITS) | PAGE_WRITE);
1754 p1[pindex].flags |= PAGE_WRITE;
1755 /* and since the content will be modified, we must invalidate
1756 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001757 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001758#ifdef DEBUG_TB_CHECK
1759 tb_invalidate_check(address);
1760#endif
1761 return 1;
1762 }
1763 }
1764 return 0;
1765}
1766
1767/* call this function when system calls directly modify a memory area */
pbrook53a59602006-03-25 19:31:22 +00001768/* ??? This should be redundant now we have lock_user. */
1769void page_unprotect_range(target_ulong data, target_ulong data_size)
bellard9fa3e852004-01-04 18:06:42 +00001770{
pbrook53a59602006-03-25 19:31:22 +00001771 target_ulong start, end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001772
pbrook53a59602006-03-25 19:31:22 +00001773 start = data;
bellard9fa3e852004-01-04 18:06:42 +00001774 end = start + data_size;
1775 start &= TARGET_PAGE_MASK;
1776 end = TARGET_PAGE_ALIGN(end);
1777 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001778 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001779 }
1780}
1781
bellard6a00d602005-11-21 23:25:50 +00001782static inline void tlb_set_dirty(CPUState *env,
1783 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001784{
1785}
bellard9fa3e852004-01-04 18:06:42 +00001786#endif /* defined(CONFIG_USER_ONLY) */
1787
bellard33417e72003-08-10 21:47:01 +00001788/* register physical memory. 'size' must be a multiple of the target
1789 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1790 io memory page */
bellard2e126692004-04-25 21:28:44 +00001791void cpu_register_physical_memory(target_phys_addr_t start_addr,
1792 unsigned long size,
1793 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001794{
bellard108c49b2005-07-24 12:55:09 +00001795 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001796 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00001797 CPUState *env;
bellard33417e72003-08-10 21:47:01 +00001798
bellard5fd386f2004-05-23 21:11:22 +00001799 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001800 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001801 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard108c49b2005-07-24 12:55:09 +00001802 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
bellard9fa3e852004-01-04 18:06:42 +00001803 p->phys_offset = phys_offset;
bellard2a4188a2006-06-25 21:54:59 +00001804 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1805 (phys_offset & IO_MEM_ROMD))
bellard33417e72003-08-10 21:47:01 +00001806 phys_offset += TARGET_PAGE_SIZE;
1807 }
bellard9d420372006-06-25 22:25:22 +00001808
1809 /* since each CPU stores ram addresses in its TLB cache, we must
1810 reset the modified entries */
1811 /* XXX: slow ! */
1812 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1813 tlb_flush(env, 1);
1814 }
bellard33417e72003-08-10 21:47:01 +00001815}
1816
bellardba863452006-09-24 18:41:10 +00001817/* XXX: temporary until new memory mapping API */
1818uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1819{
1820 PhysPageDesc *p;
1821
1822 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1823 if (!p)
1824 return IO_MEM_UNASSIGNED;
1825 return p->phys_offset;
1826}
1827
bellarde9a1ab12007-02-08 23:08:38 +00001828/* XXX: better than nothing */
1829ram_addr_t qemu_ram_alloc(unsigned int size)
1830{
1831 ram_addr_t addr;
1832 if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1833 fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
1834 size, phys_ram_size);
1835 abort();
1836 }
1837 addr = phys_ram_alloc_offset;
1838 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1839 return addr;
1840}
1841
1842void qemu_ram_free(ram_addr_t addr)
1843{
1844}
1845
bellarda4193c82004-06-03 14:01:43 +00001846static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001847{
pbrook67d3b952006-12-18 05:03:52 +00001848#ifdef DEBUG_UNASSIGNED
1849 printf("Unassigned mem read 0x%08x\n", (int)addr);
1850#endif
bellard33417e72003-08-10 21:47:01 +00001851 return 0;
1852}
1853
bellarda4193c82004-06-03 14:01:43 +00001854static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001855{
pbrook67d3b952006-12-18 05:03:52 +00001856#ifdef DEBUG_UNASSIGNED
1857 printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
1858#endif
bellard33417e72003-08-10 21:47:01 +00001859}
1860
1861static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1862 unassigned_mem_readb,
1863 unassigned_mem_readb,
1864 unassigned_mem_readb,
1865};
1866
1867static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1868 unassigned_mem_writeb,
1869 unassigned_mem_writeb,
1870 unassigned_mem_writeb,
1871};
1872
bellarda4193c82004-06-03 14:01:43 +00001873static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001874{
bellard3a7d9292005-08-21 09:26:42 +00001875 unsigned long ram_addr;
1876 int dirty_flags;
1877 ram_addr = addr - (unsigned long)phys_ram_base;
1878 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1879 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1880#if !defined(CONFIG_USER_ONLY)
1881 tb_invalidate_phys_page_fast(ram_addr, 1);
1882 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1883#endif
1884 }
bellardc27004e2005-01-03 23:35:10 +00001885 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001886#ifdef USE_KQEMU
1887 if (cpu_single_env->kqemu_enabled &&
1888 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1889 kqemu_modify_page(cpu_single_env, ram_addr);
1890#endif
bellardf23db162005-08-21 19:12:28 +00001891 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1892 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1893 /* we remove the notdirty callback only if the code has been
1894 flushed */
1895 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001896 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001897}
1898
bellarda4193c82004-06-03 14:01:43 +00001899static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001900{
bellard3a7d9292005-08-21 09:26:42 +00001901 unsigned long ram_addr;
1902 int dirty_flags;
1903 ram_addr = addr - (unsigned long)phys_ram_base;
1904 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1905 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1906#if !defined(CONFIG_USER_ONLY)
1907 tb_invalidate_phys_page_fast(ram_addr, 2);
1908 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1909#endif
1910 }
bellardc27004e2005-01-03 23:35:10 +00001911 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001912#ifdef USE_KQEMU
1913 if (cpu_single_env->kqemu_enabled &&
1914 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1915 kqemu_modify_page(cpu_single_env, ram_addr);
1916#endif
bellardf23db162005-08-21 19:12:28 +00001917 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1918 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1919 /* we remove the notdirty callback only if the code has been
1920 flushed */
1921 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001922 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001923}
1924
bellarda4193c82004-06-03 14:01:43 +00001925static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001926{
bellard3a7d9292005-08-21 09:26:42 +00001927 unsigned long ram_addr;
1928 int dirty_flags;
1929 ram_addr = addr - (unsigned long)phys_ram_base;
1930 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1931 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1932#if !defined(CONFIG_USER_ONLY)
1933 tb_invalidate_phys_page_fast(ram_addr, 4);
1934 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1935#endif
1936 }
bellardc27004e2005-01-03 23:35:10 +00001937 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00001938#ifdef USE_KQEMU
1939 if (cpu_single_env->kqemu_enabled &&
1940 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
1941 kqemu_modify_page(cpu_single_env, ram_addr);
1942#endif
bellardf23db162005-08-21 19:12:28 +00001943 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1944 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1945 /* we remove the notdirty callback only if the code has been
1946 flushed */
1947 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00001948 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001949}
1950
bellard3a7d9292005-08-21 09:26:42 +00001951static CPUReadMemoryFunc *error_mem_read[3] = {
1952 NULL, /* never used */
1953 NULL, /* never used */
1954 NULL, /* never used */
1955};
1956
bellard1ccde1c2004-02-06 19:46:14 +00001957static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1958 notdirty_mem_writeb,
1959 notdirty_mem_writew,
1960 notdirty_mem_writel,
1961};
1962
bellard33417e72003-08-10 21:47:01 +00001963static void io_mem_init(void)
1964{
bellard3a7d9292005-08-21 09:26:42 +00001965 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00001966 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00001967 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001968 io_mem_nb = 5;
1969
1970 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001971 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00001972 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001973}
1974
1975/* mem_read and mem_write are arrays of functions containing the
1976 function to access byte (index 0), word (index 1) and dword (index
1977 2). All functions must be supplied. If io_index is non zero, the
1978 corresponding io zone is modified. If it is zero, a new io zone is
1979 allocated. The return value can be used with
1980 cpu_register_physical_memory(). (-1) is returned if error. */
1981int cpu_register_io_memory(int io_index,
1982 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001983 CPUWriteMemoryFunc **mem_write,
1984 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001985{
1986 int i;
1987
1988 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00001989 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00001990 return -1;
1991 io_index = io_mem_nb++;
1992 } else {
1993 if (io_index >= IO_MEM_NB_ENTRIES)
1994 return -1;
1995 }
bellardb5ff1b32005-11-26 10:38:39 +00001996
bellard33417e72003-08-10 21:47:01 +00001997 for(i = 0;i < 3; i++) {
1998 io_mem_read[io_index][i] = mem_read[i];
1999 io_mem_write[io_index][i] = mem_write[i];
2000 }
bellarda4193c82004-06-03 14:01:43 +00002001 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002002 return io_index << IO_MEM_SHIFT;
2003}
bellard61382a52003-10-27 21:22:23 +00002004
bellard8926b512004-10-10 15:14:20 +00002005CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2006{
2007 return io_mem_write[io_index >> IO_MEM_SHIFT];
2008}
2009
2010CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2011{
2012 return io_mem_read[io_index >> IO_MEM_SHIFT];
2013}
2014
bellard13eb76e2004-01-24 15:23:36 +00002015/* physical memory access (slow version, mainly for debug) */
2016#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002017void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002018 int len, int is_write)
2019{
2020 int l, flags;
2021 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002022 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002023
2024 while (len > 0) {
2025 page = addr & TARGET_PAGE_MASK;
2026 l = (page + TARGET_PAGE_SIZE) - addr;
2027 if (l > len)
2028 l = len;
2029 flags = page_get_flags(page);
2030 if (!(flags & PAGE_VALID))
2031 return;
2032 if (is_write) {
2033 if (!(flags & PAGE_WRITE))
2034 return;
pbrook53a59602006-03-25 19:31:22 +00002035 p = lock_user(addr, len, 0);
2036 memcpy(p, buf, len);
2037 unlock_user(p, addr, len);
bellard13eb76e2004-01-24 15:23:36 +00002038 } else {
2039 if (!(flags & PAGE_READ))
2040 return;
pbrook53a59602006-03-25 19:31:22 +00002041 p = lock_user(addr, len, 1);
2042 memcpy(buf, p, len);
2043 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002044 }
2045 len -= l;
2046 buf += l;
2047 addr += l;
2048 }
2049}
bellard8df1cd02005-01-28 22:37:22 +00002050
bellard13eb76e2004-01-24 15:23:36 +00002051#else
bellard2e126692004-04-25 21:28:44 +00002052void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002053 int len, int is_write)
2054{
2055 int l, io_index;
2056 uint8_t *ptr;
2057 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002058 target_phys_addr_t page;
2059 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002060 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002061
2062 while (len > 0) {
2063 page = addr & TARGET_PAGE_MASK;
2064 l = (page + TARGET_PAGE_SIZE) - addr;
2065 if (l > len)
2066 l = len;
bellard92e873b2004-05-21 14:52:29 +00002067 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002068 if (!p) {
2069 pd = IO_MEM_UNASSIGNED;
2070 } else {
2071 pd = p->phys_offset;
2072 }
2073
2074 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002075 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002076 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002077 /* XXX: could force cpu_single_env to NULL to avoid
2078 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002079 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002080 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002081 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002082 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002083 l = 4;
2084 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002085 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002086 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002087 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002088 l = 2;
2089 } else {
bellard1c213d12005-09-03 10:49:04 +00002090 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002091 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002092 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002093 l = 1;
2094 }
2095 } else {
bellardb448f2f2004-02-25 23:24:04 +00002096 unsigned long addr1;
2097 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002098 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002099 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002100 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002101 if (!cpu_physical_memory_is_dirty(addr1)) {
2102 /* invalidate code */
2103 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2104 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002105 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2106 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002107 }
bellard13eb76e2004-01-24 15:23:36 +00002108 }
2109 } else {
bellard2a4188a2006-06-25 21:54:59 +00002110 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2111 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002112 /* I/O case */
2113 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2114 if (l >= 4 && ((addr & 3) == 0)) {
2115 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002116 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002117 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002118 l = 4;
2119 } else if (l >= 2 && ((addr & 1) == 0)) {
2120 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002121 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002122 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002123 l = 2;
2124 } else {
bellard1c213d12005-09-03 10:49:04 +00002125 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002126 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002127 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002128 l = 1;
2129 }
2130 } else {
2131 /* RAM case */
2132 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2133 (addr & ~TARGET_PAGE_MASK);
2134 memcpy(buf, ptr, l);
2135 }
2136 }
2137 len -= l;
2138 buf += l;
2139 addr += l;
2140 }
2141}
bellard8df1cd02005-01-28 22:37:22 +00002142
bellardd0ecd2a2006-04-23 17:14:48 +00002143/* used for ROM loading : can write in RAM and ROM */
2144void cpu_physical_memory_write_rom(target_phys_addr_t addr,
2145 const uint8_t *buf, int len)
2146{
2147 int l;
2148 uint8_t *ptr;
2149 target_phys_addr_t page;
2150 unsigned long pd;
2151 PhysPageDesc *p;
2152
2153 while (len > 0) {
2154 page = addr & TARGET_PAGE_MASK;
2155 l = (page + TARGET_PAGE_SIZE) - addr;
2156 if (l > len)
2157 l = len;
2158 p = phys_page_find(page >> TARGET_PAGE_BITS);
2159 if (!p) {
2160 pd = IO_MEM_UNASSIGNED;
2161 } else {
2162 pd = p->phys_offset;
2163 }
2164
2165 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002166 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2167 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002168 /* do nothing */
2169 } else {
2170 unsigned long addr1;
2171 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2172 /* ROM/RAM case */
2173 ptr = phys_ram_base + addr1;
2174 memcpy(ptr, buf, l);
2175 }
2176 len -= l;
2177 buf += l;
2178 addr += l;
2179 }
2180}
2181
2182
bellard8df1cd02005-01-28 22:37:22 +00002183/* warning: addr must be aligned */
2184uint32_t ldl_phys(target_phys_addr_t addr)
2185{
2186 int io_index;
2187 uint8_t *ptr;
2188 uint32_t val;
2189 unsigned long pd;
2190 PhysPageDesc *p;
2191
2192 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2193 if (!p) {
2194 pd = IO_MEM_UNASSIGNED;
2195 } else {
2196 pd = p->phys_offset;
2197 }
2198
bellard2a4188a2006-06-25 21:54:59 +00002199 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2200 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002201 /* I/O case */
2202 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2203 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2204 } else {
2205 /* RAM case */
2206 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2207 (addr & ~TARGET_PAGE_MASK);
2208 val = ldl_p(ptr);
2209 }
2210 return val;
2211}
2212
bellard84b7b8e2005-11-28 21:19:04 +00002213/* warning: addr must be aligned */
2214uint64_t ldq_phys(target_phys_addr_t addr)
2215{
2216 int io_index;
2217 uint8_t *ptr;
2218 uint64_t val;
2219 unsigned long pd;
2220 PhysPageDesc *p;
2221
2222 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2223 if (!p) {
2224 pd = IO_MEM_UNASSIGNED;
2225 } else {
2226 pd = p->phys_offset;
2227 }
2228
bellard2a4188a2006-06-25 21:54:59 +00002229 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2230 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002231 /* I/O case */
2232 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2233#ifdef TARGET_WORDS_BIGENDIAN
2234 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2235 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2236#else
2237 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2238 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2239#endif
2240 } else {
2241 /* RAM case */
2242 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2243 (addr & ~TARGET_PAGE_MASK);
2244 val = ldq_p(ptr);
2245 }
2246 return val;
2247}
2248
bellardaab33092005-10-30 20:48:42 +00002249/* XXX: optimize */
2250uint32_t ldub_phys(target_phys_addr_t addr)
2251{
2252 uint8_t val;
2253 cpu_physical_memory_read(addr, &val, 1);
2254 return val;
2255}
2256
2257/* XXX: optimize */
2258uint32_t lduw_phys(target_phys_addr_t addr)
2259{
2260 uint16_t val;
2261 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2262 return tswap16(val);
2263}
2264
bellard8df1cd02005-01-28 22:37:22 +00002265/* warning: addr must be aligned. The ram page is not masked as dirty
2266 and the code inside is not invalidated. It is useful if the dirty
2267 bits are used to track modified PTEs */
2268void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2269{
2270 int io_index;
2271 uint8_t *ptr;
2272 unsigned long pd;
2273 PhysPageDesc *p;
2274
2275 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2276 if (!p) {
2277 pd = IO_MEM_UNASSIGNED;
2278 } else {
2279 pd = p->phys_offset;
2280 }
2281
bellard3a7d9292005-08-21 09:26:42 +00002282 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002283 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2284 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2285 } else {
2286 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2287 (addr & ~TARGET_PAGE_MASK);
2288 stl_p(ptr, val);
2289 }
2290}
2291
2292/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002293void stl_phys(target_phys_addr_t addr, uint32_t val)
2294{
2295 int io_index;
2296 uint8_t *ptr;
2297 unsigned long pd;
2298 PhysPageDesc *p;
2299
2300 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2301 if (!p) {
2302 pd = IO_MEM_UNASSIGNED;
2303 } else {
2304 pd = p->phys_offset;
2305 }
2306
bellard3a7d9292005-08-21 09:26:42 +00002307 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002308 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2309 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2310 } else {
2311 unsigned long addr1;
2312 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2313 /* RAM case */
2314 ptr = phys_ram_base + addr1;
2315 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002316 if (!cpu_physical_memory_is_dirty(addr1)) {
2317 /* invalidate code */
2318 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2319 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002320 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2321 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002322 }
bellard8df1cd02005-01-28 22:37:22 +00002323 }
2324}
2325
bellardaab33092005-10-30 20:48:42 +00002326/* XXX: optimize */
2327void stb_phys(target_phys_addr_t addr, uint32_t val)
2328{
2329 uint8_t v = val;
2330 cpu_physical_memory_write(addr, &v, 1);
2331}
2332
2333/* XXX: optimize */
2334void stw_phys(target_phys_addr_t addr, uint32_t val)
2335{
2336 uint16_t v = tswap16(val);
2337 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2338}
2339
2340/* XXX: optimize */
2341void stq_phys(target_phys_addr_t addr, uint64_t val)
2342{
2343 val = tswap64(val);
2344 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2345}
2346
bellard13eb76e2004-01-24 15:23:36 +00002347#endif
2348
2349/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002350int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2351 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002352{
2353 int l;
2354 target_ulong page, phys_addr;
2355
2356 while (len > 0) {
2357 page = addr & TARGET_PAGE_MASK;
2358 phys_addr = cpu_get_phys_page_debug(env, page);
2359 /* if no physical page mapped, return an error */
2360 if (phys_addr == -1)
2361 return -1;
2362 l = (page + TARGET_PAGE_SIZE) - addr;
2363 if (l > len)
2364 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002365 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2366 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002367 len -= l;
2368 buf += l;
2369 addr += l;
2370 }
2371 return 0;
2372}
2373
bellarde3db7222005-01-26 22:00:47 +00002374void dump_exec_info(FILE *f,
2375 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2376{
2377 int i, target_code_size, max_target_code_size;
2378 int direct_jmp_count, direct_jmp2_count, cross_page;
2379 TranslationBlock *tb;
2380
2381 target_code_size = 0;
2382 max_target_code_size = 0;
2383 cross_page = 0;
2384 direct_jmp_count = 0;
2385 direct_jmp2_count = 0;
2386 for(i = 0; i < nb_tbs; i++) {
2387 tb = &tbs[i];
2388 target_code_size += tb->size;
2389 if (tb->size > max_target_code_size)
2390 max_target_code_size = tb->size;
2391 if (tb->page_addr[1] != -1)
2392 cross_page++;
2393 if (tb->tb_next_offset[0] != 0xffff) {
2394 direct_jmp_count++;
2395 if (tb->tb_next_offset[1] != 0xffff) {
2396 direct_jmp2_count++;
2397 }
2398 }
2399 }
2400 /* XXX: avoid using doubles ? */
2401 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2402 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2403 nb_tbs ? target_code_size / nb_tbs : 0,
2404 max_target_code_size);
2405 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2406 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2407 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2408 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2409 cross_page,
2410 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2411 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2412 direct_jmp_count,
2413 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2414 direct_jmp2_count,
2415 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2416 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2417 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2418 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2419}
2420
bellard61382a52003-10-27 21:22:23 +00002421#if !defined(CONFIG_USER_ONLY)
2422
2423#define MMUSUFFIX _cmmu
2424#define GETPC() NULL
2425#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002426#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002427
2428#define SHIFT 0
2429#include "softmmu_template.h"
2430
2431#define SHIFT 1
2432#include "softmmu_template.h"
2433
2434#define SHIFT 2
2435#include "softmmu_template.h"
2436
2437#define SHIFT 3
2438#include "softmmu_template.h"
2439
2440#undef env
2441
2442#endif