blob: 0dc8d15952bab819c92b103cfe142d7f5f6b686d [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
24#include <sys/mman.h>
25#endif
bellard54936002003-05-13 00:25:15 +000026#include <stdlib.h>
27#include <stdio.h>
28#include <stdarg.h>
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <inttypes.h>
33
bellard6180a182003-09-30 21:04:53 +000034#include "cpu.h"
35#include "exec-all.h"
bellard54936002003-05-13 00:25:15 +000036
bellardfd6ce8f2003-05-14 19:00:11 +000037//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000038//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000039//#define DEBUG_TLB
bellardfd6ce8f2003-05-14 19:00:11 +000040
41/* make various TB consistency checks */
42//#define DEBUG_TB_CHECK
bellard98857882004-01-18 21:52:14 +000043//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000044
45/* threshold to flush the translated code buffer */
46#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
47
bellard9fa3e852004-01-04 18:06:42 +000048#define SMC_BITMAP_USE_THRESHOLD 10
49
50#define MMAP_AREA_START 0x00000000
51#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000052
53TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
54TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
bellard9fa3e852004-01-04 18:06:42 +000055TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000056int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000057/* any access to the tbs or the page table must use this lock */
58spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000059
60uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
61uint8_t *code_gen_ptr;
62
bellard9fa3e852004-01-04 18:06:42 +000063int phys_ram_size;
64int phys_ram_fd;
65uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +000066uint8_t *phys_ram_dirty;
bellard9fa3e852004-01-04 18:06:42 +000067
bellard54936002003-05-13 00:25:15 +000068typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +000069 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +000070 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +000071 /* in order to optimize self modifying code, we count the number
72 of lookups we do to a given page to use a bitmap */
73 unsigned int code_write_count;
74 uint8_t *code_bitmap;
75#if defined(CONFIG_USER_ONLY)
76 unsigned long flags;
77#endif
bellard54936002003-05-13 00:25:15 +000078} PageDesc;
79
bellard92e873b2004-05-21 14:52:29 +000080typedef struct PhysPageDesc {
81 /* offset in host memory of the page + io_index in the low 12 bits */
82 unsigned long phys_offset;
83} PhysPageDesc;
84
bellard9fa3e852004-01-04 18:06:42 +000085typedef struct VirtPageDesc {
86 /* physical address of code page. It is valid only if 'valid_tag'
87 matches 'virt_valid_tag' */
88 target_ulong phys_addr;
89 unsigned int valid_tag;
90#if !defined(CONFIG_SOFTMMU)
91 /* original page access rights. It is valid only if 'valid_tag'
92 matches 'virt_valid_tag' */
93 unsigned int prot;
94#endif
95} VirtPageDesc;
96
bellard54936002003-05-13 00:25:15 +000097#define L2_BITS 10
98#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
99
100#define L1_SIZE (1 << L1_BITS)
101#define L2_SIZE (1 << L2_BITS)
102
bellard33417e72003-08-10 21:47:01 +0000103static void io_mem_init(void);
bellardfd6ce8f2003-05-14 19:00:11 +0000104
bellard83fb7ad2004-07-05 21:25:26 +0000105unsigned long qemu_real_host_page_size;
106unsigned long qemu_host_page_bits;
107unsigned long qemu_host_page_size;
108unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000109
bellard92e873b2004-05-21 14:52:29 +0000110/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000111static PageDesc *l1_map[L1_SIZE];
bellard92e873b2004-05-21 14:52:29 +0000112static PhysPageDesc *l1_phys_map[L1_SIZE];
bellard54936002003-05-13 00:25:15 +0000113
bellard9fa3e852004-01-04 18:06:42 +0000114#if !defined(CONFIG_USER_ONLY)
115static VirtPageDesc *l1_virt_map[L1_SIZE];
116static unsigned int virt_valid_tag;
117#endif
118
bellard33417e72003-08-10 21:47:01 +0000119/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000120CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
121CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000122void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000123static int io_mem_nb;
124
bellard34865132003-10-05 14:28:56 +0000125/* log support */
126char *logfilename = "/tmp/qemu.log";
127FILE *logfile;
128int loglevel;
129
bellardb346ff42003-06-15 20:05:50 +0000130static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000131{
bellard83fb7ad2004-07-05 21:25:26 +0000132 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000133 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000134#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000135 {
136 SYSTEM_INFO system_info;
137 DWORD old_protect;
138
139 GetSystemInfo(&system_info);
140 qemu_real_host_page_size = system_info.dwPageSize;
141
142 VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
143 PAGE_EXECUTE_READWRITE, &old_protect);
144 }
bellard67b915a2004-03-31 23:37:16 +0000145#else
bellard83fb7ad2004-07-05 21:25:26 +0000146 qemu_real_host_page_size = getpagesize();
bellardd5a8f072004-09-29 21:15:28 +0000147 {
148 unsigned long start, end;
149
150 start = (unsigned long)code_gen_buffer;
151 start &= ~(qemu_real_host_page_size - 1);
152
153 end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
154 end += qemu_real_host_page_size - 1;
155 end &= ~(qemu_real_host_page_size - 1);
156
157 mprotect((void *)start, end - start,
158 PROT_READ | PROT_WRITE | PROT_EXEC);
159 }
bellard67b915a2004-03-31 23:37:16 +0000160#endif
bellardd5a8f072004-09-29 21:15:28 +0000161
bellard83fb7ad2004-07-05 21:25:26 +0000162 if (qemu_host_page_size == 0)
163 qemu_host_page_size = qemu_real_host_page_size;
164 if (qemu_host_page_size < TARGET_PAGE_SIZE)
165 qemu_host_page_size = TARGET_PAGE_SIZE;
166 qemu_host_page_bits = 0;
167 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
168 qemu_host_page_bits++;
169 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard9fa3e852004-01-04 18:06:42 +0000170#if !defined(CONFIG_USER_ONLY)
171 virt_valid_tag = 1;
172#endif
bellard54936002003-05-13 00:25:15 +0000173}
174
bellardfd6ce8f2003-05-14 19:00:11 +0000175static inline PageDesc *page_find_alloc(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000176{
bellard54936002003-05-13 00:25:15 +0000177 PageDesc **lp, *p;
178
bellard54936002003-05-13 00:25:15 +0000179 lp = &l1_map[index >> L2_BITS];
180 p = *lp;
181 if (!p) {
182 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000183 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000184 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000185 *lp = p;
186 }
187 return p + (index & (L2_SIZE - 1));
188}
189
bellardfd6ce8f2003-05-14 19:00:11 +0000190static inline PageDesc *page_find(unsigned int index)
bellard54936002003-05-13 00:25:15 +0000191{
bellard54936002003-05-13 00:25:15 +0000192 PageDesc *p;
193
bellard54936002003-05-13 00:25:15 +0000194 p = l1_map[index >> L2_BITS];
195 if (!p)
196 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000197 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000198}
199
bellard92e873b2004-05-21 14:52:29 +0000200static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
201{
202 PhysPageDesc **lp, *p;
203
204 lp = &l1_phys_map[index >> L2_BITS];
205 p = *lp;
206 if (!p) {
207 /* allocate if not found */
208 p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
209 memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
210 *lp = p;
211 }
212 return p + (index & (L2_SIZE - 1));
213}
214
215static inline PhysPageDesc *phys_page_find(unsigned int index)
216{
217 PhysPageDesc *p;
218
219 p = l1_phys_map[index >> L2_BITS];
220 if (!p)
221 return 0;
222 return p + (index & (L2_SIZE - 1));
223}
224
bellard9fa3e852004-01-04 18:06:42 +0000225#if !defined(CONFIG_USER_ONLY)
bellard4f2ac232004-04-26 19:44:02 +0000226static void tlb_protect_code(CPUState *env, target_ulong addr);
227static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
bellardfd6ce8f2003-05-14 19:00:11 +0000228
bellard9fa3e852004-01-04 18:06:42 +0000229static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
230{
231 VirtPageDesc **lp, *p;
232
233 lp = &l1_virt_map[index >> L2_BITS];
234 p = *lp;
235 if (!p) {
236 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000237 p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
bellard9fa3e852004-01-04 18:06:42 +0000238 memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
239 *lp = p;
240 }
241 return p + (index & (L2_SIZE - 1));
242}
243
244static inline VirtPageDesc *virt_page_find(unsigned int index)
245{
246 VirtPageDesc *p;
247
248 p = l1_virt_map[index >> L2_BITS];
bellardfd6ce8f2003-05-14 19:00:11 +0000249 if (!p)
250 return 0;
bellard9fa3e852004-01-04 18:06:42 +0000251 return p + (index & (L2_SIZE - 1));
bellardfd6ce8f2003-05-14 19:00:11 +0000252}
253
bellard9fa3e852004-01-04 18:06:42 +0000254static void virt_page_flush(void)
bellard54936002003-05-13 00:25:15 +0000255{
bellard9fa3e852004-01-04 18:06:42 +0000256 int i, j;
257 VirtPageDesc *p;
258
259 virt_valid_tag++;
bellard54936002003-05-13 00:25:15 +0000260
bellard9fa3e852004-01-04 18:06:42 +0000261 if (virt_valid_tag == 0) {
262 virt_valid_tag = 1;
263 for(i = 0; i < L1_SIZE; i++) {
264 p = l1_virt_map[i];
265 if (p) {
266 for(j = 0; j < L2_SIZE; j++)
267 p[j].valid_tag = 0;
268 }
bellardfd6ce8f2003-05-14 19:00:11 +0000269 }
bellard54936002003-05-13 00:25:15 +0000270 }
271}
bellard9fa3e852004-01-04 18:06:42 +0000272#else
273static void virt_page_flush(void)
274{
275}
276#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000277
bellardb346ff42003-06-15 20:05:50 +0000278void cpu_exec_init(void)
bellardfd6ce8f2003-05-14 19:00:11 +0000279{
280 if (!code_gen_ptr) {
281 code_gen_ptr = code_gen_buffer;
bellardb346ff42003-06-15 20:05:50 +0000282 page_init();
bellard33417e72003-08-10 21:47:01 +0000283 io_mem_init();
bellardfd6ce8f2003-05-14 19:00:11 +0000284 }
285}
286
bellard9fa3e852004-01-04 18:06:42 +0000287static inline void invalidate_page_bitmap(PageDesc *p)
288{
289 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000290 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000291 p->code_bitmap = NULL;
292 }
293 p->code_write_count = 0;
294}
295
bellardfd6ce8f2003-05-14 19:00:11 +0000296/* set to NULL all the 'first_tb' fields in all PageDescs */
297static void page_flush_tb(void)
298{
299 int i, j;
300 PageDesc *p;
301
302 for(i = 0; i < L1_SIZE; i++) {
303 p = l1_map[i];
304 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000305 for(j = 0; j < L2_SIZE; j++) {
306 p->first_tb = NULL;
307 invalidate_page_bitmap(p);
308 p++;
309 }
bellardfd6ce8f2003-05-14 19:00:11 +0000310 }
311 }
312}
313
314/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000315/* XXX: tb_flush is currently not thread safe */
bellard01243112004-01-04 15:48:17 +0000316void tb_flush(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000317{
bellard01243112004-01-04 15:48:17 +0000318#if defined(DEBUG_FLUSH)
bellardfd6ce8f2003-05-14 19:00:11 +0000319 printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
320 code_gen_ptr - code_gen_buffer,
321 nb_tbs,
bellard01243112004-01-04 15:48:17 +0000322 nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000323#endif
324 nb_tbs = 0;
bellard8a8a6082004-10-03 13:36:49 +0000325 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +0000326 virt_page_flush();
327
bellard8a8a6082004-10-03 13:36:49 +0000328 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000329 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000330
bellardfd6ce8f2003-05-14 19:00:11 +0000331 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000332 /* XXX: flush processor icache at this point if cache flush is
333 expensive */
bellardfd6ce8f2003-05-14 19:00:11 +0000334}
335
336#ifdef DEBUG_TB_CHECK
337
338static void tb_invalidate_check(unsigned long address)
339{
340 TranslationBlock *tb;
341 int i;
342 address &= TARGET_PAGE_MASK;
343 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
344 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
345 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
346 address >= tb->pc + tb->size)) {
347 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
348 address, tb->pc, tb->size);
349 }
350 }
351 }
352}
353
354/* verify that all the pages have correct rights for code */
355static void tb_page_check(void)
356{
357 TranslationBlock *tb;
358 int i, flags1, flags2;
359
360 for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
361 for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
362 flags1 = page_get_flags(tb->pc);
363 flags2 = page_get_flags(tb->pc + tb->size - 1);
364 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
365 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
366 tb->pc, tb->size, flags1, flags2);
367 }
368 }
369 }
370}
371
bellardd4e81642003-05-25 16:46:15 +0000372void tb_jmp_check(TranslationBlock *tb)
373{
374 TranslationBlock *tb1;
375 unsigned int n1;
376
377 /* suppress any remaining jumps to this TB */
378 tb1 = tb->jmp_first;
379 for(;;) {
380 n1 = (long)tb1 & 3;
381 tb1 = (TranslationBlock *)((long)tb1 & ~3);
382 if (n1 == 2)
383 break;
384 tb1 = tb1->jmp_next[n1];
385 }
386 /* check end of list */
387 if (tb1 != tb) {
388 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
389 }
390}
391
bellardfd6ce8f2003-05-14 19:00:11 +0000392#endif
393
394/* invalidate one TB */
395static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
396 int next_offset)
397{
398 TranslationBlock *tb1;
399 for(;;) {
400 tb1 = *ptb;
401 if (tb1 == tb) {
402 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
403 break;
404 }
405 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
406 }
407}
408
bellard9fa3e852004-01-04 18:06:42 +0000409static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
410{
411 TranslationBlock *tb1;
412 unsigned int n1;
413
414 for(;;) {
415 tb1 = *ptb;
416 n1 = (long)tb1 & 3;
417 tb1 = (TranslationBlock *)((long)tb1 & ~3);
418 if (tb1 == tb) {
419 *ptb = tb1->page_next[n1];
420 break;
421 }
422 ptb = &tb1->page_next[n1];
423 }
424}
425
bellardd4e81642003-05-25 16:46:15 +0000426static inline void tb_jmp_remove(TranslationBlock *tb, int n)
427{
428 TranslationBlock *tb1, **ptb;
429 unsigned int n1;
430
431 ptb = &tb->jmp_next[n];
432 tb1 = *ptb;
433 if (tb1) {
434 /* find tb(n) in circular list */
435 for(;;) {
436 tb1 = *ptb;
437 n1 = (long)tb1 & 3;
438 tb1 = (TranslationBlock *)((long)tb1 & ~3);
439 if (n1 == n && tb1 == tb)
440 break;
441 if (n1 == 2) {
442 ptb = &tb1->jmp_first;
443 } else {
444 ptb = &tb1->jmp_next[n1];
445 }
446 }
447 /* now we can suppress tb(n) from the list */
448 *ptb = tb->jmp_next[n];
449
450 tb->jmp_next[n] = NULL;
451 }
452}
453
454/* reset the jump entry 'n' of a TB so that it is not chained to
455 another TB */
456static inline void tb_reset_jump(TranslationBlock *tb, int n)
457{
458 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
459}
460
bellard9fa3e852004-01-04 18:06:42 +0000461static inline void tb_invalidate(TranslationBlock *tb)
bellardfd6ce8f2003-05-14 19:00:11 +0000462{
bellardd4e81642003-05-25 16:46:15 +0000463 unsigned int h, n1;
bellard9fa3e852004-01-04 18:06:42 +0000464 TranslationBlock *tb1, *tb2, **ptb;
bellardd4e81642003-05-25 16:46:15 +0000465
bellard36bdbe52003-11-19 22:12:02 +0000466 tb_invalidated_flag = 1;
bellard59817cc2004-02-16 22:01:13 +0000467
bellardfd6ce8f2003-05-14 19:00:11 +0000468 /* remove the TB from the hash list */
469 h = tb_hash_func(tb->pc);
bellard9fa3e852004-01-04 18:06:42 +0000470 ptb = &tb_hash[h];
471 for(;;) {
472 tb1 = *ptb;
473 /* NOTE: the TB is not necessarily linked in the hash. It
474 indicates that it is not currently used */
475 if (tb1 == NULL)
476 return;
477 if (tb1 == tb) {
478 *ptb = tb1->hash_next;
479 break;
480 }
481 ptb = &tb1->hash_next;
bellardfd6ce8f2003-05-14 19:00:11 +0000482 }
bellardd4e81642003-05-25 16:46:15 +0000483
484 /* suppress this TB from the two jump lists */
485 tb_jmp_remove(tb, 0);
486 tb_jmp_remove(tb, 1);
487
488 /* suppress any remaining jumps to this TB */
489 tb1 = tb->jmp_first;
490 for(;;) {
491 n1 = (long)tb1 & 3;
492 if (n1 == 2)
493 break;
494 tb1 = (TranslationBlock *)((long)tb1 & ~3);
495 tb2 = tb1->jmp_next[n1];
496 tb_reset_jump(tb1, n1);
497 tb1->jmp_next[n1] = NULL;
498 tb1 = tb2;
499 }
500 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
bellardfd6ce8f2003-05-14 19:00:11 +0000501}
502
bellard9fa3e852004-01-04 18:06:42 +0000503static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000504{
bellardfd6ce8f2003-05-14 19:00:11 +0000505 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000506 unsigned int h;
507 target_ulong phys_pc;
508
509 /* remove the TB from the hash list */
510 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
511 h = tb_phys_hash_func(phys_pc);
512 tb_remove(&tb_phys_hash[h], tb,
513 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000514
bellard9fa3e852004-01-04 18:06:42 +0000515 /* remove the TB from the page list */
516 if (tb->page_addr[0] != page_addr) {
517 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
518 tb_page_remove(&p->first_tb, tb);
519 invalidate_page_bitmap(p);
520 }
521 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
522 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
523 tb_page_remove(&p->first_tb, tb);
524 invalidate_page_bitmap(p);
525 }
526
527 tb_invalidate(tb);
528}
529
530static inline void set_bits(uint8_t *tab, int start, int len)
531{
532 int end, mask, end1;
533
534 end = start + len;
535 tab += start >> 3;
536 mask = 0xff << (start & 7);
537 if ((start & ~7) == (end & ~7)) {
538 if (start < end) {
539 mask &= ~(0xff << (end & 7));
540 *tab |= mask;
541 }
542 } else {
543 *tab++ |= mask;
544 start = (start + 8) & ~7;
545 end1 = end & ~7;
546 while (start < end1) {
547 *tab++ = 0xff;
548 start += 8;
549 }
550 if (start < end) {
551 mask = ~(0xff << (end & 7));
552 *tab |= mask;
553 }
554 }
555}
556
557static void build_page_bitmap(PageDesc *p)
558{
559 int n, tb_start, tb_end;
560 TranslationBlock *tb;
561
bellard59817cc2004-02-16 22:01:13 +0000562 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000563 if (!p->code_bitmap)
564 return;
565 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
566
567 tb = p->first_tb;
568 while (tb != NULL) {
569 n = (long)tb & 3;
570 tb = (TranslationBlock *)((long)tb & ~3);
571 /* NOTE: this is subtle as a TB may span two physical pages */
572 if (n == 0) {
573 /* NOTE: tb_end may be after the end of the page, but
574 it is not a problem */
575 tb_start = tb->pc & ~TARGET_PAGE_MASK;
576 tb_end = tb_start + tb->size;
577 if (tb_end > TARGET_PAGE_SIZE)
578 tb_end = TARGET_PAGE_SIZE;
579 } else {
580 tb_start = 0;
581 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
582 }
583 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
584 tb = tb->page_next[n];
585 }
586}
587
bellardd720b932004-04-25 17:57:43 +0000588#ifdef TARGET_HAS_PRECISE_SMC
589
590static void tb_gen_code(CPUState *env,
591 target_ulong pc, target_ulong cs_base, int flags,
592 int cflags)
593{
594 TranslationBlock *tb;
595 uint8_t *tc_ptr;
596 target_ulong phys_pc, phys_page2, virt_page2;
597 int code_gen_size;
598
599 phys_pc = get_phys_addr_code(env, (unsigned long)pc);
600 tb = tb_alloc((unsigned long)pc);
601 if (!tb) {
602 /* flush must be done */
603 tb_flush(env);
604 /* cannot fail at this point */
605 tb = tb_alloc((unsigned long)pc);
606 }
607 tc_ptr = code_gen_ptr;
608 tb->tc_ptr = tc_ptr;
609 tb->cs_base = cs_base;
610 tb->flags = flags;
611 tb->cflags = cflags;
612 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
613 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
614
615 /* check next page if needed */
616 virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
617 phys_page2 = -1;
618 if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
619 phys_page2 = get_phys_addr_code(env, virt_page2);
620 }
621 tb_link_phys(tb, phys_pc, phys_page2);
622}
623#endif
624
bellard9fa3e852004-01-04 18:06:42 +0000625/* invalidate all TBs which intersect with the target physical page
626 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000627 the same physical page. 'is_cpu_write_access' should be true if called
628 from a real cpu write access: the virtual CPU will exit the current
629 TB if code is modified inside this TB. */
630void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
631 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000632{
bellardd720b932004-04-25 17:57:43 +0000633 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000634 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000635 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000636 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000637 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000638 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000639
640 p = page_find(start >> TARGET_PAGE_BITS);
641 if (!p)
642 return;
643 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000644 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
645 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000646 /* build code bitmap */
647 build_page_bitmap(p);
648 }
649
650 /* we remove all the TBs in the range [start, end[ */
651 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000652 current_tb_not_found = is_cpu_write_access;
653 current_tb_modified = 0;
654 current_tb = NULL; /* avoid warning */
655 current_pc = 0; /* avoid warning */
656 current_cs_base = 0; /* avoid warning */
657 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000658 tb = p->first_tb;
659 while (tb != NULL) {
660 n = (long)tb & 3;
661 tb = (TranslationBlock *)((long)tb & ~3);
662 tb_next = tb->page_next[n];
663 /* NOTE: this is subtle as a TB may span two physical pages */
664 if (n == 0) {
665 /* NOTE: tb_end may be after the end of the page, but
666 it is not a problem */
667 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
668 tb_end = tb_start + tb->size;
669 } else {
670 tb_start = tb->page_addr[1];
671 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
672 }
673 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000674#ifdef TARGET_HAS_PRECISE_SMC
675 if (current_tb_not_found) {
676 current_tb_not_found = 0;
677 current_tb = NULL;
678 if (env->mem_write_pc) {
679 /* now we have a real cpu fault */
680 current_tb = tb_find_pc(env->mem_write_pc);
681 }
682 }
683 if (current_tb == tb &&
684 !(current_tb->cflags & CF_SINGLE_INSN)) {
685 /* If we are modifying the current TB, we must stop
686 its execution. We could be more precise by checking
687 that the modification is after the current PC, but it
688 would require a specialized function to partially
689 restore the CPU state */
690
691 current_tb_modified = 1;
692 cpu_restore_state(current_tb, env,
693 env->mem_write_pc, NULL);
694#if defined(TARGET_I386)
695 current_flags = env->hflags;
696 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
697 current_cs_base = (target_ulong)env->segs[R_CS].base;
698 current_pc = current_cs_base + env->eip;
699#else
700#error unsupported CPU
701#endif
702 }
703#endif /* TARGET_HAS_PRECISE_SMC */
bellardea1c1802004-06-14 18:56:36 +0000704 saved_tb = env->current_tb;
705 env->current_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +0000706 tb_phys_invalidate(tb, -1);
bellardea1c1802004-06-14 18:56:36 +0000707 env->current_tb = saved_tb;
708 if (env->interrupt_request && env->current_tb)
709 cpu_interrupt(env, env->interrupt_request);
bellard9fa3e852004-01-04 18:06:42 +0000710 }
711 tb = tb_next;
712 }
713#if !defined(CONFIG_USER_ONLY)
714 /* if no code remaining, no need to continue to use slow writes */
715 if (!p->first_tb) {
716 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000717 if (is_cpu_write_access) {
718 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
719 }
720 }
721#endif
722#ifdef TARGET_HAS_PRECISE_SMC
723 if (current_tb_modified) {
724 /* we generate a block containing just the instruction
725 modifying the memory. It will ensure that it cannot modify
726 itself */
bellardea1c1802004-06-14 18:56:36 +0000727 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000728 tb_gen_code(env, current_pc, current_cs_base, current_flags,
729 CF_SINGLE_INSN);
730 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000731 }
732#endif
733}
734
735/* len must be <= 8 and start must be a multiple of len */
bellardd720b932004-04-25 17:57:43 +0000736static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000737{
738 PageDesc *p;
739 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000740#if 0
bellarda4193c82004-06-03 14:01:43 +0000741 if (1) {
742 if (loglevel) {
743 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
744 cpu_single_env->mem_write_vaddr, len,
745 cpu_single_env->eip,
746 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
747 }
bellard59817cc2004-02-16 22:01:13 +0000748 }
749#endif
bellard9fa3e852004-01-04 18:06:42 +0000750 p = page_find(start >> TARGET_PAGE_BITS);
751 if (!p)
752 return;
753 if (p->code_bitmap) {
754 offset = start & ~TARGET_PAGE_MASK;
755 b = p->code_bitmap[offset >> 3] >> (offset & 7);
756 if (b & ((1 << len) - 1))
757 goto do_invalidate;
758 } else {
759 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000760 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000761 }
762}
763
bellard9fa3e852004-01-04 18:06:42 +0000764#if !defined(CONFIG_SOFTMMU)
bellardd720b932004-04-25 17:57:43 +0000765static void tb_invalidate_phys_page(target_ulong addr,
766 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000767{
bellardd720b932004-04-25 17:57:43 +0000768 int n, current_flags, current_tb_modified;
769 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000770 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000771 TranslationBlock *tb, *current_tb;
772#ifdef TARGET_HAS_PRECISE_SMC
773 CPUState *env = cpu_single_env;
774#endif
bellard9fa3e852004-01-04 18:06:42 +0000775
776 addr &= TARGET_PAGE_MASK;
777 p = page_find(addr >> TARGET_PAGE_BITS);
778 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000779 return;
780 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000781 current_tb_modified = 0;
782 current_tb = NULL;
783 current_pc = 0; /* avoid warning */
784 current_cs_base = 0; /* avoid warning */
785 current_flags = 0; /* avoid warning */
786#ifdef TARGET_HAS_PRECISE_SMC
787 if (tb && pc != 0) {
788 current_tb = tb_find_pc(pc);
789 }
790#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000791 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000792 n = (long)tb & 3;
793 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000794#ifdef TARGET_HAS_PRECISE_SMC
795 if (current_tb == tb &&
796 !(current_tb->cflags & CF_SINGLE_INSN)) {
797 /* If we are modifying the current TB, we must stop
798 its execution. We could be more precise by checking
799 that the modification is after the current PC, but it
800 would require a specialized function to partially
801 restore the CPU state */
802
803 current_tb_modified = 1;
804 cpu_restore_state(current_tb, env, pc, puc);
805#if defined(TARGET_I386)
806 current_flags = env->hflags;
807 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
808 current_cs_base = (target_ulong)env->segs[R_CS].base;
809 current_pc = current_cs_base + env->eip;
810#else
811#error unsupported CPU
812#endif
813 }
814#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000815 tb_phys_invalidate(tb, addr);
816 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000817 }
818 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000819#ifdef TARGET_HAS_PRECISE_SMC
820 if (current_tb_modified) {
821 /* we generate a block containing just the instruction
822 modifying the memory. It will ensure that it cannot modify
823 itself */
bellardea1c1802004-06-14 18:56:36 +0000824 env->current_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000825 tb_gen_code(env, current_pc, current_cs_base, current_flags,
826 CF_SINGLE_INSN);
827 cpu_resume_from_signal(env, puc);
828 }
829#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000830}
bellard9fa3e852004-01-04 18:06:42 +0000831#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000832
833/* add the tb in the target page and protect it if necessary */
bellard9fa3e852004-01-04 18:06:42 +0000834static inline void tb_alloc_page(TranslationBlock *tb,
835 unsigned int n, unsigned int page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000836{
837 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000838 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000839
bellard9fa3e852004-01-04 18:06:42 +0000840 tb->page_addr[n] = page_addr;
841 p = page_find(page_addr >> TARGET_PAGE_BITS);
842 tb->page_next[n] = p->first_tb;
843 last_first_tb = p->first_tb;
844 p->first_tb = (TranslationBlock *)((long)tb | n);
845 invalidate_page_bitmap(p);
846
bellard107db442004-06-22 18:48:46 +0000847#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000848
bellard9fa3e852004-01-04 18:06:42 +0000849#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000850 if (p->flags & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +0000851 unsigned long host_start, host_end, addr;
852 int prot;
853
bellardfd6ce8f2003-05-14 19:00:11 +0000854 /* force the host page as non writable (writes will have a
855 page fault + mprotect overhead) */
bellard83fb7ad2004-07-05 21:25:26 +0000856 host_start = page_addr & qemu_host_page_mask;
857 host_end = host_start + qemu_host_page_size;
bellardfd6ce8f2003-05-14 19:00:11 +0000858 prot = 0;
859 for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
860 prot |= page_get_flags(addr);
bellard83fb7ad2004-07-05 21:25:26 +0000861 mprotect((void *)host_start, qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +0000862 (prot & PAGE_BITS) & ~PAGE_WRITE);
863#ifdef DEBUG_TB_INVALIDATE
864 printf("protecting code page: 0x%08lx\n",
865 host_start);
866#endif
867 p->flags &= ~PAGE_WRITE;
bellardfd6ce8f2003-05-14 19:00:11 +0000868 }
bellard9fa3e852004-01-04 18:06:42 +0000869#else
870 /* if some code is already present, then the pages are already
871 protected. So we handle the case where only the first TB is
872 allocated in a physical page */
873 if (!last_first_tb) {
874 target_ulong virt_addr;
875
876 virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
877 tlb_protect_code(cpu_single_env, virt_addr);
878 }
879#endif
bellardd720b932004-04-25 17:57:43 +0000880
881#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +0000882}
883
884/* Allocate a new translation block. Flush the translation buffer if
885 too many translation blocks or too much generated code. */
bellardd4e81642003-05-25 16:46:15 +0000886TranslationBlock *tb_alloc(unsigned long pc)
bellardfd6ce8f2003-05-14 19:00:11 +0000887{
888 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000889
890 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
891 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
bellardd4e81642003-05-25 16:46:15 +0000892 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +0000893 tb = &tbs[nb_tbs++];
894 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +0000895 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +0000896 return tb;
897}
898
bellard9fa3e852004-01-04 18:06:42 +0000899/* add a new TB and link it to the physical page tables. phys_page2 is
900 (-1) to indicate that only one page contains the TB. */
901void tb_link_phys(TranslationBlock *tb,
902 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +0000903{
bellard9fa3e852004-01-04 18:06:42 +0000904 unsigned int h;
905 TranslationBlock **ptb;
906
907 /* add in the physical hash table */
908 h = tb_phys_hash_func(phys_pc);
909 ptb = &tb_phys_hash[h];
910 tb->phys_hash_next = *ptb;
911 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000912
913 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +0000914 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
915 if (phys_page2 != -1)
916 tb_alloc_page(tb, 1, phys_page2);
917 else
918 tb->page_addr[1] = -1;
bellard61382a52003-10-27 21:22:23 +0000919#ifdef DEBUG_TB_CHECK
920 tb_page_check();
921#endif
bellard9fa3e852004-01-04 18:06:42 +0000922}
923
924/* link the tb with the other TBs */
925void tb_link(TranslationBlock *tb)
926{
927#if !defined(CONFIG_USER_ONLY)
928 {
929 VirtPageDesc *vp;
930 target_ulong addr;
931
932 /* save the code memory mappings (needed to invalidate the code) */
933 addr = tb->pc & TARGET_PAGE_MASK;
934 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000935#ifdef DEBUG_TLB_CHECK
936 if (vp->valid_tag == virt_valid_tag &&
937 vp->phys_addr != tb->page_addr[0]) {
938 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
939 addr, tb->page_addr[0], vp->phys_addr);
940 }
941#endif
bellard9fa3e852004-01-04 18:06:42 +0000942 vp->phys_addr = tb->page_addr[0];
bellard59817cc2004-02-16 22:01:13 +0000943 if (vp->valid_tag != virt_valid_tag) {
944 vp->valid_tag = virt_valid_tag;
945#if !defined(CONFIG_SOFTMMU)
946 vp->prot = 0;
947#endif
948 }
bellard9fa3e852004-01-04 18:06:42 +0000949
950 if (tb->page_addr[1] != -1) {
951 addr += TARGET_PAGE_SIZE;
952 vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard98857882004-01-18 21:52:14 +0000953#ifdef DEBUG_TLB_CHECK
954 if (vp->valid_tag == virt_valid_tag &&
955 vp->phys_addr != tb->page_addr[1]) {
956 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
957 addr, tb->page_addr[1], vp->phys_addr);
958 }
959#endif
bellard9fa3e852004-01-04 18:06:42 +0000960 vp->phys_addr = tb->page_addr[1];
bellard59817cc2004-02-16 22:01:13 +0000961 if (vp->valid_tag != virt_valid_tag) {
962 vp->valid_tag = virt_valid_tag;
963#if !defined(CONFIG_SOFTMMU)
964 vp->prot = 0;
965#endif
966 }
bellard9fa3e852004-01-04 18:06:42 +0000967 }
968 }
969#endif
970
bellardd4e81642003-05-25 16:46:15 +0000971 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
972 tb->jmp_next[0] = NULL;
973 tb->jmp_next[1] = NULL;
bellardb448f2f2004-02-25 23:24:04 +0000974#ifdef USE_CODE_COPY
975 tb->cflags &= ~CF_FP_USED;
976 if (tb->cflags & CF_TB_FP_USED)
977 tb->cflags |= CF_FP_USED;
978#endif
bellardd4e81642003-05-25 16:46:15 +0000979
980 /* init original jump addresses */
981 if (tb->tb_next_offset[0] != 0xffff)
982 tb_reset_jump(tb, 0);
983 if (tb->tb_next_offset[1] != 0xffff)
984 tb_reset_jump(tb, 1);
bellardfd6ce8f2003-05-14 19:00:11 +0000985}
986
bellarda513fe12003-05-27 23:29:48 +0000987/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
988 tb[1].tc_ptr. Return NULL if not found */
989TranslationBlock *tb_find_pc(unsigned long tc_ptr)
990{
991 int m_min, m_max, m;
992 unsigned long v;
993 TranslationBlock *tb;
994
995 if (nb_tbs <= 0)
996 return NULL;
997 if (tc_ptr < (unsigned long)code_gen_buffer ||
998 tc_ptr >= (unsigned long)code_gen_ptr)
999 return NULL;
1000 /* binary search (cf Knuth) */
1001 m_min = 0;
1002 m_max = nb_tbs - 1;
1003 while (m_min <= m_max) {
1004 m = (m_min + m_max) >> 1;
1005 tb = &tbs[m];
1006 v = (unsigned long)tb->tc_ptr;
1007 if (v == tc_ptr)
1008 return tb;
1009 else if (tc_ptr < v) {
1010 m_max = m - 1;
1011 } else {
1012 m_min = m + 1;
1013 }
1014 }
1015 return &tbs[m_max];
1016}
bellard75012672003-06-21 13:11:07 +00001017
bellardea041c02003-06-25 16:16:50 +00001018static void tb_reset_jump_recursive(TranslationBlock *tb);
1019
1020static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1021{
1022 TranslationBlock *tb1, *tb_next, **ptb;
1023 unsigned int n1;
1024
1025 tb1 = tb->jmp_next[n];
1026 if (tb1 != NULL) {
1027 /* find head of list */
1028 for(;;) {
1029 n1 = (long)tb1 & 3;
1030 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1031 if (n1 == 2)
1032 break;
1033 tb1 = tb1->jmp_next[n1];
1034 }
1035 /* we are now sure now that tb jumps to tb1 */
1036 tb_next = tb1;
1037
1038 /* remove tb from the jmp_first list */
1039 ptb = &tb_next->jmp_first;
1040 for(;;) {
1041 tb1 = *ptb;
1042 n1 = (long)tb1 & 3;
1043 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1044 if (n1 == n && tb1 == tb)
1045 break;
1046 ptb = &tb1->jmp_next[n1];
1047 }
1048 *ptb = tb->jmp_next[n];
1049 tb->jmp_next[n] = NULL;
1050
1051 /* suppress the jump to next tb in generated code */
1052 tb_reset_jump(tb, n);
1053
bellard01243112004-01-04 15:48:17 +00001054 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001055 tb_reset_jump_recursive(tb_next);
1056 }
1057}
1058
1059static void tb_reset_jump_recursive(TranslationBlock *tb)
1060{
1061 tb_reset_jump_recursive2(tb, 0);
1062 tb_reset_jump_recursive2(tb, 1);
1063}
1064
bellardd720b932004-04-25 17:57:43 +00001065static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1066{
1067 target_ulong phys_addr;
1068
1069 phys_addr = cpu_get_phys_page_debug(env, pc);
1070 tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1071}
1072
bellardc33a3462003-07-29 20:50:33 +00001073/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1074 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001075int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001076{
bellarde95c8d52004-09-30 22:22:08 +00001077#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001078 int i;
bellardd720b932004-04-25 17:57:43 +00001079
bellard4c3a88a2003-07-26 12:06:08 +00001080 for(i = 0; i < env->nb_breakpoints; i++) {
1081 if (env->breakpoints[i] == pc)
1082 return 0;
1083 }
1084
1085 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1086 return -1;
1087 env->breakpoints[env->nb_breakpoints++] = pc;
bellardd720b932004-04-25 17:57:43 +00001088
1089 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001090 return 0;
1091#else
1092 return -1;
1093#endif
1094}
1095
1096/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001097int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001098{
bellarde95c8d52004-09-30 22:22:08 +00001099#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellard4c3a88a2003-07-26 12:06:08 +00001100 int i;
1101 for(i = 0; i < env->nb_breakpoints; i++) {
1102 if (env->breakpoints[i] == pc)
1103 goto found;
1104 }
1105 return -1;
1106 found:
1107 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
1108 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
1109 env->nb_breakpoints--;
bellardd720b932004-04-25 17:57:43 +00001110
1111 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001112 return 0;
1113#else
1114 return -1;
1115#endif
1116}
1117
bellardc33a3462003-07-29 20:50:33 +00001118/* enable or disable single step mode. EXCP_DEBUG is returned by the
1119 CPU loop after each instruction */
1120void cpu_single_step(CPUState *env, int enabled)
1121{
bellarde95c8d52004-09-30 22:22:08 +00001122#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
bellardc33a3462003-07-29 20:50:33 +00001123 if (env->singlestep_enabled != enabled) {
1124 env->singlestep_enabled = enabled;
1125 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001126 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001127 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001128 }
1129#endif
1130}
1131
bellard34865132003-10-05 14:28:56 +00001132/* enable or disable low levels log */
1133void cpu_set_log(int log_flags)
1134{
1135 loglevel = log_flags;
1136 if (loglevel && !logfile) {
1137 logfile = fopen(logfilename, "w");
1138 if (!logfile) {
1139 perror(logfilename);
1140 _exit(1);
1141 }
bellard9fa3e852004-01-04 18:06:42 +00001142#if !defined(CONFIG_SOFTMMU)
1143 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1144 {
1145 static uint8_t logfile_buf[4096];
1146 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1147 }
1148#else
bellard34865132003-10-05 14:28:56 +00001149 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001150#endif
bellard34865132003-10-05 14:28:56 +00001151 }
1152}
1153
1154void cpu_set_log_filename(const char *filename)
1155{
1156 logfilename = strdup(filename);
1157}
bellardc33a3462003-07-29 20:50:33 +00001158
bellard01243112004-01-04 15:48:17 +00001159/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001160void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001161{
1162 TranslationBlock *tb;
bellardee8b7022004-02-03 23:35:10 +00001163 static int interrupt_lock;
bellard59817cc2004-02-16 22:01:13 +00001164
bellard68a79312003-06-30 13:12:32 +00001165 env->interrupt_request |= mask;
bellardea041c02003-06-25 16:16:50 +00001166 /* if the cpu is currently executing code, we must unlink it and
1167 all the potentially executing TB */
1168 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001169 if (tb && !testandset(&interrupt_lock)) {
1170 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001171 tb_reset_jump_recursive(tb);
bellardee8b7022004-02-03 23:35:10 +00001172 interrupt_lock = 0;
bellardea041c02003-06-25 16:16:50 +00001173 }
1174}
1175
bellardb54ad042004-05-20 13:42:52 +00001176void cpu_reset_interrupt(CPUState *env, int mask)
1177{
1178 env->interrupt_request &= ~mask;
1179}
1180
bellardf193c792004-03-21 17:06:25 +00001181CPULogItem cpu_log_items[] = {
1182 { CPU_LOG_TB_OUT_ASM, "out_asm",
1183 "show generated host assembly code for each compiled TB" },
1184 { CPU_LOG_TB_IN_ASM, "in_asm",
1185 "show target assembly code for each compiled TB" },
1186 { CPU_LOG_TB_OP, "op",
1187 "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1188#ifdef TARGET_I386
1189 { CPU_LOG_TB_OP_OPT, "op_opt",
1190 "show micro ops after optimization for each compiled TB" },
1191#endif
1192 { CPU_LOG_INT, "int",
1193 "show interrupts/exceptions in short format" },
1194 { CPU_LOG_EXEC, "exec",
1195 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001196 { CPU_LOG_TB_CPU, "cpu",
1197 "show CPU state before bloc translation" },
bellardf193c792004-03-21 17:06:25 +00001198#ifdef TARGET_I386
1199 { CPU_LOG_PCALL, "pcall",
1200 "show protected mode far calls/returns/exceptions" },
1201#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001202#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001203 { CPU_LOG_IOPORT, "ioport",
1204 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001205#endif
bellardf193c792004-03-21 17:06:25 +00001206 { 0, NULL, NULL },
1207};
1208
1209static int cmp1(const char *s1, int n, const char *s2)
1210{
1211 if (strlen(s2) != n)
1212 return 0;
1213 return memcmp(s1, s2, n) == 0;
1214}
1215
1216/* takes a comma separated list of log masks. Return 0 if error. */
1217int cpu_str_to_log_mask(const char *str)
1218{
1219 CPULogItem *item;
1220 int mask;
1221 const char *p, *p1;
1222
1223 p = str;
1224 mask = 0;
1225 for(;;) {
1226 p1 = strchr(p, ',');
1227 if (!p1)
1228 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001229 if(cmp1(p,p1-p,"all")) {
1230 for(item = cpu_log_items; item->mask != 0; item++) {
1231 mask |= item->mask;
1232 }
1233 } else {
bellardf193c792004-03-21 17:06:25 +00001234 for(item = cpu_log_items; item->mask != 0; item++) {
1235 if (cmp1(p, p1 - p, item->name))
1236 goto found;
1237 }
1238 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001239 }
bellardf193c792004-03-21 17:06:25 +00001240 found:
1241 mask |= item->mask;
1242 if (*p1 != ',')
1243 break;
1244 p = p1 + 1;
1245 }
1246 return mask;
1247}
bellardea041c02003-06-25 16:16:50 +00001248
bellard75012672003-06-21 13:11:07 +00001249void cpu_abort(CPUState *env, const char *fmt, ...)
1250{
1251 va_list ap;
1252
1253 va_start(ap, fmt);
1254 fprintf(stderr, "qemu: fatal: ");
1255 vfprintf(stderr, fmt, ap);
1256 fprintf(stderr, "\n");
1257#ifdef TARGET_I386
1258 cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
1259#endif
1260 va_end(ap);
1261 abort();
1262}
1263
bellard01243112004-01-04 15:48:17 +00001264#if !defined(CONFIG_USER_ONLY)
1265
bellardee8b7022004-02-03 23:35:10 +00001266/* NOTE: if flush_global is true, also flush global entries (not
1267 implemented yet) */
1268void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001269{
bellard33417e72003-08-10 21:47:01 +00001270 int i;
bellard01243112004-01-04 15:48:17 +00001271
bellard9fa3e852004-01-04 18:06:42 +00001272#if defined(DEBUG_TLB)
1273 printf("tlb_flush:\n");
1274#endif
bellard01243112004-01-04 15:48:17 +00001275 /* must reset current TB so that interrupts cannot modify the
1276 links while we are modifying them */
1277 env->current_tb = NULL;
1278
bellard33417e72003-08-10 21:47:01 +00001279 for(i = 0; i < CPU_TLB_SIZE; i++) {
1280 env->tlb_read[0][i].address = -1;
1281 env->tlb_write[0][i].address = -1;
1282 env->tlb_read[1][i].address = -1;
1283 env->tlb_write[1][i].address = -1;
1284 }
bellard9fa3e852004-01-04 18:06:42 +00001285
1286 virt_page_flush();
bellard8a8a6082004-10-03 13:36:49 +00001287 memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001288
1289#if !defined(CONFIG_SOFTMMU)
1290 munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1291#endif
bellard33417e72003-08-10 21:47:01 +00001292}
1293
bellard274da6b2004-05-20 21:56:27 +00001294static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001295{
1296 if (addr == (tlb_entry->address &
1297 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1298 tlb_entry->address = -1;
1299}
1300
bellard2e126692004-04-25 21:28:44 +00001301void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001302{
bellard9fa3e852004-01-04 18:06:42 +00001303 int i, n;
1304 VirtPageDesc *vp;
1305 PageDesc *p;
1306 TranslationBlock *tb;
bellard01243112004-01-04 15:48:17 +00001307
bellard9fa3e852004-01-04 18:06:42 +00001308#if defined(DEBUG_TLB)
1309 printf("tlb_flush_page: 0x%08x\n", addr);
1310#endif
bellard01243112004-01-04 15:48:17 +00001311 /* must reset current TB so that interrupts cannot modify the
1312 links while we are modifying them */
1313 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001314
bellard61382a52003-10-27 21:22:23 +00001315 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001316 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard61382a52003-10-27 21:22:23 +00001317 tlb_flush_entry(&env->tlb_read[0][i], addr);
1318 tlb_flush_entry(&env->tlb_write[0][i], addr);
1319 tlb_flush_entry(&env->tlb_read[1][i], addr);
1320 tlb_flush_entry(&env->tlb_write[1][i], addr);
bellard01243112004-01-04 15:48:17 +00001321
bellard9fa3e852004-01-04 18:06:42 +00001322 /* remove from the virtual pc hash table all the TB at this
1323 virtual address */
1324
1325 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1326 if (vp && vp->valid_tag == virt_valid_tag) {
1327 p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1328 if (p) {
1329 /* we remove all the links to the TBs in this virtual page */
1330 tb = p->first_tb;
1331 while (tb != NULL) {
1332 n = (long)tb & 3;
1333 tb = (TranslationBlock *)((long)tb & ~3);
1334 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1335 ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1336 tb_invalidate(tb);
1337 }
1338 tb = tb->page_next[n];
1339 }
1340 }
bellard98857882004-01-18 21:52:14 +00001341 vp->valid_tag = 0;
bellard9fa3e852004-01-04 18:06:42 +00001342 }
1343
bellard01243112004-01-04 15:48:17 +00001344#if !defined(CONFIG_SOFTMMU)
bellard9fa3e852004-01-04 18:06:42 +00001345 if (addr < MMAP_AREA_END)
bellard01243112004-01-04 15:48:17 +00001346 munmap((void *)addr, TARGET_PAGE_SIZE);
bellard61382a52003-10-27 21:22:23 +00001347#endif
bellard9fa3e852004-01-04 18:06:42 +00001348}
1349
bellard4f2ac232004-04-26 19:44:02 +00001350static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard9fa3e852004-01-04 18:06:42 +00001351{
1352 if (addr == (tlb_entry->address &
1353 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
bellard98857882004-01-18 21:52:14 +00001354 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1355 (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
bellard1ccde1c2004-02-06 19:46:14 +00001356 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
bellard01243112004-01-04 15:48:17 +00001357 }
bellard61382a52003-10-27 21:22:23 +00001358}
1359
bellard9fa3e852004-01-04 18:06:42 +00001360/* update the TLBs so that writes to code in the virtual page 'addr'
1361 can be detected */
bellard4f2ac232004-04-26 19:44:02 +00001362static void tlb_protect_code(CPUState *env, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001363{
bellard61382a52003-10-27 21:22:23 +00001364 int i;
1365
1366 addr &= TARGET_PAGE_MASK;
1367 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001368 tlb_protect_code1(&env->tlb_write[0][i], addr);
1369 tlb_protect_code1(&env->tlb_write[1][i], addr);
1370#if !defined(CONFIG_SOFTMMU)
1371 /* NOTE: as we generated the code for this page, it is already at
1372 least readable */
1373 if (addr < MMAP_AREA_END)
1374 mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1375#endif
1376}
1377
bellard9fa3e852004-01-04 18:06:42 +00001378static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
bellard4f2ac232004-04-26 19:44:02 +00001379 unsigned long phys_addr)
bellard9fa3e852004-01-04 18:06:42 +00001380{
1381 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1382 ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
bellard1ccde1c2004-02-06 19:46:14 +00001383 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001384 }
1385}
1386
1387/* update the TLB so that writes in physical page 'phys_addr' are no longer
1388 tested self modifying code */
bellard4f2ac232004-04-26 19:44:02 +00001389static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001390{
1391 int i;
1392
1393 phys_addr &= TARGET_PAGE_MASK;
bellard1ccde1c2004-02-06 19:46:14 +00001394 phys_addr += (long)phys_ram_base;
1395 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1396 tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1397 tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1398}
1399
1400static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1401 unsigned long start, unsigned long length)
1402{
1403 unsigned long addr;
1404 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1405 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1406 if ((addr - start) < length) {
1407 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1408 }
1409 }
1410}
1411
1412void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
1413{
1414 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001415 unsigned long length, start1;
bellard1ccde1c2004-02-06 19:46:14 +00001416 int i;
1417
1418 start &= TARGET_PAGE_MASK;
1419 end = TARGET_PAGE_ALIGN(end);
1420
1421 length = end - start;
1422 if (length == 0)
1423 return;
1424 memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
1425
1426 env = cpu_single_env;
1427 /* we modify the TLB cache so that the dirty bit will be set again
1428 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001429 start1 = start + (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001430 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001431 tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
bellard9fa3e852004-01-04 18:06:42 +00001432 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard59817cc2004-02-16 22:01:13 +00001433 tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1434
1435#if !defined(CONFIG_SOFTMMU)
1436 /* XXX: this is expensive */
1437 {
1438 VirtPageDesc *p;
1439 int j;
1440 target_ulong addr;
1441
1442 for(i = 0; i < L1_SIZE; i++) {
1443 p = l1_virt_map[i];
1444 if (p) {
1445 addr = i << (TARGET_PAGE_BITS + L2_BITS);
1446 for(j = 0; j < L2_SIZE; j++) {
1447 if (p->valid_tag == virt_valid_tag &&
1448 p->phys_addr >= start && p->phys_addr < end &&
1449 (p->prot & PROT_WRITE)) {
1450 if (addr < MMAP_AREA_END) {
1451 mprotect((void *)addr, TARGET_PAGE_SIZE,
1452 p->prot & ~PROT_WRITE);
1453 }
1454 }
1455 addr += TARGET_PAGE_SIZE;
1456 p++;
1457 }
1458 }
1459 }
1460 }
1461#endif
bellard1ccde1c2004-02-06 19:46:14 +00001462}
1463
1464static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
1465 unsigned long start)
1466{
1467 unsigned long addr;
1468 if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1469 addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1470 if (addr == start) {
1471 tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1472 }
1473 }
1474}
1475
1476/* update the TLB corresponding to virtual page vaddr and phys addr
1477 addr so that it is no longer dirty */
1478static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1479{
1480 CPUState *env = cpu_single_env;
1481 int i;
1482
1483 phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
1484
1485 addr &= TARGET_PAGE_MASK;
1486 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1487 tlb_set_dirty1(&env->tlb_write[0][i], addr);
1488 tlb_set_dirty1(&env->tlb_write[1][i], addr);
bellard9fa3e852004-01-04 18:06:42 +00001489}
1490
bellard59817cc2004-02-16 22:01:13 +00001491/* add a new TLB entry. At most one entry for a given virtual address
1492 is permitted. Return 0 if OK or 2 if the page could not be mapped
1493 (can only happen in non SOFTMMU mode for I/O pages or pages
1494 conflicting with the host address space). */
bellard2e126692004-04-25 21:28:44 +00001495int tlb_set_page(CPUState *env, target_ulong vaddr,
1496 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001497 int is_user, int is_softmmu)
1498{
bellard92e873b2004-05-21 14:52:29 +00001499 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001500 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001501 TranslationBlock *first_tb;
1502 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001503 target_ulong address;
1504 unsigned long addend;
bellard9fa3e852004-01-04 18:06:42 +00001505 int ret;
1506
bellard92e873b2004-05-21 14:52:29 +00001507 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1508 first_tb = NULL;
bellard9fa3e852004-01-04 18:06:42 +00001509 if (!p) {
1510 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001511 } else {
bellard92e873b2004-05-21 14:52:29 +00001512 PageDesc *p1;
bellard9fa3e852004-01-04 18:06:42 +00001513 pd = p->phys_offset;
bellard92e873b2004-05-21 14:52:29 +00001514 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
1515 /* NOTE: we also allocate the page at this stage */
1516 p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
1517 first_tb = p1->first_tb;
1518 }
bellard9fa3e852004-01-04 18:06:42 +00001519 }
1520#if defined(DEBUG_TLB)
1521 printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1522 vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1523#endif
1524
1525 ret = 0;
1526#if !defined(CONFIG_SOFTMMU)
1527 if (is_softmmu)
1528#endif
1529 {
1530 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1531 /* IO memory case */
1532 address = vaddr | pd;
1533 addend = paddr;
1534 } else {
1535 /* standard memory */
1536 address = vaddr;
1537 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1538 }
1539
1540 index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1541 addend -= vaddr;
bellard67b915a2004-03-31 23:37:16 +00001542 if (prot & PAGE_READ) {
bellard9fa3e852004-01-04 18:06:42 +00001543 env->tlb_read[is_user][index].address = address;
1544 env->tlb_read[is_user][index].addend = addend;
1545 } else {
1546 env->tlb_read[is_user][index].address = -1;
1547 env->tlb_read[is_user][index].addend = -1;
1548 }
bellard67b915a2004-03-31 23:37:16 +00001549 if (prot & PAGE_WRITE) {
bellard9fa3e852004-01-04 18:06:42 +00001550 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1551 /* ROM: access is ignored (same as unassigned) */
1552 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
bellard1ccde1c2004-02-06 19:46:14 +00001553 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001554 } else
1555 /* XXX: the PowerPC code seems not ready to handle
1556 self modifying code with DCBI */
1557#if defined(TARGET_HAS_SMC) || 1
1558 if (first_tb) {
bellard9fa3e852004-01-04 18:06:42 +00001559 /* if code is present, we use a specific memory
1560 handler. It works only for physical memory access */
1561 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
bellard1ccde1c2004-02-06 19:46:14 +00001562 env->tlb_write[is_user][index].addend = addend;
bellardd720b932004-04-25 17:57:43 +00001563 } else
1564#endif
1565 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001566 !cpu_physical_memory_is_dirty(pd)) {
1567 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1568 env->tlb_write[is_user][index].addend = addend;
bellard9fa3e852004-01-04 18:06:42 +00001569 } else {
1570 env->tlb_write[is_user][index].address = address;
1571 env->tlb_write[is_user][index].addend = addend;
1572 }
1573 } else {
1574 env->tlb_write[is_user][index].address = -1;
1575 env->tlb_write[is_user][index].addend = -1;
1576 }
1577 }
1578#if !defined(CONFIG_SOFTMMU)
1579 else {
1580 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1581 /* IO access: no mapping is done as it will be handled by the
1582 soft MMU */
1583 if (!(env->hflags & HF_SOFTMMU_MASK))
1584 ret = 2;
1585 } else {
1586 void *map_addr;
bellard9fa3e852004-01-04 18:06:42 +00001587
bellard59817cc2004-02-16 22:01:13 +00001588 if (vaddr >= MMAP_AREA_END) {
1589 ret = 2;
1590 } else {
1591 if (prot & PROT_WRITE) {
1592 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellardd720b932004-04-25 17:57:43 +00001593#if defined(TARGET_HAS_SMC) || 1
bellard59817cc2004-02-16 22:01:13 +00001594 first_tb ||
bellardd720b932004-04-25 17:57:43 +00001595#endif
bellard59817cc2004-02-16 22:01:13 +00001596 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1597 !cpu_physical_memory_is_dirty(pd))) {
1598 /* ROM: we do as if code was inside */
1599 /* if code is present, we only map as read only and save the
1600 original mapping */
1601 VirtPageDesc *vp;
1602
1603 vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1604 vp->phys_addr = pd;
1605 vp->prot = prot;
1606 vp->valid_tag = virt_valid_tag;
1607 prot &= ~PAGE_WRITE;
1608 }
bellard9fa3e852004-01-04 18:06:42 +00001609 }
bellard59817cc2004-02-16 22:01:13 +00001610 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
1611 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1612 if (map_addr == MAP_FAILED) {
1613 cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1614 paddr, vaddr);
1615 }
bellard9fa3e852004-01-04 18:06:42 +00001616 }
1617 }
1618 }
1619#endif
1620 return ret;
1621}
1622
1623/* called from signal handler: invalidate the code and unprotect the
1624 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001625int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001626{
1627#if !defined(CONFIG_SOFTMMU)
1628 VirtPageDesc *vp;
1629
1630#if defined(DEBUG_TLB)
1631 printf("page_unprotect: addr=0x%08x\n", addr);
1632#endif
1633 addr &= TARGET_PAGE_MASK;
bellard59817cc2004-02-16 22:01:13 +00001634
1635 /* if it is not mapped, no need to worry here */
1636 if (addr >= MMAP_AREA_END)
1637 return 0;
bellard9fa3e852004-01-04 18:06:42 +00001638 vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1639 if (!vp)
1640 return 0;
1641 /* NOTE: in this case, validate_tag is _not_ tested as it
1642 validates only the code TLB */
1643 if (vp->valid_tag != virt_valid_tag)
1644 return 0;
1645 if (!(vp->prot & PAGE_WRITE))
1646 return 0;
1647#if defined(DEBUG_TLB)
1648 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1649 addr, vp->phys_addr, vp->prot);
1650#endif
bellard59817cc2004-02-16 22:01:13 +00001651 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1652 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1653 (unsigned long)addr, vp->prot);
bellardd720b932004-04-25 17:57:43 +00001654 /* set the dirty bit */
1655 phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1656 /* flush the code inside */
1657 tb_invalidate_phys_page(vp->phys_addr, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001658 return 1;
1659#else
1660 return 0;
1661#endif
bellard33417e72003-08-10 21:47:01 +00001662}
1663
bellard01243112004-01-04 15:48:17 +00001664#else
1665
bellardee8b7022004-02-03 23:35:10 +00001666void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001667{
1668}
1669
bellard2e126692004-04-25 21:28:44 +00001670void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001671{
1672}
1673
bellard2e126692004-04-25 21:28:44 +00001674int tlb_set_page(CPUState *env, target_ulong vaddr,
1675 target_phys_addr_t paddr, int prot,
bellard9fa3e852004-01-04 18:06:42 +00001676 int is_user, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001677{
bellard9fa3e852004-01-04 18:06:42 +00001678 return 0;
1679}
bellard33417e72003-08-10 21:47:01 +00001680
bellard9fa3e852004-01-04 18:06:42 +00001681/* dump memory mappings */
1682void page_dump(FILE *f)
1683{
1684 unsigned long start, end;
1685 int i, j, prot, prot1;
1686 PageDesc *p;
1687
1688 fprintf(f, "%-8s %-8s %-8s %s\n",
1689 "start", "end", "size", "prot");
1690 start = -1;
1691 end = -1;
1692 prot = 0;
1693 for(i = 0; i <= L1_SIZE; i++) {
1694 if (i < L1_SIZE)
1695 p = l1_map[i];
1696 else
1697 p = NULL;
1698 for(j = 0;j < L2_SIZE; j++) {
1699 if (!p)
1700 prot1 = 0;
1701 else
1702 prot1 = p[j].flags;
1703 if (prot1 != prot) {
1704 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1705 if (start != -1) {
1706 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1707 start, end, end - start,
1708 prot & PAGE_READ ? 'r' : '-',
1709 prot & PAGE_WRITE ? 'w' : '-',
1710 prot & PAGE_EXEC ? 'x' : '-');
1711 }
1712 if (prot1 != 0)
1713 start = end;
1714 else
1715 start = -1;
1716 prot = prot1;
1717 }
1718 if (!p)
1719 break;
1720 }
bellard33417e72003-08-10 21:47:01 +00001721 }
bellard33417e72003-08-10 21:47:01 +00001722}
1723
bellard9fa3e852004-01-04 18:06:42 +00001724int page_get_flags(unsigned long address)
bellard33417e72003-08-10 21:47:01 +00001725{
bellard9fa3e852004-01-04 18:06:42 +00001726 PageDesc *p;
1727
1728 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001729 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001730 return 0;
1731 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001732}
1733
bellard9fa3e852004-01-04 18:06:42 +00001734/* modify the flags of a page and invalidate the code if
1735 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1736 depending on PAGE_WRITE */
1737void page_set_flags(unsigned long start, unsigned long end, int flags)
1738{
1739 PageDesc *p;
1740 unsigned long addr;
1741
1742 start = start & TARGET_PAGE_MASK;
1743 end = TARGET_PAGE_ALIGN(end);
1744 if (flags & PAGE_WRITE)
1745 flags |= PAGE_WRITE_ORG;
1746 spin_lock(&tb_lock);
1747 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1748 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1749 /* if the write protection is set, then we invalidate the code
1750 inside */
1751 if (!(p->flags & PAGE_WRITE) &&
1752 (flags & PAGE_WRITE) &&
1753 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001754 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001755 }
1756 p->flags = flags;
1757 }
1758 spin_unlock(&tb_lock);
1759}
1760
1761/* called from signal handler: invalidate the code and unprotect the
1762 page. Return TRUE if the fault was succesfully handled. */
bellardd720b932004-04-25 17:57:43 +00001763int page_unprotect(unsigned long address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001764{
1765 unsigned int page_index, prot, pindex;
1766 PageDesc *p, *p1;
1767 unsigned long host_start, host_end, addr;
1768
bellard83fb7ad2004-07-05 21:25:26 +00001769 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001770 page_index = host_start >> TARGET_PAGE_BITS;
1771 p1 = page_find(page_index);
1772 if (!p1)
1773 return 0;
bellard83fb7ad2004-07-05 21:25:26 +00001774 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001775 p = p1;
1776 prot = 0;
1777 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1778 prot |= p->flags;
1779 p++;
1780 }
1781 /* if the page was really writable, then we change its
1782 protection back to writable */
1783 if (prot & PAGE_WRITE_ORG) {
1784 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1785 if (!(p1[pindex].flags & PAGE_WRITE)) {
bellard83fb7ad2004-07-05 21:25:26 +00001786 mprotect((void *)host_start, qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001787 (prot & PAGE_BITS) | PAGE_WRITE);
1788 p1[pindex].flags |= PAGE_WRITE;
1789 /* and since the content will be modified, we must invalidate
1790 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001791 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001792#ifdef DEBUG_TB_CHECK
1793 tb_invalidate_check(address);
1794#endif
1795 return 1;
1796 }
1797 }
1798 return 0;
1799}
1800
1801/* call this function when system calls directly modify a memory area */
1802void page_unprotect_range(uint8_t *data, unsigned long data_size)
1803{
1804 unsigned long start, end, addr;
1805
1806 start = (unsigned long)data;
1807 end = start + data_size;
1808 start &= TARGET_PAGE_MASK;
1809 end = TARGET_PAGE_ALIGN(end);
1810 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
bellardd720b932004-04-25 17:57:43 +00001811 page_unprotect(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001812 }
1813}
1814
bellard1ccde1c2004-02-06 19:46:14 +00001815static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1816{
1817}
bellard9fa3e852004-01-04 18:06:42 +00001818#endif /* defined(CONFIG_USER_ONLY) */
1819
bellard33417e72003-08-10 21:47:01 +00001820/* register physical memory. 'size' must be a multiple of the target
1821 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1822 io memory page */
bellard2e126692004-04-25 21:28:44 +00001823void cpu_register_physical_memory(target_phys_addr_t start_addr,
1824 unsigned long size,
1825 unsigned long phys_offset)
bellard33417e72003-08-10 21:47:01 +00001826{
1827 unsigned long addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00001828 PhysPageDesc *p;
bellard33417e72003-08-10 21:47:01 +00001829
bellard5fd386f2004-05-23 21:11:22 +00001830 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001831 end_addr = start_addr + size;
bellard5fd386f2004-05-23 21:11:22 +00001832 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
bellard92e873b2004-05-21 14:52:29 +00001833 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001834 p->phys_offset = phys_offset;
1835 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
bellard33417e72003-08-10 21:47:01 +00001836 phys_offset += TARGET_PAGE_SIZE;
1837 }
1838}
1839
bellarda4193c82004-06-03 14:01:43 +00001840static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00001841{
1842 return 0;
1843}
1844
bellarda4193c82004-06-03 14:01:43 +00001845static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00001846{
1847}
1848
1849static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1850 unassigned_mem_readb,
1851 unassigned_mem_readb,
1852 unassigned_mem_readb,
1853};
1854
1855static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1856 unassigned_mem_writeb,
1857 unassigned_mem_writeb,
1858 unassigned_mem_writeb,
1859};
1860
bellard9fa3e852004-01-04 18:06:42 +00001861/* self modifying code support in soft mmu mode : writing to a page
1862 containing code comes to these functions */
1863
bellarda4193c82004-06-03 14:01:43 +00001864static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001865{
bellard1ccde1c2004-02-06 19:46:14 +00001866 unsigned long phys_addr;
1867
bellard274da6b2004-05-20 21:56:27 +00001868 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001869#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001870 tb_invalidate_phys_page_fast(phys_addr, 1);
bellard9fa3e852004-01-04 18:06:42 +00001871#endif
bellard1ccde1c2004-02-06 19:46:14 +00001872 stb_raw((uint8_t *)addr, val);
1873 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001874}
1875
bellarda4193c82004-06-03 14:01:43 +00001876static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001877{
bellard1ccde1c2004-02-06 19:46:14 +00001878 unsigned long phys_addr;
1879
bellard274da6b2004-05-20 21:56:27 +00001880 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001881#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001882 tb_invalidate_phys_page_fast(phys_addr, 2);
bellard9fa3e852004-01-04 18:06:42 +00001883#endif
bellard1ccde1c2004-02-06 19:46:14 +00001884 stw_raw((uint8_t *)addr, val);
1885 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001886}
1887
bellarda4193c82004-06-03 14:01:43 +00001888static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard9fa3e852004-01-04 18:06:42 +00001889{
bellard1ccde1c2004-02-06 19:46:14 +00001890 unsigned long phys_addr;
1891
bellard274da6b2004-05-20 21:56:27 +00001892 phys_addr = addr - (unsigned long)phys_ram_base;
bellard9fa3e852004-01-04 18:06:42 +00001893#if !defined(CONFIG_USER_ONLY)
bellardd720b932004-04-25 17:57:43 +00001894 tb_invalidate_phys_page_fast(phys_addr, 4);
bellard9fa3e852004-01-04 18:06:42 +00001895#endif
bellard1ccde1c2004-02-06 19:46:14 +00001896 stl_raw((uint8_t *)addr, val);
1897 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
bellard9fa3e852004-01-04 18:06:42 +00001898}
1899
1900static CPUReadMemoryFunc *code_mem_read[3] = {
1901 NULL, /* never used */
1902 NULL, /* never used */
1903 NULL, /* never used */
1904};
1905
1906static CPUWriteMemoryFunc *code_mem_write[3] = {
1907 code_mem_writeb,
1908 code_mem_writew,
1909 code_mem_writel,
1910};
bellard33417e72003-08-10 21:47:01 +00001911
bellarda4193c82004-06-03 14:01:43 +00001912static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001913{
1914 stb_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001915 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001916}
1917
bellarda4193c82004-06-03 14:01:43 +00001918static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001919{
1920 stw_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001921 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001922}
1923
bellarda4193c82004-06-03 14:01:43 +00001924static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00001925{
1926 stl_raw((uint8_t *)addr, val);
bellardd720b932004-04-25 17:57:43 +00001927 tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00001928}
1929
1930static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1931 notdirty_mem_writeb,
1932 notdirty_mem_writew,
1933 notdirty_mem_writel,
1934};
1935
bellard33417e72003-08-10 21:47:01 +00001936static void io_mem_init(void)
1937{
bellarda4193c82004-06-03 14:01:43 +00001938 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1939 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1940 cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1941 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00001942 io_mem_nb = 5;
1943
1944 /* alloc dirty bits array */
bellard59817cc2004-02-16 22:01:13 +00001945 phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001946}
1947
1948/* mem_read and mem_write are arrays of functions containing the
1949 function to access byte (index 0), word (index 1) and dword (index
1950 2). All functions must be supplied. If io_index is non zero, the
1951 corresponding io zone is modified. If it is zero, a new io zone is
1952 allocated. The return value can be used with
1953 cpu_register_physical_memory(). (-1) is returned if error. */
1954int cpu_register_io_memory(int io_index,
1955 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00001956 CPUWriteMemoryFunc **mem_write,
1957 void *opaque)
bellard33417e72003-08-10 21:47:01 +00001958{
1959 int i;
1960
1961 if (io_index <= 0) {
1962 if (io_index >= IO_MEM_NB_ENTRIES)
1963 return -1;
1964 io_index = io_mem_nb++;
1965 } else {
1966 if (io_index >= IO_MEM_NB_ENTRIES)
1967 return -1;
1968 }
1969
1970 for(i = 0;i < 3; i++) {
1971 io_mem_read[io_index][i] = mem_read[i];
1972 io_mem_write[io_index][i] = mem_write[i];
1973 }
bellarda4193c82004-06-03 14:01:43 +00001974 io_mem_opaque[io_index] = opaque;
bellard33417e72003-08-10 21:47:01 +00001975 return io_index << IO_MEM_SHIFT;
1976}
bellard61382a52003-10-27 21:22:23 +00001977
bellard13eb76e2004-01-24 15:23:36 +00001978/* physical memory access (slow version, mainly for debug) */
1979#if defined(CONFIG_USER_ONLY)
bellard2e126692004-04-25 21:28:44 +00001980void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00001981 int len, int is_write)
1982{
1983 int l, flags;
1984 target_ulong page;
1985
1986 while (len > 0) {
1987 page = addr & TARGET_PAGE_MASK;
1988 l = (page + TARGET_PAGE_SIZE) - addr;
1989 if (l > len)
1990 l = len;
1991 flags = page_get_flags(page);
1992 if (!(flags & PAGE_VALID))
1993 return;
1994 if (is_write) {
1995 if (!(flags & PAGE_WRITE))
1996 return;
1997 memcpy((uint8_t *)addr, buf, len);
1998 } else {
1999 if (!(flags & PAGE_READ))
2000 return;
2001 memcpy(buf, (uint8_t *)addr, len);
2002 }
2003 len -= l;
2004 buf += l;
2005 addr += l;
2006 }
2007}
2008#else
bellard2e126692004-04-25 21:28:44 +00002009void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002010 int len, int is_write)
2011{
2012 int l, io_index;
2013 uint8_t *ptr;
2014 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002015 target_phys_addr_t page;
2016 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002017 PhysPageDesc *p;
bellard13eb76e2004-01-24 15:23:36 +00002018
2019 while (len > 0) {
2020 page = addr & TARGET_PAGE_MASK;
2021 l = (page + TARGET_PAGE_SIZE) - addr;
2022 if (l > len)
2023 l = len;
bellard92e873b2004-05-21 14:52:29 +00002024 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002025 if (!p) {
2026 pd = IO_MEM_UNASSIGNED;
2027 } else {
2028 pd = p->phys_offset;
2029 }
2030
2031 if (is_write) {
2032 if ((pd & ~TARGET_PAGE_MASK) != 0) {
2033 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2034 if (l >= 4 && ((addr & 3) == 0)) {
2035 /* 32 bit read access */
2036 val = ldl_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002037 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002038 l = 4;
2039 } else if (l >= 2 && ((addr & 1) == 0)) {
2040 /* 16 bit read access */
2041 val = lduw_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002042 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002043 l = 2;
2044 } else {
2045 /* 8 bit access */
2046 val = ldub_raw(buf);
bellarda4193c82004-06-03 14:01:43 +00002047 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002048 l = 1;
2049 }
2050 } else {
bellardb448f2f2004-02-25 23:24:04 +00002051 unsigned long addr1;
2052 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002053 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002054 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002055 memcpy(ptr, buf, l);
bellardb448f2f2004-02-25 23:24:04 +00002056 /* invalidate code */
2057 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2058 /* set dirty bit */
2059 phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1;
bellard13eb76e2004-01-24 15:23:36 +00002060 }
2061 } else {
2062 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2063 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
2064 /* I/O case */
2065 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2066 if (l >= 4 && ((addr & 3) == 0)) {
2067 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002068 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002069 stl_raw(buf, val);
2070 l = 4;
2071 } else if (l >= 2 && ((addr & 1) == 0)) {
2072 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002073 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002074 stw_raw(buf, val);
2075 l = 2;
2076 } else {
2077 /* 8 bit access */
bellarda4193c82004-06-03 14:01:43 +00002078 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellard13eb76e2004-01-24 15:23:36 +00002079 stb_raw(buf, val);
2080 l = 1;
2081 }
2082 } else {
2083 /* RAM case */
2084 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
2085 (addr & ~TARGET_PAGE_MASK);
2086 memcpy(buf, ptr, l);
2087 }
2088 }
2089 len -= l;
2090 buf += l;
2091 addr += l;
2092 }
2093}
2094#endif
2095
2096/* virtual memory access for debug */
bellardb448f2f2004-02-25 23:24:04 +00002097int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2098 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002099{
2100 int l;
2101 target_ulong page, phys_addr;
2102
2103 while (len > 0) {
2104 page = addr & TARGET_PAGE_MASK;
2105 phys_addr = cpu_get_phys_page_debug(env, page);
2106 /* if no physical page mapped, return an error */
2107 if (phys_addr == -1)
2108 return -1;
2109 l = (page + TARGET_PAGE_SIZE) - addr;
2110 if (l > len)
2111 l = len;
bellardb448f2f2004-02-25 23:24:04 +00002112 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2113 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002114 len -= l;
2115 buf += l;
2116 addr += l;
2117 }
2118 return 0;
2119}
2120
bellard61382a52003-10-27 21:22:23 +00002121#if !defined(CONFIG_USER_ONLY)
2122
2123#define MMUSUFFIX _cmmu
2124#define GETPC() NULL
2125#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00002126#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00002127
2128#define SHIFT 0
2129#include "softmmu_template.h"
2130
2131#define SHIFT 1
2132#include "softmmu_template.h"
2133
2134#define SHIFT 2
2135#include "softmmu_template.h"
2136
2137#define SHIFT 3
2138#include "softmmu_template.h"
2139
2140#undef env
2141
2142#endif