blob: 617dea13ca4b0eb2c8cd4884f5add9c3c845169d [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"
bellard54936002003-05-13 00:25:15 +000021#include <stdlib.h>
22#include <stdio.h>
23#include <stdarg.h>
24#include <string.h>
25#include <errno.h>
26#include <unistd.h>
27#include <inttypes.h>
bellard67b915a2004-03-31 23:37:16 +000028#if !defined(CONFIG_SOFTMMU)
bellardfd6ce8f2003-05-14 19:00:11 +000029#include <sys/mman.h>
bellard67b915a2004-03-31 23:37:16 +000030#endif
bellard54936002003-05-13 00:25:15 +000031
bellard6180a182003-09-30 21:04:53 +000032#include "cpu.h"
33#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000034
bellardfd6ce8f2003-05-14 19:00:11 +000035//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000036//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000037//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000038
39/* make various TB consistency checks */
40//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000041//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000042
43/* threshold to flush the translated code buffer */
44#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
45
bellard9fa3e852004-01-04 18:06:42 +000046#define SMC_BITMAP_USE_THRESHOLD 10
47
48#define MMAP_AREA_START 0x00000000
49#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000050
51TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
52TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
bellard9fa3e852004-01-04 18:06:42 +000053TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000054int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000055/* any access to the tbs or the page table must use this lock */
56spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000057
58uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
59uint8_t *code_gen_ptr;
60
bellard9fa3e852004-01-04 18:06:42 +000061int phys_ram_size;
62int phys_ram_fd;
63uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000064uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000065
bellard54936002003-05-13 00:25:15 +000066typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000067 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000068 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000069 /* in order to optimize self modifying code, we count the number
70 of lookups we do to a given page to use a bitmap */
71 unsigned int code_write_count;
72 uint8_t *code_bitmap;
73#if defined(CONFIG_USER_ONLY)
74 unsigned long flags;
75#endif
bellard54936002003-05-13 00:25:15 +000076} PageDesc;
77
bellard92e873b2004-05-21 14:52:29 +000078typedef struct PhysPageDesc {
79 /* offset in host memory of the page + io_index in the low 12 bits */
80 unsigned long phys_offset;
81} PhysPageDesc;
82
bellard9fa3e852004-01-04 18:06:42 +000083typedef struct VirtPageDesc {
84 /* physical address of code page. It is valid only if 'valid_tag'
85 matches 'virt_valid_tag' */
86 target_ulong phys_addr;
87 unsigned int valid_tag;
88#if !defined(CONFIG_SOFTMMU)
89 /* original page access rights. It is valid only if 'valid_tag'
90 matches 'virt_valid_tag' */
91 unsigned int prot;
92#endif
93} VirtPageDesc;
94
bellard54936002003-05-13 00:25:15 +000095#define L2_BITS 10
96#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
97
98#define L1_SIZE (1 << L1_BITS)
99#define L2_SIZE (1 << L2_BITS)
100
bellard33417e72003-08-10 21:47:01 +0000101static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000102
bellard54936002003-05-13 00:25:15 +0000103unsigned long real_host_page_size;
104unsigned long host_page_bits;
105unsigned long host_page_size;
106unsigned long host_page_mask;
107
bellard92e873b2004-05-21 14:52:29 +0000108/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000109static PageDesc *l1_map[L1_SIZE];
bellard92e873b2004-05-21 14:52:29 +0000110static PhysPageDesc *l1_phys_map[L1_SIZE];
bellard54936002003-05-13 00:25:15 +0000111
bellard9fa3e852004-01-04 18:06:42 +0000112#if !defined(CONFIG_USER_ONLY)
113static VirtPageDesc *l1_virt_map[L1_SIZE];
114static unsigned int virt_valid_tag;
115#endif
116
bellard33417e72003-08-10 21:47:01 +0000117/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000118CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
119CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000120void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000121static int io_mem_nb;
122
bellard34865132003-10-05 14:28:56 +0000123/* log support */
124char *logfilename = "/tmp/qemu.log";
125FILE *logfile;
126int loglevel;
127
bellardb346ff42003-06-15 20:05:50 +0000128static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000129{
130 /* NOTE: we can always suppose that host_page_size >=
131 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000132#ifdef _WIN32
133 real_host_page_size = 4096;
134#else
bellard54936002003-05-13 00:25:15 +0000135 real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000136#endif
bellard54936002003-05-13 00:25:15 +0000137 if (host_page_size == 0)
138 host_page_size = real_host_page_size;
139 if (host_page_size < TARGET_PAGE_SIZE)
140 host_page_size = TARGET_PAGE_SIZE;
141 host_page_bits = 0;
142 while ((1 << host_page_bits) < host_page_size)
143 host_page_bits++;
144 host_page_mask = ~(host_page_size - 1);
bellard9fa3e852004-01-04 18:06:42 +0000145#if !defined(CONFIG_USER_ONLY)
146 virt_valid_tag = 1;
147#endif
bellard54936002003-05-13 00:25:15 +0000148}
149
bellardfd6ce8f2003-05-14 19:00:11 +0000150static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000151{
bellard54936002003-05-13 00:25:15 +0000152 PageDesc **lp, *p;
153
bellard54936002003-05-13 00:25:15 +0000154 lp = &l1_map[index >> L2_BITS];
155 p = *lp;
156 if (!p) {
157 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000158 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000159 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000160 *lp = p;
161 }
162 return p + (index & (L2_SIZE - 1));
163}
164
bellardfd6ce8f2003-05-14 19:00:11 +0000165static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000166{
bellard54936002003-05-13 00:25:15 +0000167 PageDesc *p;
168
bellard54936002003-05-13 00:25:15 +0000169 p = l1_map[index >> L2_BITS];
170 if (!p)
171 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000172 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000173}
174
bellard92e873b2004-05-21 14:52:29 +0000175static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
176{
177 PhysPageDesc **lp, *p;
178
179 lp = &l1_phys_map[index >> L2_BITS];
180 p = *lp;
181 if (!p) {
182 /* allocate if not found */
183 p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
184 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
185 *lp = p;
186 }
187 return p + (index & (L2_SIZE - 1));
188}
189
190static inline PhysPageDesc *phys_page_find(unsigned int index)
191{
192 PhysPageDesc *p;
193
194 p = l1_phys_map[index >> L2_BITS];
195 if (!p)
196 return 0;
197 return p + (index & (L2_SIZE - 1));
198}
199
bellard9fa3e852004-01-04 18:06:42 +0000200#if !defined(CONFIG_USER_ONLY)
bellard4f2ac232004-04-26 19:44:02 +0000201static void tlb_protect_code(CPUState *env, target_ulong addr);
202static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000203
bellard9fa3e852004-01-04 18:06:42 +0000204static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
205{
206 VirtPageDesc **lp, *p;
207
208 lp = &l1_virt_map[index >> L2_BITS];
209 p = *lp;
210 if (!p) {
211 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000212 p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000213 memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
214 *lp = p;
215 }
216 return p + (index & (L2_SIZE - 1));
217}
218
219static inline VirtPageDesc *virt_page_find(unsigned int index)
220{
221 VirtPageDesc *p;
222
223 p = l1_virt_map[index >> L2_BITS];
bellardfd6ce8f2003-05-14 19:00:11 +0000224 if (!p)
225 return 0;
bellard9fa3e852004-01-04 18:06:42 +0000226 return p + (index & (L2_SIZE - 1));
bellardfd6ce8f2003-05-14 19:00:11 +0000227}
228
bellard9fa3e852004-01-04 18:06:42 +0000229static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000230{
bellard9fa3e852004-01-04 18:06:42 +0000231 int i, j;
232 VirtPageDesc *p;
233
234 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000235
bellard9fa3e852004-01-04 18:06:42 +0000236 if (virt_valid_tag == 0) {
237 virt_valid_tag = 1;
238 for(i = 0; i < L1_SIZE; i++) {
239 p = l1_virt_map[i];
240 if (p) {
241 for(j = 0; j < L2_SIZE; j++)
242 p[j].valid_tag = 0;
243 }
bellardfd6ce8f2003-05-14 19:00:11 +0000244 }
bellard54936002003-05-13 00:25:15 +0000245 }
246}
bellard9fa3e852004-01-04 18:06:42 +0000247#else
248static void virt_page_flush(void)
249{
250}
251#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000252
bellardb346ff42003-06-15 20:05:50 +0000253void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000254{
255 if (!code_gen_ptr) {
256 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000257 page_init();
bellard33417e72003-08-10 21:47:01 +0000258 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000259 }
260}
261
bellard9fa3e852004-01-04 18:06:42 +0000262static inline void invalidate_page_bitmap(PageDesc *p)
263{
264 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000265 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000266 p->code_bitmap = NULL;
267 }
268 p->code_write_count = 0;
269}
270
bellardfd6ce8f2003-05-14 19:00:11 +0000271/* set to NULL all the 'first_tb' fields in all PageDescs */
272static void page_flush_tb(void)
273{
274 int i, j;
275 PageDesc *p;
276
277 for(i = 0; i < L1_SIZE; i++) {
278 p = l1_map[i];
279 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000280 for(j = 0; j < L2_SIZE; j++) {
281 p->first_tb = NULL;
282 invalidate_page_bitmap(p);
283 p++;
284 }
bellardfd6ce8f2003-05-14 19:00:11 +0000285 }
286 }
287}
288
289/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000290/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000291void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000292{
293 int i;
bellard01243112004-01-04 15:48:17 +0000294#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000295 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
296 code_gen_ptr - code_gen_buffer,
297 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000298 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000299#endif
300 nb_tbs = 0;
301 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
302 tb_hash[i] = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000303 virt_page_flush();
304
305 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++)
306 tb_phys_hash[i] = NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000307 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000308
bellardfd6ce8f2003-05-14 19:00:11 +0000309 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000310 /* XXX: flush processor icache at this point if cache flush is
311 expensive */
bellardfd6ce8f2003-05-14 19:00:11 +0000312}
313
314#ifdef DEBUG_TB_CHECK
315
316static void tb_invalidate_check(unsigned long address)
317{
318 TranslationBlock *tb;
319 int i;
320 address &= TARGET_PAGE_MASK;
321 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
322 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
323 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
324 address >= tb->pc + tb->size)) {
325 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
326 address, tb->pc, tb->size);
327 }
328 }
329 }
330}
331
332/* verify that all the pages have correct rights for code */
333static void tb_page_check(void)
334{
335 TranslationBlock *tb;
336 int i, flags1, flags2;
337
338 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
339 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
340 flags1 = page_get_flags(tb->pc);
341 flags2 = page_get_flags(tb->pc + tb->size - 1);
342 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
343 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
344 tb->pc, tb->size, flags1, flags2);
345 }
346 }
347 }
348}
349
bellardd4e81642003-05-25 16:46:15 +0000350void tb_jmp_check(TranslationBlock *tb)
351{
352 TranslationBlock *tb1;
353 unsigned int n1;
354
355 /* suppress any remaining jumps to this TB */
356 tb1 = tb->jmp_first;
357 for(;;) {
358 n1 = (long)tb1 & 3;
359 tb1 = (TranslationBlock *)((long)tb1 & ~3);
360 if (n1 == 2)
361 break;
362 tb1 = tb1->jmp_next[n1];
363 }
364 /* check end of list */
365 if (tb1 != tb) {
366 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
367 }
368}
369
bellardfd6ce8f2003-05-14 19:00:11 +0000370#endif
371
372/* invalidate one TB */
373static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
374 int next_offset)
375{
376 TranslationBlock *tb1;
377 for(;;) {
378 tb1 = *ptb;
379 if (tb1 == tb) {
380 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
381 break;
382 }
383 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
384 }
385}
386
bellard9fa3e852004-01-04 18:06:42 +0000387static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
388{
389 TranslationBlock *tb1;
390 unsigned int n1;
391
392 for(;;) {
393 tb1 = *ptb;
394 n1 = (long)tb1 & 3;
395 tb1 = (TranslationBlock *)((long)tb1 & ~3);
396 if (tb1 == tb) {
397 *ptb = tb1->page_next[n1];
398 break;
399 }
400 ptb = &tb1->page_next[n1];
401 }
402}
403
bellardd4e81642003-05-25 16:46:15 +0000404static inline void tb_jmp_remove(TranslationBlock *tb, int n)
405{
406 TranslationBlock *tb1, **ptb;
407 unsigned int n1;
408
409 ptb = &tb->jmp_next[n];
410 tb1 = *ptb;
411 if (tb1) {
412 /* find tb(n) in circular list */
413 for(;;) {
414 tb1 = *ptb;
415 n1 = (long)tb1 & 3;
416 tb1 = (TranslationBlock *)((long)tb1 & ~3);
417 if (n1 == n && tb1 == tb)
418 break;
419 if (n1 == 2) {
420 ptb = &tb1->jmp_first;
421 } else {
422 ptb = &tb1->jmp_next[n1];
423 }
424 }
425 /* now we can suppress tb(n) from the list */
426 *ptb = tb->jmp_next[n];
427
428 tb->jmp_next[n] = NULL;
429 }
430}
431
432/* reset the jump entry 'n' of a TB so that it is not chained to
433 another TB */
434static inline void tb_reset_jump(TranslationBlock *tb, int n)
435{
436 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
437}
438
bellard9fa3e852004-01-04 18:06:42 +0000439static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000440{
bellardd4e81642003-05-25 16:46:15 +0000441 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000442 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000443
bellard36bdbe52003-11-19 22:12:02 +0000444 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000445
bellardfd6ce8f2003-05-14 19:00:11 +0000446 /* remove the TB from the hash list */
447 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000448 ptb = &tb_hash[h];
449 for(;;) {
450 tb1 = *ptb;
451 /* NOTE: the TB is not necessarily linked in the hash. It
452 indicates that it is not currently used */
453 if (tb1 == NULL)
454 return;
455 if (tb1 == tb) {
456 *ptb = tb1->hash_next;
457 break;
458 }
459 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000460 }
bellardd4e81642003-05-25 16:46:15 +0000461
462 /* suppress this TB from the two jump lists */
463 tb_jmp_remove(tb, 0);
464 tb_jmp_remove(tb, 1);
465
466 /* suppress any remaining jumps to this TB */
467 tb1 = tb->jmp_first;
468 for(;;) {
469 n1 = (long)tb1 & 3;
470 if (n1 == 2)
471 break;
472 tb1 = (TranslationBlock *)((long)tb1 & ~3);
473 tb2 = tb1->jmp_next[n1];
474 tb_reset_jump(tb1, n1);
475 tb1->jmp_next[n1] = NULL;
476 tb1 = tb2;
477 }
478 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000479}
480
bellard9fa3e852004-01-04 18:06:42 +0000481static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000482{
bellardfd6ce8f2003-05-14 19:00:11 +0000483 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000484 unsigned int h;
485 target_ulong phys_pc;
486
487 /* remove the TB from the hash list */
488 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
489 h = tb_phys_hash_func(phys_pc);
490 tb_remove(&tb_phys_hash[h], tb,
491 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000492
bellard9fa3e852004-01-04 18:06:42 +0000493 /* remove the TB from the page list */
494 if (tb->page_addr[0] != page_addr) {
495 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
496 tb_page_remove(&p->first_tb, tb);
497 invalidate_page_bitmap(p);
498 }
499 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
500 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
501 tb_page_remove(&p->first_tb, tb);
502 invalidate_page_bitmap(p);
503 }
504
505 tb_invalidate(tb);
506}
507
508static inline void set_bits(uint8_t *tab, int start, int len)
509{
510 int end, mask, end1;
511
512 end = start + len;
513 tab += start >> 3;
514 mask = 0xff << (start & 7);
515 if ((start & ~7) == (end & ~7)) {
516 if (start < end) {
517 mask &= ~(0xff << (end & 7));
518 *tab |= mask;
519 }
520 } else {
521 *tab++ |= mask;
522 start = (start + 8) & ~7;
523 end1 = end & ~7;
524 while (start < end1) {
525 *tab++ = 0xff;
526 start += 8;
527 }
528 if (start < end) {
529 mask = ~(0xff << (end & 7));
530 *tab |= mask;
531 }
532 }
533}
534
535static void build_page_bitmap(PageDesc *p)
536{
537 int n, tb_start, tb_end;
538 TranslationBlock *tb;
539
bellard59817cc2004-02-16 22:01:13 +0000540 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000541 if (!p->code_bitmap)
542 return;
543 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
544
545 tb = p->first_tb;
546 while (tb != NULL) {
547 n = (long)tb & 3;
548 tb = (TranslationBlock *)((long)tb & ~3);
549 /* NOTE: this is subtle as a TB may span two physical pages */
550 if (n == 0) {
551 /* NOTE: tb_end may be after the end of the page, but
552 it is not a problem */
553 tb_start = tb->pc & ~TARGET_PAGE_MASK;
554 tb_end = tb_start + tb->size;
555 if (tb_end > TARGET_PAGE_SIZE)
556 tb_end = TARGET_PAGE_SIZE;
557 } else {
558 tb_start = 0;
559 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
560 }
561 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
562 tb = tb->page_next[n];
563 }
564}
565
bellardd720b932004-04-25 17:57:43 +0000566#ifdef TARGET_HAS_PRECISE_SMC
567
568static void tb_gen_code(CPUState *env,
569 target_ulong pc, target_ulong cs_base, int flags,
570 int cflags)
571{
572 TranslationBlock *tb;
573 uint8_t *tc_ptr;
574 target_ulong phys_pc, phys_page2, virt_page2;
575 int code_gen_size;
576
577 phys_pc = get_phys_addr_code(env, (unsigned long)pc);
578 tb = tb_alloc((unsigned long)pc);
579 if (!tb) {
580 /* flush must be done */
581 tb_flush(env);
582 /* cannot fail at this point */
583 tb = tb_alloc((unsigned long)pc);
584 }
585 tc_ptr = code_gen_ptr;
586 tb->tc_ptr = tc_ptr;
587 tb->cs_base = cs_base;
588 tb->flags = flags;
589 tb->cflags = cflags;
590 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
591 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
592
593 /* check next page if needed */
594 virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
595 phys_page2 = -1;
596 if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
597 phys_page2 = get_phys_addr_code(env, virt_page2);
598 }
599 tb_link_phys(tb, phys_pc, phys_page2);
600}
601#endif
602
bellard9fa3e852004-01-04 18:06:42 +0000603/* invalidate all TBs which intersect with the target physical page
604 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000605 the same physical page. 'is_cpu_write_access' should be true if called
606 from a real cpu write access: the virtual CPU will exit the current
607 TB if code is modified inside this TB. */
608void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
609 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000610{
bellardd720b932004-04-25 17:57:43 +0000611 int n, current_tb_modified, current_tb_not_found, current_flags;
612#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
613 CPUState *env = cpu_single_env;
614#endif
bellard9fa3e852004-01-04 18:06:42 +0000615 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000616 TranslationBlock *tb, *tb_next, *current_tb;
bellard9fa3e852004-01-04 18:06:42 +0000617 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000618 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000619
620 p = page_find(start >> TARGET_PAGE_BITS);
621 if (!p)
622 return;
623 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000624 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
625 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000626 /* build code bitmap */
627 build_page_bitmap(p);
628 }
629
630 /* we remove all the TBs in the range [start, end[ */
631 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000632 current_tb_not_found = is_cpu_write_access;
633 current_tb_modified = 0;
634 current_tb = NULL; /* avoid warning */
635 current_pc = 0; /* avoid warning */
636 current_cs_base = 0; /* avoid warning */
637 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000638 tb = p->first_tb;
639 while (tb != NULL) {
640 n = (long)tb & 3;
641 tb = (TranslationBlock *)((long)tb & ~3);
642 tb_next = tb->page_next[n];
643 /* NOTE: this is subtle as a TB may span two physical pages */
644 if (n == 0) {
645 /* NOTE: tb_end may be after the end of the page, but
646 it is not a problem */
647 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
648 tb_end = tb_start + tb->size;
649 } else {
650 tb_start = tb->page_addr[1];
651 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
652 }
653 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000654#ifdef TARGET_HAS_PRECISE_SMC
655 if (current_tb_not_found) {
656 current_tb_not_found = 0;
657 current_tb = NULL;
658 if (env->mem_write_pc) {
659 /* now we have a real cpu fault */
660 current_tb = tb_find_pc(env->mem_write_pc);
661 }
662 }
663 if (current_tb == tb &&
664 !(current_tb->cflags & CF_SINGLE_INSN)) {
665 /* If we are modifying the current TB, we must stop
666 its execution. We could be more precise by checking
667 that the modification is after the current PC, but it
668 would require a specialized function to partially
669 restore the CPU state */
670
671 current_tb_modified = 1;
672 cpu_restore_state(current_tb, env,
673 env->mem_write_pc, NULL);
674#if defined(TARGET_I386)
675 current_flags = env->hflags;
676 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
677 current_cs_base = (target_ulong)env->segs[R_CS].base;
678 current_pc = current_cs_base + env->eip;
679#else
680#error unsupported CPU
681#endif
682 }
683#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000684 tb_phys_invalidate(tb, -1);
685 }
686 tb = tb_next;
687 }
688#if !defined(CONFIG_USER_ONLY)
689 /* if no code remaining, no need to continue to use slow writes */
690 if (!p->first_tb) {
691 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000692 if (is_cpu_write_access) {
693 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
694 }
695 }
696#endif
697#ifdef TARGET_HAS_PRECISE_SMC
698 if (current_tb_modified) {
699 /* we generate a block containing just the instruction
700 modifying the memory. It will ensure that it cannot modify
701 itself */
702 tb_gen_code(env, current_pc, current_cs_base, current_flags,
703 CF_SINGLE_INSN);
704 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000705 }
706#endif
707}
708
709/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000710static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000711{
712 PageDesc *p;
713 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000714#if 0
bellarda4193c82004-06-03 14:01:43 +0000715 if (1) {
716 if (loglevel) {
717 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
718 cpu_single_env->mem_write_vaddr, len,
719 cpu_single_env->eip,
720 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
721 }
bellard59817cc2004-02-16 22:01:13 +0000722 }
723#endif
bellard9fa3e852004-01-04 18:06:42 +0000724 p = page_find(start >> TARGET_PAGE_BITS);
725 if (!p)
726 return;
727 if (p->code_bitmap) {
728 offset = start & ~TARGET_PAGE_MASK;
729 b = p->code_bitmap[offset >> 3] >> (offset & 7);
730 if (b & ((1 << len) - 1))
731 goto do_invalidate;
732 } else {
733 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000734 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000735 }
736}
737
bellard9fa3e852004-01-04 18:06:42 +0000738#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000739static void tb_invalidate_phys_page(target_ulong addr,
740 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000741{
bellardd720b932004-04-25 17:57:43 +0000742 int n, current_flags, current_tb_modified;
743 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000744 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000745 TranslationBlock *tb, *current_tb;
746#ifdef TARGET_HAS_PRECISE_SMC
747 CPUState *env = cpu_single_env;
748#endif
bellard9fa3e852004-01-04 18:06:42 +0000749
750 addr &= TARGET_PAGE_MASK;
751 p = page_find(addr >> TARGET_PAGE_BITS);
752 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000753 return;
754 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000755 current_tb_modified = 0;
756 current_tb = NULL;
757 current_pc = 0; /* avoid warning */
758 current_cs_base = 0; /* avoid warning */
759 current_flags = 0; /* avoid warning */
760#ifdef TARGET_HAS_PRECISE_SMC
761 if (tb && pc != 0) {
762 current_tb = tb_find_pc(pc);
763 }
764#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000765 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000766 n = (long)tb & 3;
767 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000768#ifdef TARGET_HAS_PRECISE_SMC
769 if (current_tb == tb &&
770 !(current_tb->cflags & CF_SINGLE_INSN)) {
771 /* If we are modifying the current TB, we must stop
772 its execution. We could be more precise by checking
773 that the modification is after the current PC, but it
774 would require a specialized function to partially
775 restore the CPU state */
776
777 current_tb_modified = 1;
778 cpu_restore_state(current_tb, env, pc, puc);
779#if defined(TARGET_I386)
780 current_flags = env->hflags;
781 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
782 current_cs_base = (target_ulong)env->segs[R_CS].base;
783 current_pc = current_cs_base + env->eip;
784#else
785#error unsupported CPU
786#endif
787 }
788#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000789 tb_phys_invalidate(tb, addr);
790 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000791 }
792 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000793#ifdef TARGET_HAS_PRECISE_SMC
794 if (current_tb_modified) {
795 /* we generate a block containing just the instruction
796 modifying the memory. It will ensure that it cannot modify
797 itself */
798 tb_gen_code(env, current_pc, current_cs_base, current_flags,
799 CF_SINGLE_INSN);
800 cpu_resume_from_signal(env, puc);
801 }
802#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000803}
bellard9fa3e852004-01-04 18:06:42 +0000804#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000805
806/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000807static inline void tb_alloc_page(TranslationBlock *tb,
808 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000809{
810 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000811 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000812
bellard9fa3e852004-01-04 18:06:42 +0000813 tb->page_addr[n] = page_addr;
814 p = page_find(page_addr >> TARGET_PAGE_BITS);
815 tb->page_next[n] = p->first_tb;
816 last_first_tb = p->first_tb;
817 p->first_tb = (TranslationBlock *)((long)tb | n);
818 invalidate_page_bitmap(p);
819
bellardd720b932004-04-25 17:57:43 +0000820#ifdef TARGET_HAS_SMC
821
bellard9fa3e852004-01-04 18:06:42 +0000822#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000823 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000824 unsigned long host_start, host_end, addr;
825 int prot;
826
bellardfd6ce8f2003-05-14 19:00:11 +0000827 /* force the host page as non writable (writes will have a
828 page fault + mprotect overhead) */
bellardfd6ce8f2003-05-14 19:00:11 +0000829 host_start = page_addr & host_page_mask;
830 host_end = host_start + host_page_size;
831 prot = 0;
832 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
833 prot |= page_get_flags(addr);
834 mprotect((void *)host_start, host_page_size,
835 (prot & PAGE_BITS) & ~PAGE_WRITE);
836#ifdef DEBUG_TB_INVALIDATE
837 printf("protecting code page: 0x%08lx\n",
838 host_start);
839#endif
840 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000841 }
bellard9fa3e852004-01-04 18:06:42 +0000842#else
843 /* if some code is already present, then the pages are already
844 protected. So we handle the case where only the first TB is
845 allocated in a physical page */
846 if (!last_first_tb) {
847 target_ulong virt_addr;
848
849 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
850 tlb_protect_code(cpu_single_env, virt_addr);
851 }
852#endif
bellardd720b932004-04-25 17:57:43 +0000853
854#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000855}
856
857/* Allocate a new translation block. Flush the translation buffer if
858 too many translation blocks or too much generated code. */
bellardd4e81642003-05-25 16:46:15 +0000859TranslationBlock *tb_alloc(unsigned long pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000860{
861 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000862
863 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
864 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000865 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000866 tb = &tbs[nb_tbs++];
867 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000868 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000869 return tb;
870}
871
bellard9fa3e852004-01-04 18:06:42 +0000872/* add a new TB and link it to the physical page tables. phys_page2 is
873 (-1) to indicate that only one page contains the TB. */
874void tb_link_phys(TranslationBlock *tb,
875 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000876{
bellard9fa3e852004-01-04 18:06:42 +0000877 unsigned int h;
878 TranslationBlock **ptb;
879
880 /* add in the physical hash table */
881 h = tb_phys_hash_func(phys_pc);
882 ptb = &tb_phys_hash[h];
883 tb->phys_hash_next = *ptb;
884 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000885
886 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000887 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
888 if (phys_page2 != -1)
889 tb_alloc_page(tb, 1, phys_page2);
890 else
891 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +0000892#ifdef DEBUG_TB_CHECK
893 tb_page_check();
894#endif
bellard9fa3e852004-01-04 18:06:42 +0000895}
896
897/* link the tb with the other TBs */
898void tb_link(TranslationBlock *tb)
899{
900#if !defined(CONFIG_USER_ONLY)
901 {
902 VirtPageDesc *vp;
903 target_ulong addr;
904
905 /* save the code memory mappings (needed to invalidate the code) */
906 addr = tb->pc & TARGET_PAGE_MASK;
907 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000908#ifdef DEBUG_TLB_CHECK
909 if (vp->valid_tag == virt_valid_tag &&
910 vp->phys_addr != tb->page_addr[0]) {
911 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
912 addr, tb->page_addr[0], vp->phys_addr);
913 }
914#endif
bellard9fa3e852004-01-04 18:06:42 +0000915 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +0000916 if (vp->valid_tag != virt_valid_tag) {
917 vp->valid_tag = virt_valid_tag;
918#if !defined(CONFIG_SOFTMMU)
919 vp->prot = 0;
920#endif
921 }
bellard9fa3e852004-01-04 18:06:42 +0000922
923 if (tb->page_addr[1] != -1) {
924 addr += TARGET_PAGE_SIZE;
925 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000926#ifdef DEBUG_TLB_CHECK
927 if (vp->valid_tag == virt_valid_tag &&
928 vp->phys_addr != tb->page_addr[1]) {
929 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
930 addr, tb->page_addr[1], vp->phys_addr);
931 }
932#endif
bellard9fa3e852004-01-04 18:06:42 +0000933 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +0000934 if (vp->valid_tag != virt_valid_tag) {
935 vp->valid_tag = virt_valid_tag;
936#if !defined(CONFIG_SOFTMMU)
937 vp->prot = 0;
938#endif
939 }
bellard9fa3e852004-01-04 18:06:42 +0000940 }
941 }
942#endif
943
bellardd4e81642003-05-25 16:46:15 +0000944 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
945 tb->jmp_next[0] = NULL;
946 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000947#ifdef USE_CODE_COPY
948 tb->cflags &= ~CF_FP_USED;
949 if (tb->cflags & CF_TB_FP_USED)
950 tb->cflags |= CF_FP_USED;
951#endif
bellardd4e81642003-05-25 16:46:15 +0000952
953 /* init original jump addresses */
954 if (tb->tb_next_offset[0] != 0xffff)
955 tb_reset_jump(tb, 0);
956 if (tb->tb_next_offset[1] != 0xffff)
957 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +0000958}
959
bellarda513fe12003-05-27 23:29:48 +0000960/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
961 tb[1].tc_ptr. Return NULL if not found */
962TranslationBlock *tb_find_pc(unsigned long tc_ptr)
963{
964 int m_min, m_max, m;
965 unsigned long v;
966 TranslationBlock *tb;
967
968 if (nb_tbs <= 0)
969 return NULL;
970 if (tc_ptr < (unsigned long)code_gen_buffer ||
971 tc_ptr >= (unsigned long)code_gen_ptr)
972 return NULL;
973 /* binary search (cf Knuth) */
974 m_min = 0;
975 m_max = nb_tbs - 1;
976 while (m_min <= m_max) {
977 m = (m_min + m_max) >> 1;
978 tb = &tbs[m];
979 v = (unsigned long)tb->tc_ptr;
980 if (v == tc_ptr)
981 return tb;
982 else if (tc_ptr < v) {
983 m_max = m - 1;
984 } else {
985 m_min = m + 1;
986 }
987 }
988 return &tbs[m_max];
989}
bellard75012672003-06-21 13:11:07 +0000990
bellardea041c02003-06-25 16:16:50 +0000991static void tb_reset_jump_recursive(TranslationBlock *tb);
992
993static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
994{
995 TranslationBlock *tb1, *tb_next, **ptb;
996 unsigned int n1;
997
998 tb1 = tb->jmp_next[n];
999 if (tb1 != NULL) {
1000 /* find head of list */
1001 for(;;) {
1002 n1 = (long)tb1 & 3;
1003 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1004 if (n1 == 2)
1005 break;
1006 tb1 = tb1->jmp_next[n1];
1007 }
1008 /* we are now sure now that tb jumps to tb1 */
1009 tb_next = tb1;
1010
1011 /* remove tb from the jmp_first list */
1012 ptb = &tb_next->jmp_first;
1013 for(;;) {
1014 tb1 = *ptb;
1015 n1 = (long)tb1 & 3;
1016 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1017 if (n1 == n && tb1 == tb)
1018 break;
1019 ptb = &tb1->jmp_next[n1];
1020 }
1021 *ptb = tb->jmp_next[n];
1022 tb->jmp_next[n] = NULL;
1023
1024 /* suppress the jump to next tb in generated code */
1025 tb_reset_jump(tb, n);
1026
bellard01243112004-01-04 15:48:17 +00001027 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001028 tb_reset_jump_recursive(tb_next);
1029 }
1030}
1031
1032static void tb_reset_jump_recursive(TranslationBlock *tb)
1033{
1034 tb_reset_jump_recursive2(tb, 0);
1035 tb_reset_jump_recursive2(tb, 1);
1036}
1037
bellardd720b932004-04-25 17:57:43 +00001038static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1039{
1040 target_ulong phys_addr;
1041
1042 phys_addr = cpu_get_phys_page_debug(env, pc);
1043 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1044}
1045
bellardc33a3462003-07-29 20:50:33 +00001046/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1047 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001048int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001049{
bellarda541f292004-04-12 20:39:29 +00001050#if defined(TARGET_I386) || defined(TARGET_PPC)
bellard4c3a88a2003-07-26 12:06:08 +00001051 int i;
bellardd720b932004-04-25 17:57:43 +00001052
bellard4c3a88a2003-07-26 12:06:08 +00001053 for(i = 0; i < env->nb_breakpoints; i++) {
1054 if (env->breakpoints[i] == pc)
1055 return 0;
1056 }
1057
1058 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1059 return -1;
1060 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001061
1062 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001063 return 0;
1064#else
1065 return -1;
1066#endif
1067}
1068
1069/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001070int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001071{
bellarda541f292004-04-12 20:39:29 +00001072#if defined(TARGET_I386) || defined(TARGET_PPC)
bellard4c3a88a2003-07-26 12:06:08 +00001073 int i;
1074 for(i = 0; i < env->nb_breakpoints; i++) {
1075 if (env->breakpoints[i] == pc)
1076 goto found;
1077 }
1078 return -1;
1079 found:
1080 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
1081 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
1082 env->nb_breakpoints--;
bellardd720b932004-04-25 17:57:43 +00001083
1084 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001085 return 0;
1086#else
1087 return -1;
1088#endif
1089}
1090
bellardc33a3462003-07-29 20:50:33 +00001091/* enable or disable single step mode. EXCP_DEBUG is returned by the
1092 CPU loop after each instruction */
1093void cpu_single_step(CPUState *env, int enabled)
1094{
bellarda541f292004-04-12 20:39:29 +00001095#if defined(TARGET_I386) || defined(TARGET_PPC)
bellardc33a3462003-07-29 20:50:33 +00001096 if (env->singlestep_enabled != enabled) {
1097 env->singlestep_enabled = enabled;
1098 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001099 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001100 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001101 }
1102#endif
1103}
1104
bellard34865132003-10-05 14:28:56 +00001105/* enable or disable low levels log */
1106void cpu_set_log(int log_flags)
1107{
1108 loglevel = log_flags;
1109 if (loglevel && !logfile) {
1110 logfile = fopen(logfilename, "w");
1111 if (!logfile) {
1112 perror(logfilename);
1113 _exit(1);
1114 }
bellard9fa3e852004-01-04 18:06:42 +00001115#if !defined(CONFIG_SOFTMMU)
1116 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1117 {
1118 static uint8_t logfile_buf[4096];
1119 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1120 }
1121#else
bellard34865132003-10-05 14:28:56 +00001122 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001123#endif
bellard34865132003-10-05 14:28:56 +00001124 }
1125}
1126
1127void cpu_set_log_filename(const char *filename)
1128{
1129 logfilename = strdup(filename);
1130}
bellardc33a3462003-07-29 20:50:33 +00001131
bellard01243112004-01-04 15:48:17 +00001132/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001133void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001134{
1135 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001136 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001137
bellard68a79312003-06-30 13:12:32 +00001138 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001139 /* if the cpu is currently executing code, we must unlink it and
1140 all the potentially executing TB */
1141 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001142 if (tb && !testandset(&interrupt_lock)) {
1143 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001144 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001145 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001146 }
1147}
1148
bellardb54ad042004-05-20 13:42:52 +00001149void cpu_reset_interrupt(CPUState *env, int mask)
1150{
1151 env->interrupt_request &= ~mask;
1152}
1153
bellardf193c792004-03-21 17:06:25 +00001154CPULogItem cpu_log_items[] = {
1155 { CPU_LOG_TB_OUT_ASM, "out_asm",
1156 "show generated host assembly code for each compiled TB" },
1157 { CPU_LOG_TB_IN_ASM, "in_asm",
1158 "show target assembly code for each compiled TB" },
1159 { CPU_LOG_TB_OP, "op",
1160 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1161#ifdef TARGET_I386
1162 { CPU_LOG_TB_OP_OPT, "op_opt",
1163 "show micro ops after optimization for each compiled TB" },
1164#endif
1165 { CPU_LOG_INT, "int",
1166 "show interrupts/exceptions in short format" },
1167 { CPU_LOG_EXEC, "exec",
1168 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001169 { CPU_LOG_TB_CPU, "cpu",
1170 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001171#ifdef TARGET_I386
1172 { CPU_LOG_PCALL, "pcall",
1173 "show protected mode far calls/returns/exceptions" },
1174#endif
bellardfd872592004-05-12 19:11:15 +00001175 { CPU_LOG_IOPORT, "ioport",
1176 "show all i/o ports accesses" },
bellardf193c792004-03-21 17:06:25 +00001177 { 0, NULL, NULL },
1178};
1179
1180static int cmp1(const char *s1, int n, const char *s2)
1181{
1182 if (strlen(s2) != n)
1183 return 0;
1184 return memcmp(s1, s2, n) == 0;
1185}
1186
1187/* takes a comma separated list of log masks. Return 0 if error. */
1188int cpu_str_to_log_mask(const char *str)
1189{
1190 CPULogItem *item;
1191 int mask;
1192 const char *p, *p1;
1193
1194 p = str;
1195 mask = 0;
1196 for(;;) {
1197 p1 = strchr(p, ',');
1198 if (!p1)
1199 p1 = p + strlen(p);
1200 for(item = cpu_log_items; item->mask != 0; item++) {
1201 if (cmp1(p, p1 - p, item->name))
1202 goto found;
1203 }
1204 return 0;
1205 found:
1206 mask |= item->mask;
1207 if (*p1 != ',')
1208 break;
1209 p = p1 + 1;
1210 }
1211 return mask;
1212}
bellardea041c02003-06-25 16:16:50 +00001213
bellard75012672003-06-21 13:11:07 +00001214void cpu_abort(CPUState *env, const char *fmt, ...)
1215{
1216 va_list ap;
1217
1218 va_start(ap, fmt);
1219 fprintf(stderr, "qemu: fatal: ");
1220 vfprintf(stderr, fmt, ap);
1221 fprintf(stderr, "\n");
1222#ifdef TARGET_I386
1223 cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
1224#endif
1225 va_end(ap);
1226 abort();
1227}
1228
bellard01243112004-01-04 15:48:17 +00001229#if !defined(CONFIG_USER_ONLY)
1230
bellardee8b7022004-02-03 23:35:10 +00001231/* NOTE: if flush_global is true, also flush global entries (not
1232 implemented yet) */
1233void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001234{
bellard33417e72003-08-10 21:47:01 +00001235 int i;
bellard01243112004-01-04 15:48:17 +00001236
bellard9fa3e852004-01-04 18:06:42 +00001237#if defined(DEBUG_TLB)
1238 printf("tlb_flush:\n");
1239#endif
bellard01243112004-01-04 15:48:17 +00001240 /* must reset current TB so that interrupts cannot modify the
1241 links while we are modifying them */
1242 env->current_tb = NULL;
1243
bellard33417e72003-08-10 21:47:01 +00001244 for(i = 0; i < CPU_TLB_SIZE; i++) {
1245 env->tlb_read[0][i].address = -1;
1246 env->tlb_write[0][i].address = -1;
1247 env->tlb_read[1][i].address = -1;
1248 env->tlb_write[1][i].address = -1;
1249 }
bellard9fa3e852004-01-04 18:06:42 +00001250
1251 virt_page_flush();
1252 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
1253 tb_hash[i] = NULL;
1254
1255#if !defined(CONFIG_SOFTMMU)
1256 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1257#endif
bellard33417e72003-08-10 21:47:01 +00001258}
1259
bellard274da6b2004-05-20 21:56:27 +00001260static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001261{
1262 if (addr == (tlb_entry->address &
1263 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1264 tlb_entry->address = -1;
1265}
1266
bellard2e126692004-04-25 21:28:44 +00001267void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001268{
bellard9fa3e852004-01-04 18:06:42 +00001269 int i, n;
1270 VirtPageDesc *vp;
1271 PageDesc *p;
1272 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001273
bellard9fa3e852004-01-04 18:06:42 +00001274#if defined(DEBUG_TLB)
1275 printf("tlb_flush_page: 0x%08x\n", addr);
1276#endif
bellard01243112004-01-04 15:48:17 +00001277 /* must reset current TB so that interrupts cannot modify the
1278 links while we are modifying them */
1279 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001280
bellard61382a52003-10-27 21:22:23 +00001281 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001282 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001283 tlb_flush_entry(&env->tlb_read[0][i], addr);
1284 tlb_flush_entry(&env->tlb_write[0][i], addr);
1285 tlb_flush_entry(&env->tlb_read[1][i], addr);
1286 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001287
bellard9fa3e852004-01-04 18:06:42 +00001288 /* remove from the virtual pc hash table all the TB at this
1289 virtual address */
1290
1291 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1292 if (vp && vp->valid_tag == virt_valid_tag) {
1293 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1294 if (p) {
1295 /* we remove all the links to the TBs in this virtual page */
1296 tb = p->first_tb;
1297 while (tb != NULL) {
1298 n = (long)tb & 3;
1299 tb = (TranslationBlock *)((long)tb & ~3);
1300 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1301 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1302 tb_invalidate(tb);
1303 }
1304 tb = tb->page_next[n];
1305 }
1306 }
bellard98857882004-01-18 21:52:14 +00001307 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001308 }
1309
bellard01243112004-01-04 15:48:17 +00001310#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001311 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001312 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001313#endif
bellard9fa3e852004-01-04 18:06:42 +00001314}
1315
bellard4f2ac232004-04-26 19:44:02 +00001316static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001317{
1318 if (addr == (tlb_entry->address &
1319 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001320 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1321 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001322 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001323 }
bellard61382a52003-10-27 21:22:23 +00001324}
1325
bellard9fa3e852004-01-04 18:06:42 +00001326/* update the TLBs so that writes to code in the virtual page 'addr'
1327 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001328static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001329{
bellard61382a52003-10-27 21:22:23 +00001330 int i;
1331
1332 addr &= TARGET_PAGE_MASK;
1333 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001334 tlb_protect_code1(&env->tlb_write[0][i], addr);
1335 tlb_protect_code1(&env->tlb_write[1][i], addr);
1336#if !defined(CONFIG_SOFTMMU)
1337 /* NOTE: as we generated the code for this page, it is already at
1338 least readable */
1339 if (addr < MMAP_AREA_END)
1340 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1341#endif
1342}
1343
bellard9fa3e852004-01-04 18:06:42 +00001344static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001345 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001346{
1347 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1348 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001349 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001350 }
1351}
1352
1353/* update the TLB so that writes in physical page 'phys_addr' are no longer
1354 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001355static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001356{
1357 int i;
1358
1359 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001360 phys_addr += (long)phys_ram_base;
1361 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1362 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1363 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1364}
1365
1366static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1367 unsigned long start, unsigned long length)
1368{
1369 unsigned long addr;
1370 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1371 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1372 if ((addr - start) < length) {
1373 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1374 }
1375 }
1376}
1377
1378void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
1379{
1380 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001381 unsigned long length, start1;
bellard1ccde1c2004-02-06 19:46:14 +00001382 int i;
1383
1384 start &= TARGET_PAGE_MASK;
1385 end = TARGET_PAGE_ALIGN(end);
1386
1387 length = end - start;
1388 if (length == 0)
1389 return;
1390 memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
1391
1392 env = cpu_single_env;
1393 /* we modify the TLB cache so that the dirty bit will be set again
1394 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001395 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001396 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001397 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001398 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001399 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1400
1401#if !defined(CONFIG_SOFTMMU)
1402 /* XXX: this is expensive */
1403 {
1404 VirtPageDesc *p;
1405 int j;
1406 target_ulong addr;
1407
1408 for(i = 0; i < L1_SIZE; i++) {
1409 p = l1_virt_map[i];
1410 if (p) {
1411 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1412 for(j = 0; j < L2_SIZE; j++) {
1413 if (p->valid_tag == virt_valid_tag &&
1414 p->phys_addr >= start && p->phys_addr < end &&
1415 (p->prot & PROT_WRITE)) {
1416 if (addr < MMAP_AREA_END) {
1417 mprotect((void *)addr, TARGET_PAGE_SIZE,
1418 p->prot & ~PROT_WRITE);
1419 }
1420 }
1421 addr += TARGET_PAGE_SIZE;
1422 p++;
1423 }
1424 }
1425 }
1426 }
1427#endif
bellard1ccde1c2004-02-06 19:46:14 +00001428}
1429
1430static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1431 unsigned long start)
1432{
1433 unsigned long addr;
1434 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1435 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1436 if (addr == start) {
1437 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1438 }
1439 }
1440}
1441
1442/* update the TLB corresponding to virtual page vaddr and phys addr
1443 addr so that it is no longer dirty */
1444static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1445{
1446 CPUState *env = cpu_single_env;
1447 int i;
1448
1449 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
1450
1451 addr &= TARGET_PAGE_MASK;
1452 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1453 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1454 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001455}
1456
bellard59817cc2004-02-16 22:01:13 +00001457/* add a new TLB entry. At most one entry for a given virtual address
1458 is permitted. Return 0 if OK or 2 if the page could not be mapped
1459 (can only happen in non SOFTMMU mode for I/O pages or pages
1460 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001461int tlb_set_page(CPUState *env, target_ulong vaddr,
1462 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001463 int is_user, int is_softmmu)
1464{
bellard92e873b2004-05-21 14:52:29 +00001465 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001466 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001467 TranslationBlock *first_tb;
1468 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001469 target_ulong address;
1470 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001471 int ret;
1472
bellard92e873b2004-05-21 14:52:29 +00001473 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1474 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001475 if (!p) {
1476 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001477 } else {
bellard92e873b2004-05-21 14:52:29 +00001478 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001479 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001480 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1481 /* NOTE: we also allocate the page at this stage */
1482 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1483 first_tb = p1->first_tb;
1484 }
bellard9fa3e852004-01-04 18:06:42 +00001485 }
1486#if defined(DEBUG_TLB)
1487 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1488 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1489#endif
1490
1491 ret = 0;
1492#if !defined(CONFIG_SOFTMMU)
1493 if (is_softmmu)
1494#endif
1495 {
1496 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1497 /* IO memory case */
1498 address = vaddr | pd;
1499 addend = paddr;
1500 } else {
1501 /* standard memory */
1502 address = vaddr;
1503 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1504 }
1505
1506 index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1507 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001508 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001509 env->tlb_read[is_user][index].address = address;
1510 env->tlb_read[is_user][index].addend = addend;
1511 } else {
1512 env->tlb_read[is_user][index].address = -1;
1513 env->tlb_read[is_user][index].addend = -1;
1514 }
bellard67b915a2004-03-31 23:37:16 +00001515 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001516 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1517 /* ROM: access is ignored (same as unassigned) */
1518 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001519 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001520 } else
1521 /* XXX: the PowerPC code seems not ready to handle
1522 self modifying code with DCBI */
1523#if defined(TARGET_HAS_SMC) || 1
1524 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001525 /* if code is present, we use a specific memory
1526 handler. It works only for physical memory access */
1527 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001528 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001529 } else
1530#endif
1531 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001532 !cpu_physical_memory_is_dirty(pd)) {
1533 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1534 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001535 } else {
1536 env->tlb_write[is_user][index].address = address;
1537 env->tlb_write[is_user][index].addend = addend;
1538 }
1539 } else {
1540 env->tlb_write[is_user][index].address = -1;
1541 env->tlb_write[is_user][index].addend = -1;
1542 }
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
1569 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1570 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. */
bellardd720b932004-04-25 17:57:43 +00001591int page_unprotect(unsigned long 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 */
1621 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1622 /* 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
bellard2e126692004-04-25 21:28:44 +00001640int tlb_set_page(CPUState *env, target_ulong vaddr,
1641 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001642 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
bellard9fa3e852004-01-04 18:06:42 +00001690int page_get_flags(unsigned long 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 */
1703void page_set_flags(unsigned long start, unsigned long end, int flags)
1704{
1705 PageDesc *p;
1706 unsigned long addr;
1707
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. */
bellardd720b932004-04-25 17:57:43 +00001729int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001730{
1731 unsigned int page_index, prot, pindex;
1732 PageDesc *p, *p1;
1733 unsigned long host_start, host_end, addr;
1734
1735 host_start = address & host_page_mask;
1736 page_index = host_start >> TARGET_PAGE_BITS;
1737 p1 = page_find(page_index);
1738 if (!p1)
1739 return 0;
1740 host_end = host_start + host_page_size;
1741 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)) {
1752 mprotect((void *)host_start, host_page_size,
1753 (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 */
1768void page_unprotect_range(uint8_t *data, unsigned long data_size)
1769{
1770 unsigned long start, end, addr;
1771
1772 start = (unsigned long)data;
1773 end = start + data_size;
1774 start &= TARGET_PAGE_MASK;
1775 end = TARGET_PAGE_ALIGN(end);
1776 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001777 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001778 }
1779}
1780
bellard1ccde1c2004-02-06 19:46:14 +00001781static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1782{
1783}
bellard9fa3e852004-01-04 18:06:42 +00001784#endif /* defined(CONFIG_USER_ONLY) */
1785
bellard33417e72003-08-10 21:47:01 +00001786/* register physical memory. 'size' must be a multiple of the target
1787 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1788 io memory page */
bellard2e126692004-04-25 21:28:44 +00001789void cpu_register_physical_memory(target_phys_addr_t start_addr,
1790 unsigned long size,
1791 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001792{
1793 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001794 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001795
bellard5fd386f2004-05-23 21:11:22 +00001796 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001797 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001798 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001799 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001800 p->phys_offset = phys_offset;
1801 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001802 phys_offset += TARGET_PAGE_SIZE;
1803 }
1804}
1805
bellarda4193c82004-06-03 14:01:43 +00001806static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001807{
1808 return 0;
1809}
1810
bellarda4193c82004-06-03 14:01:43 +00001811static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001812{
1813}
1814
1815static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1816 unassigned_mem_readb,
1817 unassigned_mem_readb,
1818 unassigned_mem_readb,
1819};
1820
1821static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1822 unassigned_mem_writeb,
1823 unassigned_mem_writeb,
1824 unassigned_mem_writeb,
1825};
1826
bellard9fa3e852004-01-04 18:06:42 +00001827/* self modifying code support in soft mmu mode : writing to a page
1828 containing code comes to these functions */
1829
bellarda4193c82004-06-03 14:01:43 +00001830static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001831{
bellard1ccde1c2004-02-06 19:46:14 +00001832 unsigned long phys_addr;
1833
bellard274da6b2004-05-20 21:56:27 +00001834 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001835#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001836 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001837#endif
bellard1ccde1c2004-02-06 19:46:14 +00001838 stb_raw((uint8_t *)addr, val);
1839 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001840}
1841
bellarda4193c82004-06-03 14:01:43 +00001842static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001843{
bellard1ccde1c2004-02-06 19:46:14 +00001844 unsigned long phys_addr;
1845
bellard274da6b2004-05-20 21:56:27 +00001846 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001847#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001848 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001849#endif
bellard1ccde1c2004-02-06 19:46:14 +00001850 stw_raw((uint8_t *)addr, val);
1851 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001852}
1853
bellarda4193c82004-06-03 14:01:43 +00001854static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001855{
bellard1ccde1c2004-02-06 19:46:14 +00001856 unsigned long phys_addr;
1857
bellard274da6b2004-05-20 21:56:27 +00001858 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001859#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001860 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00001861#endif
bellard1ccde1c2004-02-06 19:46:14 +00001862 stl_raw((uint8_t *)addr, val);
1863 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001864}
1865
1866static CPUReadMemoryFunc *code_mem_read[3] = {
1867 NULL, /* never used */
1868 NULL, /* never used */
1869 NULL, /* never used */
1870};
1871
1872static CPUWriteMemoryFunc *code_mem_write[3] = {
1873 code_mem_writeb,
1874 code_mem_writew,
1875 code_mem_writel,
1876};
bellard33417e72003-08-10 21:47:01 +00001877
bellarda4193c82004-06-03 14:01:43 +00001878static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001879{
1880 stb_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001881 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001882}
1883
bellarda4193c82004-06-03 14:01:43 +00001884static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001885{
1886 stw_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001887 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001888}
1889
bellarda4193c82004-06-03 14:01:43 +00001890static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001891{
1892 stl_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001893 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001894}
1895
1896static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1897 notdirty_mem_writeb,
1898 notdirty_mem_writew,
1899 notdirty_mem_writel,
1900};
1901
bellard33417e72003-08-10 21:47:01 +00001902static void io_mem_init(void)
1903{
bellarda4193c82004-06-03 14:01:43 +00001904 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1905 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1906 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1907 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001908 io_mem_nb = 5;
1909
1910 /* alloc dirty bits array */
bellard59817cc2004-02-16 22:01:13 +00001911 phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001912}
1913
1914/* mem_read and mem_write are arrays of functions containing the
1915 function to access byte (index 0), word (index 1) and dword (index
1916 2). All functions must be supplied. If io_index is non zero, the
1917 corresponding io zone is modified. If it is zero, a new io zone is
1918 allocated. The return value can be used with
1919 cpu_register_physical_memory(). (-1) is returned if error. */
1920int cpu_register_io_memory(int io_index,
1921 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001922 CPUWriteMemoryFunc **mem_write,
1923 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001924{
1925 int i;
1926
1927 if (io_index <= 0) {
1928 if (io_index >= IO_MEM_NB_ENTRIES)
1929 return -1;
1930 io_index = io_mem_nb++;
1931 } else {
1932 if (io_index >= IO_MEM_NB_ENTRIES)
1933 return -1;
1934 }
1935
1936 for(i = 0;i < 3; i++) {
1937 io_mem_read[io_index][i] = mem_read[i];
1938 io_mem_write[io_index][i] = mem_write[i];
1939 }
bellarda4193c82004-06-03 14:01:43 +00001940 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001941 return io_index << IO_MEM_SHIFT;
1942}
bellard61382a52003-10-27 21:22:23 +00001943
bellard13eb76e2004-01-24 15:23:36 +00001944/* physical memory access (slow version, mainly for debug) */
1945#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001946void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001947 int len, int is_write)
1948{
1949 int l, flags;
1950 target_ulong page;
1951
1952 while (len > 0) {
1953 page = addr & TARGET_PAGE_MASK;
1954 l = (page + TARGET_PAGE_SIZE) - addr;
1955 if (l > len)
1956 l = len;
1957 flags = page_get_flags(page);
1958 if (!(flags & PAGE_VALID))
1959 return;
1960 if (is_write) {
1961 if (!(flags & PAGE_WRITE))
1962 return;
1963 memcpy((uint8_t *)addr, buf, len);
1964 } else {
1965 if (!(flags & PAGE_READ))
1966 return;
1967 memcpy(buf, (uint8_t *)addr, len);
1968 }
1969 len -= l;
1970 buf += l;
1971 addr += l;
1972 }
1973}
1974#else
bellard2e126692004-04-25 21:28:44 +00001975void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001976 int len, int is_write)
1977{
1978 int l, io_index;
1979 uint8_t *ptr;
1980 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00001981 target_phys_addr_t page;
1982 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00001983 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00001984
1985 while (len > 0) {
1986 page = addr & TARGET_PAGE_MASK;
1987 l = (page + TARGET_PAGE_SIZE) - addr;
1988 if (l > len)
1989 l = len;
bellard92e873b2004-05-21 14:52:29 +00001990 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00001991 if (!p) {
1992 pd = IO_MEM_UNASSIGNED;
1993 } else {
1994 pd = p->phys_offset;
1995 }
1996
1997 if (is_write) {
1998 if ((pd & ~TARGET_PAGE_MASK) != 0) {
1999 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2000 if (l >= 4 && ((addr & 3) == 0)) {
2001 /* 32 bit read access */
2002 val = ldl_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002003 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002004 l = 4;
2005 } else if (l >= 2 && ((addr & 1) == 0)) {
2006 /* 16 bit read access */
2007 val = lduw_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002008 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002009 l = 2;
2010 } else {
2011 /* 8 bit access */
2012 val = ldub_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002013 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002014 l = 1;
2015 }
2016 } else {
bellardb448f2f2004-02-25 23:24:04 +00002017 unsigned long addr1;
2018 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002019 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002020 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002021 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002022 /* invalidate code */
2023 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2024 /* set dirty bit */
2025 phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1;
bellard13eb76e2004-01-24 15:23:36 +00002026 }
2027 } else {
2028 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2029 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2030 /* I/O case */
2031 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2032 if (l >= 4 && ((addr & 3) == 0)) {
2033 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002034 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002035 stl_raw(buf, val);
2036 l = 4;
2037 } else if (l >= 2 && ((addr & 1) == 0)) {
2038 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002039 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002040 stw_raw(buf, val);
2041 l = 2;
2042 } else {
2043 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002044 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002045 stb_raw(buf, val);
2046 l = 1;
2047 }
2048 } else {
2049 /* RAM case */
2050 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2051 (addr & ~TARGET_PAGE_MASK);
2052 memcpy(buf, ptr, l);
2053 }
2054 }
2055 len -= l;
2056 buf += l;
2057 addr += l;
2058 }
2059}
2060#endif
2061
2062/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002063int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2064 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002065{
2066 int l;
2067 target_ulong page, phys_addr;
2068
2069 while (len > 0) {
2070 page = addr & TARGET_PAGE_MASK;
2071 phys_addr = cpu_get_phys_page_debug(env, page);
2072 /* if no physical page mapped, return an error */
2073 if (phys_addr == -1)
2074 return -1;
2075 l = (page + TARGET_PAGE_SIZE) - addr;
2076 if (l > len)
2077 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002078 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2079 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002080 len -= l;
2081 buf += l;
2082 addr += l;
2083 }
2084 return 0;
2085}
2086
bellard61382a52003-10-27 21:22:23 +00002087#if !defined(CONFIG_USER_ONLY)
2088
2089#define MMUSUFFIX _cmmu
2090#define GETPC() NULL
2091#define env cpu_single_env
2092
2093#define SHIFT 0
2094#include "softmmu_template.h"
2095
2096#define SHIFT 1
2097#include "softmmu_template.h"
2098
2099#define SHIFT 2
2100#include "softmmu_template.h"
2101
2102#define SHIFT 3
2103#include "softmmu_template.h"
2104
2105#undef env
2106
2107#endif