blob: 2cf0a6a5e3ef82512d0b463c82f2ef8501b01adb [file] [log] [blame]
bellard54936002003-05-13 00:25:15 +00001/*
bellardfd6ce8f2003-05-14 19:00:11 +00002 * virtual page mapping and translated block handling
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard54936002003-05-13 00:25:15 +00004 * 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
ths4fddf622007-12-17 04:42:29 +000022#define WIN32_LEAN_AND_MEAN
bellardd5a8f072004-09-29 21:15:28 +000023#include <windows.h>
24#else
bellarda98d49b2004-11-14 16:22:05 +000025#include <sys/types.h>
bellardd5a8f072004-09-29 21:15:28 +000026#include <sys/mman.h>
27#endif
bellard54936002003-05-13 00:25:15 +000028#include <stdlib.h>
29#include <stdio.h>
30#include <stdarg.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <inttypes.h>
35
bellard6180a182003-09-30 21:04:53 +000036#include "cpu.h"
37#include "exec-all.h"
aurel32ca10f862008-04-11 21:35:42 +000038#include "qemu-common.h"
bellardb67d9a52008-05-23 09:57:34 +000039#include "tcg.h"
pbrook53a59602006-03-25 19:31:22 +000040#if defined(CONFIG_USER_ONLY)
41#include <qemu.h>
42#endif
bellard54936002003-05-13 00:25:15 +000043
bellardfd6ce8f2003-05-14 19:00:11 +000044//#define DEBUG_TB_INVALIDATE
bellard66e85a22003-06-24 13:28:12 +000045//#define DEBUG_FLUSH
bellard9fa3e852004-01-04 18:06:42 +000046//#define DEBUG_TLB
pbrook67d3b952006-12-18 05:03:52 +000047//#define DEBUG_UNASSIGNED
bellardfd6ce8f2003-05-14 19:00:11 +000048
49/* make various TB consistency checks */
ths5fafdf22007-09-16 21:08:06 +000050//#define DEBUG_TB_CHECK
51//#define DEBUG_TLB_CHECK
bellardfd6ce8f2003-05-14 19:00:11 +000052
ths1196be32007-03-17 15:17:58 +000053//#define DEBUG_IOPORT
blueswir1db7b5422007-05-26 17:36:03 +000054//#define DEBUG_SUBPAGE
ths1196be32007-03-17 15:17:58 +000055
pbrook99773bd2006-04-16 15:14:59 +000056#if !defined(CONFIG_USER_ONLY)
57/* TB consistency checks only implemented for usermode emulation. */
58#undef DEBUG_TB_CHECK
59#endif
60
bellard9fa3e852004-01-04 18:06:42 +000061#define SMC_BITMAP_USE_THRESHOLD 10
62
63#define MMAP_AREA_START 0x00000000
64#define MMAP_AREA_END 0xa8000000
bellardfd6ce8f2003-05-14 19:00:11 +000065
bellard108c49b2005-07-24 12:55:09 +000066#if defined(TARGET_SPARC64)
67#define TARGET_PHYS_ADDR_SPACE_BITS 41
blueswir15dcb6b92007-05-19 12:58:30 +000068#elif defined(TARGET_SPARC)
69#define TARGET_PHYS_ADDR_SPACE_BITS 36
j_mayerbedb69e2007-04-05 20:08:21 +000070#elif defined(TARGET_ALPHA)
71#define TARGET_PHYS_ADDR_SPACE_BITS 42
72#define TARGET_VIRT_ADDR_SPACE_BITS 42
bellard108c49b2005-07-24 12:55:09 +000073#elif defined(TARGET_PPC64)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
aurel3200f82b82008-04-27 21:12:55 +000075#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
76#define TARGET_PHYS_ADDR_SPACE_BITS 42
77#elif defined(TARGET_I386) && !defined(USE_KQEMU)
78#define TARGET_PHYS_ADDR_SPACE_BITS 36
bellard108c49b2005-07-24 12:55:09 +000079#else
80/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
81#define TARGET_PHYS_ADDR_SPACE_BITS 32
82#endif
83
pbrookfab94c02008-05-24 13:56:15 +000084TranslationBlock *tbs;
bellard26a5f132008-05-28 12:30:31 +000085int code_gen_max_blocks;
bellard9fa3e852004-01-04 18:06:42 +000086TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
bellardfd6ce8f2003-05-14 19:00:11 +000087int nb_tbs;
bellardeb51d102003-05-14 21:51:13 +000088/* any access to the tbs or the page table must use this lock */
89spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
bellardfd6ce8f2003-05-14 19:00:11 +000090
bellard7cb69ca2008-05-10 10:55:51 +000091uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
bellard26a5f132008-05-28 12:30:31 +000092uint8_t *code_gen_buffer;
93unsigned long code_gen_buffer_size;
94/* threshold to flush the translated code buffer */
95unsigned long code_gen_buffer_max_size;
bellardfd6ce8f2003-05-14 19:00:11 +000096uint8_t *code_gen_ptr;
97
pbrooke2eef172008-06-08 01:09:01 +000098#if !defined(CONFIG_USER_ONLY)
aurel3200f82b82008-04-27 21:12:55 +000099ram_addr_t phys_ram_size;
bellard9fa3e852004-01-04 18:06:42 +0000100int phys_ram_fd;
101uint8_t *phys_ram_base;
bellard1ccde1c2004-02-06 19:46:14 +0000102uint8_t *phys_ram_dirty;
bellarde9a1ab12007-02-08 23:08:38 +0000103static ram_addr_t phys_ram_alloc_offset = 0;
pbrooke2eef172008-06-08 01:09:01 +0000104#endif
bellard9fa3e852004-01-04 18:06:42 +0000105
bellard6a00d602005-11-21 23:25:50 +0000106CPUState *first_cpu;
107/* current CPU in the current thread. It is only valid inside
108 cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000109CPUState *cpu_single_env;
bellard6a00d602005-11-21 23:25:50 +0000110
bellard54936002003-05-13 00:25:15 +0000111typedef struct PageDesc {
bellard92e873b2004-05-21 14:52:29 +0000112 /* list of TBs intersecting this ram page */
bellardfd6ce8f2003-05-14 19:00:11 +0000113 TranslationBlock *first_tb;
bellard9fa3e852004-01-04 18:06:42 +0000114 /* in order to optimize self modifying code, we count the number
115 of lookups we do to a given page to use a bitmap */
116 unsigned int code_write_count;
117 uint8_t *code_bitmap;
118#if defined(CONFIG_USER_ONLY)
119 unsigned long flags;
120#endif
bellard54936002003-05-13 00:25:15 +0000121} PageDesc;
122
bellard92e873b2004-05-21 14:52:29 +0000123typedef struct PhysPageDesc {
124 /* offset in host memory of the page + io_index in the low 12 bits */
aurel3200f82b82008-04-27 21:12:55 +0000125 ram_addr_t phys_offset;
bellard92e873b2004-05-21 14:52:29 +0000126} PhysPageDesc;
127
bellard54936002003-05-13 00:25:15 +0000128#define L2_BITS 10
j_mayerbedb69e2007-04-05 20:08:21 +0000129#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
130/* XXX: this is a temporary hack for alpha target.
131 * In the future, this is to be replaced by a multi-level table
132 * to actually be able to handle the complete 64 bits address space.
133 */
134#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
135#else
aurel3203875442008-04-22 20:45:18 +0000136#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
j_mayerbedb69e2007-04-05 20:08:21 +0000137#endif
bellard54936002003-05-13 00:25:15 +0000138
139#define L1_SIZE (1 << L1_BITS)
140#define L2_SIZE (1 << L2_BITS)
141
bellard83fb7ad2004-07-05 21:25:26 +0000142unsigned long qemu_real_host_page_size;
143unsigned long qemu_host_page_bits;
144unsigned long qemu_host_page_size;
145unsigned long qemu_host_page_mask;
bellard54936002003-05-13 00:25:15 +0000146
bellard92e873b2004-05-21 14:52:29 +0000147/* XXX: for system emulation, it could just be an array */
bellard54936002003-05-13 00:25:15 +0000148static PageDesc *l1_map[L1_SIZE];
bellard0a962c02005-02-10 22:00:27 +0000149PhysPageDesc **l1_phys_map;
bellard54936002003-05-13 00:25:15 +0000150
pbrooke2eef172008-06-08 01:09:01 +0000151#if !defined(CONFIG_USER_ONLY)
152static void io_mem_init(void);
153
bellard33417e72003-08-10 21:47:01 +0000154/* io memory support */
bellard33417e72003-08-10 21:47:01 +0000155CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
156CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
bellarda4193c82004-06-03 14:01:43 +0000157void *io_mem_opaque[IO_MEM_NB_ENTRIES];
bellard33417e72003-08-10 21:47:01 +0000158static int io_mem_nb;
pbrook6658ffb2007-03-16 23:58:11 +0000159static int io_mem_watch;
160#endif
bellard33417e72003-08-10 21:47:01 +0000161
bellard34865132003-10-05 14:28:56 +0000162/* log support */
163char *logfilename = "/tmp/qemu.log";
164FILE *logfile;
165int loglevel;
pbrooke735b912007-06-30 13:53:24 +0000166static int log_append = 0;
bellard34865132003-10-05 14:28:56 +0000167
bellarde3db7222005-01-26 22:00:47 +0000168/* statistics */
169static int tlb_flush_count;
170static int tb_flush_count;
171static int tb_phys_invalidate_count;
172
blueswir1db7b5422007-05-26 17:36:03 +0000173#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
174typedef struct subpage_t {
175 target_phys_addr_t base;
blueswir13ee89922008-01-02 19:45:26 +0000176 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
177 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
178 void *opaque[TARGET_PAGE_SIZE][2][4];
blueswir1db7b5422007-05-26 17:36:03 +0000179} subpage_t;
180
bellard7cb69ca2008-05-10 10:55:51 +0000181#ifdef _WIN32
182static void map_exec(void *addr, long size)
183{
184 DWORD old_protect;
185 VirtualProtect(addr, size,
186 PAGE_EXECUTE_READWRITE, &old_protect);
187
188}
189#else
190static void map_exec(void *addr, long size)
191{
bellard43694152008-05-29 09:35:57 +0000192 unsigned long start, end, page_size;
bellard7cb69ca2008-05-10 10:55:51 +0000193
bellard43694152008-05-29 09:35:57 +0000194 page_size = getpagesize();
bellard7cb69ca2008-05-10 10:55:51 +0000195 start = (unsigned long)addr;
bellard43694152008-05-29 09:35:57 +0000196 start &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000197
198 end = (unsigned long)addr + size;
bellard43694152008-05-29 09:35:57 +0000199 end += page_size - 1;
200 end &= ~(page_size - 1);
bellard7cb69ca2008-05-10 10:55:51 +0000201
202 mprotect((void *)start, end - start,
203 PROT_READ | PROT_WRITE | PROT_EXEC);
204}
205#endif
206
bellardb346ff42003-06-15 20:05:50 +0000207static void page_init(void)
bellard54936002003-05-13 00:25:15 +0000208{
bellard83fb7ad2004-07-05 21:25:26 +0000209 /* NOTE: we can always suppose that qemu_host_page_size >=
bellard54936002003-05-13 00:25:15 +0000210 TARGET_PAGE_SIZE */
bellard67b915a2004-03-31 23:37:16 +0000211#ifdef _WIN32
bellardd5a8f072004-09-29 21:15:28 +0000212 {
213 SYSTEM_INFO system_info;
214 DWORD old_protect;
ths3b46e622007-09-17 08:09:54 +0000215
bellardd5a8f072004-09-29 21:15:28 +0000216 GetSystemInfo(&system_info);
217 qemu_real_host_page_size = system_info.dwPageSize;
bellardd5a8f072004-09-29 21:15:28 +0000218 }
bellard67b915a2004-03-31 23:37:16 +0000219#else
bellard83fb7ad2004-07-05 21:25:26 +0000220 qemu_real_host_page_size = getpagesize();
bellard67b915a2004-03-31 23:37:16 +0000221#endif
bellard83fb7ad2004-07-05 21:25:26 +0000222 if (qemu_host_page_size == 0)
223 qemu_host_page_size = qemu_real_host_page_size;
224 if (qemu_host_page_size < TARGET_PAGE_SIZE)
225 qemu_host_page_size = TARGET_PAGE_SIZE;
226 qemu_host_page_bits = 0;
227 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
228 qemu_host_page_bits++;
229 qemu_host_page_mask = ~(qemu_host_page_size - 1);
bellard108c49b2005-07-24 12:55:09 +0000230 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
231 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
balrog50a95692007-12-12 01:16:23 +0000232
233#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
234 {
235 long long startaddr, endaddr;
236 FILE *f;
237 int n;
238
pbrookc8a706f2008-06-02 16:16:42 +0000239 mmap_lock();
pbrook07765902008-05-31 16:33:53 +0000240 last_brk = (unsigned long)sbrk(0);
balrog50a95692007-12-12 01:16:23 +0000241 f = fopen("/proc/self/maps", "r");
242 if (f) {
243 do {
244 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
245 if (n == 2) {
blueswir1e0b8d652008-05-03 17:51:24 +0000246 startaddr = MIN(startaddr,
247 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
248 endaddr = MIN(endaddr,
249 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
pbrookb5fc9092008-05-29 13:56:10 +0000250 page_set_flags(startaddr & TARGET_PAGE_MASK,
balrog50a95692007-12-12 01:16:23 +0000251 TARGET_PAGE_ALIGN(endaddr),
252 PAGE_RESERVED);
253 }
254 } while (!feof(f));
255 fclose(f);
256 }
pbrookc8a706f2008-06-02 16:16:42 +0000257 mmap_unlock();
balrog50a95692007-12-12 01:16:23 +0000258 }
259#endif
bellard54936002003-05-13 00:25:15 +0000260}
261
aurel3200f82b82008-04-27 21:12:55 +0000262static inline PageDesc *page_find_alloc(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000263{
bellard54936002003-05-13 00:25:15 +0000264 PageDesc **lp, *p;
265
bellard54936002003-05-13 00:25:15 +0000266 lp = &l1_map[index >> L2_BITS];
267 p = *lp;
268 if (!p) {
269 /* allocate if not found */
bellard59817cc2004-02-16 22:01:13 +0000270 p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
bellardfd6ce8f2003-05-14 19:00:11 +0000271 memset(p, 0, sizeof(PageDesc) * L2_SIZE);
bellard54936002003-05-13 00:25:15 +0000272 *lp = p;
273 }
274 return p + (index & (L2_SIZE - 1));
275}
276
aurel3200f82b82008-04-27 21:12:55 +0000277static inline PageDesc *page_find(target_ulong index)
bellard54936002003-05-13 00:25:15 +0000278{
bellard54936002003-05-13 00:25:15 +0000279 PageDesc *p;
280
bellard54936002003-05-13 00:25:15 +0000281 p = l1_map[index >> L2_BITS];
282 if (!p)
283 return 0;
bellardfd6ce8f2003-05-14 19:00:11 +0000284 return p + (index & (L2_SIZE - 1));
bellard54936002003-05-13 00:25:15 +0000285}
286
bellard108c49b2005-07-24 12:55:09 +0000287static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
bellard92e873b2004-05-21 14:52:29 +0000288{
bellard108c49b2005-07-24 12:55:09 +0000289 void **lp, **p;
pbrooke3f4e2a2006-04-08 20:02:06 +0000290 PhysPageDesc *pd;
bellard92e873b2004-05-21 14:52:29 +0000291
bellard108c49b2005-07-24 12:55:09 +0000292 p = (void **)l1_phys_map;
293#if TARGET_PHYS_ADDR_SPACE_BITS > 32
294
295#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
296#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
297#endif
298 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000299 p = *lp;
300 if (!p) {
301 /* allocate if not found */
bellard108c49b2005-07-24 12:55:09 +0000302 if (!alloc)
303 return NULL;
304 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
305 memset(p, 0, sizeof(void *) * L1_SIZE);
306 *lp = p;
307 }
308#endif
309 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
pbrooke3f4e2a2006-04-08 20:02:06 +0000310 pd = *lp;
311 if (!pd) {
312 int i;
bellard108c49b2005-07-24 12:55:09 +0000313 /* allocate if not found */
314 if (!alloc)
315 return NULL;
pbrooke3f4e2a2006-04-08 20:02:06 +0000316 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
317 *lp = pd;
318 for (i = 0; i < L2_SIZE; i++)
319 pd[i].phys_offset = IO_MEM_UNASSIGNED;
bellard92e873b2004-05-21 14:52:29 +0000320 }
pbrooke3f4e2a2006-04-08 20:02:06 +0000321 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
bellard92e873b2004-05-21 14:52:29 +0000322}
323
bellard108c49b2005-07-24 12:55:09 +0000324static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
bellard92e873b2004-05-21 14:52:29 +0000325{
bellard108c49b2005-07-24 12:55:09 +0000326 return phys_page_find_alloc(index, 0);
bellard92e873b2004-05-21 14:52:29 +0000327}
328
bellard9fa3e852004-01-04 18:06:42 +0000329#if !defined(CONFIG_USER_ONLY)
bellard6a00d602005-11-21 23:25:50 +0000330static void tlb_protect_code(ram_addr_t ram_addr);
ths5fafdf22007-09-16 21:08:06 +0000331static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +0000332 target_ulong vaddr);
pbrookc8a706f2008-06-02 16:16:42 +0000333#define mmap_lock() do { } while(0)
334#define mmap_unlock() do { } while(0)
bellard9fa3e852004-01-04 18:06:42 +0000335#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000336
bellard43694152008-05-29 09:35:57 +0000337#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
338
339#if defined(CONFIG_USER_ONLY)
340/* Currently it is not recommanded to allocate big chunks of data in
341 user mode. It will change when a dedicated libc will be used */
342#define USE_STATIC_CODE_GEN_BUFFER
343#endif
344
345#ifdef USE_STATIC_CODE_GEN_BUFFER
346static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
347#endif
348
bellard26a5f132008-05-28 12:30:31 +0000349void code_gen_alloc(unsigned long tb_size)
350{
bellard43694152008-05-29 09:35:57 +0000351#ifdef USE_STATIC_CODE_GEN_BUFFER
352 code_gen_buffer = static_code_gen_buffer;
353 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
354 map_exec(code_gen_buffer, code_gen_buffer_size);
355#else
bellard26a5f132008-05-28 12:30:31 +0000356 code_gen_buffer_size = tb_size;
357 if (code_gen_buffer_size == 0) {
bellard43694152008-05-29 09:35:57 +0000358#if defined(CONFIG_USER_ONLY)
359 /* in user mode, phys_ram_size is not meaningful */
360 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
361#else
bellard26a5f132008-05-28 12:30:31 +0000362 /* XXX: needs ajustments */
363 code_gen_buffer_size = (int)(phys_ram_size / 4);
bellard43694152008-05-29 09:35:57 +0000364#endif
bellard26a5f132008-05-28 12:30:31 +0000365 }
366 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
367 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
368 /* The code gen buffer location may have constraints depending on
369 the host cpu and OS */
370#if defined(__linux__)
371 {
372 int flags;
373 flags = MAP_PRIVATE | MAP_ANONYMOUS;
374#if defined(__x86_64__)
375 flags |= MAP_32BIT;
376 /* Cannot map more than that */
377 if (code_gen_buffer_size > (800 * 1024 * 1024))
378 code_gen_buffer_size = (800 * 1024 * 1024);
379#endif
380 code_gen_buffer = mmap(NULL, code_gen_buffer_size,
381 PROT_WRITE | PROT_READ | PROT_EXEC,
382 flags, -1, 0);
383 if (code_gen_buffer == MAP_FAILED) {
384 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
385 exit(1);
386 }
387 }
388#else
389 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
390 if (!code_gen_buffer) {
391 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
392 exit(1);
393 }
394 map_exec(code_gen_buffer, code_gen_buffer_size);
395#endif
bellard43694152008-05-29 09:35:57 +0000396#endif /* !USE_STATIC_CODE_GEN_BUFFER */
bellard26a5f132008-05-28 12:30:31 +0000397 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
398 code_gen_buffer_max_size = code_gen_buffer_size -
399 code_gen_max_block_size();
400 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
401 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
402}
403
404/* Must be called before using the QEMU cpus. 'tb_size' is the size
405 (in bytes) allocated to the translation buffer. Zero means default
406 size. */
407void cpu_exec_init_all(unsigned long tb_size)
408{
bellard26a5f132008-05-28 12:30:31 +0000409 cpu_gen_init();
410 code_gen_alloc(tb_size);
411 code_gen_ptr = code_gen_buffer;
bellard43694152008-05-29 09:35:57 +0000412 page_init();
pbrooke2eef172008-06-08 01:09:01 +0000413#if !defined(CONFIG_USER_ONLY)
bellard26a5f132008-05-28 12:30:31 +0000414 io_mem_init();
pbrooke2eef172008-06-08 01:09:01 +0000415#endif
bellard26a5f132008-05-28 12:30:31 +0000416}
417
bellard6a00d602005-11-21 23:25:50 +0000418void cpu_exec_init(CPUState *env)
bellardfd6ce8f2003-05-14 19:00:11 +0000419{
bellard6a00d602005-11-21 23:25:50 +0000420 CPUState **penv;
421 int cpu_index;
422
bellard6a00d602005-11-21 23:25:50 +0000423 env->next_cpu = NULL;
424 penv = &first_cpu;
425 cpu_index = 0;
426 while (*penv != NULL) {
427 penv = (CPUState **)&(*penv)->next_cpu;
428 cpu_index++;
429 }
430 env->cpu_index = cpu_index;
pbrook6658ffb2007-03-16 23:58:11 +0000431 env->nb_watchpoints = 0;
bellard6a00d602005-11-21 23:25:50 +0000432 *penv = env;
bellardfd6ce8f2003-05-14 19:00:11 +0000433}
434
bellard9fa3e852004-01-04 18:06:42 +0000435static inline void invalidate_page_bitmap(PageDesc *p)
436{
437 if (p->code_bitmap) {
bellard59817cc2004-02-16 22:01:13 +0000438 qemu_free(p->code_bitmap);
bellard9fa3e852004-01-04 18:06:42 +0000439 p->code_bitmap = NULL;
440 }
441 p->code_write_count = 0;
442}
443
bellardfd6ce8f2003-05-14 19:00:11 +0000444/* set to NULL all the 'first_tb' fields in all PageDescs */
445static void page_flush_tb(void)
446{
447 int i, j;
448 PageDesc *p;
449
450 for(i = 0; i < L1_SIZE; i++) {
451 p = l1_map[i];
452 if (p) {
bellard9fa3e852004-01-04 18:06:42 +0000453 for(j = 0; j < L2_SIZE; j++) {
454 p->first_tb = NULL;
455 invalidate_page_bitmap(p);
456 p++;
457 }
bellardfd6ce8f2003-05-14 19:00:11 +0000458 }
459 }
460}
461
462/* flush all the translation blocks */
bellardd4e81642003-05-25 16:46:15 +0000463/* XXX: tb_flush is currently not thread safe */
bellard6a00d602005-11-21 23:25:50 +0000464void tb_flush(CPUState *env1)
bellardfd6ce8f2003-05-14 19:00:11 +0000465{
bellard6a00d602005-11-21 23:25:50 +0000466 CPUState *env;
bellard01243112004-01-04 15:48:17 +0000467#if defined(DEBUG_FLUSH)
blueswir1ab3d1722007-11-04 07:31:40 +0000468 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
469 (unsigned long)(code_gen_ptr - code_gen_buffer),
470 nb_tbs, nb_tbs > 0 ?
471 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
bellardfd6ce8f2003-05-14 19:00:11 +0000472#endif
bellard26a5f132008-05-28 12:30:31 +0000473 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
pbrooka208e542008-03-31 17:07:36 +0000474 cpu_abort(env1, "Internal error: code buffer overflow\n");
475
bellardfd6ce8f2003-05-14 19:00:11 +0000476 nb_tbs = 0;
ths3b46e622007-09-17 08:09:54 +0000477
bellard6a00d602005-11-21 23:25:50 +0000478 for(env = first_cpu; env != NULL; env = env->next_cpu) {
479 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
480 }
bellard9fa3e852004-01-04 18:06:42 +0000481
bellard8a8a6082004-10-03 13:36:49 +0000482 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
bellardfd6ce8f2003-05-14 19:00:11 +0000483 page_flush_tb();
bellard9fa3e852004-01-04 18:06:42 +0000484
bellardfd6ce8f2003-05-14 19:00:11 +0000485 code_gen_ptr = code_gen_buffer;
bellardd4e81642003-05-25 16:46:15 +0000486 /* XXX: flush processor icache at this point if cache flush is
487 expensive */
bellarde3db7222005-01-26 22:00:47 +0000488 tb_flush_count++;
bellardfd6ce8f2003-05-14 19:00:11 +0000489}
490
491#ifdef DEBUG_TB_CHECK
492
j_mayerbc98a7e2007-04-04 07:55:12 +0000493static void tb_invalidate_check(target_ulong address)
bellardfd6ce8f2003-05-14 19:00:11 +0000494{
495 TranslationBlock *tb;
496 int i;
497 address &= TARGET_PAGE_MASK;
pbrook99773bd2006-04-16 15:14:59 +0000498 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
499 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000500 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
501 address >= tb->pc + tb->size)) {
502 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
pbrook99773bd2006-04-16 15:14:59 +0000503 address, (long)tb->pc, tb->size);
bellardfd6ce8f2003-05-14 19:00:11 +0000504 }
505 }
506 }
507}
508
509/* verify that all the pages have correct rights for code */
510static void tb_page_check(void)
511{
512 TranslationBlock *tb;
513 int i, flags1, flags2;
ths3b46e622007-09-17 08:09:54 +0000514
pbrook99773bd2006-04-16 15:14:59 +0000515 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
516 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
bellardfd6ce8f2003-05-14 19:00:11 +0000517 flags1 = page_get_flags(tb->pc);
518 flags2 = page_get_flags(tb->pc + tb->size - 1);
519 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
520 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
pbrook99773bd2006-04-16 15:14:59 +0000521 (long)tb->pc, tb->size, flags1, flags2);
bellardfd6ce8f2003-05-14 19:00:11 +0000522 }
523 }
524 }
525}
526
bellardd4e81642003-05-25 16:46:15 +0000527void tb_jmp_check(TranslationBlock *tb)
528{
529 TranslationBlock *tb1;
530 unsigned int n1;
531
532 /* suppress any remaining jumps to this TB */
533 tb1 = tb->jmp_first;
534 for(;;) {
535 n1 = (long)tb1 & 3;
536 tb1 = (TranslationBlock *)((long)tb1 & ~3);
537 if (n1 == 2)
538 break;
539 tb1 = tb1->jmp_next[n1];
540 }
541 /* check end of list */
542 if (tb1 != tb) {
543 printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
544 }
545}
546
bellardfd6ce8f2003-05-14 19:00:11 +0000547#endif
548
549/* invalidate one TB */
550static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
551 int next_offset)
552{
553 TranslationBlock *tb1;
554 for(;;) {
555 tb1 = *ptb;
556 if (tb1 == tb) {
557 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
558 break;
559 }
560 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
561 }
562}
563
bellard9fa3e852004-01-04 18:06:42 +0000564static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
565{
566 TranslationBlock *tb1;
567 unsigned int n1;
568
569 for(;;) {
570 tb1 = *ptb;
571 n1 = (long)tb1 & 3;
572 tb1 = (TranslationBlock *)((long)tb1 & ~3);
573 if (tb1 == tb) {
574 *ptb = tb1->page_next[n1];
575 break;
576 }
577 ptb = &tb1->page_next[n1];
578 }
579}
580
bellardd4e81642003-05-25 16:46:15 +0000581static inline void tb_jmp_remove(TranslationBlock *tb, int n)
582{
583 TranslationBlock *tb1, **ptb;
584 unsigned int n1;
585
586 ptb = &tb->jmp_next[n];
587 tb1 = *ptb;
588 if (tb1) {
589 /* find tb(n) in circular list */
590 for(;;) {
591 tb1 = *ptb;
592 n1 = (long)tb1 & 3;
593 tb1 = (TranslationBlock *)((long)tb1 & ~3);
594 if (n1 == n && tb1 == tb)
595 break;
596 if (n1 == 2) {
597 ptb = &tb1->jmp_first;
598 } else {
599 ptb = &tb1->jmp_next[n1];
600 }
601 }
602 /* now we can suppress tb(n) from the list */
603 *ptb = tb->jmp_next[n];
604
605 tb->jmp_next[n] = NULL;
606 }
607}
608
609/* reset the jump entry 'n' of a TB so that it is not chained to
610 another TB */
611static inline void tb_reset_jump(TranslationBlock *tb, int n)
612{
613 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
614}
615
aurel3200f82b82008-04-27 21:12:55 +0000616static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000617{
bellard6a00d602005-11-21 23:25:50 +0000618 CPUState *env;
bellardfd6ce8f2003-05-14 19:00:11 +0000619 PageDesc *p;
bellard8a40a182005-11-20 10:35:40 +0000620 unsigned int h, n1;
aurel3200f82b82008-04-27 21:12:55 +0000621 target_phys_addr_t phys_pc;
bellard8a40a182005-11-20 10:35:40 +0000622 TranslationBlock *tb1, *tb2;
ths3b46e622007-09-17 08:09:54 +0000623
bellard9fa3e852004-01-04 18:06:42 +0000624 /* remove the TB from the hash list */
625 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
626 h = tb_phys_hash_func(phys_pc);
ths5fafdf22007-09-16 21:08:06 +0000627 tb_remove(&tb_phys_hash[h], tb,
bellard9fa3e852004-01-04 18:06:42 +0000628 offsetof(TranslationBlock, phys_hash_next));
bellardfd6ce8f2003-05-14 19:00:11 +0000629
bellard9fa3e852004-01-04 18:06:42 +0000630 /* remove the TB from the page list */
631 if (tb->page_addr[0] != page_addr) {
632 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
633 tb_page_remove(&p->first_tb, tb);
634 invalidate_page_bitmap(p);
635 }
636 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
637 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
638 tb_page_remove(&p->first_tb, tb);
639 invalidate_page_bitmap(p);
640 }
641
bellard8a40a182005-11-20 10:35:40 +0000642 tb_invalidated_flag = 1;
643
644 /* remove the TB from the hash list */
645 h = tb_jmp_cache_hash_func(tb->pc);
bellard6a00d602005-11-21 23:25:50 +0000646 for(env = first_cpu; env != NULL; env = env->next_cpu) {
647 if (env->tb_jmp_cache[h] == tb)
648 env->tb_jmp_cache[h] = NULL;
649 }
bellard8a40a182005-11-20 10:35:40 +0000650
651 /* suppress this TB from the two jump lists */
652 tb_jmp_remove(tb, 0);
653 tb_jmp_remove(tb, 1);
654
655 /* suppress any remaining jumps to this TB */
656 tb1 = tb->jmp_first;
657 for(;;) {
658 n1 = (long)tb1 & 3;
659 if (n1 == 2)
660 break;
661 tb1 = (TranslationBlock *)((long)tb1 & ~3);
662 tb2 = tb1->jmp_next[n1];
663 tb_reset_jump(tb1, n1);
664 tb1->jmp_next[n1] = NULL;
665 tb1 = tb2;
666 }
667 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
668
bellarde3db7222005-01-26 22:00:47 +0000669 tb_phys_invalidate_count++;
bellard9fa3e852004-01-04 18:06:42 +0000670}
671
672static inline void set_bits(uint8_t *tab, int start, int len)
673{
674 int end, mask, end1;
675
676 end = start + len;
677 tab += start >> 3;
678 mask = 0xff << (start & 7);
679 if ((start & ~7) == (end & ~7)) {
680 if (start < end) {
681 mask &= ~(0xff << (end & 7));
682 *tab |= mask;
683 }
684 } else {
685 *tab++ |= mask;
686 start = (start + 8) & ~7;
687 end1 = end & ~7;
688 while (start < end1) {
689 *tab++ = 0xff;
690 start += 8;
691 }
692 if (start < end) {
693 mask = ~(0xff << (end & 7));
694 *tab |= mask;
695 }
696 }
697}
698
699static void build_page_bitmap(PageDesc *p)
700{
701 int n, tb_start, tb_end;
702 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +0000703
bellard59817cc2004-02-16 22:01:13 +0000704 p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
bellard9fa3e852004-01-04 18:06:42 +0000705 if (!p->code_bitmap)
706 return;
707 memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
708
709 tb = p->first_tb;
710 while (tb != NULL) {
711 n = (long)tb & 3;
712 tb = (TranslationBlock *)((long)tb & ~3);
713 /* NOTE: this is subtle as a TB may span two physical pages */
714 if (n == 0) {
715 /* NOTE: tb_end may be after the end of the page, but
716 it is not a problem */
717 tb_start = tb->pc & ~TARGET_PAGE_MASK;
718 tb_end = tb_start + tb->size;
719 if (tb_end > TARGET_PAGE_SIZE)
720 tb_end = TARGET_PAGE_SIZE;
721 } else {
722 tb_start = 0;
723 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
724 }
725 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
726 tb = tb->page_next[n];
727 }
728}
729
bellardd720b932004-04-25 17:57:43 +0000730#ifdef TARGET_HAS_PRECISE_SMC
731
ths5fafdf22007-09-16 21:08:06 +0000732static void tb_gen_code(CPUState *env,
bellardd720b932004-04-25 17:57:43 +0000733 target_ulong pc, target_ulong cs_base, int flags,
734 int cflags)
735{
736 TranslationBlock *tb;
737 uint8_t *tc_ptr;
738 target_ulong phys_pc, phys_page2, virt_page2;
739 int code_gen_size;
740
bellardc27004e2005-01-03 23:35:10 +0000741 phys_pc = get_phys_addr_code(env, pc);
742 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000743 if (!tb) {
744 /* flush must be done */
745 tb_flush(env);
746 /* cannot fail at this point */
bellardc27004e2005-01-03 23:35:10 +0000747 tb = tb_alloc(pc);
bellardd720b932004-04-25 17:57:43 +0000748 }
749 tc_ptr = code_gen_ptr;
750 tb->tc_ptr = tc_ptr;
751 tb->cs_base = cs_base;
752 tb->flags = flags;
753 tb->cflags = cflags;
blueswir1d07bde82007-12-11 19:35:45 +0000754 cpu_gen_code(env, tb, &code_gen_size);
bellardd720b932004-04-25 17:57:43 +0000755 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
ths3b46e622007-09-17 08:09:54 +0000756
bellardd720b932004-04-25 17:57:43 +0000757 /* check next page if needed */
bellardc27004e2005-01-03 23:35:10 +0000758 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellardd720b932004-04-25 17:57:43 +0000759 phys_page2 = -1;
bellardc27004e2005-01-03 23:35:10 +0000760 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellardd720b932004-04-25 17:57:43 +0000761 phys_page2 = get_phys_addr_code(env, virt_page2);
762 }
763 tb_link_phys(tb, phys_pc, phys_page2);
764}
765#endif
ths3b46e622007-09-17 08:09:54 +0000766
bellard9fa3e852004-01-04 18:06:42 +0000767/* invalidate all TBs which intersect with the target physical page
768 starting in range [start;end[. NOTE: start and end must refer to
bellardd720b932004-04-25 17:57:43 +0000769 the same physical page. 'is_cpu_write_access' should be true if called
770 from a real cpu write access: the virtual CPU will exit the current
771 TB if code is modified inside this TB. */
aurel3200f82b82008-04-27 21:12:55 +0000772void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
bellardd720b932004-04-25 17:57:43 +0000773 int is_cpu_write_access)
bellard9fa3e852004-01-04 18:06:42 +0000774{
bellardd720b932004-04-25 17:57:43 +0000775 int n, current_tb_modified, current_tb_not_found, current_flags;
bellardd720b932004-04-25 17:57:43 +0000776 CPUState *env = cpu_single_env;
bellard9fa3e852004-01-04 18:06:42 +0000777 PageDesc *p;
bellardea1c1802004-06-14 18:56:36 +0000778 TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
bellard9fa3e852004-01-04 18:06:42 +0000779 target_ulong tb_start, tb_end;
bellardd720b932004-04-25 17:57:43 +0000780 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000781
782 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000783 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000784 return;
ths5fafdf22007-09-16 21:08:06 +0000785 if (!p->code_bitmap &&
bellardd720b932004-04-25 17:57:43 +0000786 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
787 is_cpu_write_access) {
bellard9fa3e852004-01-04 18:06:42 +0000788 /* build code bitmap */
789 build_page_bitmap(p);
790 }
791
792 /* we remove all the TBs in the range [start, end[ */
793 /* XXX: see if in some cases it could be faster to invalidate all the code */
bellardd720b932004-04-25 17:57:43 +0000794 current_tb_not_found = is_cpu_write_access;
795 current_tb_modified = 0;
796 current_tb = NULL; /* avoid warning */
797 current_pc = 0; /* avoid warning */
798 current_cs_base = 0; /* avoid warning */
799 current_flags = 0; /* avoid warning */
bellard9fa3e852004-01-04 18:06:42 +0000800 tb = p->first_tb;
801 while (tb != NULL) {
802 n = (long)tb & 3;
803 tb = (TranslationBlock *)((long)tb & ~3);
804 tb_next = tb->page_next[n];
805 /* NOTE: this is subtle as a TB may span two physical pages */
806 if (n == 0) {
807 /* NOTE: tb_end may be after the end of the page, but
808 it is not a problem */
809 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
810 tb_end = tb_start + tb->size;
811 } else {
812 tb_start = tb->page_addr[1];
813 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
814 }
815 if (!(tb_end <= start || tb_start >= end)) {
bellardd720b932004-04-25 17:57:43 +0000816#ifdef TARGET_HAS_PRECISE_SMC
817 if (current_tb_not_found) {
818 current_tb_not_found = 0;
819 current_tb = NULL;
820 if (env->mem_write_pc) {
821 /* now we have a real cpu fault */
822 current_tb = tb_find_pc(env->mem_write_pc);
823 }
824 }
825 if (current_tb == tb &&
826 !(current_tb->cflags & CF_SINGLE_INSN)) {
827 /* If we are modifying the current TB, we must stop
828 its execution. We could be more precise by checking
829 that the modification is after the current PC, but it
830 would require a specialized function to partially
831 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000832
bellardd720b932004-04-25 17:57:43 +0000833 current_tb_modified = 1;
ths5fafdf22007-09-16 21:08:06 +0000834 cpu_restore_state(current_tb, env,
bellardd720b932004-04-25 17:57:43 +0000835 env->mem_write_pc, NULL);
836#if defined(TARGET_I386)
837 current_flags = env->hflags;
838 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
839 current_cs_base = (target_ulong)env->segs[R_CS].base;
840 current_pc = current_cs_base + env->eip;
841#else
842#error unsupported CPU
843#endif
844 }
845#endif /* TARGET_HAS_PRECISE_SMC */
bellard6f5a9f72005-11-26 20:12:28 +0000846 /* we need to do that to handle the case where a signal
847 occurs while doing tb_phys_invalidate() */
848 saved_tb = NULL;
849 if (env) {
850 saved_tb = env->current_tb;
851 env->current_tb = NULL;
852 }
bellard9fa3e852004-01-04 18:06:42 +0000853 tb_phys_invalidate(tb, -1);
bellard6f5a9f72005-11-26 20:12:28 +0000854 if (env) {
855 env->current_tb = saved_tb;
856 if (env->interrupt_request && env->current_tb)
857 cpu_interrupt(env, env->interrupt_request);
858 }
bellard9fa3e852004-01-04 18:06:42 +0000859 }
860 tb = tb_next;
861 }
862#if !defined(CONFIG_USER_ONLY)
863 /* if no code remaining, no need to continue to use slow writes */
864 if (!p->first_tb) {
865 invalidate_page_bitmap(p);
bellardd720b932004-04-25 17:57:43 +0000866 if (is_cpu_write_access) {
867 tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
868 }
869 }
870#endif
871#ifdef TARGET_HAS_PRECISE_SMC
872 if (current_tb_modified) {
873 /* we generate a block containing just the instruction
874 modifying the memory. It will ensure that it cannot modify
875 itself */
bellardea1c1802004-06-14 18:56:36 +0000876 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000877 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000878 CF_SINGLE_INSN);
879 cpu_resume_from_signal(env, NULL);
bellard9fa3e852004-01-04 18:06:42 +0000880 }
881#endif
882}
883
884/* len must be <= 8 and start must be a multiple of len */
aurel3200f82b82008-04-27 21:12:55 +0000885static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
bellard9fa3e852004-01-04 18:06:42 +0000886{
887 PageDesc *p;
888 int offset, b;
bellard59817cc2004-02-16 22:01:13 +0000889#if 0
bellarda4193c82004-06-03 14:01:43 +0000890 if (1) {
891 if (loglevel) {
ths5fafdf22007-09-16 21:08:06 +0000892 fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
893 cpu_single_env->mem_write_vaddr, len,
894 cpu_single_env->eip,
bellarda4193c82004-06-03 14:01:43 +0000895 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
896 }
bellard59817cc2004-02-16 22:01:13 +0000897 }
898#endif
bellard9fa3e852004-01-04 18:06:42 +0000899 p = page_find(start >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000900 if (!p)
bellard9fa3e852004-01-04 18:06:42 +0000901 return;
902 if (p->code_bitmap) {
903 offset = start & ~TARGET_PAGE_MASK;
904 b = p->code_bitmap[offset >> 3] >> (offset & 7);
905 if (b & ((1 << len) - 1))
906 goto do_invalidate;
907 } else {
908 do_invalidate:
bellardd720b932004-04-25 17:57:43 +0000909 tb_invalidate_phys_page_range(start, start + len, 1);
bellard9fa3e852004-01-04 18:06:42 +0000910 }
911}
912
bellard9fa3e852004-01-04 18:06:42 +0000913#if !defined(CONFIG_SOFTMMU)
aurel3200f82b82008-04-27 21:12:55 +0000914static void tb_invalidate_phys_page(target_phys_addr_t addr,
bellardd720b932004-04-25 17:57:43 +0000915 unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +0000916{
bellardd720b932004-04-25 17:57:43 +0000917 int n, current_flags, current_tb_modified;
918 target_ulong current_pc, current_cs_base;
bellard9fa3e852004-01-04 18:06:42 +0000919 PageDesc *p;
bellardd720b932004-04-25 17:57:43 +0000920 TranslationBlock *tb, *current_tb;
921#ifdef TARGET_HAS_PRECISE_SMC
922 CPUState *env = cpu_single_env;
923#endif
bellard9fa3e852004-01-04 18:06:42 +0000924
925 addr &= TARGET_PAGE_MASK;
926 p = page_find(addr >> TARGET_PAGE_BITS);
ths5fafdf22007-09-16 21:08:06 +0000927 if (!p)
bellardfd6ce8f2003-05-14 19:00:11 +0000928 return;
929 tb = p->first_tb;
bellardd720b932004-04-25 17:57:43 +0000930 current_tb_modified = 0;
931 current_tb = NULL;
932 current_pc = 0; /* avoid warning */
933 current_cs_base = 0; /* avoid warning */
934 current_flags = 0; /* avoid warning */
935#ifdef TARGET_HAS_PRECISE_SMC
936 if (tb && pc != 0) {
937 current_tb = tb_find_pc(pc);
938 }
939#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000940 while (tb != NULL) {
bellard9fa3e852004-01-04 18:06:42 +0000941 n = (long)tb & 3;
942 tb = (TranslationBlock *)((long)tb & ~3);
bellardd720b932004-04-25 17:57:43 +0000943#ifdef TARGET_HAS_PRECISE_SMC
944 if (current_tb == tb &&
945 !(current_tb->cflags & CF_SINGLE_INSN)) {
946 /* If we are modifying the current TB, we must stop
947 its execution. We could be more precise by checking
948 that the modification is after the current PC, but it
949 would require a specialized function to partially
950 restore the CPU state */
ths3b46e622007-09-17 08:09:54 +0000951
bellardd720b932004-04-25 17:57:43 +0000952 current_tb_modified = 1;
953 cpu_restore_state(current_tb, env, pc, puc);
954#if defined(TARGET_I386)
955 current_flags = env->hflags;
956 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
957 current_cs_base = (target_ulong)env->segs[R_CS].base;
958 current_pc = current_cs_base + env->eip;
959#else
960#error unsupported CPU
961#endif
962 }
963#endif /* TARGET_HAS_PRECISE_SMC */
bellard9fa3e852004-01-04 18:06:42 +0000964 tb_phys_invalidate(tb, addr);
965 tb = tb->page_next[n];
bellardfd6ce8f2003-05-14 19:00:11 +0000966 }
967 p->first_tb = NULL;
bellardd720b932004-04-25 17:57:43 +0000968#ifdef TARGET_HAS_PRECISE_SMC
969 if (current_tb_modified) {
970 /* we generate a block containing just the instruction
971 modifying the memory. It will ensure that it cannot modify
972 itself */
bellardea1c1802004-06-14 18:56:36 +0000973 env->current_tb = NULL;
ths5fafdf22007-09-16 21:08:06 +0000974 tb_gen_code(env, current_pc, current_cs_base, current_flags,
bellardd720b932004-04-25 17:57:43 +0000975 CF_SINGLE_INSN);
976 cpu_resume_from_signal(env, puc);
977 }
978#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000979}
bellard9fa3e852004-01-04 18:06:42 +0000980#endif
bellardfd6ce8f2003-05-14 19:00:11 +0000981
982/* add the tb in the target page and protect it if necessary */
ths5fafdf22007-09-16 21:08:06 +0000983static inline void tb_alloc_page(TranslationBlock *tb,
pbrook53a59602006-03-25 19:31:22 +0000984 unsigned int n, target_ulong page_addr)
bellardfd6ce8f2003-05-14 19:00:11 +0000985{
986 PageDesc *p;
bellard9fa3e852004-01-04 18:06:42 +0000987 TranslationBlock *last_first_tb;
bellardfd6ce8f2003-05-14 19:00:11 +0000988
bellard9fa3e852004-01-04 18:06:42 +0000989 tb->page_addr[n] = page_addr;
bellard3a7d9292005-08-21 09:26:42 +0000990 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +0000991 tb->page_next[n] = p->first_tb;
992 last_first_tb = p->first_tb;
993 p->first_tb = (TranslationBlock *)((long)tb | n);
994 invalidate_page_bitmap(p);
995
bellard107db442004-06-22 18:48:46 +0000996#if defined(TARGET_HAS_SMC) || 1
bellardd720b932004-04-25 17:57:43 +0000997
bellard9fa3e852004-01-04 18:06:42 +0000998#if defined(CONFIG_USER_ONLY)
bellardfd6ce8f2003-05-14 19:00:11 +0000999 if (p->flags & PAGE_WRITE) {
pbrook53a59602006-03-25 19:31:22 +00001000 target_ulong addr;
1001 PageDesc *p2;
bellard9fa3e852004-01-04 18:06:42 +00001002 int prot;
1003
bellardfd6ce8f2003-05-14 19:00:11 +00001004 /* force the host page as non writable (writes will have a
1005 page fault + mprotect overhead) */
pbrook53a59602006-03-25 19:31:22 +00001006 page_addr &= qemu_host_page_mask;
bellardfd6ce8f2003-05-14 19:00:11 +00001007 prot = 0;
pbrook53a59602006-03-25 19:31:22 +00001008 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1009 addr += TARGET_PAGE_SIZE) {
1010
1011 p2 = page_find (addr >> TARGET_PAGE_BITS);
1012 if (!p2)
1013 continue;
1014 prot |= p2->flags;
1015 p2->flags &= ~PAGE_WRITE;
1016 page_get_flags(addr);
1017 }
ths5fafdf22007-09-16 21:08:06 +00001018 mprotect(g2h(page_addr), qemu_host_page_size,
bellardfd6ce8f2003-05-14 19:00:11 +00001019 (prot & PAGE_BITS) & ~PAGE_WRITE);
1020#ifdef DEBUG_TB_INVALIDATE
blueswir1ab3d1722007-11-04 07:31:40 +00001021 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
pbrook53a59602006-03-25 19:31:22 +00001022 page_addr);
bellardfd6ce8f2003-05-14 19:00:11 +00001023#endif
bellardfd6ce8f2003-05-14 19:00:11 +00001024 }
bellard9fa3e852004-01-04 18:06:42 +00001025#else
1026 /* if some code is already present, then the pages are already
1027 protected. So we handle the case where only the first TB is
1028 allocated in a physical page */
1029 if (!last_first_tb) {
bellard6a00d602005-11-21 23:25:50 +00001030 tlb_protect_code(page_addr);
bellard9fa3e852004-01-04 18:06:42 +00001031 }
1032#endif
bellardd720b932004-04-25 17:57:43 +00001033
1034#endif /* TARGET_HAS_SMC */
bellardfd6ce8f2003-05-14 19:00:11 +00001035}
1036
1037/* Allocate a new translation block. Flush the translation buffer if
1038 too many translation blocks or too much generated code. */
bellardc27004e2005-01-03 23:35:10 +00001039TranslationBlock *tb_alloc(target_ulong pc)
bellardfd6ce8f2003-05-14 19:00:11 +00001040{
1041 TranslationBlock *tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001042
bellard26a5f132008-05-28 12:30:31 +00001043 if (nb_tbs >= code_gen_max_blocks ||
1044 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
bellardd4e81642003-05-25 16:46:15 +00001045 return NULL;
bellardfd6ce8f2003-05-14 19:00:11 +00001046 tb = &tbs[nb_tbs++];
1047 tb->pc = pc;
bellardb448f2f2004-02-25 23:24:04 +00001048 tb->cflags = 0;
bellardd4e81642003-05-25 16:46:15 +00001049 return tb;
1050}
1051
bellard9fa3e852004-01-04 18:06:42 +00001052/* add a new TB and link it to the physical page tables. phys_page2 is
1053 (-1) to indicate that only one page contains the TB. */
ths5fafdf22007-09-16 21:08:06 +00001054void tb_link_phys(TranslationBlock *tb,
bellard9fa3e852004-01-04 18:06:42 +00001055 target_ulong phys_pc, target_ulong phys_page2)
bellardd4e81642003-05-25 16:46:15 +00001056{
bellard9fa3e852004-01-04 18:06:42 +00001057 unsigned int h;
1058 TranslationBlock **ptb;
1059
pbrookc8a706f2008-06-02 16:16:42 +00001060 /* Grab the mmap lock to stop another thread invalidating this TB
1061 before we are done. */
1062 mmap_lock();
bellard9fa3e852004-01-04 18:06:42 +00001063 /* add in the physical hash table */
1064 h = tb_phys_hash_func(phys_pc);
1065 ptb = &tb_phys_hash[h];
1066 tb->phys_hash_next = *ptb;
1067 *ptb = tb;
bellardfd6ce8f2003-05-14 19:00:11 +00001068
1069 /* add in the page list */
bellard9fa3e852004-01-04 18:06:42 +00001070 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1071 if (phys_page2 != -1)
1072 tb_alloc_page(tb, 1, phys_page2);
1073 else
1074 tb->page_addr[1] = -1;
bellard9fa3e852004-01-04 18:06:42 +00001075
bellardd4e81642003-05-25 16:46:15 +00001076 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1077 tb->jmp_next[0] = NULL;
1078 tb->jmp_next[1] = NULL;
1079
1080 /* init original jump addresses */
1081 if (tb->tb_next_offset[0] != 0xffff)
1082 tb_reset_jump(tb, 0);
1083 if (tb->tb_next_offset[1] != 0xffff)
1084 tb_reset_jump(tb, 1);
bellard8a40a182005-11-20 10:35:40 +00001085
1086#ifdef DEBUG_TB_CHECK
1087 tb_page_check();
1088#endif
pbrookc8a706f2008-06-02 16:16:42 +00001089 mmap_unlock();
bellardfd6ce8f2003-05-14 19:00:11 +00001090}
1091
bellarda513fe12003-05-27 23:29:48 +00001092/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1093 tb[1].tc_ptr. Return NULL if not found */
1094TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1095{
1096 int m_min, m_max, m;
1097 unsigned long v;
1098 TranslationBlock *tb;
1099
1100 if (nb_tbs <= 0)
1101 return NULL;
1102 if (tc_ptr < (unsigned long)code_gen_buffer ||
1103 tc_ptr >= (unsigned long)code_gen_ptr)
1104 return NULL;
1105 /* binary search (cf Knuth) */
1106 m_min = 0;
1107 m_max = nb_tbs - 1;
1108 while (m_min <= m_max) {
1109 m = (m_min + m_max) >> 1;
1110 tb = &tbs[m];
1111 v = (unsigned long)tb->tc_ptr;
1112 if (v == tc_ptr)
1113 return tb;
1114 else if (tc_ptr < v) {
1115 m_max = m - 1;
1116 } else {
1117 m_min = m + 1;
1118 }
ths5fafdf22007-09-16 21:08:06 +00001119 }
bellarda513fe12003-05-27 23:29:48 +00001120 return &tbs[m_max];
1121}
bellard75012672003-06-21 13:11:07 +00001122
bellardea041c02003-06-25 16:16:50 +00001123static void tb_reset_jump_recursive(TranslationBlock *tb);
1124
1125static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1126{
1127 TranslationBlock *tb1, *tb_next, **ptb;
1128 unsigned int n1;
1129
1130 tb1 = tb->jmp_next[n];
1131 if (tb1 != NULL) {
1132 /* find head of list */
1133 for(;;) {
1134 n1 = (long)tb1 & 3;
1135 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1136 if (n1 == 2)
1137 break;
1138 tb1 = tb1->jmp_next[n1];
1139 }
1140 /* we are now sure now that tb jumps to tb1 */
1141 tb_next = tb1;
1142
1143 /* remove tb from the jmp_first list */
1144 ptb = &tb_next->jmp_first;
1145 for(;;) {
1146 tb1 = *ptb;
1147 n1 = (long)tb1 & 3;
1148 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1149 if (n1 == n && tb1 == tb)
1150 break;
1151 ptb = &tb1->jmp_next[n1];
1152 }
1153 *ptb = tb->jmp_next[n];
1154 tb->jmp_next[n] = NULL;
ths3b46e622007-09-17 08:09:54 +00001155
bellardea041c02003-06-25 16:16:50 +00001156 /* suppress the jump to next tb in generated code */
1157 tb_reset_jump(tb, n);
1158
bellard01243112004-01-04 15:48:17 +00001159 /* suppress jumps in the tb on which we could have jumped */
bellardea041c02003-06-25 16:16:50 +00001160 tb_reset_jump_recursive(tb_next);
1161 }
1162}
1163
1164static void tb_reset_jump_recursive(TranslationBlock *tb)
1165{
1166 tb_reset_jump_recursive2(tb, 0);
1167 tb_reset_jump_recursive2(tb, 1);
1168}
1169
bellard1fddef42005-04-17 19:16:13 +00001170#if defined(TARGET_HAS_ICE)
bellardd720b932004-04-25 17:57:43 +00001171static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1172{
j_mayer9b3c35e2007-04-07 11:21:28 +00001173 target_phys_addr_t addr;
1174 target_ulong pd;
pbrookc2f07f82006-04-08 17:14:56 +00001175 ram_addr_t ram_addr;
1176 PhysPageDesc *p;
bellardd720b932004-04-25 17:57:43 +00001177
pbrookc2f07f82006-04-08 17:14:56 +00001178 addr = cpu_get_phys_page_debug(env, pc);
1179 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1180 if (!p) {
1181 pd = IO_MEM_UNASSIGNED;
1182 } else {
1183 pd = p->phys_offset;
1184 }
1185 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
pbrook706cd4b2006-04-08 17:36:21 +00001186 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
bellardd720b932004-04-25 17:57:43 +00001187}
bellardc27004e2005-01-03 23:35:10 +00001188#endif
bellardd720b932004-04-25 17:57:43 +00001189
pbrook6658ffb2007-03-16 23:58:11 +00001190/* Add a watchpoint. */
1191int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1192{
1193 int i;
1194
1195 for (i = 0; i < env->nb_watchpoints; i++) {
1196 if (addr == env->watchpoint[i].vaddr)
1197 return 0;
1198 }
1199 if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1200 return -1;
1201
1202 i = env->nb_watchpoints++;
1203 env->watchpoint[i].vaddr = addr;
1204 tlb_flush_page(env, addr);
1205 /* FIXME: This flush is needed because of the hack to make memory ops
1206 terminate the TB. It can be removed once the proper IO trap and
1207 re-execute bits are in. */
1208 tb_flush(env);
1209 return i;
1210}
1211
1212/* Remove a watchpoint. */
1213int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1214{
1215 int i;
1216
1217 for (i = 0; i < env->nb_watchpoints; i++) {
1218 if (addr == env->watchpoint[i].vaddr) {
1219 env->nb_watchpoints--;
1220 env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1221 tlb_flush_page(env, addr);
1222 return 0;
1223 }
1224 }
1225 return -1;
1226}
1227
edgar_igl7d03f822008-05-17 18:58:29 +00001228/* Remove all watchpoints. */
1229void cpu_watchpoint_remove_all(CPUState *env) {
1230 int i;
1231
1232 for (i = 0; i < env->nb_watchpoints; i++) {
1233 tlb_flush_page(env, env->watchpoint[i].vaddr);
1234 }
1235 env->nb_watchpoints = 0;
1236}
1237
bellardc33a3462003-07-29 20:50:33 +00001238/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1239 breakpoint is reached */
bellard2e126692004-04-25 21:28:44 +00001240int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001241{
bellard1fddef42005-04-17 19:16:13 +00001242#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001243 int i;
ths3b46e622007-09-17 08:09:54 +00001244
bellard4c3a88a2003-07-26 12:06:08 +00001245 for(i = 0; i < env->nb_breakpoints; i++) {
1246 if (env->breakpoints[i] == pc)
1247 return 0;
1248 }
1249
1250 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1251 return -1;
1252 env->breakpoints[env->nb_breakpoints++] = pc;
ths3b46e622007-09-17 08:09:54 +00001253
bellardd720b932004-04-25 17:57:43 +00001254 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001255 return 0;
1256#else
1257 return -1;
1258#endif
1259}
1260
edgar_igl7d03f822008-05-17 18:58:29 +00001261/* remove all breakpoints */
1262void cpu_breakpoint_remove_all(CPUState *env) {
1263#if defined(TARGET_HAS_ICE)
1264 int i;
1265 for(i = 0; i < env->nb_breakpoints; i++) {
1266 breakpoint_invalidate(env, env->breakpoints[i]);
1267 }
1268 env->nb_breakpoints = 0;
1269#endif
1270}
1271
bellard4c3a88a2003-07-26 12:06:08 +00001272/* remove a breakpoint */
bellard2e126692004-04-25 21:28:44 +00001273int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
bellard4c3a88a2003-07-26 12:06:08 +00001274{
bellard1fddef42005-04-17 19:16:13 +00001275#if defined(TARGET_HAS_ICE)
bellard4c3a88a2003-07-26 12:06:08 +00001276 int i;
1277 for(i = 0; i < env->nb_breakpoints; i++) {
1278 if (env->breakpoints[i] == pc)
1279 goto found;
1280 }
1281 return -1;
1282 found:
bellard4c3a88a2003-07-26 12:06:08 +00001283 env->nb_breakpoints--;
bellard1fddef42005-04-17 19:16:13 +00001284 if (i < env->nb_breakpoints)
1285 env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
bellardd720b932004-04-25 17:57:43 +00001286
1287 breakpoint_invalidate(env, pc);
bellard4c3a88a2003-07-26 12:06:08 +00001288 return 0;
1289#else
1290 return -1;
1291#endif
1292}
1293
bellardc33a3462003-07-29 20:50:33 +00001294/* enable or disable single step mode. EXCP_DEBUG is returned by the
1295 CPU loop after each instruction */
1296void cpu_single_step(CPUState *env, int enabled)
1297{
bellard1fddef42005-04-17 19:16:13 +00001298#if defined(TARGET_HAS_ICE)
bellardc33a3462003-07-29 20:50:33 +00001299 if (env->singlestep_enabled != enabled) {
1300 env->singlestep_enabled = enabled;
1301 /* must flush all the translated code to avoid inconsistancies */
bellard9fa3e852004-01-04 18:06:42 +00001302 /* XXX: only flush what is necessary */
bellard01243112004-01-04 15:48:17 +00001303 tb_flush(env);
bellardc33a3462003-07-29 20:50:33 +00001304 }
1305#endif
1306}
1307
bellard34865132003-10-05 14:28:56 +00001308/* enable or disable low levels log */
1309void cpu_set_log(int log_flags)
1310{
1311 loglevel = log_flags;
1312 if (loglevel && !logfile) {
pbrook11fcfab2007-07-01 18:21:11 +00001313 logfile = fopen(logfilename, log_append ? "a" : "w");
bellard34865132003-10-05 14:28:56 +00001314 if (!logfile) {
1315 perror(logfilename);
1316 _exit(1);
1317 }
bellard9fa3e852004-01-04 18:06:42 +00001318#if !defined(CONFIG_SOFTMMU)
1319 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1320 {
1321 static uint8_t logfile_buf[4096];
1322 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1323 }
1324#else
bellard34865132003-10-05 14:28:56 +00001325 setvbuf(logfile, NULL, _IOLBF, 0);
bellard9fa3e852004-01-04 18:06:42 +00001326#endif
pbrooke735b912007-06-30 13:53:24 +00001327 log_append = 1;
1328 }
1329 if (!loglevel && logfile) {
1330 fclose(logfile);
1331 logfile = NULL;
bellard34865132003-10-05 14:28:56 +00001332 }
1333}
1334
1335void cpu_set_log_filename(const char *filename)
1336{
1337 logfilename = strdup(filename);
pbrooke735b912007-06-30 13:53:24 +00001338 if (logfile) {
1339 fclose(logfile);
1340 logfile = NULL;
1341 }
1342 cpu_set_log(loglevel);
bellard34865132003-10-05 14:28:56 +00001343}
bellardc33a3462003-07-29 20:50:33 +00001344
bellard01243112004-01-04 15:48:17 +00001345/* mask must never be zero, except for A20 change call */
bellard68a79312003-06-30 13:12:32 +00001346void cpu_interrupt(CPUState *env, int mask)
bellardea041c02003-06-25 16:16:50 +00001347{
pbrookd5975362008-06-07 20:50:51 +00001348#if !defined(USE_NPTL)
bellardea041c02003-06-25 16:16:50 +00001349 TranslationBlock *tb;
aurel3215a51152008-03-28 22:29:15 +00001350 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
pbrookd5975362008-06-07 20:50:51 +00001351#endif
bellard59817cc2004-02-16 22:01:13 +00001352
pbrookd5975362008-06-07 20:50:51 +00001353 /* FIXME: This is probably not threadsafe. A different thread could
1354 be in the mittle of a read-modify-write operation. */
bellard68a79312003-06-30 13:12:32 +00001355 env->interrupt_request |= mask;
pbrookd5975362008-06-07 20:50:51 +00001356#if defined(USE_NPTL)
1357 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1358 problem and hope the cpu will stop of its own accord. For userspace
1359 emulation this often isn't actually as bad as it sounds. Often
1360 signals are used primarily to interrupt blocking syscalls. */
1361#else
bellardea041c02003-06-25 16:16:50 +00001362 /* if the cpu is currently executing code, we must unlink it and
1363 all the potentially executing TB */
1364 tb = env->current_tb;
bellardee8b7022004-02-03 23:35:10 +00001365 if (tb && !testandset(&interrupt_lock)) {
1366 env->current_tb = NULL;
bellardea041c02003-06-25 16:16:50 +00001367 tb_reset_jump_recursive(tb);
aurel3215a51152008-03-28 22:29:15 +00001368 resetlock(&interrupt_lock);
bellardea041c02003-06-25 16:16:50 +00001369 }
pbrookd5975362008-06-07 20:50:51 +00001370#endif
bellardea041c02003-06-25 16:16:50 +00001371}
1372
bellardb54ad042004-05-20 13:42:52 +00001373void cpu_reset_interrupt(CPUState *env, int mask)
1374{
1375 env->interrupt_request &= ~mask;
1376}
1377
bellardf193c792004-03-21 17:06:25 +00001378CPULogItem cpu_log_items[] = {
ths5fafdf22007-09-16 21:08:06 +00001379 { CPU_LOG_TB_OUT_ASM, "out_asm",
bellardf193c792004-03-21 17:06:25 +00001380 "show generated host assembly code for each compiled TB" },
1381 { CPU_LOG_TB_IN_ASM, "in_asm",
1382 "show target assembly code for each compiled TB" },
ths5fafdf22007-09-16 21:08:06 +00001383 { CPU_LOG_TB_OP, "op",
bellard57fec1f2008-02-01 10:50:11 +00001384 "show micro ops for each compiled TB" },
bellardf193c792004-03-21 17:06:25 +00001385 { CPU_LOG_TB_OP_OPT, "op_opt",
blueswir1e01a1152008-03-14 17:37:11 +00001386 "show micro ops "
1387#ifdef TARGET_I386
1388 "before eflags optimization and "
bellardf193c792004-03-21 17:06:25 +00001389#endif
blueswir1e01a1152008-03-14 17:37:11 +00001390 "after liveness analysis" },
bellardf193c792004-03-21 17:06:25 +00001391 { CPU_LOG_INT, "int",
1392 "show interrupts/exceptions in short format" },
1393 { CPU_LOG_EXEC, "exec",
1394 "show trace before each executed TB (lots of logs)" },
bellard9fddaa02004-05-21 12:59:32 +00001395 { CPU_LOG_TB_CPU, "cpu",
thse91c8a72007-06-03 13:35:16 +00001396 "show CPU state before block translation" },
bellardf193c792004-03-21 17:06:25 +00001397#ifdef TARGET_I386
1398 { CPU_LOG_PCALL, "pcall",
1399 "show protected mode far calls/returns/exceptions" },
1400#endif
bellard8e3a9fd2004-10-09 17:32:58 +00001401#ifdef DEBUG_IOPORT
bellardfd872592004-05-12 19:11:15 +00001402 { CPU_LOG_IOPORT, "ioport",
1403 "show all i/o ports accesses" },
bellard8e3a9fd2004-10-09 17:32:58 +00001404#endif
bellardf193c792004-03-21 17:06:25 +00001405 { 0, NULL, NULL },
1406};
1407
1408static int cmp1(const char *s1, int n, const char *s2)
1409{
1410 if (strlen(s2) != n)
1411 return 0;
1412 return memcmp(s1, s2, n) == 0;
1413}
ths3b46e622007-09-17 08:09:54 +00001414
bellardf193c792004-03-21 17:06:25 +00001415/* takes a comma separated list of log masks. Return 0 if error. */
1416int cpu_str_to_log_mask(const char *str)
1417{
1418 CPULogItem *item;
1419 int mask;
1420 const char *p, *p1;
1421
1422 p = str;
1423 mask = 0;
1424 for(;;) {
1425 p1 = strchr(p, ',');
1426 if (!p1)
1427 p1 = p + strlen(p);
bellard8e3a9fd2004-10-09 17:32:58 +00001428 if(cmp1(p,p1-p,"all")) {
1429 for(item = cpu_log_items; item->mask != 0; item++) {
1430 mask |= item->mask;
1431 }
1432 } else {
bellardf193c792004-03-21 17:06:25 +00001433 for(item = cpu_log_items; item->mask != 0; item++) {
1434 if (cmp1(p, p1 - p, item->name))
1435 goto found;
1436 }
1437 return 0;
bellard8e3a9fd2004-10-09 17:32:58 +00001438 }
bellardf193c792004-03-21 17:06:25 +00001439 found:
1440 mask |= item->mask;
1441 if (*p1 != ',')
1442 break;
1443 p = p1 + 1;
1444 }
1445 return mask;
1446}
bellardea041c02003-06-25 16:16:50 +00001447
bellard75012672003-06-21 13:11:07 +00001448void cpu_abort(CPUState *env, const char *fmt, ...)
1449{
1450 va_list ap;
pbrook493ae1f2007-11-23 16:53:59 +00001451 va_list ap2;
bellard75012672003-06-21 13:11:07 +00001452
1453 va_start(ap, fmt);
pbrook493ae1f2007-11-23 16:53:59 +00001454 va_copy(ap2, ap);
bellard75012672003-06-21 13:11:07 +00001455 fprintf(stderr, "qemu: fatal: ");
1456 vfprintf(stderr, fmt, ap);
1457 fprintf(stderr, "\n");
1458#ifdef TARGET_I386
bellard7fe48482004-10-09 18:08:01 +00001459 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1460#else
1461 cpu_dump_state(env, stderr, fprintf, 0);
bellard75012672003-06-21 13:11:07 +00001462#endif
balrog924edca2007-06-10 14:07:13 +00001463 if (logfile) {
j_mayerf9373292007-09-29 12:18:20 +00001464 fprintf(logfile, "qemu: fatal: ");
pbrook493ae1f2007-11-23 16:53:59 +00001465 vfprintf(logfile, fmt, ap2);
j_mayerf9373292007-09-29 12:18:20 +00001466 fprintf(logfile, "\n");
1467#ifdef TARGET_I386
1468 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1469#else
1470 cpu_dump_state(env, logfile, fprintf, 0);
1471#endif
balrog924edca2007-06-10 14:07:13 +00001472 fflush(logfile);
1473 fclose(logfile);
1474 }
pbrook493ae1f2007-11-23 16:53:59 +00001475 va_end(ap2);
j_mayerf9373292007-09-29 12:18:20 +00001476 va_end(ap);
bellard75012672003-06-21 13:11:07 +00001477 abort();
1478}
1479
thsc5be9f02007-02-28 20:20:53 +00001480CPUState *cpu_copy(CPUState *env)
1481{
ths01ba9812007-12-09 02:22:57 +00001482 CPUState *new_env = cpu_init(env->cpu_model_str);
thsc5be9f02007-02-28 20:20:53 +00001483 /* preserve chaining and index */
1484 CPUState *next_cpu = new_env->next_cpu;
1485 int cpu_index = new_env->cpu_index;
1486 memcpy(new_env, env, sizeof(CPUState));
1487 new_env->next_cpu = next_cpu;
1488 new_env->cpu_index = cpu_index;
1489 return new_env;
1490}
1491
bellard01243112004-01-04 15:48:17 +00001492#if !defined(CONFIG_USER_ONLY)
1493
edgar_igl5c751e92008-05-06 08:44:21 +00001494static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1495{
1496 unsigned int i;
1497
1498 /* Discard jump cache entries for any tb which might potentially
1499 overlap the flushed page. */
1500 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1501 memset (&env->tb_jmp_cache[i], 0,
1502 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1503
1504 i = tb_jmp_cache_hash_page(addr);
1505 memset (&env->tb_jmp_cache[i], 0,
1506 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1507}
1508
bellardee8b7022004-02-03 23:35:10 +00001509/* NOTE: if flush_global is true, also flush global entries (not
1510 implemented yet) */
1511void tlb_flush(CPUState *env, int flush_global)
bellard33417e72003-08-10 21:47:01 +00001512{
bellard33417e72003-08-10 21:47:01 +00001513 int i;
bellard01243112004-01-04 15:48:17 +00001514
bellard9fa3e852004-01-04 18:06:42 +00001515#if defined(DEBUG_TLB)
1516 printf("tlb_flush:\n");
1517#endif
bellard01243112004-01-04 15:48:17 +00001518 /* must reset current TB so that interrupts cannot modify the
1519 links while we are modifying them */
1520 env->current_tb = NULL;
1521
bellard33417e72003-08-10 21:47:01 +00001522 for(i = 0; i < CPU_TLB_SIZE; i++) {
bellard84b7b8e2005-11-28 21:19:04 +00001523 env->tlb_table[0][i].addr_read = -1;
1524 env->tlb_table[0][i].addr_write = -1;
1525 env->tlb_table[0][i].addr_code = -1;
1526 env->tlb_table[1][i].addr_read = -1;
1527 env->tlb_table[1][i].addr_write = -1;
1528 env->tlb_table[1][i].addr_code = -1;
j_mayer6fa4cea2007-04-05 06:43:27 +00001529#if (NB_MMU_MODES >= 3)
1530 env->tlb_table[2][i].addr_read = -1;
1531 env->tlb_table[2][i].addr_write = -1;
1532 env->tlb_table[2][i].addr_code = -1;
1533#if (NB_MMU_MODES == 4)
1534 env->tlb_table[3][i].addr_read = -1;
1535 env->tlb_table[3][i].addr_write = -1;
1536 env->tlb_table[3][i].addr_code = -1;
1537#endif
1538#endif
bellard33417e72003-08-10 21:47:01 +00001539 }
bellard9fa3e852004-01-04 18:06:42 +00001540
bellard8a40a182005-11-20 10:35:40 +00001541 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
bellard9fa3e852004-01-04 18:06:42 +00001542
bellard0a962c02005-02-10 22:00:27 +00001543#ifdef USE_KQEMU
1544 if (env->kqemu_enabled) {
1545 kqemu_flush(env, flush_global);
1546 }
1547#endif
bellarde3db7222005-01-26 22:00:47 +00001548 tlb_flush_count++;
bellard33417e72003-08-10 21:47:01 +00001549}
1550
bellard274da6b2004-05-20 21:56:27 +00001551static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
bellard61382a52003-10-27 21:22:23 +00001552{
ths5fafdf22007-09-16 21:08:06 +00001553 if (addr == (tlb_entry->addr_read &
bellard84b7b8e2005-11-28 21:19:04 +00001554 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001555 addr == (tlb_entry->addr_write &
bellard84b7b8e2005-11-28 21:19:04 +00001556 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
ths5fafdf22007-09-16 21:08:06 +00001557 addr == (tlb_entry->addr_code &
bellard84b7b8e2005-11-28 21:19:04 +00001558 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1559 tlb_entry->addr_read = -1;
1560 tlb_entry->addr_write = -1;
1561 tlb_entry->addr_code = -1;
1562 }
bellard61382a52003-10-27 21:22:23 +00001563}
1564
bellard2e126692004-04-25 21:28:44 +00001565void tlb_flush_page(CPUState *env, target_ulong addr)
bellard33417e72003-08-10 21:47:01 +00001566{
bellard8a40a182005-11-20 10:35:40 +00001567 int i;
bellard01243112004-01-04 15:48:17 +00001568
bellard9fa3e852004-01-04 18:06:42 +00001569#if defined(DEBUG_TLB)
bellard108c49b2005-07-24 12:55:09 +00001570 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
bellard9fa3e852004-01-04 18:06:42 +00001571#endif
bellard01243112004-01-04 15:48:17 +00001572 /* must reset current TB so that interrupts cannot modify the
1573 links while we are modifying them */
1574 env->current_tb = NULL;
bellard33417e72003-08-10 21:47:01 +00001575
bellard61382a52003-10-27 21:22:23 +00001576 addr &= TARGET_PAGE_MASK;
bellard33417e72003-08-10 21:47:01 +00001577 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001578 tlb_flush_entry(&env->tlb_table[0][i], addr);
1579 tlb_flush_entry(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001580#if (NB_MMU_MODES >= 3)
1581 tlb_flush_entry(&env->tlb_table[2][i], addr);
1582#if (NB_MMU_MODES == 4)
1583 tlb_flush_entry(&env->tlb_table[3][i], addr);
1584#endif
1585#endif
bellard01243112004-01-04 15:48:17 +00001586
edgar_igl5c751e92008-05-06 08:44:21 +00001587 tlb_flush_jmp_cache(env, addr);
bellard9fa3e852004-01-04 18:06:42 +00001588
bellard0a962c02005-02-10 22:00:27 +00001589#ifdef USE_KQEMU
1590 if (env->kqemu_enabled) {
1591 kqemu_flush_page(env, addr);
1592 }
1593#endif
bellard9fa3e852004-01-04 18:06:42 +00001594}
1595
bellard9fa3e852004-01-04 18:06:42 +00001596/* update the TLBs so that writes to code in the virtual page 'addr'
1597 can be detected */
bellard6a00d602005-11-21 23:25:50 +00001598static void tlb_protect_code(ram_addr_t ram_addr)
bellard61382a52003-10-27 21:22:23 +00001599{
ths5fafdf22007-09-16 21:08:06 +00001600 cpu_physical_memory_reset_dirty(ram_addr,
bellard6a00d602005-11-21 23:25:50 +00001601 ram_addr + TARGET_PAGE_SIZE,
1602 CODE_DIRTY_FLAG);
bellard9fa3e852004-01-04 18:06:42 +00001603}
1604
bellard9fa3e852004-01-04 18:06:42 +00001605/* update the TLB so that writes in physical page 'phys_addr' are no longer
bellard3a7d9292005-08-21 09:26:42 +00001606 tested for self modifying code */
ths5fafdf22007-09-16 21:08:06 +00001607static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
bellard3a7d9292005-08-21 09:26:42 +00001608 target_ulong vaddr)
bellard9fa3e852004-01-04 18:06:42 +00001609{
bellard3a7d9292005-08-21 09:26:42 +00001610 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
bellard1ccde1c2004-02-06 19:46:14 +00001611}
1612
ths5fafdf22007-09-16 21:08:06 +00001613static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
bellard1ccde1c2004-02-06 19:46:14 +00001614 unsigned long start, unsigned long length)
1615{
1616 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001617 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1618 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001619 if ((addr - start) < length) {
bellard84b7b8e2005-11-28 21:19:04 +00001620 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
bellard1ccde1c2004-02-06 19:46:14 +00001621 }
1622 }
1623}
1624
bellard3a7d9292005-08-21 09:26:42 +00001625void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
bellard0a962c02005-02-10 22:00:27 +00001626 int dirty_flags)
bellard1ccde1c2004-02-06 19:46:14 +00001627{
1628 CPUState *env;
bellard4f2ac232004-04-26 19:44:02 +00001629 unsigned long length, start1;
bellard0a962c02005-02-10 22:00:27 +00001630 int i, mask, len;
1631 uint8_t *p;
bellard1ccde1c2004-02-06 19:46:14 +00001632
1633 start &= TARGET_PAGE_MASK;
1634 end = TARGET_PAGE_ALIGN(end);
1635
1636 length = end - start;
1637 if (length == 0)
1638 return;
bellard0a962c02005-02-10 22:00:27 +00001639 len = length >> TARGET_PAGE_BITS;
bellard3a7d9292005-08-21 09:26:42 +00001640#ifdef USE_KQEMU
bellard6a00d602005-11-21 23:25:50 +00001641 /* XXX: should not depend on cpu context */
1642 env = first_cpu;
bellard3a7d9292005-08-21 09:26:42 +00001643 if (env->kqemu_enabled) {
bellardf23db162005-08-21 19:12:28 +00001644 ram_addr_t addr;
1645 addr = start;
1646 for(i = 0; i < len; i++) {
1647 kqemu_set_notdirty(env, addr);
1648 addr += TARGET_PAGE_SIZE;
1649 }
bellard3a7d9292005-08-21 09:26:42 +00001650 }
1651#endif
bellardf23db162005-08-21 19:12:28 +00001652 mask = ~dirty_flags;
1653 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1654 for(i = 0; i < len; i++)
1655 p[i] &= mask;
1656
bellard1ccde1c2004-02-06 19:46:14 +00001657 /* we modify the TLB cache so that the dirty bit will be set again
1658 when accessing the range */
bellard59817cc2004-02-16 22:01:13 +00001659 start1 = start + (unsigned long)phys_ram_base;
bellard6a00d602005-11-21 23:25:50 +00001660 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1661 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001662 tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
bellard6a00d602005-11-21 23:25:50 +00001663 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001664 tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
j_mayer6fa4cea2007-04-05 06:43:27 +00001665#if (NB_MMU_MODES >= 3)
1666 for(i = 0; i < CPU_TLB_SIZE; i++)
1667 tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1668#if (NB_MMU_MODES == 4)
1669 for(i = 0; i < CPU_TLB_SIZE; i++)
1670 tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1671#endif
1672#endif
bellard6a00d602005-11-21 23:25:50 +00001673 }
bellard1ccde1c2004-02-06 19:46:14 +00001674}
1675
bellard3a7d9292005-08-21 09:26:42 +00001676static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1677{
1678 ram_addr_t ram_addr;
1679
bellard84b7b8e2005-11-28 21:19:04 +00001680 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
ths5fafdf22007-09-16 21:08:06 +00001681 ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
bellard3a7d9292005-08-21 09:26:42 +00001682 tlb_entry->addend - (unsigned long)phys_ram_base;
1683 if (!cpu_physical_memory_is_dirty(ram_addr)) {
bellard84b7b8e2005-11-28 21:19:04 +00001684 tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
bellard3a7d9292005-08-21 09:26:42 +00001685 }
1686 }
1687}
1688
1689/* update the TLB according to the current state of the dirty bits */
1690void cpu_tlb_update_dirty(CPUState *env)
1691{
1692 int i;
1693 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001694 tlb_update_dirty(&env->tlb_table[0][i]);
bellard3a7d9292005-08-21 09:26:42 +00001695 for(i = 0; i < CPU_TLB_SIZE; i++)
bellard84b7b8e2005-11-28 21:19:04 +00001696 tlb_update_dirty(&env->tlb_table[1][i]);
j_mayer6fa4cea2007-04-05 06:43:27 +00001697#if (NB_MMU_MODES >= 3)
1698 for(i = 0; i < CPU_TLB_SIZE; i++)
1699 tlb_update_dirty(&env->tlb_table[2][i]);
1700#if (NB_MMU_MODES == 4)
1701 for(i = 0; i < CPU_TLB_SIZE; i++)
1702 tlb_update_dirty(&env->tlb_table[3][i]);
1703#endif
1704#endif
bellard3a7d9292005-08-21 09:26:42 +00001705}
1706
ths5fafdf22007-09-16 21:08:06 +00001707static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
bellard108c49b2005-07-24 12:55:09 +00001708 unsigned long start)
bellard1ccde1c2004-02-06 19:46:14 +00001709{
1710 unsigned long addr;
bellard84b7b8e2005-11-28 21:19:04 +00001711 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1712 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
bellard1ccde1c2004-02-06 19:46:14 +00001713 if (addr == start) {
bellard84b7b8e2005-11-28 21:19:04 +00001714 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
bellard1ccde1c2004-02-06 19:46:14 +00001715 }
1716 }
1717}
1718
1719/* update the TLB corresponding to virtual page vaddr and phys addr
1720 addr so that it is no longer dirty */
bellard6a00d602005-11-21 23:25:50 +00001721static inline void tlb_set_dirty(CPUState *env,
1722 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00001723{
bellard1ccde1c2004-02-06 19:46:14 +00001724 int i;
1725
bellard1ccde1c2004-02-06 19:46:14 +00001726 addr &= TARGET_PAGE_MASK;
1727 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard84b7b8e2005-11-28 21:19:04 +00001728 tlb_set_dirty1(&env->tlb_table[0][i], addr);
1729 tlb_set_dirty1(&env->tlb_table[1][i], addr);
j_mayer6fa4cea2007-04-05 06:43:27 +00001730#if (NB_MMU_MODES >= 3)
1731 tlb_set_dirty1(&env->tlb_table[2][i], addr);
1732#if (NB_MMU_MODES == 4)
1733 tlb_set_dirty1(&env->tlb_table[3][i], addr);
1734#endif
1735#endif
bellard9fa3e852004-01-04 18:06:42 +00001736}
1737
bellard59817cc2004-02-16 22:01:13 +00001738/* add a new TLB entry. At most one entry for a given virtual address
1739 is permitted. Return 0 if OK or 2 if the page could not be mapped
1740 (can only happen in non SOFTMMU mode for I/O pages or pages
1741 conflicting with the host address space). */
ths5fafdf22007-09-16 21:08:06 +00001742int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1743 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001744 int mmu_idx, int is_softmmu)
bellard9fa3e852004-01-04 18:06:42 +00001745{
bellard92e873b2004-05-21 14:52:29 +00001746 PhysPageDesc *p;
bellard4f2ac232004-04-26 19:44:02 +00001747 unsigned long pd;
bellard9fa3e852004-01-04 18:06:42 +00001748 unsigned int index;
bellard4f2ac232004-04-26 19:44:02 +00001749 target_ulong address;
bellard108c49b2005-07-24 12:55:09 +00001750 target_phys_addr_t addend;
bellard9fa3e852004-01-04 18:06:42 +00001751 int ret;
bellard84b7b8e2005-11-28 21:19:04 +00001752 CPUTLBEntry *te;
pbrook6658ffb2007-03-16 23:58:11 +00001753 int i;
bellard9fa3e852004-01-04 18:06:42 +00001754
bellard92e873b2004-05-21 14:52:29 +00001755 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
bellard9fa3e852004-01-04 18:06:42 +00001756 if (!p) {
1757 pd = IO_MEM_UNASSIGNED;
bellard9fa3e852004-01-04 18:06:42 +00001758 } else {
1759 pd = p->phys_offset;
bellard9fa3e852004-01-04 18:06:42 +00001760 }
1761#if defined(DEBUG_TLB)
j_mayer6ebbf392007-10-14 07:07:08 +00001762 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
1763 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
bellard9fa3e852004-01-04 18:06:42 +00001764#endif
1765
1766 ret = 0;
bellard9fa3e852004-01-04 18:06:42 +00001767 {
bellard2a4188a2006-06-25 21:54:59 +00001768 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
bellard9fa3e852004-01-04 18:06:42 +00001769 /* IO memory case */
1770 address = vaddr | pd;
1771 addend = paddr;
1772 } else {
1773 /* standard memory */
1774 address = vaddr;
1775 addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1776 }
pbrook6658ffb2007-03-16 23:58:11 +00001777
1778 /* Make accesses to pages with watchpoints go via the
1779 watchpoint trap routines. */
1780 for (i = 0; i < env->nb_watchpoints; i++) {
1781 if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1782 if (address & ~TARGET_PAGE_MASK) {
balrogd79acba2007-06-26 20:01:13 +00001783 env->watchpoint[i].addend = 0;
pbrook6658ffb2007-03-16 23:58:11 +00001784 address = vaddr | io_mem_watch;
1785 } else {
balrogd79acba2007-06-26 20:01:13 +00001786 env->watchpoint[i].addend = pd - paddr +
1787 (unsigned long) phys_ram_base;
pbrook6658ffb2007-03-16 23:58:11 +00001788 /* TODO: Figure out how to make read watchpoints coexist
1789 with code. */
1790 pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1791 }
1792 }
1793 }
balrogd79acba2007-06-26 20:01:13 +00001794
bellard90f18422005-07-24 10:17:31 +00001795 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
bellard9fa3e852004-01-04 18:06:42 +00001796 addend -= vaddr;
j_mayer6ebbf392007-10-14 07:07:08 +00001797 te = &env->tlb_table[mmu_idx][index];
bellard84b7b8e2005-11-28 21:19:04 +00001798 te->addend = addend;
bellard67b915a2004-03-31 23:37:16 +00001799 if (prot & PAGE_READ) {
bellard84b7b8e2005-11-28 21:19:04 +00001800 te->addr_read = address;
bellard9fa3e852004-01-04 18:06:42 +00001801 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001802 te->addr_read = -1;
1803 }
edgar_igl5c751e92008-05-06 08:44:21 +00001804
bellard84b7b8e2005-11-28 21:19:04 +00001805 if (prot & PAGE_EXEC) {
1806 te->addr_code = address;
1807 } else {
1808 te->addr_code = -1;
bellard9fa3e852004-01-04 18:06:42 +00001809 }
bellard67b915a2004-03-31 23:37:16 +00001810 if (prot & PAGE_WRITE) {
ths5fafdf22007-09-16 21:08:06 +00001811 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
bellard856074e2006-07-04 09:47:34 +00001812 (pd & IO_MEM_ROMD)) {
1813 /* write access calls the I/O callback */
ths5fafdf22007-09-16 21:08:06 +00001814 te->addr_write = vaddr |
bellard856074e2006-07-04 09:47:34 +00001815 (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
ths5fafdf22007-09-16 21:08:06 +00001816 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
bellard1ccde1c2004-02-06 19:46:14 +00001817 !cpu_physical_memory_is_dirty(pd)) {
bellard84b7b8e2005-11-28 21:19:04 +00001818 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
bellard9fa3e852004-01-04 18:06:42 +00001819 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001820 te->addr_write = address;
bellard9fa3e852004-01-04 18:06:42 +00001821 }
1822 } else {
bellard84b7b8e2005-11-28 21:19:04 +00001823 te->addr_write = -1;
bellard9fa3e852004-01-04 18:06:42 +00001824 }
1825 }
bellard9fa3e852004-01-04 18:06:42 +00001826 return ret;
1827}
1828
bellard01243112004-01-04 15:48:17 +00001829#else
1830
bellardee8b7022004-02-03 23:35:10 +00001831void tlb_flush(CPUState *env, int flush_global)
bellard01243112004-01-04 15:48:17 +00001832{
1833}
1834
bellard2e126692004-04-25 21:28:44 +00001835void tlb_flush_page(CPUState *env, target_ulong addr)
bellard01243112004-01-04 15:48:17 +00001836{
1837}
1838
ths5fafdf22007-09-16 21:08:06 +00001839int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1840 target_phys_addr_t paddr, int prot,
j_mayer6ebbf392007-10-14 07:07:08 +00001841 int mmu_idx, int is_softmmu)
bellard33417e72003-08-10 21:47:01 +00001842{
bellard9fa3e852004-01-04 18:06:42 +00001843 return 0;
1844}
bellard33417e72003-08-10 21:47:01 +00001845
bellard9fa3e852004-01-04 18:06:42 +00001846/* dump memory mappings */
1847void page_dump(FILE *f)
1848{
1849 unsigned long start, end;
1850 int i, j, prot, prot1;
1851 PageDesc *p;
1852
1853 fprintf(f, "%-8s %-8s %-8s %s\n",
1854 "start", "end", "size", "prot");
1855 start = -1;
1856 end = -1;
1857 prot = 0;
1858 for(i = 0; i <= L1_SIZE; i++) {
1859 if (i < L1_SIZE)
1860 p = l1_map[i];
1861 else
1862 p = NULL;
1863 for(j = 0;j < L2_SIZE; j++) {
1864 if (!p)
1865 prot1 = 0;
1866 else
1867 prot1 = p[j].flags;
1868 if (prot1 != prot) {
1869 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1870 if (start != -1) {
1871 fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
ths5fafdf22007-09-16 21:08:06 +00001872 start, end, end - start,
bellard9fa3e852004-01-04 18:06:42 +00001873 prot & PAGE_READ ? 'r' : '-',
1874 prot & PAGE_WRITE ? 'w' : '-',
1875 prot & PAGE_EXEC ? 'x' : '-');
1876 }
1877 if (prot1 != 0)
1878 start = end;
1879 else
1880 start = -1;
1881 prot = prot1;
1882 }
1883 if (!p)
1884 break;
1885 }
bellard33417e72003-08-10 21:47:01 +00001886 }
bellard33417e72003-08-10 21:47:01 +00001887}
1888
pbrook53a59602006-03-25 19:31:22 +00001889int page_get_flags(target_ulong address)
bellard33417e72003-08-10 21:47:01 +00001890{
bellard9fa3e852004-01-04 18:06:42 +00001891 PageDesc *p;
1892
1893 p = page_find(address >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00001894 if (!p)
bellard9fa3e852004-01-04 18:06:42 +00001895 return 0;
1896 return p->flags;
bellard33417e72003-08-10 21:47:01 +00001897}
1898
bellard9fa3e852004-01-04 18:06:42 +00001899/* modify the flags of a page and invalidate the code if
1900 necessary. The flag PAGE_WRITE_ORG is positionned automatically
1901 depending on PAGE_WRITE */
pbrook53a59602006-03-25 19:31:22 +00001902void page_set_flags(target_ulong start, target_ulong end, int flags)
bellard9fa3e852004-01-04 18:06:42 +00001903{
1904 PageDesc *p;
pbrook53a59602006-03-25 19:31:22 +00001905 target_ulong addr;
bellard9fa3e852004-01-04 18:06:42 +00001906
pbrookc8a706f2008-06-02 16:16:42 +00001907 /* mmap_lock should already be held. */
bellard9fa3e852004-01-04 18:06:42 +00001908 start = start & TARGET_PAGE_MASK;
1909 end = TARGET_PAGE_ALIGN(end);
1910 if (flags & PAGE_WRITE)
1911 flags |= PAGE_WRITE_ORG;
bellard9fa3e852004-01-04 18:06:42 +00001912 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1913 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1914 /* if the write protection is set, then we invalidate the code
1915 inside */
ths5fafdf22007-09-16 21:08:06 +00001916 if (!(p->flags & PAGE_WRITE) &&
bellard9fa3e852004-01-04 18:06:42 +00001917 (flags & PAGE_WRITE) &&
1918 p->first_tb) {
bellardd720b932004-04-25 17:57:43 +00001919 tb_invalidate_phys_page(addr, 0, NULL);
bellard9fa3e852004-01-04 18:06:42 +00001920 }
1921 p->flags = flags;
1922 }
bellard9fa3e852004-01-04 18:06:42 +00001923}
1924
ths3d97b402007-11-02 19:02:07 +00001925int page_check_range(target_ulong start, target_ulong len, int flags)
1926{
1927 PageDesc *p;
1928 target_ulong end;
1929 target_ulong addr;
1930
1931 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1932 start = start & TARGET_PAGE_MASK;
1933
1934 if( end < start )
1935 /* we've wrapped around */
1936 return -1;
1937 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1938 p = page_find(addr >> TARGET_PAGE_BITS);
1939 if( !p )
1940 return -1;
1941 if( !(p->flags & PAGE_VALID) )
1942 return -1;
1943
bellarddae32702007-11-14 10:51:00 +00001944 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
ths3d97b402007-11-02 19:02:07 +00001945 return -1;
bellarddae32702007-11-14 10:51:00 +00001946 if (flags & PAGE_WRITE) {
1947 if (!(p->flags & PAGE_WRITE_ORG))
1948 return -1;
1949 /* unprotect the page if it was put read-only because it
1950 contains translated code */
1951 if (!(p->flags & PAGE_WRITE)) {
1952 if (!page_unprotect(addr, 0, NULL))
1953 return -1;
1954 }
1955 return 0;
1956 }
ths3d97b402007-11-02 19:02:07 +00001957 }
1958 return 0;
1959}
1960
bellard9fa3e852004-01-04 18:06:42 +00001961/* called from signal handler: invalidate the code and unprotect the
1962 page. Return TRUE if the fault was succesfully handled. */
pbrook53a59602006-03-25 19:31:22 +00001963int page_unprotect(target_ulong address, unsigned long pc, void *puc)
bellard9fa3e852004-01-04 18:06:42 +00001964{
1965 unsigned int page_index, prot, pindex;
1966 PageDesc *p, *p1;
pbrook53a59602006-03-25 19:31:22 +00001967 target_ulong host_start, host_end, addr;
bellard9fa3e852004-01-04 18:06:42 +00001968
pbrookc8a706f2008-06-02 16:16:42 +00001969 /* Technically this isn't safe inside a signal handler. However we
1970 know this only ever happens in a synchronous SEGV handler, so in
1971 practice it seems to be ok. */
1972 mmap_lock();
1973
bellard83fb7ad2004-07-05 21:25:26 +00001974 host_start = address & qemu_host_page_mask;
bellard9fa3e852004-01-04 18:06:42 +00001975 page_index = host_start >> TARGET_PAGE_BITS;
1976 p1 = page_find(page_index);
pbrookc8a706f2008-06-02 16:16:42 +00001977 if (!p1) {
1978 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00001979 return 0;
pbrookc8a706f2008-06-02 16:16:42 +00001980 }
bellard83fb7ad2004-07-05 21:25:26 +00001981 host_end = host_start + qemu_host_page_size;
bellard9fa3e852004-01-04 18:06:42 +00001982 p = p1;
1983 prot = 0;
1984 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1985 prot |= p->flags;
1986 p++;
1987 }
1988 /* if the page was really writable, then we change its
1989 protection back to writable */
1990 if (prot & PAGE_WRITE_ORG) {
1991 pindex = (address - host_start) >> TARGET_PAGE_BITS;
1992 if (!(p1[pindex].flags & PAGE_WRITE)) {
ths5fafdf22007-09-16 21:08:06 +00001993 mprotect((void *)g2h(host_start), qemu_host_page_size,
bellard9fa3e852004-01-04 18:06:42 +00001994 (prot & PAGE_BITS) | PAGE_WRITE);
1995 p1[pindex].flags |= PAGE_WRITE;
1996 /* and since the content will be modified, we must invalidate
1997 the corresponding translated code. */
bellardd720b932004-04-25 17:57:43 +00001998 tb_invalidate_phys_page(address, pc, puc);
bellard9fa3e852004-01-04 18:06:42 +00001999#ifdef DEBUG_TB_CHECK
2000 tb_invalidate_check(address);
2001#endif
pbrookc8a706f2008-06-02 16:16:42 +00002002 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002003 return 1;
2004 }
2005 }
pbrookc8a706f2008-06-02 16:16:42 +00002006 mmap_unlock();
bellard9fa3e852004-01-04 18:06:42 +00002007 return 0;
2008}
2009
bellard6a00d602005-11-21 23:25:50 +00002010static inline void tlb_set_dirty(CPUState *env,
2011 unsigned long addr, target_ulong vaddr)
bellard1ccde1c2004-02-06 19:46:14 +00002012{
2013}
bellard9fa3e852004-01-04 18:06:42 +00002014#endif /* defined(CONFIG_USER_ONLY) */
2015
pbrooke2eef172008-06-08 01:09:01 +00002016#if !defined(CONFIG_USER_ONLY)
blueswir1db7b5422007-05-26 17:36:03 +00002017static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002018 ram_addr_t memory);
2019static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2020 ram_addr_t orig_memory);
blueswir1db7b5422007-05-26 17:36:03 +00002021#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2022 need_subpage) \
2023 do { \
2024 if (addr > start_addr) \
2025 start_addr2 = 0; \
2026 else { \
2027 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2028 if (start_addr2 > 0) \
2029 need_subpage = 1; \
2030 } \
2031 \
blueswir149e9fba2007-05-30 17:25:06 +00002032 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
blueswir1db7b5422007-05-26 17:36:03 +00002033 end_addr2 = TARGET_PAGE_SIZE - 1; \
2034 else { \
2035 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2036 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2037 need_subpage = 1; \
2038 } \
2039 } while (0)
2040
bellard33417e72003-08-10 21:47:01 +00002041/* register physical memory. 'size' must be a multiple of the target
2042 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
2043 io memory page */
ths5fafdf22007-09-16 21:08:06 +00002044void cpu_register_physical_memory(target_phys_addr_t start_addr,
aurel3200f82b82008-04-27 21:12:55 +00002045 ram_addr_t size,
2046 ram_addr_t phys_offset)
bellard33417e72003-08-10 21:47:01 +00002047{
bellard108c49b2005-07-24 12:55:09 +00002048 target_phys_addr_t addr, end_addr;
bellard92e873b2004-05-21 14:52:29 +00002049 PhysPageDesc *p;
bellard9d420372006-06-25 22:25:22 +00002050 CPUState *env;
aurel3200f82b82008-04-27 21:12:55 +00002051 ram_addr_t orig_size = size;
blueswir1db7b5422007-05-26 17:36:03 +00002052 void *subpage;
bellard33417e72003-08-10 21:47:01 +00002053
bellardda260242008-05-30 20:48:25 +00002054#ifdef USE_KQEMU
2055 /* XXX: should not depend on cpu context */
2056 env = first_cpu;
2057 if (env->kqemu_enabled) {
2058 kqemu_set_phys_mem(start_addr, size, phys_offset);
2059 }
2060#endif
bellard5fd386f2004-05-23 21:11:22 +00002061 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
blueswir149e9fba2007-05-30 17:25:06 +00002062 end_addr = start_addr + (target_phys_addr_t)size;
2063 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
blueswir1db7b5422007-05-26 17:36:03 +00002064 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2065 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
aurel3200f82b82008-04-27 21:12:55 +00002066 ram_addr_t orig_memory = p->phys_offset;
blueswir1db7b5422007-05-26 17:36:03 +00002067 target_phys_addr_t start_addr2, end_addr2;
2068 int need_subpage = 0;
2069
2070 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2071 need_subpage);
blueswir14254fab2008-01-01 16:57:19 +00002072 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002073 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2074 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2075 &p->phys_offset, orig_memory);
2076 } else {
2077 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2078 >> IO_MEM_SHIFT];
2079 }
2080 subpage_register(subpage, start_addr2, end_addr2, phys_offset);
2081 } else {
2082 p->phys_offset = phys_offset;
2083 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2084 (phys_offset & IO_MEM_ROMD))
2085 phys_offset += TARGET_PAGE_SIZE;
2086 }
2087 } else {
2088 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2089 p->phys_offset = phys_offset;
2090 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2091 (phys_offset & IO_MEM_ROMD))
2092 phys_offset += TARGET_PAGE_SIZE;
2093 else {
2094 target_phys_addr_t start_addr2, end_addr2;
2095 int need_subpage = 0;
2096
2097 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2098 end_addr2, need_subpage);
2099
blueswir14254fab2008-01-01 16:57:19 +00002100 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
blueswir1db7b5422007-05-26 17:36:03 +00002101 subpage = subpage_init((addr & TARGET_PAGE_MASK),
2102 &p->phys_offset, IO_MEM_UNASSIGNED);
2103 subpage_register(subpage, start_addr2, end_addr2,
2104 phys_offset);
2105 }
2106 }
2107 }
bellard33417e72003-08-10 21:47:01 +00002108 }
ths3b46e622007-09-17 08:09:54 +00002109
bellard9d420372006-06-25 22:25:22 +00002110 /* since each CPU stores ram addresses in its TLB cache, we must
2111 reset the modified entries */
2112 /* XXX: slow ! */
2113 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2114 tlb_flush(env, 1);
2115 }
bellard33417e72003-08-10 21:47:01 +00002116}
2117
bellardba863452006-09-24 18:41:10 +00002118/* XXX: temporary until new memory mapping API */
aurel3200f82b82008-04-27 21:12:55 +00002119ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
bellardba863452006-09-24 18:41:10 +00002120{
2121 PhysPageDesc *p;
2122
2123 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2124 if (!p)
2125 return IO_MEM_UNASSIGNED;
2126 return p->phys_offset;
2127}
2128
bellarde9a1ab12007-02-08 23:08:38 +00002129/* XXX: better than nothing */
aurel3200f82b82008-04-27 21:12:55 +00002130ram_addr_t qemu_ram_alloc(ram_addr_t size)
bellarde9a1ab12007-02-08 23:08:38 +00002131{
2132 ram_addr_t addr;
balrog7fb4fdc2008-04-24 17:59:27 +00002133 if ((phys_ram_alloc_offset + size) > phys_ram_size) {
bellarded441462008-05-23 11:56:45 +00002134 fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
2135 (uint64_t)size, (uint64_t)phys_ram_size);
bellarde9a1ab12007-02-08 23:08:38 +00002136 abort();
2137 }
2138 addr = phys_ram_alloc_offset;
2139 phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
2140 return addr;
2141}
2142
2143void qemu_ram_free(ram_addr_t addr)
2144{
2145}
2146
bellarda4193c82004-06-03 14:01:43 +00002147static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
bellard33417e72003-08-10 21:47:01 +00002148{
pbrook67d3b952006-12-18 05:03:52 +00002149#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002150 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
pbrook67d3b952006-12-18 05:03:52 +00002151#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002152#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002153 do_unassigned_access(addr, 0, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002154#elif TARGET_CRIS
2155 do_unassigned_access(addr, 0, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002156#endif
bellard33417e72003-08-10 21:47:01 +00002157 return 0;
2158}
2159
bellarda4193c82004-06-03 14:01:43 +00002160static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard33417e72003-08-10 21:47:01 +00002161{
pbrook67d3b952006-12-18 05:03:52 +00002162#ifdef DEBUG_UNASSIGNED
blueswir1ab3d1722007-11-04 07:31:40 +00002163 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
pbrook67d3b952006-12-18 05:03:52 +00002164#endif
blueswir1b4f0a312007-05-06 17:59:24 +00002165#ifdef TARGET_SPARC
blueswir16c36d3f2007-05-17 19:30:10 +00002166 do_unassigned_access(addr, 1, 0, 0);
thsf1ccf902007-10-08 13:16:14 +00002167#elif TARGET_CRIS
2168 do_unassigned_access(addr, 1, 0, 0);
blueswir1b4f0a312007-05-06 17:59:24 +00002169#endif
bellard33417e72003-08-10 21:47:01 +00002170}
2171
2172static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2173 unassigned_mem_readb,
2174 unassigned_mem_readb,
2175 unassigned_mem_readb,
2176};
2177
2178static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2179 unassigned_mem_writeb,
2180 unassigned_mem_writeb,
2181 unassigned_mem_writeb,
2182};
2183
bellarda4193c82004-06-03 14:01:43 +00002184static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002185{
bellard3a7d9292005-08-21 09:26:42 +00002186 unsigned long ram_addr;
2187 int dirty_flags;
2188 ram_addr = addr - (unsigned long)phys_ram_base;
2189 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2190 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2191#if !defined(CONFIG_USER_ONLY)
2192 tb_invalidate_phys_page_fast(ram_addr, 1);
2193 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2194#endif
2195 }
bellardc27004e2005-01-03 23:35:10 +00002196 stb_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002197#ifdef USE_KQEMU
2198 if (cpu_single_env->kqemu_enabled &&
2199 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2200 kqemu_modify_page(cpu_single_env, ram_addr);
2201#endif
bellardf23db162005-08-21 19:12:28 +00002202 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2203 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2204 /* we remove the notdirty callback only if the code has been
2205 flushed */
2206 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002207 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002208}
2209
bellarda4193c82004-06-03 14:01:43 +00002210static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002211{
bellard3a7d9292005-08-21 09:26:42 +00002212 unsigned long ram_addr;
2213 int dirty_flags;
2214 ram_addr = addr - (unsigned long)phys_ram_base;
2215 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2216 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2217#if !defined(CONFIG_USER_ONLY)
2218 tb_invalidate_phys_page_fast(ram_addr, 2);
2219 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2220#endif
2221 }
bellardc27004e2005-01-03 23:35:10 +00002222 stw_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002223#ifdef USE_KQEMU
2224 if (cpu_single_env->kqemu_enabled &&
2225 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2226 kqemu_modify_page(cpu_single_env, ram_addr);
2227#endif
bellardf23db162005-08-21 19:12:28 +00002228 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2229 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2230 /* we remove the notdirty callback only if the code has been
2231 flushed */
2232 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002233 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002234}
2235
bellarda4193c82004-06-03 14:01:43 +00002236static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellard1ccde1c2004-02-06 19:46:14 +00002237{
bellard3a7d9292005-08-21 09:26:42 +00002238 unsigned long ram_addr;
2239 int dirty_flags;
2240 ram_addr = addr - (unsigned long)phys_ram_base;
2241 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2242 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2243#if !defined(CONFIG_USER_ONLY)
2244 tb_invalidate_phys_page_fast(ram_addr, 4);
2245 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2246#endif
2247 }
bellardc27004e2005-01-03 23:35:10 +00002248 stl_p((uint8_t *)(long)addr, val);
bellardf32fc642006-02-08 22:43:39 +00002249#ifdef USE_KQEMU
2250 if (cpu_single_env->kqemu_enabled &&
2251 (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2252 kqemu_modify_page(cpu_single_env, ram_addr);
2253#endif
bellardf23db162005-08-21 19:12:28 +00002254 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2255 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2256 /* we remove the notdirty callback only if the code has been
2257 flushed */
2258 if (dirty_flags == 0xff)
bellard6a00d602005-11-21 23:25:50 +00002259 tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
bellard1ccde1c2004-02-06 19:46:14 +00002260}
2261
bellard3a7d9292005-08-21 09:26:42 +00002262static CPUReadMemoryFunc *error_mem_read[3] = {
2263 NULL, /* never used */
2264 NULL, /* never used */
2265 NULL, /* never used */
2266};
2267
bellard1ccde1c2004-02-06 19:46:14 +00002268static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2269 notdirty_mem_writeb,
2270 notdirty_mem_writew,
2271 notdirty_mem_writel,
2272};
2273
pbrook6658ffb2007-03-16 23:58:11 +00002274/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2275 so these check for a hit then pass through to the normal out-of-line
2276 phys routines. */
2277static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2278{
2279 return ldub_phys(addr);
2280}
2281
2282static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2283{
2284 return lduw_phys(addr);
2285}
2286
2287static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2288{
2289 return ldl_phys(addr);
2290}
2291
2292/* Generate a debug exception if a watchpoint has been hit.
2293 Returns the real physical address of the access. addr will be a host
balrogd79acba2007-06-26 20:01:13 +00002294 address in case of a RAM location. */
pbrook6658ffb2007-03-16 23:58:11 +00002295static target_ulong check_watchpoint(target_phys_addr_t addr)
2296{
2297 CPUState *env = cpu_single_env;
2298 target_ulong watch;
2299 target_ulong retaddr;
2300 int i;
2301
2302 retaddr = addr;
2303 for (i = 0; i < env->nb_watchpoints; i++) {
2304 watch = env->watchpoint[i].vaddr;
2305 if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
balrogd79acba2007-06-26 20:01:13 +00002306 retaddr = addr - env->watchpoint[i].addend;
pbrook6658ffb2007-03-16 23:58:11 +00002307 if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2308 cpu_single_env->watchpoint_hit = i + 1;
2309 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2310 break;
2311 }
2312 }
2313 }
2314 return retaddr;
2315}
2316
2317static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2318 uint32_t val)
2319{
2320 addr = check_watchpoint(addr);
2321 stb_phys(addr, val);
2322}
2323
2324static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2325 uint32_t val)
2326{
2327 addr = check_watchpoint(addr);
2328 stw_phys(addr, val);
2329}
2330
2331static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2332 uint32_t val)
2333{
2334 addr = check_watchpoint(addr);
2335 stl_phys(addr, val);
2336}
2337
2338static CPUReadMemoryFunc *watch_mem_read[3] = {
2339 watch_mem_readb,
2340 watch_mem_readw,
2341 watch_mem_readl,
2342};
2343
2344static CPUWriteMemoryFunc *watch_mem_write[3] = {
2345 watch_mem_writeb,
2346 watch_mem_writew,
2347 watch_mem_writel,
2348};
pbrook6658ffb2007-03-16 23:58:11 +00002349
blueswir1db7b5422007-05-26 17:36:03 +00002350static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2351 unsigned int len)
2352{
blueswir1db7b5422007-05-26 17:36:03 +00002353 uint32_t ret;
2354 unsigned int idx;
2355
2356 idx = SUBPAGE_IDX(addr - mmio->base);
2357#if defined(DEBUG_SUBPAGE)
2358 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2359 mmio, len, addr, idx);
2360#endif
blueswir13ee89922008-01-02 19:45:26 +00002361 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
blueswir1db7b5422007-05-26 17:36:03 +00002362
2363 return ret;
2364}
2365
2366static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2367 uint32_t value, unsigned int len)
2368{
blueswir1db7b5422007-05-26 17:36:03 +00002369 unsigned int idx;
2370
2371 idx = SUBPAGE_IDX(addr - mmio->base);
2372#if defined(DEBUG_SUBPAGE)
2373 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2374 mmio, len, addr, idx, value);
2375#endif
blueswir13ee89922008-01-02 19:45:26 +00002376 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
blueswir1db7b5422007-05-26 17:36:03 +00002377}
2378
2379static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2380{
2381#if defined(DEBUG_SUBPAGE)
2382 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2383#endif
2384
2385 return subpage_readlen(opaque, addr, 0);
2386}
2387
2388static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2389 uint32_t value)
2390{
2391#if defined(DEBUG_SUBPAGE)
2392 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2393#endif
2394 subpage_writelen(opaque, addr, value, 0);
2395}
2396
2397static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2398{
2399#if defined(DEBUG_SUBPAGE)
2400 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2401#endif
2402
2403 return subpage_readlen(opaque, addr, 1);
2404}
2405
2406static void subpage_writew (void *opaque, target_phys_addr_t addr,
2407 uint32_t value)
2408{
2409#if defined(DEBUG_SUBPAGE)
2410 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2411#endif
2412 subpage_writelen(opaque, addr, value, 1);
2413}
2414
2415static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2416{
2417#if defined(DEBUG_SUBPAGE)
2418 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2419#endif
2420
2421 return subpage_readlen(opaque, addr, 2);
2422}
2423
2424static void subpage_writel (void *opaque,
2425 target_phys_addr_t addr, uint32_t value)
2426{
2427#if defined(DEBUG_SUBPAGE)
2428 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2429#endif
2430 subpage_writelen(opaque, addr, value, 2);
2431}
2432
2433static CPUReadMemoryFunc *subpage_read[] = {
2434 &subpage_readb,
2435 &subpage_readw,
2436 &subpage_readl,
2437};
2438
2439static CPUWriteMemoryFunc *subpage_write[] = {
2440 &subpage_writeb,
2441 &subpage_writew,
2442 &subpage_writel,
2443};
2444
2445static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
aurel3200f82b82008-04-27 21:12:55 +00002446 ram_addr_t memory)
blueswir1db7b5422007-05-26 17:36:03 +00002447{
2448 int idx, eidx;
blueswir14254fab2008-01-01 16:57:19 +00002449 unsigned int i;
blueswir1db7b5422007-05-26 17:36:03 +00002450
2451 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2452 return -1;
2453 idx = SUBPAGE_IDX(start);
2454 eidx = SUBPAGE_IDX(end);
2455#if defined(DEBUG_SUBPAGE)
2456 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
2457 mmio, start, end, idx, eidx, memory);
2458#endif
2459 memory >>= IO_MEM_SHIFT;
2460 for (; idx <= eidx; idx++) {
blueswir14254fab2008-01-01 16:57:19 +00002461 for (i = 0; i < 4; i++) {
blueswir13ee89922008-01-02 19:45:26 +00002462 if (io_mem_read[memory][i]) {
2463 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2464 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
2465 }
2466 if (io_mem_write[memory][i]) {
2467 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2468 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
2469 }
blueswir14254fab2008-01-01 16:57:19 +00002470 }
blueswir1db7b5422007-05-26 17:36:03 +00002471 }
2472
2473 return 0;
2474}
2475
aurel3200f82b82008-04-27 21:12:55 +00002476static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
2477 ram_addr_t orig_memory)
blueswir1db7b5422007-05-26 17:36:03 +00002478{
2479 subpage_t *mmio;
2480 int subpage_memory;
2481
2482 mmio = qemu_mallocz(sizeof(subpage_t));
2483 if (mmio != NULL) {
2484 mmio->base = base;
2485 subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
2486#if defined(DEBUG_SUBPAGE)
2487 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2488 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
2489#endif
2490 *phys = subpage_memory | IO_MEM_SUBPAGE;
2491 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
2492 }
2493
2494 return mmio;
2495}
2496
bellard33417e72003-08-10 21:47:01 +00002497static void io_mem_init(void)
2498{
bellard3a7d9292005-08-21 09:26:42 +00002499 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
bellarda4193c82004-06-03 14:01:43 +00002500 cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
bellard3a7d9292005-08-21 09:26:42 +00002501 cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002502 io_mem_nb = 5;
2503
pbrook6658ffb2007-03-16 23:58:11 +00002504 io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2505 watch_mem_write, NULL);
bellard1ccde1c2004-02-06 19:46:14 +00002506 /* alloc dirty bits array */
bellard0a962c02005-02-10 22:00:27 +00002507 phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
bellard3a7d9292005-08-21 09:26:42 +00002508 memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
bellard33417e72003-08-10 21:47:01 +00002509}
2510
2511/* mem_read and mem_write are arrays of functions containing the
2512 function to access byte (index 0), word (index 1) and dword (index
blueswir13ee89922008-01-02 19:45:26 +00002513 2). Functions can be omitted with a NULL function pointer. The
2514 registered functions may be modified dynamically later.
2515 If io_index is non zero, the corresponding io zone is
blueswir14254fab2008-01-01 16:57:19 +00002516 modified. If it is zero, a new io zone is allocated. The return
2517 value can be used with cpu_register_physical_memory(). (-1) is
2518 returned if error. */
bellard33417e72003-08-10 21:47:01 +00002519int cpu_register_io_memory(int io_index,
2520 CPUReadMemoryFunc **mem_read,
bellarda4193c82004-06-03 14:01:43 +00002521 CPUWriteMemoryFunc **mem_write,
2522 void *opaque)
bellard33417e72003-08-10 21:47:01 +00002523{
blueswir14254fab2008-01-01 16:57:19 +00002524 int i, subwidth = 0;
bellard33417e72003-08-10 21:47:01 +00002525
2526 if (io_index <= 0) {
bellardb5ff1b32005-11-26 10:38:39 +00002527 if (io_mem_nb >= IO_MEM_NB_ENTRIES)
bellard33417e72003-08-10 21:47:01 +00002528 return -1;
2529 io_index = io_mem_nb++;
2530 } else {
2531 if (io_index >= IO_MEM_NB_ENTRIES)
2532 return -1;
2533 }
bellardb5ff1b32005-11-26 10:38:39 +00002534
bellard33417e72003-08-10 21:47:01 +00002535 for(i = 0;i < 3; i++) {
blueswir14254fab2008-01-01 16:57:19 +00002536 if (!mem_read[i] || !mem_write[i])
2537 subwidth = IO_MEM_SUBWIDTH;
bellard33417e72003-08-10 21:47:01 +00002538 io_mem_read[io_index][i] = mem_read[i];
2539 io_mem_write[io_index][i] = mem_write[i];
2540 }
bellarda4193c82004-06-03 14:01:43 +00002541 io_mem_opaque[io_index] = opaque;
blueswir14254fab2008-01-01 16:57:19 +00002542 return (io_index << IO_MEM_SHIFT) | subwidth;
bellard33417e72003-08-10 21:47:01 +00002543}
bellard61382a52003-10-27 21:22:23 +00002544
bellard8926b512004-10-10 15:14:20 +00002545CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2546{
2547 return io_mem_write[io_index >> IO_MEM_SHIFT];
2548}
2549
2550CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2551{
2552 return io_mem_read[io_index >> IO_MEM_SHIFT];
2553}
2554
pbrooke2eef172008-06-08 01:09:01 +00002555#endif /* !defined(CONFIG_USER_ONLY) */
2556
bellard13eb76e2004-01-24 15:23:36 +00002557/* physical memory access (slow version, mainly for debug) */
2558#if defined(CONFIG_USER_ONLY)
ths5fafdf22007-09-16 21:08:06 +00002559void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002560 int len, int is_write)
2561{
2562 int l, flags;
2563 target_ulong page;
pbrook53a59602006-03-25 19:31:22 +00002564 void * p;
bellard13eb76e2004-01-24 15:23:36 +00002565
2566 while (len > 0) {
2567 page = addr & TARGET_PAGE_MASK;
2568 l = (page + TARGET_PAGE_SIZE) - addr;
2569 if (l > len)
2570 l = len;
2571 flags = page_get_flags(page);
2572 if (!(flags & PAGE_VALID))
2573 return;
2574 if (is_write) {
2575 if (!(flags & PAGE_WRITE))
2576 return;
bellard579a97f2007-11-11 14:26:47 +00002577 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002578 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
bellard579a97f2007-11-11 14:26:47 +00002579 /* FIXME - should this return an error rather than just fail? */
2580 return;
aurel3272fb7da2008-04-27 23:53:45 +00002581 memcpy(p, buf, l);
2582 unlock_user(p, addr, l);
bellard13eb76e2004-01-24 15:23:36 +00002583 } else {
2584 if (!(flags & PAGE_READ))
2585 return;
bellard579a97f2007-11-11 14:26:47 +00002586 /* XXX: this code should not depend on lock_user */
aurel3272fb7da2008-04-27 23:53:45 +00002587 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
bellard579a97f2007-11-11 14:26:47 +00002588 /* FIXME - should this return an error rather than just fail? */
2589 return;
aurel3272fb7da2008-04-27 23:53:45 +00002590 memcpy(buf, p, l);
aurel325b257572008-04-28 08:54:59 +00002591 unlock_user(p, addr, 0);
bellard13eb76e2004-01-24 15:23:36 +00002592 }
2593 len -= l;
2594 buf += l;
2595 addr += l;
2596 }
2597}
bellard8df1cd02005-01-28 22:37:22 +00002598
bellard13eb76e2004-01-24 15:23:36 +00002599#else
ths5fafdf22007-09-16 21:08:06 +00002600void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
bellard13eb76e2004-01-24 15:23:36 +00002601 int len, int is_write)
2602{
2603 int l, io_index;
2604 uint8_t *ptr;
2605 uint32_t val;
bellard2e126692004-04-25 21:28:44 +00002606 target_phys_addr_t page;
2607 unsigned long pd;
bellard92e873b2004-05-21 14:52:29 +00002608 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002609
bellard13eb76e2004-01-24 15:23:36 +00002610 while (len > 0) {
2611 page = addr & TARGET_PAGE_MASK;
2612 l = (page + TARGET_PAGE_SIZE) - addr;
2613 if (l > len)
2614 l = len;
bellard92e873b2004-05-21 14:52:29 +00002615 p = phys_page_find(page >> TARGET_PAGE_BITS);
bellard13eb76e2004-01-24 15:23:36 +00002616 if (!p) {
2617 pd = IO_MEM_UNASSIGNED;
2618 } else {
2619 pd = p->phys_offset;
2620 }
ths3b46e622007-09-17 08:09:54 +00002621
bellard13eb76e2004-01-24 15:23:36 +00002622 if (is_write) {
bellard3a7d9292005-08-21 09:26:42 +00002623 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard13eb76e2004-01-24 15:23:36 +00002624 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
bellard6a00d602005-11-21 23:25:50 +00002625 /* XXX: could force cpu_single_env to NULL to avoid
2626 potential bugs */
bellard13eb76e2004-01-24 15:23:36 +00002627 if (l >= 4 && ((addr & 3) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002628 /* 32 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002629 val = ldl_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002630 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002631 l = 4;
2632 } else if (l >= 2 && ((addr & 1) == 0)) {
bellard1c213d12005-09-03 10:49:04 +00002633 /* 16 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002634 val = lduw_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002635 io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002636 l = 2;
2637 } else {
bellard1c213d12005-09-03 10:49:04 +00002638 /* 8 bit write access */
bellardc27004e2005-01-03 23:35:10 +00002639 val = ldub_p(buf);
bellarda4193c82004-06-03 14:01:43 +00002640 io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
bellard13eb76e2004-01-24 15:23:36 +00002641 l = 1;
2642 }
2643 } else {
bellardb448f2f2004-02-25 23:24:04 +00002644 unsigned long addr1;
2645 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
bellard13eb76e2004-01-24 15:23:36 +00002646 /* RAM case */
bellardb448f2f2004-02-25 23:24:04 +00002647 ptr = phys_ram_base + addr1;
bellard13eb76e2004-01-24 15:23:36 +00002648 memcpy(ptr, buf, l);
bellard3a7d9292005-08-21 09:26:42 +00002649 if (!cpu_physical_memory_is_dirty(addr1)) {
2650 /* invalidate code */
2651 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2652 /* set dirty bit */
ths5fafdf22007-09-16 21:08:06 +00002653 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
bellardf23db162005-08-21 19:12:28 +00002654 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002655 }
bellard13eb76e2004-01-24 15:23:36 +00002656 }
2657 } else {
ths5fafdf22007-09-16 21:08:06 +00002658 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002659 !(pd & IO_MEM_ROMD)) {
bellard13eb76e2004-01-24 15:23:36 +00002660 /* I/O case */
2661 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2662 if (l >= 4 && ((addr & 3) == 0)) {
2663 /* 32 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002664 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002665 stl_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002666 l = 4;
2667 } else if (l >= 2 && ((addr & 1) == 0)) {
2668 /* 16 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002669 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002670 stw_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002671 l = 2;
2672 } else {
bellard1c213d12005-09-03 10:49:04 +00002673 /* 8 bit read access */
bellarda4193c82004-06-03 14:01:43 +00002674 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
bellardc27004e2005-01-03 23:35:10 +00002675 stb_p(buf, val);
bellard13eb76e2004-01-24 15:23:36 +00002676 l = 1;
2677 }
2678 } else {
2679 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002680 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard13eb76e2004-01-24 15:23:36 +00002681 (addr & ~TARGET_PAGE_MASK);
2682 memcpy(buf, ptr, l);
2683 }
2684 }
2685 len -= l;
2686 buf += l;
2687 addr += l;
2688 }
2689}
bellard8df1cd02005-01-28 22:37:22 +00002690
bellardd0ecd2a2006-04-23 17:14:48 +00002691/* used for ROM loading : can write in RAM and ROM */
ths5fafdf22007-09-16 21:08:06 +00002692void cpu_physical_memory_write_rom(target_phys_addr_t addr,
bellardd0ecd2a2006-04-23 17:14:48 +00002693 const uint8_t *buf, int len)
2694{
2695 int l;
2696 uint8_t *ptr;
2697 target_phys_addr_t page;
2698 unsigned long pd;
2699 PhysPageDesc *p;
ths3b46e622007-09-17 08:09:54 +00002700
bellardd0ecd2a2006-04-23 17:14:48 +00002701 while (len > 0) {
2702 page = addr & TARGET_PAGE_MASK;
2703 l = (page + TARGET_PAGE_SIZE) - addr;
2704 if (l > len)
2705 l = len;
2706 p = phys_page_find(page >> TARGET_PAGE_BITS);
2707 if (!p) {
2708 pd = IO_MEM_UNASSIGNED;
2709 } else {
2710 pd = p->phys_offset;
2711 }
ths3b46e622007-09-17 08:09:54 +00002712
bellardd0ecd2a2006-04-23 17:14:48 +00002713 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
bellard2a4188a2006-06-25 21:54:59 +00002714 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2715 !(pd & IO_MEM_ROMD)) {
bellardd0ecd2a2006-04-23 17:14:48 +00002716 /* do nothing */
2717 } else {
2718 unsigned long addr1;
2719 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2720 /* ROM/RAM case */
2721 ptr = phys_ram_base + addr1;
2722 memcpy(ptr, buf, l);
2723 }
2724 len -= l;
2725 buf += l;
2726 addr += l;
2727 }
2728}
2729
2730
bellard8df1cd02005-01-28 22:37:22 +00002731/* warning: addr must be aligned */
2732uint32_t ldl_phys(target_phys_addr_t addr)
2733{
2734 int io_index;
2735 uint8_t *ptr;
2736 uint32_t val;
2737 unsigned long pd;
2738 PhysPageDesc *p;
2739
2740 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2741 if (!p) {
2742 pd = IO_MEM_UNASSIGNED;
2743 } else {
2744 pd = p->phys_offset;
2745 }
ths3b46e622007-09-17 08:09:54 +00002746
ths5fafdf22007-09-16 21:08:06 +00002747 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
bellard2a4188a2006-06-25 21:54:59 +00002748 !(pd & IO_MEM_ROMD)) {
bellard8df1cd02005-01-28 22:37:22 +00002749 /* I/O case */
2750 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2751 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2752 } else {
2753 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002754 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002755 (addr & ~TARGET_PAGE_MASK);
2756 val = ldl_p(ptr);
2757 }
2758 return val;
2759}
2760
bellard84b7b8e2005-11-28 21:19:04 +00002761/* warning: addr must be aligned */
2762uint64_t ldq_phys(target_phys_addr_t addr)
2763{
2764 int io_index;
2765 uint8_t *ptr;
2766 uint64_t val;
2767 unsigned long pd;
2768 PhysPageDesc *p;
2769
2770 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2771 if (!p) {
2772 pd = IO_MEM_UNASSIGNED;
2773 } else {
2774 pd = p->phys_offset;
2775 }
ths3b46e622007-09-17 08:09:54 +00002776
bellard2a4188a2006-06-25 21:54:59 +00002777 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2778 !(pd & IO_MEM_ROMD)) {
bellard84b7b8e2005-11-28 21:19:04 +00002779 /* I/O case */
2780 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2781#ifdef TARGET_WORDS_BIGENDIAN
2782 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2783 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2784#else
2785 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2786 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2787#endif
2788 } else {
2789 /* RAM case */
ths5fafdf22007-09-16 21:08:06 +00002790 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard84b7b8e2005-11-28 21:19:04 +00002791 (addr & ~TARGET_PAGE_MASK);
2792 val = ldq_p(ptr);
2793 }
2794 return val;
2795}
2796
bellardaab33092005-10-30 20:48:42 +00002797/* XXX: optimize */
2798uint32_t ldub_phys(target_phys_addr_t addr)
2799{
2800 uint8_t val;
2801 cpu_physical_memory_read(addr, &val, 1);
2802 return val;
2803}
2804
2805/* XXX: optimize */
2806uint32_t lduw_phys(target_phys_addr_t addr)
2807{
2808 uint16_t val;
2809 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2810 return tswap16(val);
2811}
2812
bellard8df1cd02005-01-28 22:37:22 +00002813/* warning: addr must be aligned. The ram page is not masked as dirty
2814 and the code inside is not invalidated. It is useful if the dirty
2815 bits are used to track modified PTEs */
2816void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2817{
2818 int io_index;
2819 uint8_t *ptr;
2820 unsigned long pd;
2821 PhysPageDesc *p;
2822
2823 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2824 if (!p) {
2825 pd = IO_MEM_UNASSIGNED;
2826 } else {
2827 pd = p->phys_offset;
2828 }
ths3b46e622007-09-17 08:09:54 +00002829
bellard3a7d9292005-08-21 09:26:42 +00002830 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002831 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2832 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2833 } else {
ths5fafdf22007-09-16 21:08:06 +00002834 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
bellard8df1cd02005-01-28 22:37:22 +00002835 (addr & ~TARGET_PAGE_MASK);
2836 stl_p(ptr, val);
2837 }
2838}
2839
j_mayerbc98a7e2007-04-04 07:55:12 +00002840void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2841{
2842 int io_index;
2843 uint8_t *ptr;
2844 unsigned long pd;
2845 PhysPageDesc *p;
2846
2847 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2848 if (!p) {
2849 pd = IO_MEM_UNASSIGNED;
2850 } else {
2851 pd = p->phys_offset;
2852 }
ths3b46e622007-09-17 08:09:54 +00002853
j_mayerbc98a7e2007-04-04 07:55:12 +00002854 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2855 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2856#ifdef TARGET_WORDS_BIGENDIAN
2857 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2858 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2859#else
2860 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2861 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2862#endif
2863 } else {
ths5fafdf22007-09-16 21:08:06 +00002864 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
j_mayerbc98a7e2007-04-04 07:55:12 +00002865 (addr & ~TARGET_PAGE_MASK);
2866 stq_p(ptr, val);
2867 }
2868}
2869
bellard8df1cd02005-01-28 22:37:22 +00002870/* warning: addr must be aligned */
bellard8df1cd02005-01-28 22:37:22 +00002871void stl_phys(target_phys_addr_t addr, uint32_t val)
2872{
2873 int io_index;
2874 uint8_t *ptr;
2875 unsigned long pd;
2876 PhysPageDesc *p;
2877
2878 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2879 if (!p) {
2880 pd = IO_MEM_UNASSIGNED;
2881 } else {
2882 pd = p->phys_offset;
2883 }
ths3b46e622007-09-17 08:09:54 +00002884
bellard3a7d9292005-08-21 09:26:42 +00002885 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
bellard8df1cd02005-01-28 22:37:22 +00002886 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2887 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2888 } else {
2889 unsigned long addr1;
2890 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2891 /* RAM case */
2892 ptr = phys_ram_base + addr1;
2893 stl_p(ptr, val);
bellard3a7d9292005-08-21 09:26:42 +00002894 if (!cpu_physical_memory_is_dirty(addr1)) {
2895 /* invalidate code */
2896 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2897 /* set dirty bit */
bellardf23db162005-08-21 19:12:28 +00002898 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2899 (0xff & ~CODE_DIRTY_FLAG);
bellard3a7d9292005-08-21 09:26:42 +00002900 }
bellard8df1cd02005-01-28 22:37:22 +00002901 }
2902}
2903
bellardaab33092005-10-30 20:48:42 +00002904/* XXX: optimize */
2905void stb_phys(target_phys_addr_t addr, uint32_t val)
2906{
2907 uint8_t v = val;
2908 cpu_physical_memory_write(addr, &v, 1);
2909}
2910
2911/* XXX: optimize */
2912void stw_phys(target_phys_addr_t addr, uint32_t val)
2913{
2914 uint16_t v = tswap16(val);
2915 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2916}
2917
2918/* XXX: optimize */
2919void stq_phys(target_phys_addr_t addr, uint64_t val)
2920{
2921 val = tswap64(val);
2922 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2923}
2924
bellard13eb76e2004-01-24 15:23:36 +00002925#endif
2926
2927/* virtual memory access for debug */
ths5fafdf22007-09-16 21:08:06 +00002928int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
bellardb448f2f2004-02-25 23:24:04 +00002929 uint8_t *buf, int len, int is_write)
bellard13eb76e2004-01-24 15:23:36 +00002930{
2931 int l;
j_mayer9b3c35e2007-04-07 11:21:28 +00002932 target_phys_addr_t phys_addr;
2933 target_ulong page;
bellard13eb76e2004-01-24 15:23:36 +00002934
2935 while (len > 0) {
2936 page = addr & TARGET_PAGE_MASK;
2937 phys_addr = cpu_get_phys_page_debug(env, page);
2938 /* if no physical page mapped, return an error */
2939 if (phys_addr == -1)
2940 return -1;
2941 l = (page + TARGET_PAGE_SIZE) - addr;
2942 if (l > len)
2943 l = len;
ths5fafdf22007-09-16 21:08:06 +00002944 cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
bellardb448f2f2004-02-25 23:24:04 +00002945 buf, l, is_write);
bellard13eb76e2004-01-24 15:23:36 +00002946 len -= l;
2947 buf += l;
2948 addr += l;
2949 }
2950 return 0;
2951}
2952
bellarde3db7222005-01-26 22:00:47 +00002953void dump_exec_info(FILE *f,
2954 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2955{
2956 int i, target_code_size, max_target_code_size;
2957 int direct_jmp_count, direct_jmp2_count, cross_page;
2958 TranslationBlock *tb;
ths3b46e622007-09-17 08:09:54 +00002959
bellarde3db7222005-01-26 22:00:47 +00002960 target_code_size = 0;
2961 max_target_code_size = 0;
2962 cross_page = 0;
2963 direct_jmp_count = 0;
2964 direct_jmp2_count = 0;
2965 for(i = 0; i < nb_tbs; i++) {
2966 tb = &tbs[i];
2967 target_code_size += tb->size;
2968 if (tb->size > max_target_code_size)
2969 max_target_code_size = tb->size;
2970 if (tb->page_addr[1] != -1)
2971 cross_page++;
2972 if (tb->tb_next_offset[0] != 0xffff) {
2973 direct_jmp_count++;
2974 if (tb->tb_next_offset[1] != 0xffff) {
2975 direct_jmp2_count++;
2976 }
2977 }
2978 }
2979 /* XXX: avoid using doubles ? */
bellard57fec1f2008-02-01 10:50:11 +00002980 cpu_fprintf(f, "Translation buffer state:\n");
bellard26a5f132008-05-28 12:30:31 +00002981 cpu_fprintf(f, "gen code size %ld/%ld\n",
2982 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
2983 cpu_fprintf(f, "TB count %d/%d\n",
2984 nb_tbs, code_gen_max_blocks);
ths5fafdf22007-09-16 21:08:06 +00002985 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
bellarde3db7222005-01-26 22:00:47 +00002986 nb_tbs ? target_code_size / nb_tbs : 0,
2987 max_target_code_size);
ths5fafdf22007-09-16 21:08:06 +00002988 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
bellarde3db7222005-01-26 22:00:47 +00002989 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2990 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
ths5fafdf22007-09-16 21:08:06 +00002991 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2992 cross_page,
bellarde3db7222005-01-26 22:00:47 +00002993 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2994 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
ths5fafdf22007-09-16 21:08:06 +00002995 direct_jmp_count,
bellarde3db7222005-01-26 22:00:47 +00002996 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2997 direct_jmp2_count,
2998 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
bellard57fec1f2008-02-01 10:50:11 +00002999 cpu_fprintf(f, "\nStatistics:\n");
bellarde3db7222005-01-26 22:00:47 +00003000 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3001 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3002 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
bellardb67d9a52008-05-23 09:57:34 +00003003 tcg_dump_info(f, cpu_fprintf);
bellarde3db7222005-01-26 22:00:47 +00003004}
3005
ths5fafdf22007-09-16 21:08:06 +00003006#if !defined(CONFIG_USER_ONLY)
bellard61382a52003-10-27 21:22:23 +00003007
3008#define MMUSUFFIX _cmmu
3009#define GETPC() NULL
3010#define env cpu_single_env
bellardb769d8f2004-10-03 15:07:13 +00003011#define SOFTMMU_CODE_ACCESS
bellard61382a52003-10-27 21:22:23 +00003012
3013#define SHIFT 0
3014#include "softmmu_template.h"
3015
3016#define SHIFT 1
3017#include "softmmu_template.h"
3018
3019#define SHIFT 2
3020#include "softmmu_template.h"
3021
3022#define SHIFT 3
3023#include "softmmu_template.h"
3024
3025#undef env
3026
3027#endif