blob: 33f36531b977ecef3ff9bb9382ebf8c782e2fa3b [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"
David 'Digit' Turner852088c2013-12-14 23:04:12 +010036#include "exec/exec-all.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080037#include "qemu-common.h"
38#include "tcg.h"
39#include "hw/hw.h"
David 'Digit' Turner84569132013-12-13 17:34:07 +010040#include "qemu/osdep.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010041#include "sysemu/kvm.h"
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010042#include "exec/cputlb.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010043#include "exec/hax.h"
David 'Digit' Turner7a78db72013-12-14 11:46:01 +010044#include "qemu/timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080045#if defined(CONFIG_USER_ONLY)
46#include <qemu.h>
47#endif
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080048#ifdef CONFIG_MEMCHECK
49#include "memcheck/memcheck_api.h"
50#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080051
52//#define DEBUG_TB_INVALIDATE
53//#define DEBUG_FLUSH
54//#define DEBUG_TLB
55//#define DEBUG_UNASSIGNED
56
57/* make various TB consistency checks */
58//#define DEBUG_TB_CHECK
59//#define DEBUG_TLB_CHECK
60
61//#define DEBUG_IOPORT
62//#define DEBUG_SUBPAGE
63
64#if !defined(CONFIG_USER_ONLY)
65/* TB consistency checks only implemented for usermode emulation. */
66#undef DEBUG_TB_CHECK
67#endif
68
69#define SMC_BITMAP_USE_THRESHOLD 10
70
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070071static TranslationBlock *tbs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080072int code_gen_max_blocks;
73TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070074static int nb_tbs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080075/* any access to the tbs or the page table must use this lock */
76spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
77
78#if defined(__arm__) || defined(__sparc_v9__)
79/* The prologue must be reachable with a direct jump. ARM and Sparc64
80 have limited branch ranges (possibly also PPC) so place it in a
81 section close to code segment. */
82#define code_gen_section \
83 __attribute__((__section__(".gen_code"))) \
84 __attribute__((aligned (32)))
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070085#elif defined(_WIN32)
86/* Maximum alignment for Win32 is 16. */
87#define code_gen_section \
88 __attribute__((aligned (16)))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080089#else
90#define code_gen_section \
91 __attribute__((aligned (32)))
92#endif
93
94uint8_t code_gen_prologue[1024] code_gen_section;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070095static uint8_t *code_gen_buffer;
96static unsigned long code_gen_buffer_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080097/* threshold to flush the translated code buffer */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070098static unsigned long code_gen_buffer_max_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080099uint8_t *code_gen_ptr;
100
101#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800102int phys_ram_fd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700103static int in_migration;
104
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200105RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800106#endif
107
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100108CPUOldState *first_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800109/* current CPU in the current thread. It is only valid inside
110 cpu_exec() */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100111CPUOldState *cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800112/* 0 = Do not count executed instructions.
113 1 = Precise instruction counting.
114 2 = Adaptive rate instruction counting. */
115int use_icount = 0;
116/* Current instruction counter. While executing translated code this may
117 include some instructions that have not yet been executed. */
118int64_t qemu_icount;
119
120typedef struct PageDesc {
121 /* list of TBs intersecting this ram page */
122 TranslationBlock *first_tb;
123 /* in order to optimize self modifying code, we count the number
124 of lookups we do to a given page to use a bitmap */
125 unsigned int code_write_count;
126 uint8_t *code_bitmap;
127#if defined(CONFIG_USER_ONLY)
128 unsigned long flags;
129#endif
130} PageDesc;
131
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800132#define L2_BITS 10
133#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
134/* XXX: this is a temporary hack for alpha target.
135 * In the future, this is to be replaced by a multi-level table
136 * to actually be able to handle the complete 64 bits address space.
137 */
138#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
139#else
140#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
141#endif
142
143#define L1_SIZE (1 << L1_BITS)
144#define L2_SIZE (1 << L2_BITS)
145
David 'Digit' Turnerf0729c72014-01-13 16:10:10 +0100146uintptr_t qemu_real_host_page_size;
147uintptr_t qemu_host_page_bits;
148uintptr_t qemu_host_page_size;
149uintptr_t qemu_host_page_mask;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800150
151/* XXX: for system emulation, it could just be an array */
152static PageDesc *l1_map[L1_SIZE];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700153static PhysPageDesc **l1_phys_map;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800154
155#if !defined(CONFIG_USER_ONLY)
156static void io_mem_init(void);
157
158/* io memory support */
159CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
160CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
161void *io_mem_opaque[IO_MEM_NB_ENTRIES];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700162static char io_mem_used[IO_MEM_NB_ENTRIES];
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +0100163int io_mem_watch;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800164#endif
165
166/* log support */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700167#ifdef WIN32
168static const char *logfilename = "qemu.log";
169#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700170static const char *logfilename = "/tmp/qemu.log";
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700171#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800172FILE *logfile;
173int loglevel;
174static int log_append = 0;
175
176/* statistics */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800177static int tb_flush_count;
178static int tb_phys_invalidate_count;
179
180#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
181typedef struct subpage_t {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100182 hwaddr base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800183 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
184 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
185 void *opaque[TARGET_PAGE_SIZE][2][4];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700186 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800187} subpage_t;
188
189#ifdef _WIN32
190static void map_exec(void *addr, long size)
191{
192 DWORD old_protect;
193 VirtualProtect(addr, size,
194 PAGE_EXECUTE_READWRITE, &old_protect);
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200195
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800196}
197#else
198static void map_exec(void *addr, long size)
199{
200 unsigned long start, end, page_size;
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200201
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800202 page_size = getpagesize();
203 start = (unsigned long)addr;
204 start &= ~(page_size - 1);
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200205
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800206 end = (unsigned long)addr + size;
207 end += page_size - 1;
208 end &= ~(page_size - 1);
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200209
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800210 mprotect((void *)start, end - start,
211 PROT_READ | PROT_WRITE | PROT_EXEC);
212}
213#endif
214
215static void page_init(void)
216{
217 /* NOTE: we can always suppose that qemu_host_page_size >=
218 TARGET_PAGE_SIZE */
219#ifdef _WIN32
220 {
221 SYSTEM_INFO system_info;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800222
223 GetSystemInfo(&system_info);
224 qemu_real_host_page_size = system_info.dwPageSize;
225 }
226#else
227 qemu_real_host_page_size = getpagesize();
228#endif
229 if (qemu_host_page_size == 0)
230 qemu_host_page_size = qemu_real_host_page_size;
231 if (qemu_host_page_size < TARGET_PAGE_SIZE)
232 qemu_host_page_size = TARGET_PAGE_SIZE;
233 qemu_host_page_bits = 0;
234 while ((1 << qemu_host_page_bits) < qemu_host_page_size)
235 qemu_host_page_bits++;
236 qemu_host_page_mask = ~(qemu_host_page_size - 1);
237 l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
238 memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
239
240#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
241 {
242 long long startaddr, endaddr;
243 FILE *f;
244 int n;
245
246 mmap_lock();
247 last_brk = (unsigned long)sbrk(0);
248 f = fopen("/proc/self/maps", "r");
249 if (f) {
250 do {
251 n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
252 if (n == 2) {
253 startaddr = MIN(startaddr,
254 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
255 endaddr = MIN(endaddr,
256 (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
257 page_set_flags(startaddr & TARGET_PAGE_MASK,
258 TARGET_PAGE_ALIGN(endaddr),
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800259 PAGE_RESERVED);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800260 }
261 } while (!feof(f));
262 fclose(f);
263 }
264 mmap_unlock();
265 }
266#endif
267}
268
269static inline PageDesc **page_l1_map(target_ulong index)
270{
271#if TARGET_LONG_BITS > 32
272 /* Host memory outside guest VM. For 32-bit targets we have already
273 excluded high addresses. */
274 if (index > ((target_ulong)L2_SIZE * L1_SIZE))
275 return NULL;
276#endif
277 return &l1_map[index >> L2_BITS];
278}
279
280static inline PageDesc *page_find_alloc(target_ulong index)
281{
282 PageDesc **lp, *p;
283 lp = page_l1_map(index);
284 if (!lp)
285 return NULL;
286
287 p = *lp;
288 if (!p) {
289 /* allocate if not found */
290#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800291 size_t len = sizeof(PageDesc) * L2_SIZE;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100292 /* Don't use g_malloc because it may recurse. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700293 p = mmap(NULL, len, PROT_READ | PROT_WRITE,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800294 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
295 *lp = p;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700296 if (h2g_valid(p)) {
297 unsigned long addr = h2g(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800298 page_set_flags(addr & TARGET_PAGE_MASK,
299 TARGET_PAGE_ALIGN(addr + len),
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800300 PAGE_RESERVED);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800301 }
302#else
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100303 p = g_malloc0(sizeof(PageDesc) * L2_SIZE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800304 *lp = p;
305#endif
306 }
307 return p + (index & (L2_SIZE - 1));
308}
309
310static inline PageDesc *page_find(target_ulong index)
311{
312 PageDesc **lp, *p;
313 lp = page_l1_map(index);
314 if (!lp)
315 return NULL;
316
317 p = *lp;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700318 if (!p) {
319 return NULL;
320 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800321 return p + (index & (L2_SIZE - 1));
322}
323
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100324static PhysPageDesc *phys_page_find_alloc(hwaddr index, int alloc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800325{
326 void **lp, **p;
327 PhysPageDesc *pd;
328
329 p = (void **)l1_phys_map;
330#if TARGET_PHYS_ADDR_SPACE_BITS > 32
331
332#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
333#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
334#endif
335 lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
336 p = *lp;
337 if (!p) {
338 /* allocate if not found */
339 if (!alloc)
340 return NULL;
341 p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
342 memset(p, 0, sizeof(void *) * L1_SIZE);
343 *lp = p;
344 }
345#endif
346 lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
347 pd = *lp;
348 if (!pd) {
349 int i;
350 /* allocate if not found */
351 if (!alloc)
352 return NULL;
353 pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
354 *lp = pd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355 for (i = 0; i < L2_SIZE; i++) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356 pd[i].phys_offset = IO_MEM_UNASSIGNED;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700357 pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
358 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800359 }
360 return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
361}
362
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +0100363PhysPageDesc *phys_page_find(hwaddr index)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800364{
365 return phys_page_find_alloc(index, 0);
366}
367
368#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800369#define mmap_lock() do { } while(0)
370#define mmap_unlock() do { } while(0)
371#endif
372
373#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
374
375#if defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700376/* Currently it is not recommended to allocate big chunks of data in
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800377 user mode. It will change when a dedicated libc will be used */
378#define USE_STATIC_CODE_GEN_BUFFER
379#endif
380
381#ifdef USE_STATIC_CODE_GEN_BUFFER
382static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
383#endif
384
385static void code_gen_alloc(unsigned long tb_size)
386{
387#ifdef USE_STATIC_CODE_GEN_BUFFER
388 code_gen_buffer = static_code_gen_buffer;
389 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
390 map_exec(code_gen_buffer, code_gen_buffer_size);
391#else
392 code_gen_buffer_size = tb_size;
393 if (code_gen_buffer_size == 0) {
394#if defined(CONFIG_USER_ONLY)
395 /* in user mode, phys_ram_size is not meaningful */
396 code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
397#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700398 /* XXX: needs adjustments */
399 code_gen_buffer_size = (unsigned long)(ram_size / 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800400#endif
401 }
402 if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
403 code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
404 /* The code gen buffer location may have constraints depending on
405 the host cpu and OS */
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200406#if defined(__linux__)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800407 {
408 int flags;
409 void *start = NULL;
410
411 flags = MAP_PRIVATE | MAP_ANONYMOUS;
412#if defined(__x86_64__)
413 flags |= MAP_32BIT;
414 /* Cannot map more than that */
415 if (code_gen_buffer_size > (800 * 1024 * 1024))
416 code_gen_buffer_size = (800 * 1024 * 1024);
417#elif defined(__sparc_v9__)
418 // Map the buffer below 2G, so we can use direct calls and branches
419 flags |= MAP_FIXED;
420 start = (void *) 0x60000000UL;
421 if (code_gen_buffer_size > (512 * 1024 * 1024))
422 code_gen_buffer_size = (512 * 1024 * 1024);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700423#elif defined(__arm__)
424 /* Map the buffer below 32M, so we can use direct calls and branches */
425 flags |= MAP_FIXED;
426 start = (void *) 0x01000000UL;
427 if (code_gen_buffer_size > 16 * 1024 * 1024)
428 code_gen_buffer_size = 16 * 1024 * 1024;
David 'Digit' Turner36411062010-12-22 17:34:53 +0100429#elif defined(__s390x__)
430 /* Map the buffer so that we can use direct calls and branches. */
431 /* We have a +- 4GB range on the branches; leave some slop. */
432 if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) {
433 code_gen_buffer_size = 3ul * 1024 * 1024 * 1024;
434 }
435 start = (void *)0x90000000UL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800436#endif
437 code_gen_buffer = mmap(start, code_gen_buffer_size,
438 PROT_WRITE | PROT_READ | PROT_EXEC,
439 flags, -1, 0);
440 if (code_gen_buffer == MAP_FAILED) {
441 fprintf(stderr, "Could not allocate dynamic translator buffer\n");
442 exit(1);
443 }
444 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200445#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
446 || defined(__DragonFly__) || defined(__OpenBSD__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700447 {
448 int flags;
449 void *addr = NULL;
450 flags = MAP_PRIVATE | MAP_ANONYMOUS;
451#if defined(__x86_64__)
452 /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
453 * 0x40000000 is free */
454 flags |= MAP_FIXED;
455 addr = (void *)0x40000000;
456 /* Cannot map more than that */
457 if (code_gen_buffer_size > (800 * 1024 * 1024))
458 code_gen_buffer_size = (800 * 1024 * 1024);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200459#elif defined(__sparc_v9__)
460 // Map the buffer below 2G, so we can use direct calls and branches
461 flags |= MAP_FIXED;
462 addr = (void *) 0x60000000UL;
463 if (code_gen_buffer_size > (512 * 1024 * 1024)) {
464 code_gen_buffer_size = (512 * 1024 * 1024);
465 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700466#endif
467 code_gen_buffer = mmap(addr, code_gen_buffer_size,
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200468 PROT_WRITE | PROT_READ | PROT_EXEC,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700469 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 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800475#else
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100476 code_gen_buffer = g_malloc(code_gen_buffer_size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800477 map_exec(code_gen_buffer, code_gen_buffer_size);
478#endif
479#endif /* !USE_STATIC_CODE_GEN_BUFFER */
480 map_exec(code_gen_prologue, sizeof(code_gen_prologue));
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800481 code_gen_buffer_max_size = code_gen_buffer_size -
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800482 code_gen_max_block_size();
483 code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100484 tbs = g_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800485}
486
487/* Must be called before using the QEMU cpus. 'tb_size' is the size
488 (in bytes) allocated to the translation buffer. Zero means default
489 size. */
490void cpu_exec_init_all(unsigned long tb_size)
491{
492 cpu_gen_init();
493 code_gen_alloc(tb_size);
494 code_gen_ptr = code_gen_buffer;
495 page_init();
496#if !defined(CONFIG_USER_ONLY)
497 io_mem_init();
498#endif
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200499#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
500 /* There's no guest base to take into account, so go ahead and
501 initialize the prologue now. */
502 tcg_prologue_init(&tcg_ctx);
503#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800504}
505
506#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
507
508#define CPU_COMMON_SAVE_VERSION 1
509
510static void cpu_common_save(QEMUFile *f, void *opaque)
511{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100512 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800513
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700514 cpu_synchronize_state(env, 0);
515
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800516 qemu_put_be32s(f, &env->halted);
517 qemu_put_be32s(f, &env->interrupt_request);
518}
519
520static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
521{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100522 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800523
524 if (version_id != CPU_COMMON_SAVE_VERSION)
525 return -EINVAL;
526
527 qemu_get_be32s(f, &env->halted);
528 qemu_get_be32s(f, &env->interrupt_request);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700529 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
530 version_id is increased. */
531 env->interrupt_request &= ~0x01;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800532 tlb_flush(env, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700533 cpu_synchronize_state(env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800534
535 return 0;
536}
537#endif
538
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100539CPUOldState *qemu_get_cpu(int cpu)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700540{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100541 CPUOldState *env = first_cpu;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700542
543 while (env) {
544 if (env->cpu_index == cpu)
545 break;
546 env = env->next_cpu;
547 }
548
549 return env;
550}
551
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100552void cpu_exec_init(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800553{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100554 CPUOldState **penv;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800555 int cpu_index;
556
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700557#if defined(CONFIG_USER_ONLY)
558 cpu_list_lock();
559#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800560 env->next_cpu = NULL;
561 penv = &first_cpu;
562 cpu_index = 0;
563 while (*penv != NULL) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700564 penv = &(*penv)->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800565 cpu_index++;
566 }
567 env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700568 env->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700569 QTAILQ_INIT(&env->breakpoints);
570 QTAILQ_INIT(&env->watchpoints);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800571 *penv = env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700572#if defined(CONFIG_USER_ONLY)
573 cpu_list_unlock();
574#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800575#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
576 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
577 cpu_common_save, cpu_common_load, env);
578 register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
579 cpu_save, cpu_load, env);
580#endif
581}
582
583static inline void invalidate_page_bitmap(PageDesc *p)
584{
585 if (p->code_bitmap) {
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100586 g_free(p->code_bitmap);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800587 p->code_bitmap = NULL;
588 }
589 p->code_write_count = 0;
590}
591
592/* set to NULL all the 'first_tb' fields in all PageDescs */
593static void page_flush_tb(void)
594{
595 int i, j;
596 PageDesc *p;
597
598 for(i = 0; i < L1_SIZE; i++) {
599 p = l1_map[i];
600 if (p) {
601 for(j = 0; j < L2_SIZE; j++) {
602 p->first_tb = NULL;
603 invalidate_page_bitmap(p);
604 p++;
605 }
606 }
607 }
608}
609
610/* flush all the translation blocks */
611/* XXX: tb_flush is currently not thread safe */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100612void tb_flush(CPUOldState *env1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800613{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100614 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800615#if defined(DEBUG_FLUSH)
616 printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
617 (unsigned long)(code_gen_ptr - code_gen_buffer),
618 nb_tbs, nb_tbs > 0 ?
619 ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
620#endif
621 if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
622 cpu_abort(env1, "Internal error: code buffer overflow\n");
623
624 nb_tbs = 0;
625
626 for(env = first_cpu; env != NULL; env = env->next_cpu) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800627#ifdef CONFIG_MEMCHECK
628 int tb_to_clean;
629 for (tb_to_clean = 0; tb_to_clean < TB_JMP_CACHE_SIZE; tb_to_clean++) {
630 if (env->tb_jmp_cache[tb_to_clean] != NULL &&
631 env->tb_jmp_cache[tb_to_clean]->tpc2gpc != NULL) {
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100632 g_free(env->tb_jmp_cache[tb_to_clean]->tpc2gpc);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800633 env->tb_jmp_cache[tb_to_clean]->tpc2gpc = NULL;
634 env->tb_jmp_cache[tb_to_clean]->tpc2gpc_pairs = 0;
635 }
636 }
637#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800638 memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
639 }
640
641 memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
642 page_flush_tb();
643
644 code_gen_ptr = code_gen_buffer;
645 /* XXX: flush processor icache at this point if cache flush is
646 expensive */
647 tb_flush_count++;
648}
649
650#ifdef DEBUG_TB_CHECK
651
652static void tb_invalidate_check(target_ulong address)
653{
654 TranslationBlock *tb;
655 int i;
656 address &= TARGET_PAGE_MASK;
657 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
658 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
659 if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
660 address >= tb->pc + tb->size)) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700661 printf("ERROR invalidate: address=" TARGET_FMT_lx
662 " PC=%08lx size=%04x\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800663 address, (long)tb->pc, tb->size);
664 }
665 }
666 }
667}
668
669/* verify that all the pages have correct rights for code */
670static void tb_page_check(void)
671{
672 TranslationBlock *tb;
673 int i, flags1, flags2;
674
675 for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
676 for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
677 flags1 = page_get_flags(tb->pc);
678 flags2 = page_get_flags(tb->pc + tb->size - 1);
679 if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
680 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
681 (long)tb->pc, tb->size, flags1, flags2);
682 }
683 }
684 }
685}
686
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800687#endif
688
689/* invalidate one TB */
690static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
691 int next_offset)
692{
693 TranslationBlock *tb1;
694 for(;;) {
695 tb1 = *ptb;
696 if (tb1 == tb) {
697 *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
698 break;
699 }
700 ptb = (TranslationBlock **)((char *)tb1 + next_offset);
701 }
702}
703
704static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
705{
706 TranslationBlock *tb1;
707 unsigned int n1;
708
709 for(;;) {
710 tb1 = *ptb;
711 n1 = (long)tb1 & 3;
712 tb1 = (TranslationBlock *)((long)tb1 & ~3);
713 if (tb1 == tb) {
714 *ptb = tb1->page_next[n1];
715 break;
716 }
717 ptb = &tb1->page_next[n1];
718 }
719}
720
721static inline void tb_jmp_remove(TranslationBlock *tb, int n)
722{
723 TranslationBlock *tb1, **ptb;
724 unsigned int n1;
725
726 ptb = &tb->jmp_next[n];
727 tb1 = *ptb;
728 if (tb1) {
729 /* find tb(n) in circular list */
730 for(;;) {
731 tb1 = *ptb;
732 n1 = (long)tb1 & 3;
733 tb1 = (TranslationBlock *)((long)tb1 & ~3);
734 if (n1 == n && tb1 == tb)
735 break;
736 if (n1 == 2) {
737 ptb = &tb1->jmp_first;
738 } else {
739 ptb = &tb1->jmp_next[n1];
740 }
741 }
742 /* now we can suppress tb(n) from the list */
743 *ptb = tb->jmp_next[n];
744
745 tb->jmp_next[n] = NULL;
746 }
747}
748
749/* reset the jump entry 'n' of a TB so that it is not chained to
750 another TB */
751static inline void tb_reset_jump(TranslationBlock *tb, int n)
752{
753 tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
754}
755
756void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
757{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100758 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800759 PageDesc *p;
760 unsigned int h, n1;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100761 hwaddr phys_pc;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800762 TranslationBlock *tb1, *tb2;
763
764 /* remove the TB from the hash list */
765 phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
766 h = tb_phys_hash_func(phys_pc);
767 tb_remove(&tb_phys_hash[h], tb,
768 offsetof(TranslationBlock, phys_hash_next));
769
770 /* remove the TB from the page list */
771 if (tb->page_addr[0] != page_addr) {
772 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
773 tb_page_remove(&p->first_tb, tb);
774 invalidate_page_bitmap(p);
775 }
776 if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
777 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
778 tb_page_remove(&p->first_tb, tb);
779 invalidate_page_bitmap(p);
780 }
781
782 tb_invalidated_flag = 1;
783
784 /* remove the TB from the hash list */
785 h = tb_jmp_cache_hash_func(tb->pc);
786 for(env = first_cpu; env != NULL; env = env->next_cpu) {
787 if (env->tb_jmp_cache[h] == tb)
788 env->tb_jmp_cache[h] = NULL;
789 }
790
791 /* suppress this TB from the two jump lists */
792 tb_jmp_remove(tb, 0);
793 tb_jmp_remove(tb, 1);
794
795 /* suppress any remaining jumps to this TB */
796 tb1 = tb->jmp_first;
797 for(;;) {
798 n1 = (long)tb1 & 3;
799 if (n1 == 2)
800 break;
801 tb1 = (TranslationBlock *)((long)tb1 & ~3);
802 tb2 = tb1->jmp_next[n1];
803 tb_reset_jump(tb1, n1);
804 tb1->jmp_next[n1] = NULL;
805 tb1 = tb2;
806 }
807 tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
808
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800809#ifdef CONFIG_MEMCHECK
810 if (tb->tpc2gpc != NULL) {
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100811 g_free(tb->tpc2gpc);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800812 tb->tpc2gpc = NULL;
813 tb->tpc2gpc_pairs = 0;
814 }
815#endif // CONFIG_MEMCHECK
816
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800817 tb_phys_invalidate_count++;
818}
819
820static inline void set_bits(uint8_t *tab, int start, int len)
821{
822 int end, mask, end1;
823
824 end = start + len;
825 tab += start >> 3;
826 mask = 0xff << (start & 7);
827 if ((start & ~7) == (end & ~7)) {
828 if (start < end) {
829 mask &= ~(0xff << (end & 7));
830 *tab |= mask;
831 }
832 } else {
833 *tab++ |= mask;
834 start = (start + 8) & ~7;
835 end1 = end & ~7;
836 while (start < end1) {
837 *tab++ = 0xff;
838 start += 8;
839 }
840 if (start < end) {
841 mask = ~(0xff << (end & 7));
842 *tab |= mask;
843 }
844 }
845}
846
847static void build_page_bitmap(PageDesc *p)
848{
849 int n, tb_start, tb_end;
850 TranslationBlock *tb;
851
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100852 p->code_bitmap = g_malloc0(TARGET_PAGE_SIZE / 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800853
854 tb = p->first_tb;
855 while (tb != NULL) {
856 n = (long)tb & 3;
857 tb = (TranslationBlock *)((long)tb & ~3);
858 /* NOTE: this is subtle as a TB may span two physical pages */
859 if (n == 0) {
860 /* NOTE: tb_end may be after the end of the page, but
861 it is not a problem */
862 tb_start = tb->pc & ~TARGET_PAGE_MASK;
863 tb_end = tb_start + tb->size;
864 if (tb_end > TARGET_PAGE_SIZE)
865 tb_end = TARGET_PAGE_SIZE;
866 } else {
867 tb_start = 0;
868 tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
869 }
870 set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
871 tb = tb->page_next[n];
872 }
873}
874
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100875TranslationBlock *tb_gen_code(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800876 target_ulong pc, target_ulong cs_base,
877 int flags, int cflags)
878{
879 TranslationBlock *tb;
880 uint8_t *tc_ptr;
881 target_ulong phys_pc, phys_page2, virt_page2;
882 int code_gen_size;
883
884 phys_pc = get_phys_addr_code(env, pc);
885 tb = tb_alloc(pc);
886 if (!tb) {
887 /* flush must be done */
888 tb_flush(env);
889 /* cannot fail at this point */
890 tb = tb_alloc(pc);
891 /* Don't forget to invalidate previous TB info. */
892 tb_invalidated_flag = 1;
893 }
894 tc_ptr = code_gen_ptr;
895 tb->tc_ptr = tc_ptr;
896 tb->cs_base = cs_base;
897 tb->flags = flags;
898 tb->cflags = cflags;
899#ifdef CONFIG_TRACE
900 tb->bb_rec = NULL;
901 tb->prev_time = 0;
902#endif
903 cpu_gen_code(env, tb, &code_gen_size);
904 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
905
906 /* check next page if needed */
907 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
908 phys_page2 = -1;
909 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
910 phys_page2 = get_phys_addr_code(env, virt_page2);
911 }
912 tb_link_phys(tb, phys_pc, phys_page2);
913 return tb;
914}
915
916/* invalidate all TBs which intersect with the target physical page
917 starting in range [start;end[. NOTE: start and end must refer to
918 the same physical page. 'is_cpu_write_access' should be true if called
919 from a real cpu write access: the virtual CPU will exit the current
920 TB if code is modified inside this TB. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100921void tb_invalidate_phys_page_range(hwaddr start, hwaddr end,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800922 int is_cpu_write_access)
923{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700924 TranslationBlock *tb, *tb_next, *saved_tb;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100925 CPUOldState *env = cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800926 target_ulong tb_start, tb_end;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700927 PageDesc *p;
928 int n;
929#ifdef TARGET_HAS_PRECISE_SMC
930 int current_tb_not_found = is_cpu_write_access;
931 TranslationBlock *current_tb = NULL;
932 int current_tb_modified = 0;
933 target_ulong current_pc = 0;
934 target_ulong current_cs_base = 0;
935 int current_flags = 0;
936#endif /* TARGET_HAS_PRECISE_SMC */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800937
938 p = page_find(start >> TARGET_PAGE_BITS);
939 if (!p)
940 return;
941 if (!p->code_bitmap &&
942 ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
943 is_cpu_write_access) {
944 /* build code bitmap */
945 build_page_bitmap(p);
946 }
947
948 /* we remove all the TBs in the range [start, end[ */
949 /* 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 -0800950 tb = p->first_tb;
951 while (tb != NULL) {
952 n = (long)tb & 3;
953 tb = (TranslationBlock *)((long)tb & ~3);
954 tb_next = tb->page_next[n];
955 /* NOTE: this is subtle as a TB may span two physical pages */
956 if (n == 0) {
957 /* NOTE: tb_end may be after the end of the page, but
958 it is not a problem */
959 tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
960 tb_end = tb_start + tb->size;
961 } else {
962 tb_start = tb->page_addr[1];
963 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
964 }
965 if (!(tb_end <= start || tb_start >= end)) {
966#ifdef TARGET_HAS_PRECISE_SMC
967 if (current_tb_not_found) {
968 current_tb_not_found = 0;
969 current_tb = NULL;
970 if (env->mem_io_pc) {
971 /* now we have a real cpu fault */
972 current_tb = tb_find_pc(env->mem_io_pc);
973 }
974 }
975 if (current_tb == tb &&
976 (current_tb->cflags & CF_COUNT_MASK) != 1) {
977 /* If we are modifying the current TB, we must stop
978 its execution. We could be more precise by checking
979 that the modification is after the current PC, but it
980 would require a specialized function to partially
981 restore the CPU state */
982
983 current_tb_modified = 1;
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200984 cpu_restore_state(current_tb, env, env->mem_io_pc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700985 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
986 &current_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800987 }
988#endif /* TARGET_HAS_PRECISE_SMC */
989 /* we need to do that to handle the case where a signal
990 occurs while doing tb_phys_invalidate() */
991 saved_tb = NULL;
992 if (env) {
993 saved_tb = env->current_tb;
994 env->current_tb = NULL;
995 }
996 tb_phys_invalidate(tb, -1);
997 if (env) {
998 env->current_tb = saved_tb;
999 if (env->interrupt_request && env->current_tb)
1000 cpu_interrupt(env, env->interrupt_request);
1001 }
1002 }
1003 tb = tb_next;
1004 }
1005#if !defined(CONFIG_USER_ONLY)
1006 /* if no code remaining, no need to continue to use slow writes */
1007 if (!p->first_tb) {
1008 invalidate_page_bitmap(p);
1009 if (is_cpu_write_access) {
1010 tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
1011 }
1012 }
1013#endif
1014#ifdef TARGET_HAS_PRECISE_SMC
1015 if (current_tb_modified) {
1016 /* we generate a block containing just the instruction
1017 modifying the memory. It will ensure that it cannot modify
1018 itself */
1019 env->current_tb = NULL;
1020 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
1021 cpu_resume_from_signal(env, NULL);
1022 }
1023#endif
1024}
1025
1026/* len must be <= 8 and start must be a multiple of len */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001027static inline void tb_invalidate_phys_page_fast(hwaddr start, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001028{
1029 PageDesc *p;
1030 int offset, b;
1031#if 0
1032 if (1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001033 qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
1034 cpu_single_env->mem_io_vaddr, len,
1035 cpu_single_env->eip,
1036 cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001037 }
1038#endif
1039 p = page_find(start >> TARGET_PAGE_BITS);
1040 if (!p)
1041 return;
1042 if (p->code_bitmap) {
1043 offset = start & ~TARGET_PAGE_MASK;
1044 b = p->code_bitmap[offset >> 3] >> (offset & 7);
1045 if (b & ((1 << len) - 1))
1046 goto do_invalidate;
1047 } else {
1048 do_invalidate:
1049 tb_invalidate_phys_page_range(start, start + len, 1);
1050 }
1051}
1052
1053#if !defined(CONFIG_SOFTMMU)
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001054static void tb_invalidate_phys_page(hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001055 unsigned long pc, void *puc)
1056{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001057 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001058 PageDesc *p;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001059 int n;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001060#ifdef TARGET_HAS_PRECISE_SMC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001061 TranslationBlock *current_tb = NULL;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001062 CPUOldState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001063 int current_tb_modified = 0;
1064 target_ulong current_pc = 0;
1065 target_ulong current_cs_base = 0;
1066 int current_flags = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001067#endif
1068
1069 addr &= TARGET_PAGE_MASK;
1070 p = page_find(addr >> TARGET_PAGE_BITS);
1071 if (!p)
1072 return;
1073 tb = p->first_tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001074#ifdef TARGET_HAS_PRECISE_SMC
1075 if (tb && pc != 0) {
1076 current_tb = tb_find_pc(pc);
1077 }
1078#endif
1079 while (tb != NULL) {
1080 n = (long)tb & 3;
1081 tb = (TranslationBlock *)((long)tb & ~3);
1082#ifdef TARGET_HAS_PRECISE_SMC
1083 if (current_tb == tb &&
1084 (current_tb->cflags & CF_COUNT_MASK) != 1) {
1085 /* If we are modifying the current TB, we must stop
1086 its execution. We could be more precise by checking
1087 that the modification is after the current PC, but it
1088 would require a specialized function to partially
1089 restore the CPU state */
1090
1091 current_tb_modified = 1;
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001092 cpu_restore_state(current_tb, env, pc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001093 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
1094 &current_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001095 }
1096#endif /* TARGET_HAS_PRECISE_SMC */
1097 tb_phys_invalidate(tb, addr);
1098 tb = tb->page_next[n];
1099 }
1100 p->first_tb = NULL;
1101#ifdef TARGET_HAS_PRECISE_SMC
1102 if (current_tb_modified) {
1103 /* we generate a block containing just the instruction
1104 modifying the memory. It will ensure that it cannot modify
1105 itself */
1106 env->current_tb = NULL;
1107 tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
1108 cpu_resume_from_signal(env, puc);
1109 }
1110#endif
1111}
1112#endif
1113
1114/* add the tb in the target page and protect it if necessary */
1115static inline void tb_alloc_page(TranslationBlock *tb,
1116 unsigned int n, target_ulong page_addr)
1117{
1118 PageDesc *p;
1119 TranslationBlock *last_first_tb;
1120
1121 tb->page_addr[n] = page_addr;
1122 p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
1123 tb->page_next[n] = p->first_tb;
1124 last_first_tb = p->first_tb;
1125 p->first_tb = (TranslationBlock *)((long)tb | n);
1126 invalidate_page_bitmap(p);
1127
1128#if defined(TARGET_HAS_SMC) || 1
1129
1130#if defined(CONFIG_USER_ONLY)
1131 if (p->flags & PAGE_WRITE) {
1132 target_ulong addr;
1133 PageDesc *p2;
1134 int prot;
1135
1136 /* force the host page as non writable (writes will have a
1137 page fault + mprotect overhead) */
1138 page_addr &= qemu_host_page_mask;
1139 prot = 0;
1140 for(addr = page_addr; addr < page_addr + qemu_host_page_size;
1141 addr += TARGET_PAGE_SIZE) {
1142
1143 p2 = page_find (addr >> TARGET_PAGE_BITS);
1144 if (!p2)
1145 continue;
1146 prot |= p2->flags;
1147 p2->flags &= ~PAGE_WRITE;
1148 page_get_flags(addr);
1149 }
1150 mprotect(g2h(page_addr), qemu_host_page_size,
1151 (prot & PAGE_BITS) & ~PAGE_WRITE);
1152#ifdef DEBUG_TB_INVALIDATE
1153 printf("protecting code page: 0x" TARGET_FMT_lx "\n",
1154 page_addr);
1155#endif
1156 }
1157#else
1158 /* if some code is already present, then the pages are already
1159 protected. So we handle the case where only the first TB is
1160 allocated in a physical page */
1161 if (!last_first_tb) {
1162 tlb_protect_code(page_addr);
1163 }
1164#endif
1165
1166#endif /* TARGET_HAS_SMC */
1167}
1168
1169/* Allocate a new translation block. Flush the translation buffer if
1170 too many translation blocks or too much generated code. */
1171TranslationBlock *tb_alloc(target_ulong pc)
1172{
1173 TranslationBlock *tb;
1174
1175 if (nb_tbs >= code_gen_max_blocks ||
1176 (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
1177 return NULL;
1178 tb = &tbs[nb_tbs++];
1179 tb->pc = pc;
1180 tb->cflags = 0;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001181#ifdef CONFIG_MEMCHECK
1182 tb->tpc2gpc = NULL;
1183 tb->tpc2gpc_pairs = 0;
1184#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001185 return tb;
1186}
1187
1188void tb_free(TranslationBlock *tb)
1189{
1190 /* In practice this is mostly used for single use temporary TB
1191 Ignore the hard cases and just back up if this TB happens to
1192 be the last one generated. */
1193 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
1194 code_gen_ptr = tb->tc_ptr;
1195 nb_tbs--;
1196 }
1197}
1198
1199/* add a new TB and link it to the physical page tables. phys_page2 is
1200 (-1) to indicate that only one page contains the TB. */
1201void tb_link_phys(TranslationBlock *tb,
1202 target_ulong phys_pc, target_ulong phys_page2)
1203{
1204 unsigned int h;
1205 TranslationBlock **ptb;
1206
1207 /* Grab the mmap lock to stop another thread invalidating this TB
1208 before we are done. */
1209 mmap_lock();
1210 /* add in the physical hash table */
1211 h = tb_phys_hash_func(phys_pc);
1212 ptb = &tb_phys_hash[h];
1213 tb->phys_hash_next = *ptb;
1214 *ptb = tb;
1215
1216 /* add in the page list */
1217 tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
1218 if (phys_page2 != -1)
1219 tb_alloc_page(tb, 1, phys_page2);
1220 else
1221 tb->page_addr[1] = -1;
1222
1223 tb->jmp_first = (TranslationBlock *)((long)tb | 2);
1224 tb->jmp_next[0] = NULL;
1225 tb->jmp_next[1] = NULL;
1226
1227 /* init original jump addresses */
1228 if (tb->tb_next_offset[0] != 0xffff)
1229 tb_reset_jump(tb, 0);
1230 if (tb->tb_next_offset[1] != 0xffff)
1231 tb_reset_jump(tb, 1);
1232
1233#ifdef DEBUG_TB_CHECK
1234 tb_page_check();
1235#endif
1236 mmap_unlock();
1237}
1238
1239/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1240 tb[1].tc_ptr. Return NULL if not found */
1241TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1242{
1243 int m_min, m_max, m;
1244 unsigned long v;
1245 TranslationBlock *tb;
1246
1247 if (nb_tbs <= 0)
1248 return NULL;
1249 if (tc_ptr < (unsigned long)code_gen_buffer ||
1250 tc_ptr >= (unsigned long)code_gen_ptr)
1251 return NULL;
1252 /* binary search (cf Knuth) */
1253 m_min = 0;
1254 m_max = nb_tbs - 1;
1255 while (m_min <= m_max) {
1256 m = (m_min + m_max) >> 1;
1257 tb = &tbs[m];
1258 v = (unsigned long)tb->tc_ptr;
1259 if (v == tc_ptr)
1260 return tb;
1261 else if (tc_ptr < v) {
1262 m_max = m - 1;
1263 } else {
1264 m_min = m + 1;
1265 }
1266 }
1267 return &tbs[m_max];
1268}
1269
1270static void tb_reset_jump_recursive(TranslationBlock *tb);
1271
1272static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1273{
1274 TranslationBlock *tb1, *tb_next, **ptb;
1275 unsigned int n1;
1276
1277 tb1 = tb->jmp_next[n];
1278 if (tb1 != NULL) {
1279 /* find head of list */
1280 for(;;) {
1281 n1 = (long)tb1 & 3;
1282 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1283 if (n1 == 2)
1284 break;
1285 tb1 = tb1->jmp_next[n1];
1286 }
1287 /* we are now sure now that tb jumps to tb1 */
1288 tb_next = tb1;
1289
1290 /* remove tb from the jmp_first list */
1291 ptb = &tb_next->jmp_first;
1292 for(;;) {
1293 tb1 = *ptb;
1294 n1 = (long)tb1 & 3;
1295 tb1 = (TranslationBlock *)((long)tb1 & ~3);
1296 if (n1 == n && tb1 == tb)
1297 break;
1298 ptb = &tb1->jmp_next[n1];
1299 }
1300 *ptb = tb->jmp_next[n];
1301 tb->jmp_next[n] = NULL;
1302
1303 /* suppress the jump to next tb in generated code */
1304 tb_reset_jump(tb, n);
1305
1306 /* suppress jumps in the tb on which we could have jumped */
1307 tb_reset_jump_recursive(tb_next);
1308 }
1309}
1310
1311static void tb_reset_jump_recursive(TranslationBlock *tb)
1312{
1313 tb_reset_jump_recursive2(tb, 0);
1314 tb_reset_jump_recursive2(tb, 1);
1315}
1316
1317#if defined(TARGET_HAS_ICE)
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001318static void breakpoint_invalidate(CPUOldState *env, target_ulong pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001319{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001320 hwaddr addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001321 target_ulong pd;
1322 ram_addr_t ram_addr;
1323 PhysPageDesc *p;
1324
1325 addr = cpu_get_phys_page_debug(env, pc);
1326 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1327 if (!p) {
1328 pd = IO_MEM_UNASSIGNED;
1329 } else {
1330 pd = p->phys_offset;
1331 }
1332 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
1333 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
1334}
1335#endif
1336
1337/* Add a watchpoint. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001338int cpu_watchpoint_insert(CPUOldState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001339 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001340{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001341 target_ulong len_mask = ~(len - 1);
1342 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001343
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001344 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
1345 if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
1346 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
1347 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
1348 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001349 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001350 wp = g_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001351
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001352 wp->vaddr = addr;
1353 wp->len_mask = len_mask;
1354 wp->flags = flags;
1355
1356 /* keep all GDB-injected watchpoints in front */
1357 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001358 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001359 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001360 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001361
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001362 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001363
1364 if (watchpoint)
1365 *watchpoint = wp;
1366 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001367}
1368
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001369/* Remove a specific watchpoint. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001370int cpu_watchpoint_remove(CPUOldState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001371 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001372{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001373 target_ulong len_mask = ~(len - 1);
1374 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001375
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001376 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001377 if (addr == wp->vaddr && len_mask == wp->len_mask
1378 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
1379 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001380 return 0;
1381 }
1382 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001383 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001384}
1385
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001386/* Remove a specific watchpoint by reference. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001387void cpu_watchpoint_remove_by_ref(CPUOldState *env, CPUWatchpoint *watchpoint)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001388{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001389 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001390
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001391 tlb_flush_page(env, watchpoint->vaddr);
1392
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001393 g_free(watchpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001394}
1395
1396/* Remove all matching watchpoints. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001397void cpu_watchpoint_remove_all(CPUOldState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001398{
1399 CPUWatchpoint *wp, *next;
1400
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001401 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001402 if (wp->flags & mask)
1403 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001404 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001405}
1406
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001407/* Add a breakpoint. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001408int cpu_breakpoint_insert(CPUOldState *env, target_ulong pc, int flags,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001409 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001410{
1411#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001412 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001413
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001414 bp = g_malloc(sizeof(*bp));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001415
1416 bp->pc = pc;
1417 bp->flags = flags;
1418
1419 /* keep all GDB-injected breakpoints in front */
1420 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001421 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001422 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001423 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001424
1425 breakpoint_invalidate(env, pc);
1426
1427 if (breakpoint)
1428 *breakpoint = bp;
1429 return 0;
1430#else
1431 return -ENOSYS;
1432#endif
1433}
1434
1435/* Remove a specific breakpoint. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001436int cpu_breakpoint_remove(CPUOldState *env, target_ulong pc, int flags)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001437{
1438#if defined(TARGET_HAS_ICE)
1439 CPUBreakpoint *bp;
1440
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001441 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001442 if (bp->pc == pc && bp->flags == flags) {
1443 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001444 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001445 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001446 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001447 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001448#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001449 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001450#endif
1451}
1452
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001453/* Remove a specific breakpoint by reference. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001454void cpu_breakpoint_remove_by_ref(CPUOldState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001455{
1456#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001457 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001458
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001459 breakpoint_invalidate(env, breakpoint->pc);
1460
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001461 g_free(breakpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001462#endif
1463}
1464
1465/* Remove all matching breakpoints. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001466void cpu_breakpoint_remove_all(CPUOldState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001467{
1468#if defined(TARGET_HAS_ICE)
1469 CPUBreakpoint *bp, *next;
1470
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001471 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001472 if (bp->flags & mask)
1473 cpu_breakpoint_remove_by_ref(env, bp);
1474 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001475#endif
1476}
1477
1478/* enable or disable single step mode. EXCP_DEBUG is returned by the
1479 CPU loop after each instruction */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001480void cpu_single_step(CPUOldState *env, int enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001481{
1482#if defined(TARGET_HAS_ICE)
1483 if (env->singlestep_enabled != enabled) {
1484 env->singlestep_enabled = enabled;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001485 if (kvm_enabled())
1486 kvm_update_guest_debug(env, 0);
1487 else {
1488 /* must flush all the translated code to avoid inconsistencies */
1489 /* XXX: only flush what is necessary */
1490 tb_flush(env);
1491 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001492 }
1493#endif
1494}
1495
1496/* enable or disable low levels log */
1497void cpu_set_log(int log_flags)
1498{
1499 loglevel = log_flags;
1500 if (loglevel && !logfile) {
1501 logfile = fopen(logfilename, log_append ? "a" : "w");
1502 if (!logfile) {
1503 perror(logfilename);
Iliyan Malchev4a2c9dd2012-04-02 08:20:56 -07001504 exit(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001505 }
1506#if !defined(CONFIG_SOFTMMU)
1507 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1508 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001509 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001510 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1511 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001512#elif !defined(_WIN32)
1513 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001514 setvbuf(logfile, NULL, _IOLBF, 0);
1515#endif
1516 log_append = 1;
1517 }
1518 if (!loglevel && logfile) {
1519 fclose(logfile);
1520 logfile = NULL;
1521 }
1522}
1523
1524void cpu_set_log_filename(const char *filename)
1525{
1526 logfilename = strdup(filename);
1527 if (logfile) {
1528 fclose(logfile);
1529 logfile = NULL;
1530 }
1531 cpu_set_log(loglevel);
1532}
1533
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001534static void cpu_unlink_tb(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001535{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001536 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
1537 problem and hope the cpu will stop of its own accord. For userspace
1538 emulation this often isn't actually as bad as it sounds. Often
1539 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001540 TranslationBlock *tb;
1541 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
1542
David 'Digit' Turner795bb192011-05-09 15:20:22 +02001543 spin_lock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001544 tb = env->current_tb;
1545 /* if the cpu is currently executing code, we must unlink it and
1546 all the potentially executing TB */
David 'Digit' Turner795bb192011-05-09 15:20:22 +02001547 if (tb) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001548 env->current_tb = NULL;
1549 tb_reset_jump_recursive(tb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001550 }
David 'Digit' Turner795bb192011-05-09 15:20:22 +02001551 spin_unlock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001552}
1553
1554/* mask must never be zero, except for A20 change call */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001555void cpu_interrupt(CPUOldState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001556{
1557 int old_mask;
1558
1559 old_mask = env->interrupt_request;
1560 env->interrupt_request |= mask;
1561
1562#ifndef CONFIG_USER_ONLY
1563 /*
1564 * If called from iothread context, wake the target cpu in
1565 * case its halted.
1566 */
1567 if (!qemu_cpu_self(env)) {
1568 qemu_cpu_kick(env);
1569 return;
1570 }
1571#endif
1572
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001573 if (use_icount) {
1574 env->icount_decr.u16.high = 0xffff;
1575#ifndef CONFIG_USER_ONLY
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001576 if (!can_do_io(env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001577 && (mask & ~old_mask) != 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001578 cpu_abort(env, "Raised interrupt while not in I/O function");
1579 }
1580#endif
1581 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001582 cpu_unlink_tb(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001583 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001584}
1585
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001586void cpu_reset_interrupt(CPUOldState *env, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001587{
1588 env->interrupt_request &= ~mask;
1589}
1590
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001591void cpu_exit(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001592{
1593 env->exit_request = 1;
1594 cpu_unlink_tb(env);
1595}
1596
1597const CPULogItem cpu_log_items[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001598 { CPU_LOG_TB_OUT_ASM, "out_asm",
1599 "show generated host assembly code for each compiled TB" },
1600 { CPU_LOG_TB_IN_ASM, "in_asm",
1601 "show target assembly code for each compiled TB" },
1602 { CPU_LOG_TB_OP, "op",
1603 "show micro ops for each compiled TB" },
1604 { CPU_LOG_TB_OP_OPT, "op_opt",
1605 "show micro ops "
1606#ifdef TARGET_I386
1607 "before eflags optimization and "
1608#endif
1609 "after liveness analysis" },
1610 { CPU_LOG_INT, "int",
1611 "show interrupts/exceptions in short format" },
1612 { CPU_LOG_EXEC, "exec",
1613 "show trace before each executed TB (lots of logs)" },
1614 { CPU_LOG_TB_CPU, "cpu",
1615 "show CPU state before block translation" },
1616#ifdef TARGET_I386
1617 { CPU_LOG_PCALL, "pcall",
1618 "show protected mode far calls/returns/exceptions" },
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001619 { CPU_LOG_RESET, "cpu_reset",
1620 "show CPU state before CPU resets" },
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001621#endif
1622#ifdef DEBUG_IOPORT
1623 { CPU_LOG_IOPORT, "ioport",
1624 "show all i/o ports accesses" },
1625#endif
1626 { 0, NULL, NULL },
1627};
1628
1629static int cmp1(const char *s1, int n, const char *s2)
1630{
1631 if (strlen(s2) != n)
1632 return 0;
1633 return memcmp(s1, s2, n) == 0;
1634}
1635
1636/* takes a comma separated list of log masks. Return 0 if error. */
1637int cpu_str_to_log_mask(const char *str)
1638{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001639 const CPULogItem *item;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001640 int mask;
1641 const char *p, *p1;
1642
1643 p = str;
1644 mask = 0;
1645 for(;;) {
1646 p1 = strchr(p, ',');
1647 if (!p1)
1648 p1 = p + strlen(p);
1649 if(cmp1(p,p1-p,"all")) {
1650 for(item = cpu_log_items; item->mask != 0; item++) {
1651 mask |= item->mask;
1652 }
1653 } else {
1654 for(item = cpu_log_items; item->mask != 0; item++) {
1655 if (cmp1(p, p1 - p, item->name))
1656 goto found;
1657 }
1658 return 0;
1659 }
1660 found:
1661 mask |= item->mask;
1662 if (*p1 != ',')
1663 break;
1664 p = p1 + 1;
1665 }
1666 return mask;
1667}
1668
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001669void cpu_abort(CPUOldState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001670{
1671 va_list ap;
1672 va_list ap2;
1673
1674 va_start(ap, fmt);
1675 va_copy(ap2, ap);
1676 fprintf(stderr, "qemu: fatal: ");
1677 vfprintf(stderr, fmt, ap);
1678 fprintf(stderr, "\n");
1679#ifdef TARGET_I386
1680 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1681#else
1682 cpu_dump_state(env, stderr, fprintf, 0);
1683#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001684 if (qemu_log_enabled()) {
1685 qemu_log("qemu: fatal: ");
1686 qemu_log_vprintf(fmt, ap2);
1687 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001688#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001689 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001690#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001691 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001692#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001693 qemu_log_flush();
1694 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001695 }
1696 va_end(ap2);
1697 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +01001698#if defined(CONFIG_USER_ONLY)
1699 {
1700 struct sigaction act;
1701 sigfillset(&act.sa_mask);
1702 act.sa_handler = SIG_DFL;
1703 sigaction(SIGABRT, &act, NULL);
1704 }
1705#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001706 abort();
1707}
1708
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001709CPUOldState *cpu_copy(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001710{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001711 CPUOldState *new_env = cpu_init(env->cpu_model_str);
1712 CPUOldState *next_cpu = new_env->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001713 int cpu_index = new_env->cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001714#if defined(TARGET_HAS_ICE)
1715 CPUBreakpoint *bp;
1716 CPUWatchpoint *wp;
1717#endif
1718
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001719 memcpy(new_env, env, sizeof(CPUOldState));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001720
1721 /* Preserve chaining and index. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001722 new_env->next_cpu = next_cpu;
1723 new_env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001724
1725 /* Clone all break/watchpoints.
1726 Note: Once we support ptrace with hw-debug register access, make sure
1727 BP_CPU break/watchpoints are handled correctly on clone. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001728 QTAILQ_INIT(&env->breakpoints);
1729 QTAILQ_INIT(&env->watchpoints);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001730#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001731 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001732 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
1733 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001734 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001735 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
1736 wp->flags, NULL);
1737 }
1738#endif
1739
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001740 return new_env;
1741}
1742
1743#if !defined(CONFIG_USER_ONLY)
1744
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001745/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001746void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
1747 int dirty_flags)
1748{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001749 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001750 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001751 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001752
1753 start &= TARGET_PAGE_MASK;
1754 end = TARGET_PAGE_ALIGN(end);
1755
1756 length = end - start;
1757 if (length == 0)
1758 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001759 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001760
1761 /* we modify the TLB cache so that the dirty bit will be set again
1762 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001763 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001764 /* Chek that we don't span multiple blocks - this breaks the
1765 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001766 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001767 != (end - 1) - start) {
1768 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001769 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001770
1771 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1772 int mmu_idx;
1773 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
1774 for(i = 0; i < CPU_TLB_SIZE; i++)
1775 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
1776 start1, length);
1777 }
1778 }
1779}
1780
1781int cpu_physical_memory_set_dirty_tracking(int enable)
1782{
1783 in_migration = enable;
1784 if (kvm_enabled()) {
1785 return kvm_set_migration_log(enable);
1786 }
1787 return 0;
1788}
1789
1790int cpu_physical_memory_get_dirty_tracking(void)
1791{
1792 return in_migration;
1793}
1794
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001795int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
1796 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001797{
1798 int ret = 0;
1799
1800 if (kvm_enabled())
1801 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
1802 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001803}
1804
1805static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1806{
1807 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001808 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001809
1810 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001811 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
1812 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001813 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001814 if (!cpu_physical_memory_is_dirty(ram_addr)) {
1815 tlb_entry->addr_write |= TLB_NOTDIRTY;
1816 }
1817 }
1818}
1819
1820/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001821void cpu_tlb_update_dirty(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001822{
1823 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001824 int mmu_idx;
1825 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
1826 for(i = 0; i < CPU_TLB_SIZE; i++)
1827 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
1828 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001829}
1830
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001831
1832#else
1833
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001834void tlb_flush(CPUOldState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001835{
1836}
1837
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001838void tlb_flush_page(CPUOldState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001839{
1840}
1841
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001842int tlb_set_page_exec(CPUOldState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001843 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001844 int mmu_idx, int is_softmmu)
1845{
1846 return 0;
1847}
1848
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001849/*
1850 * Walks guest process memory "regions" one by one
1851 * and calls callback function 'fn' for each region.
1852 */
1853int walk_memory_regions(void *priv,
1854 int (*fn)(void *, unsigned long, unsigned long, unsigned long))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001855{
1856 unsigned long start, end;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001857 PageDesc *p = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001858 int i, j, prot, prot1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001859 int rc = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001860
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001861 start = end = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001862 prot = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001863
1864 for (i = 0; i <= L1_SIZE; i++) {
1865 p = (i < L1_SIZE) ? l1_map[i] : NULL;
1866 for (j = 0; j < L2_SIZE; j++) {
1867 prot1 = (p == NULL) ? 0 : p[j].flags;
1868 /*
1869 * "region" is one continuous chunk of memory
1870 * that has same protection flags set.
1871 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001872 if (prot1 != prot) {
1873 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1874 if (start != -1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001875 rc = (*fn)(priv, start, end, prot);
1876 /* callback can stop iteration by returning != 0 */
1877 if (rc != 0)
1878 return (rc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001879 }
1880 if (prot1 != 0)
1881 start = end;
1882 else
1883 start = -1;
1884 prot = prot1;
1885 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001886 if (p == NULL)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001887 break;
1888 }
1889 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001890 return (rc);
1891}
1892
1893static int dump_region(void *priv, unsigned long start,
1894 unsigned long end, unsigned long prot)
1895{
1896 FILE *f = (FILE *)priv;
1897
1898 (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1899 start, end, end - start,
1900 ((prot & PAGE_READ) ? 'r' : '-'),
1901 ((prot & PAGE_WRITE) ? 'w' : '-'),
1902 ((prot & PAGE_EXEC) ? 'x' : '-'));
1903
1904 return (0);
1905}
1906
1907/* dump memory mappings */
1908void page_dump(FILE *f)
1909{
1910 (void) fprintf(f, "%-8s %-8s %-8s %s\n",
1911 "start", "end", "size", "prot");
1912 walk_memory_regions(f, dump_region);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001913}
1914
1915int page_get_flags(target_ulong address)
1916{
1917 PageDesc *p;
1918
1919 p = page_find(address >> TARGET_PAGE_BITS);
1920 if (!p)
1921 return 0;
1922 return p->flags;
1923}
1924
David 'Digit' Turner36411062010-12-22 17:34:53 +01001925/* Modify the flags of a page and invalidate the code if necessary.
1926 The flag PAGE_WRITE_ORG is positioned automatically depending
1927 on PAGE_WRITE. The mmap_lock should already be held. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001928void page_set_flags(target_ulong start, target_ulong end, int flags)
1929{
1930 PageDesc *p;
1931 target_ulong addr;
1932
1933 /* mmap_lock should already be held. */
1934 start = start & TARGET_PAGE_MASK;
1935 end = TARGET_PAGE_ALIGN(end);
1936 if (flags & PAGE_WRITE)
1937 flags |= PAGE_WRITE_ORG;
1938 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1939 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1940 /* We may be called for host regions that are outside guest
1941 address space. */
1942 if (!p)
1943 return;
1944 /* if the write protection is set, then we invalidate the code
1945 inside */
1946 if (!(p->flags & PAGE_WRITE) &&
1947 (flags & PAGE_WRITE) &&
1948 p->first_tb) {
1949 tb_invalidate_phys_page(addr, 0, NULL);
1950 }
1951 p->flags = flags;
1952 }
1953}
1954
1955int page_check_range(target_ulong start, target_ulong len, int flags)
1956{
1957 PageDesc *p;
1958 target_ulong end;
1959 target_ulong addr;
1960
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001961 if (start + len < start)
1962 /* we've wrapped around */
1963 return -1;
1964
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001965 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
1966 start = start & TARGET_PAGE_MASK;
1967
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001968 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1969 p = page_find(addr >> TARGET_PAGE_BITS);
1970 if( !p )
1971 return -1;
1972 if( !(p->flags & PAGE_VALID) )
1973 return -1;
1974
1975 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
1976 return -1;
1977 if (flags & PAGE_WRITE) {
1978 if (!(p->flags & PAGE_WRITE_ORG))
1979 return -1;
1980 /* unprotect the page if it was put read-only because it
1981 contains translated code */
1982 if (!(p->flags & PAGE_WRITE)) {
1983 if (!page_unprotect(addr, 0, NULL))
1984 return -1;
1985 }
1986 return 0;
1987 }
1988 }
1989 return 0;
1990}
1991
1992/* called from signal handler: invalidate the code and unprotect the
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001993 page. Return TRUE if the fault was successfully handled. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001994int page_unprotect(target_ulong address, unsigned long pc, void *puc)
1995{
1996 unsigned int page_index, prot, pindex;
1997 PageDesc *p, *p1;
1998 target_ulong host_start, host_end, addr;
1999
2000 /* Technically this isn't safe inside a signal handler. However we
2001 know this only ever happens in a synchronous SEGV handler, so in
2002 practice it seems to be ok. */
2003 mmap_lock();
2004
2005 host_start = address & qemu_host_page_mask;
2006 page_index = host_start >> TARGET_PAGE_BITS;
2007 p1 = page_find(page_index);
2008 if (!p1) {
2009 mmap_unlock();
2010 return 0;
2011 }
2012 host_end = host_start + qemu_host_page_size;
2013 p = p1;
2014 prot = 0;
2015 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
2016 prot |= p->flags;
2017 p++;
2018 }
2019 /* if the page was really writable, then we change its
2020 protection back to writable */
2021 if (prot & PAGE_WRITE_ORG) {
2022 pindex = (address - host_start) >> TARGET_PAGE_BITS;
2023 if (!(p1[pindex].flags & PAGE_WRITE)) {
2024 mprotect((void *)g2h(host_start), qemu_host_page_size,
2025 (prot & PAGE_BITS) | PAGE_WRITE);
2026 p1[pindex].flags |= PAGE_WRITE;
2027 /* and since the content will be modified, we must invalidate
2028 the corresponding translated code. */
2029 tb_invalidate_phys_page(address, pc, puc);
2030#ifdef DEBUG_TB_CHECK
2031 tb_invalidate_check(address);
2032#endif
2033 mmap_unlock();
2034 return 1;
2035 }
2036 }
2037 mmap_unlock();
2038 return 0;
2039}
2040
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002041static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002042 unsigned long addr, target_ulong vaddr)
2043{
2044}
2045#endif /* defined(CONFIG_USER_ONLY) */
2046
2047#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002048
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002049static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002050 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002051static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002052 ram_addr_t orig_memory, ram_addr_t region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002053#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
2054 need_subpage) \
2055 do { \
2056 if (addr > start_addr) \
2057 start_addr2 = 0; \
2058 else { \
2059 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
2060 if (start_addr2 > 0) \
2061 need_subpage = 1; \
2062 } \
2063 \
2064 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
2065 end_addr2 = TARGET_PAGE_SIZE - 1; \
2066 else { \
2067 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
2068 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
2069 need_subpage = 1; \
2070 } \
2071 } while (0)
2072
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002073/* register physical memory.
2074 For RAM, 'size' must be a multiple of the target page size.
2075 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002076 io memory page. The address used when calling the IO function is
2077 the offset from the start of the region, plus region_offset. Both
2078 start_addr and region_offset are rounded down to a page boundary
2079 before calculating this offset. This should not be a problem unless
2080 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002081void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002082 ram_addr_t size,
2083 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002084 ram_addr_t region_offset,
2085 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002086{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002087 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002088 PhysPageDesc *p;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002089 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002090 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002091 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002092
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002093 if (kvm_enabled())
2094 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -08002095#ifdef CONFIG_HAX
2096 if (hax_enabled())
2097 hax_set_phys_mem(start_addr, size, phys_offset);
2098#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002099
2100 if (phys_offset == IO_MEM_UNASSIGNED) {
2101 region_offset = start_addr;
2102 }
2103 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002104 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002105 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002106
2107 addr = start_addr;
2108 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002109 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2110 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
2111 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002112 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002113 int need_subpage = 0;
2114
2115 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
2116 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002117 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002118 if (!(orig_memory & IO_MEM_SUBPAGE)) {
2119 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002120 &p->phys_offset, orig_memory,
2121 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002122 } else {
2123 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
2124 >> IO_MEM_SHIFT];
2125 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002126 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
2127 region_offset);
2128 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002129 } else {
2130 p->phys_offset = phys_offset;
2131 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
2132 (phys_offset & IO_MEM_ROMD))
2133 phys_offset += TARGET_PAGE_SIZE;
2134 }
2135 } else {
2136 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
2137 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002138 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002139 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002140 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002141 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002142 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002143 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002144 int need_subpage = 0;
2145
2146 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
2147 end_addr2, need_subpage);
2148
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002149 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002150 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002151 &p->phys_offset, IO_MEM_UNASSIGNED,
2152 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002153 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002154 phys_offset, region_offset);
2155 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002156 }
2157 }
2158 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002159 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002160 addr += TARGET_PAGE_SIZE;
2161 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002162
2163 /* since each CPU stores ram addresses in its TLB cache, we must
2164 reset the modified entries */
2165 /* XXX: slow ! */
2166 for(env = first_cpu; env != NULL; env = env->next_cpu) {
2167 tlb_flush(env, 1);
2168 }
2169}
2170
2171/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002172ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002173{
2174 PhysPageDesc *p;
2175
2176 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2177 if (!p)
2178 return IO_MEM_UNASSIGNED;
2179 return p->phys_offset;
2180}
2181
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002182void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002183{
2184 if (kvm_enabled())
2185 kvm_coalesce_mmio_region(addr, size);
2186}
2187
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002188void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002189{
2190 if (kvm_enabled())
2191 kvm_uncoalesce_mmio_region(addr, size);
2192}
2193
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002194static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002195{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002196 RAMBlock *block, *next_block;
2197 ram_addr_t offset = 0, mingap = ULONG_MAX;
2198
2199 if (QLIST_EMPTY(&ram_list.blocks))
2200 return 0;
2201
2202 QLIST_FOREACH(block, &ram_list.blocks, next) {
2203 ram_addr_t end, next = ULONG_MAX;
2204
2205 end = block->offset + block->length;
2206
2207 QLIST_FOREACH(next_block, &ram_list.blocks, next) {
2208 if (next_block->offset >= end) {
2209 next = MIN(next, next_block->offset);
2210 }
2211 }
2212 if (next - end >= size && next - end < mingap) {
2213 offset = end;
2214 mingap = next - end;
2215 }
2216 }
2217 return offset;
2218}
2219
2220static ram_addr_t last_ram_offset(void)
2221{
2222 RAMBlock *block;
2223 ram_addr_t last = 0;
2224
2225 QLIST_FOREACH(block, &ram_list.blocks, next)
2226 last = MAX(last, block->offset + block->length);
2227
2228 return last;
2229}
2230
2231ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
2232 ram_addr_t size, void *host)
2233{
2234 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002235
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002236 size = TARGET_PAGE_ALIGN(size);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002237 new_block = g_malloc0(sizeof(*new_block));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002238
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002239#if 0
2240 if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
2241 char *id = dev->parent_bus->info->get_dev_path(dev);
2242 if (id) {
2243 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002244 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002245 }
2246 }
2247#endif
2248 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
2249
2250 QLIST_FOREACH(block, &ram_list.blocks, next) {
2251 if (!strcmp(block->idstr, new_block->idstr)) {
2252 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
2253 new_block->idstr);
2254 abort();
2255 }
2256 }
2257
2258 if (host) {
2259 new_block->host = host;
2260 new_block->flags |= RAM_PREALLOC_MASK;
2261 } else {
2262 if (mem_path) {
2263#if 0 && defined (__linux__) && !defined(TARGET_S390X)
2264 new_block->host = file_ram_alloc(new_block, size, mem_path);
2265 if (!new_block->host) {
2266 new_block->host = qemu_vmalloc(size);
2267 qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
2268 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002269#else
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002270 fprintf(stderr, "-mem-path option unsupported\n");
2271 exit(1);
2272#endif
2273 } else {
2274#if defined(TARGET_S390X) && defined(CONFIG_KVM)
2275 /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
2276 new_block->host = mmap((void*)0x1000000, size,
2277 PROT_EXEC|PROT_READ|PROT_WRITE,
2278 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2279#else
2280 new_block->host = qemu_vmalloc(size);
Jun Nakajimaa381ef02011-12-17 19:13:25 -08002281
2282#ifdef CONFIG_HAX
2283 /*
2284 * In HAX, qemu allocates the virtual address, and HAX kernel
2285 * module populates the region with physical memory. Currently
2286 * we don’t populate guest memory on demand, thus we should
2287 * make sure that sufficient amount of memory is available in
2288 * advance.
2289 */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002290 if (hax_enabled()) {
2291 int ret = hax_populate_ram(
2292 (uint64_t)(uintptr_t)new_block->host,
2293 size);
2294 if (ret < 0) {
Jun Nakajimaa381ef02011-12-17 19:13:25 -08002295 fprintf(stderr, "Hax failed to populate ram\n");
2296 exit(-1);
2297 }
2298 }
2299#endif
2300
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002301#endif
2302#ifdef MADV_MERGEABLE
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002303 madvise(new_block->host, size, MADV_MERGEABLE);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002304#endif
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002305 }
2306 }
2307
2308 new_block->offset = find_ram_offset(size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002309 new_block->length = size;
2310
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002311 QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002312
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002313 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002314 last_ram_offset() >> TARGET_PAGE_BITS);
2315 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002316 0xff, size >> TARGET_PAGE_BITS);
2317
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002318 if (kvm_enabled())
2319 kvm_setup_guest_memory(new_block->host, size);
2320
2321 return new_block->offset;
2322}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002323
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002324ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
2325{
2326 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
2327}
2328
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002329void qemu_ram_free(ram_addr_t addr)
2330{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002331 RAMBlock *block;
2332
2333 QLIST_FOREACH(block, &ram_list.blocks, next) {
2334 if (addr == block->offset) {
2335 QLIST_REMOVE(block, next);
2336 if (block->flags & RAM_PREALLOC_MASK) {
2337 ;
2338 } else if (mem_path) {
2339#if defined (__linux__) && !defined(TARGET_S390X)
2340 if (block->fd) {
2341 munmap(block->host, block->length);
2342 close(block->fd);
2343 } else {
2344 qemu_vfree(block->host);
2345 }
2346#else
2347 abort();
2348#endif
2349 } else {
2350#if defined(TARGET_S390X) && defined(CONFIG_KVM)
2351 munmap(block->host, block->length);
2352#else
2353 qemu_vfree(block->host);
2354#endif
2355 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002356 g_free(block);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002357 return;
2358 }
2359 }
2360
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002361}
2362
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002363#ifndef _WIN32
2364void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
2365{
2366#ifndef CONFIG_ANDROID
2367 RAMBlock *block;
2368 ram_addr_t offset;
2369 int flags;
2370 void *area, *vaddr;
2371
2372 QLIST_FOREACH(block, &ram_list.blocks, next) {
2373 offset = addr - block->offset;
2374 if (offset < block->length) {
2375 vaddr = block->host + offset;
2376 if (block->flags & RAM_PREALLOC_MASK) {
2377 ;
2378 } else {
2379 flags = MAP_FIXED;
2380 munmap(vaddr, length);
2381 if (mem_path) {
2382#if defined(__linux__) && !defined(TARGET_S390X)
2383 if (block->fd) {
2384#ifdef MAP_POPULATE
2385 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
2386 MAP_PRIVATE;
2387#else
2388 flags |= MAP_PRIVATE;
2389#endif
2390 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
2391 flags, block->fd, offset);
2392 } else {
2393 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
2394 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
2395 flags, -1, 0);
2396 }
2397#else
2398 abort();
2399#endif
2400 } else {
2401#if defined(TARGET_S390X) && defined(CONFIG_KVM)
2402 flags |= MAP_SHARED | MAP_ANONYMOUS;
2403 area = mmap(vaddr, length, PROT_EXEC|PROT_READ|PROT_WRITE,
2404 flags, -1, 0);
2405#else
2406 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
2407 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
2408 flags, -1, 0);
2409#endif
2410 }
2411 if (area != vaddr) {
2412 fprintf(stderr, "Could not remap addr: %lx@%lx\n",
2413 length, addr);
2414 exit(1);
2415 }
2416 qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
2417 }
2418 return;
2419 }
2420 }
2421#endif /* !CONFIG_ANDROID */
2422}
2423#endif /* !_WIN32 */
2424
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002425/* Return a host pointer to ram allocated with qemu_ram_alloc.
2426 With the exception of the softmmu code in this file, this should
2427 only be used for local memory (e.g. video ram) that the device owns,
2428 and knows it isn't going to access beyond the end of the block.
2429
2430 It should not be used for general purpose DMA.
2431 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
2432 */
2433void *qemu_get_ram_ptr(ram_addr_t addr)
2434{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002435 RAMBlock *block;
2436
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002437 QLIST_FOREACH(block, &ram_list.blocks, next) {
2438 if (addr - block->offset < block->length) {
2439 /* Move this entry to to start of the list. */
2440 if (block != QLIST_FIRST(&ram_list.blocks)) {
2441 QLIST_REMOVE(block, next);
2442 QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002443 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002444 return block->host + (addr - block->offset);
2445 }
2446 }
2447
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002448 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
2449 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002450
2451 return NULL;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002452 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002453
2454/* Return a host pointer to ram allocated with qemu_ram_alloc.
2455 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
2456 */
2457void *qemu_safe_ram_ptr(ram_addr_t addr)
2458{
2459 RAMBlock *block;
2460
2461 QLIST_FOREACH(block, &ram_list.blocks, next) {
2462 if (addr - block->offset < block->length) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002463 return block->host + (addr - block->offset);
2464}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002465 }
2466
2467 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
2468 abort();
2469
2470 return NULL;
2471}
2472
2473int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
2474{
2475 RAMBlock *block;
2476 uint8_t *host = ptr;
2477
2478 QLIST_FOREACH(block, &ram_list.blocks, next) {
2479 if (host - block->host < block->length) {
2480 *ram_addr = block->offset + (host - block->host);
2481 return 0;
2482 }
2483 }
2484 return -1;
2485}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002486
2487/* Some of the softmmu routines need to translate from a host pointer
2488 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002489ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002490{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002491 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002492
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002493 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002494 fprintf(stderr, "Bad ram pointer %p\n", ptr);
2495 abort();
2496 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002497 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002498}
2499
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002500static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002501{
2502#ifdef DEBUG_UNASSIGNED
2503 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2504#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002505#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002506 do_unassigned_access(addr, 0, 0, 0, 1);
2507#endif
2508 return 0;
2509}
2510
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002511static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002512{
2513#ifdef DEBUG_UNASSIGNED
2514 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2515#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002516#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002517 do_unassigned_access(addr, 0, 0, 0, 2);
2518#endif
2519 return 0;
2520}
2521
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002522static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002523{
2524#ifdef DEBUG_UNASSIGNED
2525 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
2526#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002527#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002528 do_unassigned_access(addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002529#endif
2530 return 0;
2531}
2532
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002533static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002534{
2535#ifdef DEBUG_UNASSIGNED
2536 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2537#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002538#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002539 do_unassigned_access(addr, 1, 0, 0, 1);
2540#endif
2541}
2542
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002543static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002544{
2545#ifdef DEBUG_UNASSIGNED
2546 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2547#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002548#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002549 do_unassigned_access(addr, 1, 0, 0, 2);
2550#endif
2551}
2552
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002553static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002554{
2555#ifdef DEBUG_UNASSIGNED
2556 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
2557#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002558#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002559 do_unassigned_access(addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002560#endif
2561}
2562
David 'Digit' Turner36411062010-12-22 17:34:53 +01002563static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002564 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002565 unassigned_mem_readw,
2566 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002567};
2568
David 'Digit' Turner36411062010-12-22 17:34:53 +01002569static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002570 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002571 unassigned_mem_writew,
2572 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002573};
2574
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002575static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002576 uint32_t val)
2577{
2578 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002579 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002580 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2581#if !defined(CONFIG_USER_ONLY)
2582 tb_invalidate_phys_page_fast(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002583 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002584#endif
2585 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002586 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002587 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002588 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002589 /* we remove the notdirty callback only if the code has been
2590 flushed */
2591 if (dirty_flags == 0xff)
2592 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2593}
2594
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002595static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002596 uint32_t val)
2597{
2598 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002599 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002600 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2601#if !defined(CONFIG_USER_ONLY)
2602 tb_invalidate_phys_page_fast(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002603 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002604#endif
2605 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002606 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002607 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002608 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002609 /* we remove the notdirty callback only if the code has been
2610 flushed */
2611 if (dirty_flags == 0xff)
2612 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2613}
2614
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002615static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002616 uint32_t val)
2617{
2618 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002619 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002620 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2621#if !defined(CONFIG_USER_ONLY)
2622 tb_invalidate_phys_page_fast(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002623 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002624#endif
2625 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002626 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002627 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002628 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002629 /* we remove the notdirty callback only if the code has been
2630 flushed */
2631 if (dirty_flags == 0xff)
2632 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
2633}
2634
David 'Digit' Turner36411062010-12-22 17:34:53 +01002635static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002636 NULL, /* never used */
2637 NULL, /* never used */
2638 NULL, /* never used */
2639};
2640
David 'Digit' Turner36411062010-12-22 17:34:53 +01002641static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002642 notdirty_mem_writeb,
2643 notdirty_mem_writew,
2644 notdirty_mem_writel,
2645};
2646
2647/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002648static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002649{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002650 CPUOldState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002651 target_ulong pc, cs_base;
2652 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002653 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002654 CPUWatchpoint *wp;
2655 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002656
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002657 if (env->watchpoint_hit) {
2658 /* We re-entered the check after replacing the TB. Now raise
2659 * the debug interrupt so that is will trigger after the
2660 * current instruction. */
2661 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2662 return;
2663 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002664 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002665 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002666 if ((vaddr == (wp->vaddr & len_mask) ||
2667 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
2668 wp->flags |= BP_WATCHPOINT_HIT;
2669 if (!env->watchpoint_hit) {
2670 env->watchpoint_hit = wp;
2671 tb = tb_find_pc(env->mem_io_pc);
2672 if (!tb) {
2673 cpu_abort(env, "check_watchpoint: could not find TB for "
2674 "pc=%p", (void *)env->mem_io_pc);
2675 }
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02002676 cpu_restore_state(tb, env, env->mem_io_pc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002677 tb_phys_invalidate(tb, -1);
2678 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
2679 env->exception_index = EXCP_DEBUG;
2680 } else {
2681 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
2682 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
2683 }
2684 cpu_resume_from_signal(env, NULL);
2685 }
2686 } else {
2687 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002688 }
2689 }
2690}
2691
2692/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
2693 so these check for a hit then pass through to the normal out-of-line
2694 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002695static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002696{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002697 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002698 return ldub_phys(addr);
2699}
2700
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002701static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002702{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002703 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002704 return lduw_phys(addr);
2705}
2706
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002707static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002708{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002709 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002710 return ldl_phys(addr);
2711}
2712
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002713static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002714 uint32_t val)
2715{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002716 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002717 stb_phys(addr, val);
2718}
2719
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002720static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002721 uint32_t val)
2722{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002723 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002724 stw_phys(addr, val);
2725}
2726
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002727static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002728 uint32_t val)
2729{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002730 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002731 stl_phys(addr, val);
2732}
2733
David 'Digit' Turner36411062010-12-22 17:34:53 +01002734static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002735 watch_mem_readb,
2736 watch_mem_readw,
2737 watch_mem_readl,
2738};
2739
David 'Digit' Turner36411062010-12-22 17:34:53 +01002740static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002741 watch_mem_writeb,
2742 watch_mem_writew,
2743 watch_mem_writel,
2744};
2745
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002746static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002747 unsigned int len)
2748{
2749 uint32_t ret;
2750 unsigned int idx;
2751
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002752 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002753#if defined(DEBUG_SUBPAGE)
2754 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
2755 mmio, len, addr, idx);
2756#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002757 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
2758 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002759
2760 return ret;
2761}
2762
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002763static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002764 uint32_t value, unsigned int len)
2765{
2766 unsigned int idx;
2767
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002768 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002769#if defined(DEBUG_SUBPAGE)
2770 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
2771 mmio, len, addr, idx, value);
2772#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002773 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
2774 addr + mmio->region_offset[idx][1][len],
2775 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002776}
2777
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002778static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002779{
2780#if defined(DEBUG_SUBPAGE)
2781 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2782#endif
2783
2784 return subpage_readlen(opaque, addr, 0);
2785}
2786
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002787static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002788 uint32_t value)
2789{
2790#if defined(DEBUG_SUBPAGE)
2791 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2792#endif
2793 subpage_writelen(opaque, addr, value, 0);
2794}
2795
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002796static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002797{
2798#if defined(DEBUG_SUBPAGE)
2799 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2800#endif
2801
2802 return subpage_readlen(opaque, addr, 1);
2803}
2804
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002805static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002806 uint32_t value)
2807{
2808#if defined(DEBUG_SUBPAGE)
2809 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2810#endif
2811 subpage_writelen(opaque, addr, value, 1);
2812}
2813
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002814static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002815{
2816#if defined(DEBUG_SUBPAGE)
2817 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
2818#endif
2819
2820 return subpage_readlen(opaque, addr, 2);
2821}
2822
2823static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002824 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002825{
2826#if defined(DEBUG_SUBPAGE)
2827 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
2828#endif
2829 subpage_writelen(opaque, addr, value, 2);
2830}
2831
David 'Digit' Turner36411062010-12-22 17:34:53 +01002832static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002833 &subpage_readb,
2834 &subpage_readw,
2835 &subpage_readl,
2836};
2837
David 'Digit' Turner36411062010-12-22 17:34:53 +01002838static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002839 &subpage_writeb,
2840 &subpage_writew,
2841 &subpage_writel,
2842};
2843
2844static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002845 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002846{
2847 int idx, eidx;
2848 unsigned int i;
2849
2850 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
2851 return -1;
2852 idx = SUBPAGE_IDX(start);
2853 eidx = SUBPAGE_IDX(end);
2854#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002855 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 -08002856 mmio, start, end, idx, eidx, memory);
2857#endif
2858 memory >>= IO_MEM_SHIFT;
2859 for (; idx <= eidx; idx++) {
2860 for (i = 0; i < 4; i++) {
2861 if (io_mem_read[memory][i]) {
2862 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
2863 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002864 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002865 }
2866 if (io_mem_write[memory][i]) {
2867 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2868 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002869 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002870 }
2871 }
2872 }
2873
2874 return 0;
2875}
2876
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002877static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002878 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002879{
2880 subpage_t *mmio;
2881 int subpage_memory;
2882
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002883 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002884
2885 mmio->base = base;
2886 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002887#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002888 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2889 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002890#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002891 *phys = subpage_memory | IO_MEM_SUBPAGE;
2892 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
2893 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002894
2895 return mmio;
2896}
2897
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002898static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002899{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002900 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002901
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002902 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2903 if (!io_mem_used[i]) {
2904 io_mem_used[i] = 1;
2905 return i;
2906 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002907 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002908 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002909}
2910
2911/* mem_read and mem_write are arrays of functions containing the
2912 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002913 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002914 If io_index is non zero, the corresponding io zone is
2915 modified. If it is zero, a new io zone is allocated. The return
2916 value can be used with cpu_register_physical_memory(). (-1) is
2917 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002918static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01002919 CPUReadMemoryFunc * const *mem_read,
2920 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002921 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002922{
2923 int i, subwidth = 0;
2924
2925 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002926 io_index = get_free_io_mem_idx();
2927 if (io_index == -1)
2928 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002929 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002930 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002931 if (io_index >= IO_MEM_NB_ENTRIES)
2932 return -1;
2933 }
2934
2935 for(i = 0;i < 3; i++) {
2936 if (!mem_read[i] || !mem_write[i])
2937 subwidth = IO_MEM_SUBWIDTH;
2938 io_mem_read[io_index][i] = mem_read[i];
2939 io_mem_write[io_index][i] = mem_write[i];
2940 }
2941 io_mem_opaque[io_index] = opaque;
2942 return (io_index << IO_MEM_SHIFT) | subwidth;
2943}
2944
David 'Digit' Turner36411062010-12-22 17:34:53 +01002945int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
2946 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002947 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002948{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002949 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002950}
2951
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002952void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002953{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002954 int i;
2955 int io_index = io_table_address >> IO_MEM_SHIFT;
2956
2957 for (i=0;i < 3; i++) {
2958 io_mem_read[io_index][i] = unassigned_mem_read[i];
2959 io_mem_write[io_index][i] = unassigned_mem_write[i];
2960 }
2961 io_mem_opaque[io_index] = NULL;
2962 io_mem_used[io_index] = 0;
2963}
2964
2965static void io_mem_init(void)
2966{
2967 int i;
2968
2969 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
2970 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
2971 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
2972 for (i=0; i<5; i++)
2973 io_mem_used[i] = 1;
2974
2975 io_mem_watch = cpu_register_io_memory(watch_mem_read,
2976 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002977}
2978
2979#endif /* !defined(CONFIG_USER_ONLY) */
2980
2981/* physical memory access (slow version, mainly for debug) */
2982#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002983void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002984 int len, int is_write)
2985{
2986 int l, flags;
2987 target_ulong page;
2988 void * p;
2989
2990 while (len > 0) {
2991 page = addr & TARGET_PAGE_MASK;
2992 l = (page + TARGET_PAGE_SIZE) - addr;
2993 if (l > len)
2994 l = len;
2995 flags = page_get_flags(page);
2996 if (!(flags & PAGE_VALID))
2997 return;
2998 if (is_write) {
2999 if (!(flags & PAGE_WRITE))
3000 return;
3001 /* XXX: this code should not depend on lock_user */
3002 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
3003 /* FIXME - should this return an error rather than just fail? */
3004 return;
3005 memcpy(p, buf, l);
3006 unlock_user(p, addr, l);
3007 } else {
3008 if (!(flags & PAGE_READ))
3009 return;
3010 /* XXX: this code should not depend on lock_user */
3011 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
3012 /* FIXME - should this return an error rather than just fail? */
3013 return;
3014 memcpy(buf, p, l);
3015 unlock_user(p, addr, 0);
3016 }
3017 len -= l;
3018 buf += l;
3019 addr += l;
3020 }
3021}
3022
3023#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07003024
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003025static void invalidate_and_set_dirty(hwaddr addr,
3026 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07003027{
3028 if (!cpu_physical_memory_is_dirty(addr)) {
3029 /* invalidate code */
3030 tb_invalidate_phys_page_range(addr, addr + length, 0);
3031 /* set dirty bit */
3032 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
3033 }
3034}
3035
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003036void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003037 int len, int is_write)
3038{
3039 int l, io_index;
3040 uint8_t *ptr;
3041 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003042 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003043 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003044 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003045 PhysPageDesc *p;
3046
3047 while (len > 0) {
3048 page = addr & TARGET_PAGE_MASK;
3049 l = (page + TARGET_PAGE_SIZE) - addr;
3050 if (l > len)
3051 l = len;
3052 p = phys_page_find(page >> TARGET_PAGE_BITS);
3053 if (!p) {
3054 pd = IO_MEM_UNASSIGNED;
3055 } else {
3056 pd = p->phys_offset;
3057 }
3058
3059 if (is_write) {
3060 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003061 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003062 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003063 if (p)
3064 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003065 /* XXX: could force cpu_single_env to NULL to avoid
3066 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003067 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003068 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003069 val = ldl_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003070 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003071 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003072 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003073 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003074 val = lduw_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003075 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003076 l = 2;
3077 } else {
3078 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003079 val = ldub_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003080 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003081 l = 1;
3082 }
3083 } else {
3084 unsigned long addr1;
3085 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3086 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003087 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003088 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07003089 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003090 }
3091 } else {
3092 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3093 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003094 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003095 /* I/O case */
3096 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003097 if (p)
3098 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
3099 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003100 /* 32 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003101 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003102 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003103 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003104 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003105 /* 16 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003106 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003107 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003108 l = 2;
3109 } else {
3110 /* 8 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003111 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003112 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003113 l = 1;
3114 }
3115 } else {
3116 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003117 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003118 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003119 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003120 }
3121 }
3122 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003123 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003124 addr += l;
3125 }
3126}
3127
3128/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003129void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003130 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003131{
3132 int l;
3133 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003134 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003135 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003136 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003137 PhysPageDesc *p;
3138
3139 while (len > 0) {
3140 page = addr & TARGET_PAGE_MASK;
3141 l = (page + TARGET_PAGE_SIZE) - addr;
3142 if (l > len)
3143 l = len;
3144 p = phys_page_find(page >> TARGET_PAGE_BITS);
3145 if (!p) {
3146 pd = IO_MEM_UNASSIGNED;
3147 } else {
3148 pd = p->phys_offset;
3149 }
3150
3151 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
3152 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
3153 !(pd & IO_MEM_ROMD)) {
3154 /* do nothing */
3155 } else {
3156 unsigned long addr1;
3157 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3158 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003159 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003160 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07003161 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003162 }
3163 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003164 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003165 addr += l;
3166 }
3167}
3168
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003169typedef struct {
3170 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003171 hwaddr addr;
3172 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003173} BounceBuffer;
3174
3175static BounceBuffer bounce;
3176
3177typedef struct MapClient {
3178 void *opaque;
3179 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003180 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003181} MapClient;
3182
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003183static QLIST_HEAD(map_client_list, MapClient) map_client_list
3184 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003185
3186void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
3187{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01003188 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003189
3190 client->opaque = opaque;
3191 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003192 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003193 return client;
3194}
3195
3196void cpu_unregister_map_client(void *_client)
3197{
3198 MapClient *client = (MapClient *)_client;
3199
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003200 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01003201 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003202}
3203
3204static void cpu_notify_map_clients(void)
3205{
3206 MapClient *client;
3207
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003208 while (!QLIST_EMPTY(&map_client_list)) {
3209 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003210 client->callback(client->opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07003211 QLIST_REMOVE(client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003212 }
3213}
3214
3215/* Map a physical memory region into a host virtual address.
3216 * May map a subset of the requested range, given by and returned in *plen.
3217 * May return NULL if resources needed to perform the mapping are exhausted.
3218 * Use only for reads OR writes - not for read-modify-write operations.
3219 * Use cpu_register_map_client() to know when retrying the map operation is
3220 * likely to succeed.
3221 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003222void *cpu_physical_memory_map(hwaddr addr,
3223 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003224 int is_write)
3225{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003226 hwaddr len = *plen;
3227 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003228 int l;
3229 uint8_t *ret = NULL;
3230 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003231 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003232 unsigned long pd;
3233 PhysPageDesc *p;
3234 unsigned long addr1;
3235
3236 while (len > 0) {
3237 page = addr & TARGET_PAGE_MASK;
3238 l = (page + TARGET_PAGE_SIZE) - addr;
3239 if (l > len)
3240 l = len;
3241 p = phys_page_find(page >> TARGET_PAGE_BITS);
3242 if (!p) {
3243 pd = IO_MEM_UNASSIGNED;
3244 } else {
3245 pd = p->phys_offset;
3246 }
3247
3248 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3249 if (done || bounce.buffer) {
3250 break;
3251 }
3252 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
3253 bounce.addr = addr;
3254 bounce.len = l;
3255 if (!is_write) {
3256 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
3257 }
3258 ptr = bounce.buffer;
3259 } else {
3260 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3261 ptr = qemu_get_ram_ptr(addr1);
3262 }
3263 if (!done) {
3264 ret = ptr;
3265 } else if (ret + done != ptr) {
3266 break;
3267 }
3268
3269 len -= l;
3270 addr += l;
3271 done += l;
3272 }
3273 *plen = done;
3274 return ret;
3275}
3276
3277/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
3278 * Will also mark the memory as dirty if is_write == 1. access_len gives
3279 * the amount of memory that was actually read or written by the caller.
3280 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003281void cpu_physical_memory_unmap(void *buffer, hwaddr len,
3282 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003283{
3284 if (buffer != bounce.buffer) {
3285 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003286 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003287 while (access_len) {
3288 unsigned l;
3289 l = TARGET_PAGE_SIZE;
3290 if (l > access_len)
3291 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07003292 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003293 addr1 += l;
3294 access_len -= l;
3295 }
3296 }
3297 return;
3298 }
3299 if (is_write) {
3300 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
3301 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003302 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003303 bounce.buffer = NULL;
3304 cpu_notify_map_clients();
3305}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003306
3307/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003308uint32_t ldl_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003309{
3310 int io_index;
3311 uint8_t *ptr;
3312 uint32_t val;
3313 unsigned long pd;
3314 PhysPageDesc *p;
3315
3316 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3317 if (!p) {
3318 pd = IO_MEM_UNASSIGNED;
3319 } else {
3320 pd = p->phys_offset;
3321 }
3322
3323 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3324 !(pd & IO_MEM_ROMD)) {
3325 /* I/O case */
3326 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003327 if (p)
3328 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003329 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3330 } else {
3331 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003332 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003333 (addr & ~TARGET_PAGE_MASK);
3334 val = ldl_p(ptr);
3335 }
3336 return val;
3337}
3338
3339/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003340uint64_t ldq_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003341{
3342 int io_index;
3343 uint8_t *ptr;
3344 uint64_t val;
3345 unsigned long pd;
3346 PhysPageDesc *p;
3347
3348 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3349 if (!p) {
3350 pd = IO_MEM_UNASSIGNED;
3351 } else {
3352 pd = p->phys_offset;
3353 }
3354
3355 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
3356 !(pd & IO_MEM_ROMD)) {
3357 /* I/O case */
3358 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003359 if (p)
3360 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003361#ifdef TARGET_WORDS_BIGENDIAN
3362 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
3363 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
3364#else
3365 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
3366 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
3367#endif
3368 } else {
3369 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003370 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003371 (addr & ~TARGET_PAGE_MASK);
3372 val = ldq_p(ptr);
3373 }
3374 return val;
3375}
3376
3377/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003378uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003379{
3380 uint8_t val;
3381 cpu_physical_memory_read(addr, &val, 1);
3382 return val;
3383}
3384
3385/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003386uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003387{
3388 uint16_t val;
3389 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
3390 return tswap16(val);
3391}
3392
3393/* warning: addr must be aligned. The ram page is not masked as dirty
3394 and the code inside is not invalidated. It is useful if the dirty
3395 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003396void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003397{
3398 int io_index;
3399 uint8_t *ptr;
3400 unsigned long pd;
3401 PhysPageDesc *p;
3402
3403 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3404 if (!p) {
3405 pd = IO_MEM_UNASSIGNED;
3406 } else {
3407 pd = p->phys_offset;
3408 }
3409
3410 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3411 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003412 if (p)
3413 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003414 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3415 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003416 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3417 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003418 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003419
3420 if (unlikely(in_migration)) {
3421 if (!cpu_physical_memory_is_dirty(addr1)) {
3422 /* invalidate code */
3423 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
3424 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003425 cpu_physical_memory_set_dirty_flags(
3426 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003427 }
3428 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003429 }
3430}
3431
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003432void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003433{
3434 int io_index;
3435 uint8_t *ptr;
3436 unsigned long pd;
3437 PhysPageDesc *p;
3438
3439 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3440 if (!p) {
3441 pd = IO_MEM_UNASSIGNED;
3442 } else {
3443 pd = p->phys_offset;
3444 }
3445
3446 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3447 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003448 if (p)
3449 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003450#ifdef TARGET_WORDS_BIGENDIAN
3451 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
3452 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
3453#else
3454 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3455 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
3456#endif
3457 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003458 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003459 (addr & ~TARGET_PAGE_MASK);
3460 stq_p(ptr, val);
3461 }
3462}
3463
3464/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003465void stl_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003466{
3467 int io_index;
3468 uint8_t *ptr;
3469 unsigned long pd;
3470 PhysPageDesc *p;
3471
3472 p = phys_page_find(addr >> TARGET_PAGE_BITS);
3473 if (!p) {
3474 pd = IO_MEM_UNASSIGNED;
3475 } else {
3476 pd = p->phys_offset;
3477 }
3478
3479 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
3480 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003481 if (p)
3482 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003483 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
3484 } else {
3485 unsigned long addr1;
3486 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
3487 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003488 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003489 stl_p(ptr, val);
Pete Delaneyd09d7662013-03-28 19:53:13 -07003490 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003491 }
3492}
3493
3494/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003495void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003496{
3497 uint8_t v = val;
3498 cpu_physical_memory_write(addr, &v, 1);
3499}
3500
3501/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003502void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003503{
3504 uint16_t v = tswap16(val);
3505 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
3506}
3507
3508/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003509void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003510{
3511 val = tswap64(val);
3512 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
3513}
3514
3515#endif
3516
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003517/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01003518int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003519 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003520{
3521 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01003522 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003523 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003524 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003525
3526 while (len > 0) {
3527 page = addr & TARGET_PAGE_MASK;
3528 phys_addr = cpu_get_phys_page_debug(env, page);
3529 /* if no physical page mapped, return an error */
3530 if (phys_addr == -1)
3531 return -1;
3532 l = (page + TARGET_PAGE_SIZE) - addr;
3533 if (l > len)
3534 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003535 phys_addr += (addr & ~TARGET_PAGE_MASK);
3536#if !defined(CONFIG_USER_ONLY)
3537 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003538 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003539 else
3540#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003541 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003542 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01003543 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003544 addr += l;
3545 }
3546 return 0;
3547}
3548
3549/* in deterministic execution mode, instructions doing device I/Os
3550 must be at the end of the TB */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01003551void cpu_io_recompile(CPUOldState *env, void *retaddr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003552{
3553 TranslationBlock *tb;
3554 uint32_t n, cflags;
3555 target_ulong pc, cs_base;
3556 uint64_t flags;
3557
3558 tb = tb_find_pc((unsigned long)retaddr);
3559 if (!tb) {
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02003560 cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003561 retaddr);
3562 }
3563 n = env->icount_decr.u16.low + tb->icount;
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02003564 cpu_restore_state(tb, env, (unsigned long)retaddr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003565 /* Calculate how many instructions had been executed before the fault
3566 occurred. */
3567 n = n - env->icount_decr.u16.low;
3568 /* Generate a new TB ending on the I/O insn. */
3569 n++;
3570 /* On MIPS and SH, delay slot instructions can only be restarted if
3571 they were already the first instruction in the TB. If this is not
3572 the first instruction in a TB then re-execute the preceding
3573 branch. */
3574#if defined(TARGET_MIPS)
3575 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
3576 env->active_tc.PC -= 4;
3577 env->icount_decr.u16.low++;
3578 env->hflags &= ~MIPS_HFLAG_BMASK;
3579 }
3580#elif defined(TARGET_SH4)
3581 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
3582 && n > 1) {
3583 env->pc -= 2;
3584 env->icount_decr.u16.low++;
3585 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
3586 }
3587#endif
3588 /* This should never happen. */
3589 if (n > CF_COUNT_MASK)
3590 cpu_abort(env, "TB too big during recompile");
3591
3592 cflags = n | CF_LAST_IO;
3593 pc = tb->pc;
3594 cs_base = tb->cs_base;
3595 flags = tb->flags;
3596 tb_phys_invalidate(tb, -1);
3597 /* FIXME: In theory this could raise an exception. In practice
3598 we have already translated the block once so it's probably ok. */
3599 tb_gen_code(env, pc, cs_base, flags, cflags);
3600 /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
3601 the first in the TB) then we end up generating a whole new TB and
3602 repeating the fault, which is horribly inefficient.
3603 Better would be to execute just this insn uncached, or generate a
3604 second new TB. */
3605 cpu_resume_from_signal(env, NULL);
3606}
3607
David 'Digit' Turner36411062010-12-22 17:34:53 +01003608#if !defined(CONFIG_USER_ONLY)
3609
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003610void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003611{
3612 int i, target_code_size, max_target_code_size;
3613 int direct_jmp_count, direct_jmp2_count, cross_page;
3614 TranslationBlock *tb;
3615
3616 target_code_size = 0;
3617 max_target_code_size = 0;
3618 cross_page = 0;
3619 direct_jmp_count = 0;
3620 direct_jmp2_count = 0;
3621 for(i = 0; i < nb_tbs; i++) {
3622 tb = &tbs[i];
3623 target_code_size += tb->size;
3624 if (tb->size > max_target_code_size)
3625 max_target_code_size = tb->size;
3626 if (tb->page_addr[1] != -1)
3627 cross_page++;
3628 if (tb->tb_next_offset[0] != 0xffff) {
3629 direct_jmp_count++;
3630 if (tb->tb_next_offset[1] != 0xffff) {
3631 direct_jmp2_count++;
3632 }
3633 }
3634 }
3635 /* XXX: avoid using doubles ? */
3636 cpu_fprintf(f, "Translation buffer state:\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003637 cpu_fprintf(f, "gen code size %td/%ld\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003638 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02003639 cpu_fprintf(f, "TB count %d/%d\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003640 nb_tbs, code_gen_max_blocks);
3641 cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
3642 nb_tbs ? target_code_size / nb_tbs : 0,
3643 max_target_code_size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02003644 cpu_fprintf(f, "TB avg host size %td bytes (expansion ratio: %0.1f)\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003645 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
3646 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
3647 cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
3648 cross_page,
3649 nb_tbs ? (cross_page * 100) / nb_tbs : 0);
3650 cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
3651 direct_jmp_count,
3652 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
3653 direct_jmp2_count,
3654 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
3655 cpu_fprintf(f, "\nStatistics:\n");
3656 cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
3657 cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
3658 cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
3659 tcg_dump_info(f, cpu_fprintf);
3660}
3661
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003662#endif