blob: 8fe166bb0b6b78eff05cca83392a97ac5396192a [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
bellard54936002003-05-13 00:25:15 +00003 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
bellard67b915a2004-03-31 23:37:16 +000020#include "config.h"
bellardd5a8f072004-09-29 21:15:28 +000021#ifdef _WIN32
22#include <windows.h>
23#else
bellarda98d49b2004-11-14 16:22:05 +000024#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000025#include <sys/mman.h>
26#endif
bellard54936002003-05-13 00:25:15 +000027#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
bellard6180a182003-09-30 21:04:53 +000035#include "cpu.h"
36#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000037
bellardfd6ce8f2003-05-14 19:00:11 +000038//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000039//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000040//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000041
42/* make various TB consistency checks */
43//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000044//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000045
46/* threshold to flush the translated code buffer */
47#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
48
bellard9fa3e852004-01-04 18:06:42 +000049#define SMC_BITMAP_USE_THRESHOLD 10
50
51#define MMAP_AREA_START 0x00000000
52#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000053
54TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
55TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
bellard9fa3e852004-01-04 18:06:42 +000056TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000057int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000058/* any access to the tbs or the page table must use this lock */
59spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000060
61uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
62uint8_t *code_gen_ptr;
63
bellard9fa3e852004-01-04 18:06:42 +000064int phys_ram_size;
65int phys_ram_fd;
66uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000067uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000068
bellard54936002003-05-13 00:25:15 +000069typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000070 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000071 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000072 /* in order to optimize self modifying code, we count the number
73 of lookups we do to a given page to use a bitmap */
74 unsigned int code_write_count;
75 uint8_t *code_bitmap;
76#if defined(CONFIG_USER_ONLY)
77 unsigned long flags;
78#endif
bellard54936002003-05-13 00:25:15 +000079} PageDesc;
80
bellard92e873b2004-05-21 14:52:29 +000081typedef struct PhysPageDesc {
82 /* offset in host memory of the page + io_index in the low 12 bits */
83 unsigned long phys_offset;
84} PhysPageDesc;
85
bellard9fa3e852004-01-04 18:06:42 +000086typedef struct VirtPageDesc {
87 /* physical address of code page. It is valid only if 'valid_tag'
88 matches 'virt_valid_tag' */
89 target_ulong phys_addr;
90 unsigned int valid_tag;
91#if !defined(CONFIG_SOFTMMU)
92 /* original page access rights. It is valid only if 'valid_tag'
93 matches 'virt_valid_tag' */
94 unsigned int prot;
95#endif
96} VirtPageDesc;
97
bellard54936002003-05-13 00:25:15 +000098#define L2_BITS 10
99#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
100
101#define L1_SIZE (1 << L1_BITS)
102#define L2_SIZE (1 << L2_BITS)
103
bellard33417e72003-08-10 21:47:01 +0000104static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000105
bellard83fb7ad2004-07-05 21:25:26 +0000106unsigned long qemu_real_host_page_size;
107unsigned long qemu_host_page_bits;
108unsigned long qemu_host_page_size;
109unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000110
bellard92e873b2004-05-21 14:52:29 +0000111/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000112static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000113PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000114
bellard9fa3e852004-01-04 18:06:42 +0000115#if !defined(CONFIG_USER_ONLY)
116static VirtPageDesc *l1_virt_map[L1_SIZE];
117static unsigned int virt_valid_tag;
118#endif
119
bellard33417e72003-08-10 21:47:01 +0000120/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000121CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
122CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000123void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000124static int io_mem_nb;
125
bellard34865132003-10-05 14:28:56 +0000126/* log support */
127char *logfilename = "/tmp/qemu.log";
128FILE *logfile;
129int loglevel;
130
bellarde3db7222005-01-26 22:00:47 +0000131/* statistics */
132static int tlb_flush_count;
133static int tb_flush_count;
134static int tb_phys_invalidate_count;
135
bellardb346ff42003-06-15 20:05:50 +0000136static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000137{
bellard83fb7ad2004-07-05 21:25:26 +0000138 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000139 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000140#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000141 {
142 SYSTEM_INFO system_info;
143 DWORD old_protect;
144
145 GetSystemInfo(&system_info);
146 qemu_real_host_page_size = system_info.dwPageSize;
147
148 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
149 PAGE_EXECUTE_READWRITE, &old_protect);
150 }
bellard67b915a2004-03-31 23:37:16 +0000151#else
bellard83fb7ad2004-07-05 21:25:26 +0000152 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000153 {
154 unsigned long start, end;
155
156 start = (unsigned long)code_gen_buffer;
157 start &= ~(qemu_real_host_page_size - 1);
158
159 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
160 end += qemu_real_host_page_size - 1;
161 end &= ~(qemu_real_host_page_size - 1);
162
163 mprotect((void *)start, end - start,
164 PROT_READ | PROT_WRITE | PROT_EXEC);
165 }
bellard67b915a2004-03-31 23:37:16 +0000166#endif
bellardd5a8f072004-09-29 21:15:28 +0000167
bellard83fb7ad2004-07-05 21:25:26 +0000168 if (qemu_host_page_size == 0)
169 qemu_host_page_size = qemu_real_host_page_size;
170 if (qemu_host_page_size < TARGET_PAGE_SIZE)
171 qemu_host_page_size = TARGET_PAGE_SIZE;
172 qemu_host_page_bits = 0;
173 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
174 qemu_host_page_bits++;
175 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard9fa3e852004-01-04 18:06:42 +0000176#if !defined(CONFIG_USER_ONLY)
177 virt_valid_tag = 1;
178#endif
bellard0a962c02005-02-10 22:00:27 +0000179 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
180 memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
bellard54936002003-05-13 00:25:15 +0000181}
182
bellardfd6ce8f2003-05-14 19:00:11 +0000183static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000184{
bellard54936002003-05-13 00:25:15 +0000185 PageDesc **lp, *p;
186
bellard54936002003-05-13 00:25:15 +0000187 lp = &l1_map[index >> L2_BITS];
188 p = *lp;
189 if (!p) {
190 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000191 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000192 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000193 *lp = p;
194 }
195 return p + (index & (L2_SIZE - 1));
196}
197
bellardfd6ce8f2003-05-14 19:00:11 +0000198static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000199{
bellard54936002003-05-13 00:25:15 +0000200 PageDesc *p;
201
bellard54936002003-05-13 00:25:15 +0000202 p = l1_map[index >> L2_BITS];
203 if (!p)
204 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000205 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000206}
207
bellard92e873b2004-05-21 14:52:29 +0000208static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
209{
210 PhysPageDesc **lp, *p;
211
212 lp = &l1_phys_map[index >> L2_BITS];
213 p = *lp;
214 if (!p) {
215 /* allocate if not found */
bellard0a962c02005-02-10 22:00:27 +0000216 p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
bellard92e873b2004-05-21 14:52:29 +0000217 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
218 *lp = p;
219 }
220 return p + (index & (L2_SIZE - 1));
221}
222
223static inline PhysPageDesc *phys_page_find(unsigned int index)
224{
225 PhysPageDesc *p;
226
227 p = l1_phys_map[index >> L2_BITS];
228 if (!p)
229 return 0;
230 return p + (index & (L2_SIZE - 1));
231}
232
bellard9fa3e852004-01-04 18:06:42 +0000233#if !defined(CONFIG_USER_ONLY)
bellard4f2ac232004-04-26 19:44:02 +0000234static void tlb_protect_code(CPUState *env, target_ulong addr);
235static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000236
bellard9fa3e852004-01-04 18:06:42 +0000237static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
238{
239 VirtPageDesc **lp, *p;
240
bellardc27004e2005-01-03 23:35:10 +0000241 /* XXX: should not truncate for 64 bit addresses */
242#if TARGET_LONG_BITS > 32
243 index &= (L1_SIZE - 1);
244#endif
bellard9fa3e852004-01-04 18:06:42 +0000245 lp = &l1_virt_map[index >> L2_BITS];
246 p = *lp;
247 if (!p) {
248 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000249 p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000250 memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
251 *lp = p;
252 }
253 return p + (index & (L2_SIZE - 1));
254}
255
256static inline VirtPageDesc *virt_page_find(unsigned int index)
257{
258 VirtPageDesc *p;
259
260 p = l1_virt_map[index >> L2_BITS];
bellardfd6ce8f2003-05-14 19:00:11 +0000261 if (!p)
262 return 0;
bellard9fa3e852004-01-04 18:06:42 +0000263 return p + (index & (L2_SIZE - 1));
bellardfd6ce8f2003-05-14 19:00:11 +0000264}
265
bellard9fa3e852004-01-04 18:06:42 +0000266static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000267{
bellard9fa3e852004-01-04 18:06:42 +0000268 int i, j;
269 VirtPageDesc *p;
270
271 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000272
bellard9fa3e852004-01-04 18:06:42 +0000273 if (virt_valid_tag == 0) {
274 virt_valid_tag = 1;
275 for(i = 0; i < L1_SIZE; i++) {
276 p = l1_virt_map[i];
277 if (p) {
278 for(j = 0; j < L2_SIZE; j++)
279 p[j].valid_tag = 0;
280 }
bellardfd6ce8f2003-05-14 19:00:11 +0000281 }
bellard54936002003-05-13 00:25:15 +0000282 }
283}
bellard9fa3e852004-01-04 18:06:42 +0000284#else
285static void virt_page_flush(void)
286{
287}
288#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000289
bellardb346ff42003-06-15 20:05:50 +0000290void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000291{
292 if (!code_gen_ptr) {
293 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000294 page_init();
bellard33417e72003-08-10 21:47:01 +0000295 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000296 }
297}
298
bellard9fa3e852004-01-04 18:06:42 +0000299static inline void invalidate_page_bitmap(PageDesc *p)
300{
301 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000302 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000303 p->code_bitmap = NULL;
304 }
305 p->code_write_count = 0;
306}
307
bellardfd6ce8f2003-05-14 19:00:11 +0000308/* set to NULL all the 'first_tb' fields in all PageDescs */
309static void page_flush_tb(void)
310{
311 int i, j;
312 PageDesc *p;
313
314 for(i = 0; i < L1_SIZE; i++) {
315 p = l1_map[i];
316 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000317 for(j = 0; j < L2_SIZE; j++) {
318 p->first_tb = NULL;
319 invalidate_page_bitmap(p);
320 p++;
321 }
bellardfd6ce8f2003-05-14 19:00:11 +0000322 }
323 }
324}
325
326/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000327/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000328void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000329{
bellard01243112004-01-04 15:48:17 +0000330#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000331 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
332 code_gen_ptr - code_gen_buffer,
333 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000334 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000335#endif
336 nb_tbs = 0;
bellard8a8a6082004-10-03 13:36:49 +0000337 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000338 virt_page_flush();
339
bellard8a8a6082004-10-03 13:36:49 +0000340 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000341 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000342
bellardfd6ce8f2003-05-14 19:00:11 +0000343 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000344 /* XXX: flush processor icache at this point if cache flush is
345 expensive */
bellarde3db7222005-01-26 22:00:47 +0000346 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000347}
348
349#ifdef DEBUG_TB_CHECK
350
351static void tb_invalidate_check(unsigned long address)
352{
353 TranslationBlock *tb;
354 int i;
355 address &= TARGET_PAGE_MASK;
356 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
357 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
358 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
359 address >= tb->pc + tb->size)) {
360 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
361 address, tb->pc, tb->size);
362 }
363 }
364 }
365}
366
367/* verify that all the pages have correct rights for code */
368static void tb_page_check(void)
369{
370 TranslationBlock *tb;
371 int i, flags1, flags2;
372
373 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
374 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
375 flags1 = page_get_flags(tb->pc);
376 flags2 = page_get_flags(tb->pc + tb->size - 1);
377 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
378 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
379 tb->pc, tb->size, flags1, flags2);
380 }
381 }
382 }
383}
384
bellardd4e81642003-05-25 16:46:15 +0000385void tb_jmp_check(TranslationBlock *tb)
386{
387 TranslationBlock *tb1;
388 unsigned int n1;
389
390 /* suppress any remaining jumps to this TB */
391 tb1 = tb->jmp_first;
392 for(;;) {
393 n1 = (long)tb1 & 3;
394 tb1 = (TranslationBlock *)((long)tb1 & ~3);
395 if (n1 == 2)
396 break;
397 tb1 = tb1->jmp_next[n1];
398 }
399 /* check end of list */
400 if (tb1 != tb) {
401 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
402 }
403}
404
bellardfd6ce8f2003-05-14 19:00:11 +0000405#endif
406
407/* invalidate one TB */
408static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
409 int next_offset)
410{
411 TranslationBlock *tb1;
412 for(;;) {
413 tb1 = *ptb;
414 if (tb1 == tb) {
415 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
416 break;
417 }
418 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
419 }
420}
421
bellard9fa3e852004-01-04 18:06:42 +0000422static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
423{
424 TranslationBlock *tb1;
425 unsigned int n1;
426
427 for(;;) {
428 tb1 = *ptb;
429 n1 = (long)tb1 & 3;
430 tb1 = (TranslationBlock *)((long)tb1 & ~3);
431 if (tb1 == tb) {
432 *ptb = tb1->page_next[n1];
433 break;
434 }
435 ptb = &tb1->page_next[n1];
436 }
437}
438
bellardd4e81642003-05-25 16:46:15 +0000439static inline void tb_jmp_remove(TranslationBlock *tb, int n)
440{
441 TranslationBlock *tb1, **ptb;
442 unsigned int n1;
443
444 ptb = &tb->jmp_next[n];
445 tb1 = *ptb;
446 if (tb1) {
447 /* find tb(n) in circular list */
448 for(;;) {
449 tb1 = *ptb;
450 n1 = (long)tb1 & 3;
451 tb1 = (TranslationBlock *)((long)tb1 & ~3);
452 if (n1 == n && tb1 == tb)
453 break;
454 if (n1 == 2) {
455 ptb = &tb1->jmp_first;
456 } else {
457 ptb = &tb1->jmp_next[n1];
458 }
459 }
460 /* now we can suppress tb(n) from the list */
461 *ptb = tb->jmp_next[n];
462
463 tb->jmp_next[n] = NULL;
464 }
465}
466
467/* reset the jump entry 'n' of a TB so that it is not chained to
468 another TB */
469static inline void tb_reset_jump(TranslationBlock *tb, int n)
470{
471 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
472}
473
bellard9fa3e852004-01-04 18:06:42 +0000474static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000475{
bellardd4e81642003-05-25 16:46:15 +0000476 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000477 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000478
bellard36bdbe52003-11-19 22:12:02 +0000479 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000480
bellardfd6ce8f2003-05-14 19:00:11 +0000481 /* remove the TB from the hash list */
482 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000483 ptb = &tb_hash[h];
484 for(;;) {
485 tb1 = *ptb;
486 /* NOTE: the TB is not necessarily linked in the hash. It
487 indicates that it is not currently used */
488 if (tb1 == NULL)
489 return;
490 if (tb1 == tb) {
491 *ptb = tb1->hash_next;
492 break;
493 }
494 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000495 }
bellardd4e81642003-05-25 16:46:15 +0000496
497 /* suppress this TB from the two jump lists */
498 tb_jmp_remove(tb, 0);
499 tb_jmp_remove(tb, 1);
500
501 /* suppress any remaining jumps to this TB */
502 tb1 = tb->jmp_first;
503 for(;;) {
504 n1 = (long)tb1 & 3;
505 if (n1 == 2)
506 break;
507 tb1 = (TranslationBlock *)((long)tb1 & ~3);
508 tb2 = tb1->jmp_next[n1];
509 tb_reset_jump(tb1, n1);
510 tb1->jmp_next[n1] = NULL;
511 tb1 = tb2;
512 }
513 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000514}
515
bellard9fa3e852004-01-04 18:06:42 +0000516static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000517{
bellardfd6ce8f2003-05-14 19:00:11 +0000518 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000519 unsigned int h;
520 target_ulong phys_pc;
521
522 /* remove the TB from the hash list */
523 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
524 h = tb_phys_hash_func(phys_pc);
525 tb_remove(&tb_phys_hash[h], tb,
526 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000527
bellard9fa3e852004-01-04 18:06:42 +0000528 /* remove the TB from the page list */
529 if (tb->page_addr[0] != page_addr) {
530 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
531 tb_page_remove(&p->first_tb, tb);
532 invalidate_page_bitmap(p);
533 }
534 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
535 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
536 tb_page_remove(&p->first_tb, tb);
537 invalidate_page_bitmap(p);
538 }
539
540 tb_invalidate(tb);
bellarde3db7222005-01-26 22:00:47 +0000541 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000542}
543
544static inline void set_bits(uint8_t *tab, int start, int len)
545{
546 int end, mask, end1;
547
548 end = start + len;
549 tab += start >> 3;
550 mask = 0xff << (start & 7);
551 if ((start & ~7) == (end & ~7)) {
552 if (start < end) {
553 mask &= ~(0xff << (end & 7));
554 *tab |= mask;
555 }
556 } else {
557 *tab++ |= mask;
558 start = (start + 8) & ~7;
559 end1 = end & ~7;
560 while (start < end1) {
561 *tab++ = 0xff;
562 start += 8;
563 }
564 if (start < end) {
565 mask = ~(0xff << (end & 7));
566 *tab |= mask;
567 }
568 }
569}
570
571static void build_page_bitmap(PageDesc *p)
572{
573 int n, tb_start, tb_end;
574 TranslationBlock *tb;
575
bellard59817cc2004-02-16 22:01:13 +0000576 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000577 if (!p->code_bitmap)
578 return;
579 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
580
581 tb = p->first_tb;
582 while (tb != NULL) {
583 n = (long)tb & 3;
584 tb = (TranslationBlock *)((long)tb & ~3);
585 /* NOTE: this is subtle as a TB may span two physical pages */
586 if (n == 0) {
587 /* NOTE: tb_end may be after the end of the page, but
588 it is not a problem */
589 tb_start = tb->pc & ~TARGET_PAGE_MASK;
590 tb_end = tb_start + tb->size;
591 if (tb_end > TARGET_PAGE_SIZE)
592 tb_end = TARGET_PAGE_SIZE;
593 } else {
594 tb_start = 0;
595 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
596 }
597 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
598 tb = tb->page_next[n];
599 }
600}
601
bellardd720b932004-04-25 17:57:43 +0000602#ifdef TARGET_HAS_PRECISE_SMC
603
604static void tb_gen_code(CPUState *env,
605 target_ulong pc, target_ulong cs_base, int flags,
606 int cflags)
607{
608 TranslationBlock *tb;
609 uint8_t *tc_ptr;
610 target_ulong phys_pc, phys_page2, virt_page2;
611 int code_gen_size;
612
bellardc27004e2005-01-03 23:35:10 +0000613 phys_pc = get_phys_addr_code(env, pc);
614 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000615 if (!tb) {
616 /* flush must be done */
617 tb_flush(env);
618 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000619 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000620 }
621 tc_ptr = code_gen_ptr;
622 tb->tc_ptr = tc_ptr;
623 tb->cs_base = cs_base;
624 tb->flags = flags;
625 tb->cflags = cflags;
626 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
627 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
628
629 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000630 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000631 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000632 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000633 phys_page2 = get_phys_addr_code(env, virt_page2);
634 }
635 tb_link_phys(tb, phys_pc, phys_page2);
636}
637#endif
638
bellard9fa3e852004-01-04 18:06:42 +0000639/* invalidate all TBs which intersect with the target physical page
640 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000641 the same physical page. 'is_cpu_write_access' should be true if called
642 from a real cpu write access: the virtual CPU will exit the current
643 TB if code is modified inside this TB. */
644void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
645 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000646{
bellardd720b932004-04-25 17:57:43 +0000647 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000648 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000649 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000650 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000651 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000652 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000653
654 p = page_find(start >> TARGET_PAGE_BITS);
655 if (!p)
656 return;
657 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000658 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
659 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000660 /* build code bitmap */
661 build_page_bitmap(p);
662 }
663
664 /* we remove all the TBs in the range [start, end[ */
665 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000666 current_tb_not_found = is_cpu_write_access;
667 current_tb_modified = 0;
668 current_tb = NULL; /* avoid warning */
669 current_pc = 0; /* avoid warning */
670 current_cs_base = 0; /* avoid warning */
671 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000672 tb = p->first_tb;
673 while (tb != NULL) {
674 n = (long)tb & 3;
675 tb = (TranslationBlock *)((long)tb & ~3);
676 tb_next = tb->page_next[n];
677 /* NOTE: this is subtle as a TB may span two physical pages */
678 if (n == 0) {
679 /* NOTE: tb_end may be after the end of the page, but
680 it is not a problem */
681 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
682 tb_end = tb_start + tb->size;
683 } else {
684 tb_start = tb->page_addr[1];
685 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
686 }
687 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000688#ifdef TARGET_HAS_PRECISE_SMC
689 if (current_tb_not_found) {
690 current_tb_not_found = 0;
691 current_tb = NULL;
692 if (env->mem_write_pc) {
693 /* now we have a real cpu fault */
694 current_tb = tb_find_pc(env->mem_write_pc);
695 }
696 }
697 if (current_tb == tb &&
698 !(current_tb->cflags & CF_SINGLE_INSN)) {
699 /* If we are modifying the current TB, we must stop
700 its execution. We could be more precise by checking
701 that the modification is after the current PC, but it
702 would require a specialized function to partially
703 restore the CPU state */
704
705 current_tb_modified = 1;
706 cpu_restore_state(current_tb, env,
707 env->mem_write_pc, NULL);
708#if defined(TARGET_I386)
709 current_flags = env->hflags;
710 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
711 current_cs_base = (target_ulong)env->segs[R_CS].base;
712 current_pc = current_cs_base + env->eip;
713#else
714#error unsupported CPU
715#endif
716 }
717#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000718 saved_tb = env->current_tb;
719 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000720 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000721 env->current_tb = saved_tb;
722 if (env->interrupt_request && env->current_tb)
723 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000724 }
725 tb = tb_next;
726 }
727#if !defined(CONFIG_USER_ONLY)
728 /* if no code remaining, no need to continue to use slow writes */
729 if (!p->first_tb) {
730 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000731 if (is_cpu_write_access) {
732 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
733 }
734 }
735#endif
736#ifdef TARGET_HAS_PRECISE_SMC
737 if (current_tb_modified) {
738 /* we generate a block containing just the instruction
739 modifying the memory. It will ensure that it cannot modify
740 itself */
bellardea1c1802004-06-14 18:56:36 +0000741 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000742 tb_gen_code(env, current_pc, current_cs_base, current_flags,
743 CF_SINGLE_INSN);
744 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000745 }
746#endif
747}
748
749/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000750static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000751{
752 PageDesc *p;
753 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000754#if 0
bellarda4193c82004-06-03 14:01:43 +0000755 if (1) {
756 if (loglevel) {
757 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
758 cpu_single_env->mem_write_vaddr, len,
759 cpu_single_env->eip,
760 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
761 }
bellard59817cc2004-02-16 22:01:13 +0000762 }
763#endif
bellard9fa3e852004-01-04 18:06:42 +0000764 p = page_find(start >> TARGET_PAGE_BITS);
765 if (!p)
766 return;
767 if (p->code_bitmap) {
768 offset = start & ~TARGET_PAGE_MASK;
769 b = p->code_bitmap[offset >> 3] >> (offset & 7);
770 if (b & ((1 << len) - 1))
771 goto do_invalidate;
772 } else {
773 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000774 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000775 }
776}
777
bellard9fa3e852004-01-04 18:06:42 +0000778#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000779static void tb_invalidate_phys_page(target_ulong addr,
780 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000781{
bellardd720b932004-04-25 17:57:43 +0000782 int n, current_flags, current_tb_modified;
783 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000784 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000785 TranslationBlock *tb, *current_tb;
786#ifdef TARGET_HAS_PRECISE_SMC
787 CPUState *env = cpu_single_env;
788#endif
bellard9fa3e852004-01-04 18:06:42 +0000789
790 addr &= TARGET_PAGE_MASK;
791 p = page_find(addr >> TARGET_PAGE_BITS);
792 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000793 return;
794 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000795 current_tb_modified = 0;
796 current_tb = NULL;
797 current_pc = 0; /* avoid warning */
798 current_cs_base = 0; /* avoid warning */
799 current_flags = 0; /* avoid warning */
800#ifdef TARGET_HAS_PRECISE_SMC
801 if (tb && pc != 0) {
802 current_tb = tb_find_pc(pc);
803 }
804#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000805 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000806 n = (long)tb & 3;
807 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000808#ifdef TARGET_HAS_PRECISE_SMC
809 if (current_tb == tb &&
810 !(current_tb->cflags & CF_SINGLE_INSN)) {
811 /* If we are modifying the current TB, we must stop
812 its execution. We could be more precise by checking
813 that the modification is after the current PC, but it
814 would require a specialized function to partially
815 restore the CPU state */
816
817 current_tb_modified = 1;
818 cpu_restore_state(current_tb, env, pc, puc);
819#if defined(TARGET_I386)
820 current_flags = env->hflags;
821 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
822 current_cs_base = (target_ulong)env->segs[R_CS].base;
823 current_pc = current_cs_base + env->eip;
824#else
825#error unsupported CPU
826#endif
827 }
828#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000829 tb_phys_invalidate(tb, addr);
830 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000831 }
832 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000833#ifdef TARGET_HAS_PRECISE_SMC
834 if (current_tb_modified) {
835 /* we generate a block containing just the instruction
836 modifying the memory. It will ensure that it cannot modify
837 itself */
bellardea1c1802004-06-14 18:56:36 +0000838 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000839 tb_gen_code(env, current_pc, current_cs_base, current_flags,
840 CF_SINGLE_INSN);
841 cpu_resume_from_signal(env, puc);
842 }
843#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000844}
bellard9fa3e852004-01-04 18:06:42 +0000845#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000846
847/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000848static inline void tb_alloc_page(TranslationBlock *tb,
849 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000850{
851 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000852 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000853
bellard9fa3e852004-01-04 18:06:42 +0000854 tb->page_addr[n] = page_addr;
855 p = page_find(page_addr >> TARGET_PAGE_BITS);
856 tb->page_next[n] = p->first_tb;
857 last_first_tb = p->first_tb;
858 p->first_tb = (TranslationBlock *)((long)tb | n);
859 invalidate_page_bitmap(p);
860
bellard107db442004-06-22 18:48:46 +0000861#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000862
bellard9fa3e852004-01-04 18:06:42 +0000863#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000864 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000865 unsigned long host_start, host_end, addr;
866 int prot;
867
bellardfd6ce8f2003-05-14 19:00:11 +0000868 /* force the host page as non writable (writes will have a
869 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000870 host_start = page_addr & qemu_host_page_mask;
871 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000872 prot = 0;
873 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
874 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000875 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000876 (prot & PAGE_BITS) & ~PAGE_WRITE);
877#ifdef DEBUG_TB_INVALIDATE
878 printf("protecting code page: 0x%08lx\n",
879 host_start);
880#endif
881 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000882 }
bellard9fa3e852004-01-04 18:06:42 +0000883#else
884 /* if some code is already present, then the pages are already
885 protected. So we handle the case where only the first TB is
886 allocated in a physical page */
887 if (!last_first_tb) {
888 target_ulong virt_addr;
889
890 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
891 tlb_protect_code(cpu_single_env, virt_addr);
892 }
893#endif
bellardd720b932004-04-25 17:57:43 +0000894
895#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000896}
897
898/* Allocate a new translation block. Flush the translation buffer if
899 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000900TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000901{
902 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000903
904 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
905 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000906 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000907 tb = &tbs[nb_tbs++];
908 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000909 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000910 return tb;
911}
912
bellard9fa3e852004-01-04 18:06:42 +0000913/* add a new TB and link it to the physical page tables. phys_page2 is
914 (-1) to indicate that only one page contains the TB. */
915void tb_link_phys(TranslationBlock *tb,
916 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000917{
bellard9fa3e852004-01-04 18:06:42 +0000918 unsigned int h;
919 TranslationBlock **ptb;
920
921 /* add in the physical hash table */
922 h = tb_phys_hash_func(phys_pc);
923 ptb = &tb_phys_hash[h];
924 tb->phys_hash_next = *ptb;
925 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000926
927 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000928 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
929 if (phys_page2 != -1)
930 tb_alloc_page(tb, 1, phys_page2);
931 else
932 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +0000933#ifdef DEBUG_TB_CHECK
934 tb_page_check();
935#endif
bellard9fa3e852004-01-04 18:06:42 +0000936}
937
938/* link the tb with the other TBs */
939void tb_link(TranslationBlock *tb)
940{
941#if !defined(CONFIG_USER_ONLY)
942 {
943 VirtPageDesc *vp;
944 target_ulong addr;
945
946 /* save the code memory mappings (needed to invalidate the code) */
947 addr = tb->pc & TARGET_PAGE_MASK;
948 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000949#ifdef DEBUG_TLB_CHECK
950 if (vp->valid_tag == virt_valid_tag &&
951 vp->phys_addr != tb->page_addr[0]) {
952 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
953 addr, tb->page_addr[0], vp->phys_addr);
954 }
955#endif
bellard9fa3e852004-01-04 18:06:42 +0000956 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +0000957 if (vp->valid_tag != virt_valid_tag) {
958 vp->valid_tag = virt_valid_tag;
959#if !defined(CONFIG_SOFTMMU)
960 vp->prot = 0;
961#endif
962 }
bellard9fa3e852004-01-04 18:06:42 +0000963
964 if (tb->page_addr[1] != -1) {
965 addr += TARGET_PAGE_SIZE;
966 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000967#ifdef DEBUG_TLB_CHECK
968 if (vp->valid_tag == virt_valid_tag &&
969 vp->phys_addr != tb->page_addr[1]) {
970 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
971 addr, tb->page_addr[1], vp->phys_addr);
972 }
973#endif
bellard9fa3e852004-01-04 18:06:42 +0000974 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +0000975 if (vp->valid_tag != virt_valid_tag) {
976 vp->valid_tag = virt_valid_tag;
977#if !defined(CONFIG_SOFTMMU)
978 vp->prot = 0;
979#endif
980 }
bellard9fa3e852004-01-04 18:06:42 +0000981 }
982 }
983#endif
984
bellardd4e81642003-05-25 16:46:15 +0000985 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
986 tb->jmp_next[0] = NULL;
987 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000988#ifdef USE_CODE_COPY
989 tb->cflags &= ~CF_FP_USED;
990 if (tb->cflags & CF_TB_FP_USED)
991 tb->cflags |= CF_FP_USED;
992#endif
bellardd4e81642003-05-25 16:46:15 +0000993
994 /* init original jump addresses */
995 if (tb->tb_next_offset[0] != 0xffff)
996 tb_reset_jump(tb, 0);
997 if (tb->tb_next_offset[1] != 0xffff)
998 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +0000999}
1000
bellarda513fe12003-05-27 23:29:48 +00001001/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1002 tb[1].tc_ptr. Return NULL if not found */
1003TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1004{
1005 int m_min, m_max, m;
1006 unsigned long v;
1007 TranslationBlock *tb;
1008
1009 if (nb_tbs <= 0)
1010 return NULL;
1011 if (tc_ptr < (unsigned long)code_gen_buffer ||
1012 tc_ptr >= (unsigned long)code_gen_ptr)
1013 return NULL;
1014 /* binary search (cf Knuth) */
1015 m_min = 0;
1016 m_max = nb_tbs - 1;
1017 while (m_min <= m_max) {
1018 m = (m_min + m_max) >> 1;
1019 tb = &tbs[m];
1020 v = (unsigned long)tb->tc_ptr;
1021 if (v == tc_ptr)
1022 return tb;
1023 else if (tc_ptr < v) {
1024 m_max = m - 1;
1025 } else {
1026 m_min = m + 1;
1027 }
1028 }
1029 return &tbs[m_max];
1030}
bellard75012672003-06-21 13:11:07 +00001031
bellardea041c02003-06-25 16:16:50 +00001032static void tb_reset_jump_recursive(TranslationBlock *tb);
1033
1034static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1035{
1036 TranslationBlock *tb1, *tb_next, **ptb;
1037 unsigned int n1;
1038
1039 tb1 = tb->jmp_next[n];
1040 if (tb1 != NULL) {
1041 /* find head of list */
1042 for(;;) {
1043 n1 = (long)tb1 & 3;
1044 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1045 if (n1 == 2)
1046 break;
1047 tb1 = tb1->jmp_next[n1];
1048 }
1049 /* we are now sure now that tb jumps to tb1 */
1050 tb_next = tb1;
1051
1052 /* remove tb from the jmp_first list */
1053 ptb = &tb_next->jmp_first;
1054 for(;;) {
1055 tb1 = *ptb;
1056 n1 = (long)tb1 & 3;
1057 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1058 if (n1 == n && tb1 == tb)
1059 break;
1060 ptb = &tb1->jmp_next[n1];
1061 }
1062 *ptb = tb->jmp_next[n];
1063 tb->jmp_next[n] = NULL;
1064
1065 /* suppress the jump to next tb in generated code */
1066 tb_reset_jump(tb, n);
1067
bellard01243112004-01-04 15:48:17 +00001068 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001069 tb_reset_jump_recursive(tb_next);
1070 }
1071}
1072
1073static void tb_reset_jump_recursive(TranslationBlock *tb)
1074{
1075 tb_reset_jump_recursive2(tb, 0);
1076 tb_reset_jump_recursive2(tb, 1);
1077}
1078
bellardc27004e2005-01-03 23:35:10 +00001079#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellardd720b932004-04-25 17:57:43 +00001080static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1081{
1082 target_ulong phys_addr;
1083
1084 phys_addr = cpu_get_phys_page_debug(env, pc);
1085 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1086}
bellardc27004e2005-01-03 23:35:10 +00001087#endif
bellardd720b932004-04-25 17:57:43 +00001088
bellardc33a3462003-07-29 20:50:33 +00001089/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1090 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001091int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001092{
bellarde95c8d52004-09-30 22:22:08 +00001093#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001094 int i;
bellardd720b932004-04-25 17:57:43 +00001095
bellard4c3a88a2003-07-26 12:06:08 +00001096 for(i = 0; i < env->nb_breakpoints; i++) {
1097 if (env->breakpoints[i] == pc)
1098 return 0;
1099 }
1100
1101 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1102 return -1;
1103 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001104
1105 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001106 return 0;
1107#else
1108 return -1;
1109#endif
1110}
1111
1112/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001113int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001114{
bellarde95c8d52004-09-30 22:22:08 +00001115#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001116 int i;
1117 for(i = 0; i < env->nb_breakpoints; i++) {
1118 if (env->breakpoints[i] == pc)
1119 goto found;
1120 }
1121 return -1;
1122 found:
1123 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
1124 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
1125 env->nb_breakpoints--;
bellardd720b932004-04-25 17:57:43 +00001126
1127 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001128 return 0;
1129#else
1130 return -1;
1131#endif
1132}
1133
bellardc33a3462003-07-29 20:50:33 +00001134/* enable or disable single step mode. EXCP_DEBUG is returned by the
1135 CPU loop after each instruction */
1136void cpu_single_step(CPUState *env, int enabled)
1137{
bellarde95c8d52004-09-30 22:22:08 +00001138#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellardc33a3462003-07-29 20:50:33 +00001139 if (env->singlestep_enabled != enabled) {
1140 env->singlestep_enabled = enabled;
1141 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001142 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001143 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001144 }
1145#endif
1146}
1147
bellard34865132003-10-05 14:28:56 +00001148/* enable or disable low levels log */
1149void cpu_set_log(int log_flags)
1150{
1151 loglevel = log_flags;
1152 if (loglevel && !logfile) {
1153 logfile = fopen(logfilename, "w");
1154 if (!logfile) {
1155 perror(logfilename);
1156 _exit(1);
1157 }
bellard9fa3e852004-01-04 18:06:42 +00001158#if !defined(CONFIG_SOFTMMU)
1159 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1160 {
1161 static uint8_t logfile_buf[4096];
1162 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1163 }
1164#else
bellard34865132003-10-05 14:28:56 +00001165 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001166#endif
bellard34865132003-10-05 14:28:56 +00001167 }
1168}
1169
1170void cpu_set_log_filename(const char *filename)
1171{
1172 logfilename = strdup(filename);
1173}
bellardc33a3462003-07-29 20:50:33 +00001174
bellard01243112004-01-04 15:48:17 +00001175/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001176void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001177{
1178 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001179 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001180
bellard68a79312003-06-30 13:12:32 +00001181 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001182 /* if the cpu is currently executing code, we must unlink it and
1183 all the potentially executing TB */
1184 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001185 if (tb && !testandset(&interrupt_lock)) {
1186 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001187 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001188 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001189 }
1190}
1191
bellardb54ad042004-05-20 13:42:52 +00001192void cpu_reset_interrupt(CPUState *env, int mask)
1193{
1194 env->interrupt_request &= ~mask;
1195}
1196
bellardf193c792004-03-21 17:06:25 +00001197CPULogItem cpu_log_items[] = {
1198 { CPU_LOG_TB_OUT_ASM, "out_asm",
1199 "show generated host assembly code for each compiled TB" },
1200 { CPU_LOG_TB_IN_ASM, "in_asm",
1201 "show target assembly code for each compiled TB" },
1202 { CPU_LOG_TB_OP, "op",
1203 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1204#ifdef TARGET_I386
1205 { CPU_LOG_TB_OP_OPT, "op_opt",
1206 "show micro ops after optimization for each compiled TB" },
1207#endif
1208 { CPU_LOG_INT, "int",
1209 "show interrupts/exceptions in short format" },
1210 { CPU_LOG_EXEC, "exec",
1211 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001212 { CPU_LOG_TB_CPU, "cpu",
1213 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001214#ifdef TARGET_I386
1215 { CPU_LOG_PCALL, "pcall",
1216 "show protected mode far calls/returns/exceptions" },
1217#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001218#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001219 { CPU_LOG_IOPORT, "ioport",
1220 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001221#endif
bellardf193c792004-03-21 17:06:25 +00001222 { 0, NULL, NULL },
1223};
1224
1225static int cmp1(const char *s1, int n, const char *s2)
1226{
1227 if (strlen(s2) != n)
1228 return 0;
1229 return memcmp(s1, s2, n) == 0;
1230}
1231
1232/* takes a comma separated list of log masks. Return 0 if error. */
1233int cpu_str_to_log_mask(const char *str)
1234{
1235 CPULogItem *item;
1236 int mask;
1237 const char *p, *p1;
1238
1239 p = str;
1240 mask = 0;
1241 for(;;) {
1242 p1 = strchr(p, ',');
1243 if (!p1)
1244 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001245 if(cmp1(p,p1-p,"all")) {
1246 for(item = cpu_log_items; item->mask != 0; item++) {
1247 mask |= item->mask;
1248 }
1249 } else {
bellardf193c792004-03-21 17:06:25 +00001250 for(item = cpu_log_items; item->mask != 0; item++) {
1251 if (cmp1(p, p1 - p, item->name))
1252 goto found;
1253 }
1254 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001255 }
bellardf193c792004-03-21 17:06:25 +00001256 found:
1257 mask |= item->mask;
1258 if (*p1 != ',')
1259 break;
1260 p = p1 + 1;
1261 }
1262 return mask;
1263}
bellardea041c02003-06-25 16:16:50 +00001264
bellard75012672003-06-21 13:11:07 +00001265void cpu_abort(CPUState *env, const char *fmt, ...)
1266{
1267 va_list ap;
1268
1269 va_start(ap, fmt);
1270 fprintf(stderr, "qemu: fatal: ");
1271 vfprintf(stderr, fmt, ap);
1272 fprintf(stderr, "\n");
1273#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001274 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1275#else
1276 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001277#endif
1278 va_end(ap);
1279 abort();
1280}
1281
bellard01243112004-01-04 15:48:17 +00001282#if !defined(CONFIG_USER_ONLY)
1283
bellardee8b7022004-02-03 23:35:10 +00001284/* NOTE: if flush_global is true, also flush global entries (not
1285 implemented yet) */
1286void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001287{
bellard33417e72003-08-10 21:47:01 +00001288 int i;
bellard01243112004-01-04 15:48:17 +00001289
bellard9fa3e852004-01-04 18:06:42 +00001290#if defined(DEBUG_TLB)
1291 printf("tlb_flush:\n");
1292#endif
bellard01243112004-01-04 15:48:17 +00001293 /* must reset current TB so that interrupts cannot modify the
1294 links while we are modifying them */
1295 env->current_tb = NULL;
1296
bellard33417e72003-08-10 21:47:01 +00001297 for(i = 0; i < CPU_TLB_SIZE; i++) {
1298 env->tlb_read[0][i].address = -1;
1299 env->tlb_write[0][i].address = -1;
1300 env->tlb_read[1][i].address = -1;
1301 env->tlb_write[1][i].address = -1;
1302 }
bellard9fa3e852004-01-04 18:06:42 +00001303
1304 virt_page_flush();
bellard8a8a6082004-10-03 13:36:49 +00001305 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001306
1307#if !defined(CONFIG_SOFTMMU)
1308 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1309#endif
bellard0a962c02005-02-10 22:00:27 +00001310#ifdef USE_KQEMU
1311 if (env->kqemu_enabled) {
1312 kqemu_flush(env, flush_global);
1313 }
1314#endif
bellarde3db7222005-01-26 22:00:47 +00001315 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001316}
1317
bellard274da6b2004-05-20 21:56:27 +00001318static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001319{
1320 if (addr == (tlb_entry->address &
1321 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1322 tlb_entry->address = -1;
1323}
1324
bellard2e126692004-04-25 21:28:44 +00001325void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001326{
bellard9fa3e852004-01-04 18:06:42 +00001327 int i, n;
1328 VirtPageDesc *vp;
1329 PageDesc *p;
1330 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001331
bellard9fa3e852004-01-04 18:06:42 +00001332#if defined(DEBUG_TLB)
1333 printf("tlb_flush_page: 0x%08x\n", addr);
1334#endif
bellard01243112004-01-04 15:48:17 +00001335 /* must reset current TB so that interrupts cannot modify the
1336 links while we are modifying them */
1337 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001338
bellard61382a52003-10-27 21:22:23 +00001339 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001340 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001341 tlb_flush_entry(&env->tlb_read[0][i], addr);
1342 tlb_flush_entry(&env->tlb_write[0][i], addr);
1343 tlb_flush_entry(&env->tlb_read[1][i], addr);
1344 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001345
bellard9fa3e852004-01-04 18:06:42 +00001346 /* remove from the virtual pc hash table all the TB at this
1347 virtual address */
1348
1349 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1350 if (vp && vp->valid_tag == virt_valid_tag) {
1351 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1352 if (p) {
1353 /* we remove all the links to the TBs in this virtual page */
1354 tb = p->first_tb;
1355 while (tb != NULL) {
1356 n = (long)tb & 3;
1357 tb = (TranslationBlock *)((long)tb & ~3);
1358 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1359 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1360 tb_invalidate(tb);
1361 }
1362 tb = tb->page_next[n];
1363 }
1364 }
bellard98857882004-01-18 21:52:14 +00001365 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001366 }
1367
bellard01243112004-01-04 15:48:17 +00001368#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001369 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001370 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001371#endif
bellard0a962c02005-02-10 22:00:27 +00001372#ifdef USE_KQEMU
1373 if (env->kqemu_enabled) {
1374 kqemu_flush_page(env, addr);
1375 }
1376#endif
bellard9fa3e852004-01-04 18:06:42 +00001377}
1378
bellard4f2ac232004-04-26 19:44:02 +00001379static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001380{
1381 if (addr == (tlb_entry->address &
1382 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001383 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1384 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001385 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001386 }
bellard61382a52003-10-27 21:22:23 +00001387}
1388
bellard9fa3e852004-01-04 18:06:42 +00001389/* update the TLBs so that writes to code in the virtual page 'addr'
1390 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001391static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001392{
bellard61382a52003-10-27 21:22:23 +00001393 int i;
1394
1395 addr &= TARGET_PAGE_MASK;
1396 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001397 tlb_protect_code1(&env->tlb_write[0][i], addr);
1398 tlb_protect_code1(&env->tlb_write[1][i], addr);
1399#if !defined(CONFIG_SOFTMMU)
1400 /* NOTE: as we generated the code for this page, it is already at
1401 least readable */
1402 if (addr < MMAP_AREA_END)
1403 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1404#endif
1405}
1406
bellard9fa3e852004-01-04 18:06:42 +00001407static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001408 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001409{
1410 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1411 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001412 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001413 }
1414}
1415
1416/* update the TLB so that writes in physical page 'phys_addr' are no longer
1417 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001418static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001419{
1420 int i;
1421
1422 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001423 phys_addr += (long)phys_ram_base;
1424 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1425 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1426 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1427}
1428
1429static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1430 unsigned long start, unsigned long length)
1431{
1432 unsigned long addr;
1433 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1434 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1435 if ((addr - start) < length) {
1436 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1437 }
1438 }
1439}
1440
bellard0a962c02005-02-10 22:00:27 +00001441void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
1442 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001443{
1444 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001445 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001446 int i, mask, len;
1447 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001448
1449 start &= TARGET_PAGE_MASK;
1450 end = TARGET_PAGE_ALIGN(end);
1451
1452 length = end - start;
1453 if (length == 0)
1454 return;
bellard0a962c02005-02-10 22:00:27 +00001455 mask = ~dirty_flags;
1456 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1457 len = length >> TARGET_PAGE_BITS;
1458 for(i = 0; i < len; i++)
1459 p[i] &= mask;
bellard1ccde1c2004-02-06 19:46:14 +00001460
1461 env = cpu_single_env;
1462 /* we modify the TLB cache so that the dirty bit will be set again
1463 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001464 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001465 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001466 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001467 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001468 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1469
1470#if !defined(CONFIG_SOFTMMU)
1471 /* XXX: this is expensive */
1472 {
1473 VirtPageDesc *p;
1474 int j;
1475 target_ulong addr;
1476
1477 for(i = 0; i < L1_SIZE; i++) {
1478 p = l1_virt_map[i];
1479 if (p) {
1480 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1481 for(j = 0; j < L2_SIZE; j++) {
1482 if (p->valid_tag == virt_valid_tag &&
1483 p->phys_addr >= start && p->phys_addr < end &&
1484 (p->prot & PROT_WRITE)) {
1485 if (addr < MMAP_AREA_END) {
1486 mprotect((void *)addr, TARGET_PAGE_SIZE,
1487 p->prot & ~PROT_WRITE);
1488 }
1489 }
1490 addr += TARGET_PAGE_SIZE;
1491 p++;
1492 }
1493 }
1494 }
1495 }
1496#endif
bellard1ccde1c2004-02-06 19:46:14 +00001497}
1498
1499static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1500 unsigned long start)
1501{
1502 unsigned long addr;
1503 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1504 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1505 if (addr == start) {
1506 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1507 }
1508 }
1509}
1510
1511/* update the TLB corresponding to virtual page vaddr and phys addr
1512 addr so that it is no longer dirty */
1513static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1514{
1515 CPUState *env = cpu_single_env;
1516 int i;
1517
bellard0a962c02005-02-10 22:00:27 +00001518 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff;
bellard1ccde1c2004-02-06 19:46:14 +00001519
1520 addr &= TARGET_PAGE_MASK;
1521 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1522 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1523 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001524}
1525
bellard59817cc2004-02-16 22:01:13 +00001526/* add a new TLB entry. At most one entry for a given virtual address
1527 is permitted. Return 0 if OK or 2 if the page could not be mapped
1528 (can only happen in non SOFTMMU mode for I/O pages or pages
1529 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001530int tlb_set_page(CPUState *env, target_ulong vaddr,
1531 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001532 int is_user, int is_softmmu)
1533{
bellard92e873b2004-05-21 14:52:29 +00001534 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001535 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001536 TranslationBlock *first_tb;
1537 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001538 target_ulong address;
1539 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001540 int ret;
1541
bellard92e873b2004-05-21 14:52:29 +00001542 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1543 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001544 if (!p) {
1545 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001546 } else {
bellard92e873b2004-05-21 14:52:29 +00001547 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001548 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001549 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1550 /* NOTE: we also allocate the page at this stage */
1551 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1552 first_tb = p1->first_tb;
1553 }
bellard9fa3e852004-01-04 18:06:42 +00001554 }
1555#if defined(DEBUG_TLB)
1556 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1557 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1558#endif
1559
1560 ret = 0;
1561#if !defined(CONFIG_SOFTMMU)
1562 if (is_softmmu)
1563#endif
1564 {
1565 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1566 /* IO memory case */
1567 address = vaddr | pd;
1568 addend = paddr;
1569 } else {
1570 /* standard memory */
1571 address = vaddr;
1572 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1573 }
1574
1575 index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1576 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001577 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001578 env->tlb_read[is_user][index].address = address;
1579 env->tlb_read[is_user][index].addend = addend;
1580 } else {
1581 env->tlb_read[is_user][index].address = -1;
1582 env->tlb_read[is_user][index].addend = -1;
1583 }
bellard67b915a2004-03-31 23:37:16 +00001584 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001585 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1586 /* ROM: access is ignored (same as unassigned) */
1587 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001588 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001589 } else
1590 /* XXX: the PowerPC code seems not ready to handle
1591 self modifying code with DCBI */
1592#if defined(TARGET_HAS_SMC) || 1
1593 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001594 /* if code is present, we use a specific memory
1595 handler. It works only for physical memory access */
1596 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001597 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001598 } else
1599#endif
1600 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001601 !cpu_physical_memory_is_dirty(pd)) {
1602 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1603 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001604 } else {
1605 env->tlb_write[is_user][index].address = address;
1606 env->tlb_write[is_user][index].addend = addend;
1607 }
1608 } else {
1609 env->tlb_write[is_user][index].address = -1;
1610 env->tlb_write[is_user][index].addend = -1;
1611 }
1612 }
1613#if !defined(CONFIG_SOFTMMU)
1614 else {
1615 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1616 /* IO access: no mapping is done as it will be handled by the
1617 soft MMU */
1618 if (!(env->hflags & HF_SOFTMMU_MASK))
1619 ret = 2;
1620 } else {
1621 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001622
bellard59817cc2004-02-16 22:01:13 +00001623 if (vaddr >= MMAP_AREA_END) {
1624 ret = 2;
1625 } else {
1626 if (prot & PROT_WRITE) {
1627 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001628#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001629 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001630#endif
bellard59817cc2004-02-16 22:01:13 +00001631 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1632 !cpu_physical_memory_is_dirty(pd))) {
1633 /* ROM: we do as if code was inside */
1634 /* if code is present, we only map as read only and save the
1635 original mapping */
1636 VirtPageDesc *vp;
1637
1638 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1639 vp->phys_addr = pd;
1640 vp->prot = prot;
1641 vp->valid_tag = virt_valid_tag;
1642 prot &= ~PAGE_WRITE;
1643 }
bellard9fa3e852004-01-04 18:06:42 +00001644 }
bellard59817cc2004-02-16 22:01:13 +00001645 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1646 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1647 if (map_addr == MAP_FAILED) {
1648 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1649 paddr, vaddr);
1650 }
bellard9fa3e852004-01-04 18:06:42 +00001651 }
1652 }
1653 }
1654#endif
1655 return ret;
1656}
1657
1658/* called from signal handler: invalidate the code and unprotect the
1659 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001660int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001661{
1662#if !defined(CONFIG_SOFTMMU)
1663 VirtPageDesc *vp;
1664
1665#if defined(DEBUG_TLB)
1666 printf("page_unprotect: addr=0x%08x\n", addr);
1667#endif
1668 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001669
1670 /* if it is not mapped, no need to worry here */
1671 if (addr >= MMAP_AREA_END)
1672 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001673 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1674 if (!vp)
1675 return 0;
1676 /* NOTE: in this case, validate_tag is _not_ tested as it
1677 validates only the code TLB */
1678 if (vp->valid_tag != virt_valid_tag)
1679 return 0;
1680 if (!(vp->prot & PAGE_WRITE))
1681 return 0;
1682#if defined(DEBUG_TLB)
1683 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1684 addr, vp->phys_addr, vp->prot);
1685#endif
bellard59817cc2004-02-16 22:01:13 +00001686 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1687 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1688 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001689 /* set the dirty bit */
bellard0a962c02005-02-10 22:00:27 +00001690 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellardd720b932004-04-25 17:57:43 +00001691 /* flush the code inside */
1692 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001693 return 1;
1694#else
1695 return 0;
1696#endif
bellard33417e72003-08-10 21:47:01 +00001697}
1698
bellard01243112004-01-04 15:48:17 +00001699#else
1700
bellardee8b7022004-02-03 23:35:10 +00001701void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001702{
1703}
1704
bellard2e126692004-04-25 21:28:44 +00001705void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001706{
1707}
1708
bellard2e126692004-04-25 21:28:44 +00001709int tlb_set_page(CPUState *env, target_ulong vaddr,
1710 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001711 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001712{
bellard9fa3e852004-01-04 18:06:42 +00001713 return 0;
1714}
bellard33417e72003-08-10 21:47:01 +00001715
bellard9fa3e852004-01-04 18:06:42 +00001716/* dump memory mappings */
1717void page_dump(FILE *f)
1718{
1719 unsigned long start, end;
1720 int i, j, prot, prot1;
1721 PageDesc *p;
1722
1723 fprintf(f, "%-8s %-8s %-8s %s\n",
1724 "start", "end", "size", "prot");
1725 start = -1;
1726 end = -1;
1727 prot = 0;
1728 for(i = 0; i <= L1_SIZE; i++) {
1729 if (i < L1_SIZE)
1730 p = l1_map[i];
1731 else
1732 p = NULL;
1733 for(j = 0;j < L2_SIZE; j++) {
1734 if (!p)
1735 prot1 = 0;
1736 else
1737 prot1 = p[j].flags;
1738 if (prot1 != prot) {
1739 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1740 if (start != -1) {
1741 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1742 start, end, end - start,
1743 prot & PAGE_READ ? 'r' : '-',
1744 prot & PAGE_WRITE ? 'w' : '-',
1745 prot & PAGE_EXEC ? 'x' : '-');
1746 }
1747 if (prot1 != 0)
1748 start = end;
1749 else
1750 start = -1;
1751 prot = prot1;
1752 }
1753 if (!p)
1754 break;
1755 }
bellard33417e72003-08-10 21:47:01 +00001756 }
bellard33417e72003-08-10 21:47:01 +00001757}
1758
bellard9fa3e852004-01-04 18:06:42 +00001759int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001760{
bellard9fa3e852004-01-04 18:06:42 +00001761 PageDesc *p;
1762
1763 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001764 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001765 return 0;
1766 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001767}
1768
bellard9fa3e852004-01-04 18:06:42 +00001769/* modify the flags of a page and invalidate the code if
1770 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1771 depending on PAGE_WRITE */
1772void page_set_flags(unsigned long start, unsigned long end, int flags)
1773{
1774 PageDesc *p;
1775 unsigned long addr;
1776
1777 start = start & TARGET_PAGE_MASK;
1778 end = TARGET_PAGE_ALIGN(end);
1779 if (flags & PAGE_WRITE)
1780 flags |= PAGE_WRITE_ORG;
1781 spin_lock(&tb_lock);
1782 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1783 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1784 /* if the write protection is set, then we invalidate the code
1785 inside */
1786 if (!(p->flags & PAGE_WRITE) &&
1787 (flags & PAGE_WRITE) &&
1788 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001789 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001790 }
1791 p->flags = flags;
1792 }
1793 spin_unlock(&tb_lock);
1794}
1795
1796/* called from signal handler: invalidate the code and unprotect the
1797 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001798int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001799{
1800 unsigned int page_index, prot, pindex;
1801 PageDesc *p, *p1;
1802 unsigned long host_start, host_end, addr;
1803
bellard83fb7ad2004-07-05 21:25:26 +00001804 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001805 page_index = host_start >> TARGET_PAGE_BITS;
1806 p1 = page_find(page_index);
1807 if (!p1)
1808 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001809 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001810 p = p1;
1811 prot = 0;
1812 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1813 prot |= p->flags;
1814 p++;
1815 }
1816 /* if the page was really writable, then we change its
1817 protection back to writable */
1818 if (prot & PAGE_WRITE_ORG) {
1819 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1820 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001821 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001822 (prot & PAGE_BITS) | PAGE_WRITE);
1823 p1[pindex].flags |= PAGE_WRITE;
1824 /* and since the content will be modified, we must invalidate
1825 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001826 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001827#ifdef DEBUG_TB_CHECK
1828 tb_invalidate_check(address);
1829#endif
1830 return 1;
1831 }
1832 }
1833 return 0;
1834}
1835
1836/* call this function when system calls directly modify a memory area */
1837void page_unprotect_range(uint8_t *data, unsigned long data_size)
1838{
1839 unsigned long start, end, addr;
1840
1841 start = (unsigned long)data;
1842 end = start + data_size;
1843 start &= TARGET_PAGE_MASK;
1844 end = TARGET_PAGE_ALIGN(end);
1845 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001846 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001847 }
1848}
1849
bellard1ccde1c2004-02-06 19:46:14 +00001850static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1851{
1852}
bellard9fa3e852004-01-04 18:06:42 +00001853#endif /* defined(CONFIG_USER_ONLY) */
1854
bellard33417e72003-08-10 21:47:01 +00001855/* register physical memory. 'size' must be a multiple of the target
1856 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1857 io memory page */
bellard2e126692004-04-25 21:28:44 +00001858void cpu_register_physical_memory(target_phys_addr_t start_addr,
1859 unsigned long size,
1860 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001861{
1862 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001863 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001864
bellard5fd386f2004-05-23 21:11:22 +00001865 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001866 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001867 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001868 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001869 p->phys_offset = phys_offset;
1870 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001871 phys_offset += TARGET_PAGE_SIZE;
1872 }
1873}
1874
bellarda4193c82004-06-03 14:01:43 +00001875static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001876{
1877 return 0;
1878}
1879
bellarda4193c82004-06-03 14:01:43 +00001880static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001881{
1882}
1883
1884static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1885 unassigned_mem_readb,
1886 unassigned_mem_readb,
1887 unassigned_mem_readb,
1888};
1889
1890static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1891 unassigned_mem_writeb,
1892 unassigned_mem_writeb,
1893 unassigned_mem_writeb,
1894};
1895
bellard9fa3e852004-01-04 18:06:42 +00001896/* self modifying code support in soft mmu mode : writing to a page
1897 containing code comes to these functions */
1898
bellarda4193c82004-06-03 14:01:43 +00001899static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001900{
bellard1ccde1c2004-02-06 19:46:14 +00001901 unsigned long phys_addr;
1902
bellard274da6b2004-05-20 21:56:27 +00001903 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001904#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001905 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001906#endif
bellardc27004e2005-01-03 23:35:10 +00001907 stb_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00001908 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00001909}
1910
bellarda4193c82004-06-03 14:01:43 +00001911static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001912{
bellard1ccde1c2004-02-06 19:46:14 +00001913 unsigned long phys_addr;
1914
bellard274da6b2004-05-20 21:56:27 +00001915 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001916#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001917 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001918#endif
bellardc27004e2005-01-03 23:35:10 +00001919 stw_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00001920 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00001921}
1922
bellarda4193c82004-06-03 14:01:43 +00001923static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001924{
bellard1ccde1c2004-02-06 19:46:14 +00001925 unsigned long phys_addr;
1926
bellard274da6b2004-05-20 21:56:27 +00001927 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001928#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001929 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00001930#endif
bellardc27004e2005-01-03 23:35:10 +00001931 stl_p((uint8_t *)(long)addr, val);
bellard0a962c02005-02-10 22:00:27 +00001932 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
bellard9fa3e852004-01-04 18:06:42 +00001933}
1934
1935static CPUReadMemoryFunc *code_mem_read[3] = {
1936 NULL, /* never used */
1937 NULL, /* never used */
1938 NULL, /* never used */
1939};
1940
1941static CPUWriteMemoryFunc *code_mem_write[3] = {
1942 code_mem_writeb,
1943 code_mem_writew,
1944 code_mem_writel,
1945};
bellard33417e72003-08-10 21:47:01 +00001946
bellarda4193c82004-06-03 14:01:43 +00001947static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001948{
bellardc27004e2005-01-03 23:35:10 +00001949 stb_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001950 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001951}
1952
bellarda4193c82004-06-03 14:01:43 +00001953static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001954{
bellardc27004e2005-01-03 23:35:10 +00001955 stw_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001956 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001957}
1958
bellarda4193c82004-06-03 14:01:43 +00001959static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001960{
bellardc27004e2005-01-03 23:35:10 +00001961 stl_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001962 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001963}
1964
1965static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1966 notdirty_mem_writeb,
1967 notdirty_mem_writew,
1968 notdirty_mem_writel,
1969};
1970
bellard33417e72003-08-10 21:47:01 +00001971static void io_mem_init(void)
1972{
bellarda4193c82004-06-03 14:01:43 +00001973 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1974 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1975 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1976 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001977 io_mem_nb = 5;
1978
1979 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00001980 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001981}
1982
1983/* mem_read and mem_write are arrays of functions containing the
1984 function to access byte (index 0), word (index 1) and dword (index
1985 2). All functions must be supplied. If io_index is non zero, the
1986 corresponding io zone is modified. If it is zero, a new io zone is
1987 allocated. The return value can be used with
1988 cpu_register_physical_memory(). (-1) is returned if error. */
1989int cpu_register_io_memory(int io_index,
1990 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001991 CPUWriteMemoryFunc **mem_write,
1992 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001993{
1994 int i;
1995
1996 if (io_index <= 0) {
1997 if (io_index >= IO_MEM_NB_ENTRIES)
1998 return -1;
1999 io_index = io_mem_nb++;
2000 } else {
2001 if (io_index >= IO_MEM_NB_ENTRIES)
2002 return -1;
2003 }
2004
2005 for(i = 0;i < 3; i++) {
2006 io_mem_read[io_index][i] = mem_read[i];
2007 io_mem_write[io_index][i] = mem_write[i];
2008 }
bellarda4193c82004-06-03 14:01:43 +00002009 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00002010 return io_index << IO_MEM_SHIFT;
2011}
bellard61382a52003-10-27 21:22:23 +00002012
bellard8926b512004-10-10 15:14:20 +00002013CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2014{
2015 return io_mem_write[io_index >> IO_MEM_SHIFT];
2016}
2017
2018CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2019{
2020 return io_mem_read[io_index >> IO_MEM_SHIFT];
2021}
2022
bellard13eb76e2004-01-24 15:23:36 +00002023/* physical memory access (slow version, mainly for debug) */
2024#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002025void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002026 int len, int is_write)
2027{
2028 int l, flags;
2029 target_ulong page;
2030
2031 while (len > 0) {
2032 page = addr & TARGET_PAGE_MASK;
2033 l = (page + TARGET_PAGE_SIZE) - addr;
2034 if (l > len)
2035 l = len;
2036 flags = page_get_flags(page);
2037 if (!(flags & PAGE_VALID))
2038 return;
2039 if (is_write) {
2040 if (!(flags & PAGE_WRITE))
2041 return;
2042 memcpy((uint8_t *)addr, buf, len);
2043 } else {
2044 if (!(flags & PAGE_READ))
2045 return;
2046 memcpy(buf, (uint8_t *)addr, len);
2047 }
2048 len -= l;
2049 buf += l;
2050 addr += l;
2051 }
2052}
bellard8df1cd02005-01-28 22:37:22 +00002053
2054/* never used */
2055uint32_t ldl_phys(target_phys_addr_t addr)
2056{
2057 return 0;
2058}
2059
2060void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2061{
2062}
2063
2064void stl_phys(target_phys_addr_t addr, uint32_t val)
2065{
2066}
2067
bellard13eb76e2004-01-24 15:23:36 +00002068#else
bellard2e126692004-04-25 21:28:44 +00002069void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002070 int len, int is_write)
2071{
2072 int l, io_index;
2073 uint8_t *ptr;
2074 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002075 target_phys_addr_t page;
2076 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002077 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002078
2079 while (len > 0) {
2080 page = addr & TARGET_PAGE_MASK;
2081 l = (page + TARGET_PAGE_SIZE) - addr;
2082 if (l > len)
2083 l = len;
bellard92e873b2004-05-21 14:52:29 +00002084 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002085 if (!p) {
2086 pd = IO_MEM_UNASSIGNED;
2087 } else {
2088 pd = p->phys_offset;
2089 }
2090
2091 if (is_write) {
2092 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2093 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2094 if (l >= 4 && ((addr & 3) == 0)) {
2095 /* 32 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002096 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002097 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002098 l = 4;
2099 } else if (l >= 2 && ((addr & 1) == 0)) {
2100 /* 16 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002101 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002102 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002103 l = 2;
2104 } else {
2105 /* 8 bit access */
bellardc27004e2005-01-03 23:35:10 +00002106 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002107 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002108 l = 1;
2109 }
2110 } else {
bellardb448f2f2004-02-25 23:24:04 +00002111 unsigned long addr1;
2112 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002113 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002114 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002115 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002116 /* invalidate code */
2117 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2118 /* set dirty bit */
bellard0a962c02005-02-10 22:00:27 +00002119 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
bellard13eb76e2004-01-24 15:23:36 +00002120 }
2121 } else {
2122 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2123 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2124 /* I/O case */
2125 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2126 if (l >= 4 && ((addr & 3) == 0)) {
2127 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002128 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002129 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002130 l = 4;
2131 } else if (l >= 2 && ((addr & 1) == 0)) {
2132 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002133 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002134 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002135 l = 2;
2136 } else {
2137 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002138 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002139 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002140 l = 1;
2141 }
2142 } else {
2143 /* RAM case */
2144 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2145 (addr & ~TARGET_PAGE_MASK);
2146 memcpy(buf, ptr, l);
2147 }
2148 }
2149 len -= l;
2150 buf += l;
2151 addr += l;
2152 }
2153}
bellard8df1cd02005-01-28 22:37:22 +00002154
2155/* warning: addr must be aligned */
2156uint32_t ldl_phys(target_phys_addr_t addr)
2157{
2158 int io_index;
2159 uint8_t *ptr;
2160 uint32_t val;
2161 unsigned long pd;
2162 PhysPageDesc *p;
2163
2164 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2165 if (!p) {
2166 pd = IO_MEM_UNASSIGNED;
2167 } else {
2168 pd = p->phys_offset;
2169 }
2170
2171 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2172 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2173 /* I/O case */
2174 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2175 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2176 } else {
2177 /* RAM case */
2178 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2179 (addr & ~TARGET_PAGE_MASK);
2180 val = ldl_p(ptr);
2181 }
2182 return val;
2183}
2184
2185/* warning: addr must be aligned. The ram page is not masked as dirty
2186 and the code inside is not invalidated. It is useful if the dirty
2187 bits are used to track modified PTEs */
2188void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2189{
2190 int io_index;
2191 uint8_t *ptr;
2192 unsigned long pd;
2193 PhysPageDesc *p;
2194
2195 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2196 if (!p) {
2197 pd = IO_MEM_UNASSIGNED;
2198 } else {
2199 pd = p->phys_offset;
2200 }
2201
2202 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2203 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2204 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2205 } else {
2206 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2207 (addr & ~TARGET_PAGE_MASK);
2208 stl_p(ptr, val);
2209 }
2210}
2211
2212/* warning: addr must be aligned */
2213/* XXX: optimize code invalidation test */
2214void stl_phys(target_phys_addr_t addr, uint32_t val)
2215{
2216 int io_index;
2217 uint8_t *ptr;
2218 unsigned long pd;
2219 PhysPageDesc *p;
2220
2221 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2222 if (!p) {
2223 pd = IO_MEM_UNASSIGNED;
2224 } else {
2225 pd = p->phys_offset;
2226 }
2227
2228 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2229 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2230 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2231 } else {
2232 unsigned long addr1;
2233 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2234 /* RAM case */
2235 ptr = phys_ram_base + addr1;
2236 stl_p(ptr, val);
2237 /* invalidate code */
2238 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2239 /* set dirty bit */
bellard0a962c02005-02-10 22:00:27 +00002240 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
bellard8df1cd02005-01-28 22:37:22 +00002241 }
2242}
2243
bellard13eb76e2004-01-24 15:23:36 +00002244#endif
2245
2246/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002247int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2248 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002249{
2250 int l;
2251 target_ulong page, phys_addr;
2252
2253 while (len > 0) {
2254 page = addr & TARGET_PAGE_MASK;
2255 phys_addr = cpu_get_phys_page_debug(env, page);
2256 /* if no physical page mapped, return an error */
2257 if (phys_addr == -1)
2258 return -1;
2259 l = (page + TARGET_PAGE_SIZE) - addr;
2260 if (l > len)
2261 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002262 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2263 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002264 len -= l;
2265 buf += l;
2266 addr += l;
2267 }
2268 return 0;
2269}
2270
bellarde3db7222005-01-26 22:00:47 +00002271void dump_exec_info(FILE *f,
2272 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2273{
2274 int i, target_code_size, max_target_code_size;
2275 int direct_jmp_count, direct_jmp2_count, cross_page;
2276 TranslationBlock *tb;
2277
2278 target_code_size = 0;
2279 max_target_code_size = 0;
2280 cross_page = 0;
2281 direct_jmp_count = 0;
2282 direct_jmp2_count = 0;
2283 for(i = 0; i < nb_tbs; i++) {
2284 tb = &tbs[i];
2285 target_code_size += tb->size;
2286 if (tb->size > max_target_code_size)
2287 max_target_code_size = tb->size;
2288 if (tb->page_addr[1] != -1)
2289 cross_page++;
2290 if (tb->tb_next_offset[0] != 0xffff) {
2291 direct_jmp_count++;
2292 if (tb->tb_next_offset[1] != 0xffff) {
2293 direct_jmp2_count++;
2294 }
2295 }
2296 }
2297 /* XXX: avoid using doubles ? */
2298 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2299 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2300 nb_tbs ? target_code_size / nb_tbs : 0,
2301 max_target_code_size);
2302 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2303 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2304 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2305 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2306 cross_page,
2307 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2308 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2309 direct_jmp_count,
2310 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2311 direct_jmp2_count,
2312 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2313 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2314 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2315 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2316}
2317
bellard61382a52003-10-27 21:22:23 +00002318#if !defined(CONFIG_USER_ONLY)
2319
2320#define MMUSUFFIX _cmmu
2321#define GETPC() NULL
2322#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002323#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002324
2325#define SHIFT 0
2326#include "softmmu_template.h"
2327
2328#define SHIFT 1
2329#include "softmmu_template.h"
2330
2331#define SHIFT 2
2332#include "softmmu_template.h"
2333
2334#define SHIFT 3
2335#include "softmmu_template.h"
2336
2337#undef env
2338
2339#endif