blob: 91694a53a20b9a9a113f610071e1a5b64f57f119 [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;
bellardea1c1802004-06-14 18:56:36 +0000616 TranslationBlock *tb, *tb_next, *current_tb, *saved_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 */
bellardea1c1802004-06-14 18:56:36 +0000684 saved_tb = env->current_tb;
685 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000686 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000687 env->current_tb = saved_tb;
688 if (env->interrupt_request && env->current_tb)
689 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000690 }
691 tb = tb_next;
692 }
693#if !defined(CONFIG_USER_ONLY)
694 /* if no code remaining, no need to continue to use slow writes */
695 if (!p->first_tb) {
696 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000697 if (is_cpu_write_access) {
698 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
699 }
700 }
701#endif
702#ifdef TARGET_HAS_PRECISE_SMC
703 if (current_tb_modified) {
704 /* we generate a block containing just the instruction
705 modifying the memory. It will ensure that it cannot modify
706 itself */
bellardea1c1802004-06-14 18:56:36 +0000707 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000708 tb_gen_code(env, current_pc, current_cs_base, current_flags,
709 CF_SINGLE_INSN);
710 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000711 }
712#endif
713}
714
715/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000716static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000717{
718 PageDesc *p;
719 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000720#if 0
bellarda4193c82004-06-03 14:01:43 +0000721 if (1) {
722 if (loglevel) {
723 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
724 cpu_single_env->mem_write_vaddr, len,
725 cpu_single_env->eip,
726 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
727 }
bellard59817cc2004-02-16 22:01:13 +0000728 }
729#endif
bellard9fa3e852004-01-04 18:06:42 +0000730 p = page_find(start >> TARGET_PAGE_BITS);
731 if (!p)
732 return;
733 if (p->code_bitmap) {
734 offset = start & ~TARGET_PAGE_MASK;
735 b = p->code_bitmap[offset >> 3] >> (offset & 7);
736 if (b & ((1 << len) - 1))
737 goto do_invalidate;
738 } else {
739 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000740 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000741 }
742}
743
bellard9fa3e852004-01-04 18:06:42 +0000744#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000745static void tb_invalidate_phys_page(target_ulong addr,
746 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000747{
bellardd720b932004-04-25 17:57:43 +0000748 int n, current_flags, current_tb_modified;
749 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000750 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000751 TranslationBlock *tb, *current_tb;
752#ifdef TARGET_HAS_PRECISE_SMC
753 CPUState *env = cpu_single_env;
754#endif
bellard9fa3e852004-01-04 18:06:42 +0000755
756 addr &= TARGET_PAGE_MASK;
757 p = page_find(addr >> TARGET_PAGE_BITS);
758 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000759 return;
760 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000761 current_tb_modified = 0;
762 current_tb = NULL;
763 current_pc = 0; /* avoid warning */
764 current_cs_base = 0; /* avoid warning */
765 current_flags = 0; /* avoid warning */
766#ifdef TARGET_HAS_PRECISE_SMC
767 if (tb && pc != 0) {
768 current_tb = tb_find_pc(pc);
769 }
770#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000771 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000772 n = (long)tb & 3;
773 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000774#ifdef TARGET_HAS_PRECISE_SMC
775 if (current_tb == tb &&
776 !(current_tb->cflags & CF_SINGLE_INSN)) {
777 /* If we are modifying the current TB, we must stop
778 its execution. We could be more precise by checking
779 that the modification is after the current PC, but it
780 would require a specialized function to partially
781 restore the CPU state */
782
783 current_tb_modified = 1;
784 cpu_restore_state(current_tb, env, pc, puc);
785#if defined(TARGET_I386)
786 current_flags = env->hflags;
787 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
788 current_cs_base = (target_ulong)env->segs[R_CS].base;
789 current_pc = current_cs_base + env->eip;
790#else
791#error unsupported CPU
792#endif
793 }
794#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000795 tb_phys_invalidate(tb, addr);
796 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000797 }
798 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000799#ifdef TARGET_HAS_PRECISE_SMC
800 if (current_tb_modified) {
801 /* we generate a block containing just the instruction
802 modifying the memory. It will ensure that it cannot modify
803 itself */
bellardea1c1802004-06-14 18:56:36 +0000804 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000805 tb_gen_code(env, current_pc, current_cs_base, current_flags,
806 CF_SINGLE_INSN);
807 cpu_resume_from_signal(env, puc);
808 }
809#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000810}
bellard9fa3e852004-01-04 18:06:42 +0000811#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000812
813/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000814static inline void tb_alloc_page(TranslationBlock *tb,
815 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000816{
817 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000818 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000819
bellard9fa3e852004-01-04 18:06:42 +0000820 tb->page_addr[n] = page_addr;
821 p = page_find(page_addr >> TARGET_PAGE_BITS);
822 tb->page_next[n] = p->first_tb;
823 last_first_tb = p->first_tb;
824 p->first_tb = (TranslationBlock *)((long)tb | n);
825 invalidate_page_bitmap(p);
826
bellardd720b932004-04-25 17:57:43 +0000827#ifdef TARGET_HAS_SMC
828
bellard9fa3e852004-01-04 18:06:42 +0000829#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000830 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000831 unsigned long host_start, host_end, addr;
832 int prot;
833
bellardfd6ce8f2003-05-14 19:00:11 +0000834 /* force the host page as non writable (writes will have a
835 page fault + mprotect overhead) */
bellardfd6ce8f2003-05-14 19:00:11 +0000836 host_start = page_addr & host_page_mask;
837 host_end = host_start + host_page_size;
838 prot = 0;
839 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
840 prot |= page_get_flags(addr);
841 mprotect((void *)host_start, host_page_size,
842 (prot & PAGE_BITS) & ~PAGE_WRITE);
843#ifdef DEBUG_TB_INVALIDATE
844 printf("protecting code page: 0x%08lx\n",
845 host_start);
846#endif
847 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000848 }
bellard9fa3e852004-01-04 18:06:42 +0000849#else
850 /* if some code is already present, then the pages are already
851 protected. So we handle the case where only the first TB is
852 allocated in a physical page */
853 if (!last_first_tb) {
854 target_ulong virt_addr;
855
856 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
857 tlb_protect_code(cpu_single_env, virt_addr);
858 }
859#endif
bellardd720b932004-04-25 17:57:43 +0000860
861#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000862}
863
864/* Allocate a new translation block. Flush the translation buffer if
865 too many translation blocks or too much generated code. */
bellardd4e81642003-05-25 16:46:15 +0000866TranslationBlock *tb_alloc(unsigned long pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000867{
868 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000869
870 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
871 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000872 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000873 tb = &tbs[nb_tbs++];
874 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000875 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000876 return tb;
877}
878
bellard9fa3e852004-01-04 18:06:42 +0000879/* add a new TB and link it to the physical page tables. phys_page2 is
880 (-1) to indicate that only one page contains the TB. */
881void tb_link_phys(TranslationBlock *tb,
882 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000883{
bellard9fa3e852004-01-04 18:06:42 +0000884 unsigned int h;
885 TranslationBlock **ptb;
886
887 /* add in the physical hash table */
888 h = tb_phys_hash_func(phys_pc);
889 ptb = &tb_phys_hash[h];
890 tb->phys_hash_next = *ptb;
891 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000892
893 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000894 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
895 if (phys_page2 != -1)
896 tb_alloc_page(tb, 1, phys_page2);
897 else
898 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +0000899#ifdef DEBUG_TB_CHECK
900 tb_page_check();
901#endif
bellard9fa3e852004-01-04 18:06:42 +0000902}
903
904/* link the tb with the other TBs */
905void tb_link(TranslationBlock *tb)
906{
907#if !defined(CONFIG_USER_ONLY)
908 {
909 VirtPageDesc *vp;
910 target_ulong addr;
911
912 /* save the code memory mappings (needed to invalidate the code) */
913 addr = tb->pc & TARGET_PAGE_MASK;
914 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000915#ifdef DEBUG_TLB_CHECK
916 if (vp->valid_tag == virt_valid_tag &&
917 vp->phys_addr != tb->page_addr[0]) {
918 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
919 addr, tb->page_addr[0], vp->phys_addr);
920 }
921#endif
bellard9fa3e852004-01-04 18:06:42 +0000922 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +0000923 if (vp->valid_tag != virt_valid_tag) {
924 vp->valid_tag = virt_valid_tag;
925#if !defined(CONFIG_SOFTMMU)
926 vp->prot = 0;
927#endif
928 }
bellard9fa3e852004-01-04 18:06:42 +0000929
930 if (tb->page_addr[1] != -1) {
931 addr += TARGET_PAGE_SIZE;
932 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000933#ifdef DEBUG_TLB_CHECK
934 if (vp->valid_tag == virt_valid_tag &&
935 vp->phys_addr != tb->page_addr[1]) {
936 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
937 addr, tb->page_addr[1], vp->phys_addr);
938 }
939#endif
bellard9fa3e852004-01-04 18:06:42 +0000940 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +0000941 if (vp->valid_tag != virt_valid_tag) {
942 vp->valid_tag = virt_valid_tag;
943#if !defined(CONFIG_SOFTMMU)
944 vp->prot = 0;
945#endif
946 }
bellard9fa3e852004-01-04 18:06:42 +0000947 }
948 }
949#endif
950
bellardd4e81642003-05-25 16:46:15 +0000951 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
952 tb->jmp_next[0] = NULL;
953 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000954#ifdef USE_CODE_COPY
955 tb->cflags &= ~CF_FP_USED;
956 if (tb->cflags & CF_TB_FP_USED)
957 tb->cflags |= CF_FP_USED;
958#endif
bellardd4e81642003-05-25 16:46:15 +0000959
960 /* init original jump addresses */
961 if (tb->tb_next_offset[0] != 0xffff)
962 tb_reset_jump(tb, 0);
963 if (tb->tb_next_offset[1] != 0xffff)
964 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +0000965}
966
bellarda513fe12003-05-27 23:29:48 +0000967/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
968 tb[1].tc_ptr. Return NULL if not found */
969TranslationBlock *tb_find_pc(unsigned long tc_ptr)
970{
971 int m_min, m_max, m;
972 unsigned long v;
973 TranslationBlock *tb;
974
975 if (nb_tbs <= 0)
976 return NULL;
977 if (tc_ptr < (unsigned long)code_gen_buffer ||
978 tc_ptr >= (unsigned long)code_gen_ptr)
979 return NULL;
980 /* binary search (cf Knuth) */
981 m_min = 0;
982 m_max = nb_tbs - 1;
983 while (m_min <= m_max) {
984 m = (m_min + m_max) >> 1;
985 tb = &tbs[m];
986 v = (unsigned long)tb->tc_ptr;
987 if (v == tc_ptr)
988 return tb;
989 else if (tc_ptr < v) {
990 m_max = m - 1;
991 } else {
992 m_min = m + 1;
993 }
994 }
995 return &tbs[m_max];
996}
bellard75012672003-06-21 13:11:07 +0000997
bellardea041c02003-06-25 16:16:50 +0000998static void tb_reset_jump_recursive(TranslationBlock *tb);
999
1000static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1001{
1002 TranslationBlock *tb1, *tb_next, **ptb;
1003 unsigned int n1;
1004
1005 tb1 = tb->jmp_next[n];
1006 if (tb1 != NULL) {
1007 /* find head of list */
1008 for(;;) {
1009 n1 = (long)tb1 & 3;
1010 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1011 if (n1 == 2)
1012 break;
1013 tb1 = tb1->jmp_next[n1];
1014 }
1015 /* we are now sure now that tb jumps to tb1 */
1016 tb_next = tb1;
1017
1018 /* remove tb from the jmp_first list */
1019 ptb = &tb_next->jmp_first;
1020 for(;;) {
1021 tb1 = *ptb;
1022 n1 = (long)tb1 & 3;
1023 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1024 if (n1 == n && tb1 == tb)
1025 break;
1026 ptb = &tb1->jmp_next[n1];
1027 }
1028 *ptb = tb->jmp_next[n];
1029 tb->jmp_next[n] = NULL;
1030
1031 /* suppress the jump to next tb in generated code */
1032 tb_reset_jump(tb, n);
1033
bellard01243112004-01-04 15:48:17 +00001034 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001035 tb_reset_jump_recursive(tb_next);
1036 }
1037}
1038
1039static void tb_reset_jump_recursive(TranslationBlock *tb)
1040{
1041 tb_reset_jump_recursive2(tb, 0);
1042 tb_reset_jump_recursive2(tb, 1);
1043}
1044
bellardd720b932004-04-25 17:57:43 +00001045static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1046{
1047 target_ulong phys_addr;
1048
1049 phys_addr = cpu_get_phys_page_debug(env, pc);
1050 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1051}
1052
bellardc33a3462003-07-29 20:50:33 +00001053/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1054 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001055int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001056{
bellarda541f292004-04-12 20:39:29 +00001057#if defined(TARGET_I386) || defined(TARGET_PPC)
bellard4c3a88a2003-07-26 12:06:08 +00001058 int i;
bellardd720b932004-04-25 17:57:43 +00001059
bellard4c3a88a2003-07-26 12:06:08 +00001060 for(i = 0; i < env->nb_breakpoints; i++) {
1061 if (env->breakpoints[i] == pc)
1062 return 0;
1063 }
1064
1065 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1066 return -1;
1067 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001068
1069 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001070 return 0;
1071#else
1072 return -1;
1073#endif
1074}
1075
1076/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001077int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001078{
bellarda541f292004-04-12 20:39:29 +00001079#if defined(TARGET_I386) || defined(TARGET_PPC)
bellard4c3a88a2003-07-26 12:06:08 +00001080 int i;
1081 for(i = 0; i < env->nb_breakpoints; i++) {
1082 if (env->breakpoints[i] == pc)
1083 goto found;
1084 }
1085 return -1;
1086 found:
1087 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
1088 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
1089 env->nb_breakpoints--;
bellardd720b932004-04-25 17:57:43 +00001090
1091 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001092 return 0;
1093#else
1094 return -1;
1095#endif
1096}
1097
bellardc33a3462003-07-29 20:50:33 +00001098/* enable or disable single step mode. EXCP_DEBUG is returned by the
1099 CPU loop after each instruction */
1100void cpu_single_step(CPUState *env, int enabled)
1101{
bellarda541f292004-04-12 20:39:29 +00001102#if defined(TARGET_I386) || defined(TARGET_PPC)
bellardc33a3462003-07-29 20:50:33 +00001103 if (env->singlestep_enabled != enabled) {
1104 env->singlestep_enabled = enabled;
1105 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001106 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001107 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001108 }
1109#endif
1110}
1111
bellard34865132003-10-05 14:28:56 +00001112/* enable or disable low levels log */
1113void cpu_set_log(int log_flags)
1114{
1115 loglevel = log_flags;
1116 if (loglevel && !logfile) {
1117 logfile = fopen(logfilename, "w");
1118 if (!logfile) {
1119 perror(logfilename);
1120 _exit(1);
1121 }
bellard9fa3e852004-01-04 18:06:42 +00001122#if !defined(CONFIG_SOFTMMU)
1123 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1124 {
1125 static uint8_t logfile_buf[4096];
1126 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1127 }
1128#else
bellard34865132003-10-05 14:28:56 +00001129 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001130#endif
bellard34865132003-10-05 14:28:56 +00001131 }
1132}
1133
1134void cpu_set_log_filename(const char *filename)
1135{
1136 logfilename = strdup(filename);
1137}
bellardc33a3462003-07-29 20:50:33 +00001138
bellard01243112004-01-04 15:48:17 +00001139/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001140void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001141{
1142 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001143 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001144
bellard68a79312003-06-30 13:12:32 +00001145 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001146 /* if the cpu is currently executing code, we must unlink it and
1147 all the potentially executing TB */
1148 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001149 if (tb && !testandset(&interrupt_lock)) {
1150 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001151 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001152 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001153 }
1154}
1155
bellardb54ad042004-05-20 13:42:52 +00001156void cpu_reset_interrupt(CPUState *env, int mask)
1157{
1158 env->interrupt_request &= ~mask;
1159}
1160
bellardf193c792004-03-21 17:06:25 +00001161CPULogItem cpu_log_items[] = {
1162 { CPU_LOG_TB_OUT_ASM, "out_asm",
1163 "show generated host assembly code for each compiled TB" },
1164 { CPU_LOG_TB_IN_ASM, "in_asm",
1165 "show target assembly code for each compiled TB" },
1166 { CPU_LOG_TB_OP, "op",
1167 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1168#ifdef TARGET_I386
1169 { CPU_LOG_TB_OP_OPT, "op_opt",
1170 "show micro ops after optimization for each compiled TB" },
1171#endif
1172 { CPU_LOG_INT, "int",
1173 "show interrupts/exceptions in short format" },
1174 { CPU_LOG_EXEC, "exec",
1175 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001176 { CPU_LOG_TB_CPU, "cpu",
1177 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001178#ifdef TARGET_I386
1179 { CPU_LOG_PCALL, "pcall",
1180 "show protected mode far calls/returns/exceptions" },
1181#endif
bellardfd872592004-05-12 19:11:15 +00001182 { CPU_LOG_IOPORT, "ioport",
1183 "show all i/o ports accesses" },
bellardf193c792004-03-21 17:06:25 +00001184 { 0, NULL, NULL },
1185};
1186
1187static int cmp1(const char *s1, int n, const char *s2)
1188{
1189 if (strlen(s2) != n)
1190 return 0;
1191 return memcmp(s1, s2, n) == 0;
1192}
1193
1194/* takes a comma separated list of log masks. Return 0 if error. */
1195int cpu_str_to_log_mask(const char *str)
1196{
1197 CPULogItem *item;
1198 int mask;
1199 const char *p, *p1;
1200
1201 p = str;
1202 mask = 0;
1203 for(;;) {
1204 p1 = strchr(p, ',');
1205 if (!p1)
1206 p1 = p + strlen(p);
1207 for(item = cpu_log_items; item->mask != 0; item++) {
1208 if (cmp1(p, p1 - p, item->name))
1209 goto found;
1210 }
1211 return 0;
1212 found:
1213 mask |= item->mask;
1214 if (*p1 != ',')
1215 break;
1216 p = p1 + 1;
1217 }
1218 return mask;
1219}
bellardea041c02003-06-25 16:16:50 +00001220
bellard75012672003-06-21 13:11:07 +00001221void cpu_abort(CPUState *env, const char *fmt, ...)
1222{
1223 va_list ap;
1224
1225 va_start(ap, fmt);
1226 fprintf(stderr, "qemu: fatal: ");
1227 vfprintf(stderr, fmt, ap);
1228 fprintf(stderr, "\n");
1229#ifdef TARGET_I386
1230 cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
1231#endif
1232 va_end(ap);
1233 abort();
1234}
1235
bellard01243112004-01-04 15:48:17 +00001236#if !defined(CONFIG_USER_ONLY)
1237
bellardee8b7022004-02-03 23:35:10 +00001238/* NOTE: if flush_global is true, also flush global entries (not
1239 implemented yet) */
1240void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001241{
bellard33417e72003-08-10 21:47:01 +00001242 int i;
bellard01243112004-01-04 15:48:17 +00001243
bellard9fa3e852004-01-04 18:06:42 +00001244#if defined(DEBUG_TLB)
1245 printf("tlb_flush:\n");
1246#endif
bellard01243112004-01-04 15:48:17 +00001247 /* must reset current TB so that interrupts cannot modify the
1248 links while we are modifying them */
1249 env->current_tb = NULL;
1250
bellard33417e72003-08-10 21:47:01 +00001251 for(i = 0; i < CPU_TLB_SIZE; i++) {
1252 env->tlb_read[0][i].address = -1;
1253 env->tlb_write[0][i].address = -1;
1254 env->tlb_read[1][i].address = -1;
1255 env->tlb_write[1][i].address = -1;
1256 }
bellard9fa3e852004-01-04 18:06:42 +00001257
1258 virt_page_flush();
1259 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
1260 tb_hash[i] = NULL;
1261
1262#if !defined(CONFIG_SOFTMMU)
1263 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1264#endif
bellard33417e72003-08-10 21:47:01 +00001265}
1266
bellard274da6b2004-05-20 21:56:27 +00001267static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001268{
1269 if (addr == (tlb_entry->address &
1270 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1271 tlb_entry->address = -1;
1272}
1273
bellard2e126692004-04-25 21:28:44 +00001274void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001275{
bellard9fa3e852004-01-04 18:06:42 +00001276 int i, n;
1277 VirtPageDesc *vp;
1278 PageDesc *p;
1279 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001280
bellard9fa3e852004-01-04 18:06:42 +00001281#if defined(DEBUG_TLB)
1282 printf("tlb_flush_page: 0x%08x\n", addr);
1283#endif
bellard01243112004-01-04 15:48:17 +00001284 /* must reset current TB so that interrupts cannot modify the
1285 links while we are modifying them */
1286 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001287
bellard61382a52003-10-27 21:22:23 +00001288 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001289 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001290 tlb_flush_entry(&env->tlb_read[0][i], addr);
1291 tlb_flush_entry(&env->tlb_write[0][i], addr);
1292 tlb_flush_entry(&env->tlb_read[1][i], addr);
1293 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001294
bellard9fa3e852004-01-04 18:06:42 +00001295 /* remove from the virtual pc hash table all the TB at this
1296 virtual address */
1297
1298 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1299 if (vp && vp->valid_tag == virt_valid_tag) {
1300 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1301 if (p) {
1302 /* we remove all the links to the TBs in this virtual page */
1303 tb = p->first_tb;
1304 while (tb != NULL) {
1305 n = (long)tb & 3;
1306 tb = (TranslationBlock *)((long)tb & ~3);
1307 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1308 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1309 tb_invalidate(tb);
1310 }
1311 tb = tb->page_next[n];
1312 }
1313 }
bellard98857882004-01-18 21:52:14 +00001314 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001315 }
1316
bellard01243112004-01-04 15:48:17 +00001317#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001318 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001319 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001320#endif
bellard9fa3e852004-01-04 18:06:42 +00001321}
1322
bellard4f2ac232004-04-26 19:44:02 +00001323static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001324{
1325 if (addr == (tlb_entry->address &
1326 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001327 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1328 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001329 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001330 }
bellard61382a52003-10-27 21:22:23 +00001331}
1332
bellard9fa3e852004-01-04 18:06:42 +00001333/* update the TLBs so that writes to code in the virtual page 'addr'
1334 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001335static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001336{
bellard61382a52003-10-27 21:22:23 +00001337 int i;
1338
1339 addr &= TARGET_PAGE_MASK;
1340 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001341 tlb_protect_code1(&env->tlb_write[0][i], addr);
1342 tlb_protect_code1(&env->tlb_write[1][i], addr);
1343#if !defined(CONFIG_SOFTMMU)
1344 /* NOTE: as we generated the code for this page, it is already at
1345 least readable */
1346 if (addr < MMAP_AREA_END)
1347 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1348#endif
1349}
1350
bellard9fa3e852004-01-04 18:06:42 +00001351static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001352 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001353{
1354 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1355 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001356 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001357 }
1358}
1359
1360/* update the TLB so that writes in physical page 'phys_addr' are no longer
1361 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001362static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001363{
1364 int i;
1365
1366 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001367 phys_addr += (long)phys_ram_base;
1368 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1369 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1370 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1371}
1372
1373static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1374 unsigned long start, unsigned long length)
1375{
1376 unsigned long addr;
1377 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1378 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1379 if ((addr - start) < length) {
1380 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1381 }
1382 }
1383}
1384
1385void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
1386{
1387 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001388 unsigned long length, start1;
bellard1ccde1c2004-02-06 19:46:14 +00001389 int i;
1390
1391 start &= TARGET_PAGE_MASK;
1392 end = TARGET_PAGE_ALIGN(end);
1393
1394 length = end - start;
1395 if (length == 0)
1396 return;
1397 memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
1398
1399 env = cpu_single_env;
1400 /* we modify the TLB cache so that the dirty bit will be set again
1401 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001402 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001403 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001404 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001405 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001406 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1407
1408#if !defined(CONFIG_SOFTMMU)
1409 /* XXX: this is expensive */
1410 {
1411 VirtPageDesc *p;
1412 int j;
1413 target_ulong addr;
1414
1415 for(i = 0; i < L1_SIZE; i++) {
1416 p = l1_virt_map[i];
1417 if (p) {
1418 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1419 for(j = 0; j < L2_SIZE; j++) {
1420 if (p->valid_tag == virt_valid_tag &&
1421 p->phys_addr >= start && p->phys_addr < end &&
1422 (p->prot & PROT_WRITE)) {
1423 if (addr < MMAP_AREA_END) {
1424 mprotect((void *)addr, TARGET_PAGE_SIZE,
1425 p->prot & ~PROT_WRITE);
1426 }
1427 }
1428 addr += TARGET_PAGE_SIZE;
1429 p++;
1430 }
1431 }
1432 }
1433 }
1434#endif
bellard1ccde1c2004-02-06 19:46:14 +00001435}
1436
1437static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1438 unsigned long start)
1439{
1440 unsigned long addr;
1441 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1442 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1443 if (addr == start) {
1444 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1445 }
1446 }
1447}
1448
1449/* update the TLB corresponding to virtual page vaddr and phys addr
1450 addr so that it is no longer dirty */
1451static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1452{
1453 CPUState *env = cpu_single_env;
1454 int i;
1455
1456 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
1457
1458 addr &= TARGET_PAGE_MASK;
1459 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1460 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1461 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001462}
1463
bellard59817cc2004-02-16 22:01:13 +00001464/* add a new TLB entry. At most one entry for a given virtual address
1465 is permitted. Return 0 if OK or 2 if the page could not be mapped
1466 (can only happen in non SOFTMMU mode for I/O pages or pages
1467 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001468int tlb_set_page(CPUState *env, target_ulong vaddr,
1469 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001470 int is_user, int is_softmmu)
1471{
bellard92e873b2004-05-21 14:52:29 +00001472 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001473 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001474 TranslationBlock *first_tb;
1475 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001476 target_ulong address;
1477 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001478 int ret;
1479
bellard92e873b2004-05-21 14:52:29 +00001480 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1481 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001482 if (!p) {
1483 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001484 } else {
bellard92e873b2004-05-21 14:52:29 +00001485 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001486 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001487 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1488 /* NOTE: we also allocate the page at this stage */
1489 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1490 first_tb = p1->first_tb;
1491 }
bellard9fa3e852004-01-04 18:06:42 +00001492 }
1493#if defined(DEBUG_TLB)
1494 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1495 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1496#endif
1497
1498 ret = 0;
1499#if !defined(CONFIG_SOFTMMU)
1500 if (is_softmmu)
1501#endif
1502 {
1503 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1504 /* IO memory case */
1505 address = vaddr | pd;
1506 addend = paddr;
1507 } else {
1508 /* standard memory */
1509 address = vaddr;
1510 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1511 }
1512
1513 index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1514 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001515 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001516 env->tlb_read[is_user][index].address = address;
1517 env->tlb_read[is_user][index].addend = addend;
1518 } else {
1519 env->tlb_read[is_user][index].address = -1;
1520 env->tlb_read[is_user][index].addend = -1;
1521 }
bellard67b915a2004-03-31 23:37:16 +00001522 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001523 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1524 /* ROM: access is ignored (same as unassigned) */
1525 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001526 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001527 } else
1528 /* XXX: the PowerPC code seems not ready to handle
1529 self modifying code with DCBI */
1530#if defined(TARGET_HAS_SMC) || 1
1531 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001532 /* if code is present, we use a specific memory
1533 handler. It works only for physical memory access */
1534 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001535 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001536 } else
1537#endif
1538 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001539 !cpu_physical_memory_is_dirty(pd)) {
1540 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1541 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001542 } else {
1543 env->tlb_write[is_user][index].address = address;
1544 env->tlb_write[is_user][index].addend = addend;
1545 }
1546 } else {
1547 env->tlb_write[is_user][index].address = -1;
1548 env->tlb_write[is_user][index].addend = -1;
1549 }
1550 }
1551#if !defined(CONFIG_SOFTMMU)
1552 else {
1553 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1554 /* IO access: no mapping is done as it will be handled by the
1555 soft MMU */
1556 if (!(env->hflags & HF_SOFTMMU_MASK))
1557 ret = 2;
1558 } else {
1559 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001560
bellard59817cc2004-02-16 22:01:13 +00001561 if (vaddr >= MMAP_AREA_END) {
1562 ret = 2;
1563 } else {
1564 if (prot & PROT_WRITE) {
1565 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001566#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001567 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001568#endif
bellard59817cc2004-02-16 22:01:13 +00001569 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1570 !cpu_physical_memory_is_dirty(pd))) {
1571 /* ROM: we do as if code was inside */
1572 /* if code is present, we only map as read only and save the
1573 original mapping */
1574 VirtPageDesc *vp;
1575
1576 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1577 vp->phys_addr = pd;
1578 vp->prot = prot;
1579 vp->valid_tag = virt_valid_tag;
1580 prot &= ~PAGE_WRITE;
1581 }
bellard9fa3e852004-01-04 18:06:42 +00001582 }
bellard59817cc2004-02-16 22:01:13 +00001583 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1584 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1585 if (map_addr == MAP_FAILED) {
1586 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1587 paddr, vaddr);
1588 }
bellard9fa3e852004-01-04 18:06:42 +00001589 }
1590 }
1591 }
1592#endif
1593 return ret;
1594}
1595
1596/* called from signal handler: invalidate the code and unprotect the
1597 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001598int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001599{
1600#if !defined(CONFIG_SOFTMMU)
1601 VirtPageDesc *vp;
1602
1603#if defined(DEBUG_TLB)
1604 printf("page_unprotect: addr=0x%08x\n", addr);
1605#endif
1606 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001607
1608 /* if it is not mapped, no need to worry here */
1609 if (addr >= MMAP_AREA_END)
1610 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001611 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1612 if (!vp)
1613 return 0;
1614 /* NOTE: in this case, validate_tag is _not_ tested as it
1615 validates only the code TLB */
1616 if (vp->valid_tag != virt_valid_tag)
1617 return 0;
1618 if (!(vp->prot & PAGE_WRITE))
1619 return 0;
1620#if defined(DEBUG_TLB)
1621 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1622 addr, vp->phys_addr, vp->prot);
1623#endif
bellard59817cc2004-02-16 22:01:13 +00001624 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1625 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1626 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001627 /* set the dirty bit */
1628 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1629 /* flush the code inside */
1630 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001631 return 1;
1632#else
1633 return 0;
1634#endif
bellard33417e72003-08-10 21:47:01 +00001635}
1636
bellard01243112004-01-04 15:48:17 +00001637#else
1638
bellardee8b7022004-02-03 23:35:10 +00001639void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001640{
1641}
1642
bellard2e126692004-04-25 21:28:44 +00001643void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001644{
1645}
1646
bellard2e126692004-04-25 21:28:44 +00001647int tlb_set_page(CPUState *env, target_ulong vaddr,
1648 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001649 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001650{
bellard9fa3e852004-01-04 18:06:42 +00001651 return 0;
1652}
bellard33417e72003-08-10 21:47:01 +00001653
bellard9fa3e852004-01-04 18:06:42 +00001654/* dump memory mappings */
1655void page_dump(FILE *f)
1656{
1657 unsigned long start, end;
1658 int i, j, prot, prot1;
1659 PageDesc *p;
1660
1661 fprintf(f, "%-8s %-8s %-8s %s\n",
1662 "start", "end", "size", "prot");
1663 start = -1;
1664 end = -1;
1665 prot = 0;
1666 for(i = 0; i <= L1_SIZE; i++) {
1667 if (i < L1_SIZE)
1668 p = l1_map[i];
1669 else
1670 p = NULL;
1671 for(j = 0;j < L2_SIZE; j++) {
1672 if (!p)
1673 prot1 = 0;
1674 else
1675 prot1 = p[j].flags;
1676 if (prot1 != prot) {
1677 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1678 if (start != -1) {
1679 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1680 start, end, end - start,
1681 prot & PAGE_READ ? 'r' : '-',
1682 prot & PAGE_WRITE ? 'w' : '-',
1683 prot & PAGE_EXEC ? 'x' : '-');
1684 }
1685 if (prot1 != 0)
1686 start = end;
1687 else
1688 start = -1;
1689 prot = prot1;
1690 }
1691 if (!p)
1692 break;
1693 }
bellard33417e72003-08-10 21:47:01 +00001694 }
bellard33417e72003-08-10 21:47:01 +00001695}
1696
bellard9fa3e852004-01-04 18:06:42 +00001697int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001698{
bellard9fa3e852004-01-04 18:06:42 +00001699 PageDesc *p;
1700
1701 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001702 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001703 return 0;
1704 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001705}
1706
bellard9fa3e852004-01-04 18:06:42 +00001707/* modify the flags of a page and invalidate the code if
1708 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1709 depending on PAGE_WRITE */
1710void page_set_flags(unsigned long start, unsigned long end, int flags)
1711{
1712 PageDesc *p;
1713 unsigned long addr;
1714
1715 start = start & TARGET_PAGE_MASK;
1716 end = TARGET_PAGE_ALIGN(end);
1717 if (flags & PAGE_WRITE)
1718 flags |= PAGE_WRITE_ORG;
1719 spin_lock(&tb_lock);
1720 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1721 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1722 /* if the write protection is set, then we invalidate the code
1723 inside */
1724 if (!(p->flags & PAGE_WRITE) &&
1725 (flags & PAGE_WRITE) &&
1726 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001727 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001728 }
1729 p->flags = flags;
1730 }
1731 spin_unlock(&tb_lock);
1732}
1733
1734/* called from signal handler: invalidate the code and unprotect the
1735 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001736int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001737{
1738 unsigned int page_index, prot, pindex;
1739 PageDesc *p, *p1;
1740 unsigned long host_start, host_end, addr;
1741
1742 host_start = address & host_page_mask;
1743 page_index = host_start >> TARGET_PAGE_BITS;
1744 p1 = page_find(page_index);
1745 if (!p1)
1746 return 0;
1747 host_end = host_start + host_page_size;
1748 p = p1;
1749 prot = 0;
1750 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1751 prot |= p->flags;
1752 p++;
1753 }
1754 /* if the page was really writable, then we change its
1755 protection back to writable */
1756 if (prot & PAGE_WRITE_ORG) {
1757 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1758 if (!(p1[pindex].flags & PAGE_WRITE)) {
1759 mprotect((void *)host_start, host_page_size,
1760 (prot & PAGE_BITS) | PAGE_WRITE);
1761 p1[pindex].flags |= PAGE_WRITE;
1762 /* and since the content will be modified, we must invalidate
1763 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001764 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001765#ifdef DEBUG_TB_CHECK
1766 tb_invalidate_check(address);
1767#endif
1768 return 1;
1769 }
1770 }
1771 return 0;
1772}
1773
1774/* call this function when system calls directly modify a memory area */
1775void page_unprotect_range(uint8_t *data, unsigned long data_size)
1776{
1777 unsigned long start, end, addr;
1778
1779 start = (unsigned long)data;
1780 end = start + data_size;
1781 start &= TARGET_PAGE_MASK;
1782 end = TARGET_PAGE_ALIGN(end);
1783 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001784 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001785 }
1786}
1787
bellard1ccde1c2004-02-06 19:46:14 +00001788static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1789{
1790}
bellard9fa3e852004-01-04 18:06:42 +00001791#endif /* defined(CONFIG_USER_ONLY) */
1792
bellard33417e72003-08-10 21:47:01 +00001793/* register physical memory. 'size' must be a multiple of the target
1794 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1795 io memory page */
bellard2e126692004-04-25 21:28:44 +00001796void cpu_register_physical_memory(target_phys_addr_t start_addr,
1797 unsigned long size,
1798 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001799{
1800 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001801 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001802
bellard5fd386f2004-05-23 21:11:22 +00001803 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001804 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001805 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001806 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001807 p->phys_offset = phys_offset;
1808 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001809 phys_offset += TARGET_PAGE_SIZE;
1810 }
1811}
1812
bellarda4193c82004-06-03 14:01:43 +00001813static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001814{
1815 return 0;
1816}
1817
bellarda4193c82004-06-03 14:01:43 +00001818static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001819{
1820}
1821
1822static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1823 unassigned_mem_readb,
1824 unassigned_mem_readb,
1825 unassigned_mem_readb,
1826};
1827
1828static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1829 unassigned_mem_writeb,
1830 unassigned_mem_writeb,
1831 unassigned_mem_writeb,
1832};
1833
bellard9fa3e852004-01-04 18:06:42 +00001834/* self modifying code support in soft mmu mode : writing to a page
1835 containing code comes to these functions */
1836
bellarda4193c82004-06-03 14:01:43 +00001837static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001838{
bellard1ccde1c2004-02-06 19:46:14 +00001839 unsigned long phys_addr;
1840
bellard274da6b2004-05-20 21:56:27 +00001841 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001842#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001843 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001844#endif
bellard1ccde1c2004-02-06 19:46:14 +00001845 stb_raw((uint8_t *)addr, val);
1846 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001847}
1848
bellarda4193c82004-06-03 14:01:43 +00001849static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001850{
bellard1ccde1c2004-02-06 19:46:14 +00001851 unsigned long phys_addr;
1852
bellard274da6b2004-05-20 21:56:27 +00001853 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001854#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001855 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001856#endif
bellard1ccde1c2004-02-06 19:46:14 +00001857 stw_raw((uint8_t *)addr, val);
1858 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001859}
1860
bellarda4193c82004-06-03 14:01:43 +00001861static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001862{
bellard1ccde1c2004-02-06 19:46:14 +00001863 unsigned long phys_addr;
1864
bellard274da6b2004-05-20 21:56:27 +00001865 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001866#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001867 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00001868#endif
bellard1ccde1c2004-02-06 19:46:14 +00001869 stl_raw((uint8_t *)addr, val);
1870 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001871}
1872
1873static CPUReadMemoryFunc *code_mem_read[3] = {
1874 NULL, /* never used */
1875 NULL, /* never used */
1876 NULL, /* never used */
1877};
1878
1879static CPUWriteMemoryFunc *code_mem_write[3] = {
1880 code_mem_writeb,
1881 code_mem_writew,
1882 code_mem_writel,
1883};
bellard33417e72003-08-10 21:47:01 +00001884
bellarda4193c82004-06-03 14:01:43 +00001885static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001886{
1887 stb_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001888 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001889}
1890
bellarda4193c82004-06-03 14:01:43 +00001891static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001892{
1893 stw_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001894 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001895}
1896
bellarda4193c82004-06-03 14:01:43 +00001897static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001898{
1899 stl_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001900 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001901}
1902
1903static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1904 notdirty_mem_writeb,
1905 notdirty_mem_writew,
1906 notdirty_mem_writel,
1907};
1908
bellard33417e72003-08-10 21:47:01 +00001909static void io_mem_init(void)
1910{
bellarda4193c82004-06-03 14:01:43 +00001911 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1912 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1913 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1914 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001915 io_mem_nb = 5;
1916
1917 /* alloc dirty bits array */
bellard59817cc2004-02-16 22:01:13 +00001918 phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001919}
1920
1921/* mem_read and mem_write are arrays of functions containing the
1922 function to access byte (index 0), word (index 1) and dword (index
1923 2). All functions must be supplied. If io_index is non zero, the
1924 corresponding io zone is modified. If it is zero, a new io zone is
1925 allocated. The return value can be used with
1926 cpu_register_physical_memory(). (-1) is returned if error. */
1927int cpu_register_io_memory(int io_index,
1928 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001929 CPUWriteMemoryFunc **mem_write,
1930 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001931{
1932 int i;
1933
1934 if (io_index <= 0) {
1935 if (io_index >= IO_MEM_NB_ENTRIES)
1936 return -1;
1937 io_index = io_mem_nb++;
1938 } else {
1939 if (io_index >= IO_MEM_NB_ENTRIES)
1940 return -1;
1941 }
1942
1943 for(i = 0;i < 3; i++) {
1944 io_mem_read[io_index][i] = mem_read[i];
1945 io_mem_write[io_index][i] = mem_write[i];
1946 }
bellarda4193c82004-06-03 14:01:43 +00001947 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001948 return io_index << IO_MEM_SHIFT;
1949}
bellard61382a52003-10-27 21:22:23 +00001950
bellard13eb76e2004-01-24 15:23:36 +00001951/* physical memory access (slow version, mainly for debug) */
1952#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001953void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001954 int len, int is_write)
1955{
1956 int l, flags;
1957 target_ulong page;
1958
1959 while (len > 0) {
1960 page = addr & TARGET_PAGE_MASK;
1961 l = (page + TARGET_PAGE_SIZE) - addr;
1962 if (l > len)
1963 l = len;
1964 flags = page_get_flags(page);
1965 if (!(flags & PAGE_VALID))
1966 return;
1967 if (is_write) {
1968 if (!(flags & PAGE_WRITE))
1969 return;
1970 memcpy((uint8_t *)addr, buf, len);
1971 } else {
1972 if (!(flags & PAGE_READ))
1973 return;
1974 memcpy(buf, (uint8_t *)addr, len);
1975 }
1976 len -= l;
1977 buf += l;
1978 addr += l;
1979 }
1980}
1981#else
bellard2e126692004-04-25 21:28:44 +00001982void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001983 int len, int is_write)
1984{
1985 int l, io_index;
1986 uint8_t *ptr;
1987 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00001988 target_phys_addr_t page;
1989 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00001990 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00001991
1992 while (len > 0) {
1993 page = addr & TARGET_PAGE_MASK;
1994 l = (page + TARGET_PAGE_SIZE) - addr;
1995 if (l > len)
1996 l = len;
bellard92e873b2004-05-21 14:52:29 +00001997 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00001998 if (!p) {
1999 pd = IO_MEM_UNASSIGNED;
2000 } else {
2001 pd = p->phys_offset;
2002 }
2003
2004 if (is_write) {
2005 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2006 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2007 if (l >= 4 && ((addr & 3) == 0)) {
2008 /* 32 bit read access */
2009 val = ldl_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002010 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002011 l = 4;
2012 } else if (l >= 2 && ((addr & 1) == 0)) {
2013 /* 16 bit read access */
2014 val = lduw_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002015 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002016 l = 2;
2017 } else {
2018 /* 8 bit access */
2019 val = ldub_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002020 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002021 l = 1;
2022 }
2023 } else {
bellardb448f2f2004-02-25 23:24:04 +00002024 unsigned long addr1;
2025 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002026 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002027 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002028 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002029 /* invalidate code */
2030 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2031 /* set dirty bit */
2032 phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1;
bellard13eb76e2004-01-24 15:23:36 +00002033 }
2034 } else {
2035 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2036 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2037 /* I/O case */
2038 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2039 if (l >= 4 && ((addr & 3) == 0)) {
2040 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002041 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002042 stl_raw(buf, val);
2043 l = 4;
2044 } else if (l >= 2 && ((addr & 1) == 0)) {
2045 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002046 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002047 stw_raw(buf, val);
2048 l = 2;
2049 } else {
2050 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002051 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002052 stb_raw(buf, val);
2053 l = 1;
2054 }
2055 } else {
2056 /* RAM case */
2057 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2058 (addr & ~TARGET_PAGE_MASK);
2059 memcpy(buf, ptr, l);
2060 }
2061 }
2062 len -= l;
2063 buf += l;
2064 addr += l;
2065 }
2066}
2067#endif
2068
2069/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002070int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2071 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002072{
2073 int l;
2074 target_ulong page, phys_addr;
2075
2076 while (len > 0) {
2077 page = addr & TARGET_PAGE_MASK;
2078 phys_addr = cpu_get_phys_page_debug(env, page);
2079 /* if no physical page mapped, return an error */
2080 if (phys_addr == -1)
2081 return -1;
2082 l = (page + TARGET_PAGE_SIZE) - addr;
2083 if (l > len)
2084 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002085 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2086 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002087 len -= l;
2088 buf += l;
2089 addr += l;
2090 }
2091 return 0;
2092}
2093
bellard61382a52003-10-27 21:22:23 +00002094#if !defined(CONFIG_USER_ONLY)
2095
2096#define MMUSUFFIX _cmmu
2097#define GETPC() NULL
2098#define env cpu_single_env
2099
2100#define SHIFT 0
2101#include "softmmu_template.h"
2102
2103#define SHIFT 1
2104#include "softmmu_template.h"
2105
2106#define SHIFT 2
2107#include "softmmu_template.h"
2108
2109#define SHIFT 3
2110#include "softmmu_template.h"
2111
2112#undef env
2113
2114#endif