blob: 5f5565283c01818f72cbc1f80e587c9692128940 [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);
Jun Nakajimaa381ef02011-12-17 19:13:25 -08001356#ifdef CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001357 } else if (hax_enabled()) {
Jun Nakajimaa381ef02011-12-17 19:13:25 -08001358 /*
1359 * In HAX, qemu allocates the virtual address, and HAX kernel
1360 * module populates the region with physical memory. Currently
1361 * we don’t populate guest memory on demand, thus we should
1362 * make sure that sufficient amount of memory is available in
1363 * advance.
1364 */
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001365 int ret = hax_populate_ram(
1366 (uint64_t)(uintptr_t)new_block->host,
1367 (uint32_t)size);
1368 if (ret < 0) {
1369 fprintf(stderr, "Hax failed to populate ram\n");
1370 exit(-1);
Jun Nakajimaa381ef02011-12-17 19:13:25 -08001371 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001372#endif // CONFIG_HAX
1373 } else {
1374 if (mem_path) {
1375 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1376 /*
1377 * file_ram_alloc() needs to allocate just like
1378 * phys_mem_alloc, but we haven't bothered to provide
1379 * a hook there.
1380 */
1381 fprintf(stderr,
1382 "-mem-path not supported with this accelerator\n");
1383 exit(1);
1384 }
1385 new_block->host = file_ram_alloc(new_block, size, mem_path);
1386 }
1387 if (!new_block->host) {
1388 new_block->host = phys_mem_alloc(size);
1389 if (!new_block->host) {
1390 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1391 name, strerror(errno));
1392 exit(1);
1393 }
1394 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001395 }
1396 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001397 new_block->length = size;
1398
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001399 /* Keep the list sorted from biggest to smallest block. */
1400 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1401 if (block->length < new_block->length) {
1402 break;
1403 }
1404 }
1405 if (block) {
1406 QTAILQ_INSERT_BEFORE(block, new_block, next);
1407 } else {
1408 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1409 }
1410 ram_list.mru_block = NULL;
1411
1412 ram_list.version++;
1413 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001414
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001415 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001416 last_ram_offset() >> TARGET_PAGE_BITS);
1417 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001418 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001419 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001420
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001421 //qemu_ram_setup_dump(new_block->host, size);
1422 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1423 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
1424
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001425 if (kvm_enabled())
1426 kvm_setup_guest_memory(new_block->host, size);
1427
1428 return new_block->offset;
1429}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001430
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001431ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1432{
1433 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1434}
1435
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001436void qemu_ram_free_from_ptr(ram_addr_t addr)
1437{
1438 RAMBlock *block;
1439
1440 /* This assumes the iothread lock is taken here too. */
1441 qemu_mutex_lock_ramlist();
1442 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1443 if (addr == block->offset) {
1444 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1445 ram_list.mru_block = NULL;
1446 ram_list.version++;
1447 g_free(block);
1448 break;
1449 }
1450 }
1451 qemu_mutex_unlock_ramlist();
1452}
1453
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001454void qemu_ram_free(ram_addr_t addr)
1455{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001456 RAMBlock *block;
1457
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001458 /* This assumes the iothread lock is taken here too. */
1459 qemu_mutex_lock_ramlist();
1460 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001461 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001462 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1463 ram_list.mru_block = NULL;
1464 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001465 if (block->flags & RAM_PREALLOC_MASK) {
1466 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001467 } else if (xen_enabled()) {
1468 //xen_invalidate_map_cache_entry(block->host);
1469#ifndef _WIN32
1470 } else if (block->fd >= 0) {
1471 munmap(block->host, block->length);
1472 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001473#endif
1474 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001475 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001476 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001477 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001478 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001479 }
1480 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001481 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001482
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001483}
1484
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001485#ifndef _WIN32
1486void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1487{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001488 RAMBlock *block;
1489 ram_addr_t offset;
1490 int flags;
1491 void *area, *vaddr;
1492
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001493 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001494 offset = addr - block->offset;
1495 if (offset < block->length) {
1496 vaddr = block->host + offset;
1497 if (block->flags & RAM_PREALLOC_MASK) {
1498 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001499 } else if (xen_enabled()) {
1500 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001501 } else {
1502 flags = MAP_FIXED;
1503 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001504 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001505#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001506 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1507 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001508#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001509 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001510#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001511 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1512 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001513 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001514 /*
1515 * Remap needs to match alloc. Accelerators that
1516 * set phys_mem_alloc never remap. If they did,
1517 * we'd need a remap hook here.
1518 */
1519 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1520
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001521 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1522 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1523 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001524 }
1525 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001526 fprintf(stderr, "Could not remap addr: "
1527 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001528 length, addr);
1529 exit(1);
1530 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001531 memory_try_enable_merging(vaddr, length);
1532 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001533 }
1534 return;
1535 }
1536 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001537}
1538#endif /* !_WIN32 */
1539
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001540/* Return a host pointer to ram allocated with qemu_ram_alloc.
1541 With the exception of the softmmu code in this file, this should
1542 only be used for local memory (e.g. video ram) that the device owns,
1543 and knows it isn't going to access beyond the end of the block.
1544
1545 It should not be used for general purpose DMA.
1546 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1547 */
1548void *qemu_get_ram_ptr(ram_addr_t addr)
1549{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001550 RAMBlock *block = qemu_get_ram_block(addr);
1551#if 0
1552 if (xen_enabled()) {
1553 /* We need to check if the requested address is in the RAM
1554 * because we don't want to map the entire memory in QEMU.
1555 * In that case just map until the end of the page.
1556 */
1557 if (block->offset == 0) {
1558 return xen_map_cache(addr, 0, 0);
1559 } else if (block->host == NULL) {
1560 block->host =
1561 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001562 }
1563 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001564#endif
1565 return block->host + (addr - block->offset);
1566}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001567
1568/* Return a host pointer to ram allocated with qemu_ram_alloc.
1569 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1570 */
1571void *qemu_safe_ram_ptr(ram_addr_t addr)
1572{
1573 RAMBlock *block;
1574
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001575 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001576 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001577 return block->host + (addr - block->offset);
1578 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001579 }
1580
1581 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1582 abort();
1583
1584 return NULL;
1585}
1586
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001587/* Some of the softmmu routines need to translate from a host pointer
1588 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001589int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1590{
1591 RAMBlock *block;
1592 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001593#if 0
1594 if (xen_enabled()) {
1595 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1596 return qemu_get_ram_block(*ram_addr)->mr;
1597 }
1598#endif
1599 block = ram_list.mru_block;
1600 if (block && block->host && host - block->host < block->length) {
1601 goto found;
1602 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001603
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001604 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1605 /* This case append when the block is not mapped. */
1606 if (block->host == NULL) {
1607 continue;
1608 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001609 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001610 goto found;
1611 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001612 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001613
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001614 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001615
1616found:
1617 *ram_addr = block->offset + (host - block->host);
1618 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001619}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001620
1621/* Some of the softmmu routines need to translate from a host pointer
1622 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001623ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001624{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001625 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001626
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001627 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001628 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1629 abort();
1630 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001631 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001632}
1633
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001634static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001635{
1636#ifdef DEBUG_UNASSIGNED
1637 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1638#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001639#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001640 do_unassigned_access(addr, 0, 0, 0, 1);
1641#endif
1642 return 0;
1643}
1644
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001645static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001646{
1647#ifdef DEBUG_UNASSIGNED
1648 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1649#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001650#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001651 do_unassigned_access(addr, 0, 0, 0, 2);
1652#endif
1653 return 0;
1654}
1655
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001656static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001657{
1658#ifdef DEBUG_UNASSIGNED
1659 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1660#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001661#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001662 do_unassigned_access(addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001663#endif
1664 return 0;
1665}
1666
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001667static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001668{
1669#ifdef DEBUG_UNASSIGNED
1670 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1671#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001672#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001673 do_unassigned_access(addr, 1, 0, 0, 1);
1674#endif
1675}
1676
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001677static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001678{
1679#ifdef DEBUG_UNASSIGNED
1680 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1681#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001682#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001683 do_unassigned_access(addr, 1, 0, 0, 2);
1684#endif
1685}
1686
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001687static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001688{
1689#ifdef DEBUG_UNASSIGNED
1690 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1691#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001692#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001693 do_unassigned_access(addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001694#endif
1695}
1696
David 'Digit' Turner36411062010-12-22 17:34:53 +01001697static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001698 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001699 unassigned_mem_readw,
1700 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001701};
1702
David 'Digit' Turner36411062010-12-22 17:34:53 +01001703static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001704 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001705 unassigned_mem_writew,
1706 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001707};
1708
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001709static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001710 uint32_t val)
1711{
1712 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001713 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001714 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1715#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001716 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001717 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001718#endif
1719 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001720 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001721 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001722 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001723 /* we remove the notdirty callback only if the code has been
1724 flushed */
1725 if (dirty_flags == 0xff)
1726 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1727}
1728
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001729static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001730 uint32_t val)
1731{
1732 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001733 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001734 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1735#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001736 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001737 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001738#endif
1739 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001740 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001741 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001742 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001743 /* we remove the notdirty callback only if the code has been
1744 flushed */
1745 if (dirty_flags == 0xff)
1746 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1747}
1748
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001749static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001750 uint32_t val)
1751{
1752 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001753 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001754 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1755#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001756 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001757 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001758#endif
1759 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001760 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001761 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001762 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001763 /* we remove the notdirty callback only if the code has been
1764 flushed */
1765 if (dirty_flags == 0xff)
1766 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1767}
1768
David 'Digit' Turner36411062010-12-22 17:34:53 +01001769static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001770 NULL, /* never used */
1771 NULL, /* never used */
1772 NULL, /* never used */
1773};
1774
David 'Digit' Turner36411062010-12-22 17:34:53 +01001775static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001776 notdirty_mem_writeb,
1777 notdirty_mem_writew,
1778 notdirty_mem_writel,
1779};
1780
1781/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001782static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001783{
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001784 CPUArchState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001785 target_ulong pc, cs_base;
1786 TranslationBlock *tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001787 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001788 CPUWatchpoint *wp;
1789 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001790
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001791 if (env->watchpoint_hit) {
1792 /* We re-entered the check after replacing the TB. Now raise
1793 * the debug interrupt so that is will trigger after the
1794 * current instruction. */
1795 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
1796 return;
1797 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001798 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001799 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001800 if ((vaddr == (wp->vaddr & len_mask) ||
1801 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1802 wp->flags |= BP_WATCHPOINT_HIT;
1803 if (!env->watchpoint_hit) {
1804 env->watchpoint_hit = wp;
1805 tb = tb_find_pc(env->mem_io_pc);
1806 if (!tb) {
1807 cpu_abort(env, "check_watchpoint: could not find TB for "
1808 "pc=%p", (void *)env->mem_io_pc);
1809 }
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001810 cpu_restore_state(tb, env, env->mem_io_pc);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001811 tb_phys_invalidate(tb, -1);
1812 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1813 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001814 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001815 } else {
1816 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1817 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001818 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001819 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001820 }
1821 } else {
1822 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001823 }
1824 }
1825}
1826
1827/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1828 so these check for a hit then pass through to the normal out-of-line
1829 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001830static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001831{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001832 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001833 return ldub_phys(addr);
1834}
1835
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001836static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001837{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001838 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001839 return lduw_phys(addr);
1840}
1841
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001842static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001843{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001844 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001845 return ldl_phys(addr);
1846}
1847
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001848static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001849 uint32_t val)
1850{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001851 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001852 stb_phys(addr, val);
1853}
1854
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001855static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001856 uint32_t val)
1857{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001858 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001859 stw_phys(addr, val);
1860}
1861
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001862static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001863 uint32_t val)
1864{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001865 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001866 stl_phys(addr, val);
1867}
1868
David 'Digit' Turner36411062010-12-22 17:34:53 +01001869static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001870 watch_mem_readb,
1871 watch_mem_readw,
1872 watch_mem_readl,
1873};
1874
David 'Digit' Turner36411062010-12-22 17:34:53 +01001875static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001876 watch_mem_writeb,
1877 watch_mem_writew,
1878 watch_mem_writel,
1879};
1880
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001881static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001882 unsigned int len)
1883{
1884 uint32_t ret;
1885 unsigned int idx;
1886
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001887 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001888#if defined(DEBUG_SUBPAGE)
1889 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1890 mmio, len, addr, idx);
1891#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001892 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1893 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001894
1895 return ret;
1896}
1897
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001898static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001899 uint32_t value, unsigned int len)
1900{
1901 unsigned int idx;
1902
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001903 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001904#if defined(DEBUG_SUBPAGE)
1905 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1906 mmio, len, addr, idx, value);
1907#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001908 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1909 addr + mmio->region_offset[idx][1][len],
1910 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001911}
1912
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001913static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001914{
1915#if defined(DEBUG_SUBPAGE)
1916 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1917#endif
1918
1919 return subpage_readlen(opaque, addr, 0);
1920}
1921
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001922static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001923 uint32_t value)
1924{
1925#if defined(DEBUG_SUBPAGE)
1926 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1927#endif
1928 subpage_writelen(opaque, addr, value, 0);
1929}
1930
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001931static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001932{
1933#if defined(DEBUG_SUBPAGE)
1934 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1935#endif
1936
1937 return subpage_readlen(opaque, addr, 1);
1938}
1939
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001940static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001941 uint32_t value)
1942{
1943#if defined(DEBUG_SUBPAGE)
1944 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1945#endif
1946 subpage_writelen(opaque, addr, value, 1);
1947}
1948
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001949static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001950{
1951#if defined(DEBUG_SUBPAGE)
1952 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1953#endif
1954
1955 return subpage_readlen(opaque, addr, 2);
1956}
1957
1958static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001959 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001960{
1961#if defined(DEBUG_SUBPAGE)
1962 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1963#endif
1964 subpage_writelen(opaque, addr, value, 2);
1965}
1966
David 'Digit' Turner36411062010-12-22 17:34:53 +01001967static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001968 &subpage_readb,
1969 &subpage_readw,
1970 &subpage_readl,
1971};
1972
David 'Digit' Turner36411062010-12-22 17:34:53 +01001973static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001974 &subpage_writeb,
1975 &subpage_writew,
1976 &subpage_writel,
1977};
1978
1979static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001980 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001981{
1982 int idx, eidx;
1983 unsigned int i;
1984
1985 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1986 return -1;
1987 idx = SUBPAGE_IDX(start);
1988 eidx = SUBPAGE_IDX(end);
1989#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001990 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 -08001991 mmio, start, end, idx, eidx, memory);
1992#endif
1993 memory >>= IO_MEM_SHIFT;
1994 for (; idx <= eidx; idx++) {
1995 for (i = 0; i < 4; i++) {
1996 if (io_mem_read[memory][i]) {
1997 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
1998 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001999 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002000 }
2001 if (io_mem_write[memory][i]) {
2002 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
2003 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002004 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002005 }
2006 }
2007 }
2008
2009 return 0;
2010}
2011
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002012static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002013 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002014{
2015 subpage_t *mmio;
2016 int subpage_memory;
2017
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002018 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002019
2020 mmio->base = base;
2021 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002022#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002023 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
2024 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002025#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002026 *phys = subpage_memory | IO_MEM_SUBPAGE;
2027 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
2028 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002029
2030 return mmio;
2031}
2032
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002033static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002034{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002035 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002036
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002037 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
2038 if (!io_mem_used[i]) {
2039 io_mem_used[i] = 1;
2040 return i;
2041 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002042 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002043 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002044}
2045
2046/* mem_read and mem_write are arrays of functions containing the
2047 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002048 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002049 If io_index is non zero, the corresponding io zone is
2050 modified. If it is zero, a new io zone is allocated. The return
2051 value can be used with cpu_register_physical_memory(). (-1) is
2052 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002053static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01002054 CPUReadMemoryFunc * const *mem_read,
2055 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002056 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002057{
2058 int i, subwidth = 0;
2059
2060 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002061 io_index = get_free_io_mem_idx();
2062 if (io_index == -1)
2063 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002064 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002065 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002066 if (io_index >= IO_MEM_NB_ENTRIES)
2067 return -1;
2068 }
2069
2070 for(i = 0;i < 3; i++) {
2071 if (!mem_read[i] || !mem_write[i])
2072 subwidth = IO_MEM_SUBWIDTH;
2073 io_mem_read[io_index][i] = mem_read[i];
2074 io_mem_write[io_index][i] = mem_write[i];
2075 }
2076 io_mem_opaque[io_index] = opaque;
2077 return (io_index << IO_MEM_SHIFT) | subwidth;
2078}
2079
David 'Digit' Turner36411062010-12-22 17:34:53 +01002080int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
2081 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002082 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002083{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002084 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002085}
2086
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002087void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002088{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002089 int i;
2090 int io_index = io_table_address >> IO_MEM_SHIFT;
2091
2092 for (i=0;i < 3; i++) {
2093 io_mem_read[io_index][i] = unassigned_mem_read[i];
2094 io_mem_write[io_index][i] = unassigned_mem_write[i];
2095 }
2096 io_mem_opaque[io_index] = NULL;
2097 io_mem_used[io_index] = 0;
2098}
2099
2100static void io_mem_init(void)
2101{
2102 int i;
2103
2104 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
2105 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
2106 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
2107 for (i=0; i<5; i++)
2108 io_mem_used[i] = 1;
2109
2110 io_mem_watch = cpu_register_io_memory(watch_mem_read,
2111 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002112}
2113
2114#endif /* !defined(CONFIG_USER_ONLY) */
2115
2116/* physical memory access (slow version, mainly for debug) */
2117#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002118void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002119 int len, int is_write)
2120{
2121 int l, flags;
2122 target_ulong page;
2123 void * p;
2124
2125 while (len > 0) {
2126 page = addr & TARGET_PAGE_MASK;
2127 l = (page + TARGET_PAGE_SIZE) - addr;
2128 if (l > len)
2129 l = len;
2130 flags = page_get_flags(page);
2131 if (!(flags & PAGE_VALID))
2132 return;
2133 if (is_write) {
2134 if (!(flags & PAGE_WRITE))
2135 return;
2136 /* XXX: this code should not depend on lock_user */
2137 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
2138 /* FIXME - should this return an error rather than just fail? */
2139 return;
2140 memcpy(p, buf, l);
2141 unlock_user(p, addr, l);
2142 } else {
2143 if (!(flags & PAGE_READ))
2144 return;
2145 /* XXX: this code should not depend on lock_user */
2146 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
2147 /* FIXME - should this return an error rather than just fail? */
2148 return;
2149 memcpy(buf, p, l);
2150 unlock_user(p, addr, 0);
2151 }
2152 len -= l;
2153 buf += l;
2154 addr += l;
2155 }
2156}
2157
2158#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07002159
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002160static void invalidate_and_set_dirty(hwaddr addr,
2161 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07002162{
2163 if (!cpu_physical_memory_is_dirty(addr)) {
2164 /* invalidate code */
2165 tb_invalidate_phys_page_range(addr, addr + length, 0);
2166 /* set dirty bit */
2167 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
2168 }
2169}
2170
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002171void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002172 int len, int is_write)
2173{
2174 int l, io_index;
2175 uint8_t *ptr;
2176 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002177 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002178 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002179 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002180 PhysPageDesc *p;
2181
2182 while (len > 0) {
2183 page = addr & TARGET_PAGE_MASK;
2184 l = (page + TARGET_PAGE_SIZE) - addr;
2185 if (l > len)
2186 l = len;
2187 p = phys_page_find(page >> TARGET_PAGE_BITS);
2188 if (!p) {
2189 pd = IO_MEM_UNASSIGNED;
2190 } else {
2191 pd = p->phys_offset;
2192 }
2193
2194 if (is_write) {
2195 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002196 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002197 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002198 if (p)
2199 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002200 /* XXX: could force cpu_single_env to NULL to avoid
2201 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002202 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002203 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002204 val = ldl_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002205 io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002206 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002207 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002208 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002209 val = lduw_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002210 io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002211 l = 2;
2212 } else {
2213 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002214 val = ldub_p(buf8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002215 io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002216 l = 1;
2217 }
2218 } else {
2219 unsigned long addr1;
2220 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2221 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002222 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002223 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002224 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002225 }
2226 } else {
2227 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2228 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002229 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002230 /* I/O case */
2231 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002232 if (p)
2233 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2234 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002235 /* 32 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002236 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002237 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002238 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002239 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002240 /* 16 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002241 val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002242 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002243 l = 2;
2244 } else {
2245 /* 8 bit read access */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002246 val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002247 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002248 l = 1;
2249 }
2250 } else {
2251 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002252 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002253 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002254 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002255 }
2256 }
2257 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002258 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002259 addr += l;
2260 }
2261}
2262
2263/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002264void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002265 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002266{
2267 int l;
2268 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002269 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002270 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002271 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002272 PhysPageDesc *p;
2273
2274 while (len > 0) {
2275 page = addr & TARGET_PAGE_MASK;
2276 l = (page + TARGET_PAGE_SIZE) - addr;
2277 if (l > len)
2278 l = len;
2279 p = phys_page_find(page >> TARGET_PAGE_BITS);
2280 if (!p) {
2281 pd = IO_MEM_UNASSIGNED;
2282 } else {
2283 pd = p->phys_offset;
2284 }
2285
2286 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2287 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2288 !(pd & IO_MEM_ROMD)) {
2289 /* do nothing */
2290 } else {
2291 unsigned long addr1;
2292 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2293 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002294 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002295 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002296 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002297 }
2298 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002299 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002300 addr += l;
2301 }
2302}
2303
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002304typedef struct {
2305 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002306 hwaddr addr;
2307 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002308} BounceBuffer;
2309
2310static BounceBuffer bounce;
2311
2312typedef struct MapClient {
2313 void *opaque;
2314 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002315 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002316} MapClient;
2317
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002318static QLIST_HEAD(map_client_list, MapClient) map_client_list
2319 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002320
2321void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2322{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002323 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002324
2325 client->opaque = opaque;
2326 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002327 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002328 return client;
2329}
2330
2331void cpu_unregister_map_client(void *_client)
2332{
2333 MapClient *client = (MapClient *)_client;
2334
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002335 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002336 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002337}
2338
2339static void cpu_notify_map_clients(void)
2340{
2341 MapClient *client;
2342
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002343 while (!QLIST_EMPTY(&map_client_list)) {
2344 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002345 client->callback(client->opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002346 QLIST_REMOVE(client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002347 }
2348}
2349
2350/* Map a physical memory region into a host virtual address.
2351 * May map a subset of the requested range, given by and returned in *plen.
2352 * May return NULL if resources needed to perform the mapping are exhausted.
2353 * Use only for reads OR writes - not for read-modify-write operations.
2354 * Use cpu_register_map_client() to know when retrying the map operation is
2355 * likely to succeed.
2356 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002357void *cpu_physical_memory_map(hwaddr addr,
2358 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002359 int is_write)
2360{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002361 hwaddr len = *plen;
2362 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002363 int l;
2364 uint8_t *ret = NULL;
2365 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002366 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002367 unsigned long pd;
2368 PhysPageDesc *p;
2369 unsigned long addr1;
2370
2371 while (len > 0) {
2372 page = addr & TARGET_PAGE_MASK;
2373 l = (page + TARGET_PAGE_SIZE) - addr;
2374 if (l > len)
2375 l = len;
2376 p = phys_page_find(page >> TARGET_PAGE_BITS);
2377 if (!p) {
2378 pd = IO_MEM_UNASSIGNED;
2379 } else {
2380 pd = p->phys_offset;
2381 }
2382
2383 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2384 if (done || bounce.buffer) {
2385 break;
2386 }
2387 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2388 bounce.addr = addr;
2389 bounce.len = l;
2390 if (!is_write) {
2391 cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
2392 }
2393 ptr = bounce.buffer;
2394 } else {
2395 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2396 ptr = qemu_get_ram_ptr(addr1);
2397 }
2398 if (!done) {
2399 ret = ptr;
2400 } else if (ret + done != ptr) {
2401 break;
2402 }
2403
2404 len -= l;
2405 addr += l;
2406 done += l;
2407 }
2408 *plen = done;
2409 return ret;
2410}
2411
2412/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2413 * Will also mark the memory as dirty if is_write == 1. access_len gives
2414 * the amount of memory that was actually read or written by the caller.
2415 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002416void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2417 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002418{
2419 if (buffer != bounce.buffer) {
2420 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002421 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002422 while (access_len) {
2423 unsigned l;
2424 l = TARGET_PAGE_SIZE;
2425 if (l > access_len)
2426 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002427 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002428 addr1 += l;
2429 access_len -= l;
2430 }
2431 }
2432 return;
2433 }
2434 if (is_write) {
2435 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2436 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002437 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002438 bounce.buffer = NULL;
2439 cpu_notify_map_clients();
2440}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002441
2442/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002443uint32_t ldl_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002444{
2445 int io_index;
2446 uint8_t *ptr;
2447 uint32_t val;
2448 unsigned long pd;
2449 PhysPageDesc *p;
2450
2451 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2452 if (!p) {
2453 pd = IO_MEM_UNASSIGNED;
2454 } else {
2455 pd = p->phys_offset;
2456 }
2457
2458 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2459 !(pd & IO_MEM_ROMD)) {
2460 /* I/O case */
2461 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002462 if (p)
2463 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002464 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2465 } else {
2466 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002467 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002468 (addr & ~TARGET_PAGE_MASK);
2469 val = ldl_p(ptr);
2470 }
2471 return val;
2472}
2473
2474/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002475uint64_t ldq_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002476{
2477 int io_index;
2478 uint8_t *ptr;
2479 uint64_t val;
2480 unsigned long pd;
2481 PhysPageDesc *p;
2482
2483 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2484 if (!p) {
2485 pd = IO_MEM_UNASSIGNED;
2486 } else {
2487 pd = p->phys_offset;
2488 }
2489
2490 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2491 !(pd & IO_MEM_ROMD)) {
2492 /* I/O case */
2493 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002494 if (p)
2495 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002496#ifdef TARGET_WORDS_BIGENDIAN
2497 val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2498 val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2499#else
2500 val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2501 val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2502#endif
2503 } else {
2504 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002505 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002506 (addr & ~TARGET_PAGE_MASK);
2507 val = ldq_p(ptr);
2508 }
2509 return val;
2510}
2511
2512/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002513uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002514{
2515 uint8_t val;
2516 cpu_physical_memory_read(addr, &val, 1);
2517 return val;
2518}
2519
2520/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002521uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002522{
2523 uint16_t val;
2524 cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2525 return tswap16(val);
2526}
2527
2528/* warning: addr must be aligned. The ram page is not masked as dirty
2529 and the code inside is not invalidated. It is useful if the dirty
2530 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002531void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002532{
2533 int io_index;
2534 uint8_t *ptr;
2535 unsigned long pd;
2536 PhysPageDesc *p;
2537
2538 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2539 if (!p) {
2540 pd = IO_MEM_UNASSIGNED;
2541 } else {
2542 pd = p->phys_offset;
2543 }
2544
2545 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2546 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002547 if (p)
2548 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002549 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2550 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002551 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2552 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002553 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002554
2555 if (unlikely(in_migration)) {
2556 if (!cpu_physical_memory_is_dirty(addr1)) {
2557 /* invalidate code */
2558 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2559 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002560 cpu_physical_memory_set_dirty_flags(
2561 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002562 }
2563 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002564 }
2565}
2566
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002567void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002568{
2569 int io_index;
2570 uint8_t *ptr;
2571 unsigned long pd;
2572 PhysPageDesc *p;
2573
2574 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2575 if (!p) {
2576 pd = IO_MEM_UNASSIGNED;
2577 } else {
2578 pd = p->phys_offset;
2579 }
2580
2581 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2582 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002583 if (p)
2584 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002585#ifdef TARGET_WORDS_BIGENDIAN
2586 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2587 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2588#else
2589 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2590 io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2591#endif
2592 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002593 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002594 (addr & ~TARGET_PAGE_MASK);
2595 stq_p(ptr, val);
2596 }
2597}
2598
2599/* warning: addr must be aligned */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002600void stl_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002601{
2602 int io_index;
2603 uint8_t *ptr;
2604 unsigned long pd;
2605 PhysPageDesc *p;
2606
2607 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2608 if (!p) {
2609 pd = IO_MEM_UNASSIGNED;
2610 } else {
2611 pd = p->phys_offset;
2612 }
2613
2614 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2615 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002616 if (p)
2617 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002618 io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2619 } else {
2620 unsigned long addr1;
2621 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2622 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002623 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002624 stl_p(ptr, val);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002625 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002626 }
2627}
2628
2629/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002630void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002631{
2632 uint8_t v = val;
2633 cpu_physical_memory_write(addr, &v, 1);
2634}
2635
2636/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002637void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002638{
2639 uint16_t v = tswap16(val);
2640 cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2641}
2642
2643/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002644void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002645{
2646 val = tswap64(val);
2647 cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2648}
2649
2650#endif
2651
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002652/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002653int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002654 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002655{
2656 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002657 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002658 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002659 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002660
2661 while (len > 0) {
2662 page = addr & TARGET_PAGE_MASK;
2663 phys_addr = cpu_get_phys_page_debug(env, page);
2664 /* if no physical page mapped, return an error */
2665 if (phys_addr == -1)
2666 return -1;
2667 l = (page + TARGET_PAGE_SIZE) - addr;
2668 if (l > len)
2669 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002670 phys_addr += (addr & ~TARGET_PAGE_MASK);
2671#if !defined(CONFIG_USER_ONLY)
2672 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002673 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002674 else
2675#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002676 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002677 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002678 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002679 addr += l;
2680 }
2681 return 0;
2682}