blob: 48cbe85749bc6e8e4a2943f7db877160032a7078 [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];
bellard92e873b2004-05-21 14:52:29 +0000113static PhysPageDesc *l1_phys_map[L1_SIZE];
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
bellard54936002003-05-13 00:25:15 +0000179}
180
bellardfd6ce8f2003-05-14 19:00:11 +0000181static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000182{
bellard54936002003-05-13 00:25:15 +0000183 PageDesc **lp, *p;
184
bellard54936002003-05-13 00:25:15 +0000185 lp = &l1_map[index >> L2_BITS];
186 p = *lp;
187 if (!p) {
188 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000189 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000190 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000191 *lp = p;
192 }
193 return p + (index & (L2_SIZE - 1));
194}
195
bellardfd6ce8f2003-05-14 19:00:11 +0000196static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000197{
bellard54936002003-05-13 00:25:15 +0000198 PageDesc *p;
199
bellard54936002003-05-13 00:25:15 +0000200 p = l1_map[index >> L2_BITS];
201 if (!p)
202 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000203 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000204}
205
bellard92e873b2004-05-21 14:52:29 +0000206static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
207{
208 PhysPageDesc **lp, *p;
209
210 lp = &l1_phys_map[index >> L2_BITS];
211 p = *lp;
212 if (!p) {
213 /* allocate if not found */
214 p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
215 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
216 *lp = p;
217 }
218 return p + (index & (L2_SIZE - 1));
219}
220
221static inline PhysPageDesc *phys_page_find(unsigned int index)
222{
223 PhysPageDesc *p;
224
225 p = l1_phys_map[index >> L2_BITS];
226 if (!p)
227 return 0;
228 return p + (index & (L2_SIZE - 1));
229}
230
bellard9fa3e852004-01-04 18:06:42 +0000231#if !defined(CONFIG_USER_ONLY)
bellard4f2ac232004-04-26 19:44:02 +0000232static void tlb_protect_code(CPUState *env, target_ulong addr);
233static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000234
bellard9fa3e852004-01-04 18:06:42 +0000235static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
236{
237 VirtPageDesc **lp, *p;
238
bellardc27004e2005-01-03 23:35:10 +0000239 /* XXX: should not truncate for 64 bit addresses */
240#if TARGET_LONG_BITS > 32
241 index &= (L1_SIZE - 1);
242#endif
bellard9fa3e852004-01-04 18:06:42 +0000243 lp = &l1_virt_map[index >> L2_BITS];
244 p = *lp;
245 if (!p) {
246 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000247 p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000248 memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
249 *lp = p;
250 }
251 return p + (index & (L2_SIZE - 1));
252}
253
254static inline VirtPageDesc *virt_page_find(unsigned int index)
255{
256 VirtPageDesc *p;
257
258 p = l1_virt_map[index >> L2_BITS];
bellardfd6ce8f2003-05-14 19:00:11 +0000259 if (!p)
260 return 0;
bellard9fa3e852004-01-04 18:06:42 +0000261 return p + (index & (L2_SIZE - 1));
bellardfd6ce8f2003-05-14 19:00:11 +0000262}
263
bellard9fa3e852004-01-04 18:06:42 +0000264static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000265{
bellard9fa3e852004-01-04 18:06:42 +0000266 int i, j;
267 VirtPageDesc *p;
268
269 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000270
bellard9fa3e852004-01-04 18:06:42 +0000271 if (virt_valid_tag == 0) {
272 virt_valid_tag = 1;
273 for(i = 0; i < L1_SIZE; i++) {
274 p = l1_virt_map[i];
275 if (p) {
276 for(j = 0; j < L2_SIZE; j++)
277 p[j].valid_tag = 0;
278 }
bellardfd6ce8f2003-05-14 19:00:11 +0000279 }
bellard54936002003-05-13 00:25:15 +0000280 }
281}
bellard9fa3e852004-01-04 18:06:42 +0000282#else
283static void virt_page_flush(void)
284{
285}
286#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000287
bellardb346ff42003-06-15 20:05:50 +0000288void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000289{
290 if (!code_gen_ptr) {
291 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000292 page_init();
bellard33417e72003-08-10 21:47:01 +0000293 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000294 }
295}
296
bellard9fa3e852004-01-04 18:06:42 +0000297static inline void invalidate_page_bitmap(PageDesc *p)
298{
299 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000300 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000301 p->code_bitmap = NULL;
302 }
303 p->code_write_count = 0;
304}
305
bellardfd6ce8f2003-05-14 19:00:11 +0000306/* set to NULL all the 'first_tb' fields in all PageDescs */
307static void page_flush_tb(void)
308{
309 int i, j;
310 PageDesc *p;
311
312 for(i = 0; i < L1_SIZE; i++) {
313 p = l1_map[i];
314 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000315 for(j = 0; j < L2_SIZE; j++) {
316 p->first_tb = NULL;
317 invalidate_page_bitmap(p);
318 p++;
319 }
bellardfd6ce8f2003-05-14 19:00:11 +0000320 }
321 }
322}
323
324/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000325/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000326void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000327{
bellard01243112004-01-04 15:48:17 +0000328#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000329 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
330 code_gen_ptr - code_gen_buffer,
331 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000332 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000333#endif
334 nb_tbs = 0;
bellard8a8a6082004-10-03 13:36:49 +0000335 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000336 virt_page_flush();
337
bellard8a8a6082004-10-03 13:36:49 +0000338 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000339 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000340
bellardfd6ce8f2003-05-14 19:00:11 +0000341 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000342 /* XXX: flush processor icache at this point if cache flush is
343 expensive */
bellarde3db7222005-01-26 22:00:47 +0000344 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000345}
346
347#ifdef DEBUG_TB_CHECK
348
349static void tb_invalidate_check(unsigned long address)
350{
351 TranslationBlock *tb;
352 int i;
353 address &= TARGET_PAGE_MASK;
354 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
355 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
356 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
357 address >= tb->pc + tb->size)) {
358 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
359 address, tb->pc, tb->size);
360 }
361 }
362 }
363}
364
365/* verify that all the pages have correct rights for code */
366static void tb_page_check(void)
367{
368 TranslationBlock *tb;
369 int i, flags1, flags2;
370
371 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
372 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
373 flags1 = page_get_flags(tb->pc);
374 flags2 = page_get_flags(tb->pc + tb->size - 1);
375 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
376 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
377 tb->pc, tb->size, flags1, flags2);
378 }
379 }
380 }
381}
382
bellardd4e81642003-05-25 16:46:15 +0000383void tb_jmp_check(TranslationBlock *tb)
384{
385 TranslationBlock *tb1;
386 unsigned int n1;
387
388 /* suppress any remaining jumps to this TB */
389 tb1 = tb->jmp_first;
390 for(;;) {
391 n1 = (long)tb1 & 3;
392 tb1 = (TranslationBlock *)((long)tb1 & ~3);
393 if (n1 == 2)
394 break;
395 tb1 = tb1->jmp_next[n1];
396 }
397 /* check end of list */
398 if (tb1 != tb) {
399 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
400 }
401}
402
bellardfd6ce8f2003-05-14 19:00:11 +0000403#endif
404
405/* invalidate one TB */
406static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
407 int next_offset)
408{
409 TranslationBlock *tb1;
410 for(;;) {
411 tb1 = *ptb;
412 if (tb1 == tb) {
413 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
414 break;
415 }
416 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
417 }
418}
419
bellard9fa3e852004-01-04 18:06:42 +0000420static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
421{
422 TranslationBlock *tb1;
423 unsigned int n1;
424
425 for(;;) {
426 tb1 = *ptb;
427 n1 = (long)tb1 & 3;
428 tb1 = (TranslationBlock *)((long)tb1 & ~3);
429 if (tb1 == tb) {
430 *ptb = tb1->page_next[n1];
431 break;
432 }
433 ptb = &tb1->page_next[n1];
434 }
435}
436
bellardd4e81642003-05-25 16:46:15 +0000437static inline void tb_jmp_remove(TranslationBlock *tb, int n)
438{
439 TranslationBlock *tb1, **ptb;
440 unsigned int n1;
441
442 ptb = &tb->jmp_next[n];
443 tb1 = *ptb;
444 if (tb1) {
445 /* find tb(n) in circular list */
446 for(;;) {
447 tb1 = *ptb;
448 n1 = (long)tb1 & 3;
449 tb1 = (TranslationBlock *)((long)tb1 & ~3);
450 if (n1 == n && tb1 == tb)
451 break;
452 if (n1 == 2) {
453 ptb = &tb1->jmp_first;
454 } else {
455 ptb = &tb1->jmp_next[n1];
456 }
457 }
458 /* now we can suppress tb(n) from the list */
459 *ptb = tb->jmp_next[n];
460
461 tb->jmp_next[n] = NULL;
462 }
463}
464
465/* reset the jump entry 'n' of a TB so that it is not chained to
466 another TB */
467static inline void tb_reset_jump(TranslationBlock *tb, int n)
468{
469 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
470}
471
bellard9fa3e852004-01-04 18:06:42 +0000472static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000473{
bellardd4e81642003-05-25 16:46:15 +0000474 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000475 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000476
bellard36bdbe52003-11-19 22:12:02 +0000477 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000478
bellardfd6ce8f2003-05-14 19:00:11 +0000479 /* remove the TB from the hash list */
480 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000481 ptb = &tb_hash[h];
482 for(;;) {
483 tb1 = *ptb;
484 /* NOTE: the TB is not necessarily linked in the hash. It
485 indicates that it is not currently used */
486 if (tb1 == NULL)
487 return;
488 if (tb1 == tb) {
489 *ptb = tb1->hash_next;
490 break;
491 }
492 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000493 }
bellardd4e81642003-05-25 16:46:15 +0000494
495 /* suppress this TB from the two jump lists */
496 tb_jmp_remove(tb, 0);
497 tb_jmp_remove(tb, 1);
498
499 /* suppress any remaining jumps to this TB */
500 tb1 = tb->jmp_first;
501 for(;;) {
502 n1 = (long)tb1 & 3;
503 if (n1 == 2)
504 break;
505 tb1 = (TranslationBlock *)((long)tb1 & ~3);
506 tb2 = tb1->jmp_next[n1];
507 tb_reset_jump(tb1, n1);
508 tb1->jmp_next[n1] = NULL;
509 tb1 = tb2;
510 }
511 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000512}
513
bellard9fa3e852004-01-04 18:06:42 +0000514static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000515{
bellardfd6ce8f2003-05-14 19:00:11 +0000516 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000517 unsigned int h;
518 target_ulong phys_pc;
519
520 /* remove the TB from the hash list */
521 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
522 h = tb_phys_hash_func(phys_pc);
523 tb_remove(&tb_phys_hash[h], tb,
524 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000525
bellard9fa3e852004-01-04 18:06:42 +0000526 /* remove the TB from the page list */
527 if (tb->page_addr[0] != page_addr) {
528 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
529 tb_page_remove(&p->first_tb, tb);
530 invalidate_page_bitmap(p);
531 }
532 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
533 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
534 tb_page_remove(&p->first_tb, tb);
535 invalidate_page_bitmap(p);
536 }
537
538 tb_invalidate(tb);
bellarde3db7222005-01-26 22:00:47 +0000539 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000540}
541
542static inline void set_bits(uint8_t *tab, int start, int len)
543{
544 int end, mask, end1;
545
546 end = start + len;
547 tab += start >> 3;
548 mask = 0xff << (start & 7);
549 if ((start & ~7) == (end & ~7)) {
550 if (start < end) {
551 mask &= ~(0xff << (end & 7));
552 *tab |= mask;
553 }
554 } else {
555 *tab++ |= mask;
556 start = (start + 8) & ~7;
557 end1 = end & ~7;
558 while (start < end1) {
559 *tab++ = 0xff;
560 start += 8;
561 }
562 if (start < end) {
563 mask = ~(0xff << (end & 7));
564 *tab |= mask;
565 }
566 }
567}
568
569static void build_page_bitmap(PageDesc *p)
570{
571 int n, tb_start, tb_end;
572 TranslationBlock *tb;
573
bellard59817cc2004-02-16 22:01:13 +0000574 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000575 if (!p->code_bitmap)
576 return;
577 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
578
579 tb = p->first_tb;
580 while (tb != NULL) {
581 n = (long)tb & 3;
582 tb = (TranslationBlock *)((long)tb & ~3);
583 /* NOTE: this is subtle as a TB may span two physical pages */
584 if (n == 0) {
585 /* NOTE: tb_end may be after the end of the page, but
586 it is not a problem */
587 tb_start = tb->pc & ~TARGET_PAGE_MASK;
588 tb_end = tb_start + tb->size;
589 if (tb_end > TARGET_PAGE_SIZE)
590 tb_end = TARGET_PAGE_SIZE;
591 } else {
592 tb_start = 0;
593 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
594 }
595 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
596 tb = tb->page_next[n];
597 }
598}
599
bellardd720b932004-04-25 17:57:43 +0000600#ifdef TARGET_HAS_PRECISE_SMC
601
602static void tb_gen_code(CPUState *env,
603 target_ulong pc, target_ulong cs_base, int flags,
604 int cflags)
605{
606 TranslationBlock *tb;
607 uint8_t *tc_ptr;
608 target_ulong phys_pc, phys_page2, virt_page2;
609 int code_gen_size;
610
bellardc27004e2005-01-03 23:35:10 +0000611 phys_pc = get_phys_addr_code(env, pc);
612 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000613 if (!tb) {
614 /* flush must be done */
615 tb_flush(env);
616 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000617 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000618 }
619 tc_ptr = code_gen_ptr;
620 tb->tc_ptr = tc_ptr;
621 tb->cs_base = cs_base;
622 tb->flags = flags;
623 tb->cflags = cflags;
624 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
625 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
626
627 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000628 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000629 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000630 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000631 phys_page2 = get_phys_addr_code(env, virt_page2);
632 }
633 tb_link_phys(tb, phys_pc, phys_page2);
634}
635#endif
636
bellard9fa3e852004-01-04 18:06:42 +0000637/* invalidate all TBs which intersect with the target physical page
638 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000639 the same physical page. 'is_cpu_write_access' should be true if called
640 from a real cpu write access: the virtual CPU will exit the current
641 TB if code is modified inside this TB. */
642void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
643 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000644{
bellardd720b932004-04-25 17:57:43 +0000645 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000646 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000647 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000648 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000649 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000650 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000651
652 p = page_find(start >> TARGET_PAGE_BITS);
653 if (!p)
654 return;
655 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000656 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
657 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000658 /* build code bitmap */
659 build_page_bitmap(p);
660 }
661
662 /* we remove all the TBs in the range [start, end[ */
663 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000664 current_tb_not_found = is_cpu_write_access;
665 current_tb_modified = 0;
666 current_tb = NULL; /* avoid warning */
667 current_pc = 0; /* avoid warning */
668 current_cs_base = 0; /* avoid warning */
669 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000670 tb = p->first_tb;
671 while (tb != NULL) {
672 n = (long)tb & 3;
673 tb = (TranslationBlock *)((long)tb & ~3);
674 tb_next = tb->page_next[n];
675 /* NOTE: this is subtle as a TB may span two physical pages */
676 if (n == 0) {
677 /* NOTE: tb_end may be after the end of the page, but
678 it is not a problem */
679 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
680 tb_end = tb_start + tb->size;
681 } else {
682 tb_start = tb->page_addr[1];
683 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
684 }
685 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000686#ifdef TARGET_HAS_PRECISE_SMC
687 if (current_tb_not_found) {
688 current_tb_not_found = 0;
689 current_tb = NULL;
690 if (env->mem_write_pc) {
691 /* now we have a real cpu fault */
692 current_tb = tb_find_pc(env->mem_write_pc);
693 }
694 }
695 if (current_tb == tb &&
696 !(current_tb->cflags & CF_SINGLE_INSN)) {
697 /* If we are modifying the current TB, we must stop
698 its execution. We could be more precise by checking
699 that the modification is after the current PC, but it
700 would require a specialized function to partially
701 restore the CPU state */
702
703 current_tb_modified = 1;
704 cpu_restore_state(current_tb, env,
705 env->mem_write_pc, NULL);
706#if defined(TARGET_I386)
707 current_flags = env->hflags;
708 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
709 current_cs_base = (target_ulong)env->segs[R_CS].base;
710 current_pc = current_cs_base + env->eip;
711#else
712#error unsupported CPU
713#endif
714 }
715#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000716 saved_tb = env->current_tb;
717 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000718 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000719 env->current_tb = saved_tb;
720 if (env->interrupt_request && env->current_tb)
721 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000722 }
723 tb = tb_next;
724 }
725#if !defined(CONFIG_USER_ONLY)
726 /* if no code remaining, no need to continue to use slow writes */
727 if (!p->first_tb) {
728 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000729 if (is_cpu_write_access) {
730 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
731 }
732 }
733#endif
734#ifdef TARGET_HAS_PRECISE_SMC
735 if (current_tb_modified) {
736 /* we generate a block containing just the instruction
737 modifying the memory. It will ensure that it cannot modify
738 itself */
bellardea1c1802004-06-14 18:56:36 +0000739 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000740 tb_gen_code(env, current_pc, current_cs_base, current_flags,
741 CF_SINGLE_INSN);
742 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000743 }
744#endif
745}
746
747/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000748static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000749{
750 PageDesc *p;
751 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000752#if 0
bellarda4193c82004-06-03 14:01:43 +0000753 if (1) {
754 if (loglevel) {
755 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
756 cpu_single_env->mem_write_vaddr, len,
757 cpu_single_env->eip,
758 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
759 }
bellard59817cc2004-02-16 22:01:13 +0000760 }
761#endif
bellard9fa3e852004-01-04 18:06:42 +0000762 p = page_find(start >> TARGET_PAGE_BITS);
763 if (!p)
764 return;
765 if (p->code_bitmap) {
766 offset = start & ~TARGET_PAGE_MASK;
767 b = p->code_bitmap[offset >> 3] >> (offset & 7);
768 if (b & ((1 << len) - 1))
769 goto do_invalidate;
770 } else {
771 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000772 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000773 }
774}
775
bellard9fa3e852004-01-04 18:06:42 +0000776#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000777static void tb_invalidate_phys_page(target_ulong addr,
778 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000779{
bellardd720b932004-04-25 17:57:43 +0000780 int n, current_flags, current_tb_modified;
781 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000782 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000783 TranslationBlock *tb, *current_tb;
784#ifdef TARGET_HAS_PRECISE_SMC
785 CPUState *env = cpu_single_env;
786#endif
bellard9fa3e852004-01-04 18:06:42 +0000787
788 addr &= TARGET_PAGE_MASK;
789 p = page_find(addr >> TARGET_PAGE_BITS);
790 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000791 return;
792 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000793 current_tb_modified = 0;
794 current_tb = NULL;
795 current_pc = 0; /* avoid warning */
796 current_cs_base = 0; /* avoid warning */
797 current_flags = 0; /* avoid warning */
798#ifdef TARGET_HAS_PRECISE_SMC
799 if (tb && pc != 0) {
800 current_tb = tb_find_pc(pc);
801 }
802#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000803 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000804 n = (long)tb & 3;
805 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000806#ifdef TARGET_HAS_PRECISE_SMC
807 if (current_tb == tb &&
808 !(current_tb->cflags & CF_SINGLE_INSN)) {
809 /* If we are modifying the current TB, we must stop
810 its execution. We could be more precise by checking
811 that the modification is after the current PC, but it
812 would require a specialized function to partially
813 restore the CPU state */
814
815 current_tb_modified = 1;
816 cpu_restore_state(current_tb, env, pc, puc);
817#if defined(TARGET_I386)
818 current_flags = env->hflags;
819 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
820 current_cs_base = (target_ulong)env->segs[R_CS].base;
821 current_pc = current_cs_base + env->eip;
822#else
823#error unsupported CPU
824#endif
825 }
826#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000827 tb_phys_invalidate(tb, addr);
828 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000829 }
830 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000831#ifdef TARGET_HAS_PRECISE_SMC
832 if (current_tb_modified) {
833 /* we generate a block containing just the instruction
834 modifying the memory. It will ensure that it cannot modify
835 itself */
bellardea1c1802004-06-14 18:56:36 +0000836 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000837 tb_gen_code(env, current_pc, current_cs_base, current_flags,
838 CF_SINGLE_INSN);
839 cpu_resume_from_signal(env, puc);
840 }
841#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000842}
bellard9fa3e852004-01-04 18:06:42 +0000843#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000844
845/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000846static inline void tb_alloc_page(TranslationBlock *tb,
847 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000848{
849 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000850 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000851
bellard9fa3e852004-01-04 18:06:42 +0000852 tb->page_addr[n] = page_addr;
853 p = page_find(page_addr >> TARGET_PAGE_BITS);
854 tb->page_next[n] = p->first_tb;
855 last_first_tb = p->first_tb;
856 p->first_tb = (TranslationBlock *)((long)tb | n);
857 invalidate_page_bitmap(p);
858
bellard107db442004-06-22 18:48:46 +0000859#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000860
bellard9fa3e852004-01-04 18:06:42 +0000861#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000862 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000863 unsigned long host_start, host_end, addr;
864 int prot;
865
bellardfd6ce8f2003-05-14 19:00:11 +0000866 /* force the host page as non writable (writes will have a
867 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000868 host_start = page_addr & qemu_host_page_mask;
869 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000870 prot = 0;
871 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
872 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000873 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000874 (prot & PAGE_BITS) & ~PAGE_WRITE);
875#ifdef DEBUG_TB_INVALIDATE
876 printf("protecting code page: 0x%08lx\n",
877 host_start);
878#endif
879 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000880 }
bellard9fa3e852004-01-04 18:06:42 +0000881#else
882 /* if some code is already present, then the pages are already
883 protected. So we handle the case where only the first TB is
884 allocated in a physical page */
885 if (!last_first_tb) {
886 target_ulong virt_addr;
887
888 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
889 tlb_protect_code(cpu_single_env, virt_addr);
890 }
891#endif
bellardd720b932004-04-25 17:57:43 +0000892
893#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000894}
895
896/* Allocate a new translation block. Flush the translation buffer if
897 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +0000898TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000899{
900 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000901
902 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
903 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000904 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000905 tb = &tbs[nb_tbs++];
906 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000907 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000908 return tb;
909}
910
bellard9fa3e852004-01-04 18:06:42 +0000911/* add a new TB and link it to the physical page tables. phys_page2 is
912 (-1) to indicate that only one page contains the TB. */
913void tb_link_phys(TranslationBlock *tb,
914 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000915{
bellard9fa3e852004-01-04 18:06:42 +0000916 unsigned int h;
917 TranslationBlock **ptb;
918
919 /* add in the physical hash table */
920 h = tb_phys_hash_func(phys_pc);
921 ptb = &tb_phys_hash[h];
922 tb->phys_hash_next = *ptb;
923 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000924
925 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000926 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
927 if (phys_page2 != -1)
928 tb_alloc_page(tb, 1, phys_page2);
929 else
930 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +0000931#ifdef DEBUG_TB_CHECK
932 tb_page_check();
933#endif
bellard9fa3e852004-01-04 18:06:42 +0000934}
935
936/* link the tb with the other TBs */
937void tb_link(TranslationBlock *tb)
938{
939#if !defined(CONFIG_USER_ONLY)
940 {
941 VirtPageDesc *vp;
942 target_ulong addr;
943
944 /* save the code memory mappings (needed to invalidate the code) */
945 addr = tb->pc & TARGET_PAGE_MASK;
946 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000947#ifdef DEBUG_TLB_CHECK
948 if (vp->valid_tag == virt_valid_tag &&
949 vp->phys_addr != tb->page_addr[0]) {
950 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
951 addr, tb->page_addr[0], vp->phys_addr);
952 }
953#endif
bellard9fa3e852004-01-04 18:06:42 +0000954 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +0000955 if (vp->valid_tag != virt_valid_tag) {
956 vp->valid_tag = virt_valid_tag;
957#if !defined(CONFIG_SOFTMMU)
958 vp->prot = 0;
959#endif
960 }
bellard9fa3e852004-01-04 18:06:42 +0000961
962 if (tb->page_addr[1] != -1) {
963 addr += TARGET_PAGE_SIZE;
964 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000965#ifdef DEBUG_TLB_CHECK
966 if (vp->valid_tag == virt_valid_tag &&
967 vp->phys_addr != tb->page_addr[1]) {
968 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
969 addr, tb->page_addr[1], vp->phys_addr);
970 }
971#endif
bellard9fa3e852004-01-04 18:06:42 +0000972 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +0000973 if (vp->valid_tag != virt_valid_tag) {
974 vp->valid_tag = virt_valid_tag;
975#if !defined(CONFIG_SOFTMMU)
976 vp->prot = 0;
977#endif
978 }
bellard9fa3e852004-01-04 18:06:42 +0000979 }
980 }
981#endif
982
bellardd4e81642003-05-25 16:46:15 +0000983 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
984 tb->jmp_next[0] = NULL;
985 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000986#ifdef USE_CODE_COPY
987 tb->cflags &= ~CF_FP_USED;
988 if (tb->cflags & CF_TB_FP_USED)
989 tb->cflags |= CF_FP_USED;
990#endif
bellardd4e81642003-05-25 16:46:15 +0000991
992 /* init original jump addresses */
993 if (tb->tb_next_offset[0] != 0xffff)
994 tb_reset_jump(tb, 0);
995 if (tb->tb_next_offset[1] != 0xffff)
996 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +0000997}
998
bellarda513fe12003-05-27 23:29:48 +0000999/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1000 tb[1].tc_ptr. Return NULL if not found */
1001TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1002{
1003 int m_min, m_max, m;
1004 unsigned long v;
1005 TranslationBlock *tb;
1006
1007 if (nb_tbs <= 0)
1008 return NULL;
1009 if (tc_ptr < (unsigned long)code_gen_buffer ||
1010 tc_ptr >= (unsigned long)code_gen_ptr)
1011 return NULL;
1012 /* binary search (cf Knuth) */
1013 m_min = 0;
1014 m_max = nb_tbs - 1;
1015 while (m_min <= m_max) {
1016 m = (m_min + m_max) >> 1;
1017 tb = &tbs[m];
1018 v = (unsigned long)tb->tc_ptr;
1019 if (v == tc_ptr)
1020 return tb;
1021 else if (tc_ptr < v) {
1022 m_max = m - 1;
1023 } else {
1024 m_min = m + 1;
1025 }
1026 }
1027 return &tbs[m_max];
1028}
bellard75012672003-06-21 13:11:07 +00001029
bellardea041c02003-06-25 16:16:50 +00001030static void tb_reset_jump_recursive(TranslationBlock *tb);
1031
1032static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1033{
1034 TranslationBlock *tb1, *tb_next, **ptb;
1035 unsigned int n1;
1036
1037 tb1 = tb->jmp_next[n];
1038 if (tb1 != NULL) {
1039 /* find head of list */
1040 for(;;) {
1041 n1 = (long)tb1 & 3;
1042 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1043 if (n1 == 2)
1044 break;
1045 tb1 = tb1->jmp_next[n1];
1046 }
1047 /* we are now sure now that tb jumps to tb1 */
1048 tb_next = tb1;
1049
1050 /* remove tb from the jmp_first list */
1051 ptb = &tb_next->jmp_first;
1052 for(;;) {
1053 tb1 = *ptb;
1054 n1 = (long)tb1 & 3;
1055 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1056 if (n1 == n && tb1 == tb)
1057 break;
1058 ptb = &tb1->jmp_next[n1];
1059 }
1060 *ptb = tb->jmp_next[n];
1061 tb->jmp_next[n] = NULL;
1062
1063 /* suppress the jump to next tb in generated code */
1064 tb_reset_jump(tb, n);
1065
bellard01243112004-01-04 15:48:17 +00001066 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001067 tb_reset_jump_recursive(tb_next);
1068 }
1069}
1070
1071static void tb_reset_jump_recursive(TranslationBlock *tb)
1072{
1073 tb_reset_jump_recursive2(tb, 0);
1074 tb_reset_jump_recursive2(tb, 1);
1075}
1076
bellardc27004e2005-01-03 23:35:10 +00001077#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellardd720b932004-04-25 17:57:43 +00001078static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1079{
1080 target_ulong phys_addr;
1081
1082 phys_addr = cpu_get_phys_page_debug(env, pc);
1083 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1084}
bellardc27004e2005-01-03 23:35:10 +00001085#endif
bellardd720b932004-04-25 17:57:43 +00001086
bellardc33a3462003-07-29 20:50:33 +00001087/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1088 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001089int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001090{
bellarde95c8d52004-09-30 22:22:08 +00001091#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001092 int i;
bellardd720b932004-04-25 17:57:43 +00001093
bellard4c3a88a2003-07-26 12:06:08 +00001094 for(i = 0; i < env->nb_breakpoints; i++) {
1095 if (env->breakpoints[i] == pc)
1096 return 0;
1097 }
1098
1099 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1100 return -1;
1101 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001102
1103 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001104 return 0;
1105#else
1106 return -1;
1107#endif
1108}
1109
1110/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001111int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001112{
bellarde95c8d52004-09-30 22:22:08 +00001113#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001114 int i;
1115 for(i = 0; i < env->nb_breakpoints; i++) {
1116 if (env->breakpoints[i] == pc)
1117 goto found;
1118 }
1119 return -1;
1120 found:
1121 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
1122 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
1123 env->nb_breakpoints--;
bellardd720b932004-04-25 17:57:43 +00001124
1125 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001126 return 0;
1127#else
1128 return -1;
1129#endif
1130}
1131
bellardc33a3462003-07-29 20:50:33 +00001132/* enable or disable single step mode. EXCP_DEBUG is returned by the
1133 CPU loop after each instruction */
1134void cpu_single_step(CPUState *env, int enabled)
1135{
bellarde95c8d52004-09-30 22:22:08 +00001136#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellardc33a3462003-07-29 20:50:33 +00001137 if (env->singlestep_enabled != enabled) {
1138 env->singlestep_enabled = enabled;
1139 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001140 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001141 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001142 }
1143#endif
1144}
1145
bellard34865132003-10-05 14:28:56 +00001146/* enable or disable low levels log */
1147void cpu_set_log(int log_flags)
1148{
1149 loglevel = log_flags;
1150 if (loglevel && !logfile) {
1151 logfile = fopen(logfilename, "w");
1152 if (!logfile) {
1153 perror(logfilename);
1154 _exit(1);
1155 }
bellard9fa3e852004-01-04 18:06:42 +00001156#if !defined(CONFIG_SOFTMMU)
1157 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1158 {
1159 static uint8_t logfile_buf[4096];
1160 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1161 }
1162#else
bellard34865132003-10-05 14:28:56 +00001163 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001164#endif
bellard34865132003-10-05 14:28:56 +00001165 }
1166}
1167
1168void cpu_set_log_filename(const char *filename)
1169{
1170 logfilename = strdup(filename);
1171}
bellardc33a3462003-07-29 20:50:33 +00001172
bellard01243112004-01-04 15:48:17 +00001173/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001174void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001175{
1176 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001177 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001178
bellard68a79312003-06-30 13:12:32 +00001179 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001180 /* if the cpu is currently executing code, we must unlink it and
1181 all the potentially executing TB */
1182 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001183 if (tb && !testandset(&interrupt_lock)) {
1184 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001185 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001186 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001187 }
1188}
1189
bellardb54ad042004-05-20 13:42:52 +00001190void cpu_reset_interrupt(CPUState *env, int mask)
1191{
1192 env->interrupt_request &= ~mask;
1193}
1194
bellardf193c792004-03-21 17:06:25 +00001195CPULogItem cpu_log_items[] = {
1196 { CPU_LOG_TB_OUT_ASM, "out_asm",
1197 "show generated host assembly code for each compiled TB" },
1198 { CPU_LOG_TB_IN_ASM, "in_asm",
1199 "show target assembly code for each compiled TB" },
1200 { CPU_LOG_TB_OP, "op",
1201 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1202#ifdef TARGET_I386
1203 { CPU_LOG_TB_OP_OPT, "op_opt",
1204 "show micro ops after optimization for each compiled TB" },
1205#endif
1206 { CPU_LOG_INT, "int",
1207 "show interrupts/exceptions in short format" },
1208 { CPU_LOG_EXEC, "exec",
1209 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001210 { CPU_LOG_TB_CPU, "cpu",
1211 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001212#ifdef TARGET_I386
1213 { CPU_LOG_PCALL, "pcall",
1214 "show protected mode far calls/returns/exceptions" },
1215#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001216#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001217 { CPU_LOG_IOPORT, "ioport",
1218 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001219#endif
bellardf193c792004-03-21 17:06:25 +00001220 { 0, NULL, NULL },
1221};
1222
1223static int cmp1(const char *s1, int n, const char *s2)
1224{
1225 if (strlen(s2) != n)
1226 return 0;
1227 return memcmp(s1, s2, n) == 0;
1228}
1229
1230/* takes a comma separated list of log masks. Return 0 if error. */
1231int cpu_str_to_log_mask(const char *str)
1232{
1233 CPULogItem *item;
1234 int mask;
1235 const char *p, *p1;
1236
1237 p = str;
1238 mask = 0;
1239 for(;;) {
1240 p1 = strchr(p, ',');
1241 if (!p1)
1242 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001243 if(cmp1(p,p1-p,"all")) {
1244 for(item = cpu_log_items; item->mask != 0; item++) {
1245 mask |= item->mask;
1246 }
1247 } else {
bellardf193c792004-03-21 17:06:25 +00001248 for(item = cpu_log_items; item->mask != 0; item++) {
1249 if (cmp1(p, p1 - p, item->name))
1250 goto found;
1251 }
1252 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001253 }
bellardf193c792004-03-21 17:06:25 +00001254 found:
1255 mask |= item->mask;
1256 if (*p1 != ',')
1257 break;
1258 p = p1 + 1;
1259 }
1260 return mask;
1261}
bellardea041c02003-06-25 16:16:50 +00001262
bellard75012672003-06-21 13:11:07 +00001263void cpu_abort(CPUState *env, const char *fmt, ...)
1264{
1265 va_list ap;
1266
1267 va_start(ap, fmt);
1268 fprintf(stderr, "qemu: fatal: ");
1269 vfprintf(stderr, fmt, ap);
1270 fprintf(stderr, "\n");
1271#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001272 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1273#else
1274 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001275#endif
1276 va_end(ap);
1277 abort();
1278}
1279
bellard01243112004-01-04 15:48:17 +00001280#if !defined(CONFIG_USER_ONLY)
1281
bellardee8b7022004-02-03 23:35:10 +00001282/* NOTE: if flush_global is true, also flush global entries (not
1283 implemented yet) */
1284void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001285{
bellard33417e72003-08-10 21:47:01 +00001286 int i;
bellard01243112004-01-04 15:48:17 +00001287
bellard9fa3e852004-01-04 18:06:42 +00001288#if defined(DEBUG_TLB)
1289 printf("tlb_flush:\n");
1290#endif
bellard01243112004-01-04 15:48:17 +00001291 /* must reset current TB so that interrupts cannot modify the
1292 links while we are modifying them */
1293 env->current_tb = NULL;
1294
bellard33417e72003-08-10 21:47:01 +00001295 for(i = 0; i < CPU_TLB_SIZE; i++) {
1296 env->tlb_read[0][i].address = -1;
1297 env->tlb_write[0][i].address = -1;
1298 env->tlb_read[1][i].address = -1;
1299 env->tlb_write[1][i].address = -1;
1300 }
bellard9fa3e852004-01-04 18:06:42 +00001301
1302 virt_page_flush();
bellard8a8a6082004-10-03 13:36:49 +00001303 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001304
1305#if !defined(CONFIG_SOFTMMU)
1306 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1307#endif
bellarde3db7222005-01-26 22:00:47 +00001308 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001309}
1310
bellard274da6b2004-05-20 21:56:27 +00001311static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001312{
1313 if (addr == (tlb_entry->address &
1314 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1315 tlb_entry->address = -1;
1316}
1317
bellard2e126692004-04-25 21:28:44 +00001318void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001319{
bellard9fa3e852004-01-04 18:06:42 +00001320 int i, n;
1321 VirtPageDesc *vp;
1322 PageDesc *p;
1323 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001324
bellard9fa3e852004-01-04 18:06:42 +00001325#if defined(DEBUG_TLB)
1326 printf("tlb_flush_page: 0x%08x\n", addr);
1327#endif
bellard01243112004-01-04 15:48:17 +00001328 /* must reset current TB so that interrupts cannot modify the
1329 links while we are modifying them */
1330 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001331
bellard61382a52003-10-27 21:22:23 +00001332 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001333 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001334 tlb_flush_entry(&env->tlb_read[0][i], addr);
1335 tlb_flush_entry(&env->tlb_write[0][i], addr);
1336 tlb_flush_entry(&env->tlb_read[1][i], addr);
1337 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001338
bellard9fa3e852004-01-04 18:06:42 +00001339 /* remove from the virtual pc hash table all the TB at this
1340 virtual address */
1341
1342 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1343 if (vp && vp->valid_tag == virt_valid_tag) {
1344 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1345 if (p) {
1346 /* we remove all the links to the TBs in this virtual page */
1347 tb = p->first_tb;
1348 while (tb != NULL) {
1349 n = (long)tb & 3;
1350 tb = (TranslationBlock *)((long)tb & ~3);
1351 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1352 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1353 tb_invalidate(tb);
1354 }
1355 tb = tb->page_next[n];
1356 }
1357 }
bellard98857882004-01-18 21:52:14 +00001358 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001359 }
1360
bellard01243112004-01-04 15:48:17 +00001361#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001362 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001363 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001364#endif
bellard9fa3e852004-01-04 18:06:42 +00001365}
1366
bellard4f2ac232004-04-26 19:44:02 +00001367static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001368{
1369 if (addr == (tlb_entry->address &
1370 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001371 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1372 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001373 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001374 }
bellard61382a52003-10-27 21:22:23 +00001375}
1376
bellard9fa3e852004-01-04 18:06:42 +00001377/* update the TLBs so that writes to code in the virtual page 'addr'
1378 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001379static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001380{
bellard61382a52003-10-27 21:22:23 +00001381 int i;
1382
1383 addr &= TARGET_PAGE_MASK;
1384 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001385 tlb_protect_code1(&env->tlb_write[0][i], addr);
1386 tlb_protect_code1(&env->tlb_write[1][i], addr);
1387#if !defined(CONFIG_SOFTMMU)
1388 /* NOTE: as we generated the code for this page, it is already at
1389 least readable */
1390 if (addr < MMAP_AREA_END)
1391 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1392#endif
1393}
1394
bellard9fa3e852004-01-04 18:06:42 +00001395static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001396 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001397{
1398 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1399 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001400 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001401 }
1402}
1403
1404/* update the TLB so that writes in physical page 'phys_addr' are no longer
1405 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001406static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001407{
1408 int i;
1409
1410 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001411 phys_addr += (long)phys_ram_base;
1412 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1413 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1414 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1415}
1416
1417static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1418 unsigned long start, unsigned long length)
1419{
1420 unsigned long addr;
1421 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1422 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1423 if ((addr - start) < length) {
1424 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1425 }
1426 }
1427}
1428
1429void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
1430{
1431 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001432 unsigned long length, start1;
bellard1ccde1c2004-02-06 19:46:14 +00001433 int i;
1434
1435 start &= TARGET_PAGE_MASK;
1436 end = TARGET_PAGE_ALIGN(end);
1437
1438 length = end - start;
1439 if (length == 0)
1440 return;
1441 memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
1442
1443 env = cpu_single_env;
1444 /* we modify the TLB cache so that the dirty bit will be set again
1445 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001446 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001447 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001448 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001449 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001450 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1451
1452#if !defined(CONFIG_SOFTMMU)
1453 /* XXX: this is expensive */
1454 {
1455 VirtPageDesc *p;
1456 int j;
1457 target_ulong addr;
1458
1459 for(i = 0; i < L1_SIZE; i++) {
1460 p = l1_virt_map[i];
1461 if (p) {
1462 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1463 for(j = 0; j < L2_SIZE; j++) {
1464 if (p->valid_tag == virt_valid_tag &&
1465 p->phys_addr >= start && p->phys_addr < end &&
1466 (p->prot & PROT_WRITE)) {
1467 if (addr < MMAP_AREA_END) {
1468 mprotect((void *)addr, TARGET_PAGE_SIZE,
1469 p->prot & ~PROT_WRITE);
1470 }
1471 }
1472 addr += TARGET_PAGE_SIZE;
1473 p++;
1474 }
1475 }
1476 }
1477 }
1478#endif
bellard1ccde1c2004-02-06 19:46:14 +00001479}
1480
1481static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1482 unsigned long start)
1483{
1484 unsigned long addr;
1485 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1486 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1487 if (addr == start) {
1488 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1489 }
1490 }
1491}
1492
1493/* update the TLB corresponding to virtual page vaddr and phys addr
1494 addr so that it is no longer dirty */
1495static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1496{
1497 CPUState *env = cpu_single_env;
1498 int i;
1499
1500 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
1501
1502 addr &= TARGET_PAGE_MASK;
1503 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1504 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1505 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001506}
1507
bellard59817cc2004-02-16 22:01:13 +00001508/* add a new TLB entry. At most one entry for a given virtual address
1509 is permitted. Return 0 if OK or 2 if the page could not be mapped
1510 (can only happen in non SOFTMMU mode for I/O pages or pages
1511 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001512int tlb_set_page(CPUState *env, target_ulong vaddr,
1513 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001514 int is_user, int is_softmmu)
1515{
bellard92e873b2004-05-21 14:52:29 +00001516 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001517 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001518 TranslationBlock *first_tb;
1519 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001520 target_ulong address;
1521 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001522 int ret;
1523
bellard92e873b2004-05-21 14:52:29 +00001524 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1525 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001526 if (!p) {
1527 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001528 } else {
bellard92e873b2004-05-21 14:52:29 +00001529 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001530 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001531 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1532 /* NOTE: we also allocate the page at this stage */
1533 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1534 first_tb = p1->first_tb;
1535 }
bellard9fa3e852004-01-04 18:06:42 +00001536 }
1537#if defined(DEBUG_TLB)
1538 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1539 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1540#endif
1541
1542 ret = 0;
1543#if !defined(CONFIG_SOFTMMU)
1544 if (is_softmmu)
1545#endif
1546 {
1547 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1548 /* IO memory case */
1549 address = vaddr | pd;
1550 addend = paddr;
1551 } else {
1552 /* standard memory */
1553 address = vaddr;
1554 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1555 }
1556
1557 index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1558 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001559 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001560 env->tlb_read[is_user][index].address = address;
1561 env->tlb_read[is_user][index].addend = addend;
1562 } else {
1563 env->tlb_read[is_user][index].address = -1;
1564 env->tlb_read[is_user][index].addend = -1;
1565 }
bellard67b915a2004-03-31 23:37:16 +00001566 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001567 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1568 /* ROM: access is ignored (same as unassigned) */
1569 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001570 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001571 } else
1572 /* XXX: the PowerPC code seems not ready to handle
1573 self modifying code with DCBI */
1574#if defined(TARGET_HAS_SMC) || 1
1575 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001576 /* if code is present, we use a specific memory
1577 handler. It works only for physical memory access */
1578 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001579 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001580 } else
1581#endif
1582 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001583 !cpu_physical_memory_is_dirty(pd)) {
1584 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1585 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001586 } else {
1587 env->tlb_write[is_user][index].address = address;
1588 env->tlb_write[is_user][index].addend = addend;
1589 }
1590 } else {
1591 env->tlb_write[is_user][index].address = -1;
1592 env->tlb_write[is_user][index].addend = -1;
1593 }
1594 }
1595#if !defined(CONFIG_SOFTMMU)
1596 else {
1597 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1598 /* IO access: no mapping is done as it will be handled by the
1599 soft MMU */
1600 if (!(env->hflags & HF_SOFTMMU_MASK))
1601 ret = 2;
1602 } else {
1603 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001604
bellard59817cc2004-02-16 22:01:13 +00001605 if (vaddr >= MMAP_AREA_END) {
1606 ret = 2;
1607 } else {
1608 if (prot & PROT_WRITE) {
1609 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001610#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001611 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001612#endif
bellard59817cc2004-02-16 22:01:13 +00001613 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1614 !cpu_physical_memory_is_dirty(pd))) {
1615 /* ROM: we do as if code was inside */
1616 /* if code is present, we only map as read only and save the
1617 original mapping */
1618 VirtPageDesc *vp;
1619
1620 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1621 vp->phys_addr = pd;
1622 vp->prot = prot;
1623 vp->valid_tag = virt_valid_tag;
1624 prot &= ~PAGE_WRITE;
1625 }
bellard9fa3e852004-01-04 18:06:42 +00001626 }
bellard59817cc2004-02-16 22:01:13 +00001627 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1628 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1629 if (map_addr == MAP_FAILED) {
1630 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1631 paddr, vaddr);
1632 }
bellard9fa3e852004-01-04 18:06:42 +00001633 }
1634 }
1635 }
1636#endif
1637 return ret;
1638}
1639
1640/* called from signal handler: invalidate the code and unprotect the
1641 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001642int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001643{
1644#if !defined(CONFIG_SOFTMMU)
1645 VirtPageDesc *vp;
1646
1647#if defined(DEBUG_TLB)
1648 printf("page_unprotect: addr=0x%08x\n", addr);
1649#endif
1650 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001651
1652 /* if it is not mapped, no need to worry here */
1653 if (addr >= MMAP_AREA_END)
1654 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001655 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1656 if (!vp)
1657 return 0;
1658 /* NOTE: in this case, validate_tag is _not_ tested as it
1659 validates only the code TLB */
1660 if (vp->valid_tag != virt_valid_tag)
1661 return 0;
1662 if (!(vp->prot & PAGE_WRITE))
1663 return 0;
1664#if defined(DEBUG_TLB)
1665 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1666 addr, vp->phys_addr, vp->prot);
1667#endif
bellard59817cc2004-02-16 22:01:13 +00001668 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1669 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1670 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001671 /* set the dirty bit */
1672 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1673 /* flush the code inside */
1674 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001675 return 1;
1676#else
1677 return 0;
1678#endif
bellard33417e72003-08-10 21:47:01 +00001679}
1680
bellard01243112004-01-04 15:48:17 +00001681#else
1682
bellardee8b7022004-02-03 23:35:10 +00001683void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001684{
1685}
1686
bellard2e126692004-04-25 21:28:44 +00001687void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001688{
1689}
1690
bellard2e126692004-04-25 21:28:44 +00001691int tlb_set_page(CPUState *env, target_ulong vaddr,
1692 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001693 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001694{
bellard9fa3e852004-01-04 18:06:42 +00001695 return 0;
1696}
bellard33417e72003-08-10 21:47:01 +00001697
bellard9fa3e852004-01-04 18:06:42 +00001698/* dump memory mappings */
1699void page_dump(FILE *f)
1700{
1701 unsigned long start, end;
1702 int i, j, prot, prot1;
1703 PageDesc *p;
1704
1705 fprintf(f, "%-8s %-8s %-8s %s\n",
1706 "start", "end", "size", "prot");
1707 start = -1;
1708 end = -1;
1709 prot = 0;
1710 for(i = 0; i <= L1_SIZE; i++) {
1711 if (i < L1_SIZE)
1712 p = l1_map[i];
1713 else
1714 p = NULL;
1715 for(j = 0;j < L2_SIZE; j++) {
1716 if (!p)
1717 prot1 = 0;
1718 else
1719 prot1 = p[j].flags;
1720 if (prot1 != prot) {
1721 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1722 if (start != -1) {
1723 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1724 start, end, end - start,
1725 prot & PAGE_READ ? 'r' : '-',
1726 prot & PAGE_WRITE ? 'w' : '-',
1727 prot & PAGE_EXEC ? 'x' : '-');
1728 }
1729 if (prot1 != 0)
1730 start = end;
1731 else
1732 start = -1;
1733 prot = prot1;
1734 }
1735 if (!p)
1736 break;
1737 }
bellard33417e72003-08-10 21:47:01 +00001738 }
bellard33417e72003-08-10 21:47:01 +00001739}
1740
bellard9fa3e852004-01-04 18:06:42 +00001741int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001742{
bellard9fa3e852004-01-04 18:06:42 +00001743 PageDesc *p;
1744
1745 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001746 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001747 return 0;
1748 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001749}
1750
bellard9fa3e852004-01-04 18:06:42 +00001751/* modify the flags of a page and invalidate the code if
1752 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1753 depending on PAGE_WRITE */
1754void page_set_flags(unsigned long start, unsigned long end, int flags)
1755{
1756 PageDesc *p;
1757 unsigned long addr;
1758
1759 start = start & TARGET_PAGE_MASK;
1760 end = TARGET_PAGE_ALIGN(end);
1761 if (flags & PAGE_WRITE)
1762 flags |= PAGE_WRITE_ORG;
1763 spin_lock(&tb_lock);
1764 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1765 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1766 /* if the write protection is set, then we invalidate the code
1767 inside */
1768 if (!(p->flags & PAGE_WRITE) &&
1769 (flags & PAGE_WRITE) &&
1770 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001771 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001772 }
1773 p->flags = flags;
1774 }
1775 spin_unlock(&tb_lock);
1776}
1777
1778/* called from signal handler: invalidate the code and unprotect the
1779 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001780int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001781{
1782 unsigned int page_index, prot, pindex;
1783 PageDesc *p, *p1;
1784 unsigned long host_start, host_end, addr;
1785
bellard83fb7ad2004-07-05 21:25:26 +00001786 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001787 page_index = host_start >> TARGET_PAGE_BITS;
1788 p1 = page_find(page_index);
1789 if (!p1)
1790 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001791 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001792 p = p1;
1793 prot = 0;
1794 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1795 prot |= p->flags;
1796 p++;
1797 }
1798 /* if the page was really writable, then we change its
1799 protection back to writable */
1800 if (prot & PAGE_WRITE_ORG) {
1801 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1802 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001803 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001804 (prot & PAGE_BITS) | PAGE_WRITE);
1805 p1[pindex].flags |= PAGE_WRITE;
1806 /* and since the content will be modified, we must invalidate
1807 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001808 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001809#ifdef DEBUG_TB_CHECK
1810 tb_invalidate_check(address);
1811#endif
1812 return 1;
1813 }
1814 }
1815 return 0;
1816}
1817
1818/* call this function when system calls directly modify a memory area */
1819void page_unprotect_range(uint8_t *data, unsigned long data_size)
1820{
1821 unsigned long start, end, addr;
1822
1823 start = (unsigned long)data;
1824 end = start + data_size;
1825 start &= TARGET_PAGE_MASK;
1826 end = TARGET_PAGE_ALIGN(end);
1827 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001828 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001829 }
1830}
1831
bellard1ccde1c2004-02-06 19:46:14 +00001832static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1833{
1834}
bellard9fa3e852004-01-04 18:06:42 +00001835#endif /* defined(CONFIG_USER_ONLY) */
1836
bellard33417e72003-08-10 21:47:01 +00001837/* register physical memory. 'size' must be a multiple of the target
1838 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1839 io memory page */
bellard2e126692004-04-25 21:28:44 +00001840void cpu_register_physical_memory(target_phys_addr_t start_addr,
1841 unsigned long size,
1842 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001843{
1844 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001845 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001846
bellard5fd386f2004-05-23 21:11:22 +00001847 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001848 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001849 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001850 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001851 p->phys_offset = phys_offset;
1852 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001853 phys_offset += TARGET_PAGE_SIZE;
1854 }
1855}
1856
bellarda4193c82004-06-03 14:01:43 +00001857static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001858{
1859 return 0;
1860}
1861
bellarda4193c82004-06-03 14:01:43 +00001862static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001863{
1864}
1865
1866static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1867 unassigned_mem_readb,
1868 unassigned_mem_readb,
1869 unassigned_mem_readb,
1870};
1871
1872static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1873 unassigned_mem_writeb,
1874 unassigned_mem_writeb,
1875 unassigned_mem_writeb,
1876};
1877
bellard9fa3e852004-01-04 18:06:42 +00001878/* self modifying code support in soft mmu mode : writing to a page
1879 containing code comes to these functions */
1880
bellarda4193c82004-06-03 14:01:43 +00001881static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001882{
bellard1ccde1c2004-02-06 19:46:14 +00001883 unsigned long phys_addr;
1884
bellard274da6b2004-05-20 21:56:27 +00001885 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001886#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001887 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001888#endif
bellardc27004e2005-01-03 23:35:10 +00001889 stb_p((uint8_t *)(long)addr, val);
bellard1ccde1c2004-02-06 19:46:14 +00001890 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001891}
1892
bellarda4193c82004-06-03 14:01:43 +00001893static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001894{
bellard1ccde1c2004-02-06 19:46:14 +00001895 unsigned long phys_addr;
1896
bellard274da6b2004-05-20 21:56:27 +00001897 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001898#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001899 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001900#endif
bellardc27004e2005-01-03 23:35:10 +00001901 stw_p((uint8_t *)(long)addr, val);
bellard1ccde1c2004-02-06 19:46:14 +00001902 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001903}
1904
bellarda4193c82004-06-03 14:01:43 +00001905static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001906{
bellard1ccde1c2004-02-06 19:46:14 +00001907 unsigned long phys_addr;
1908
bellard274da6b2004-05-20 21:56:27 +00001909 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001910#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001911 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00001912#endif
bellardc27004e2005-01-03 23:35:10 +00001913 stl_p((uint8_t *)(long)addr, val);
bellard1ccde1c2004-02-06 19:46:14 +00001914 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001915}
1916
1917static CPUReadMemoryFunc *code_mem_read[3] = {
1918 NULL, /* never used */
1919 NULL, /* never used */
1920 NULL, /* never used */
1921};
1922
1923static CPUWriteMemoryFunc *code_mem_write[3] = {
1924 code_mem_writeb,
1925 code_mem_writew,
1926 code_mem_writel,
1927};
bellard33417e72003-08-10 21:47:01 +00001928
bellarda4193c82004-06-03 14:01:43 +00001929static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001930{
bellardc27004e2005-01-03 23:35:10 +00001931 stb_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001932 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001933}
1934
bellarda4193c82004-06-03 14:01:43 +00001935static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001936{
bellardc27004e2005-01-03 23:35:10 +00001937 stw_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001938 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001939}
1940
bellarda4193c82004-06-03 14:01:43 +00001941static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001942{
bellardc27004e2005-01-03 23:35:10 +00001943 stl_p((uint8_t *)(long)addr, val);
bellardd720b932004-04-25 17:57:43 +00001944 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001945}
1946
1947static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1948 notdirty_mem_writeb,
1949 notdirty_mem_writew,
1950 notdirty_mem_writel,
1951};
1952
bellard33417e72003-08-10 21:47:01 +00001953static void io_mem_init(void)
1954{
bellarda4193c82004-06-03 14:01:43 +00001955 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1956 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1957 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1958 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001959 io_mem_nb = 5;
1960
1961 /* alloc dirty bits array */
bellard59817cc2004-02-16 22:01:13 +00001962 phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001963}
1964
1965/* mem_read and mem_write are arrays of functions containing the
1966 function to access byte (index 0), word (index 1) and dword (index
1967 2). All functions must be supplied. If io_index is non zero, the
1968 corresponding io zone is modified. If it is zero, a new io zone is
1969 allocated. The return value can be used with
1970 cpu_register_physical_memory(). (-1) is returned if error. */
1971int cpu_register_io_memory(int io_index,
1972 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001973 CPUWriteMemoryFunc **mem_write,
1974 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001975{
1976 int i;
1977
1978 if (io_index <= 0) {
1979 if (io_index >= IO_MEM_NB_ENTRIES)
1980 return -1;
1981 io_index = io_mem_nb++;
1982 } else {
1983 if (io_index >= IO_MEM_NB_ENTRIES)
1984 return -1;
1985 }
1986
1987 for(i = 0;i < 3; i++) {
1988 io_mem_read[io_index][i] = mem_read[i];
1989 io_mem_write[io_index][i] = mem_write[i];
1990 }
bellarda4193c82004-06-03 14:01:43 +00001991 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001992 return io_index << IO_MEM_SHIFT;
1993}
bellard61382a52003-10-27 21:22:23 +00001994
bellard8926b512004-10-10 15:14:20 +00001995CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
1996{
1997 return io_mem_write[io_index >> IO_MEM_SHIFT];
1998}
1999
2000CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2001{
2002 return io_mem_read[io_index >> IO_MEM_SHIFT];
2003}
2004
bellard13eb76e2004-01-24 15:23:36 +00002005/* physical memory access (slow version, mainly for debug) */
2006#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00002007void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002008 int len, int is_write)
2009{
2010 int l, flags;
2011 target_ulong page;
2012
2013 while (len > 0) {
2014 page = addr & TARGET_PAGE_MASK;
2015 l = (page + TARGET_PAGE_SIZE) - addr;
2016 if (l > len)
2017 l = len;
2018 flags = page_get_flags(page);
2019 if (!(flags & PAGE_VALID))
2020 return;
2021 if (is_write) {
2022 if (!(flags & PAGE_WRITE))
2023 return;
2024 memcpy((uint8_t *)addr, buf, len);
2025 } else {
2026 if (!(flags & PAGE_READ))
2027 return;
2028 memcpy(buf, (uint8_t *)addr, len);
2029 }
2030 len -= l;
2031 buf += l;
2032 addr += l;
2033 }
2034}
bellard8df1cd02005-01-28 22:37:22 +00002035
2036/* never used */
2037uint32_t ldl_phys(target_phys_addr_t addr)
2038{
2039 return 0;
2040}
2041
2042void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2043{
2044}
2045
2046void stl_phys(target_phys_addr_t addr, uint32_t val)
2047{
2048}
2049
bellard13eb76e2004-01-24 15:23:36 +00002050#else
bellard2e126692004-04-25 21:28:44 +00002051void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002052 int len, int is_write)
2053{
2054 int l, io_index;
2055 uint8_t *ptr;
2056 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002057 target_phys_addr_t page;
2058 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002059 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002060
2061 while (len > 0) {
2062 page = addr & TARGET_PAGE_MASK;
2063 l = (page + TARGET_PAGE_SIZE) - addr;
2064 if (l > len)
2065 l = len;
bellard92e873b2004-05-21 14:52:29 +00002066 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002067 if (!p) {
2068 pd = IO_MEM_UNASSIGNED;
2069 } else {
2070 pd = p->phys_offset;
2071 }
2072
2073 if (is_write) {
2074 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2075 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2076 if (l >= 4 && ((addr & 3) == 0)) {
2077 /* 32 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002078 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002079 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002080 l = 4;
2081 } else if (l >= 2 && ((addr & 1) == 0)) {
2082 /* 16 bit read access */
bellardc27004e2005-01-03 23:35:10 +00002083 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002084 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002085 l = 2;
2086 } else {
2087 /* 8 bit access */
bellardc27004e2005-01-03 23:35:10 +00002088 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002089 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002090 l = 1;
2091 }
2092 } else {
bellardb448f2f2004-02-25 23:24:04 +00002093 unsigned long addr1;
2094 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002095 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002096 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002097 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002098 /* invalidate code */
2099 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2100 /* set dirty bit */
bellard54163762005-01-27 23:58:13 +00002101 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1;
bellard13eb76e2004-01-24 15:23:36 +00002102 }
2103 } else {
2104 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2105 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2106 /* I/O case */
2107 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2108 if (l >= 4 && ((addr & 3) == 0)) {
2109 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002110 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002111 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002112 l = 4;
2113 } else if (l >= 2 && ((addr & 1) == 0)) {
2114 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002115 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002116 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002117 l = 2;
2118 } else {
2119 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002120 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002121 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002122 l = 1;
2123 }
2124 } else {
2125 /* RAM case */
2126 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2127 (addr & ~TARGET_PAGE_MASK);
2128 memcpy(buf, ptr, l);
2129 }
2130 }
2131 len -= l;
2132 buf += l;
2133 addr += l;
2134 }
2135}
bellard8df1cd02005-01-28 22:37:22 +00002136
2137/* warning: addr must be aligned */
2138uint32_t ldl_phys(target_phys_addr_t addr)
2139{
2140 int io_index;
2141 uint8_t *ptr;
2142 uint32_t val;
2143 unsigned long pd;
2144 PhysPageDesc *p;
2145
2146 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2147 if (!p) {
2148 pd = IO_MEM_UNASSIGNED;
2149 } else {
2150 pd = p->phys_offset;
2151 }
2152
2153 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2154 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2155 /* I/O case */
2156 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2157 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2158 } else {
2159 /* RAM case */
2160 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2161 (addr & ~TARGET_PAGE_MASK);
2162 val = ldl_p(ptr);
2163 }
2164 return val;
2165}
2166
2167/* warning: addr must be aligned. The ram page is not masked as dirty
2168 and the code inside is not invalidated. It is useful if the dirty
2169 bits are used to track modified PTEs */
2170void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2171{
2172 int io_index;
2173 uint8_t *ptr;
2174 unsigned long pd;
2175 PhysPageDesc *p;
2176
2177 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2178 if (!p) {
2179 pd = IO_MEM_UNASSIGNED;
2180 } else {
2181 pd = p->phys_offset;
2182 }
2183
2184 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2185 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2186 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2187 } else {
2188 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2189 (addr & ~TARGET_PAGE_MASK);
2190 stl_p(ptr, val);
2191 }
2192}
2193
2194/* warning: addr must be aligned */
2195/* XXX: optimize code invalidation test */
2196void stl_phys(target_phys_addr_t addr, uint32_t val)
2197{
2198 int io_index;
2199 uint8_t *ptr;
2200 unsigned long pd;
2201 PhysPageDesc *p;
2202
2203 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2204 if (!p) {
2205 pd = IO_MEM_UNASSIGNED;
2206 } else {
2207 pd = p->phys_offset;
2208 }
2209
2210 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2211 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2212 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2213 } else {
2214 unsigned long addr1;
2215 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2216 /* RAM case */
2217 ptr = phys_ram_base + addr1;
2218 stl_p(ptr, val);
2219 /* invalidate code */
2220 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2221 /* set dirty bit */
2222 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1;
2223 }
2224}
2225
bellard13eb76e2004-01-24 15:23:36 +00002226#endif
2227
2228/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002229int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2230 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002231{
2232 int l;
2233 target_ulong page, phys_addr;
2234
2235 while (len > 0) {
2236 page = addr & TARGET_PAGE_MASK;
2237 phys_addr = cpu_get_phys_page_debug(env, page);
2238 /* if no physical page mapped, return an error */
2239 if (phys_addr == -1)
2240 return -1;
2241 l = (page + TARGET_PAGE_SIZE) - addr;
2242 if (l > len)
2243 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002244 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2245 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002246 len -= l;
2247 buf += l;
2248 addr += l;
2249 }
2250 return 0;
2251}
2252
bellarde3db7222005-01-26 22:00:47 +00002253void dump_exec_info(FILE *f,
2254 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2255{
2256 int i, target_code_size, max_target_code_size;
2257 int direct_jmp_count, direct_jmp2_count, cross_page;
2258 TranslationBlock *tb;
2259
2260 target_code_size = 0;
2261 max_target_code_size = 0;
2262 cross_page = 0;
2263 direct_jmp_count = 0;
2264 direct_jmp2_count = 0;
2265 for(i = 0; i < nb_tbs; i++) {
2266 tb = &tbs[i];
2267 target_code_size += tb->size;
2268 if (tb->size > max_target_code_size)
2269 max_target_code_size = tb->size;
2270 if (tb->page_addr[1] != -1)
2271 cross_page++;
2272 if (tb->tb_next_offset[0] != 0xffff) {
2273 direct_jmp_count++;
2274 if (tb->tb_next_offset[1] != 0xffff) {
2275 direct_jmp2_count++;
2276 }
2277 }
2278 }
2279 /* XXX: avoid using doubles ? */
2280 cpu_fprintf(f, "TB count %d\n", nb_tbs);
2281 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
2282 nb_tbs ? target_code_size / nb_tbs : 0,
2283 max_target_code_size);
2284 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
2285 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2286 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2287 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2288 cross_page,
2289 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2290 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
2291 direct_jmp_count,
2292 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2293 direct_jmp2_count,
2294 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2295 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
2296 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2297 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
2298}
2299
bellard61382a52003-10-27 21:22:23 +00002300#if !defined(CONFIG_USER_ONLY)
2301
2302#define MMUSUFFIX _cmmu
2303#define GETPC() NULL
2304#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002305#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002306
2307#define SHIFT 0
2308#include "softmmu_template.h"
2309
2310#define SHIFT 1
2311#include "softmmu_template.h"
2312
2313#define SHIFT 2
2314#include "softmmu_template.h"
2315
2316#define SHIFT 3
2317#include "softmmu_template.h"
2318
2319#undef env
2320
2321#endif