blob: 222d7080c2b4e5660aacfd53838311e3f0b5b969 [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' Turner5d8f37a2009-09-14 14:32:27 -0700391 if (kvm_enabled())
392 kvm_update_guest_debug(env, 0);
393 else {
394 /* 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' Turnere2678e12014-01-16 15:56:43 +0100440static void 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
460/* mask must never be zero, except for A20 change call */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100461void cpu_interrupt(CPUOldState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700462{
463 int old_mask;
464
465 old_mask = env->interrupt_request;
466 env->interrupt_request |= mask;
467
468#ifndef CONFIG_USER_ONLY
469 /*
470 * If called from iothread context, wake the target cpu in
471 * case its halted.
472 */
473 if (!qemu_cpu_self(env)) {
474 qemu_cpu_kick(env);
475 return;
476 }
477#endif
478
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800479 if (use_icount) {
480 env->icount_decr.u16.high = 0xffff;
481#ifndef CONFIG_USER_ONLY
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800482 if (!can_do_io(env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700483 && (mask & ~old_mask) != 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800484 cpu_abort(env, "Raised interrupt while not in I/O function");
485 }
486#endif
487 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700488 cpu_unlink_tb(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800489 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800490}
491
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100492void cpu_reset_interrupt(CPUOldState *env, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800493{
494 env->interrupt_request &= ~mask;
495}
496
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100497void cpu_exit(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700498{
499 env->exit_request = 1;
500 cpu_unlink_tb(env);
501}
502
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100503void cpu_abort(CPUArchState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800504{
505 va_list ap;
506 va_list ap2;
507
508 va_start(ap, fmt);
509 va_copy(ap2, ap);
510 fprintf(stderr, "qemu: fatal: ");
511 vfprintf(stderr, fmt, ap);
512 fprintf(stderr, "\n");
513#ifdef TARGET_I386
514 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
515#else
516 cpu_dump_state(env, stderr, fprintf, 0);
517#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700518 if (qemu_log_enabled()) {
519 qemu_log("qemu: fatal: ");
520 qemu_log_vprintf(fmt, ap2);
521 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800522#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700523 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800524#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700525 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800526#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700527 qemu_log_flush();
528 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800529 }
530 va_end(ap2);
531 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +0100532#if defined(CONFIG_USER_ONLY)
533 {
534 struct sigaction act;
535 sigfillset(&act.sa_mask);
536 act.sa_handler = SIG_DFL;
537 sigaction(SIGABRT, &act, NULL);
538 }
539#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800540 abort();
541}
542
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100543CPUArchState *cpu_copy(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800544{
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100545 CPUArchState *new_env = cpu_init(env->cpu_model_str);
546 CPUArchState *next_cpu = new_env->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800547 int cpu_index = new_env->cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700548#if defined(TARGET_HAS_ICE)
549 CPUBreakpoint *bp;
550 CPUWatchpoint *wp;
551#endif
552
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100553 memcpy(new_env, env, sizeof(CPUOldState));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700554
555 /* Preserve chaining and index. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800556 new_env->next_cpu = next_cpu;
557 new_env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700558
559 /* Clone all break/watchpoints.
560 Note: Once we support ptrace with hw-debug register access, make sure
561 BP_CPU break/watchpoints are handled correctly on clone. */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700562 QTAILQ_INIT(&env->breakpoints);
563 QTAILQ_INIT(&env->watchpoints);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700564#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700565 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700566 cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
567 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700568 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700569 cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
570 wp->flags, NULL);
571 }
572#endif
573
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800574 return new_env;
575}
576
577#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100578static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
579{
580 RAMBlock *block;
581
582 /* The list is protected by the iothread lock here. */
583 block = ram_list.mru_block;
584 if (block && addr - block->offset < block->length) {
585 goto found;
586 }
587 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
588 if (addr - block->offset < block->length) {
589 goto found;
590 }
591 }
592
593 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
594 abort();
595
596found:
597 ram_list.mru_block = block;
598 return block;
599}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800600
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700601/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800602void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
603 int dirty_flags)
604{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100605 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800606 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200607 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608
609 start &= TARGET_PAGE_MASK;
610 end = TARGET_PAGE_ALIGN(end);
611
612 length = end - start;
613 if (length == 0)
614 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200615 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800616
617 /* we modify the TLB cache so that the dirty bit will be set again
618 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200619 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700620 /* Chek that we don't span multiple blocks - this breaks the
621 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200622 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700623 != (end - 1) - start) {
624 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800625 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700626
627 for(env = first_cpu; env != NULL; env = env->next_cpu) {
628 int mmu_idx;
629 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
630 for(i = 0; i < CPU_TLB_SIZE; i++)
631 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
632 start1, length);
633 }
634 }
635}
636
637int cpu_physical_memory_set_dirty_tracking(int enable)
638{
639 in_migration = enable;
640 if (kvm_enabled()) {
641 return kvm_set_migration_log(enable);
642 }
643 return 0;
644}
645
646int cpu_physical_memory_get_dirty_tracking(void)
647{
648 return in_migration;
649}
650
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100651int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
652 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700653{
654 int ret = 0;
655
656 if (kvm_enabled())
657 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
658 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800659}
660
661static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
662{
663 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700664 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800665
666 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700667 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
668 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200669 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800670 if (!cpu_physical_memory_is_dirty(ram_addr)) {
671 tlb_entry->addr_write |= TLB_NOTDIRTY;
672 }
673 }
674}
675
676/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100677void cpu_tlb_update_dirty(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800678{
679 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700680 int mmu_idx;
681 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
682 for(i = 0; i < CPU_TLB_SIZE; i++)
683 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
684 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800685}
686
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800687
688#else
689
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100690void tlb_flush(CPUArchState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800691{
692}
693
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100694void tlb_flush_page(CPUArchState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800695{
696}
697
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100698int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100699 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800700 int mmu_idx, int is_softmmu)
701{
702 return 0;
703}
704
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700705/*
706 * Walks guest process memory "regions" one by one
707 * and calls callback function 'fn' for each region.
708 */
709int walk_memory_regions(void *priv,
710 int (*fn)(void *, unsigned long, unsigned long, unsigned long))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800711{
712 unsigned long start, end;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700713 PageDesc *p = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800714 int i, j, prot, prot1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700715 int rc = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800716
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700717 start = end = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800718 prot = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700719
720 for (i = 0; i <= L1_SIZE; i++) {
721 p = (i < L1_SIZE) ? l1_map[i] : NULL;
722 for (j = 0; j < L2_SIZE; j++) {
723 prot1 = (p == NULL) ? 0 : p[j].flags;
724 /*
725 * "region" is one continuous chunk of memory
726 * that has same protection flags set.
727 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800728 if (prot1 != prot) {
729 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
730 if (start != -1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700731 rc = (*fn)(priv, start, end, prot);
732 /* callback can stop iteration by returning != 0 */
733 if (rc != 0)
734 return (rc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800735 }
736 if (prot1 != 0)
737 start = end;
738 else
739 start = -1;
740 prot = prot1;
741 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700742 if (p == NULL)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800743 break;
744 }
745 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700746 return (rc);
747}
748
749static int dump_region(void *priv, unsigned long start,
750 unsigned long end, unsigned long prot)
751{
752 FILE *f = (FILE *)priv;
753
754 (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
755 start, end, end - start,
756 ((prot & PAGE_READ) ? 'r' : '-'),
757 ((prot & PAGE_WRITE) ? 'w' : '-'),
758 ((prot & PAGE_EXEC) ? 'x' : '-'));
759
760 return (0);
761}
762
763/* dump memory mappings */
764void page_dump(FILE *f)
765{
766 (void) fprintf(f, "%-8s %-8s %-8s %s\n",
767 "start", "end", "size", "prot");
768 walk_memory_regions(f, dump_region);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800769}
770
771int page_get_flags(target_ulong address)
772{
773 PageDesc *p;
774
775 p = page_find(address >> TARGET_PAGE_BITS);
776 if (!p)
777 return 0;
778 return p->flags;
779}
780
David 'Digit' Turner36411062010-12-22 17:34:53 +0100781/* Modify the flags of a page and invalidate the code if necessary.
782 The flag PAGE_WRITE_ORG is positioned automatically depending
783 on PAGE_WRITE. The mmap_lock should already be held. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800784void page_set_flags(target_ulong start, target_ulong end, int flags)
785{
786 PageDesc *p;
787 target_ulong addr;
788
789 /* mmap_lock should already be held. */
790 start = start & TARGET_PAGE_MASK;
791 end = TARGET_PAGE_ALIGN(end);
792 if (flags & PAGE_WRITE)
793 flags |= PAGE_WRITE_ORG;
794 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
795 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
796 /* We may be called for host regions that are outside guest
797 address space. */
798 if (!p)
799 return;
800 /* if the write protection is set, then we invalidate the code
801 inside */
802 if (!(p->flags & PAGE_WRITE) &&
803 (flags & PAGE_WRITE) &&
804 p->first_tb) {
805 tb_invalidate_phys_page(addr, 0, NULL);
806 }
807 p->flags = flags;
808 }
809}
810
811int page_check_range(target_ulong start, target_ulong len, int flags)
812{
813 PageDesc *p;
814 target_ulong end;
815 target_ulong addr;
816
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700817 if (start + len < start)
818 /* we've wrapped around */
819 return -1;
820
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800821 end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
822 start = start & TARGET_PAGE_MASK;
823
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800824 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
825 p = page_find(addr >> TARGET_PAGE_BITS);
826 if( !p )
827 return -1;
828 if( !(p->flags & PAGE_VALID) )
829 return -1;
830
831 if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
832 return -1;
833 if (flags & PAGE_WRITE) {
834 if (!(p->flags & PAGE_WRITE_ORG))
835 return -1;
836 /* unprotect the page if it was put read-only because it
837 contains translated code */
838 if (!(p->flags & PAGE_WRITE)) {
839 if (!page_unprotect(addr, 0, NULL))
840 return -1;
841 }
842 return 0;
843 }
844 }
845 return 0;
846}
847
848/* called from signal handler: invalidate the code and unprotect the
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700849 page. Return TRUE if the fault was successfully handled. */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100850int page_unprotect(target_ulong address, uintptr_t pc, void *puc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800851{
852 unsigned int page_index, prot, pindex;
853 PageDesc *p, *p1;
854 target_ulong host_start, host_end, addr;
855
856 /* Technically this isn't safe inside a signal handler. However we
857 know this only ever happens in a synchronous SEGV handler, so in
858 practice it seems to be ok. */
859 mmap_lock();
860
861 host_start = address & qemu_host_page_mask;
862 page_index = host_start >> TARGET_PAGE_BITS;
863 p1 = page_find(page_index);
864 if (!p1) {
865 mmap_unlock();
866 return 0;
867 }
868 host_end = host_start + qemu_host_page_size;
869 p = p1;
870 prot = 0;
871 for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
872 prot |= p->flags;
873 p++;
874 }
875 /* if the page was really writable, then we change its
876 protection back to writable */
877 if (prot & PAGE_WRITE_ORG) {
878 pindex = (address - host_start) >> TARGET_PAGE_BITS;
879 if (!(p1[pindex].flags & PAGE_WRITE)) {
880 mprotect((void *)g2h(host_start), qemu_host_page_size,
881 (prot & PAGE_BITS) | PAGE_WRITE);
882 p1[pindex].flags |= PAGE_WRITE;
883 /* and since the content will be modified, we must invalidate
884 the corresponding translated code. */
885 tb_invalidate_phys_page(address, pc, puc);
886#ifdef DEBUG_TB_CHECK
887 tb_invalidate_check(address);
888#endif
889 mmap_unlock();
890 return 1;
891 }
892 }
893 mmap_unlock();
894 return 0;
895}
896
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100897static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800898 unsigned long addr, target_ulong vaddr)
899{
900}
901#endif /* defined(CONFIG_USER_ONLY) */
902
903#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700904
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800905static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700906 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100907static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700908 ram_addr_t orig_memory, ram_addr_t region_offset);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100909
910static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
911
912/*
913 * Set a custom physical guest memory alloator.
914 * Accelerators with unusual needs may need this. Hopefully, we can
915 * get rid of it eventually.
916 */
917void phys_mem_set_alloc(void *(*alloc)(size_t))
918{
919 phys_mem_alloc = alloc;
920}
921
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800922#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
923 need_subpage) \
924 do { \
925 if (addr > start_addr) \
926 start_addr2 = 0; \
927 else { \
928 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
929 if (start_addr2 > 0) \
930 need_subpage = 1; \
931 } \
932 \
933 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
934 end_addr2 = TARGET_PAGE_SIZE - 1; \
935 else { \
936 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
937 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
938 need_subpage = 1; \
939 } \
940 } while (0)
941
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700942/* register physical memory.
943 For RAM, 'size' must be a multiple of the target page size.
944 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700945 io memory page. The address used when calling the IO function is
946 the offset from the start of the region, plus region_offset. Both
947 start_addr and region_offset are rounded down to a page boundary
948 before calculating this offset. This should not be a problem unless
949 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100950void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700951 ram_addr_t size,
952 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200953 ram_addr_t region_offset,
954 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800955{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100956 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800957 PhysPageDesc *p;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100958 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800959 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200960 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800961
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700962 if (kvm_enabled())
963 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800964#ifdef CONFIG_HAX
965 if (hax_enabled())
966 hax_set_phys_mem(start_addr, size, phys_offset);
967#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700968
969 if (phys_offset == IO_MEM_UNASSIGNED) {
970 region_offset = start_addr;
971 }
972 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800973 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100974 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200975
976 addr = start_addr;
977 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800978 p = phys_page_find(addr >> TARGET_PAGE_BITS);
979 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
980 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100981 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800982 int need_subpage = 0;
983
984 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
985 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200986 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800987 if (!(orig_memory & IO_MEM_SUBPAGE)) {
988 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700989 &p->phys_offset, orig_memory,
990 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800991 } else {
992 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
993 >> IO_MEM_SHIFT];
994 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700995 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
996 region_offset);
997 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800998 } else {
999 p->phys_offset = phys_offset;
1000 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1001 (phys_offset & IO_MEM_ROMD))
1002 phys_offset += TARGET_PAGE_SIZE;
1003 }
1004 } else {
1005 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
1006 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001007 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001008 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001009 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001010 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001011 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001012 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001013 int need_subpage = 0;
1014
1015 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
1016 end_addr2, need_subpage);
1017
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001018 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001019 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001020 &p->phys_offset, IO_MEM_UNASSIGNED,
1021 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001022 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001023 phys_offset, region_offset);
1024 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001025 }
1026 }
1027 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001028 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001029 addr += TARGET_PAGE_SIZE;
1030 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001031
1032 /* since each CPU stores ram addresses in its TLB cache, we must
1033 reset the modified entries */
1034 /* XXX: slow ! */
1035 for(env = first_cpu; env != NULL; env = env->next_cpu) {
1036 tlb_flush(env, 1);
1037 }
1038}
1039
1040/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001041ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001042{
1043 PhysPageDesc *p;
1044
1045 p = phys_page_find(addr >> TARGET_PAGE_BITS);
1046 if (!p)
1047 return IO_MEM_UNASSIGNED;
1048 return p->phys_offset;
1049}
1050
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001051void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001052{
1053 if (kvm_enabled())
1054 kvm_coalesce_mmio_region(addr, size);
1055}
1056
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001057void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001058{
1059 if (kvm_enabled())
1060 kvm_uncoalesce_mmio_region(addr, size);
1061}
1062
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001063void qemu_mutex_lock_ramlist(void)
1064{
1065 qemu_mutex_lock(&ram_list.mutex);
1066}
1067
1068void qemu_mutex_unlock_ramlist(void)
1069{
1070 qemu_mutex_unlock(&ram_list.mutex);
1071}
1072
1073#if defined(__linux__) && !defined(CONFIG_ANDROID)
1074
1075#include <sys/vfs.h>
1076
1077#define HUGETLBFS_MAGIC 0x958458f6
1078
1079static long gethugepagesize(const char *path)
1080{
1081 struct statfs fs;
1082 int ret;
1083
1084 do {
1085 ret = statfs(path, &fs);
1086 } while (ret != 0 && errno == EINTR);
1087
1088 if (ret != 0) {
1089 perror(path);
1090 return 0;
1091 }
1092
1093 if (fs.f_type != HUGETLBFS_MAGIC)
1094 fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
1095
1096 return fs.f_bsize;
1097}
1098
1099static sigjmp_buf sigjump;
1100
1101static void sigbus_handler(int signal)
1102{
1103 siglongjmp(sigjump, 1);
1104}
1105
1106static void *file_ram_alloc(RAMBlock *block,
1107 ram_addr_t memory,
1108 const char *path)
1109{
1110 char *filename;
1111 char *sanitized_name;
1112 char *c;
1113 void *area;
1114 int fd;
1115 unsigned long hpagesize;
1116
1117 hpagesize = gethugepagesize(path);
1118 if (!hpagesize) {
1119 return NULL;
1120 }
1121
1122 if (memory < hpagesize) {
1123 return NULL;
1124 }
1125
1126 if (kvm_enabled() && !kvm_has_sync_mmu()) {
1127 fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
1128 return NULL;
1129 }
1130
1131 /* Make name safe to use with mkstemp by replacing '/' with '_'. */
1132 sanitized_name = g_strdup(block->mr->name);
1133 for (c = sanitized_name; *c != '\0'; c++) {
1134 if (*c == '/')
1135 *c = '_';
1136 }
1137
1138 filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
1139 sanitized_name);
1140 g_free(sanitized_name);
1141
1142 fd = mkstemp(filename);
1143 if (fd < 0) {
1144 perror("unable to create backing store for hugepages");
1145 g_free(filename);
1146 return NULL;
1147 }
1148 unlink(filename);
1149 g_free(filename);
1150
1151 memory = (memory+hpagesize-1) & ~(hpagesize-1);
1152
1153 /*
1154 * ftruncate is not supported by hugetlbfs in older
1155 * hosts, so don't bother bailing out on errors.
1156 * If anything goes wrong with it under other filesystems,
1157 * mmap will fail.
1158 */
1159 if (ftruncate(fd, memory))
1160 perror("ftruncate");
1161
1162 area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1163 if (area == MAP_FAILED) {
1164 perror("file_ram_alloc: can't mmap RAM pages");
1165 close(fd);
1166 return (NULL);
1167 }
1168
1169 if (mem_prealloc) {
1170 int ret, i;
1171 struct sigaction act, oldact;
1172 sigset_t set, oldset;
1173
1174 memset(&act, 0, sizeof(act));
1175 act.sa_handler = &sigbus_handler;
1176 act.sa_flags = 0;
1177
1178 ret = sigaction(SIGBUS, &act, &oldact);
1179 if (ret) {
1180 perror("file_ram_alloc: failed to install signal handler");
1181 exit(1);
1182 }
1183
1184 /* unblock SIGBUS */
1185 sigemptyset(&set);
1186 sigaddset(&set, SIGBUS);
1187 pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
1188
1189 if (sigsetjmp(sigjump, 1)) {
1190 fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
1191 exit(1);
1192 }
1193
1194 /* MAP_POPULATE silently ignores failures */
1195 for (i = 0; i < (memory/hpagesize)-1; i++) {
1196 memset(area + (hpagesize*i), 0, 1);
1197 }
1198
1199 ret = sigaction(SIGBUS, &oldact, NULL);
1200 if (ret) {
1201 perror("file_ram_alloc: failed to reinstall signal handler");
1202 exit(1);
1203 }
1204
1205 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1206 }
1207
1208 block->fd = fd;
1209 return area;
1210}
1211#else
1212static void *file_ram_alloc(RAMBlock *block,
1213 ram_addr_t memory,
1214 const char *path)
1215{
1216 fprintf(stderr, "-mem-path not supported on this host\n");
1217 exit(1);
1218}
1219#endif
1220
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001221static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001222{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001223 RAMBlock *block, *next_block;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001224 ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001225
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001226 assert(size != 0); /* it would hand out same offset multiple times */
1227
1228 if (QTAILQ_EMPTY(&ram_list.blocks))
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001229 return 0;
1230
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001231 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1232 ram_addr_t end, next = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001233
1234 end = block->offset + block->length;
1235
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001236 QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001237 if (next_block->offset >= end) {
1238 next = MIN(next, next_block->offset);
1239 }
1240 }
1241 if (next - end >= size && next - end < mingap) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001242 offset = end;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001243 mingap = next - end;
1244 }
1245 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001246
1247 if (offset == RAM_ADDR_MAX) {
1248 fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
1249 (uint64_t)size);
1250 abort();
1251 }
1252
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001253 return offset;
1254}
1255
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001256ram_addr_t last_ram_offset(void)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001257{
1258 RAMBlock *block;
1259 ram_addr_t last = 0;
1260
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001261 QTAILQ_FOREACH(block, &ram_list.blocks, next)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001262 last = MAX(last, block->offset + block->length);
1263
1264 return last;
1265}
1266
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001267static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
1268{
1269#ifndef CONFIG_ANDROID
1270 int ret;
1271
1272 /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
1273 if (!qemu_opt_get_bool(qemu_get_machine_opts(),
1274 "dump-guest-core", true)) {
1275 ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
1276 if (ret) {
1277 perror("qemu_madvise");
1278 fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
1279 "but dump_guest_core=off specified\n");
1280 }
1281 }
1282#endif // !CONFIG_ANDROID
1283}
1284
1285void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001286{
1287 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001288
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001289 new_block = NULL;
1290 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1291 if (block->offset == addr) {
1292 new_block = block;
1293 break;
1294 }
1295 }
1296 assert(new_block);
1297 assert(!new_block->idstr[0]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001298
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001299 if (dev) {
1300 char *id = qdev_get_dev_path(dev);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001301 if (id) {
1302 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001303 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001304 }
1305 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001306 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1307
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001308 /* This assumes the iothread lock is taken here too. */
1309 qemu_mutex_lock_ramlist();
1310 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1311 if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001312 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
1313 new_block->idstr);
1314 abort();
1315 }
1316 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001317 qemu_mutex_unlock_ramlist();
1318}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001319
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001320static int memory_try_enable_merging(void *addr, size_t len)
1321{
1322#ifndef CONFIG_ANDROID
1323 if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) {
1324 /* disabled by the user */
1325 return 0;
1326 }
1327
1328 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1329#else // CONFIG_ANDROID
1330 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1331#endif // CONFIG_ANDROID
1332}
1333
1334ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
1335 ram_addr_t size, void *host)
1336{
1337 RAMBlock *block, *new_block;
1338
1339 size = TARGET_PAGE_ALIGN(size);
1340 new_block = g_malloc0(sizeof(*new_block));
1341 new_block->fd = -1;
1342
1343 /* This assumes the iothread lock is taken here too. */
1344 qemu_mutex_lock_ramlist();
1345 //new_block->mr = mr;
1346 new_block->offset = find_ram_offset(size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001347 if (host) {
1348 new_block->host = host;
1349 new_block->flags |= RAM_PREALLOC_MASK;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001350 } else if (xen_enabled()) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001351 if (mem_path) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001352 fprintf(stderr, "-mem-path not supported with Xen\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001353 exit(1);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001354 }
1355 //xen_ram_alloc(new_block->offset, size, mr);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001356 } else {
1357 if (mem_path) {
1358 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1359 /*
1360 * file_ram_alloc() needs to allocate just like
1361 * phys_mem_alloc, but we haven't bothered to provide
1362 * a hook there.
1363 */
1364 fprintf(stderr,
1365 "-mem-path not supported with this accelerator\n");
1366 exit(1);
1367 }
1368 new_block->host = file_ram_alloc(new_block, size, mem_path);
1369 }
1370 if (!new_block->host) {
1371 new_block->host = phys_mem_alloc(size);
1372 if (!new_block->host) {
1373 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1374 name, strerror(errno));
1375 exit(1);
1376 }
David 'Digit' Turnerf2de2ae2014-03-07 16:25:58 +01001377#ifdef CONFIG_HAX
1378 if (hax_enabled()) {
1379 /*
1380 * In HAX, qemu allocates the virtual address, and HAX kernel
1381 * module populates the region with physical memory. Currently
1382 * we don’t populate guest memory on demand, thus we should
1383 * make sure that sufficient amount of memory is available in
1384 * advance.
1385 */
1386 int ret = hax_populate_ram(
1387 (uint64_t)(uintptr_t)new_block->host,
1388 (uint32_t)size);
1389 if (ret < 0) {
1390 fprintf(stderr, "Hax failed to populate ram\n");
1391 exit(-1);
1392 }
1393 }
1394#endif // CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001395 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001396 }
1397 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001398 new_block->length = size;
1399
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001400 /* Keep the list sorted from biggest to smallest block. */
1401 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1402 if (block->length < new_block->length) {
1403 break;
1404 }
1405 }
1406 if (block) {
1407 QTAILQ_INSERT_BEFORE(block, new_block, next);
1408 } else {
1409 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1410 }
1411 ram_list.mru_block = NULL;
1412
1413 ram_list.version++;
1414 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001415
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001416 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001417 last_ram_offset() >> TARGET_PAGE_BITS);
1418 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001419 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001420 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001421
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001422 //qemu_ram_setup_dump(new_block->host, size);
1423 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1424 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
1425
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001426 if (kvm_enabled())
1427 kvm_setup_guest_memory(new_block->host, size);
1428
1429 return new_block->offset;
1430}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001431
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001432ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1433{
1434 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1435}
1436
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001437void qemu_ram_free_from_ptr(ram_addr_t addr)
1438{
1439 RAMBlock *block;
1440
1441 /* This assumes the iothread lock is taken here too. */
1442 qemu_mutex_lock_ramlist();
1443 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1444 if (addr == block->offset) {
1445 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1446 ram_list.mru_block = NULL;
1447 ram_list.version++;
1448 g_free(block);
1449 break;
1450 }
1451 }
1452 qemu_mutex_unlock_ramlist();
1453}
1454
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001455void qemu_ram_free(ram_addr_t addr)
1456{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001457 RAMBlock *block;
1458
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001459 /* This assumes the iothread lock is taken here too. */
1460 qemu_mutex_lock_ramlist();
1461 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001462 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001463 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1464 ram_list.mru_block = NULL;
1465 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001466 if (block->flags & RAM_PREALLOC_MASK) {
1467 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001468 } else if (xen_enabled()) {
1469 //xen_invalidate_map_cache_entry(block->host);
1470#ifndef _WIN32
1471 } else if (block->fd >= 0) {
1472 munmap(block->host, block->length);
1473 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001474#endif
1475 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001476 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001477 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001478 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001479 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001480 }
1481 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001482 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001483
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001484}
1485
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001486#ifndef _WIN32
1487void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1488{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001489 RAMBlock *block;
1490 ram_addr_t offset;
1491 int flags;
1492 void *area, *vaddr;
1493
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001494 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001495 offset = addr - block->offset;
1496 if (offset < block->length) {
1497 vaddr = block->host + offset;
1498 if (block->flags & RAM_PREALLOC_MASK) {
1499 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001500 } else if (xen_enabled()) {
1501 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001502 } else {
1503 flags = MAP_FIXED;
1504 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001505 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001506#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001507 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1508 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001509#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001510 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001511#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001512 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1513 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001514 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001515 /*
1516 * Remap needs to match alloc. Accelerators that
1517 * set phys_mem_alloc never remap. If they did,
1518 * we'd need a remap hook here.
1519 */
1520 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1521
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001522 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1523 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1524 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001525 }
1526 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001527 fprintf(stderr, "Could not remap addr: "
1528 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001529 length, addr);
1530 exit(1);
1531 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001532 memory_try_enable_merging(vaddr, length);
1533 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001534 }
1535 return;
1536 }
1537 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001538}
1539#endif /* !_WIN32 */
1540
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001541/* Return a host pointer to ram allocated with qemu_ram_alloc.
1542 With the exception of the softmmu code in this file, this should
1543 only be used for local memory (e.g. video ram) that the device owns,
1544 and knows it isn't going to access beyond the end of the block.
1545
1546 It should not be used for general purpose DMA.
1547 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1548 */
1549void *qemu_get_ram_ptr(ram_addr_t addr)
1550{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001551 RAMBlock *block = qemu_get_ram_block(addr);
1552#if 0
1553 if (xen_enabled()) {
1554 /* We need to check if the requested address is in the RAM
1555 * because we don't want to map the entire memory in QEMU.
1556 * In that case just map until the end of the page.
1557 */
1558 if (block->offset == 0) {
1559 return xen_map_cache(addr, 0, 0);
1560 } else if (block->host == NULL) {
1561 block->host =
1562 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001563 }
1564 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001565#endif
1566 return block->host + (addr - block->offset);
1567}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001568
1569/* Return a host pointer to ram allocated with qemu_ram_alloc.
1570 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1571 */
1572void *qemu_safe_ram_ptr(ram_addr_t addr)
1573{
1574 RAMBlock *block;
1575
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001576 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001577 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001578 return block->host + (addr - block->offset);
1579 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001580 }
1581
1582 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1583 abort();
1584
1585 return NULL;
1586}
1587
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001588/* Some of the softmmu routines need to translate from a host pointer
1589 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001590int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1591{
1592 RAMBlock *block;
1593 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001594#if 0
1595 if (xen_enabled()) {
1596 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1597 return qemu_get_ram_block(*ram_addr)->mr;
1598 }
1599#endif
1600 block = ram_list.mru_block;
1601 if (block && block->host && host - block->host < block->length) {
1602 goto found;
1603 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001604
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001605 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1606 /* This case append when the block is not mapped. */
1607 if (block->host == NULL) {
1608 continue;
1609 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001610 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001611 goto found;
1612 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001613 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001614
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001615 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001616
1617found:
1618 *ram_addr = block->offset + (host - block->host);
1619 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001620}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001621
1622/* Some of the softmmu routines need to translate from a host pointer
1623 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001624ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001625{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001626 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001627
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001628 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001629 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1630 abort();
1631 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001632 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001633}
1634
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001635static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001636{
1637#ifdef DEBUG_UNASSIGNED
1638 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1639#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001640#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001641 do_unassigned_access(addr, 0, 0, 0, 1);
1642#endif
1643 return 0;
1644}
1645
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001646static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001647{
1648#ifdef DEBUG_UNASSIGNED
1649 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1650#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001651#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001652 do_unassigned_access(addr, 0, 0, 0, 2);
1653#endif
1654 return 0;
1655}
1656
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001657static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001658{
1659#ifdef DEBUG_UNASSIGNED
1660 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1661#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001662#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001663 do_unassigned_access(addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001664#endif
1665 return 0;
1666}
1667
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001668static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001669{
1670#ifdef DEBUG_UNASSIGNED
1671 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1672#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001673#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001674 do_unassigned_access(addr, 1, 0, 0, 1);
1675#endif
1676}
1677
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001678static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001679{
1680#ifdef DEBUG_UNASSIGNED
1681 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1682#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001683#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001684 do_unassigned_access(addr, 1, 0, 0, 2);
1685#endif
1686}
1687
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001688static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001689{
1690#ifdef DEBUG_UNASSIGNED
1691 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1692#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001693#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001694 do_unassigned_access(addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001695#endif
1696}
1697
David 'Digit' Turner36411062010-12-22 17:34:53 +01001698static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001699 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001700 unassigned_mem_readw,
1701 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001702};
1703
David 'Digit' Turner36411062010-12-22 17:34:53 +01001704static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001705 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001706 unassigned_mem_writew,
1707 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001708};
1709
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001710static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001711 uint32_t val)
1712{
1713 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001714 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001715 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1716#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001717 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001718 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001719#endif
1720 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001721 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001722 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001723 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001724 /* we remove the notdirty callback only if the code has been
1725 flushed */
1726 if (dirty_flags == 0xff)
1727 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1728}
1729
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001730static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001731 uint32_t val)
1732{
1733 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001734 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001735 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1736#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001737 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001738 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001739#endif
1740 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001741 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001742 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001743 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001744 /* we remove the notdirty callback only if the code has been
1745 flushed */
1746 if (dirty_flags == 0xff)
1747 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1748}
1749
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001750static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001751 uint32_t val)
1752{
1753 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001754 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001755 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1756#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001757 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001758 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001759#endif
1760 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001761 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001762 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001763 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001764 /* we remove the notdirty callback only if the code has been
1765 flushed */
1766 if (dirty_flags == 0xff)
1767 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1768}
1769
David 'Digit' Turner36411062010-12-22 17:34:53 +01001770static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001771 NULL, /* never used */
1772 NULL, /* never used */
1773 NULL, /* never used */
1774};
1775
David 'Digit' Turner36411062010-12-22 17:34:53 +01001776static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001777 notdirty_mem_writeb,
1778 notdirty_mem_writew,
1779 notdirty_mem_writel,
1780};
1781
1782/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001783static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001784{
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001785 CPUArchState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001786 target_ulong pc, cs_base;
1787 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001788 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001789 CPUWatchpoint *wp;
1790 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001791
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001792 if (env->watchpoint_hit) {
1793 /* We re-entered the check after replacing the TB. Now raise
1794 * the debug interrupt so that is will trigger after the
1795 * current instruction. */
1796 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
1797 return;
1798 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001799 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001800 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001801 if ((vaddr == (wp->vaddr & len_mask) ||
1802 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1803 wp->flags |= BP_WATCHPOINT_HIT;
1804 if (!env->watchpoint_hit) {
1805 env->watchpoint_hit = wp;
1806 tb = tb_find_pc(env->mem_io_pc);
1807 if (!tb) {
1808 cpu_abort(env, "check_watchpoint: could not find TB for "
1809 "pc=%p", (void *)env->mem_io_pc);
1810 }
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001811 cpu_restore_state(tb, env, env->mem_io_pc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001812 tb_phys_invalidate(tb, -1);
1813 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1814 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001815 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001816 } else {
1817 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1818 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001819 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001820 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001821 }
1822 } else {
1823 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001824 }
1825 }
1826}
1827
1828/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1829 so these check for a hit then pass through to the normal out-of-line
1830 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001831static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001832{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001833 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001834 return ldub_phys(addr);
1835}
1836
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001837static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001838{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001839 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001840 return lduw_phys(addr);
1841}
1842
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001843static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001844{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001845 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001846 return ldl_phys(addr);
1847}
1848
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001849static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001850 uint32_t val)
1851{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001852 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001853 stb_phys(addr, val);
1854}
1855
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001856static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001857 uint32_t val)
1858{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001859 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001860 stw_phys(addr, val);
1861}
1862
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001863static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001864 uint32_t val)
1865{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001866 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001867 stl_phys(addr, val);
1868}
1869
David 'Digit' Turner36411062010-12-22 17:34:53 +01001870static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001871 watch_mem_readb,
1872 watch_mem_readw,
1873 watch_mem_readl,
1874};
1875
David 'Digit' Turner36411062010-12-22 17:34:53 +01001876static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001877 watch_mem_writeb,
1878 watch_mem_writew,
1879 watch_mem_writel,
1880};
1881
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001882static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001883 unsigned int len)
1884{
1885 uint32_t ret;
1886 unsigned int idx;
1887
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001888 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001889#if defined(DEBUG_SUBPAGE)
1890 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1891 mmio, len, addr, idx);
1892#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001893 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1894 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001895
1896 return ret;
1897}
1898
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001899static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001900 uint32_t value, unsigned int len)
1901{
1902 unsigned int idx;
1903
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001904 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001905#if defined(DEBUG_SUBPAGE)
1906 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1907 mmio, len, addr, idx, value);
1908#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001909 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1910 addr + mmio->region_offset[idx][1][len],
1911 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001912}
1913
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001914static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001915{
1916#if defined(DEBUG_SUBPAGE)
1917 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1918#endif
1919
1920 return subpage_readlen(opaque, addr, 0);
1921}
1922
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001923static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001924 uint32_t value)
1925{
1926#if defined(DEBUG_SUBPAGE)
1927 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1928#endif
1929 subpage_writelen(opaque, addr, value, 0);
1930}
1931
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001932static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001933{
1934#if defined(DEBUG_SUBPAGE)
1935 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1936#endif
1937
1938 return subpage_readlen(opaque, addr, 1);
1939}
1940
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001941static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001942 uint32_t value)
1943{
1944#if defined(DEBUG_SUBPAGE)
1945 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1946#endif
1947 subpage_writelen(opaque, addr, value, 1);
1948}
1949
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001950static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001951{
1952#if defined(DEBUG_SUBPAGE)
1953 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1954#endif
1955
1956 return subpage_readlen(opaque, addr, 2);
1957}
1958
1959static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001960 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001961{
1962#if defined(DEBUG_SUBPAGE)
1963 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1964#endif
1965 subpage_writelen(opaque, addr, value, 2);
1966}
1967
David 'Digit' Turner36411062010-12-22 17:34:53 +01001968static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001969 &subpage_readb,
1970 &subpage_readw,
1971 &subpage_readl,
1972};
1973
David 'Digit' Turner36411062010-12-22 17:34:53 +01001974static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001975 &subpage_writeb,
1976 &subpage_writew,
1977 &subpage_writel,
1978};
1979
1980static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001981 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001982{
1983 int idx, eidx;
1984 unsigned int i;
1985
1986 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1987 return -1;
1988 idx = SUBPAGE_IDX(start);
1989 eidx = SUBPAGE_IDX(end);
1990#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001991 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 -08001992 mmio, start, end, idx, eidx, memory);
1993#endif
1994 memory >>= IO_MEM_SHIFT;
1995 for (; idx <= eidx; idx++) {
1996 for (i = 0; i < 4; i++) {
1997 if (io_mem_read[memory][i]) {
1998 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
1999 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002000 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002001 }
2002 if (io_mem_write[memory][i]) {
2003 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2004 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002005 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002006 }
2007 }
2008 }
2009
2010 return 0;
2011}
2012
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002013static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002014 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002015{
2016 subpage_t *mmio;
2017 int subpage_memory;
2018
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002019 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002020
2021 mmio->base = base;
2022 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002023#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002024 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2025 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002026#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002027 *phys = subpage_memory | IO_MEM_SUBPAGE;
2028 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
2029 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002030
2031 return mmio;
2032}
2033
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002034static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002035{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002036 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002037
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002038 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2039 if (!io_mem_used[i]) {
2040 io_mem_used[i] = 1;
2041 return i;
2042 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002043 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002044 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002045}
2046
2047/* mem_read and mem_write are arrays of functions containing the
2048 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002049 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002050 If io_index is non zero, the corresponding io zone is
2051 modified. If it is zero, a new io zone is allocated. The return
2052 value can be used with cpu_register_physical_memory(). (-1) is
2053 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002054static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01002055 CPUReadMemoryFunc * const *mem_read,
2056 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002057 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002058{
2059 int i, subwidth = 0;
2060
2061 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002062 io_index = get_free_io_mem_idx();
2063 if (io_index == -1)
2064 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002065 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002066 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002067 if (io_index >= IO_MEM_NB_ENTRIES)
2068 return -1;
2069 }
2070
2071 for(i = 0;i < 3; i++) {
2072 if (!mem_read[i] || !mem_write[i])
2073 subwidth = IO_MEM_SUBWIDTH;
2074 io_mem_read[io_index][i] = mem_read[i];
2075 io_mem_write[io_index][i] = mem_write[i];
2076 }
2077 io_mem_opaque[io_index] = opaque;
2078 return (io_index << IO_MEM_SHIFT) | subwidth;
2079}
2080
David 'Digit' Turner36411062010-12-22 17:34:53 +01002081int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
2082 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002083 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002084{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002085 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002086}
2087
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002088void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002089{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002090 int i;
2091 int io_index = io_table_address >> IO_MEM_SHIFT;
2092
2093 for (i=0;i < 3; i++) {
2094 io_mem_read[io_index][i] = unassigned_mem_read[i];
2095 io_mem_write[io_index][i] = unassigned_mem_write[i];
2096 }
2097 io_mem_opaque[io_index] = NULL;
2098 io_mem_used[io_index] = 0;
2099}
2100
2101static void io_mem_init(void)
2102{
2103 int i;
2104
2105 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
2106 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
2107 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
2108 for (i=0; i<5; i++)
2109 io_mem_used[i] = 1;
2110
2111 io_mem_watch = cpu_register_io_memory(watch_mem_read,
2112 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002113}
2114
2115#endif /* !defined(CONFIG_USER_ONLY) */
2116
2117/* physical memory access (slow version, mainly for debug) */
2118#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002119void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002120 int len, int is_write)
2121{
2122 int l, flags;
2123 target_ulong page;
2124 void * p;
2125
2126 while (len > 0) {
2127 page = addr & TARGET_PAGE_MASK;
2128 l = (page + TARGET_PAGE_SIZE) - addr;
2129 if (l > len)
2130 l = len;
2131 flags = page_get_flags(page);
2132 if (!(flags & PAGE_VALID))
2133 return;
2134 if (is_write) {
2135 if (!(flags & PAGE_WRITE))
2136 return;
2137 /* XXX: this code should not depend on lock_user */
2138 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
2139 /* FIXME - should this return an error rather than just fail? */
2140 return;
2141 memcpy(p, buf, l);
2142 unlock_user(p, addr, l);
2143 } else {
2144 if (!(flags & PAGE_READ))
2145 return;
2146 /* XXX: this code should not depend on lock_user */
2147 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
2148 /* FIXME - should this return an error rather than just fail? */
2149 return;
2150 memcpy(buf, p, l);
2151 unlock_user(p, addr, 0);
2152 }
2153 len -= l;
2154 buf += l;
2155 addr += l;
2156 }
2157}
2158
2159#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07002160
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002161static void invalidate_and_set_dirty(hwaddr addr,
2162 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07002163{
2164 if (!cpu_physical_memory_is_dirty(addr)) {
2165 /* invalidate code */
2166 tb_invalidate_phys_page_range(addr, addr + length, 0);
2167 /* set dirty bit */
2168 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
2169 }
2170}
2171
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002172void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002173 int len, int is_write)
2174{
2175 int l, io_index;
2176 uint8_t *ptr;
2177 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002178 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002179 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002180 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002181 PhysPageDesc *p;
2182
2183 while (len > 0) {
2184 page = addr & TARGET_PAGE_MASK;
2185 l = (page + TARGET_PAGE_SIZE) - addr;
2186 if (l > len)
2187 l = len;
2188 p = phys_page_find(page >> TARGET_PAGE_BITS);
2189 if (!p) {
2190 pd = IO_MEM_UNASSIGNED;
2191 } else {
2192 pd = p->phys_offset;
2193 }
2194
2195 if (is_write) {
2196 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002197 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002198 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002199 if (p)
2200 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002201 /* XXX: could force cpu_single_env to NULL to avoid
2202 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002203 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002204 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002205 val = ldl_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002206 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002207 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002208 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002209 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002210 val = lduw_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002211 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002212 l = 2;
2213 } else {
2214 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002215 val = ldub_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002216 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002217 l = 1;
2218 }
2219 } else {
2220 unsigned long addr1;
2221 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2222 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002223 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002224 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002225 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002226 }
2227 } else {
2228 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2229 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002230 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002231 /* I/O case */
2232 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002233 if (p)
2234 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2235 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002236 /* 32 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002237 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002238 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002239 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002240 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002241 /* 16 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002242 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002243 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002244 l = 2;
2245 } else {
2246 /* 8 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002247 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002248 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002249 l = 1;
2250 }
2251 } else {
2252 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002253 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002254 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002255 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002256 }
2257 }
2258 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002259 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002260 addr += l;
2261 }
2262}
2263
2264/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002265void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002266 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002267{
2268 int l;
2269 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002270 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002271 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002272 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002273 PhysPageDesc *p;
2274
2275 while (len > 0) {
2276 page = addr & TARGET_PAGE_MASK;
2277 l = (page + TARGET_PAGE_SIZE) - addr;
2278 if (l > len)
2279 l = len;
2280 p = phys_page_find(page >> TARGET_PAGE_BITS);
2281 if (!p) {
2282 pd = IO_MEM_UNASSIGNED;
2283 } else {
2284 pd = p->phys_offset;
2285 }
2286
2287 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2288 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2289 !(pd & IO_MEM_ROMD)) {
2290 /* do nothing */
2291 } else {
2292 unsigned long addr1;
2293 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2294 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002295 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002296 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002297 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002298 }
2299 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002300 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002301 addr += l;
2302 }
2303}
2304
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002305typedef struct {
2306 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002307 hwaddr addr;
2308 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002309} BounceBuffer;
2310
2311static BounceBuffer bounce;
2312
2313typedef struct MapClient {
2314 void *opaque;
2315 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002316 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002317} MapClient;
2318
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002319static QLIST_HEAD(map_client_list, MapClient) map_client_list
2320 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002321
2322void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2323{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002324 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002325
2326 client->opaque = opaque;
2327 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002328 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002329 return client;
2330}
2331
2332void cpu_unregister_map_client(void *_client)
2333{
2334 MapClient *client = (MapClient *)_client;
2335
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002336 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002337 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002338}
2339
2340static void cpu_notify_map_clients(void)
2341{
2342 MapClient *client;
2343
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002344 while (!QLIST_EMPTY(&map_client_list)) {
2345 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002346 client->callback(client->opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002347 QLIST_REMOVE(client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002348 }
2349}
2350
2351/* Map a physical memory region into a host virtual address.
2352 * May map a subset of the requested range, given by and returned in *plen.
2353 * May return NULL if resources needed to perform the mapping are exhausted.
2354 * Use only for reads OR writes - not for read-modify-write operations.
2355 * Use cpu_register_map_client() to know when retrying the map operation is
2356 * likely to succeed.
2357 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002358void *cpu_physical_memory_map(hwaddr addr,
2359 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002360 int is_write)
2361{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002362 hwaddr len = *plen;
2363 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002364 int l;
2365 uint8_t *ret = NULL;
2366 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002367 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002368 unsigned long pd;
2369 PhysPageDesc *p;
2370 unsigned long addr1;
2371
2372 while (len > 0) {
2373 page = addr & TARGET_PAGE_MASK;
2374 l = (page + TARGET_PAGE_SIZE) - addr;
2375 if (l > len)
2376 l = len;
2377 p = phys_page_find(page >> TARGET_PAGE_BITS);
2378 if (!p) {
2379 pd = IO_MEM_UNASSIGNED;
2380 } else {
2381 pd = p->phys_offset;
2382 }
2383
2384 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2385 if (done || bounce.buffer) {
2386 break;
2387 }
2388 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2389 bounce.addr = addr;
2390 bounce.len = l;
2391 if (!is_write) {
2392 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
2393 }
2394 ptr = bounce.buffer;
2395 } else {
2396 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2397 ptr = qemu_get_ram_ptr(addr1);
2398 }
2399 if (!done) {
2400 ret = ptr;
2401 } else if (ret + done != ptr) {
2402 break;
2403 }
2404
2405 len -= l;
2406 addr += l;
2407 done += l;
2408 }
2409 *plen = done;
2410 return ret;
2411}
2412
2413/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2414 * Will also mark the memory as dirty if is_write == 1. access_len gives
2415 * the amount of memory that was actually read or written by the caller.
2416 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002417void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2418 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002419{
2420 if (buffer != bounce.buffer) {
2421 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002422 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002423 while (access_len) {
2424 unsigned l;
2425 l = TARGET_PAGE_SIZE;
2426 if (l > access_len)
2427 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002428 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002429 addr1 += l;
2430 access_len -= l;
2431 }
2432 }
2433 return;
2434 }
2435 if (is_write) {
2436 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2437 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002438 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002439 bounce.buffer = NULL;
2440 cpu_notify_map_clients();
2441}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002442
2443/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002444uint32_t ldl_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002445{
2446 int io_index;
2447 uint8_t *ptr;
2448 uint32_t val;
2449 unsigned long pd;
2450 PhysPageDesc *p;
2451
2452 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2453 if (!p) {
2454 pd = IO_MEM_UNASSIGNED;
2455 } else {
2456 pd = p->phys_offset;
2457 }
2458
2459 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2460 !(pd & IO_MEM_ROMD)) {
2461 /* I/O case */
2462 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002463 if (p)
2464 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002465 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2466 } else {
2467 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002468 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002469 (addr & ~TARGET_PAGE_MASK);
2470 val = ldl_p(ptr);
2471 }
2472 return val;
2473}
2474
2475/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002476uint64_t ldq_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002477{
2478 int io_index;
2479 uint8_t *ptr;
2480 uint64_t val;
2481 unsigned long pd;
2482 PhysPageDesc *p;
2483
2484 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2485 if (!p) {
2486 pd = IO_MEM_UNASSIGNED;
2487 } else {
2488 pd = p->phys_offset;
2489 }
2490
2491 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2492 !(pd & IO_MEM_ROMD)) {
2493 /* I/O case */
2494 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002495 if (p)
2496 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002497#ifdef TARGET_WORDS_BIGENDIAN
2498 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2499 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2500#else
2501 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2502 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2503#endif
2504 } else {
2505 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002506 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002507 (addr & ~TARGET_PAGE_MASK);
2508 val = ldq_p(ptr);
2509 }
2510 return val;
2511}
2512
2513/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002514uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002515{
2516 uint8_t val;
2517 cpu_physical_memory_read(addr, &val, 1);
2518 return val;
2519}
2520
2521/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002522uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002523{
2524 uint16_t val;
2525 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2526 return tswap16(val);
2527}
2528
2529/* warning: addr must be aligned. The ram page is not masked as dirty
2530 and the code inside is not invalidated. It is useful if the dirty
2531 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002532void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002533{
2534 int io_index;
2535 uint8_t *ptr;
2536 unsigned long pd;
2537 PhysPageDesc *p;
2538
2539 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2540 if (!p) {
2541 pd = IO_MEM_UNASSIGNED;
2542 } else {
2543 pd = p->phys_offset;
2544 }
2545
2546 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2547 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002548 if (p)
2549 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002550 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2551 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002552 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2553 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002554 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002555
2556 if (unlikely(in_migration)) {
2557 if (!cpu_physical_memory_is_dirty(addr1)) {
2558 /* invalidate code */
2559 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2560 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002561 cpu_physical_memory_set_dirty_flags(
2562 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002563 }
2564 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002565 }
2566}
2567
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002568void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002569{
2570 int io_index;
2571 uint8_t *ptr;
2572 unsigned long pd;
2573 PhysPageDesc *p;
2574
2575 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2576 if (!p) {
2577 pd = IO_MEM_UNASSIGNED;
2578 } else {
2579 pd = p->phys_offset;
2580 }
2581
2582 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2583 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002584 if (p)
2585 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002586#ifdef TARGET_WORDS_BIGENDIAN
2587 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2588 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2589#else
2590 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2591 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2592#endif
2593 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002594 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002595 (addr & ~TARGET_PAGE_MASK);
2596 stq_p(ptr, val);
2597 }
2598}
2599
2600/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002601void stl_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002602{
2603 int io_index;
2604 uint8_t *ptr;
2605 unsigned long pd;
2606 PhysPageDesc *p;
2607
2608 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2609 if (!p) {
2610 pd = IO_MEM_UNASSIGNED;
2611 } else {
2612 pd = p->phys_offset;
2613 }
2614
2615 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2616 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002617 if (p)
2618 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002619 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2620 } else {
2621 unsigned long addr1;
2622 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2623 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002624 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002625 stl_p(ptr, val);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002626 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002627 }
2628}
2629
2630/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002631void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002632{
2633 uint8_t v = val;
2634 cpu_physical_memory_write(addr, &v, 1);
2635}
2636
2637/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002638void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002639{
2640 uint16_t v = tswap16(val);
2641 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2642}
2643
2644/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002645void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002646{
2647 val = tswap64(val);
2648 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2649}
2650
2651#endif
2652
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002653/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002654int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002655 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002656{
2657 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002658 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002659 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002660 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002661
2662 while (len > 0) {
2663 page = addr & TARGET_PAGE_MASK;
2664 phys_addr = cpu_get_phys_page_debug(env, page);
2665 /* if no physical page mapped, return an error */
2666 if (phys_addr == -1)
2667 return -1;
2668 l = (page + TARGET_PAGE_SIZE) - addr;
2669 if (l > len)
2670 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002671 phys_addr += (addr & ~TARGET_PAGE_MASK);
2672#if !defined(CONFIG_USER_ONLY)
2673 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002674 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002675 else
2676#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002677 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002678 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002679 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002680 addr += l;
2681 }
2682 return 0;
2683}