blob: ae40cc9dfe6e98af30996c06322f05a147033062 [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' Turner0e8e7482014-02-17 20:25:52 +010040#include "hw/xen/xen.h"
David 'Digit' Turner84569132013-12-13 17:34:07 +010041#include "qemu/osdep.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010042#include "sysemu/kvm.h"
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010043#include "exec/cputlb.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010044#include "exec/hax.h"
David 'Digit' Turner7a78db72013-12-14 11:46:01 +010045#include "qemu/timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080046#if defined(CONFIG_USER_ONLY)
47#include <qemu.h>
48#endif
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080049#ifdef CONFIG_MEMCHECK
50#include "memcheck/memcheck_api.h"
51#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080052
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080053//#define DEBUG_SUBPAGE
54
55#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080056int phys_ram_fd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070057static int in_migration;
58
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +010059RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) };
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060#endif
61
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +010062CPUArchState *first_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080063/* current CPU in the current thread. It is only valid inside
64 cpu_exec() */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +010065CPUArchState *cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080066/* 0 = Do not count executed instructions.
67 1 = Precise instruction counting.
68 2 = Adaptive rate instruction counting. */
69int use_icount = 0;
70/* Current instruction counter. While executing translated code this may
71 include some instructions that have not yet been executed. */
72int64_t qemu_icount;
73
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080074#if !defined(CONFIG_USER_ONLY)
75static void io_mem_init(void);
76
77/* io memory support */
78CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
79CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
80void *io_mem_opaque[IO_MEM_NB_ENTRIES];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070081static char io_mem_used[IO_MEM_NB_ENTRIES];
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010082int io_mem_watch;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080083#endif
84
85/* log support */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070086#ifdef WIN32
87static const char *logfilename = "qemu.log";
88#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070089static const char *logfilename = "/tmp/qemu.log";
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070090#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080091FILE *logfile;
92int loglevel;
93static int log_append = 0;
94
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080095#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
96typedef struct subpage_t {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +010097 hwaddr base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080098 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
99 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
100 void *opaque[TARGET_PAGE_SIZE][2][4];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700101 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800102} subpage_t;
103
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800104/* Must be called before using the QEMU cpus. 'tb_size' is the size
105 (in bytes) allocated to the translation buffer. Zero means default
106 size. */
107void cpu_exec_init_all(unsigned long tb_size)
108{
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +0100109 //cpu_gen_init();
110 //code_gen_alloc(tb_size);
111 //code_gen_ptr = code_gen_buffer;
112 //page_init();
113 tcg_exec_init(tb_size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800114#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100115 qemu_mutex_init(&ram_list.mutex);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800116 io_mem_init();
117#endif
118}
119
120#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
121
122#define CPU_COMMON_SAVE_VERSION 1
123
124static void cpu_common_save(QEMUFile *f, void *opaque)
125{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100126 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800127
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700128 cpu_synchronize_state(env, 0);
129
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800130 qemu_put_be32s(f, &env->halted);
131 qemu_put_be32s(f, &env->interrupt_request);
132}
133
134static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
135{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100136 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800137
138 if (version_id != CPU_COMMON_SAVE_VERSION)
139 return -EINVAL;
140
141 qemu_get_be32s(f, &env->halted);
142 qemu_get_be32s(f, &env->interrupt_request);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700143 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
144 version_id is increased. */
145 env->interrupt_request &= ~0x01;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800146 tlb_flush(env, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700147 cpu_synchronize_state(env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800148
149 return 0;
150}
151#endif
152
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100153CPUArchState *qemu_get_cpu(int cpu)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700154{
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100155 CPUArchState *env = first_cpu;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700156
157 while (env) {
158 if (env->cpu_index == cpu)
159 break;
160 env = env->next_cpu;
161 }
162
163 return env;
164}
165
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100166void cpu_exec_init(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800167{
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100168 CPUArchState **penv;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800169 int cpu_index;
170
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700171#if defined(CONFIG_USER_ONLY)
172 cpu_list_lock();
173#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800174 env->next_cpu = NULL;
175 penv = &first_cpu;
176 cpu_index = 0;
177 while (*penv != NULL) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700178 penv = &(*penv)->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800179 cpu_index++;
180 }
181 env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700182 env->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700183 QTAILQ_INIT(&env->breakpoints);
184 QTAILQ_INIT(&env->watchpoints);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800185 *penv = env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700186#if defined(CONFIG_USER_ONLY)
187 cpu_list_unlock();
188#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800189#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +0100190 register_savevm(NULL,
191 "cpu_common",
192 cpu_index,
193 CPU_COMMON_SAVE_VERSION,
194 cpu_common_save,
195 cpu_common_load,
196 env);
197 register_savevm(NULL,
198 "cpu",
199 cpu_index,
200 CPU_SAVE_VERSION,
201 cpu_save,
202 cpu_load,
203 env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800204#endif
205}
206
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800207#if defined(TARGET_HAS_ICE)
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100208static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800209{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100210 hwaddr addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800211 target_ulong pd;
212 ram_addr_t ram_addr;
213 PhysPageDesc *p;
214
215 addr = cpu_get_phys_page_debug(env, pc);
216 p = phys_page_find(addr >> TARGET_PAGE_BITS);
217 if (!p) {
218 pd = IO_MEM_UNASSIGNED;
219 } else {
220 pd = p->phys_offset;
221 }
222 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
223 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
224}
225#endif
226
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100227#if defined(CONFIG_USER_ONLY)
228void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
229
230{
231}
232
233int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
234 int flags, CPUWatchpoint **watchpoint)
235{
236 return -ENOSYS;
237}
238#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800239/* Add a watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100240int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700241 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800242{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700243 target_ulong len_mask = ~(len - 1);
244 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800245
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700246 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100247 if ((len & (len - 1)) || (addr & ~len_mask) ||
248 len == 0 || len > TARGET_PAGE_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700249 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
250 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
251 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800252 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100253 wp = g_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800254
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700255 wp->vaddr = addr;
256 wp->len_mask = len_mask;
257 wp->flags = flags;
258
259 /* keep all GDB-injected watchpoints in front */
260 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700261 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700262 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700263 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700264
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800265 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700266
267 if (watchpoint)
268 *watchpoint = wp;
269 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800270}
271
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700272/* Remove a specific watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100273int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700274 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800275{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700276 target_ulong len_mask = ~(len - 1);
277 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800278
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700279 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700280 if (addr == wp->vaddr && len_mask == wp->len_mask
281 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
282 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800283 return 0;
284 }
285 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700286 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800287}
288
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700289/* Remove a specific watchpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100290void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700291{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700292 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800293
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700294 tlb_flush_page(env, watchpoint->vaddr);
295
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100296 g_free(watchpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700297}
298
299/* Remove all matching watchpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100300void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700301{
302 CPUWatchpoint *wp, *next;
303
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700304 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700305 if (wp->flags & mask)
306 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800307 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800308}
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100309#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800310
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700311/* Add a breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100312int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700313 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800314{
315#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700316 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800317
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100318 bp = g_malloc(sizeof(*bp));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700319
320 bp->pc = pc;
321 bp->flags = flags;
322
323 /* keep all GDB-injected breakpoints in front */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100324 if (flags & BP_GDB) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700325 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100326 } else {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700327 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100328 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700329
330 breakpoint_invalidate(env, pc);
331
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100332 if (breakpoint) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700333 *breakpoint = bp;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100334 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700335 return 0;
336#else
337 return -ENOSYS;
338#endif
339}
340
341/* Remove a specific breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100342int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700343{
344#if defined(TARGET_HAS_ICE)
345 CPUBreakpoint *bp;
346
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700347 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700348 if (bp->pc == pc && bp->flags == flags) {
349 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800350 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700351 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800352 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700353 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800354#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356#endif
357}
358
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700359/* Remove a specific breakpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100360void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800361{
362#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700363 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800364
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700365 breakpoint_invalidate(env, breakpoint->pc);
366
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100367 g_free(breakpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700368#endif
369}
370
371/* Remove all matching breakpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100372void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700373{
374#if defined(TARGET_HAS_ICE)
375 CPUBreakpoint *bp, *next;
376
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700377 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700378 if (bp->flags & mask)
379 cpu_breakpoint_remove_by_ref(env, bp);
380 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800381#endif
382}
383
384/* enable or disable single step mode. EXCP_DEBUG is returned by the
385 CPU loop after each instruction */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100386void cpu_single_step(CPUOldState *env, int enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800387{
388#if defined(TARGET_HAS_ICE)
389 if (env->singlestep_enabled != enabled) {
390 env->singlestep_enabled = enabled;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100391 if (kvm_enabled()) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700392 kvm_update_guest_debug(env, 0);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100393 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700394 /* must flush all the translated code to avoid inconsistencies */
395 /* XXX: only flush what is necessary */
396 tb_flush(env);
397 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800398 }
399#endif
400}
401
402/* enable or disable low levels log */
403void cpu_set_log(int log_flags)
404{
405 loglevel = log_flags;
406 if (loglevel && !logfile) {
407 logfile = fopen(logfilename, log_append ? "a" : "w");
408 if (!logfile) {
409 perror(logfilename);
Iliyan Malchev4a2c9dd2012-04-02 08:20:56 -0700410 exit(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800411 }
412#if !defined(CONFIG_SOFTMMU)
413 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
414 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700415 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800416 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
417 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700418#elif !defined(_WIN32)
419 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800420 setvbuf(logfile, NULL, _IOLBF, 0);
421#endif
422 log_append = 1;
423 }
424 if (!loglevel && logfile) {
425 fclose(logfile);
426 logfile = NULL;
427 }
428}
429
430void cpu_set_log_filename(const char *filename)
431{
432 logfilename = strdup(filename);
433 if (logfile) {
434 fclose(logfile);
435 logfile = NULL;
436 }
437 cpu_set_log(loglevel);
438}
439
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100440void cpu_unlink_tb(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800441{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800442 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
443 problem and hope the cpu will stop of its own accord. For userspace
444 emulation this often isn't actually as bad as it sounds. Often
445 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700446 TranslationBlock *tb;
447 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
448
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200449 spin_lock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700450 tb = env->current_tb;
451 /* if the cpu is currently executing code, we must unlink it and
452 all the potentially executing TB */
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200453 if (tb) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700454 env->current_tb = NULL;
455 tb_reset_jump_recursive(tb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700456 }
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200457 spin_unlock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700458}
459
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100460void cpu_reset_interrupt(CPUOldState *env, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800461{
462 env->interrupt_request &= ~mask;
463}
464
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100465void cpu_exit(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700466{
467 env->exit_request = 1;
468 cpu_unlink_tb(env);
469}
470
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100471void cpu_abort(CPUArchState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800472{
473 va_list ap;
474 va_list ap2;
475
476 va_start(ap, fmt);
477 va_copy(ap2, ap);
478 fprintf(stderr, "qemu: fatal: ");
479 vfprintf(stderr, fmt, ap);
480 fprintf(stderr, "\n");
481#ifdef TARGET_I386
482 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
483#else
484 cpu_dump_state(env, stderr, fprintf, 0);
485#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700486 if (qemu_log_enabled()) {
487 qemu_log("qemu: fatal: ");
488 qemu_log_vprintf(fmt, ap2);
489 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800490#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700491 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800492#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700493 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800494#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700495 qemu_log_flush();
496 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800497 }
498 va_end(ap2);
499 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +0100500#if defined(CONFIG_USER_ONLY)
501 {
502 struct sigaction act;
503 sigfillset(&act.sa_mask);
504 act.sa_handler = SIG_DFL;
505 sigaction(SIGABRT, &act, NULL);
506 }
507#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800508 abort();
509}
510
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800511#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100512static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
513{
514 RAMBlock *block;
515
516 /* The list is protected by the iothread lock here. */
517 block = ram_list.mru_block;
518 if (block && addr - block->offset < block->length) {
519 goto found;
520 }
521 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
522 if (addr - block->offset < block->length) {
523 goto found;
524 }
525 }
526
527 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
528 abort();
529
530found:
531 ram_list.mru_block = block;
532 return block;
533}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800534
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700535/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800536void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
537 int dirty_flags)
538{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100539 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800540 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200541 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800542
543 start &= TARGET_PAGE_MASK;
544 end = TARGET_PAGE_ALIGN(end);
545
546 length = end - start;
547 if (length == 0)
548 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200549 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800550
551 /* we modify the TLB cache so that the dirty bit will be set again
552 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200553 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700554 /* Chek that we don't span multiple blocks - this breaks the
555 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200556 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700557 != (end - 1) - start) {
558 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800559 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700560
561 for(env = first_cpu; env != NULL; env = env->next_cpu) {
562 int mmu_idx;
563 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
564 for(i = 0; i < CPU_TLB_SIZE; i++)
565 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
566 start1, length);
567 }
568 }
569}
570
571int cpu_physical_memory_set_dirty_tracking(int enable)
572{
573 in_migration = enable;
574 if (kvm_enabled()) {
575 return kvm_set_migration_log(enable);
576 }
577 return 0;
578}
579
580int cpu_physical_memory_get_dirty_tracking(void)
581{
582 return in_migration;
583}
584
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100585int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
586 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700587{
588 int ret = 0;
589
590 if (kvm_enabled())
591 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
592 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800593}
594
595static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
596{
597 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700598 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800599
600 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700601 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
602 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200603 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800604 if (!cpu_physical_memory_is_dirty(ram_addr)) {
605 tlb_entry->addr_write |= TLB_NOTDIRTY;
606 }
607 }
608}
609
610/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100611void cpu_tlb_update_dirty(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800612{
613 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700614 int mmu_idx;
615 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
616 for(i = 0; i < CPU_TLB_SIZE; i++)
617 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
618 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800619}
620
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800621
622#else
623
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100624void tlb_flush(CPUArchState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800625{
626}
627
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100628void tlb_flush_page(CPUArchState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800629{
630}
631
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100632int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100633 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800634 int mmu_idx, int is_softmmu)
635{
636 return 0;
637}
638
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100639static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800640 unsigned long addr, target_ulong vaddr)
641{
642}
643#endif /* defined(CONFIG_USER_ONLY) */
644
645#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700646
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800647static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700648 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100649static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700650 ram_addr_t orig_memory, ram_addr_t region_offset);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100651
652static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
653
654/*
655 * Set a custom physical guest memory alloator.
656 * Accelerators with unusual needs may need this. Hopefully, we can
657 * get rid of it eventually.
658 */
659void phys_mem_set_alloc(void *(*alloc)(size_t))
660{
661 phys_mem_alloc = alloc;
662}
663
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800664#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
665 need_subpage) \
666 do { \
667 if (addr > start_addr) \
668 start_addr2 = 0; \
669 else { \
670 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
671 if (start_addr2 > 0) \
672 need_subpage = 1; \
673 } \
674 \
675 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
676 end_addr2 = TARGET_PAGE_SIZE - 1; \
677 else { \
678 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
679 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
680 need_subpage = 1; \
681 } \
682 } while (0)
683
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700684/* register physical memory.
685 For RAM, 'size' must be a multiple of the target page size.
686 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700687 io memory page. The address used when calling the IO function is
688 the offset from the start of the region, plus region_offset. Both
689 start_addr and region_offset are rounded down to a page boundary
690 before calculating this offset. This should not be a problem unless
691 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100692void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700693 ram_addr_t size,
694 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200695 ram_addr_t region_offset,
696 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800697{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100698 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800699 PhysPageDesc *p;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100700 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800701 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200702 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800703
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700704 if (kvm_enabled())
705 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800706#ifdef CONFIG_HAX
707 if (hax_enabled())
708 hax_set_phys_mem(start_addr, size, phys_offset);
709#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700710
711 if (phys_offset == IO_MEM_UNASSIGNED) {
712 region_offset = start_addr;
713 }
714 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800715 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100716 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200717
718 addr = start_addr;
719 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800720 p = phys_page_find(addr >> TARGET_PAGE_BITS);
721 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
722 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100723 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800724 int need_subpage = 0;
725
726 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
727 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200728 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800729 if (!(orig_memory & IO_MEM_SUBPAGE)) {
730 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700731 &p->phys_offset, orig_memory,
732 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800733 } else {
734 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
735 >> IO_MEM_SHIFT];
736 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700737 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
738 region_offset);
739 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800740 } else {
741 p->phys_offset = phys_offset;
742 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
743 (phys_offset & IO_MEM_ROMD))
744 phys_offset += TARGET_PAGE_SIZE;
745 }
746 } else {
747 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
748 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700749 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800750 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700751 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800752 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700753 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100754 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800755 int need_subpage = 0;
756
757 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
758 end_addr2, need_subpage);
759
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200760 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800761 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700762 &p->phys_offset, IO_MEM_UNASSIGNED,
763 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800764 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700765 phys_offset, region_offset);
766 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800767 }
768 }
769 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700770 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200771 addr += TARGET_PAGE_SIZE;
772 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800773
774 /* since each CPU stores ram addresses in its TLB cache, we must
775 reset the modified entries */
776 /* XXX: slow ! */
777 for(env = first_cpu; env != NULL; env = env->next_cpu) {
778 tlb_flush(env, 1);
779 }
780}
781
782/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100783ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800784{
785 PhysPageDesc *p;
786
787 p = phys_page_find(addr >> TARGET_PAGE_BITS);
788 if (!p)
789 return IO_MEM_UNASSIGNED;
790 return p->phys_offset;
791}
792
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100793void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700794{
795 if (kvm_enabled())
796 kvm_coalesce_mmio_region(addr, size);
797}
798
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100799void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700800{
801 if (kvm_enabled())
802 kvm_uncoalesce_mmio_region(addr, size);
803}
804
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100805void qemu_mutex_lock_ramlist(void)
806{
807 qemu_mutex_lock(&ram_list.mutex);
808}
809
810void qemu_mutex_unlock_ramlist(void)
811{
812 qemu_mutex_unlock(&ram_list.mutex);
813}
814
815#if defined(__linux__) && !defined(CONFIG_ANDROID)
816
817#include <sys/vfs.h>
818
819#define HUGETLBFS_MAGIC 0x958458f6
820
821static long gethugepagesize(const char *path)
822{
823 struct statfs fs;
824 int ret;
825
826 do {
827 ret = statfs(path, &fs);
828 } while (ret != 0 && errno == EINTR);
829
830 if (ret != 0) {
831 perror(path);
832 return 0;
833 }
834
835 if (fs.f_type != HUGETLBFS_MAGIC)
836 fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
837
838 return fs.f_bsize;
839}
840
841static sigjmp_buf sigjump;
842
843static void sigbus_handler(int signal)
844{
845 siglongjmp(sigjump, 1);
846}
847
848static void *file_ram_alloc(RAMBlock *block,
849 ram_addr_t memory,
850 const char *path)
851{
852 char *filename;
853 char *sanitized_name;
854 char *c;
855 void *area;
856 int fd;
857 unsigned long hpagesize;
858
859 hpagesize = gethugepagesize(path);
860 if (!hpagesize) {
861 return NULL;
862 }
863
864 if (memory < hpagesize) {
865 return NULL;
866 }
867
868 if (kvm_enabled() && !kvm_has_sync_mmu()) {
869 fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
870 return NULL;
871 }
872
873 /* Make name safe to use with mkstemp by replacing '/' with '_'. */
874 sanitized_name = g_strdup(block->mr->name);
875 for (c = sanitized_name; *c != '\0'; c++) {
876 if (*c == '/')
877 *c = '_';
878 }
879
880 filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
881 sanitized_name);
882 g_free(sanitized_name);
883
884 fd = mkstemp(filename);
885 if (fd < 0) {
886 perror("unable to create backing store for hugepages");
887 g_free(filename);
888 return NULL;
889 }
890 unlink(filename);
891 g_free(filename);
892
893 memory = (memory+hpagesize-1) & ~(hpagesize-1);
894
895 /*
896 * ftruncate is not supported by hugetlbfs in older
897 * hosts, so don't bother bailing out on errors.
898 * If anything goes wrong with it under other filesystems,
899 * mmap will fail.
900 */
901 if (ftruncate(fd, memory))
902 perror("ftruncate");
903
904 area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
905 if (area == MAP_FAILED) {
906 perror("file_ram_alloc: can't mmap RAM pages");
907 close(fd);
908 return (NULL);
909 }
910
911 if (mem_prealloc) {
912 int ret, i;
913 struct sigaction act, oldact;
914 sigset_t set, oldset;
915
916 memset(&act, 0, sizeof(act));
917 act.sa_handler = &sigbus_handler;
918 act.sa_flags = 0;
919
920 ret = sigaction(SIGBUS, &act, &oldact);
921 if (ret) {
922 perror("file_ram_alloc: failed to install signal handler");
923 exit(1);
924 }
925
926 /* unblock SIGBUS */
927 sigemptyset(&set);
928 sigaddset(&set, SIGBUS);
929 pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
930
931 if (sigsetjmp(sigjump, 1)) {
932 fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
933 exit(1);
934 }
935
936 /* MAP_POPULATE silently ignores failures */
937 for (i = 0; i < (memory/hpagesize)-1; i++) {
938 memset(area + (hpagesize*i), 0, 1);
939 }
940
941 ret = sigaction(SIGBUS, &oldact, NULL);
942 if (ret) {
943 perror("file_ram_alloc: failed to reinstall signal handler");
944 exit(1);
945 }
946
947 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
948 }
949
950 block->fd = fd;
951 return area;
952}
953#else
954static void *file_ram_alloc(RAMBlock *block,
955 ram_addr_t memory,
956 const char *path)
957{
958 fprintf(stderr, "-mem-path not supported on this host\n");
959 exit(1);
960}
961#endif
962
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200963static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700964{
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200965 RAMBlock *block, *next_block;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100966 ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200967
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100968 assert(size != 0); /* it would hand out same offset multiple times */
969
970 if (QTAILQ_EMPTY(&ram_list.blocks))
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200971 return 0;
972
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100973 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
974 ram_addr_t end, next = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200975
976 end = block->offset + block->length;
977
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100978 QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200979 if (next_block->offset >= end) {
980 next = MIN(next, next_block->offset);
981 }
982 }
983 if (next - end >= size && next - end < mingap) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100984 offset = end;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200985 mingap = next - end;
986 }
987 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100988
989 if (offset == RAM_ADDR_MAX) {
990 fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
991 (uint64_t)size);
992 abort();
993 }
994
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200995 return offset;
996}
997
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100998ram_addr_t last_ram_offset(void)
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200999{
1000 RAMBlock *block;
1001 ram_addr_t last = 0;
1002
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001003 QTAILQ_FOREACH(block, &ram_list.blocks, next)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001004 last = MAX(last, block->offset + block->length);
1005
1006 return last;
1007}
1008
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001009static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
1010{
1011#ifndef CONFIG_ANDROID
1012 int ret;
1013
1014 /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
1015 if (!qemu_opt_get_bool(qemu_get_machine_opts(),
1016 "dump-guest-core", true)) {
1017 ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
1018 if (ret) {
1019 perror("qemu_madvise");
1020 fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
1021 "but dump_guest_core=off specified\n");
1022 }
1023 }
1024#endif // !CONFIG_ANDROID
1025}
1026
1027void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001028{
1029 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001030
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001031 new_block = NULL;
1032 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1033 if (block->offset == addr) {
1034 new_block = block;
1035 break;
1036 }
1037 }
1038 assert(new_block);
1039 assert(!new_block->idstr[0]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001040
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001041 if (dev) {
1042 char *id = qdev_get_dev_path(dev);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001043 if (id) {
1044 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001045 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001046 }
1047 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001048 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1049
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001050 /* This assumes the iothread lock is taken here too. */
1051 qemu_mutex_lock_ramlist();
1052 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1053 if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001054 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
1055 new_block->idstr);
1056 abort();
1057 }
1058 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001059 qemu_mutex_unlock_ramlist();
1060}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001061
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001062static int memory_try_enable_merging(void *addr, size_t len)
1063{
1064#ifndef CONFIG_ANDROID
1065 if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) {
1066 /* disabled by the user */
1067 return 0;
1068 }
1069
1070 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1071#else // CONFIG_ANDROID
1072 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1073#endif // CONFIG_ANDROID
1074}
1075
1076ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
1077 ram_addr_t size, void *host)
1078{
1079 RAMBlock *block, *new_block;
1080
1081 size = TARGET_PAGE_ALIGN(size);
1082 new_block = g_malloc0(sizeof(*new_block));
1083 new_block->fd = -1;
1084
1085 /* This assumes the iothread lock is taken here too. */
1086 qemu_mutex_lock_ramlist();
1087 //new_block->mr = mr;
1088 new_block->offset = find_ram_offset(size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001089 if (host) {
1090 new_block->host = host;
1091 new_block->flags |= RAM_PREALLOC_MASK;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001092 } else if (xen_enabled()) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001093 if (mem_path) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001094 fprintf(stderr, "-mem-path not supported with Xen\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001095 exit(1);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001096 }
1097 //xen_ram_alloc(new_block->offset, size, mr);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001098 } else {
1099 if (mem_path) {
1100 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1101 /*
1102 * file_ram_alloc() needs to allocate just like
1103 * phys_mem_alloc, but we haven't bothered to provide
1104 * a hook there.
1105 */
1106 fprintf(stderr,
1107 "-mem-path not supported with this accelerator\n");
1108 exit(1);
1109 }
1110 new_block->host = file_ram_alloc(new_block, size, mem_path);
1111 }
1112 if (!new_block->host) {
1113 new_block->host = phys_mem_alloc(size);
1114 if (!new_block->host) {
1115 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1116 name, strerror(errno));
1117 exit(1);
1118 }
David 'Digit' Turnerf2de2ae2014-03-07 16:25:58 +01001119#ifdef CONFIG_HAX
1120 if (hax_enabled()) {
1121 /*
1122 * In HAX, qemu allocates the virtual address, and HAX kernel
1123 * module populates the region with physical memory. Currently
1124 * we don’t populate guest memory on demand, thus we should
1125 * make sure that sufficient amount of memory is available in
1126 * advance.
1127 */
1128 int ret = hax_populate_ram(
1129 (uint64_t)(uintptr_t)new_block->host,
1130 (uint32_t)size);
1131 if (ret < 0) {
1132 fprintf(stderr, "Hax failed to populate ram\n");
1133 exit(-1);
1134 }
1135 }
1136#endif // CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001137 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001138 }
1139 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001140 new_block->length = size;
1141
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001142 /* Keep the list sorted from biggest to smallest block. */
1143 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1144 if (block->length < new_block->length) {
1145 break;
1146 }
1147 }
1148 if (block) {
1149 QTAILQ_INSERT_BEFORE(block, new_block, next);
1150 } else {
1151 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1152 }
1153 ram_list.mru_block = NULL;
1154
1155 ram_list.version++;
1156 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001157
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001158 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001159 last_ram_offset() >> TARGET_PAGE_BITS);
1160 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001161 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001162 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001163
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001164 //qemu_ram_setup_dump(new_block->host, size);
1165 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1166 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
1167
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001168 if (kvm_enabled())
1169 kvm_setup_guest_memory(new_block->host, size);
1170
1171 return new_block->offset;
1172}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001173
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001174ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1175{
1176 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1177}
1178
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001179void qemu_ram_free_from_ptr(ram_addr_t addr)
1180{
1181 RAMBlock *block;
1182
1183 /* This assumes the iothread lock is taken here too. */
1184 qemu_mutex_lock_ramlist();
1185 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1186 if (addr == block->offset) {
1187 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1188 ram_list.mru_block = NULL;
1189 ram_list.version++;
1190 g_free(block);
1191 break;
1192 }
1193 }
1194 qemu_mutex_unlock_ramlist();
1195}
1196
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001197void qemu_ram_free(ram_addr_t addr)
1198{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001199 RAMBlock *block;
1200
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001201 /* This assumes the iothread lock is taken here too. */
1202 qemu_mutex_lock_ramlist();
1203 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001204 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001205 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1206 ram_list.mru_block = NULL;
1207 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001208 if (block->flags & RAM_PREALLOC_MASK) {
1209 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001210 } else if (xen_enabled()) {
1211 //xen_invalidate_map_cache_entry(block->host);
1212#ifndef _WIN32
1213 } else if (block->fd >= 0) {
1214 munmap(block->host, block->length);
1215 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001216#endif
1217 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001218 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001219 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001220 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001221 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001222 }
1223 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001224 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001225
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001226}
1227
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001228#ifndef _WIN32
1229void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1230{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001231 RAMBlock *block;
1232 ram_addr_t offset;
1233 int flags;
1234 void *area, *vaddr;
1235
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001236 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001237 offset = addr - block->offset;
1238 if (offset < block->length) {
1239 vaddr = block->host + offset;
1240 if (block->flags & RAM_PREALLOC_MASK) {
1241 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001242 } else if (xen_enabled()) {
1243 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001244 } else {
1245 flags = MAP_FIXED;
1246 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001247 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001248#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001249 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1250 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001251#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001252 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001253#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001254 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1255 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001256 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001257 /*
1258 * Remap needs to match alloc. Accelerators that
1259 * set phys_mem_alloc never remap. If they did,
1260 * we'd need a remap hook here.
1261 */
1262 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1263
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001264 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1265 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1266 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001267 }
1268 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001269 fprintf(stderr, "Could not remap addr: "
1270 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001271 length, addr);
1272 exit(1);
1273 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001274 memory_try_enable_merging(vaddr, length);
1275 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001276 }
1277 return;
1278 }
1279 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001280}
1281#endif /* !_WIN32 */
1282
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001283/* Return a host pointer to ram allocated with qemu_ram_alloc.
1284 With the exception of the softmmu code in this file, this should
1285 only be used for local memory (e.g. video ram) that the device owns,
1286 and knows it isn't going to access beyond the end of the block.
1287
1288 It should not be used for general purpose DMA.
1289 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1290 */
1291void *qemu_get_ram_ptr(ram_addr_t addr)
1292{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001293 RAMBlock *block = qemu_get_ram_block(addr);
1294#if 0
1295 if (xen_enabled()) {
1296 /* We need to check if the requested address is in the RAM
1297 * because we don't want to map the entire memory in QEMU.
1298 * In that case just map until the end of the page.
1299 */
1300 if (block->offset == 0) {
1301 return xen_map_cache(addr, 0, 0);
1302 } else if (block->host == NULL) {
1303 block->host =
1304 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001305 }
1306 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001307#endif
1308 return block->host + (addr - block->offset);
1309}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001310
1311/* Return a host pointer to ram allocated with qemu_ram_alloc.
1312 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1313 */
1314void *qemu_safe_ram_ptr(ram_addr_t addr)
1315{
1316 RAMBlock *block;
1317
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001318 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001319 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001320 return block->host + (addr - block->offset);
1321 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001322 }
1323
1324 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1325 abort();
1326
1327 return NULL;
1328}
1329
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001330/* Some of the softmmu routines need to translate from a host pointer
1331 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001332int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1333{
1334 RAMBlock *block;
1335 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001336#if 0
1337 if (xen_enabled()) {
1338 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1339 return qemu_get_ram_block(*ram_addr)->mr;
1340 }
1341#endif
1342 block = ram_list.mru_block;
1343 if (block && block->host && host - block->host < block->length) {
1344 goto found;
1345 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001346
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001347 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1348 /* This case append when the block is not mapped. */
1349 if (block->host == NULL) {
1350 continue;
1351 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001352 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001353 goto found;
1354 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001355 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001356
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001357 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001358
1359found:
1360 *ram_addr = block->offset + (host - block->host);
1361 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001362}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001363
1364/* Some of the softmmu routines need to translate from a host pointer
1365 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001366ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001367{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001368 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001369
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001370 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001371 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1372 abort();
1373 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001374 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001375}
1376
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001377static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001378{
1379#ifdef DEBUG_UNASSIGNED
1380 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1381#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001382#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001383 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001384#endif
1385 return 0;
1386}
1387
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001388static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001389{
1390#ifdef DEBUG_UNASSIGNED
1391 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1392#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001393#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001394 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001395#endif
1396 return 0;
1397}
1398
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001399static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001400{
1401#ifdef DEBUG_UNASSIGNED
1402 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1403#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001404#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001405 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001406#endif
1407 return 0;
1408}
1409
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001410static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001411{
1412#ifdef DEBUG_UNASSIGNED
1413 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1414#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001415#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001416 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001417#endif
1418}
1419
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001420static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001421{
1422#ifdef DEBUG_UNASSIGNED
1423 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1424#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001425#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001426 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001427#endif
1428}
1429
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001430static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001431{
1432#ifdef DEBUG_UNASSIGNED
1433 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1434#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001435#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001436 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001437#endif
1438}
1439
David 'Digit' Turner36411062010-12-22 17:34:53 +01001440static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001441 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001442 unassigned_mem_readw,
1443 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001444};
1445
David 'Digit' Turner36411062010-12-22 17:34:53 +01001446static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001447 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001448 unassigned_mem_writew,
1449 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001450};
1451
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001452static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001453 uint32_t val)
1454{
1455 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001456 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001457 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1458#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001459 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001460 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001461#endif
1462 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001463 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001464 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001465 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001466 /* we remove the notdirty callback only if the code has been
1467 flushed */
1468 if (dirty_flags == 0xff)
1469 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1470}
1471
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001472static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001473 uint32_t val)
1474{
1475 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001476 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001477 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1478#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001479 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001480 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001481#endif
1482 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001483 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001484 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001485 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001486 /* we remove the notdirty callback only if the code has been
1487 flushed */
1488 if (dirty_flags == 0xff)
1489 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1490}
1491
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001492static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001493 uint32_t val)
1494{
1495 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001496 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001497 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1498#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001499 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001500 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001501#endif
1502 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001503 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001504 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001505 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001506 /* we remove the notdirty callback only if the code has been
1507 flushed */
1508 if (dirty_flags == 0xff)
1509 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1510}
1511
David 'Digit' Turner36411062010-12-22 17:34:53 +01001512static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001513 NULL, /* never used */
1514 NULL, /* never used */
1515 NULL, /* never used */
1516};
1517
David 'Digit' Turner36411062010-12-22 17:34:53 +01001518static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001519 notdirty_mem_writeb,
1520 notdirty_mem_writew,
1521 notdirty_mem_writel,
1522};
1523
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001524static void tb_check_watchpoint(CPUArchState* env)
1525{
1526 TranslationBlock *tb = tb_find_pc(env->mem_io_pc);
1527 if (!tb) {
1528 cpu_abort(env, "check_watchpoint: could not find TB for "
1529 "pc=%p", (void *)env->mem_io_pc);
1530 }
1531 cpu_restore_state(env, env->mem_io_pc);
1532 tb_phys_invalidate(tb, -1);
1533}
1534
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001535/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001536static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001537{
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001538 CPUArchState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001539 target_ulong pc, cs_base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001540 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001541 CPUWatchpoint *wp;
1542 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001543
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001544 if (env->watchpoint_hit) {
1545 /* We re-entered the check after replacing the TB. Now raise
1546 * the debug interrupt so that is will trigger after the
1547 * current instruction. */
1548 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
1549 return;
1550 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001551 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001552 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001553 if ((vaddr == (wp->vaddr & len_mask) ||
1554 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1555 wp->flags |= BP_WATCHPOINT_HIT;
1556 if (!env->watchpoint_hit) {
1557 env->watchpoint_hit = wp;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001558 tb_check_watchpoint(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001559 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1560 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001561 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001562 } else {
1563 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1564 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001565 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001566 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001567 }
1568 } else {
1569 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001570 }
1571 }
1572}
1573
1574/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1575 so these check for a hit then pass through to the normal out-of-line
1576 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001577static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001578{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001579 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001580 return ldub_phys(addr);
1581}
1582
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001583static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001584{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001585 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001586 return lduw_phys(addr);
1587}
1588
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001589static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001590{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001591 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001592 return ldl_phys(addr);
1593}
1594
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001595static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001596 uint32_t val)
1597{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001598 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001599 stb_phys(addr, val);
1600}
1601
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001602static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001603 uint32_t val)
1604{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001605 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001606 stw_phys(addr, val);
1607}
1608
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001609static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001610 uint32_t val)
1611{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001612 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001613 stl_phys(addr, val);
1614}
1615
David 'Digit' Turner36411062010-12-22 17:34:53 +01001616static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001617 watch_mem_readb,
1618 watch_mem_readw,
1619 watch_mem_readl,
1620};
1621
David 'Digit' Turner36411062010-12-22 17:34:53 +01001622static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001623 watch_mem_writeb,
1624 watch_mem_writew,
1625 watch_mem_writel,
1626};
1627
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001628static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001629 unsigned int len)
1630{
1631 uint32_t ret;
1632 unsigned int idx;
1633
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001634 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001635#if defined(DEBUG_SUBPAGE)
1636 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1637 mmio, len, addr, idx);
1638#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001639 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1640 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001641
1642 return ret;
1643}
1644
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001645static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001646 uint32_t value, unsigned int len)
1647{
1648 unsigned int idx;
1649
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001650 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001651#if defined(DEBUG_SUBPAGE)
1652 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1653 mmio, len, addr, idx, value);
1654#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001655 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1656 addr + mmio->region_offset[idx][1][len],
1657 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001658}
1659
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001660static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001661{
1662#if defined(DEBUG_SUBPAGE)
1663 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1664#endif
1665
1666 return subpage_readlen(opaque, addr, 0);
1667}
1668
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001669static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001670 uint32_t value)
1671{
1672#if defined(DEBUG_SUBPAGE)
1673 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1674#endif
1675 subpage_writelen(opaque, addr, value, 0);
1676}
1677
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001678static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001679{
1680#if defined(DEBUG_SUBPAGE)
1681 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1682#endif
1683
1684 return subpage_readlen(opaque, addr, 1);
1685}
1686
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001687static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001688 uint32_t value)
1689{
1690#if defined(DEBUG_SUBPAGE)
1691 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1692#endif
1693 subpage_writelen(opaque, addr, value, 1);
1694}
1695
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001696static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001697{
1698#if defined(DEBUG_SUBPAGE)
1699 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1700#endif
1701
1702 return subpage_readlen(opaque, addr, 2);
1703}
1704
1705static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001706 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001707{
1708#if defined(DEBUG_SUBPAGE)
1709 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1710#endif
1711 subpage_writelen(opaque, addr, value, 2);
1712}
1713
David 'Digit' Turner36411062010-12-22 17:34:53 +01001714static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001715 &subpage_readb,
1716 &subpage_readw,
1717 &subpage_readl,
1718};
1719
David 'Digit' Turner36411062010-12-22 17:34:53 +01001720static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001721 &subpage_writeb,
1722 &subpage_writew,
1723 &subpage_writel,
1724};
1725
1726static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001727 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001728{
1729 int idx, eidx;
1730 unsigned int i;
1731
1732 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1733 return -1;
1734 idx = SUBPAGE_IDX(start);
1735 eidx = SUBPAGE_IDX(end);
1736#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001737 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 -08001738 mmio, start, end, idx, eidx, memory);
1739#endif
1740 memory >>= IO_MEM_SHIFT;
1741 for (; idx <= eidx; idx++) {
1742 for (i = 0; i < 4; i++) {
1743 if (io_mem_read[memory][i]) {
1744 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
1745 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001746 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001747 }
1748 if (io_mem_write[memory][i]) {
1749 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
1750 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001751 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001752 }
1753 }
1754 }
1755
1756 return 0;
1757}
1758
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001759static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001760 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001761{
1762 subpage_t *mmio;
1763 int subpage_memory;
1764
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001765 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001766
1767 mmio->base = base;
1768 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001769#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001770 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
1771 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001772#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001773 *phys = subpage_memory | IO_MEM_SUBPAGE;
1774 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
1775 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001776
1777 return mmio;
1778}
1779
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001780static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001781{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001782 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001783
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001784 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
1785 if (!io_mem_used[i]) {
1786 io_mem_used[i] = 1;
1787 return i;
1788 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001789 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001790 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001791}
1792
1793/* mem_read and mem_write are arrays of functions containing the
1794 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001795 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001796 If io_index is non zero, the corresponding io zone is
1797 modified. If it is zero, a new io zone is allocated. The return
1798 value can be used with cpu_register_physical_memory(). (-1) is
1799 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001800static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01001801 CPUReadMemoryFunc * const *mem_read,
1802 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001803 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001804{
1805 int i, subwidth = 0;
1806
1807 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001808 io_index = get_free_io_mem_idx();
1809 if (io_index == -1)
1810 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001811 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001812 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001813 if (io_index >= IO_MEM_NB_ENTRIES)
1814 return -1;
1815 }
1816
1817 for(i = 0;i < 3; i++) {
1818 if (!mem_read[i] || !mem_write[i])
1819 subwidth = IO_MEM_SUBWIDTH;
1820 io_mem_read[io_index][i] = mem_read[i];
1821 io_mem_write[io_index][i] = mem_write[i];
1822 }
1823 io_mem_opaque[io_index] = opaque;
1824 return (io_index << IO_MEM_SHIFT) | subwidth;
1825}
1826
David 'Digit' Turner36411062010-12-22 17:34:53 +01001827int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
1828 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001829 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001830{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001831 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001832}
1833
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001834void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001835{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001836 int i;
1837 int io_index = io_table_address >> IO_MEM_SHIFT;
1838
1839 for (i=0;i < 3; i++) {
1840 io_mem_read[io_index][i] = unassigned_mem_read[i];
1841 io_mem_write[io_index][i] = unassigned_mem_write[i];
1842 }
1843 io_mem_opaque[io_index] = NULL;
1844 io_mem_used[io_index] = 0;
1845}
1846
1847static void io_mem_init(void)
1848{
1849 int i;
1850
1851 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
1852 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
1853 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
1854 for (i=0; i<5; i++)
1855 io_mem_used[i] = 1;
1856
1857 io_mem_watch = cpu_register_io_memory(watch_mem_read,
1858 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001859}
1860
1861#endif /* !defined(CONFIG_USER_ONLY) */
1862
1863/* physical memory access (slow version, mainly for debug) */
1864#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001865void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001866 int len, int is_write)
1867{
1868 int l, flags;
1869 target_ulong page;
1870 void * p;
1871
1872 while (len > 0) {
1873 page = addr & TARGET_PAGE_MASK;
1874 l = (page + TARGET_PAGE_SIZE) - addr;
1875 if (l > len)
1876 l = len;
1877 flags = page_get_flags(page);
1878 if (!(flags & PAGE_VALID))
1879 return;
1880 if (is_write) {
1881 if (!(flags & PAGE_WRITE))
1882 return;
1883 /* XXX: this code should not depend on lock_user */
1884 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
1885 /* FIXME - should this return an error rather than just fail? */
1886 return;
1887 memcpy(p, buf, l);
1888 unlock_user(p, addr, l);
1889 } else {
1890 if (!(flags & PAGE_READ))
1891 return;
1892 /* XXX: this code should not depend on lock_user */
1893 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
1894 /* FIXME - should this return an error rather than just fail? */
1895 return;
1896 memcpy(buf, p, l);
1897 unlock_user(p, addr, 0);
1898 }
1899 len -= l;
1900 buf += l;
1901 addr += l;
1902 }
1903}
1904
1905#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07001906
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001907static void invalidate_and_set_dirty(hwaddr addr,
1908 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07001909{
1910 if (!cpu_physical_memory_is_dirty(addr)) {
1911 /* invalidate code */
1912 tb_invalidate_phys_page_range(addr, addr + length, 0);
1913 /* set dirty bit */
1914 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
1915 }
1916}
1917
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001918void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001919 int len, int is_write)
1920{
1921 int l, io_index;
1922 uint8_t *ptr;
1923 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001924 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001925 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001926 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001927 PhysPageDesc *p;
1928
1929 while (len > 0) {
1930 page = addr & TARGET_PAGE_MASK;
1931 l = (page + TARGET_PAGE_SIZE) - addr;
1932 if (l > len)
1933 l = len;
1934 p = phys_page_find(page >> TARGET_PAGE_BITS);
1935 if (!p) {
1936 pd = IO_MEM_UNASSIGNED;
1937 } else {
1938 pd = p->phys_offset;
1939 }
1940
1941 if (is_write) {
1942 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001943 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001944 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001945 if (p)
1946 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001947 /* XXX: could force cpu_single_env to NULL to avoid
1948 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001949 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001950 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001951 val = ldl_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001952 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001953 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001954 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001955 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001956 val = lduw_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001957 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001958 l = 2;
1959 } else {
1960 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001961 val = ldub_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001962 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001963 l = 1;
1964 }
1965 } else {
1966 unsigned long addr1;
1967 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
1968 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001969 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001970 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07001971 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001972 }
1973 } else {
1974 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
1975 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001976 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001977 /* I/O case */
1978 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001979 if (p)
1980 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
1981 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001982 /* 32 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001983 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001984 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001985 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001986 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001987 /* 16 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001988 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001989 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001990 l = 2;
1991 } else {
1992 /* 8 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001993 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001994 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001995 l = 1;
1996 }
1997 } else {
1998 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001999 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002000 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002001 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002002 }
2003 }
2004 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002005 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002006 addr += l;
2007 }
2008}
2009
2010/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002011void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002012 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002013{
2014 int l;
2015 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002016 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002017 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002018 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002019 PhysPageDesc *p;
2020
2021 while (len > 0) {
2022 page = addr & TARGET_PAGE_MASK;
2023 l = (page + TARGET_PAGE_SIZE) - addr;
2024 if (l > len)
2025 l = len;
2026 p = phys_page_find(page >> TARGET_PAGE_BITS);
2027 if (!p) {
2028 pd = IO_MEM_UNASSIGNED;
2029 } else {
2030 pd = p->phys_offset;
2031 }
2032
2033 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2034 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2035 !(pd & IO_MEM_ROMD)) {
2036 /* do nothing */
2037 } else {
2038 unsigned long addr1;
2039 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2040 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002041 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002042 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002043 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002044 }
2045 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002046 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002047 addr += l;
2048 }
2049}
2050
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002051typedef struct {
2052 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002053 hwaddr addr;
2054 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002055} BounceBuffer;
2056
2057static BounceBuffer bounce;
2058
2059typedef struct MapClient {
2060 void *opaque;
2061 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002062 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002063} MapClient;
2064
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002065static QLIST_HEAD(map_client_list, MapClient) map_client_list
2066 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002067
2068void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2069{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002070 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002071
2072 client->opaque = opaque;
2073 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002074 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002075 return client;
2076}
2077
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002078static void cpu_unregister_map_client(void *_client)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002079{
2080 MapClient *client = (MapClient *)_client;
2081
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002082 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002083 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002084}
2085
2086static void cpu_notify_map_clients(void)
2087{
2088 MapClient *client;
2089
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002090 while (!QLIST_EMPTY(&map_client_list)) {
2091 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002092 client->callback(client->opaque);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002093 cpu_unregister_map_client(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002094 }
2095}
2096
2097/* Map a physical memory region into a host virtual address.
2098 * May map a subset of the requested range, given by and returned in *plen.
2099 * May return NULL if resources needed to perform the mapping are exhausted.
2100 * Use only for reads OR writes - not for read-modify-write operations.
2101 * Use cpu_register_map_client() to know when retrying the map operation is
2102 * likely to succeed.
2103 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002104void *cpu_physical_memory_map(hwaddr addr,
2105 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002106 int is_write)
2107{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002108 hwaddr len = *plen;
2109 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002110 int l;
2111 uint8_t *ret = NULL;
2112 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002113 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002114 unsigned long pd;
2115 PhysPageDesc *p;
2116 unsigned long addr1;
2117
2118 while (len > 0) {
2119 page = addr & TARGET_PAGE_MASK;
2120 l = (page + TARGET_PAGE_SIZE) - addr;
2121 if (l > len)
2122 l = len;
2123 p = phys_page_find(page >> TARGET_PAGE_BITS);
2124 if (!p) {
2125 pd = IO_MEM_UNASSIGNED;
2126 } else {
2127 pd = p->phys_offset;
2128 }
2129
2130 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2131 if (done || bounce.buffer) {
2132 break;
2133 }
2134 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2135 bounce.addr = addr;
2136 bounce.len = l;
2137 if (!is_write) {
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002138 cpu_physical_memory_read(addr, bounce.buffer, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002139 }
2140 ptr = bounce.buffer;
2141 } else {
2142 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2143 ptr = qemu_get_ram_ptr(addr1);
2144 }
2145 if (!done) {
2146 ret = ptr;
2147 } else if (ret + done != ptr) {
2148 break;
2149 }
2150
2151 len -= l;
2152 addr += l;
2153 done += l;
2154 }
2155 *plen = done;
2156 return ret;
2157}
2158
2159/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2160 * Will also mark the memory as dirty if is_write == 1. access_len gives
2161 * the amount of memory that was actually read or written by the caller.
2162 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002163void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2164 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002165{
2166 if (buffer != bounce.buffer) {
2167 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002168 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002169 while (access_len) {
2170 unsigned l;
2171 l = TARGET_PAGE_SIZE;
2172 if (l > access_len)
2173 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002174 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002175 addr1 += l;
2176 access_len -= l;
2177 }
2178 }
2179 return;
2180 }
2181 if (is_write) {
2182 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2183 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002184 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002185 bounce.buffer = NULL;
2186 cpu_notify_map_clients();
2187}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002188
2189/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002190uint32_t ldl_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002191{
2192 int io_index;
2193 uint8_t *ptr;
2194 uint32_t val;
2195 unsigned long pd;
2196 PhysPageDesc *p;
2197
2198 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2199 if (!p) {
2200 pd = IO_MEM_UNASSIGNED;
2201 } else {
2202 pd = p->phys_offset;
2203 }
2204
2205 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2206 !(pd & IO_MEM_ROMD)) {
2207 /* I/O case */
2208 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002209 if (p)
2210 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002211 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2212 } else {
2213 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002214 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002215 (addr & ~TARGET_PAGE_MASK);
2216 val = ldl_p(ptr);
2217 }
2218 return val;
2219}
2220
2221/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002222uint64_t ldq_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002223{
2224 int io_index;
2225 uint8_t *ptr;
2226 uint64_t val;
2227 unsigned long pd;
2228 PhysPageDesc *p;
2229
2230 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2231 if (!p) {
2232 pd = IO_MEM_UNASSIGNED;
2233 } else {
2234 pd = p->phys_offset;
2235 }
2236
2237 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2238 !(pd & IO_MEM_ROMD)) {
2239 /* I/O case */
2240 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002241 if (p)
2242 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002243#ifdef TARGET_WORDS_BIGENDIAN
2244 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2245 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2246#else
2247 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2248 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2249#endif
2250 } else {
2251 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002252 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002253 (addr & ~TARGET_PAGE_MASK);
2254 val = ldq_p(ptr);
2255 }
2256 return val;
2257}
2258
2259/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002260uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002261{
2262 uint8_t val;
2263 cpu_physical_memory_read(addr, &val, 1);
2264 return val;
2265}
2266
2267/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002268uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002269{
2270 uint16_t val;
2271 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2272 return tswap16(val);
2273}
2274
2275/* warning: addr must be aligned. The ram page is not masked as dirty
2276 and the code inside is not invalidated. It is useful if the dirty
2277 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002278void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002279{
2280 int io_index;
2281 uint8_t *ptr;
2282 unsigned long pd;
2283 PhysPageDesc *p;
2284
2285 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2286 if (!p) {
2287 pd = IO_MEM_UNASSIGNED;
2288 } else {
2289 pd = p->phys_offset;
2290 }
2291
2292 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2293 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002294 if (p)
2295 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002296 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2297 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002298 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2299 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002300 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002301
2302 if (unlikely(in_migration)) {
2303 if (!cpu_physical_memory_is_dirty(addr1)) {
2304 /* invalidate code */
2305 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2306 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002307 cpu_physical_memory_set_dirty_flags(
2308 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002309 }
2310 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002311 }
2312}
2313
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002314void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002315{
2316 int io_index;
2317 uint8_t *ptr;
2318 unsigned long pd;
2319 PhysPageDesc *p;
2320
2321 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2322 if (!p) {
2323 pd = IO_MEM_UNASSIGNED;
2324 } else {
2325 pd = p->phys_offset;
2326 }
2327
2328 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2329 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002330 if (p)
2331 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002332#ifdef TARGET_WORDS_BIGENDIAN
2333 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2334 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2335#else
2336 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2337 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2338#endif
2339 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002340 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002341 (addr & ~TARGET_PAGE_MASK);
2342 stq_p(ptr, val);
2343 }
2344}
2345
2346/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002347void stl_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002348{
2349 int io_index;
2350 uint8_t *ptr;
2351 unsigned long pd;
2352 PhysPageDesc *p;
2353
2354 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2355 if (!p) {
2356 pd = IO_MEM_UNASSIGNED;
2357 } else {
2358 pd = p->phys_offset;
2359 }
2360
2361 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2362 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002363 if (p)
2364 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002365 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2366 } else {
2367 unsigned long addr1;
2368 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2369 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002370 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002371 stl_p(ptr, val);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002372 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002373 }
2374}
2375
2376/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002377void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002378{
2379 uint8_t v = val;
2380 cpu_physical_memory_write(addr, &v, 1);
2381}
2382
2383/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002384void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002385{
2386 uint16_t v = tswap16(val);
2387 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2388}
2389
2390/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002391void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002392{
2393 val = tswap64(val);
2394 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2395}
2396
2397#endif
2398
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002399/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002400int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002401 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002402{
2403 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002404 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002405 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002406 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002407
2408 while (len > 0) {
2409 page = addr & TARGET_PAGE_MASK;
2410 phys_addr = cpu_get_phys_page_debug(env, page);
2411 /* if no physical page mapped, return an error */
2412 if (phys_addr == -1)
2413 return -1;
2414 l = (page + TARGET_PAGE_SIZE) - addr;
2415 if (l > len)
2416 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002417 phys_addr += (addr & ~TARGET_PAGE_MASK);
2418#if !defined(CONFIG_USER_ONLY)
2419 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002420 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002421 else
2422#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002423 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002424 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002425 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002426 addr += l;
2427 }
2428 return 0;
2429}