blob: 2ad8a4f3c7a446bc037e64c869d0e8dba92f7baf [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * virtual page mapping and translated block handling
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080018 */
19#include "config.h"
20#ifdef _WIN32
21#define WIN32_LEAN_AND_MEAN
22#include <windows.h>
23#else
24#include <sys/types.h>
25#include <sys/mman.h>
26#endif
27#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
35#include "cpu.h"
36#include "exec-all.h"
37#include "qemu-common.h"
38#include "tcg.h"
39#include "hw/hw.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070040#include "osdep.h"
41#include "kvm.h"
David Turner6a9ef172010-09-09 22:54:36 +020042#include "qemu-timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080043#if defined(CONFIG_USER_ONLY)
44#include <qemu.h>
45#endif
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080046#ifdef CONFIG_MEMCHECK
47#include "memcheck/memcheck_api.h"
48#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080049
50//#define DEBUG_TB_INVALIDATE
51//#define DEBUG_FLUSH
52//#define DEBUG_TLB
53//#define DEBUG_UNASSIGNED
54
55/* make various TB consistency checks */
56//#define DEBUG_TB_CHECK
57//#define DEBUG_TLB_CHECK
58
59//#define DEBUG_IOPORT
60//#define DEBUG_SUBPAGE
61
62#if !defined(CONFIG_USER_ONLY)
63/* TB consistency checks only implemented for usermode emulation. */
64#undef DEBUG_TB_CHECK
65#endif
66
67#define SMC_BITMAP_USE_THRESHOLD 10
68
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069#if defined(TARGET_SPARC64)
70#define TARGET_PHYS_ADDR_SPACE_BITS 41
71#elif defined(TARGET_SPARC)
72#define TARGET_PHYS_ADDR_SPACE_BITS 36
73#elif defined(TARGET_ALPHA)
74#define TARGET_PHYS_ADDR_SPACE_BITS 42
75#define TARGET_VIRT_ADDR_SPACE_BITS 42
76#elif defined(TARGET_PPC64)
77#define TARGET_PHYS_ADDR_SPACE_BITS 42
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070078#elif defined(TARGET_X86_64)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080079#define TARGET_PHYS_ADDR_SPACE_BITS 42
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070080#elif defined(TARGET_I386)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080081#define TARGET_PHYS_ADDR_SPACE_BITS 36
82#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080083#define TARGET_PHYS_ADDR_SPACE_BITS 32
84#endif
85
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070086static TranslationBlock *tbs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080087int code_gen_max_blocks;
88TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070089static int nb_tbs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080090/* any access to the tbs or the page table must use this lock */
91spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
92
93#if defined(__arm__) || defined(__sparc_v9__)
94/* The prologue must be reachable with a direct jump. ARM and Sparc64
95 have limited branch ranges (possibly also PPC) so place it in a
96 section close to code segment. */
97#define code_gen_section \
98 __attribute__((__section__(".gen_code"))) \
99 __attribute__((aligned (32)))
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700100#elif defined(_WIN32)
101/* Maximum alignment for Win32 is 16. */
102#define code_gen_section \
103 __attribute__((aligned (16)))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800104#else
105#define code_gen_section \
106 __attribute__((aligned (32)))
107#endif
108
109uint8_t code_gen_prologue[1024] code_gen_section;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700110static uint8_t *code_gen_buffer;
111static unsigned long code_gen_buffer_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800112/* threshold to flush the translated code buffer */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700113static unsigned long code_gen_buffer_max_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800114uint8_t *code_gen_ptr;
115
116#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800117int phys_ram_fd;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800118uint8_t *phys_ram_dirty;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700119static int in_migration;
120
121typedef struct RAMBlock {
122 uint8_t *host;
123 ram_addr_t offset;
124 ram_addr_t length;
125 struct RAMBlock *next;
126} RAMBlock;
127
128static RAMBlock *ram_blocks;
129/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug)
130 then we can no longer assume contiguous ram offsets, and external uses
131 of this variable will break. */
132ram_addr_t last_ram_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800133#endif
134
135CPUState *first_cpu;
136/* current CPU in the current thread. It is only valid inside
137 cpu_exec() */
138CPUState *cpu_single_env;
139/* 0 = Do not count executed instructions.
140 1 = Precise instruction counting.
141 2 = Adaptive rate instruction counting. */
142int use_icount = 0;
143/* Current instruction counter. While executing translated code this may
144 include some instructions that have not yet been executed. */
145int64_t qemu_icount;
146
147typedef struct PageDesc {
148 /* list of TBs intersecting this ram page */
149 TranslationBlock *first_tb;
150 /* in order to optimize self modifying code, we count the number
151 of lookups we do to a given page to use a bitmap */
152 unsigned int code_write_count;
153 uint8_t *code_bitmap;
154#if defined(CONFIG_USER_ONLY)
155 unsigned long flags;
156#endif
157} PageDesc;
158
159typedef struct PhysPageDesc {
160 /* offset in host memory of the page + io_index in the low bits */
161 ram_addr_t phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700162 ram_addr_t region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800163} PhysPageDesc;
164
165#define L2_BITS 10
166#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
167/* XXX: this is a temporary hack for alpha target.
168 * In the future, this is to be replaced by a multi-level table
169 * to actually be able to handle the complete 64 bits address space.
170 */
171#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
172#else
173#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
174#endif
175
176#define L1_SIZE (1 << L1_BITS)
177#define L2_SIZE (1 << L2_BITS)
178
179unsigned long qemu_real_host_page_size;
180unsigned long qemu_host_page_bits;
181unsigned long qemu_host_page_size;
182unsigned long qemu_host_page_mask;
183
184/* XXX: for system emulation, it could just be an array */
185static PageDesc *l1_map[L1_SIZE];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700186static PhysPageDesc **l1_phys_map;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800187
188#if !defined(CONFIG_USER_ONLY)
189static void io_mem_init(void);
190
191/* io memory support */
192CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
193CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
194void *io_mem_opaque[IO_MEM_NB_ENTRIES];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700195static char io_mem_used[IO_MEM_NB_ENTRIES];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800196static int io_mem_watch;
197#endif
198
199/* log support */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700200#ifdef WIN32
201static const char *logfilename = "qemu.log";
202#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700203static const char *logfilename = "/tmp/qemu.log";
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700204#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800205FILE *logfile;
206int loglevel;
207static int log_append = 0;
208
209/* statistics */
210static int tlb_flush_count;
211static int tb_flush_count;
212static int tb_phys_invalidate_count;
213
214#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
215typedef struct subpage_t {
216 target_phys_addr_t base;
217 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
218 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
219 void *opaque[TARGET_PAGE_SIZE][2][4];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700220 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800221} subpage_t;
222
223#ifdef _WIN32
224static void map_exec(void *addr, long size)
225{
226 DWORD old_protect;
227 VirtualProtect(addr, size,
228 PAGE_EXECUTE_READWRITE, &old_protect);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800229
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800230}
231#else
232static void map_exec(void *addr, long size)
233{
234 unsigned long start, end, page_size;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800235
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800236 page_size = getpagesize();
237 start = (unsigned long)addr;
238 start &= ~(page_size - 1);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800239
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800240 end = (unsigned long)addr + size;
241 end += page_size - 1;
242 end &= ~(page_size - 1);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800243
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800244 mprotect((void *)start, end - start,
245 PROT_READ | PROT_WRITE | PROT_EXEC);
246}
247#endif
248
249static void page_init(void)
250{
251 /* NOTE: we can always suppose that qemu_host_page_size >=
252 TARGET_PAGE_SIZE */
253#ifdef _WIN32
254 {
255 SYSTEM_INFO system_info;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800256
257 GetSystemInfo(&system_info);
258 qemu_real_host_page_size = system_info.dwPageSize;
259 }
260#else
261 qemu_real_host_page_size = getpagesize();
262#endif
263 if (qemu_host_page_size == 0)
264 qemu_host_page_size = qemu_real_host_page_size;
265 if (qemu_host_page_size < TARGET_PAGE_SIZE)
266 qemu_host_page_size = TARGET_PAGE_SIZE;
267 qemu_host_page_bits = 0;
268 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
269 qemu_host_page_bits++;
270 qemu_host_page_mask = ~(qemu_host_page_size - 1);
271 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
272 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
273
274#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
275 {
276 long long startaddr, endaddr;
277 FILE *f;
278 int n;
279
280 mmap_lock();
281 last_brk = (unsigned long)sbrk(0);
282 f = fopen("/proc/self/maps", "r");
283 if (f) {
284 do {
285 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
286 if (n == 2) {
287 startaddr = MIN(startaddr,
288 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
289 endaddr = MIN(endaddr,
290 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
291 page_set_flags(startaddr & TARGET_PAGE_MASK,
292 TARGET_PAGE_ALIGN(endaddr),
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800293 PAGE_RESERVED);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800294 }
295 } while (!feof(f));
296 fclose(f);
297 }
298 mmap_unlock();
299 }
300#endif
301}
302
303static inline PageDesc **page_l1_map(target_ulong index)
304{
305#if TARGET_LONG_BITS > 32
306 /* Host memory outside guest VM. For 32-bit targets we have already
307 excluded high addresses. */
308 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
309 return NULL;
310#endif
311 return &l1_map[index >> L2_BITS];
312}
313
314static inline PageDesc *page_find_alloc(target_ulong index)
315{
316 PageDesc **lp, *p;
317 lp = page_l1_map(index);
318 if (!lp)
319 return NULL;
320
321 p = *lp;
322 if (!p) {
323 /* allocate if not found */
324#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800325 size_t len = sizeof(PageDesc) * L2_SIZE;
326 /* Don't use qemu_malloc because it may recurse. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700327 p = mmap(NULL, len, PROT_READ | PROT_WRITE,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800328 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
329 *lp = p;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700330 if (h2g_valid(p)) {
331 unsigned long addr = h2g(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800332 page_set_flags(addr & TARGET_PAGE_MASK,
333 TARGET_PAGE_ALIGN(addr + len),
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800334 PAGE_RESERVED);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800335 }
336#else
337 p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
338 *lp = p;
339#endif
340 }
341 return p + (index & (L2_SIZE - 1));
342}
343
344static inline PageDesc *page_find(target_ulong index)
345{
346 PageDesc **lp, *p;
347 lp = page_l1_map(index);
348 if (!lp)
349 return NULL;
350
351 p = *lp;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700352 if (!p) {
353 return NULL;
354 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800355 return p + (index & (L2_SIZE - 1));
356}
357
358static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
359{
360 void **lp, **p;
361 PhysPageDesc *pd;
362
363 p = (void **)l1_phys_map;
364#if TARGET_PHYS_ADDR_SPACE_BITS > 32
365
366#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
367#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
368#endif
369 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
370 p = *lp;
371 if (!p) {
372 /* allocate if not found */
373 if (!alloc)
374 return NULL;
375 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
376 memset(p, 0, sizeof(void *) * L1_SIZE);
377 *lp = p;
378 }
379#endif
380 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
381 pd = *lp;
382 if (!pd) {
383 int i;
384 /* allocate if not found */
385 if (!alloc)
386 return NULL;
387 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
388 *lp = pd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700389 for (i = 0; i < L2_SIZE; i++) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800390 pd[i].phys_offset = IO_MEM_UNASSIGNED;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700391 pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
392 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800393 }
394 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
395}
396
397static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
398{
399 return phys_page_find_alloc(index, 0);
400}
401
402#if !defined(CONFIG_USER_ONLY)
403static void tlb_protect_code(ram_addr_t ram_addr);
404static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
405 target_ulong vaddr);
406#define mmap_lock() do { } while(0)
407#define mmap_unlock() do { } while(0)
408#endif
409
410#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
411
412#if defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700413/* Currently it is not recommended to allocate big chunks of data in
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800414 user mode. It will change when a dedicated libc will be used */
415#define USE_STATIC_CODE_GEN_BUFFER
416#endif
417
418#ifdef USE_STATIC_CODE_GEN_BUFFER
419static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
420#endif
421
422static void code_gen_alloc(unsigned long tb_size)
423{
424#ifdef USE_STATIC_CODE_GEN_BUFFER
425 code_gen_buffer = static_code_gen_buffer;
426 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
427 map_exec(code_gen_buffer, code_gen_buffer_size);
428#else
429 code_gen_buffer_size = tb_size;
430 if (code_gen_buffer_size == 0) {
431#if defined(CONFIG_USER_ONLY)
432 /* in user mode, phys_ram_size is not meaningful */
433 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
434#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700435 /* XXX: needs adjustments */
436 code_gen_buffer_size = (unsigned long)(ram_size / 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800437#endif
438 }
439 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
440 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
441 /* The code gen buffer location may have constraints depending on
442 the host cpu and OS */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800443#if defined(__linux__)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800444 {
445 int flags;
446 void *start = NULL;
447
448 flags = MAP_PRIVATE | MAP_ANONYMOUS;
449#if defined(__x86_64__)
450 flags |= MAP_32BIT;
451 /* Cannot map more than that */
452 if (code_gen_buffer_size > (800 * 1024 * 1024))
453 code_gen_buffer_size = (800 * 1024 * 1024);
454#elif defined(__sparc_v9__)
455 // Map the buffer below 2G, so we can use direct calls and branches
456 flags |= MAP_FIXED;
457 start = (void *) 0x60000000UL;
458 if (code_gen_buffer_size > (512 * 1024 * 1024))
459 code_gen_buffer_size = (512 * 1024 * 1024);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700460#elif defined(__arm__)
461 /* Map the buffer below 32M, so we can use direct calls and branches */
462 flags |= MAP_FIXED;
463 start = (void *) 0x01000000UL;
464 if (code_gen_buffer_size > 16 * 1024 * 1024)
465 code_gen_buffer_size = 16 * 1024 * 1024;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800466#endif
467 code_gen_buffer = mmap(start, code_gen_buffer_size,
468 PROT_WRITE | PROT_READ | PROT_EXEC,
469 flags, -1, 0);
470 if (code_gen_buffer == MAP_FAILED) {
471 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
472 exit(1);
473 }
474 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700475#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700476 {
477 int flags;
478 void *addr = NULL;
479 flags = MAP_PRIVATE | MAP_ANONYMOUS;
480#if defined(__x86_64__)
481 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
482 * 0x40000000 is free */
483 flags |= MAP_FIXED;
484 addr = (void *)0x40000000;
485 /* Cannot map more than that */
486 if (code_gen_buffer_size > (800 * 1024 * 1024))
487 code_gen_buffer_size = (800 * 1024 * 1024);
488#endif
489 code_gen_buffer = mmap(addr, code_gen_buffer_size,
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800490 PROT_WRITE | PROT_READ | PROT_EXEC,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700491 flags, -1, 0);
492 if (code_gen_buffer == MAP_FAILED) {
493 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
494 exit(1);
495 }
496 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800497#else
498 code_gen_buffer = qemu_malloc(code_gen_buffer_size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800499 map_exec(code_gen_buffer, code_gen_buffer_size);
500#endif
501#endif /* !USE_STATIC_CODE_GEN_BUFFER */
502 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800503 code_gen_buffer_max_size = code_gen_buffer_size -
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800504 code_gen_max_block_size();
505 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
506 tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
507}
508
509/* Must be called before using the QEMU cpus. 'tb_size' is the size
510 (in bytes) allocated to the translation buffer. Zero means default
511 size. */
512void cpu_exec_init_all(unsigned long tb_size)
513{
514 cpu_gen_init();
515 code_gen_alloc(tb_size);
516 code_gen_ptr = code_gen_buffer;
517 page_init();
518#if !defined(CONFIG_USER_ONLY)
519 io_mem_init();
520#endif
521}
522
523#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
524
525#define CPU_COMMON_SAVE_VERSION 1
526
527static void cpu_common_save(QEMUFile *f, void *opaque)
528{
529 CPUState *env = opaque;
530
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700531 cpu_synchronize_state(env, 0);
532
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800533 qemu_put_be32s(f, &env->halted);
534 qemu_put_be32s(f, &env->interrupt_request);
535}
536
537static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
538{
539 CPUState *env = opaque;
540
541 if (version_id != CPU_COMMON_SAVE_VERSION)
542 return -EINVAL;
543
544 qemu_get_be32s(f, &env->halted);
545 qemu_get_be32s(f, &env->interrupt_request);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700546 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
547 version_id is increased. */
548 env->interrupt_request &= ~0x01;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800549 tlb_flush(env, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700550 cpu_synchronize_state(env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800551
552 return 0;
553}
554#endif
555
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700556CPUState *qemu_get_cpu(int cpu)
557{
558 CPUState *env = first_cpu;
559
560 while (env) {
561 if (env->cpu_index == cpu)
562 break;
563 env = env->next_cpu;
564 }
565
566 return env;
567}
568
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800569void cpu_exec_init(CPUState *env)
570{
571 CPUState **penv;
572 int cpu_index;
573
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700574#if defined(CONFIG_USER_ONLY)
575 cpu_list_lock();
576#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800577 env->next_cpu = NULL;
578 penv = &first_cpu;
579 cpu_index = 0;
580 while (*penv != NULL) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700581 penv = &(*penv)->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800582 cpu_index++;
583 }
584 env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700585 env->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700586 QTAILQ_INIT(&env->breakpoints);
587 QTAILQ_INIT(&env->watchpoints);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800588 *penv = env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700589#if defined(CONFIG_USER_ONLY)
590 cpu_list_unlock();
591#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800592#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
593 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
594 cpu_common_save, cpu_common_load, env);
595 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
596 cpu_save, cpu_load, env);
597#endif
598}
599
600static inline void invalidate_page_bitmap(PageDesc *p)
601{
602 if (p->code_bitmap) {
603 qemu_free(p->code_bitmap);
604 p->code_bitmap = NULL;
605 }
606 p->code_write_count = 0;
607}
608
609/* set to NULL all the 'first_tb' fields in all PageDescs */
610static void page_flush_tb(void)
611{
612 int i, j;
613 PageDesc *p;
614
615 for(i = 0; i < L1_SIZE; i++) {
616 p = l1_map[i];
617 if (p) {
618 for(j = 0; j < L2_SIZE; j++) {
619 p->first_tb = NULL;
620 invalidate_page_bitmap(p);
621 p++;
622 }
623 }
624 }
625}
626
627/* flush all the translation blocks */
628/* XXX: tb_flush is currently not thread safe */
629void tb_flush(CPUState *env1)
630{
631 CPUState *env;
632#if defined(DEBUG_FLUSH)
633 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
634 (unsigned long)(code_gen_ptr - code_gen_buffer),
635 nb_tbs, nb_tbs > 0 ?
636 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
637#endif
638 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
639 cpu_abort(env1, "Internal error: code buffer overflow\n");
640
641 nb_tbs = 0;
642
643 for(env = first_cpu; env != NULL; env = env->next_cpu) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800644#ifdef CONFIG_MEMCHECK
645 int tb_to_clean;
646 for (tb_to_clean = 0; tb_to_clean < TB_JMP_CACHE_SIZE; tb_to_clean++) {
647 if (env->tb_jmp_cache[tb_to_clean] != NULL &&
648 env->tb_jmp_cache[tb_to_clean]->tpc2gpc != NULL) {
649 qemu_free(env->tb_jmp_cache[tb_to_clean]->tpc2gpc);
650 env->tb_jmp_cache[tb_to_clean]->tpc2gpc = NULL;
651 env->tb_jmp_cache[tb_to_clean]->tpc2gpc_pairs = 0;
652 }
653 }
654#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800655 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
656 }
657
658 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
659 page_flush_tb();
660
661 code_gen_ptr = code_gen_buffer;
662 /* XXX: flush processor icache at this point if cache flush is
663 expensive */
664 tb_flush_count++;
665}
666
667#ifdef DEBUG_TB_CHECK
668
669static void tb_invalidate_check(target_ulong address)
670{
671 TranslationBlock *tb;
672 int i;
673 address &= TARGET_PAGE_MASK;
674 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
675 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
676 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
677 address >= tb->pc + tb->size)) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700678 printf("ERROR invalidate: address=" TARGET_FMT_lx
679 " PC=%08lx size=%04x\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800680 address, (long)tb->pc, tb->size);
681 }
682 }
683 }
684}
685
686/* verify that all the pages have correct rights for code */
687static void tb_page_check(void)
688{
689 TranslationBlock *tb;
690 int i, flags1, flags2;
691
692 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
693 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
694 flags1 = page_get_flags(tb->pc);
695 flags2 = page_get_flags(tb->pc + tb->size - 1);
696 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
697 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
698 (long)tb->pc, tb->size, flags1, flags2);
699 }
700 }
701 }
702}
703
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800704#endif
705
706/* invalidate one TB */
707static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
708 int next_offset)
709{
710 TranslationBlock *tb1;
711 for(;;) {
712 tb1 = *ptb;
713 if (tb1 == tb) {
714 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
715 break;
716 }
717 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
718 }
719}
720
721static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
722{
723 TranslationBlock *tb1;
724 unsigned int n1;
725
726 for(;;) {
727 tb1 = *ptb;
728 n1 = (long)tb1 & 3;
729 tb1 = (TranslationBlock *)((long)tb1 & ~3);
730 if (tb1 == tb) {
731 *ptb = tb1->page_next[n1];
732 break;
733 }
734 ptb = &tb1->page_next[n1];
735 }
736}
737
738static inline void tb_jmp_remove(TranslationBlock *tb, int n)
739{
740 TranslationBlock *tb1, **ptb;
741 unsigned int n1;
742
743 ptb = &tb->jmp_next[n];
744 tb1 = *ptb;
745 if (tb1) {
746 /* find tb(n) in circular list */
747 for(;;) {
748 tb1 = *ptb;
749 n1 = (long)tb1 & 3;
750 tb1 = (TranslationBlock *)((long)tb1 & ~3);
751 if (n1 == n && tb1 == tb)
752 break;
753 if (n1 == 2) {
754 ptb = &tb1->jmp_first;
755 } else {
756 ptb = &tb1->jmp_next[n1];
757 }
758 }
759 /* now we can suppress tb(n) from the list */
760 *ptb = tb->jmp_next[n];
761
762 tb->jmp_next[n] = NULL;
763 }
764}
765
766/* reset the jump entry 'n' of a TB so that it is not chained to
767 another TB */
768static inline void tb_reset_jump(TranslationBlock *tb, int n)
769{
770 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
771}
772
773void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
774{
775 CPUState *env;
776 PageDesc *p;
777 unsigned int h, n1;
778 target_phys_addr_t phys_pc;
779 TranslationBlock *tb1, *tb2;
780
781 /* remove the TB from the hash list */
782 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
783 h = tb_phys_hash_func(phys_pc);
784 tb_remove(&tb_phys_hash[h], tb,
785 offsetof(TranslationBlock, phys_hash_next));
786
787 /* remove the TB from the page list */
788 if (tb->page_addr[0] != page_addr) {
789 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
790 tb_page_remove(&p->first_tb, tb);
791 invalidate_page_bitmap(p);
792 }
793 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
794 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
795 tb_page_remove(&p->first_tb, tb);
796 invalidate_page_bitmap(p);
797 }
798
799 tb_invalidated_flag = 1;
800
801 /* remove the TB from the hash list */
802 h = tb_jmp_cache_hash_func(tb->pc);
803 for(env = first_cpu; env != NULL; env = env->next_cpu) {
804 if (env->tb_jmp_cache[h] == tb)
805 env->tb_jmp_cache[h] = NULL;
806 }
807
808 /* suppress this TB from the two jump lists */
809 tb_jmp_remove(tb, 0);
810 tb_jmp_remove(tb, 1);
811
812 /* suppress any remaining jumps to this TB */
813 tb1 = tb->jmp_first;
814 for(;;) {
815 n1 = (long)tb1 & 3;
816 if (n1 == 2)
817 break;
818 tb1 = (TranslationBlock *)((long)tb1 & ~3);
819 tb2 = tb1->jmp_next[n1];
820 tb_reset_jump(tb1, n1);
821 tb1->jmp_next[n1] = NULL;
822 tb1 = tb2;
823 }
824 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
825
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800826#ifdef CONFIG_MEMCHECK
827 if (tb->tpc2gpc != NULL) {
828 qemu_free(tb->tpc2gpc);
829 tb->tpc2gpc = NULL;
830 tb->tpc2gpc_pairs = 0;
831 }
832#endif // CONFIG_MEMCHECK
833
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800834 tb_phys_invalidate_count++;
835}
836
837static inline void set_bits(uint8_t *tab, int start, int len)
838{
839 int end, mask, end1;
840
841 end = start + len;
842 tab += start >> 3;
843 mask = 0xff << (start & 7);
844 if ((start & ~7) == (end & ~7)) {
845 if (start < end) {
846 mask &= ~(0xff << (end & 7));
847 *tab |= mask;
848 }
849 } else {
850 *tab++ |= mask;
851 start = (start + 8) & ~7;
852 end1 = end & ~7;
853 while (start < end1) {
854 *tab++ = 0xff;
855 start += 8;
856 }
857 if (start < end) {
858 mask = ~(0xff << (end & 7));
859 *tab |= mask;
860 }
861 }
862}
863
864static void build_page_bitmap(PageDesc *p)
865{
866 int n, tb_start, tb_end;
867 TranslationBlock *tb;
868
869 p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800870
871 tb = p->first_tb;
872 while (tb != NULL) {
873 n = (long)tb & 3;
874 tb = (TranslationBlock *)((long)tb & ~3);
875 /* NOTE: this is subtle as a TB may span two physical pages */
876 if (n == 0) {
877 /* NOTE: tb_end may be after the end of the page, but
878 it is not a problem */
879 tb_start = tb->pc & ~TARGET_PAGE_MASK;
880 tb_end = tb_start + tb->size;
881 if (tb_end > TARGET_PAGE_SIZE)
882 tb_end = TARGET_PAGE_SIZE;
883 } else {
884 tb_start = 0;
885 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
886 }
887 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
888 tb = tb->page_next[n];
889 }
890}
891
892TranslationBlock *tb_gen_code(CPUState *env,
893 target_ulong pc, target_ulong cs_base,
894 int flags, int cflags)
895{
896 TranslationBlock *tb;
897 uint8_t *tc_ptr;
898 target_ulong phys_pc, phys_page2, virt_page2;
899 int code_gen_size;
900
901 phys_pc = get_phys_addr_code(env, pc);
902 tb = tb_alloc(pc);
903 if (!tb) {
904 /* flush must be done */
905 tb_flush(env);
906 /* cannot fail at this point */
907 tb = tb_alloc(pc);
908 /* Don't forget to invalidate previous TB info. */
909 tb_invalidated_flag = 1;
910 }
911 tc_ptr = code_gen_ptr;
912 tb->tc_ptr = tc_ptr;
913 tb->cs_base = cs_base;
914 tb->flags = flags;
915 tb->cflags = cflags;
916#ifdef CONFIG_TRACE
917 tb->bb_rec = NULL;
918 tb->prev_time = 0;
919#endif
920 cpu_gen_code(env, tb, &code_gen_size);
921 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
922
923 /* check next page if needed */
924 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
925 phys_page2 = -1;
926 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
927 phys_page2 = get_phys_addr_code(env, virt_page2);
928 }
929 tb_link_phys(tb, phys_pc, phys_page2);
930 return tb;
931}
932
933/* invalidate all TBs which intersect with the target physical page
934 starting in range [start;end[. NOTE: start and end must refer to
935 the same physical page. 'is_cpu_write_access' should be true if called
936 from a real cpu write access: the virtual CPU will exit the current
937 TB if code is modified inside this TB. */
938void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
939 int is_cpu_write_access)
940{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700941 TranslationBlock *tb, *tb_next, *saved_tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800942 CPUState *env = cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800943 target_ulong tb_start, tb_end;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700944 PageDesc *p;
945 int n;
946#ifdef TARGET_HAS_PRECISE_SMC
947 int current_tb_not_found = is_cpu_write_access;
948 TranslationBlock *current_tb = NULL;
949 int current_tb_modified = 0;
950 target_ulong current_pc = 0;
951 target_ulong current_cs_base = 0;
952 int current_flags = 0;
953#endif /* TARGET_HAS_PRECISE_SMC */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800954
955 p = page_find(start >> TARGET_PAGE_BITS);
956 if (!p)
957 return;
958 if (!p->code_bitmap &&
959 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
960 is_cpu_write_access) {
961 /* build code bitmap */
962 build_page_bitmap(p);
963 }
964
965 /* we remove all the TBs in the range [start, end[ */
966 /* XXX: see if in some cases it could be faster to invalidate all the code */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800967 tb = p->first_tb;
968 while (tb != NULL) {
969 n = (long)tb & 3;
970 tb = (TranslationBlock *)((long)tb & ~3);
971 tb_next = tb->page_next[n];
972 /* NOTE: this is subtle as a TB may span two physical pages */
973 if (n == 0) {
974 /* NOTE: tb_end may be after the end of the page, but
975 it is not a problem */
976 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
977 tb_end = tb_start + tb->size;
978 } else {
979 tb_start = tb->page_addr[1];
980 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
981 }
982 if (!(tb_end <= start || tb_start >= end)) {
983#ifdef TARGET_HAS_PRECISE_SMC
984 if (current_tb_not_found) {
985 current_tb_not_found = 0;
986 current_tb = NULL;
987 if (env->mem_io_pc) {
988 /* now we have a real cpu fault */
989 current_tb = tb_find_pc(env->mem_io_pc);
990 }
991 }
992 if (current_tb == tb &&
993 (current_tb->cflags & CF_COUNT_MASK) != 1) {
994 /* If we are modifying the current TB, we must stop
995 its execution. We could be more precise by checking
996 that the modification is after the current PC, but it
997 would require a specialized function to partially
998 restore the CPU state */
999
1000 current_tb_modified = 1;
1001 cpu_restore_state(current_tb, env,
1002 env->mem_io_pc, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001003 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1004 &current_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001005 }
1006#endif /* TARGET_HAS_PRECISE_SMC */
1007 /* we need to do that to handle the case where a signal
1008 occurs while doing tb_phys_invalidate() */
1009 saved_tb = NULL;
1010 if (env) {
1011 saved_tb = env->current_tb;
1012 env->current_tb = NULL;
1013 }
1014 tb_phys_invalidate(tb, -1);
1015 if (env) {
1016 env->current_tb = saved_tb;
1017 if (env->interrupt_request && env->current_tb)
1018 cpu_interrupt(env, env->interrupt_request);
1019 }
1020 }
1021 tb = tb_next;
1022 }
1023#if !defined(CONFIG_USER_ONLY)
1024 /* if no code remaining, no need to continue to use slow writes */
1025 if (!p->first_tb) {
1026 invalidate_page_bitmap(p);
1027 if (is_cpu_write_access) {
1028 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
1029 }
1030 }
1031#endif
1032#ifdef TARGET_HAS_PRECISE_SMC
1033 if (current_tb_modified) {
1034 /* we generate a block containing just the instruction
1035 modifying the memory. It will ensure that it cannot modify
1036 itself */
1037 env->current_tb = NULL;
1038 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
1039 cpu_resume_from_signal(env, NULL);
1040 }
1041#endif
1042}
1043
1044/* len must be <= 8 and start must be a multiple of len */
1045static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
1046{
1047 PageDesc *p;
1048 int offset, b;
1049#if 0
1050 if (1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001051 qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
1052 cpu_single_env->mem_io_vaddr, len,
1053 cpu_single_env->eip,
1054 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001055 }
1056#endif
1057 p = page_find(start >> TARGET_PAGE_BITS);
1058 if (!p)
1059 return;
1060 if (p->code_bitmap) {
1061 offset = start & ~TARGET_PAGE_MASK;
1062 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1063 if (b & ((1 << len) - 1))
1064 goto do_invalidate;
1065 } else {
1066 do_invalidate:
1067 tb_invalidate_phys_page_range(start, start + len, 1);
1068 }
1069}
1070
1071#if !defined(CONFIG_SOFTMMU)
1072static void tb_invalidate_phys_page(target_phys_addr_t addr,
1073 unsigned long pc, void *puc)
1074{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001075 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001076 PageDesc *p;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001077 int n;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001078#ifdef TARGET_HAS_PRECISE_SMC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001079 TranslationBlock *current_tb = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001080 CPUState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001081 int current_tb_modified = 0;
1082 target_ulong current_pc = 0;
1083 target_ulong current_cs_base = 0;
1084 int current_flags = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001085#endif
1086
1087 addr &= TARGET_PAGE_MASK;
1088 p = page_find(addr >> TARGET_PAGE_BITS);
1089 if (!p)
1090 return;
1091 tb = p->first_tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001092#ifdef TARGET_HAS_PRECISE_SMC
1093 if (tb && pc != 0) {
1094 current_tb = tb_find_pc(pc);
1095 }
1096#endif
1097 while (tb != NULL) {
1098 n = (long)tb & 3;
1099 tb = (TranslationBlock *)((long)tb & ~3);
1100#ifdef TARGET_HAS_PRECISE_SMC
1101 if (current_tb == tb &&
1102 (current_tb->cflags & CF_COUNT_MASK) != 1) {
1103 /* If we are modifying the current TB, we must stop
1104 its execution. We could be more precise by checking
1105 that the modification is after the current PC, but it
1106 would require a specialized function to partially
1107 restore the CPU state */
1108
1109 current_tb_modified = 1;
1110 cpu_restore_state(current_tb, env, pc, puc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001111 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1112 &current_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001113 }
1114#endif /* TARGET_HAS_PRECISE_SMC */
1115 tb_phys_invalidate(tb, addr);
1116 tb = tb->page_next[n];
1117 }
1118 p->first_tb = NULL;
1119#ifdef TARGET_HAS_PRECISE_SMC
1120 if (current_tb_modified) {
1121 /* we generate a block containing just the instruction
1122 modifying the memory. It will ensure that it cannot modify
1123 itself */
1124 env->current_tb = NULL;
1125 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
1126 cpu_resume_from_signal(env, puc);
1127 }
1128#endif
1129}
1130#endif
1131
1132/* add the tb in the target page and protect it if necessary */
1133static inline void tb_alloc_page(TranslationBlock *tb,
1134 unsigned int n, target_ulong page_addr)
1135{
1136 PageDesc *p;
1137 TranslationBlock *last_first_tb;
1138
1139 tb->page_addr[n] = page_addr;
1140 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
1141 tb->page_next[n] = p->first_tb;
1142 last_first_tb = p->first_tb;
1143 p->first_tb = (TranslationBlock *)((long)tb | n);
1144 invalidate_page_bitmap(p);
1145
1146#if defined(TARGET_HAS_SMC) || 1
1147
1148#if defined(CONFIG_USER_ONLY)
1149 if (p->flags & PAGE_WRITE) {
1150 target_ulong addr;
1151 PageDesc *p2;
1152 int prot;
1153
1154 /* force the host page as non writable (writes will have a
1155 page fault + mprotect overhead) */
1156 page_addr &= qemu_host_page_mask;
1157 prot = 0;
1158 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1159 addr += TARGET_PAGE_SIZE) {
1160
1161 p2 = page_find (addr >> TARGET_PAGE_BITS);
1162 if (!p2)
1163 continue;
1164 prot |= p2->flags;
1165 p2->flags &= ~PAGE_WRITE;
1166 page_get_flags(addr);
1167 }
1168 mprotect(g2h(page_addr), qemu_host_page_size,
1169 (prot & PAGE_BITS) & ~PAGE_WRITE);
1170#ifdef DEBUG_TB_INVALIDATE
1171 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
1172 page_addr);
1173#endif
1174 }
1175#else
1176 /* if some code is already present, then the pages are already
1177 protected. So we handle the case where only the first TB is
1178 allocated in a physical page */
1179 if (!last_first_tb) {
1180 tlb_protect_code(page_addr);
1181 }
1182#endif
1183
1184#endif /* TARGET_HAS_SMC */
1185}
1186
1187/* Allocate a new translation block. Flush the translation buffer if
1188 too many translation blocks or too much generated code. */
1189TranslationBlock *tb_alloc(target_ulong pc)
1190{
1191 TranslationBlock *tb;
1192
1193 if (nb_tbs >= code_gen_max_blocks ||
1194 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
1195 return NULL;
1196 tb = &tbs[nb_tbs++];
1197 tb->pc = pc;
1198 tb->cflags = 0;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001199#ifdef CONFIG_MEMCHECK
1200 tb->tpc2gpc = NULL;
1201 tb->tpc2gpc_pairs = 0;
1202#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001203 return tb;
1204}
1205
1206void tb_free(TranslationBlock *tb)
1207{
1208 /* In practice this is mostly used for single use temporary TB
1209 Ignore the hard cases and just back up if this TB happens to
1210 be the last one generated. */
1211 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1212 code_gen_ptr = tb->tc_ptr;
1213 nb_tbs--;
1214 }
1215}
1216
1217/* add a new TB and link it to the physical page tables. phys_page2 is
1218 (-1) to indicate that only one page contains the TB. */
1219void tb_link_phys(TranslationBlock *tb,
1220 target_ulong phys_pc, target_ulong phys_page2)
1221{
1222 unsigned int h;
1223 TranslationBlock **ptb;
1224
1225 /* Grab the mmap lock to stop another thread invalidating this TB
1226 before we are done. */
1227 mmap_lock();
1228 /* add in the physical hash table */
1229 h = tb_phys_hash_func(phys_pc);
1230 ptb = &tb_phys_hash[h];
1231 tb->phys_hash_next = *ptb;
1232 *ptb = tb;
1233
1234 /* add in the page list */
1235 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1236 if (phys_page2 != -1)
1237 tb_alloc_page(tb, 1, phys_page2);
1238 else
1239 tb->page_addr[1] = -1;
1240
1241 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1242 tb->jmp_next[0] = NULL;
1243 tb->jmp_next[1] = NULL;
1244
1245 /* init original jump addresses */
1246 if (tb->tb_next_offset[0] != 0xffff)
1247 tb_reset_jump(tb, 0);
1248 if (tb->tb_next_offset[1] != 0xffff)
1249 tb_reset_jump(tb, 1);
1250
1251#ifdef DEBUG_TB_CHECK
1252 tb_page_check();
1253#endif
1254 mmap_unlock();
1255}
1256
1257/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1258 tb[1].tc_ptr. Return NULL if not found */
1259TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1260{
1261 int m_min, m_max, m;
1262 unsigned long v;
1263 TranslationBlock *tb;
1264
1265 if (nb_tbs <= 0)
1266 return NULL;
1267 if (tc_ptr < (unsigned long)code_gen_buffer ||
1268 tc_ptr >= (unsigned long)code_gen_ptr)
1269 return NULL;
1270 /* binary search (cf Knuth) */
1271 m_min = 0;
1272 m_max = nb_tbs - 1;
1273 while (m_min <= m_max) {
1274 m = (m_min + m_max) >> 1;
1275 tb = &tbs[m];
1276 v = (unsigned long)tb->tc_ptr;
1277 if (v == tc_ptr)
1278 return tb;
1279 else if (tc_ptr < v) {
1280 m_max = m - 1;
1281 } else {
1282 m_min = m + 1;
1283 }
1284 }
1285 return &tbs[m_max];
1286}
1287
1288static void tb_reset_jump_recursive(TranslationBlock *tb);
1289
1290static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1291{
1292 TranslationBlock *tb1, *tb_next, **ptb;
1293 unsigned int n1;
1294
1295 tb1 = tb->jmp_next[n];
1296 if (tb1 != NULL) {
1297 /* find head of list */
1298 for(;;) {
1299 n1 = (long)tb1 & 3;
1300 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1301 if (n1 == 2)
1302 break;
1303 tb1 = tb1->jmp_next[n1];
1304 }
1305 /* we are now sure now that tb jumps to tb1 */
1306 tb_next = tb1;
1307
1308 /* remove tb from the jmp_first list */
1309 ptb = &tb_next->jmp_first;
1310 for(;;) {
1311 tb1 = *ptb;
1312 n1 = (long)tb1 & 3;
1313 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1314 if (n1 == n && tb1 == tb)
1315 break;
1316 ptb = &tb1->jmp_next[n1];
1317 }
1318 *ptb = tb->jmp_next[n];
1319 tb->jmp_next[n] = NULL;
1320
1321 /* suppress the jump to next tb in generated code */
1322 tb_reset_jump(tb, n);
1323
1324 /* suppress jumps in the tb on which we could have jumped */
1325 tb_reset_jump_recursive(tb_next);
1326 }
1327}
1328
1329static void tb_reset_jump_recursive(TranslationBlock *tb)
1330{
1331 tb_reset_jump_recursive2(tb, 0);
1332 tb_reset_jump_recursive2(tb, 1);
1333}
1334
1335#if defined(TARGET_HAS_ICE)
1336static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1337{
1338 target_phys_addr_t addr;
1339 target_ulong pd;
1340 ram_addr_t ram_addr;
1341 PhysPageDesc *p;
1342
1343 addr = cpu_get_phys_page_debug(env, pc);
1344 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1345 if (!p) {
1346 pd = IO_MEM_UNASSIGNED;
1347 } else {
1348 pd = p->phys_offset;
1349 }
1350 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
1351 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
1352}
1353#endif
1354
1355/* Add a watchpoint. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001356int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
1357 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001358{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001359 target_ulong len_mask = ~(len - 1);
1360 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001361
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001362 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1363 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1364 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1365 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1366 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001367 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001368 wp = qemu_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001369
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001370 wp->vaddr = addr;
1371 wp->len_mask = len_mask;
1372 wp->flags = flags;
1373
1374 /* keep all GDB-injected watchpoints in front */
1375 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001376 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001377 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001378 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001379
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001380 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001381
1382 if (watchpoint)
1383 *watchpoint = wp;
1384 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001385}
1386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001387/* Remove a specific watchpoint. */
1388int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
1389 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001390{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001391 target_ulong len_mask = ~(len - 1);
1392 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001393
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001394 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001395 if (addr == wp->vaddr && len_mask == wp->len_mask
1396 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
1397 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001398 return 0;
1399 }
1400 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001401 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001402}
1403
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001404/* Remove a specific watchpoint by reference. */
1405void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
1406{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001407 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001408
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001409 tlb_flush_page(env, watchpoint->vaddr);
1410
1411 qemu_free(watchpoint);
1412}
1413
1414/* Remove all matching watchpoints. */
1415void cpu_watchpoint_remove_all(CPUState *env, int mask)
1416{
1417 CPUWatchpoint *wp, *next;
1418
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001419 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001420 if (wp->flags & mask)
1421 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001422 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001423}
1424
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001425/* Add a breakpoint. */
1426int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
1427 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001428{
1429#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001430 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001431
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001432 bp = qemu_malloc(sizeof(*bp));
1433
1434 bp->pc = pc;
1435 bp->flags = flags;
1436
1437 /* keep all GDB-injected breakpoints in front */
1438 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001439 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001440 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001441 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001442
1443 breakpoint_invalidate(env, pc);
1444
1445 if (breakpoint)
1446 *breakpoint = bp;
1447 return 0;
1448#else
1449 return -ENOSYS;
1450#endif
1451}
1452
1453/* Remove a specific breakpoint. */
1454int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
1455{
1456#if defined(TARGET_HAS_ICE)
1457 CPUBreakpoint *bp;
1458
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001459 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001460 if (bp->pc == pc && bp->flags == flags) {
1461 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001462 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001463 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001464 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001465 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001466#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001467 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001468#endif
1469}
1470
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001471/* Remove a specific breakpoint by reference. */
1472void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001473{
1474#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001475 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001476
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001477 breakpoint_invalidate(env, breakpoint->pc);
1478
1479 qemu_free(breakpoint);
1480#endif
1481}
1482
1483/* Remove all matching breakpoints. */
1484void cpu_breakpoint_remove_all(CPUState *env, int mask)
1485{
1486#if defined(TARGET_HAS_ICE)
1487 CPUBreakpoint *bp, *next;
1488
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001489 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001490 if (bp->flags & mask)
1491 cpu_breakpoint_remove_by_ref(env, bp);
1492 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001493#endif
1494}
1495
1496/* enable or disable single step mode. EXCP_DEBUG is returned by the
1497 CPU loop after each instruction */
1498void cpu_single_step(CPUState *env, int enabled)
1499{
1500#if defined(TARGET_HAS_ICE)
1501 if (env->singlestep_enabled != enabled) {
1502 env->singlestep_enabled = enabled;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001503 if (kvm_enabled())
1504 kvm_update_guest_debug(env, 0);
1505 else {
1506 /* must flush all the translated code to avoid inconsistencies */
1507 /* XXX: only flush what is necessary */
1508 tb_flush(env);
1509 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001510 }
1511#endif
1512}
1513
1514/* enable or disable low levels log */
1515void cpu_set_log(int log_flags)
1516{
1517 loglevel = log_flags;
1518 if (loglevel && !logfile) {
1519 logfile = fopen(logfilename, log_append ? "a" : "w");
1520 if (!logfile) {
1521 perror(logfilename);
1522 _exit(1);
1523 }
1524#if !defined(CONFIG_SOFTMMU)
1525 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1526 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001527 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001528 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1529 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001530#elif !defined(_WIN32)
1531 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001532 setvbuf(logfile, NULL, _IOLBF, 0);
1533#endif
1534 log_append = 1;
1535 }
1536 if (!loglevel && logfile) {
1537 fclose(logfile);
1538 logfile = NULL;
1539 }
1540}
1541
1542void cpu_set_log_filename(const char *filename)
1543{
1544 logfilename = strdup(filename);
1545 if (logfile) {
1546 fclose(logfile);
1547 logfile = NULL;
1548 }
1549 cpu_set_log(loglevel);
1550}
1551
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001552static void cpu_unlink_tb(CPUState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001553{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001554 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1555 problem and hope the cpu will stop of its own accord. For userspace
1556 emulation this often isn't actually as bad as it sounds. Often
1557 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001558 TranslationBlock *tb;
1559 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
1560
1561 tb = env->current_tb;
1562 /* if the cpu is currently executing code, we must unlink it and
1563 all the potentially executing TB */
1564 if (tb && !testandset(&interrupt_lock)) {
1565 env->current_tb = NULL;
1566 tb_reset_jump_recursive(tb);
1567 resetlock(&interrupt_lock);
1568 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001569}
1570
1571/* mask must never be zero, except for A20 change call */
1572void cpu_interrupt(CPUState *env, int mask)
1573{
1574 int old_mask;
1575
1576 old_mask = env->interrupt_request;
1577 env->interrupt_request |= mask;
1578
1579#ifndef CONFIG_USER_ONLY
1580 /*
1581 * If called from iothread context, wake the target cpu in
1582 * case its halted.
1583 */
1584 if (!qemu_cpu_self(env)) {
1585 qemu_cpu_kick(env);
1586 return;
1587 }
1588#endif
1589
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001590 if (use_icount) {
1591 env->icount_decr.u16.high = 0xffff;
1592#ifndef CONFIG_USER_ONLY
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001593 if (!can_do_io(env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001594 && (mask & ~old_mask) != 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001595 cpu_abort(env, "Raised interrupt while not in I/O function");
1596 }
1597#endif
1598 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001599 cpu_unlink_tb(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001600 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001601}
1602
1603void cpu_reset_interrupt(CPUState *env, int mask)
1604{
1605 env->interrupt_request &= ~mask;
1606}
1607
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001608void cpu_exit(CPUState *env)
1609{
1610 env->exit_request = 1;
1611 cpu_unlink_tb(env);
1612}
1613
1614const CPULogItem cpu_log_items[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001615 { CPU_LOG_TB_OUT_ASM, "out_asm",
1616 "show generated host assembly code for each compiled TB" },
1617 { CPU_LOG_TB_IN_ASM, "in_asm",
1618 "show target assembly code for each compiled TB" },
1619 { CPU_LOG_TB_OP, "op",
1620 "show micro ops for each compiled TB" },
1621 { CPU_LOG_TB_OP_OPT, "op_opt",
1622 "show micro ops "
1623#ifdef TARGET_I386
1624 "before eflags optimization and "
1625#endif
1626 "after liveness analysis" },
1627 { CPU_LOG_INT, "int",
1628 "show interrupts/exceptions in short format" },
1629 { CPU_LOG_EXEC, "exec",
1630 "show trace before each executed TB (lots of logs)" },
1631 { CPU_LOG_TB_CPU, "cpu",
1632 "show CPU state before block translation" },
1633#ifdef TARGET_I386
1634 { CPU_LOG_PCALL, "pcall",
1635 "show protected mode far calls/returns/exceptions" },
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001636 { CPU_LOG_RESET, "cpu_reset",
1637 "show CPU state before CPU resets" },
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001638#endif
1639#ifdef DEBUG_IOPORT
1640 { CPU_LOG_IOPORT, "ioport",
1641 "show all i/o ports accesses" },
1642#endif
1643 { 0, NULL, NULL },
1644};
1645
1646static int cmp1(const char *s1, int n, const char *s2)
1647{
1648 if (strlen(s2) != n)
1649 return 0;
1650 return memcmp(s1, s2, n) == 0;
1651}
1652
1653/* takes a comma separated list of log masks. Return 0 if error. */
1654int cpu_str_to_log_mask(const char *str)
1655{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001656 const CPULogItem *item;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001657 int mask;
1658 const char *p, *p1;
1659
1660 p = str;
1661 mask = 0;
1662 for(;;) {
1663 p1 = strchr(p, ',');
1664 if (!p1)
1665 p1 = p + strlen(p);
1666 if(cmp1(p,p1-p,"all")) {
1667 for(item = cpu_log_items; item->mask != 0; item++) {
1668 mask |= item->mask;
1669 }
1670 } else {
1671 for(item = cpu_log_items; item->mask != 0; item++) {
1672 if (cmp1(p, p1 - p, item->name))
1673 goto found;
1674 }
1675 return 0;
1676 }
1677 found:
1678 mask |= item->mask;
1679 if (*p1 != ',')
1680 break;
1681 p = p1 + 1;
1682 }
1683 return mask;
1684}
1685
1686void cpu_abort(CPUState *env, const char *fmt, ...)
1687{
1688 va_list ap;
1689 va_list ap2;
1690
1691 va_start(ap, fmt);
1692 va_copy(ap2, ap);
1693 fprintf(stderr, "qemu: fatal: ");
1694 vfprintf(stderr, fmt, ap);
1695 fprintf(stderr, "\n");
1696#ifdef TARGET_I386
1697 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1698#else
1699 cpu_dump_state(env, stderr, fprintf, 0);
1700#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001701 if (qemu_log_enabled()) {
1702 qemu_log("qemu: fatal: ");
1703 qemu_log_vprintf(fmt, ap2);
1704 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001705#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001706 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001707#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001708 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001709#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001710 qemu_log_flush();
1711 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001712 }
1713 va_end(ap2);
1714 va_end(ap);
1715 abort();
1716}
1717
1718CPUState *cpu_copy(CPUState *env)
1719{
1720 CPUState *new_env = cpu_init(env->cpu_model_str);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001721 CPUState *next_cpu = new_env->next_cpu;
1722 int cpu_index = new_env->cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001723#if defined(TARGET_HAS_ICE)
1724 CPUBreakpoint *bp;
1725 CPUWatchpoint *wp;
1726#endif
1727
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001728 memcpy(new_env, env, sizeof(CPUState));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001729
1730 /* Preserve chaining and index. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001731 new_env->next_cpu = next_cpu;
1732 new_env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001733
1734 /* Clone all break/watchpoints.
1735 Note: Once we support ptrace with hw-debug register access, make sure
1736 BP_CPU break/watchpoints are handled correctly on clone. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001737 QTAILQ_INIT(&env->breakpoints);
1738 QTAILQ_INIT(&env->watchpoints);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001739#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001740 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001741 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
1742 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001743 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001744 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
1745 wp->flags, NULL);
1746 }
1747#endif
1748
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001749 return new_env;
1750}
1751
1752#if !defined(CONFIG_USER_ONLY)
1753
1754static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
1755{
1756 unsigned int i;
1757
1758 /* Discard jump cache entries for any tb which might potentially
1759 overlap the flushed page. */
1760 i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001761 memset (&env->tb_jmp_cache[i], 0,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001762 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1763
1764 i = tb_jmp_cache_hash_page(addr);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001765 memset (&env->tb_jmp_cache[i], 0,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001766 TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
1767}
1768
1769/* NOTE: if flush_global is true, also flush global entries (not
1770 implemented yet) */
1771void tlb_flush(CPUState *env, int flush_global)
1772{
1773 int i;
1774
1775#if defined(DEBUG_TLB)
1776 printf("tlb_flush:\n");
1777#endif
1778 /* must reset current TB so that interrupts cannot modify the
1779 links while we are modifying them */
1780 env->current_tb = NULL;
1781
1782 for(i = 0; i < CPU_TLB_SIZE; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001783 int mmu_idx;
1784 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
1785 env->tlb_table[mmu_idx][i].addr_read = -1;
1786 env->tlb_table[mmu_idx][i].addr_write = -1;
1787 env->tlb_table[mmu_idx][i].addr_code = -1;
1788 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001789 }
1790
1791 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
1792
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001793#ifdef CONFIG_KQEMU
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001794 if (env->kqemu_enabled) {
1795 kqemu_flush(env, flush_global);
1796 }
1797#endif
1798 tlb_flush_count++;
1799}
1800
1801static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
1802{
1803 if (addr == (tlb_entry->addr_read &
1804 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1805 addr == (tlb_entry->addr_write &
1806 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1807 addr == (tlb_entry->addr_code &
1808 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1809 tlb_entry->addr_read = -1;
1810 tlb_entry->addr_write = -1;
1811 tlb_entry->addr_code = -1;
1812 }
1813}
1814
1815void tlb_flush_page(CPUState *env, target_ulong addr)
1816{
1817 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001818 int mmu_idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001819
1820#if defined(DEBUG_TLB)
1821 printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
1822#endif
1823 /* must reset current TB so that interrupts cannot modify the
1824 links while we are modifying them */
1825 env->current_tb = NULL;
1826
1827 addr &= TARGET_PAGE_MASK;
1828 i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001829 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
1830 tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001831
1832 tlb_flush_jmp_cache(env, addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001833}
1834
1835/* update the TLBs so that writes to code in the virtual page 'addr'
1836 can be detected */
1837static void tlb_protect_code(ram_addr_t ram_addr)
1838{
1839 cpu_physical_memory_reset_dirty(ram_addr,
1840 ram_addr + TARGET_PAGE_SIZE,
1841 CODE_DIRTY_FLAG);
1842}
1843
1844/* update the TLB so that writes in physical page 'phys_addr' are no longer
1845 tested for self modifying code */
1846static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
1847 target_ulong vaddr)
1848{
1849 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
1850}
1851
1852static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
1853 unsigned long start, unsigned long length)
1854{
1855 unsigned long addr;
1856 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1857 addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
1858 if ((addr - start) < length) {
1859 tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
1860 }
1861 }
1862}
1863
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001864/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001865void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
1866 int dirty_flags)
1867{
1868 CPUState *env;
1869 unsigned long length, start1;
1870 int i, mask, len;
1871 uint8_t *p;
1872
1873 start &= TARGET_PAGE_MASK;
1874 end = TARGET_PAGE_ALIGN(end);
1875
1876 length = end - start;
1877 if (length == 0)
1878 return;
1879 len = length >> TARGET_PAGE_BITS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001880 mask = ~dirty_flags;
1881 p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1882 for(i = 0; i < len; i++)
1883 p[i] &= mask;
1884
1885 /* we modify the TLB cache so that the dirty bit will be set again
1886 when accessing the range */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001887 start1 = (unsigned long)qemu_get_ram_ptr(start);
1888 /* Chek that we don't span multiple blocks - this breaks the
1889 address comparisons below. */
1890 if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1
1891 != (end - 1) - start) {
1892 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001893 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001894
1895 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1896 int mmu_idx;
1897 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
1898 for(i = 0; i < CPU_TLB_SIZE; i++)
1899 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
1900 start1, length);
1901 }
1902 }
1903}
1904
1905int cpu_physical_memory_set_dirty_tracking(int enable)
1906{
1907 in_migration = enable;
1908 if (kvm_enabled()) {
1909 return kvm_set_migration_log(enable);
1910 }
1911 return 0;
1912}
1913
1914int cpu_physical_memory_get_dirty_tracking(void)
1915{
1916 return in_migration;
1917}
1918
1919int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
1920 target_phys_addr_t end_addr)
1921{
1922 int ret = 0;
1923
1924 if (kvm_enabled())
1925 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1926 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001927}
1928
1929static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1930{
1931 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001932 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001933
1934 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001935 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
1936 + tlb_entry->addend);
1937 ram_addr = qemu_ram_addr_from_host(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001938 if (!cpu_physical_memory_is_dirty(ram_addr)) {
1939 tlb_entry->addr_write |= TLB_NOTDIRTY;
1940 }
1941 }
1942}
1943
1944/* update the TLB according to the current state of the dirty bits */
1945void cpu_tlb_update_dirty(CPUState *env)
1946{
1947 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001948 int mmu_idx;
1949 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
1950 for(i = 0; i < CPU_TLB_SIZE; i++)
1951 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
1952 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001953}
1954
1955static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
1956{
1957 if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
1958 tlb_entry->addr_write = vaddr;
1959}
1960
1961/* update the TLB corresponding to virtual page vaddr
1962 so that it is no longer dirty */
1963static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
1964{
1965 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001966 int mmu_idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001967
1968 vaddr &= TARGET_PAGE_MASK;
1969 i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001970 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
1971 tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001972}
1973
1974/* add a new TLB entry. At most one entry for a given virtual address
1975 is permitted. Return 0 if OK or 2 if the page could not be mapped
1976 (can only happen in non SOFTMMU mode for I/O pages or pages
1977 conflicting with the host address space). */
1978int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1979 target_phys_addr_t paddr, int prot,
1980 int mmu_idx, int is_softmmu)
1981{
1982 PhysPageDesc *p;
1983 unsigned long pd;
1984 unsigned int index;
1985 target_ulong address;
1986 target_ulong code_address;
1987 target_phys_addr_t addend;
1988 int ret;
1989 CPUTLBEntry *te;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001990 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001991 target_phys_addr_t iotlb;
1992
1993 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1994 if (!p) {
1995 pd = IO_MEM_UNASSIGNED;
1996 } else {
1997 pd = p->phys_offset;
1998 }
1999#if defined(DEBUG_TLB)
2000 printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
2001 vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
2002#endif
2003
2004 ret = 0;
2005 address = vaddr;
2006 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
2007 /* IO memory case (romd handled later) */
2008 address |= TLB_MMIO;
2009 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002010 addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002011 if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
2012 /* Normal RAM. */
2013 iotlb = pd & TARGET_PAGE_MASK;
2014 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
2015 iotlb |= IO_MEM_NOTDIRTY;
2016 else
2017 iotlb |= IO_MEM_ROM;
2018 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002019 /* IO handlers are currently passed a physical address.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002020 It would be nice to pass an offset from the base address
2021 of that region. This would avoid having to special case RAM,
2022 and avoid full address decoding in every device.
2023 We can't use the high bits of pd for this because
2024 IO_MEM_ROMD uses these as a ram address. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002025 iotlb = (pd & ~TARGET_PAGE_MASK);
2026 if (p) {
2027 iotlb += p->region_offset;
2028 } else {
2029 iotlb += paddr;
2030 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002031 }
2032
2033 code_address = address;
2034 /* Make accesses to pages with watchpoints go via the
2035 watchpoint trap routines. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002036 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002037 if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002038 iotlb = io_mem_watch + paddr;
2039 /* TODO: The memory case can be optimized by not trapping
2040 reads of pages with a write breakpoint. */
2041 address |= TLB_MMIO;
2042 }
2043 }
2044
2045 index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
2046 env->iotlb[mmu_idx][index] = iotlb - vaddr;
2047 te = &env->tlb_table[mmu_idx][index];
2048 te->addend = addend - vaddr;
2049 if (prot & PAGE_READ) {
2050 te->addr_read = address;
2051 } else {
2052 te->addr_read = -1;
2053 }
2054
2055 if (prot & PAGE_EXEC) {
2056 te->addr_code = code_address;
2057 } else {
2058 te->addr_code = -1;
2059 }
2060 if (prot & PAGE_WRITE) {
2061 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
2062 (pd & IO_MEM_ROMD)) {
2063 /* Write access calls the I/O callback. */
2064 te->addr_write = address | TLB_MMIO;
2065 } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2066 !cpu_physical_memory_is_dirty(pd)) {
2067 te->addr_write = address | TLB_NOTDIRTY;
2068 } else {
2069 te->addr_write = address;
2070 }
2071 } else {
2072 te->addr_write = -1;
2073 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002074
2075#ifdef CONFIG_MEMCHECK
2076 /*
2077 * If we have memchecker running, we need to make sure that page, cached
2078 * into TLB as the result of this operation will comply with our requirement
2079 * to cause __ld/__stx_mmu being called for memory access on the pages
2080 * containing memory blocks that require access violation checks.
2081 *
2082 * We need to check with memory checker if we should invalidate this page
2083 * iff:
2084 * - Memchecking is enabled.
2085 * - Page that's been cached belongs to the user space.
2086 * - Request to cache this page didn't come from softmmu. We're covered
2087 * there, because after page was cached here we will invalidate it in
2088 * the __ld/__stx_mmu wrapper.
2089 * - Cached page belongs to RAM, not I/O area.
2090 * - Page is cached for read, or write access.
2091 */
2092 if (memcheck_instrument_mmu && mmu_idx == 1 && !is_softmmu &&
2093 (pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
2094 (prot & (PAGE_READ | PAGE_WRITE)) &&
2095 memcheck_is_checked(vaddr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE)) {
2096 if (prot & PAGE_READ) {
2097 te->addr_read ^= TARGET_PAGE_MASK;
2098 }
2099 if (prot & PAGE_WRITE) {
2100 te->addr_write ^= TARGET_PAGE_MASK;
2101 }
2102 }
2103#endif // CONFIG_MEMCHECK
2104
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002105 return ret;
2106}
2107
2108#else
2109
2110void tlb_flush(CPUState *env, int flush_global)
2111{
2112}
2113
2114void tlb_flush_page(CPUState *env, target_ulong addr)
2115{
2116}
2117
2118int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
2119 target_phys_addr_t paddr, int prot,
2120 int mmu_idx, int is_softmmu)
2121{
2122 return 0;
2123}
2124
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002125/*
2126 * Walks guest process memory "regions" one by one
2127 * and calls callback function 'fn' for each region.
2128 */
2129int walk_memory_regions(void *priv,
2130 int (*fn)(void *, unsigned long, unsigned long, unsigned long))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002131{
2132 unsigned long start, end;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002133 PageDesc *p = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002134 int i, j, prot, prot1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002135 int rc = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002136
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002137 start = end = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002138 prot = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002139
2140 for (i = 0; i <= L1_SIZE; i++) {
2141 p = (i < L1_SIZE) ? l1_map[i] : NULL;
2142 for (j = 0; j < L2_SIZE; j++) {
2143 prot1 = (p == NULL) ? 0 : p[j].flags;
2144 /*
2145 * "region" is one continuous chunk of memory
2146 * that has same protection flags set.
2147 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002148 if (prot1 != prot) {
2149 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
2150 if (start != -1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002151 rc = (*fn)(priv, start, end, prot);
2152 /* callback can stop iteration by returning != 0 */
2153 if (rc != 0)
2154 return (rc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002155 }
2156 if (prot1 != 0)
2157 start = end;
2158 else
2159 start = -1;
2160 prot = prot1;
2161 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002162 if (p == NULL)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002163 break;
2164 }
2165 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002166 return (rc);
2167}
2168
2169static int dump_region(void *priv, unsigned long start,
2170 unsigned long end, unsigned long prot)
2171{
2172 FILE *f = (FILE *)priv;
2173
2174 (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
2175 start, end, end - start,
2176 ((prot & PAGE_READ) ? 'r' : '-'),
2177 ((prot & PAGE_WRITE) ? 'w' : '-'),
2178 ((prot & PAGE_EXEC) ? 'x' : '-'));
2179
2180 return (0);
2181}
2182
2183/* dump memory mappings */
2184void page_dump(FILE *f)
2185{
2186 (void) fprintf(f, "%-8s %-8s %-8s %s\n",
2187 "start", "end", "size", "prot");
2188 walk_memory_regions(f, dump_region);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002189}
2190
2191int page_get_flags(target_ulong address)
2192{
2193 PageDesc *p;
2194
2195 p = page_find(address >> TARGET_PAGE_BITS);
2196 if (!p)
2197 return 0;
2198 return p->flags;
2199}
2200
2201/* modify the flags of a page and invalidate the code if
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002202 necessary. The flag PAGE_WRITE_ORG is positioned automatically
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002203 depending on PAGE_WRITE */
2204void page_set_flags(target_ulong start, target_ulong end, int flags)
2205{
2206 PageDesc *p;
2207 target_ulong addr;
2208
2209 /* mmap_lock should already be held. */
2210 start = start & TARGET_PAGE_MASK;
2211 end = TARGET_PAGE_ALIGN(end);
2212 if (flags & PAGE_WRITE)
2213 flags |= PAGE_WRITE_ORG;
2214 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2215 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
2216 /* We may be called for host regions that are outside guest
2217 address space. */
2218 if (!p)
2219 return;
2220 /* if the write protection is set, then we invalidate the code
2221 inside */
2222 if (!(p->flags & PAGE_WRITE) &&
2223 (flags & PAGE_WRITE) &&
2224 p->first_tb) {
2225 tb_invalidate_phys_page(addr, 0, NULL);
2226 }
2227 p->flags = flags;
2228 }
2229}
2230
2231int page_check_range(target_ulong start, target_ulong len, int flags)
2232{
2233 PageDesc *p;
2234 target_ulong end;
2235 target_ulong addr;
2236
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002237 if (start + len < start)
2238 /* we've wrapped around */
2239 return -1;
2240
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002241 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
2242 start = start & TARGET_PAGE_MASK;
2243
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002244 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2245 p = page_find(addr >> TARGET_PAGE_BITS);
2246 if( !p )
2247 return -1;
2248 if( !(p->flags & PAGE_VALID) )
2249 return -1;
2250
2251 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
2252 return -1;
2253 if (flags & PAGE_WRITE) {
2254 if (!(p->flags & PAGE_WRITE_ORG))
2255 return -1;
2256 /* unprotect the page if it was put read-only because it
2257 contains translated code */
2258 if (!(p->flags & PAGE_WRITE)) {
2259 if (!page_unprotect(addr, 0, NULL))
2260 return -1;
2261 }
2262 return 0;
2263 }
2264 }
2265 return 0;
2266}
2267
2268/* called from signal handler: invalidate the code and unprotect the
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002269 page. Return TRUE if the fault was successfully handled. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002270int page_unprotect(target_ulong address, unsigned long pc, void *puc)
2271{
2272 unsigned int page_index, prot, pindex;
2273 PageDesc *p, *p1;
2274 target_ulong host_start, host_end, addr;
2275
2276 /* Technically this isn't safe inside a signal handler. However we
2277 know this only ever happens in a synchronous SEGV handler, so in
2278 practice it seems to be ok. */
2279 mmap_lock();
2280
2281 host_start = address & qemu_host_page_mask;
2282 page_index = host_start >> TARGET_PAGE_BITS;
2283 p1 = page_find(page_index);
2284 if (!p1) {
2285 mmap_unlock();
2286 return 0;
2287 }
2288 host_end = host_start + qemu_host_page_size;
2289 p = p1;
2290 prot = 0;
2291 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2292 prot |= p->flags;
2293 p++;
2294 }
2295 /* if the page was really writable, then we change its
2296 protection back to writable */
2297 if (prot & PAGE_WRITE_ORG) {
2298 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2299 if (!(p1[pindex].flags & PAGE_WRITE)) {
2300 mprotect((void *)g2h(host_start), qemu_host_page_size,
2301 (prot & PAGE_BITS) | PAGE_WRITE);
2302 p1[pindex].flags |= PAGE_WRITE;
2303 /* and since the content will be modified, we must invalidate
2304 the corresponding translated code. */
2305 tb_invalidate_phys_page(address, pc, puc);
2306#ifdef DEBUG_TB_CHECK
2307 tb_invalidate_check(address);
2308#endif
2309 mmap_unlock();
2310 return 1;
2311 }
2312 }
2313 mmap_unlock();
2314 return 0;
2315}
2316
2317static inline void tlb_set_dirty(CPUState *env,
2318 unsigned long addr, target_ulong vaddr)
2319{
2320}
2321#endif /* defined(CONFIG_USER_ONLY) */
2322
2323#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002324
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002325static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002326 ram_addr_t memory, ram_addr_t region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002327static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002328 ram_addr_t orig_memory, ram_addr_t region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002329#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2330 need_subpage) \
2331 do { \
2332 if (addr > start_addr) \
2333 start_addr2 = 0; \
2334 else { \
2335 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2336 if (start_addr2 > 0) \
2337 need_subpage = 1; \
2338 } \
2339 \
2340 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
2341 end_addr2 = TARGET_PAGE_SIZE - 1; \
2342 else { \
2343 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2344 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2345 need_subpage = 1; \
2346 } \
2347 } while (0)
2348
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002349/* register physical memory.
2350 For RAM, 'size' must be a multiple of the target page size.
2351 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002352 io memory page. The address used when calling the IO function is
2353 the offset from the start of the region, plus region_offset. Both
2354 start_addr and region_offset are rounded down to a page boundary
2355 before calculating this offset. This should not be a problem unless
2356 the low bits of start_addr and region_offset differ. */
2357void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2358 ram_addr_t size,
2359 ram_addr_t phys_offset,
2360 ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002361{
2362 target_phys_addr_t addr, end_addr;
2363 PhysPageDesc *p;
2364 CPUState *env;
2365 ram_addr_t orig_size = size;
2366 void *subpage;
2367
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002368 if (kvm_enabled())
2369 kvm_set_phys_mem(start_addr, size, phys_offset);
2370
2371 if (phys_offset == IO_MEM_UNASSIGNED) {
2372 region_offset = start_addr;
2373 }
2374 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002375 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
2376 end_addr = start_addr + (target_phys_addr_t)size;
2377 for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
2378 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2379 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
2380 ram_addr_t orig_memory = p->phys_offset;
2381 target_phys_addr_t start_addr2, end_addr2;
2382 int need_subpage = 0;
2383
2384 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2385 need_subpage);
2386 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
2387 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2388 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002389 &p->phys_offset, orig_memory,
2390 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002391 } else {
2392 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2393 >> IO_MEM_SHIFT];
2394 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002395 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2396 region_offset);
2397 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002398 } else {
2399 p->phys_offset = phys_offset;
2400 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2401 (phys_offset & IO_MEM_ROMD))
2402 phys_offset += TARGET_PAGE_SIZE;
2403 }
2404 } else {
2405 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2406 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002407 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002408 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002409 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002410 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002411 } else {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002412 target_phys_addr_t start_addr2, end_addr2;
2413 int need_subpage = 0;
2414
2415 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2416 end_addr2, need_subpage);
2417
2418 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
2419 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002420 &p->phys_offset, IO_MEM_UNASSIGNED,
2421 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002422 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002423 phys_offset, region_offset);
2424 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002425 }
2426 }
2427 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002428 region_offset += TARGET_PAGE_SIZE;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002429 }
2430
2431 /* since each CPU stores ram addresses in its TLB cache, we must
2432 reset the modified entries */
2433 /* XXX: slow ! */
2434 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2435 tlb_flush(env, 1);
2436 }
2437}
2438
2439/* XXX: temporary until new memory mapping API */
2440ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
2441{
2442 PhysPageDesc *p;
2443
2444 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2445 if (!p)
2446 return IO_MEM_UNASSIGNED;
2447 return p->phys_offset;
2448}
2449
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002450void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2451{
2452 if (kvm_enabled())
2453 kvm_coalesce_mmio_region(addr, size);
2454}
2455
2456void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
2457{
2458 if (kvm_enabled())
2459 kvm_uncoalesce_mmio_region(addr, size);
2460}
2461
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002462ram_addr_t qemu_ram_alloc(ram_addr_t size)
2463{
2464 RAMBlock *new_block;
2465
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002466 size = TARGET_PAGE_ALIGN(size);
2467 new_block = qemu_malloc(sizeof(*new_block));
2468
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002469#if defined(TARGET_S390X) && defined(CONFIG_KVM)
2470 /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
2471 new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE,
2472 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2473#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002474 new_block->host = qemu_vmalloc(size);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002475#endif
2476#ifdef MADV_MERGEABLE
2477 madvise(new_block->host, size, MADV_MERGEABLE);
2478#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002479 new_block->offset = last_ram_offset;
2480 new_block->length = size;
2481
2482 new_block->next = ram_blocks;
2483 ram_blocks = new_block;
2484
2485 phys_ram_dirty = qemu_realloc(phys_ram_dirty,
2486 (last_ram_offset + size) >> TARGET_PAGE_BITS);
2487 memset(phys_ram_dirty + (last_ram_offset >> TARGET_PAGE_BITS),
2488 0xff, size >> TARGET_PAGE_BITS);
2489
2490 last_ram_offset += size;
2491
2492 if (kvm_enabled())
2493 kvm_setup_guest_memory(new_block->host, size);
2494
2495 return new_block->offset;
2496}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002497
2498void qemu_ram_free(ram_addr_t addr)
2499{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002500 /* TODO: implement this. */
2501}
2502
2503/* Return a host pointer to ram allocated with qemu_ram_alloc.
2504 With the exception of the softmmu code in this file, this should
2505 only be used for local memory (e.g. video ram) that the device owns,
2506 and knows it isn't going to access beyond the end of the block.
2507
2508 It should not be used for general purpose DMA.
2509 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
2510 */
2511void *qemu_get_ram_ptr(ram_addr_t addr)
2512{
2513 RAMBlock *prev;
2514 RAMBlock **prevp;
2515 RAMBlock *block;
2516
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002517 prev = NULL;
2518 prevp = &ram_blocks;
2519 block = ram_blocks;
2520 while (block && (block->offset > addr
2521 || block->offset + block->length <= addr)) {
2522 if (prev)
2523 prevp = &prev->next;
2524 prev = block;
2525 block = block->next;
2526 }
2527 if (!block) {
2528 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
2529 abort();
2530 }
2531 /* Move this entry to to start of the list. */
2532 if (prev) {
2533 prev->next = block->next;
2534 block->next = *prevp;
2535 *prevp = block;
2536 }
2537 return block->host + (addr - block->offset);
2538}
2539
2540/* Some of the softmmu routines need to translate from a host pointer
2541 (typically a TLB entry) back to a ram offset. */
2542ram_addr_t qemu_ram_addr_from_host(void *ptr)
2543{
2544 RAMBlock *prev;
2545 RAMBlock **prevp;
2546 RAMBlock *block;
2547 uint8_t *host = ptr;
2548
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002549 prev = NULL;
2550 prevp = &ram_blocks;
2551 block = ram_blocks;
2552 while (block && (block->host > host
2553 || block->host + block->length <= host)) {
2554 if (prev)
2555 prevp = &prev->next;
2556 prev = block;
2557 block = block->next;
2558 }
2559 if (!block) {
2560 fprintf(stderr, "Bad ram pointer %p\n", ptr);
2561 abort();
2562 }
2563 return block->offset + (host - block->host);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002564}
2565
2566static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
2567{
2568#ifdef DEBUG_UNASSIGNED
2569 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2570#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002571#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002572 do_unassigned_access(addr, 0, 0, 0, 1);
2573#endif
2574 return 0;
2575}
2576
2577static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
2578{
2579#ifdef DEBUG_UNASSIGNED
2580 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2581#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002582#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002583 do_unassigned_access(addr, 0, 0, 0, 2);
2584#endif
2585 return 0;
2586}
2587
2588static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
2589{
2590#ifdef DEBUG_UNASSIGNED
2591 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2592#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002593#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002594 do_unassigned_access(addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002595#endif
2596 return 0;
2597}
2598
2599static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
2600{
2601#ifdef DEBUG_UNASSIGNED
2602 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2603#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002604#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002605 do_unassigned_access(addr, 1, 0, 0, 1);
2606#endif
2607}
2608
2609static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2610{
2611#ifdef DEBUG_UNASSIGNED
2612 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2613#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002614#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002615 do_unassigned_access(addr, 1, 0, 0, 2);
2616#endif
2617}
2618
2619static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2620{
2621#ifdef DEBUG_UNASSIGNED
2622 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2623#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002624#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002625 do_unassigned_access(addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002626#endif
2627}
2628
2629static CPUReadMemoryFunc *unassigned_mem_read[3] = {
2630 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002631 unassigned_mem_readw,
2632 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002633};
2634
2635static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
2636 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002637 unassigned_mem_writew,
2638 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002639};
2640
2641static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
2642 uint32_t val)
2643{
2644 int dirty_flags;
2645 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2646 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2647#if !defined(CONFIG_USER_ONLY)
2648 tb_invalidate_phys_page_fast(ram_addr, 1);
2649 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2650#endif
2651 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002652 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002653 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2654 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2655 /* we remove the notdirty callback only if the code has been
2656 flushed */
2657 if (dirty_flags == 0xff)
2658 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2659}
2660
2661static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
2662 uint32_t val)
2663{
2664 int dirty_flags;
2665 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2666 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2667#if !defined(CONFIG_USER_ONLY)
2668 tb_invalidate_phys_page_fast(ram_addr, 2);
2669 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2670#endif
2671 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002672 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002673 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2674 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2675 /* we remove the notdirty callback only if the code has been
2676 flushed */
2677 if (dirty_flags == 0xff)
2678 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2679}
2680
2681static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
2682 uint32_t val)
2683{
2684 int dirty_flags;
2685 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2686 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2687#if !defined(CONFIG_USER_ONLY)
2688 tb_invalidate_phys_page_fast(ram_addr, 4);
2689 dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2690#endif
2691 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002692 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002693 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2694 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2695 /* we remove the notdirty callback only if the code has been
2696 flushed */
2697 if (dirty_flags == 0xff)
2698 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2699}
2700
2701static CPUReadMemoryFunc *error_mem_read[3] = {
2702 NULL, /* never used */
2703 NULL, /* never used */
2704 NULL, /* never used */
2705};
2706
2707static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2708 notdirty_mem_writeb,
2709 notdirty_mem_writew,
2710 notdirty_mem_writel,
2711};
2712
2713/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002714static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002715{
2716 CPUState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002717 target_ulong pc, cs_base;
2718 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002719 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002720 CPUWatchpoint *wp;
2721 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002722
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002723 if (env->watchpoint_hit) {
2724 /* We re-entered the check after replacing the TB. Now raise
2725 * the debug interrupt so that is will trigger after the
2726 * current instruction. */
2727 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2728 return;
2729 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002730 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002731 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002732 if ((vaddr == (wp->vaddr & len_mask) ||
2733 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
2734 wp->flags |= BP_WATCHPOINT_HIT;
2735 if (!env->watchpoint_hit) {
2736 env->watchpoint_hit = wp;
2737 tb = tb_find_pc(env->mem_io_pc);
2738 if (!tb) {
2739 cpu_abort(env, "check_watchpoint: could not find TB for "
2740 "pc=%p", (void *)env->mem_io_pc);
2741 }
2742 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
2743 tb_phys_invalidate(tb, -1);
2744 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2745 env->exception_index = EXCP_DEBUG;
2746 } else {
2747 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2748 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2749 }
2750 cpu_resume_from_signal(env, NULL);
2751 }
2752 } else {
2753 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002754 }
2755 }
2756}
2757
2758/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2759 so these check for a hit then pass through to the normal out-of-line
2760 phys routines. */
2761static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2762{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002763 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002764 return ldub_phys(addr);
2765}
2766
2767static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2768{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002769 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002770 return lduw_phys(addr);
2771}
2772
2773static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2774{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002775 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002776 return ldl_phys(addr);
2777}
2778
2779static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2780 uint32_t val)
2781{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002782 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002783 stb_phys(addr, val);
2784}
2785
2786static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2787 uint32_t val)
2788{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002789 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002790 stw_phys(addr, val);
2791}
2792
2793static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2794 uint32_t val)
2795{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002796 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002797 stl_phys(addr, val);
2798}
2799
2800static CPUReadMemoryFunc *watch_mem_read[3] = {
2801 watch_mem_readb,
2802 watch_mem_readw,
2803 watch_mem_readl,
2804};
2805
2806static CPUWriteMemoryFunc *watch_mem_write[3] = {
2807 watch_mem_writeb,
2808 watch_mem_writew,
2809 watch_mem_writel,
2810};
2811
2812static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
2813 unsigned int len)
2814{
2815 uint32_t ret;
2816 unsigned int idx;
2817
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002818 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002819#if defined(DEBUG_SUBPAGE)
2820 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2821 mmio, len, addr, idx);
2822#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002823 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2824 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002825
2826 return ret;
2827}
2828
2829static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
2830 uint32_t value, unsigned int len)
2831{
2832 unsigned int idx;
2833
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002834 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002835#if defined(DEBUG_SUBPAGE)
2836 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2837 mmio, len, addr, idx, value);
2838#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002839 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2840 addr + mmio->region_offset[idx][1][len],
2841 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002842}
2843
2844static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
2845{
2846#if defined(DEBUG_SUBPAGE)
2847 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2848#endif
2849
2850 return subpage_readlen(opaque, addr, 0);
2851}
2852
2853static void subpage_writeb (void *opaque, target_phys_addr_t addr,
2854 uint32_t value)
2855{
2856#if defined(DEBUG_SUBPAGE)
2857 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2858#endif
2859 subpage_writelen(opaque, addr, value, 0);
2860}
2861
2862static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
2863{
2864#if defined(DEBUG_SUBPAGE)
2865 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2866#endif
2867
2868 return subpage_readlen(opaque, addr, 1);
2869}
2870
2871static void subpage_writew (void *opaque, target_phys_addr_t addr,
2872 uint32_t value)
2873{
2874#if defined(DEBUG_SUBPAGE)
2875 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2876#endif
2877 subpage_writelen(opaque, addr, value, 1);
2878}
2879
2880static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
2881{
2882#if defined(DEBUG_SUBPAGE)
2883 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2884#endif
2885
2886 return subpage_readlen(opaque, addr, 2);
2887}
2888
2889static void subpage_writel (void *opaque,
2890 target_phys_addr_t addr, uint32_t value)
2891{
2892#if defined(DEBUG_SUBPAGE)
2893 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2894#endif
2895 subpage_writelen(opaque, addr, value, 2);
2896}
2897
2898static CPUReadMemoryFunc *subpage_read[] = {
2899 &subpage_readb,
2900 &subpage_readw,
2901 &subpage_readl,
2902};
2903
2904static CPUWriteMemoryFunc *subpage_write[] = {
2905 &subpage_writeb,
2906 &subpage_writew,
2907 &subpage_writel,
2908};
2909
2910static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002911 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002912{
2913 int idx, eidx;
2914 unsigned int i;
2915
2916 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2917 return -1;
2918 idx = SUBPAGE_IDX(start);
2919 eidx = SUBPAGE_IDX(end);
2920#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002921 printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002922 mmio, start, end, idx, eidx, memory);
2923#endif
2924 memory >>= IO_MEM_SHIFT;
2925 for (; idx <= eidx; idx++) {
2926 for (i = 0; i < 4; i++) {
2927 if (io_mem_read[memory][i]) {
2928 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2929 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002930 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002931 }
2932 if (io_mem_write[memory][i]) {
2933 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2934 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002935 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002936 }
2937 }
2938 }
2939
2940 return 0;
2941}
2942
2943static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002944 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002945{
2946 subpage_t *mmio;
2947 int subpage_memory;
2948
2949 mmio = qemu_mallocz(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002950
2951 mmio->base = base;
2952 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002953#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002954 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2955 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002956#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002957 *phys = subpage_memory | IO_MEM_SUBPAGE;
2958 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
2959 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002960
2961 return mmio;
2962}
2963
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002964static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002965{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002966 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002967
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002968 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2969 if (!io_mem_used[i]) {
2970 io_mem_used[i] = 1;
2971 return i;
2972 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002973 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002974 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002975}
2976
2977/* mem_read and mem_write are arrays of functions containing the
2978 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002979 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002980 If io_index is non zero, the corresponding io zone is
2981 modified. If it is zero, a new io zone is allocated. The return
2982 value can be used with cpu_register_physical_memory(). (-1) is
2983 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002984static int cpu_register_io_memory_fixed(int io_index,
2985 CPUReadMemoryFunc **mem_read,
2986 CPUWriteMemoryFunc **mem_write,
2987 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002988{
2989 int i, subwidth = 0;
2990
2991 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002992 io_index = get_free_io_mem_idx();
2993 if (io_index == -1)
2994 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002995 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002996 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002997 if (io_index >= IO_MEM_NB_ENTRIES)
2998 return -1;
2999 }
3000
3001 for(i = 0;i < 3; i++) {
3002 if (!mem_read[i] || !mem_write[i])
3003 subwidth = IO_MEM_SUBWIDTH;
3004 io_mem_read[io_index][i] = mem_read[i];
3005 io_mem_write[io_index][i] = mem_write[i];
3006 }
3007 io_mem_opaque[io_index] = opaque;
3008 return (io_index << IO_MEM_SHIFT) | subwidth;
3009}
3010
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003011int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
3012 CPUWriteMemoryFunc **mem_write,
3013 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003014{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003015 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003016}
3017
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003018void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003019{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003020 int i;
3021 int io_index = io_table_address >> IO_MEM_SHIFT;
3022
3023 for (i=0;i < 3; i++) {
3024 io_mem_read[io_index][i] = unassigned_mem_read[i];
3025 io_mem_write[io_index][i] = unassigned_mem_write[i];
3026 }
3027 io_mem_opaque[io_index] = NULL;
3028 io_mem_used[io_index] = 0;
3029}
3030
3031static void io_mem_init(void)
3032{
3033 int i;
3034
3035 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
3036 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
3037 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
3038 for (i=0; i<5; i++)
3039 io_mem_used[i] = 1;
3040
3041 io_mem_watch = cpu_register_io_memory(watch_mem_read,
3042 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003043}
3044
3045#endif /* !defined(CONFIG_USER_ONLY) */
3046
3047/* physical memory access (slow version, mainly for debug) */
3048#if defined(CONFIG_USER_ONLY)
3049void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
3050 int len, int is_write)
3051{
3052 int l, flags;
3053 target_ulong page;
3054 void * p;
3055
3056 while (len > 0) {
3057 page = addr & TARGET_PAGE_MASK;
3058 l = (page + TARGET_PAGE_SIZE) - addr;
3059 if (l > len)
3060 l = len;
3061 flags = page_get_flags(page);
3062 if (!(flags & PAGE_VALID))
3063 return;
3064 if (is_write) {
3065 if (!(flags & PAGE_WRITE))
3066 return;
3067 /* XXX: this code should not depend on lock_user */
3068 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
3069 /* FIXME - should this return an error rather than just fail? */
3070 return;
3071 memcpy(p, buf, l);
3072 unlock_user(p, addr, l);
3073 } else {
3074 if (!(flags & PAGE_READ))
3075 return;
3076 /* XXX: this code should not depend on lock_user */
3077 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
3078 /* FIXME - should this return an error rather than just fail? */
3079 return;
3080 memcpy(buf, p, l);
3081 unlock_user(p, addr, 0);
3082 }
3083 len -= l;
3084 buf += l;
3085 addr += l;
3086 }
3087}
3088
3089#else
3090void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
3091 int len, int is_write)
3092{
3093 int l, io_index;
3094 uint8_t *ptr;
3095 uint32_t val;
3096 target_phys_addr_t page;
3097 unsigned long pd;
3098 PhysPageDesc *p;
3099
3100 while (len > 0) {
3101 page = addr & TARGET_PAGE_MASK;
3102 l = (page + TARGET_PAGE_SIZE) - addr;
3103 if (l > len)
3104 l = len;
3105 p = phys_page_find(page >> TARGET_PAGE_BITS);
3106 if (!p) {
3107 pd = IO_MEM_UNASSIGNED;
3108 } else {
3109 pd = p->phys_offset;
3110 }
3111
3112 if (is_write) {
3113 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003114 target_phys_addr_t addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003115 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003116 if (p)
3117 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003118 /* XXX: could force cpu_single_env to NULL to avoid
3119 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003120 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003121 /* 32 bit write access */
3122 val = ldl_p(buf);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003123 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003124 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003125 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003126 /* 16 bit write access */
3127 val = lduw_p(buf);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003128 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003129 l = 2;
3130 } else {
3131 /* 8 bit write access */
3132 val = ldub_p(buf);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003133 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003134 l = 1;
3135 }
3136 } else {
3137 unsigned long addr1;
3138 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3139 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003140 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003141 memcpy(ptr, buf, l);
3142 if (!cpu_physical_memory_is_dirty(addr1)) {
3143 /* invalidate code */
3144 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3145 /* set dirty bit */
3146 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3147 (0xff & ~CODE_DIRTY_FLAG);
3148 }
3149 }
3150 } else {
3151 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3152 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003153 target_phys_addr_t addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003154 /* I/O case */
3155 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003156 if (p)
3157 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
3158 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003159 /* 32 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003160 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003161 stl_p(buf, val);
3162 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003163 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003164 /* 16 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003165 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003166 stw_p(buf, val);
3167 l = 2;
3168 } else {
3169 /* 8 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003170 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003171 stb_p(buf, val);
3172 l = 1;
3173 }
3174 } else {
3175 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003176 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003177 (addr & ~TARGET_PAGE_MASK);
3178 memcpy(buf, ptr, l);
3179 }
3180 }
3181 len -= l;
3182 buf += l;
3183 addr += l;
3184 }
3185}
3186
3187/* used for ROM loading : can write in RAM and ROM */
3188void cpu_physical_memory_write_rom(target_phys_addr_t addr,
3189 const uint8_t *buf, int len)
3190{
3191 int l;
3192 uint8_t *ptr;
3193 target_phys_addr_t page;
3194 unsigned long pd;
3195 PhysPageDesc *p;
3196
3197 while (len > 0) {
3198 page = addr & TARGET_PAGE_MASK;
3199 l = (page + TARGET_PAGE_SIZE) - addr;
3200 if (l > len)
3201 l = len;
3202 p = phys_page_find(page >> TARGET_PAGE_BITS);
3203 if (!p) {
3204 pd = IO_MEM_UNASSIGNED;
3205 } else {
3206 pd = p->phys_offset;
3207 }
3208
3209 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
3210 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3211 !(pd & IO_MEM_ROMD)) {
3212 /* do nothing */
3213 } else {
3214 unsigned long addr1;
3215 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3216 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003217 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003218 memcpy(ptr, buf, l);
3219 }
3220 len -= l;
3221 buf += l;
3222 addr += l;
3223 }
3224}
3225
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003226typedef struct {
3227 void *buffer;
3228 target_phys_addr_t addr;
3229 target_phys_addr_t len;
3230} BounceBuffer;
3231
3232static BounceBuffer bounce;
3233
3234typedef struct MapClient {
3235 void *opaque;
3236 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003237 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003238} MapClient;
3239
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003240static QLIST_HEAD(map_client_list, MapClient) map_client_list
3241 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003242
3243void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
3244{
3245 MapClient *client = qemu_malloc(sizeof(*client));
3246
3247 client->opaque = opaque;
3248 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003249 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003250 return client;
3251}
3252
3253void cpu_unregister_map_client(void *_client)
3254{
3255 MapClient *client = (MapClient *)_client;
3256
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003257 QLIST_REMOVE(client, link);
3258 qemu_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003259}
3260
3261static void cpu_notify_map_clients(void)
3262{
3263 MapClient *client;
3264
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003265 while (!QLIST_EMPTY(&map_client_list)) {
3266 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003267 client->callback(client->opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003268 QLIST_REMOVE(client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003269 }
3270}
3271
3272/* Map a physical memory region into a host virtual address.
3273 * May map a subset of the requested range, given by and returned in *plen.
3274 * May return NULL if resources needed to perform the mapping are exhausted.
3275 * Use only for reads OR writes - not for read-modify-write operations.
3276 * Use cpu_register_map_client() to know when retrying the map operation is
3277 * likely to succeed.
3278 */
3279void *cpu_physical_memory_map(target_phys_addr_t addr,
3280 target_phys_addr_t *plen,
3281 int is_write)
3282{
3283 target_phys_addr_t len = *plen;
3284 target_phys_addr_t done = 0;
3285 int l;
3286 uint8_t *ret = NULL;
3287 uint8_t *ptr;
3288 target_phys_addr_t page;
3289 unsigned long pd;
3290 PhysPageDesc *p;
3291 unsigned long addr1;
3292
3293 while (len > 0) {
3294 page = addr & TARGET_PAGE_MASK;
3295 l = (page + TARGET_PAGE_SIZE) - addr;
3296 if (l > len)
3297 l = len;
3298 p = phys_page_find(page >> TARGET_PAGE_BITS);
3299 if (!p) {
3300 pd = IO_MEM_UNASSIGNED;
3301 } else {
3302 pd = p->phys_offset;
3303 }
3304
3305 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3306 if (done || bounce.buffer) {
3307 break;
3308 }
3309 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
3310 bounce.addr = addr;
3311 bounce.len = l;
3312 if (!is_write) {
3313 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
3314 }
3315 ptr = bounce.buffer;
3316 } else {
3317 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3318 ptr = qemu_get_ram_ptr(addr1);
3319 }
3320 if (!done) {
3321 ret = ptr;
3322 } else if (ret + done != ptr) {
3323 break;
3324 }
3325
3326 len -= l;
3327 addr += l;
3328 done += l;
3329 }
3330 *plen = done;
3331 return ret;
3332}
3333
3334/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
3335 * Will also mark the memory as dirty if is_write == 1. access_len gives
3336 * the amount of memory that was actually read or written by the caller.
3337 */
3338void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
3339 int is_write, target_phys_addr_t access_len)
3340{
3341 if (buffer != bounce.buffer) {
3342 if (is_write) {
3343 ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
3344 while (access_len) {
3345 unsigned l;
3346 l = TARGET_PAGE_SIZE;
3347 if (l > access_len)
3348 l = access_len;
3349 if (!cpu_physical_memory_is_dirty(addr1)) {
3350 /* invalidate code */
3351 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
3352 /* set dirty bit */
3353 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3354 (0xff & ~CODE_DIRTY_FLAG);
3355 }
3356 addr1 += l;
3357 access_len -= l;
3358 }
3359 }
3360 return;
3361 }
3362 if (is_write) {
3363 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
3364 }
3365 qemu_free(bounce.buffer);
3366 bounce.buffer = NULL;
3367 cpu_notify_map_clients();
3368}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003369
3370/* warning: addr must be aligned */
3371uint32_t ldl_phys(target_phys_addr_t addr)
3372{
3373 int io_index;
3374 uint8_t *ptr;
3375 uint32_t val;
3376 unsigned long pd;
3377 PhysPageDesc *p;
3378
3379 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3380 if (!p) {
3381 pd = IO_MEM_UNASSIGNED;
3382 } else {
3383 pd = p->phys_offset;
3384 }
3385
3386 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3387 !(pd & IO_MEM_ROMD)) {
3388 /* I/O case */
3389 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003390 if (p)
3391 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003392 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3393 } else {
3394 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003395 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003396 (addr & ~TARGET_PAGE_MASK);
3397 val = ldl_p(ptr);
3398 }
3399 return val;
3400}
3401
3402/* warning: addr must be aligned */
3403uint64_t ldq_phys(target_phys_addr_t addr)
3404{
3405 int io_index;
3406 uint8_t *ptr;
3407 uint64_t val;
3408 unsigned long pd;
3409 PhysPageDesc *p;
3410
3411 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3412 if (!p) {
3413 pd = IO_MEM_UNASSIGNED;
3414 } else {
3415 pd = p->phys_offset;
3416 }
3417
3418 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3419 !(pd & IO_MEM_ROMD)) {
3420 /* I/O case */
3421 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003422 if (p)
3423 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003424#ifdef TARGET_WORDS_BIGENDIAN
3425 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3426 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3427#else
3428 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3429 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3430#endif
3431 } else {
3432 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003433 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003434 (addr & ~TARGET_PAGE_MASK);
3435 val = ldq_p(ptr);
3436 }
3437 return val;
3438}
3439
3440/* XXX: optimize */
3441uint32_t ldub_phys(target_phys_addr_t addr)
3442{
3443 uint8_t val;
3444 cpu_physical_memory_read(addr, &val, 1);
3445 return val;
3446}
3447
3448/* XXX: optimize */
3449uint32_t lduw_phys(target_phys_addr_t addr)
3450{
3451 uint16_t val;
3452 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3453 return tswap16(val);
3454}
3455
3456/* warning: addr must be aligned. The ram page is not masked as dirty
3457 and the code inside is not invalidated. It is useful if the dirty
3458 bits are used to track modified PTEs */
3459void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
3460{
3461 int io_index;
3462 uint8_t *ptr;
3463 unsigned long pd;
3464 PhysPageDesc *p;
3465
3466 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3467 if (!p) {
3468 pd = IO_MEM_UNASSIGNED;
3469 } else {
3470 pd = p->phys_offset;
3471 }
3472
3473 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3474 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003475 if (p)
3476 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003477 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3478 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003479 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3480 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003481 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003482
3483 if (unlikely(in_migration)) {
3484 if (!cpu_physical_memory_is_dirty(addr1)) {
3485 /* invalidate code */
3486 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3487 /* set dirty bit */
3488 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3489 (0xff & ~CODE_DIRTY_FLAG);
3490 }
3491 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003492 }
3493}
3494
3495void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
3496{
3497 int io_index;
3498 uint8_t *ptr;
3499 unsigned long pd;
3500 PhysPageDesc *p;
3501
3502 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3503 if (!p) {
3504 pd = IO_MEM_UNASSIGNED;
3505 } else {
3506 pd = p->phys_offset;
3507 }
3508
3509 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3510 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003511 if (p)
3512 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003513#ifdef TARGET_WORDS_BIGENDIAN
3514 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3515 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3516#else
3517 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3518 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3519#endif
3520 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003521 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003522 (addr & ~TARGET_PAGE_MASK);
3523 stq_p(ptr, val);
3524 }
3525}
3526
3527/* warning: addr must be aligned */
3528void stl_phys(target_phys_addr_t addr, uint32_t val)
3529{
3530 int io_index;
3531 uint8_t *ptr;
3532 unsigned long pd;
3533 PhysPageDesc *p;
3534
3535 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3536 if (!p) {
3537 pd = IO_MEM_UNASSIGNED;
3538 } else {
3539 pd = p->phys_offset;
3540 }
3541
3542 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3543 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003544 if (p)
3545 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003546 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3547 } else {
3548 unsigned long addr1;
3549 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3550 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003551 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003552 stl_p(ptr, val);
3553 if (!cpu_physical_memory_is_dirty(addr1)) {
3554 /* invalidate code */
3555 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3556 /* set dirty bit */
3557 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
3558 (0xff & ~CODE_DIRTY_FLAG);
3559 }
3560 }
3561}
3562
3563/* XXX: optimize */
3564void stb_phys(target_phys_addr_t addr, uint32_t val)
3565{
3566 uint8_t v = val;
3567 cpu_physical_memory_write(addr, &v, 1);
3568}
3569
3570/* XXX: optimize */
3571void stw_phys(target_phys_addr_t addr, uint32_t val)
3572{
3573 uint16_t v = tswap16(val);
3574 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3575}
3576
3577/* XXX: optimize */
3578void stq_phys(target_phys_addr_t addr, uint64_t val)
3579{
3580 val = tswap64(val);
3581 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3582}
3583
3584#endif
3585
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003586/* virtual memory access for debug (includes writing to ROM) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003587int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
3588 uint8_t *buf, int len, int is_write)
3589{
3590 int l;
3591 target_phys_addr_t phys_addr;
3592 target_ulong page;
3593
3594 while (len > 0) {
3595 page = addr & TARGET_PAGE_MASK;
3596 phys_addr = cpu_get_phys_page_debug(env, page);
3597 /* if no physical page mapped, return an error */
3598 if (phys_addr == -1)
3599 return -1;
3600 l = (page + TARGET_PAGE_SIZE) - addr;
3601 if (l > len)
3602 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003603 phys_addr += (addr & ~TARGET_PAGE_MASK);
3604#if !defined(CONFIG_USER_ONLY)
3605 if (is_write)
3606 cpu_physical_memory_write_rom(phys_addr, buf, l);
3607 else
3608#endif
3609 cpu_physical_memory_rw(phys_addr, buf, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003610 len -= l;
3611 buf += l;
3612 addr += l;
3613 }
3614 return 0;
3615}
3616
3617/* in deterministic execution mode, instructions doing device I/Os
3618 must be at the end of the TB */
3619void cpu_io_recompile(CPUState *env, void *retaddr)
3620{
3621 TranslationBlock *tb;
3622 uint32_t n, cflags;
3623 target_ulong pc, cs_base;
3624 uint64_t flags;
3625
3626 tb = tb_find_pc((unsigned long)retaddr);
3627 if (!tb) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08003628 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003629 retaddr);
3630 }
3631 n = env->icount_decr.u16.low + tb->icount;
3632 cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
3633 /* Calculate how many instructions had been executed before the fault
3634 occurred. */
3635 n = n - env->icount_decr.u16.low;
3636 /* Generate a new TB ending on the I/O insn. */
3637 n++;
3638 /* On MIPS and SH, delay slot instructions can only be restarted if
3639 they were already the first instruction in the TB. If this is not
3640 the first instruction in a TB then re-execute the preceding
3641 branch. */
3642#if defined(TARGET_MIPS)
3643 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3644 env->active_tc.PC -= 4;
3645 env->icount_decr.u16.low++;
3646 env->hflags &= ~MIPS_HFLAG_BMASK;
3647 }
3648#elif defined(TARGET_SH4)
3649 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3650 && n > 1) {
3651 env->pc -= 2;
3652 env->icount_decr.u16.low++;
3653 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3654 }
3655#endif
3656 /* This should never happen. */
3657 if (n > CF_COUNT_MASK)
3658 cpu_abort(env, "TB too big during recompile");
3659
3660 cflags = n | CF_LAST_IO;
3661 pc = tb->pc;
3662 cs_base = tb->cs_base;
3663 flags = tb->flags;
3664 tb_phys_invalidate(tb, -1);
3665 /* FIXME: In theory this could raise an exception. In practice
3666 we have already translated the block once so it's probably ok. */
3667 tb_gen_code(env, pc, cs_base, flags, cflags);
3668 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
3669 the first in the TB) then we end up generating a whole new TB and
3670 repeating the fault, which is horribly inefficient.
3671 Better would be to execute just this insn uncached, or generate a
3672 second new TB. */
3673 cpu_resume_from_signal(env, NULL);
3674}
3675
3676void dump_exec_info(FILE *f,
3677 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
3678{
3679 int i, target_code_size, max_target_code_size;
3680 int direct_jmp_count, direct_jmp2_count, cross_page;
3681 TranslationBlock *tb;
3682
3683 target_code_size = 0;
3684 max_target_code_size = 0;
3685 cross_page = 0;
3686 direct_jmp_count = 0;
3687 direct_jmp2_count = 0;
3688 for(i = 0; i < nb_tbs; i++) {
3689 tb = &tbs[i];
3690 target_code_size += tb->size;
3691 if (tb->size > max_target_code_size)
3692 max_target_code_size = tb->size;
3693 if (tb->page_addr[1] != -1)
3694 cross_page++;
3695 if (tb->tb_next_offset[0] != 0xffff) {
3696 direct_jmp_count++;
3697 if (tb->tb_next_offset[1] != 0xffff) {
3698 direct_jmp2_count++;
3699 }
3700 }
3701 }
3702 /* XXX: avoid using doubles ? */
3703 cpu_fprintf(f, "Translation buffer state:\n");
3704 cpu_fprintf(f, "gen code size %ld/%ld\n",
3705 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08003706 cpu_fprintf(f, "TB count %d/%d\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003707 nb_tbs, code_gen_max_blocks);
3708 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
3709 nb_tbs ? target_code_size / nb_tbs : 0,
3710 max_target_code_size);
3711 cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
3712 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3713 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
3714 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3715 cross_page,
3716 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3717 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
3718 direct_jmp_count,
3719 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3720 direct_jmp2_count,
3721 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
3722 cpu_fprintf(f, "\nStatistics:\n");
3723 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3724 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3725 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
3726 tcg_dump_info(f, cpu_fprintf);
3727}
3728
3729#if !defined(CONFIG_USER_ONLY)
3730
3731#define MMUSUFFIX _cmmu
3732#define GETPC() NULL
3733#define env cpu_single_env
3734#define SOFTMMU_CODE_ACCESS
3735
3736#define SHIFT 0
3737#include "softmmu_template.h"
3738
3739#define SHIFT 1
3740#include "softmmu_template.h"
3741
3742#define SHIFT 2
3743#include "softmmu_template.h"
3744
3745#define SHIFT 3
3746#include "softmmu_template.h"
3747
3748#undef env
3749
3750#endif