blob: fff1090d02b0446c2182af305bdeded4ee093cd2 [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' Turner6234c0b2014-03-14 17:05:26 +010040#include "hw/qdev.h"
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +010041#include "hw/xen/xen.h"
David 'Digit' Turner84569132013-12-13 17:34:07 +010042#include "qemu/osdep.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010043#include "sysemu/kvm.h"
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010044#include "exec/cputlb.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010045#include "exec/hax.h"
David 'Digit' Turner7a78db72013-12-14 11:46:01 +010046#include "qemu/timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080047#if defined(CONFIG_USER_ONLY)
48#include <qemu.h>
49#endif
David 'Digit' Turner5bb450e2014-03-14 17:19:45 +010050#ifdef CONFIG_ANDROID_MEMCHECK
David 'Digit' Turner96e493a2014-03-14 17:17:26 +010051#include "android/qemu/memcheck/memcheck_api.h"
David 'Digit' Turner5bb450e2014-03-14 17:19:45 +010052#endif // CONFIG_ANDROID_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080053
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080054//#define DEBUG_SUBPAGE
55
56#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080057int phys_ram_fd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070058static int in_migration;
59
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +010060RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) };
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080061#endif
62
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +010063CPUArchState *first_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080064/* current CPU in the current thread. It is only valid inside
65 cpu_exec() */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +010066CPUArchState *cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080067/* 0 = Do not count executed instructions.
68 1 = Precise instruction counting.
69 2 = Adaptive rate instruction counting. */
70int use_icount = 0;
71/* Current instruction counter. While executing translated code this may
72 include some instructions that have not yet been executed. */
73int64_t qemu_icount;
74
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080075#if !defined(CONFIG_USER_ONLY)
76static void io_mem_init(void);
77
78/* io memory support */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +010079CPUWriteMemoryFunc *_io_mem_write[IO_MEM_NB_ENTRIES][4];
80CPUReadMemoryFunc *_io_mem_read[IO_MEM_NB_ENTRIES][4];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080081void *io_mem_opaque[IO_MEM_NB_ENTRIES];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070082static char io_mem_used[IO_MEM_NB_ENTRIES];
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010083int io_mem_watch;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080084#endif
85
86/* log support */
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070087#ifdef WIN32
88static const char *logfilename = "qemu.log";
89#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070090static const char *logfilename = "/tmp/qemu.log";
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070091#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080092FILE *logfile;
93int loglevel;
94static int log_append = 0;
95
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080096#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
97typedef struct subpage_t {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +010098 hwaddr base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080099 CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
100 CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
101 void *opaque[TARGET_PAGE_SIZE][2][4];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700102 ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800103} subpage_t;
104
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800105/* Must be called before using the QEMU cpus. 'tb_size' is the size
106 (in bytes) allocated to the translation buffer. Zero means default
107 size. */
108void cpu_exec_init_all(unsigned long tb_size)
109{
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +0100110 //cpu_gen_init();
111 //code_gen_alloc(tb_size);
112 //code_gen_ptr = code_gen_buffer;
113 //page_init();
114 tcg_exec_init(tb_size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800115#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100116 qemu_mutex_init(&ram_list.mutex);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800117 io_mem_init();
118#endif
119}
120
121#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
122
123#define CPU_COMMON_SAVE_VERSION 1
124
125static void cpu_common_save(QEMUFile *f, void *opaque)
126{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100127 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800128
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700129 cpu_synchronize_state(env, 0);
130
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800131 qemu_put_be32s(f, &env->halted);
132 qemu_put_be32s(f, &env->interrupt_request);
133}
134
135static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
136{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100137 CPUOldState *env = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800138
139 if (version_id != CPU_COMMON_SAVE_VERSION)
140 return -EINVAL;
141
142 qemu_get_be32s(f, &env->halted);
143 qemu_get_be32s(f, &env->interrupt_request);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700144 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
145 version_id is increased. */
146 env->interrupt_request &= ~0x01;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800147 tlb_flush(env, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700148 cpu_synchronize_state(env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800149
150 return 0;
151}
152#endif
153
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100154CPUArchState *qemu_get_cpu(int cpu)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700155{
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100156 CPUArchState *env = first_cpu;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700157
158 while (env) {
159 if (env->cpu_index == cpu)
160 break;
161 env = env->next_cpu;
162 }
163
164 return env;
165}
166
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100167void cpu_exec_init(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800168{
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100169 CPUArchState **penv;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800170 int cpu_index;
171
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700172#if defined(CONFIG_USER_ONLY)
173 cpu_list_lock();
174#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800175 env->next_cpu = NULL;
176 penv = &first_cpu;
177 cpu_index = 0;
178 while (*penv != NULL) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700179 penv = &(*penv)->next_cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800180 cpu_index++;
181 }
182 env->cpu_index = cpu_index;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700183 env->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700184 QTAILQ_INIT(&env->breakpoints);
185 QTAILQ_INIT(&env->watchpoints);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800186 *penv = env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700187#if defined(CONFIG_USER_ONLY)
188 cpu_list_unlock();
189#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800190#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +0100191 register_savevm(NULL,
192 "cpu_common",
193 cpu_index,
194 CPU_COMMON_SAVE_VERSION,
195 cpu_common_save,
196 cpu_common_load,
197 env);
198 register_savevm(NULL,
199 "cpu",
200 cpu_index,
201 CPU_SAVE_VERSION,
202 cpu_save,
203 cpu_load,
204 env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800205#endif
206}
207
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800208#if defined(TARGET_HAS_ICE)
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100209static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800210{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100211 hwaddr addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800212 target_ulong pd;
213 ram_addr_t ram_addr;
214 PhysPageDesc *p;
215
216 addr = cpu_get_phys_page_debug(env, pc);
217 p = phys_page_find(addr >> TARGET_PAGE_BITS);
218 if (!p) {
219 pd = IO_MEM_UNASSIGNED;
220 } else {
221 pd = p->phys_offset;
222 }
223 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
224 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
225}
226#endif
227
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100228#if defined(CONFIG_USER_ONLY)
229void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
230
231{
232}
233
234int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
235 int flags, CPUWatchpoint **watchpoint)
236{
237 return -ENOSYS;
238}
239#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800240/* Add a watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100241int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700242 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800243{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700244 target_ulong len_mask = ~(len - 1);
245 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800246
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700247 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100248 if ((len & (len - 1)) || (addr & ~len_mask) ||
249 len == 0 || len > TARGET_PAGE_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700250 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
251 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
252 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800253 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100254 wp = g_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800255
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700256 wp->vaddr = addr;
257 wp->len_mask = len_mask;
258 wp->flags = flags;
259
260 /* keep all GDB-injected watchpoints in front */
261 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700262 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700263 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700264 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700265
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800266 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700267
268 if (watchpoint)
269 *watchpoint = wp;
270 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800271}
272
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700273/* Remove a specific watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100274int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700275 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800276{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700277 target_ulong len_mask = ~(len - 1);
278 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700280 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700281 if (addr == wp->vaddr && len_mask == wp->len_mask
282 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
283 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800284 return 0;
285 }
286 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700287 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800288}
289
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700290/* Remove a specific watchpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100291void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700292{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700293 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800294
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700295 tlb_flush_page(env, watchpoint->vaddr);
296
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100297 g_free(watchpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700298}
299
300/* Remove all matching watchpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100301void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700302{
303 CPUWatchpoint *wp, *next;
304
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700305 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700306 if (wp->flags & mask)
307 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800308 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800309}
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100310#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800311
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700312/* Add a breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100313int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700314 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800315{
316#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700317 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800318
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100319 bp = g_malloc(sizeof(*bp));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700320
321 bp->pc = pc;
322 bp->flags = flags;
323
324 /* keep all GDB-injected breakpoints in front */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100325 if (flags & BP_GDB) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700326 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100327 } else {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700328 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100329 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700330
331 breakpoint_invalidate(env, pc);
332
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100333 if (breakpoint) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700334 *breakpoint = bp;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100335 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700336 return 0;
337#else
338 return -ENOSYS;
339#endif
340}
341
342/* Remove a specific breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100343int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700344{
345#if defined(TARGET_HAS_ICE)
346 CPUBreakpoint *bp;
347
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700348 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700349 if (bp->pc == pc && bp->flags == flags) {
350 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800351 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700352 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800353 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700354 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800355#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700356 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800357#endif
358}
359
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700360/* Remove a specific breakpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100361void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800362{
363#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700364 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800365
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700366 breakpoint_invalidate(env, breakpoint->pc);
367
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100368 g_free(breakpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700369#endif
370}
371
372/* Remove all matching breakpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100373void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700374{
375#if defined(TARGET_HAS_ICE)
376 CPUBreakpoint *bp, *next;
377
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700378 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700379 if (bp->flags & mask)
380 cpu_breakpoint_remove_by_ref(env, bp);
381 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800382#endif
383}
384
385/* enable or disable single step mode. EXCP_DEBUG is returned by the
386 CPU loop after each instruction */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100387void cpu_single_step(CPUOldState *env, int enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800388{
389#if defined(TARGET_HAS_ICE)
390 if (env->singlestep_enabled != enabled) {
391 env->singlestep_enabled = enabled;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100392 if (kvm_enabled()) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700393 kvm_update_guest_debug(env, 0);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100394 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700395 /* must flush all the translated code to avoid inconsistencies */
396 /* XXX: only flush what is necessary */
397 tb_flush(env);
398 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800399 }
400#endif
401}
402
403/* enable or disable low levels log */
404void cpu_set_log(int log_flags)
405{
406 loglevel = log_flags;
407 if (loglevel && !logfile) {
408 logfile = fopen(logfilename, log_append ? "a" : "w");
409 if (!logfile) {
410 perror(logfilename);
Iliyan Malchev4a2c9dd2012-04-02 08:20:56 -0700411 exit(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800412 }
413#if !defined(CONFIG_SOFTMMU)
414 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
415 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700416 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800417 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
418 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700419#elif !defined(_WIN32)
420 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800421 setvbuf(logfile, NULL, _IOLBF, 0);
422#endif
423 log_append = 1;
424 }
425 if (!loglevel && logfile) {
426 fclose(logfile);
427 logfile = NULL;
428 }
429}
430
431void cpu_set_log_filename(const char *filename)
432{
433 logfilename = strdup(filename);
434 if (logfile) {
435 fclose(logfile);
436 logfile = NULL;
437 }
438 cpu_set_log(loglevel);
439}
440
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100441void cpu_unlink_tb(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800442{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800443 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
444 problem and hope the cpu will stop of its own accord. For userspace
445 emulation this often isn't actually as bad as it sounds. Often
446 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700447 TranslationBlock *tb;
448 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
449
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200450 spin_lock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700451 tb = env->current_tb;
452 /* if the cpu is currently executing code, we must unlink it and
453 all the potentially executing TB */
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200454 if (tb) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700455 env->current_tb = NULL;
456 tb_reset_jump_recursive(tb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700457 }
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200458 spin_unlock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700459}
460
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100461void cpu_reset_interrupt(CPUOldState *env, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800462{
463 env->interrupt_request &= ~mask;
464}
465
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100466void cpu_exit(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700467{
468 env->exit_request = 1;
469 cpu_unlink_tb(env);
470}
471
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100472void cpu_abort(CPUArchState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800473{
474 va_list ap;
475 va_list ap2;
476
477 va_start(ap, fmt);
478 va_copy(ap2, ap);
479 fprintf(stderr, "qemu: fatal: ");
480 vfprintf(stderr, fmt, ap);
481 fprintf(stderr, "\n");
482#ifdef TARGET_I386
483 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
484#else
485 cpu_dump_state(env, stderr, fprintf, 0);
486#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700487 if (qemu_log_enabled()) {
488 qemu_log("qemu: fatal: ");
489 qemu_log_vprintf(fmt, ap2);
490 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800491#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700492 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800493#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700494 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800495#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700496 qemu_log_flush();
497 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800498 }
499 va_end(ap2);
500 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +0100501#if defined(CONFIG_USER_ONLY)
502 {
503 struct sigaction act;
504 sigfillset(&act.sa_mask);
505 act.sa_handler = SIG_DFL;
506 sigaction(SIGABRT, &act, NULL);
507 }
508#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800509 abort();
510}
511
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800512#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100513static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
514{
515 RAMBlock *block;
516
517 /* The list is protected by the iothread lock here. */
518 block = ram_list.mru_block;
519 if (block && addr - block->offset < block->length) {
520 goto found;
521 }
522 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
523 if (addr - block->offset < block->length) {
524 goto found;
525 }
526 }
527
528 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
529 abort();
530
531found:
532 ram_list.mru_block = block;
533 return block;
534}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800535
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700536/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800537void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
538 int dirty_flags)
539{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100540 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800541 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200542 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800543
544 start &= TARGET_PAGE_MASK;
545 end = TARGET_PAGE_ALIGN(end);
546
547 length = end - start;
548 if (length == 0)
549 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200550 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800551
552 /* we modify the TLB cache so that the dirty bit will be set again
553 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200554 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700555 /* Chek that we don't span multiple blocks - this breaks the
556 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200557 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700558 != (end - 1) - start) {
559 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800560 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700561
562 for(env = first_cpu; env != NULL; env = env->next_cpu) {
563 int mmu_idx;
564 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
565 for(i = 0; i < CPU_TLB_SIZE; i++)
566 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
567 start1, length);
568 }
569 }
570}
571
572int cpu_physical_memory_set_dirty_tracking(int enable)
573{
574 in_migration = enable;
575 if (kvm_enabled()) {
576 return kvm_set_migration_log(enable);
577 }
578 return 0;
579}
580
581int cpu_physical_memory_get_dirty_tracking(void)
582{
583 return in_migration;
584}
585
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100586int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
587 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700588{
589 int ret = 0;
590
591 if (kvm_enabled())
592 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
593 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800594}
595
596static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
597{
598 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700599 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800600
601 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700602 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
603 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200604 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800605 if (!cpu_physical_memory_is_dirty(ram_addr)) {
606 tlb_entry->addr_write |= TLB_NOTDIRTY;
607 }
608 }
609}
610
611/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100612void cpu_tlb_update_dirty(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800613{
614 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700615 int mmu_idx;
616 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
617 for(i = 0; i < CPU_TLB_SIZE; i++)
618 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
619 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800620}
621
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800622
623#else
624
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100625void tlb_flush(CPUArchState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800626{
627}
628
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100629void tlb_flush_page(CPUArchState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800630{
631}
632
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100633int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100634 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800635 int mmu_idx, int is_softmmu)
636{
637 return 0;
638}
639
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100640static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800641 unsigned long addr, target_ulong vaddr)
642{
643}
644#endif /* defined(CONFIG_USER_ONLY) */
645
646#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700647
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800648static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700649 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100650static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700651 ram_addr_t orig_memory, ram_addr_t region_offset);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100652
653static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
654
655/*
656 * Set a custom physical guest memory alloator.
657 * Accelerators with unusual needs may need this. Hopefully, we can
658 * get rid of it eventually.
659 */
660void phys_mem_set_alloc(void *(*alloc)(size_t))
661{
662 phys_mem_alloc = alloc;
663}
664
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800665#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
666 need_subpage) \
667 do { \
668 if (addr > start_addr) \
669 start_addr2 = 0; \
670 else { \
671 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
672 if (start_addr2 > 0) \
673 need_subpage = 1; \
674 } \
675 \
676 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
677 end_addr2 = TARGET_PAGE_SIZE - 1; \
678 else { \
679 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
680 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
681 need_subpage = 1; \
682 } \
683 } while (0)
684
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700685/* register physical memory.
686 For RAM, 'size' must be a multiple of the target page size.
687 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700688 io memory page. The address used when calling the IO function is
689 the offset from the start of the region, plus region_offset. Both
690 start_addr and region_offset are rounded down to a page boundary
691 before calculating this offset. This should not be a problem unless
692 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100693void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700694 ram_addr_t size,
695 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200696 ram_addr_t region_offset,
697 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800698{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100699 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800700 PhysPageDesc *p;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100701 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800702 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200703 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800704
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700705 if (kvm_enabled())
706 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800707#ifdef CONFIG_HAX
708 if (hax_enabled())
709 hax_set_phys_mem(start_addr, size, phys_offset);
710#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700711
712 if (phys_offset == IO_MEM_UNASSIGNED) {
713 region_offset = start_addr;
714 }
715 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800716 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100717 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200718
719 addr = start_addr;
720 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800721 p = phys_page_find(addr >> TARGET_PAGE_BITS);
722 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
723 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100724 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800725 int need_subpage = 0;
726
727 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
728 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200729 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800730 if (!(orig_memory & IO_MEM_SUBPAGE)) {
731 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700732 &p->phys_offset, orig_memory,
733 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800734 } else {
735 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
736 >> IO_MEM_SHIFT];
737 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700738 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
739 region_offset);
740 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800741 } else {
742 p->phys_offset = phys_offset;
743 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
744 (phys_offset & IO_MEM_ROMD))
745 phys_offset += TARGET_PAGE_SIZE;
746 }
747 } else {
748 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
749 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700750 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800751 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700752 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800753 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700754 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100755 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800756 int need_subpage = 0;
757
758 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
759 end_addr2, need_subpage);
760
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200761 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800762 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700763 &p->phys_offset, IO_MEM_UNASSIGNED,
764 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800765 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700766 phys_offset, region_offset);
767 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800768 }
769 }
770 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700771 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200772 addr += TARGET_PAGE_SIZE;
773 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800774
775 /* since each CPU stores ram addresses in its TLB cache, we must
776 reset the modified entries */
777 /* XXX: slow ! */
778 for(env = first_cpu; env != NULL; env = env->next_cpu) {
779 tlb_flush(env, 1);
780 }
781}
782
783/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100784ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800785{
786 PhysPageDesc *p;
787
788 p = phys_page_find(addr >> TARGET_PAGE_BITS);
789 if (!p)
790 return IO_MEM_UNASSIGNED;
791 return p->phys_offset;
792}
793
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100794void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700795{
796 if (kvm_enabled())
797 kvm_coalesce_mmio_region(addr, size);
798}
799
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100800void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700801{
802 if (kvm_enabled())
803 kvm_uncoalesce_mmio_region(addr, size);
804}
805
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100806void qemu_mutex_lock_ramlist(void)
807{
808 qemu_mutex_lock(&ram_list.mutex);
809}
810
811void qemu_mutex_unlock_ramlist(void)
812{
813 qemu_mutex_unlock(&ram_list.mutex);
814}
815
816#if defined(__linux__) && !defined(CONFIG_ANDROID)
817
818#include <sys/vfs.h>
819
820#define HUGETLBFS_MAGIC 0x958458f6
821
822static long gethugepagesize(const char *path)
823{
824 struct statfs fs;
825 int ret;
826
827 do {
828 ret = statfs(path, &fs);
829 } while (ret != 0 && errno == EINTR);
830
831 if (ret != 0) {
832 perror(path);
833 return 0;
834 }
835
836 if (fs.f_type != HUGETLBFS_MAGIC)
837 fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
838
839 return fs.f_bsize;
840}
841
842static sigjmp_buf sigjump;
843
844static void sigbus_handler(int signal)
845{
846 siglongjmp(sigjump, 1);
847}
848
849static void *file_ram_alloc(RAMBlock *block,
850 ram_addr_t memory,
851 const char *path)
852{
853 char *filename;
854 char *sanitized_name;
855 char *c;
856 void *area;
857 int fd;
858 unsigned long hpagesize;
859
860 hpagesize = gethugepagesize(path);
861 if (!hpagesize) {
862 return NULL;
863 }
864
865 if (memory < hpagesize) {
866 return NULL;
867 }
868
869 if (kvm_enabled() && !kvm_has_sync_mmu()) {
870 fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
871 return NULL;
872 }
873
874 /* Make name safe to use with mkstemp by replacing '/' with '_'. */
875 sanitized_name = g_strdup(block->mr->name);
876 for (c = sanitized_name; *c != '\0'; c++) {
877 if (*c == '/')
878 *c = '_';
879 }
880
881 filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
882 sanitized_name);
883 g_free(sanitized_name);
884
885 fd = mkstemp(filename);
886 if (fd < 0) {
887 perror("unable to create backing store for hugepages");
888 g_free(filename);
889 return NULL;
890 }
891 unlink(filename);
892 g_free(filename);
893
894 memory = (memory+hpagesize-1) & ~(hpagesize-1);
895
896 /*
897 * ftruncate is not supported by hugetlbfs in older
898 * hosts, so don't bother bailing out on errors.
899 * If anything goes wrong with it under other filesystems,
900 * mmap will fail.
901 */
902 if (ftruncate(fd, memory))
903 perror("ftruncate");
904
905 area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
906 if (area == MAP_FAILED) {
907 perror("file_ram_alloc: can't mmap RAM pages");
908 close(fd);
909 return (NULL);
910 }
911
912 if (mem_prealloc) {
913 int ret, i;
914 struct sigaction act, oldact;
915 sigset_t set, oldset;
916
917 memset(&act, 0, sizeof(act));
918 act.sa_handler = &sigbus_handler;
919 act.sa_flags = 0;
920
921 ret = sigaction(SIGBUS, &act, &oldact);
922 if (ret) {
923 perror("file_ram_alloc: failed to install signal handler");
924 exit(1);
925 }
926
927 /* unblock SIGBUS */
928 sigemptyset(&set);
929 sigaddset(&set, SIGBUS);
930 pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
931
932 if (sigsetjmp(sigjump, 1)) {
933 fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
934 exit(1);
935 }
936
937 /* MAP_POPULATE silently ignores failures */
938 for (i = 0; i < (memory/hpagesize)-1; i++) {
939 memset(area + (hpagesize*i), 0, 1);
940 }
941
942 ret = sigaction(SIGBUS, &oldact, NULL);
943 if (ret) {
944 perror("file_ram_alloc: failed to reinstall signal handler");
945 exit(1);
946 }
947
948 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
949 }
950
951 block->fd = fd;
952 return area;
953}
954#else
955static void *file_ram_alloc(RAMBlock *block,
956 ram_addr_t memory,
957 const char *path)
958{
959 fprintf(stderr, "-mem-path not supported on this host\n");
960 exit(1);
961}
962#endif
963
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200964static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700965{
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200966 RAMBlock *block, *next_block;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100967 ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200968
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100969 assert(size != 0); /* it would hand out same offset multiple times */
970
971 if (QTAILQ_EMPTY(&ram_list.blocks))
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200972 return 0;
973
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100974 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
975 ram_addr_t end, next = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200976
977 end = block->offset + block->length;
978
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100979 QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200980 if (next_block->offset >= end) {
981 next = MIN(next, next_block->offset);
982 }
983 }
984 if (next - end >= size && next - end < mingap) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100985 offset = end;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200986 mingap = next - end;
987 }
988 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100989
990 if (offset == RAM_ADDR_MAX) {
991 fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
992 (uint64_t)size);
993 abort();
994 }
995
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200996 return offset;
997}
998
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100999ram_addr_t last_ram_offset(void)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001000{
1001 RAMBlock *block;
1002 ram_addr_t last = 0;
1003
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001004 QTAILQ_FOREACH(block, &ram_list.blocks, next)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001005 last = MAX(last, block->offset + block->length);
1006
1007 return last;
1008}
1009
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001010static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
1011{
1012#ifndef CONFIG_ANDROID
1013 int ret;
1014
1015 /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
1016 if (!qemu_opt_get_bool(qemu_get_machine_opts(),
1017 "dump-guest-core", true)) {
1018 ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
1019 if (ret) {
1020 perror("qemu_madvise");
1021 fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
1022 "but dump_guest_core=off specified\n");
1023 }
1024 }
1025#endif // !CONFIG_ANDROID
1026}
1027
1028void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001029{
1030 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001031
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001032 new_block = NULL;
1033 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1034 if (block->offset == addr) {
1035 new_block = block;
1036 break;
1037 }
1038 }
1039 assert(new_block);
1040 assert(!new_block->idstr[0]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001041
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001042 if (dev) {
1043 char *id = qdev_get_dev_path(dev);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001044 if (id) {
1045 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001046 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001047 }
1048 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001049 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1050
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001051 /* This assumes the iothread lock is taken here too. */
1052 qemu_mutex_lock_ramlist();
1053 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1054 if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001055 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
1056 new_block->idstr);
1057 abort();
1058 }
1059 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001060 qemu_mutex_unlock_ramlist();
1061}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001062
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001063static int memory_try_enable_merging(void *addr, size_t len)
1064{
1065#ifndef CONFIG_ANDROID
1066 if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) {
1067 /* disabled by the user */
1068 return 0;
1069 }
1070
1071 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1072#else // CONFIG_ANDROID
1073 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1074#endif // CONFIG_ANDROID
1075}
1076
1077ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
1078 ram_addr_t size, void *host)
1079{
1080 RAMBlock *block, *new_block;
1081
1082 size = TARGET_PAGE_ALIGN(size);
1083 new_block = g_malloc0(sizeof(*new_block));
1084 new_block->fd = -1;
1085
1086 /* This assumes the iothread lock is taken here too. */
1087 qemu_mutex_lock_ramlist();
1088 //new_block->mr = mr;
1089 new_block->offset = find_ram_offset(size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001090 if (host) {
1091 new_block->host = host;
1092 new_block->flags |= RAM_PREALLOC_MASK;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001093 } else if (xen_enabled()) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001094 if (mem_path) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001095 fprintf(stderr, "-mem-path not supported with Xen\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001096 exit(1);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001097 }
1098 //xen_ram_alloc(new_block->offset, size, mr);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001099 } else {
1100 if (mem_path) {
1101 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1102 /*
1103 * file_ram_alloc() needs to allocate just like
1104 * phys_mem_alloc, but we haven't bothered to provide
1105 * a hook there.
1106 */
1107 fprintf(stderr,
1108 "-mem-path not supported with this accelerator\n");
1109 exit(1);
1110 }
1111 new_block->host = file_ram_alloc(new_block, size, mem_path);
1112 }
1113 if (!new_block->host) {
1114 new_block->host = phys_mem_alloc(size);
1115 if (!new_block->host) {
1116 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1117 name, strerror(errno));
1118 exit(1);
1119 }
David 'Digit' Turnerf2de2ae2014-03-07 16:25:58 +01001120#ifdef CONFIG_HAX
1121 if (hax_enabled()) {
1122 /*
1123 * In HAX, qemu allocates the virtual address, and HAX kernel
1124 * module populates the region with physical memory. Currently
1125 * we don’t populate guest memory on demand, thus we should
1126 * make sure that sufficient amount of memory is available in
1127 * advance.
1128 */
1129 int ret = hax_populate_ram(
1130 (uint64_t)(uintptr_t)new_block->host,
1131 (uint32_t)size);
1132 if (ret < 0) {
1133 fprintf(stderr, "Hax failed to populate ram\n");
1134 exit(-1);
1135 }
1136 }
1137#endif // CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001138 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001139 }
1140 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001141 new_block->length = size;
1142
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001143 /* Keep the list sorted from biggest to smallest block. */
1144 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1145 if (block->length < new_block->length) {
1146 break;
1147 }
1148 }
1149 if (block) {
1150 QTAILQ_INSERT_BEFORE(block, new_block, next);
1151 } else {
1152 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1153 }
1154 ram_list.mru_block = NULL;
1155
1156 ram_list.version++;
1157 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001158
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001159 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001160 last_ram_offset() >> TARGET_PAGE_BITS);
1161 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001162 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001163 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001164
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001165 //qemu_ram_setup_dump(new_block->host, size);
1166 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1167 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
1168
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001169 if (kvm_enabled())
1170 kvm_setup_guest_memory(new_block->host, size);
1171
1172 return new_block->offset;
1173}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001174
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001175ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1176{
1177 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1178}
1179
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001180void qemu_ram_free_from_ptr(ram_addr_t addr)
1181{
1182 RAMBlock *block;
1183
1184 /* This assumes the iothread lock is taken here too. */
1185 qemu_mutex_lock_ramlist();
1186 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1187 if (addr == block->offset) {
1188 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1189 ram_list.mru_block = NULL;
1190 ram_list.version++;
1191 g_free(block);
1192 break;
1193 }
1194 }
1195 qemu_mutex_unlock_ramlist();
1196}
1197
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001198void qemu_ram_free(ram_addr_t addr)
1199{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001200 RAMBlock *block;
1201
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001202 /* This assumes the iothread lock is taken here too. */
1203 qemu_mutex_lock_ramlist();
1204 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001205 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001206 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1207 ram_list.mru_block = NULL;
1208 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001209 if (block->flags & RAM_PREALLOC_MASK) {
1210 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001211 } else if (xen_enabled()) {
1212 //xen_invalidate_map_cache_entry(block->host);
1213#ifndef _WIN32
1214 } else if (block->fd >= 0) {
1215 munmap(block->host, block->length);
1216 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001217#endif
1218 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001219 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001220 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001221 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001222 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001223 }
1224 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001225 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001226
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001227}
1228
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001229#ifndef _WIN32
1230void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1231{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001232 RAMBlock *block;
1233 ram_addr_t offset;
1234 int flags;
1235 void *area, *vaddr;
1236
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001237 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001238 offset = addr - block->offset;
1239 if (offset < block->length) {
1240 vaddr = block->host + offset;
1241 if (block->flags & RAM_PREALLOC_MASK) {
1242 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001243 } else if (xen_enabled()) {
1244 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001245 } else {
1246 flags = MAP_FIXED;
1247 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001248 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001249#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001250 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1251 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001252#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001253 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001254#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001255 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1256 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001257 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001258 /*
1259 * Remap needs to match alloc. Accelerators that
1260 * set phys_mem_alloc never remap. If they did,
1261 * we'd need a remap hook here.
1262 */
1263 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1264
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001265 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1266 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1267 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001268 }
1269 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001270 fprintf(stderr, "Could not remap addr: "
1271 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001272 length, addr);
1273 exit(1);
1274 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001275 memory_try_enable_merging(vaddr, length);
1276 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001277 }
1278 return;
1279 }
1280 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001281}
1282#endif /* !_WIN32 */
1283
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001284/* Return a host pointer to ram allocated with qemu_ram_alloc.
1285 With the exception of the softmmu code in this file, this should
1286 only be used for local memory (e.g. video ram) that the device owns,
1287 and knows it isn't going to access beyond the end of the block.
1288
1289 It should not be used for general purpose DMA.
1290 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1291 */
1292void *qemu_get_ram_ptr(ram_addr_t addr)
1293{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001294 RAMBlock *block = qemu_get_ram_block(addr);
1295#if 0
1296 if (xen_enabled()) {
1297 /* We need to check if the requested address is in the RAM
1298 * because we don't want to map the entire memory in QEMU.
1299 * In that case just map until the end of the page.
1300 */
1301 if (block->offset == 0) {
1302 return xen_map_cache(addr, 0, 0);
1303 } else if (block->host == NULL) {
1304 block->host =
1305 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001306 }
1307 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001308#endif
1309 return block->host + (addr - block->offset);
1310}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001311
1312/* Return a host pointer to ram allocated with qemu_ram_alloc.
1313 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1314 */
1315void *qemu_safe_ram_ptr(ram_addr_t addr)
1316{
1317 RAMBlock *block;
1318
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001319 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001320 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001321 return block->host + (addr - block->offset);
1322 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001323 }
1324
1325 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1326 abort();
1327
1328 return NULL;
1329}
1330
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001331/* Some of the softmmu routines need to translate from a host pointer
1332 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001333int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1334{
1335 RAMBlock *block;
1336 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001337#if 0
1338 if (xen_enabled()) {
1339 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1340 return qemu_get_ram_block(*ram_addr)->mr;
1341 }
1342#endif
1343 block = ram_list.mru_block;
1344 if (block && block->host && host - block->host < block->length) {
1345 goto found;
1346 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001347
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001348 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1349 /* This case append when the block is not mapped. */
1350 if (block->host == NULL) {
1351 continue;
1352 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001353 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001354 goto found;
1355 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001356 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001357
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001358 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001359
1360found:
1361 *ram_addr = block->offset + (host - block->host);
1362 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001363}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001364
1365/* Some of the softmmu routines need to translate from a host pointer
1366 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001367ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001368{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001369 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001370
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001371 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001372 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1373 abort();
1374 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001375 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001376}
1377
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001378static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001379{
1380#ifdef DEBUG_UNASSIGNED
1381 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1382#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001383#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001384 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001385#endif
1386 return 0;
1387}
1388
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001389static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001390{
1391#ifdef DEBUG_UNASSIGNED
1392 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1393#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001394#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001395 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001396#endif
1397 return 0;
1398}
1399
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001400static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001401{
1402#ifdef DEBUG_UNASSIGNED
1403 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1404#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001405#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001406 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001407#endif
1408 return 0;
1409}
1410
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001411static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001412{
1413#ifdef DEBUG_UNASSIGNED
1414 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1415#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001416#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001417 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001418#endif
1419}
1420
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001421static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001422{
1423#ifdef DEBUG_UNASSIGNED
1424 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1425#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001426#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001427 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001428#endif
1429}
1430
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001431static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001432{
1433#ifdef DEBUG_UNASSIGNED
1434 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1435#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001436#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001437 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001438#endif
1439}
1440
David 'Digit' Turner36411062010-12-22 17:34:53 +01001441static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001442 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001443 unassigned_mem_readw,
1444 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001445};
1446
David 'Digit' Turner36411062010-12-22 17:34:53 +01001447static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001448 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001449 unassigned_mem_writew,
1450 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001451};
1452
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001453static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001454 uint32_t val)
1455{
1456 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001457 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001458 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1459#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001460 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001461 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001462#endif
1463 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001464 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001465 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001466 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001467 /* we remove the notdirty callback only if the code has been
1468 flushed */
1469 if (dirty_flags == 0xff)
1470 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1471}
1472
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001473static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001474 uint32_t val)
1475{
1476 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001477 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001478 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1479#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001480 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001481 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001482#endif
1483 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001484 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001485 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001486 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001487 /* we remove the notdirty callback only if the code has been
1488 flushed */
1489 if (dirty_flags == 0xff)
1490 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1491}
1492
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001493static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001494 uint32_t val)
1495{
1496 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001497 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001498 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1499#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001500 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001501 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001502#endif
1503 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001504 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001505 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001506 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001507 /* we remove the notdirty callback only if the code has been
1508 flushed */
1509 if (dirty_flags == 0xff)
1510 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1511}
1512
David 'Digit' Turner36411062010-12-22 17:34:53 +01001513static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001514 NULL, /* never used */
1515 NULL, /* never used */
1516 NULL, /* never used */
1517};
1518
David 'Digit' Turner36411062010-12-22 17:34:53 +01001519static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001520 notdirty_mem_writeb,
1521 notdirty_mem_writew,
1522 notdirty_mem_writel,
1523};
1524
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001525static void tb_check_watchpoint(CPUArchState* env)
1526{
1527 TranslationBlock *tb = tb_find_pc(env->mem_io_pc);
1528 if (!tb) {
1529 cpu_abort(env, "check_watchpoint: could not find TB for "
1530 "pc=%p", (void *)env->mem_io_pc);
1531 }
1532 cpu_restore_state(env, env->mem_io_pc);
1533 tb_phys_invalidate(tb, -1);
1534}
1535
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001536/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001537static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001538{
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001539 CPUArchState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001540 target_ulong pc, cs_base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001541 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001542 CPUWatchpoint *wp;
1543 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001544
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001545 if (env->watchpoint_hit) {
1546 /* We re-entered the check after replacing the TB. Now raise
1547 * the debug interrupt so that is will trigger after the
1548 * current instruction. */
1549 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
1550 return;
1551 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001552 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001553 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001554 if ((vaddr == (wp->vaddr & len_mask) ||
1555 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1556 wp->flags |= BP_WATCHPOINT_HIT;
1557 if (!env->watchpoint_hit) {
1558 env->watchpoint_hit = wp;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001559 tb_check_watchpoint(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001560 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1561 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001562 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001563 } else {
1564 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1565 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001566 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001567 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001568 }
1569 } else {
1570 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001571 }
1572 }
1573}
1574
1575/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1576 so these check for a hit then pass through to the normal out-of-line
1577 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001578static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001579{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001580 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001581 return ldub_phys(addr);
1582}
1583
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001584static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001585{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001586 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001587 return lduw_phys(addr);
1588}
1589
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001590static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001591{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001592 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001593 return ldl_phys(addr);
1594}
1595
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001596static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001597 uint32_t val)
1598{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001599 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001600 stb_phys(addr, val);
1601}
1602
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001603static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001604 uint32_t val)
1605{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001606 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001607 stw_phys(addr, val);
1608}
1609
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001610static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001611 uint32_t val)
1612{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001613 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001614 stl_phys(addr, val);
1615}
1616
David 'Digit' Turner36411062010-12-22 17:34:53 +01001617static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001618 watch_mem_readb,
1619 watch_mem_readw,
1620 watch_mem_readl,
1621};
1622
David 'Digit' Turner36411062010-12-22 17:34:53 +01001623static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001624 watch_mem_writeb,
1625 watch_mem_writew,
1626 watch_mem_writel,
1627};
1628
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001629static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001630 unsigned int len)
1631{
1632 uint32_t ret;
1633 unsigned int idx;
1634
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001635 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001636#if defined(DEBUG_SUBPAGE)
1637 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1638 mmio, len, addr, idx);
1639#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001640 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1641 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001642
1643 return ret;
1644}
1645
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001646static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001647 uint32_t value, unsigned int len)
1648{
1649 unsigned int idx;
1650
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001651 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001652#if defined(DEBUG_SUBPAGE)
1653 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1654 mmio, len, addr, idx, value);
1655#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001656 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1657 addr + mmio->region_offset[idx][1][len],
1658 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001659}
1660
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001661static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001662{
1663#if defined(DEBUG_SUBPAGE)
1664 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1665#endif
1666
1667 return subpage_readlen(opaque, addr, 0);
1668}
1669
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001670static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001671 uint32_t value)
1672{
1673#if defined(DEBUG_SUBPAGE)
1674 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1675#endif
1676 subpage_writelen(opaque, addr, value, 0);
1677}
1678
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001679static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001680{
1681#if defined(DEBUG_SUBPAGE)
1682 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1683#endif
1684
1685 return subpage_readlen(opaque, addr, 1);
1686}
1687
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001688static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001689 uint32_t value)
1690{
1691#if defined(DEBUG_SUBPAGE)
1692 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1693#endif
1694 subpage_writelen(opaque, addr, value, 1);
1695}
1696
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001697static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001698{
1699#if defined(DEBUG_SUBPAGE)
1700 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1701#endif
1702
1703 return subpage_readlen(opaque, addr, 2);
1704}
1705
1706static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001707 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001708{
1709#if defined(DEBUG_SUBPAGE)
1710 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1711#endif
1712 subpage_writelen(opaque, addr, value, 2);
1713}
1714
David 'Digit' Turner36411062010-12-22 17:34:53 +01001715static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001716 &subpage_readb,
1717 &subpage_readw,
1718 &subpage_readl,
1719};
1720
David 'Digit' Turner36411062010-12-22 17:34:53 +01001721static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001722 &subpage_writeb,
1723 &subpage_writew,
1724 &subpage_writel,
1725};
1726
1727static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001728 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001729{
1730 int idx, eidx;
1731 unsigned int i;
1732
1733 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1734 return -1;
1735 idx = SUBPAGE_IDX(start);
1736 eidx = SUBPAGE_IDX(end);
1737#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001738 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 -08001739 mmio, start, end, idx, eidx, memory);
1740#endif
1741 memory >>= IO_MEM_SHIFT;
1742 for (; idx <= eidx; idx++) {
1743 for (i = 0; i < 4; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001744 if (_io_mem_read[memory][i]) {
1745 mmio->mem_read[idx][i] = &_io_mem_read[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001746 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001747 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001748 }
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001749 if (_io_mem_write[memory][i]) {
1750 mmio->mem_write[idx][i] = &_io_mem_write[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001751 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001752 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001753 }
1754 }
1755 }
1756
1757 return 0;
1758}
1759
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001760static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001761 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001762{
1763 subpage_t *mmio;
1764 int subpage_memory;
1765
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001766 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001767
1768 mmio->base = base;
1769 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001770#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001771 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
1772 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001773#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001774 *phys = subpage_memory | IO_MEM_SUBPAGE;
1775 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
1776 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001777
1778 return mmio;
1779}
1780
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001781static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001782{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001783 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001784
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001785 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
1786 if (!io_mem_used[i]) {
1787 io_mem_used[i] = 1;
1788 return i;
1789 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001790 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001791 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001792}
1793
1794/* mem_read and mem_write are arrays of functions containing the
1795 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001796 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001797 If io_index is non zero, the corresponding io zone is
1798 modified. If it is zero, a new io zone is allocated. The return
1799 value can be used with cpu_register_physical_memory(). (-1) is
1800 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001801static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01001802 CPUReadMemoryFunc * const *mem_read,
1803 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001804 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001805{
1806 int i, subwidth = 0;
1807
1808 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001809 io_index = get_free_io_mem_idx();
1810 if (io_index == -1)
1811 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001812 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001813 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001814 if (io_index >= IO_MEM_NB_ENTRIES)
1815 return -1;
1816 }
1817
1818 for(i = 0;i < 3; i++) {
1819 if (!mem_read[i] || !mem_write[i])
1820 subwidth = IO_MEM_SUBWIDTH;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001821 _io_mem_read[io_index][i] = mem_read[i];
1822 _io_mem_write[io_index][i] = mem_write[i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001823 }
1824 io_mem_opaque[io_index] = opaque;
1825 return (io_index << IO_MEM_SHIFT) | subwidth;
1826}
1827
David 'Digit' Turner36411062010-12-22 17:34:53 +01001828int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
1829 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001830 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001831{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001832 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001833}
1834
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001835void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001836{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001837 int i;
1838 int io_index = io_table_address >> IO_MEM_SHIFT;
1839
1840 for (i=0;i < 3; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001841 _io_mem_read[io_index][i] = unassigned_mem_read[i];
1842 _io_mem_write[io_index][i] = unassigned_mem_write[i];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001843 }
1844 io_mem_opaque[io_index] = NULL;
1845 io_mem_used[io_index] = 0;
1846}
1847
1848static void io_mem_init(void)
1849{
1850 int i;
1851
1852 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
1853 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
1854 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
1855 for (i=0; i<5; i++)
1856 io_mem_used[i] = 1;
1857
1858 io_mem_watch = cpu_register_io_memory(watch_mem_read,
1859 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001860}
1861
1862#endif /* !defined(CONFIG_USER_ONLY) */
1863
1864/* physical memory access (slow version, mainly for debug) */
1865#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001866void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001867 int len, int is_write)
1868{
1869 int l, flags;
1870 target_ulong page;
1871 void * p;
1872
1873 while (len > 0) {
1874 page = addr & TARGET_PAGE_MASK;
1875 l = (page + TARGET_PAGE_SIZE) - addr;
1876 if (l > len)
1877 l = len;
1878 flags = page_get_flags(page);
1879 if (!(flags & PAGE_VALID))
1880 return;
1881 if (is_write) {
1882 if (!(flags & PAGE_WRITE))
1883 return;
1884 /* XXX: this code should not depend on lock_user */
1885 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
1886 /* FIXME - should this return an error rather than just fail? */
1887 return;
1888 memcpy(p, buf, l);
1889 unlock_user(p, addr, l);
1890 } else {
1891 if (!(flags & PAGE_READ))
1892 return;
1893 /* XXX: this code should not depend on lock_user */
1894 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
1895 /* FIXME - should this return an error rather than just fail? */
1896 return;
1897 memcpy(buf, p, l);
1898 unlock_user(p, addr, 0);
1899 }
1900 len -= l;
1901 buf += l;
1902 addr += l;
1903 }
1904}
1905
1906#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07001907
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001908static void invalidate_and_set_dirty(hwaddr addr,
1909 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07001910{
1911 if (!cpu_physical_memory_is_dirty(addr)) {
1912 /* invalidate code */
1913 tb_invalidate_phys_page_range(addr, addr + length, 0);
1914 /* set dirty bit */
1915 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
1916 }
1917}
1918
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001919void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001920 int len, int is_write)
1921{
1922 int l, io_index;
1923 uint8_t *ptr;
1924 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001925 hwaddr page;
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001926 ram_addr_t pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001927 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001928 PhysPageDesc *p;
1929
1930 while (len > 0) {
1931 page = addr & TARGET_PAGE_MASK;
1932 l = (page + TARGET_PAGE_SIZE) - addr;
1933 if (l > len)
1934 l = len;
1935 p = phys_page_find(page >> TARGET_PAGE_BITS);
1936 if (!p) {
1937 pd = IO_MEM_UNASSIGNED;
1938 } else {
1939 pd = p->phys_offset;
1940 }
1941
1942 if (is_write) {
1943 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001944 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001945 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001946 if (p)
1947 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001948 /* XXX: could force cpu_single_env to NULL to avoid
1949 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001950 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001951 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001952 val = ldl_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001953 io_mem_write(io_index, addr1, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001954 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001955 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001956 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001957 val = lduw_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001958 io_mem_write(io_index, addr1, val, 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001959 l = 2;
1960 } else {
1961 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001962 val = ldub_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001963 io_mem_write(io_index, addr1, val, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001964 l = 1;
1965 }
1966 } else {
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001967 ram_addr_t addr1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001968 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
1969 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001970 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001971 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07001972 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001973 }
1974 } else {
1975 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
1976 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001977 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001978 /* I/O case */
1979 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001980 if (p)
1981 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
1982 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001983 /* 32 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001984 val = io_mem_read(io_index, addr1, 4);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001985 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001986 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001987 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001988 /* 16 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001989 val = io_mem_read(io_index, addr1, 2);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001990 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001991 l = 2;
1992 } else {
1993 /* 8 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001994 val = io_mem_read(io_index, addr1, 1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001995 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001996 l = 1;
1997 }
1998 } else {
1999 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002000 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002001 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002002 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002003 }
2004 }
2005 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002006 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002007 addr += l;
2008 }
2009}
2010
2011/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002012void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002013 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002014{
2015 int l;
2016 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002017 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002018 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002019 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002020 PhysPageDesc *p;
2021
2022 while (len > 0) {
2023 page = addr & TARGET_PAGE_MASK;
2024 l = (page + TARGET_PAGE_SIZE) - addr;
2025 if (l > len)
2026 l = len;
2027 p = phys_page_find(page >> TARGET_PAGE_BITS);
2028 if (!p) {
2029 pd = IO_MEM_UNASSIGNED;
2030 } else {
2031 pd = p->phys_offset;
2032 }
2033
2034 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2035 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2036 !(pd & IO_MEM_ROMD)) {
2037 /* do nothing */
2038 } else {
2039 unsigned long addr1;
2040 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2041 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002042 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002043 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002044 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002045 }
2046 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002047 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002048 addr += l;
2049 }
2050}
2051
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002052typedef struct {
2053 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002054 hwaddr addr;
2055 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002056} BounceBuffer;
2057
2058static BounceBuffer bounce;
2059
2060typedef struct MapClient {
2061 void *opaque;
2062 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002063 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002064} MapClient;
2065
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002066static QLIST_HEAD(map_client_list, MapClient) map_client_list
2067 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002068
2069void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2070{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002071 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002072
2073 client->opaque = opaque;
2074 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002075 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002076 return client;
2077}
2078
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002079static void cpu_unregister_map_client(void *_client)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002080{
2081 MapClient *client = (MapClient *)_client;
2082
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002083 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002084 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002085}
2086
2087static void cpu_notify_map_clients(void)
2088{
2089 MapClient *client;
2090
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002091 while (!QLIST_EMPTY(&map_client_list)) {
2092 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002093 client->callback(client->opaque);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002094 cpu_unregister_map_client(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002095 }
2096}
2097
2098/* Map a physical memory region into a host virtual address.
2099 * May map a subset of the requested range, given by and returned in *plen.
2100 * May return NULL if resources needed to perform the mapping are exhausted.
2101 * Use only for reads OR writes - not for read-modify-write operations.
2102 * Use cpu_register_map_client() to know when retrying the map operation is
2103 * likely to succeed.
2104 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002105void *cpu_physical_memory_map(hwaddr addr,
2106 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002107 int is_write)
2108{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002109 hwaddr len = *plen;
2110 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002111 int l;
2112 uint8_t *ret = NULL;
2113 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002114 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002115 unsigned long pd;
2116 PhysPageDesc *p;
2117 unsigned long addr1;
2118
2119 while (len > 0) {
2120 page = addr & TARGET_PAGE_MASK;
2121 l = (page + TARGET_PAGE_SIZE) - addr;
2122 if (l > len)
2123 l = len;
2124 p = phys_page_find(page >> TARGET_PAGE_BITS);
2125 if (!p) {
2126 pd = IO_MEM_UNASSIGNED;
2127 } else {
2128 pd = p->phys_offset;
2129 }
2130
2131 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2132 if (done || bounce.buffer) {
2133 break;
2134 }
2135 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2136 bounce.addr = addr;
2137 bounce.len = l;
2138 if (!is_write) {
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002139 cpu_physical_memory_read(addr, bounce.buffer, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002140 }
2141 ptr = bounce.buffer;
2142 } else {
2143 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2144 ptr = qemu_get_ram_ptr(addr1);
2145 }
2146 if (!done) {
2147 ret = ptr;
2148 } else if (ret + done != ptr) {
2149 break;
2150 }
2151
2152 len -= l;
2153 addr += l;
2154 done += l;
2155 }
2156 *plen = done;
2157 return ret;
2158}
2159
2160/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2161 * Will also mark the memory as dirty if is_write == 1. access_len gives
2162 * the amount of memory that was actually read or written by the caller.
2163 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002164void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2165 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002166{
2167 if (buffer != bounce.buffer) {
2168 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002169 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002170 while (access_len) {
2171 unsigned l;
2172 l = TARGET_PAGE_SIZE;
2173 if (l > access_len)
2174 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002175 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002176 addr1 += l;
2177 access_len -= l;
2178 }
2179 }
2180 return;
2181 }
2182 if (is_write) {
2183 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2184 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002185 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002186 bounce.buffer = NULL;
2187 cpu_notify_map_clients();
2188}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002189
2190/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002191static inline uint32_t ldl_phys_internal(hwaddr addr,
2192 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002193{
2194 int io_index;
2195 uint8_t *ptr;
2196 uint32_t val;
2197 unsigned long pd;
2198 PhysPageDesc *p;
2199
2200 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2201 if (!p) {
2202 pd = IO_MEM_UNASSIGNED;
2203 } else {
2204 pd = p->phys_offset;
2205 }
2206
2207 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2208 !(pd & IO_MEM_ROMD)) {
2209 /* I/O case */
2210 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002211 if (p)
2212 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002213 val = io_mem_read(io_index, addr, 4);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002214#if defined(TARGET_WORDS_BIGENDIAN)
2215 if (endian == DEVICE_LITTLE_ENDIAN) {
2216 val = bswap32(val);
2217 }
2218#else
2219 if (endian == DEVICE_BIG_ENDIAN) {
2220 val = bswap32(val);
2221 }
2222#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002223 } else {
2224 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002225 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002226 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002227 switch (endian) {
2228 case DEVICE_LITTLE_ENDIAN:
2229 val = ldl_le_p(ptr);
2230 break;
2231 case DEVICE_BIG_ENDIAN:
2232 val = ldl_be_p(ptr);
2233 break;
2234 default:
2235 val = ldl_p(ptr);
2236 break;
2237 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002238 }
2239 return val;
2240}
2241
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002242uint32_t ldl_phys(hwaddr addr)
2243{
2244 return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2245}
2246
2247uint32_t ldl_le_phys(hwaddr addr)
2248{
2249 return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2250}
2251
2252uint32_t ldl_be_phys(hwaddr addr)
2253{
2254 return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
2255}
2256
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002257/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002258static inline uint64_t ldq_phys_internal(hwaddr addr,
2259 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002260{
2261 int io_index;
2262 uint8_t *ptr;
2263 uint64_t val;
2264 unsigned long pd;
2265 PhysPageDesc *p;
2266
2267 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2268 if (!p) {
2269 pd = IO_MEM_UNASSIGNED;
2270 } else {
2271 pd = p->phys_offset;
2272 }
2273
2274 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2275 !(pd & IO_MEM_ROMD)) {
2276 /* I/O case */
2277 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002278 if (p)
2279 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002280
2281 /* XXX This is broken when device endian != cpu endian.
2282 Fix and add "endian" variable check */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002283#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002284 val = (uint64_t)io_mem_read(io_index, addr, 4) << 32;
2285 val |= io_mem_read(io_index, addr + 4, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002286#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002287 val = io_mem_read(io_index, addr, 4);
2288 val |= (uint64_t)io_mem_read(io_index, addr + 4, 4) << 32;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002289#endif
2290 } else {
2291 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002292 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002293 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002294 switch (endian) {
2295 case DEVICE_LITTLE_ENDIAN:
2296 val = ldq_le_p(ptr);
2297 break;
2298 case DEVICE_BIG_ENDIAN:
2299 val = ldq_be_p(ptr);
2300 break;
2301 default:
2302 val = ldq_p(ptr);
2303 break;
2304 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002305 }
2306 return val;
2307}
2308
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002309uint64_t ldq_phys(hwaddr addr)
2310{
2311 return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2312}
2313
2314uint64_t ldq_le_phys(hwaddr addr)
2315{
2316 return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2317}
2318
2319uint64_t ldq_be_phys(hwaddr addr)
2320{
2321 return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
2322}
2323
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002324/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002325uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002326{
2327 uint8_t val;
2328 cpu_physical_memory_read(addr, &val, 1);
2329 return val;
2330}
2331
2332/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002333static inline uint32_t lduw_phys_internal(hwaddr addr,
2334 enum device_endian endian)
2335{
2336 int io_index;
2337 uint8_t *ptr;
2338 uint64_t val;
2339 unsigned long pd;
2340 PhysPageDesc *p;
2341
2342 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2343 if (!p) {
2344 pd = IO_MEM_UNASSIGNED;
2345 } else {
2346 pd = p->phys_offset;
2347 }
2348
2349 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2350 !(pd & IO_MEM_ROMD)) {
2351 /* I/O case */
2352 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2353 if (p)
2354 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002355 val = io_mem_read(io_index, addr, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002356#if defined(TARGET_WORDS_BIGENDIAN)
2357 if (endian == DEVICE_LITTLE_ENDIAN) {
2358 val = bswap16(val);
2359 }
2360#else
2361 if (endian == DEVICE_BIG_ENDIAN) {
2362 val = bswap16(val);
2363 }
2364#endif
2365 } else {
2366 /* RAM case */
2367 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
2368 (addr & ~TARGET_PAGE_MASK);
2369 switch (endian) {
2370 case DEVICE_LITTLE_ENDIAN:
2371 val = lduw_le_p(ptr);
2372 break;
2373 case DEVICE_BIG_ENDIAN:
2374 val = lduw_be_p(ptr);
2375 break;
2376 default:
2377 val = lduw_p(ptr);
2378 break;
2379 }
2380 }
2381 return val;
2382}
2383
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002384uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002385{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002386 return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2387}
2388
2389uint32_t lduw_le_phys(hwaddr addr)
2390{
2391 return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2392}
2393
2394uint32_t lduw_be_phys(hwaddr addr)
2395{
2396 return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002397}
2398
2399/* warning: addr must be aligned. The ram page is not masked as dirty
2400 and the code inside is not invalidated. It is useful if the dirty
2401 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002402void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002403{
2404 int io_index;
2405 uint8_t *ptr;
2406 unsigned long pd;
2407 PhysPageDesc *p;
2408
2409 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2410 if (!p) {
2411 pd = IO_MEM_UNASSIGNED;
2412 } else {
2413 pd = p->phys_offset;
2414 }
2415
2416 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2417 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002418 if (p)
2419 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002420 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002421 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002422 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2423 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002424 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002425
2426 if (unlikely(in_migration)) {
2427 if (!cpu_physical_memory_is_dirty(addr1)) {
2428 /* invalidate code */
2429 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2430 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002431 cpu_physical_memory_set_dirty_flags(
2432 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002433 }
2434 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002435 }
2436}
2437
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002438void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002439{
2440 int io_index;
2441 uint8_t *ptr;
2442 unsigned long pd;
2443 PhysPageDesc *p;
2444
2445 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2446 if (!p) {
2447 pd = IO_MEM_UNASSIGNED;
2448 } else {
2449 pd = p->phys_offset;
2450 }
2451
2452 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2453 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002454 if (p)
2455 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002456#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002457 io_mem_write(io_index, addr, val >> 32, 4);
2458 io_mem_write(io_index, addr + 4, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002459#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002460 io_mem_write(io_index, addr, val, 4);
2461 io_mem_write(io_index, addr + 4, val >> 32, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002462#endif
2463 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002464 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002465 (addr & ~TARGET_PAGE_MASK);
2466 stq_p(ptr, val);
2467 }
2468}
2469
2470/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002471static inline void stl_phys_internal(hwaddr addr, uint32_t val,
2472 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002473{
2474 int io_index;
2475 uint8_t *ptr;
2476 unsigned long pd;
2477 PhysPageDesc *p;
2478
2479 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2480 if (!p) {
2481 pd = IO_MEM_UNASSIGNED;
2482 } else {
2483 pd = p->phys_offset;
2484 }
2485
2486 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2487 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002488 if (p)
2489 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002490#if defined(TARGET_WORDS_BIGENDIAN)
2491 if (endian == DEVICE_LITTLE_ENDIAN) {
2492 val = bswap32(val);
2493 }
2494#else
2495 if (endian == DEVICE_BIG_ENDIAN) {
2496 val = bswap32(val);
2497 }
2498#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002499 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002500 } else {
2501 unsigned long addr1;
2502 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2503 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002504 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002505 switch (endian) {
2506 case DEVICE_LITTLE_ENDIAN:
2507 stl_le_p(ptr, val);
2508 break;
2509 case DEVICE_BIG_ENDIAN:
2510 stl_be_p(ptr, val);
2511 break;
2512 default:
2513 stl_p(ptr, val);
2514 break;
2515 }
Pete Delaneyd09d7662013-03-28 19:53:13 -07002516 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002517 }
2518}
2519
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002520void stl_phys(hwaddr addr, uint32_t val)
2521{
2522 stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2523}
2524
2525void stl_le_phys(hwaddr addr, uint32_t val)
2526{
2527 stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2528}
2529
2530void stl_be_phys(hwaddr addr, uint32_t val)
2531{
2532 stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
2533}
2534
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002535/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002536void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002537{
2538 uint8_t v = val;
2539 cpu_physical_memory_write(addr, &v, 1);
2540}
2541
2542/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002543static inline void stw_phys_internal(hwaddr addr, uint32_t val,
2544 enum device_endian endian)
2545{
2546 int io_index;
2547 uint8_t *ptr;
2548 unsigned long pd;
2549 PhysPageDesc *p;
2550
2551 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2552 if (!p) {
2553 pd = IO_MEM_UNASSIGNED;
2554 } else {
2555 pd = p->phys_offset;
2556 }
2557
2558 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2559 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2560 if (p)
2561 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2562#if defined(TARGET_WORDS_BIGENDIAN)
2563 if (endian == DEVICE_LITTLE_ENDIAN) {
2564 val = bswap16(val);
2565 }
2566#else
2567 if (endian == DEVICE_BIG_ENDIAN) {
2568 val = bswap16(val);
2569 }
2570#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002571 io_mem_write(io_index, addr, val, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002572 } else {
2573 unsigned long addr1;
2574 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2575 /* RAM case */
2576 ptr = qemu_get_ram_ptr(addr1);
2577 switch (endian) {
2578 case DEVICE_LITTLE_ENDIAN:
2579 stw_le_p(ptr, val);
2580 break;
2581 case DEVICE_BIG_ENDIAN:
2582 stw_be_p(ptr, val);
2583 break;
2584 default:
2585 stw_p(ptr, val);
2586 break;
2587 }
2588 if (!cpu_physical_memory_is_dirty(addr1)) {
2589 /* invalidate code */
2590 tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
2591 /* set dirty bit */
2592 cpu_physical_memory_set_dirty_flags(addr1,
2593 (0xff & ~CODE_DIRTY_FLAG));
2594 }
2595 }
2596}
2597
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002598void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002599{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002600 stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2601}
2602
2603void stw_le_phys(hwaddr addr, uint32_t val)
2604{
2605 stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2606}
2607
2608void stw_be_phys(hwaddr addr, uint32_t val)
2609{
2610 stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002611}
2612
2613/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002614void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002615{
2616 val = tswap64(val);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002617 cpu_physical_memory_write(addr, &val, 8);
2618}
2619
2620
2621void stq_le_phys(hwaddr addr, uint64_t val)
2622{
2623 val = cpu_to_le64(val);
2624 cpu_physical_memory_write(addr, &val, 8);
2625}
2626
2627void stq_be_phys(hwaddr addr, uint64_t val)
2628{
2629 val = cpu_to_be64(val);
2630 cpu_physical_memory_write(addr, &val, 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002631}
2632
2633#endif
2634
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002635/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002636int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002637 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002638{
2639 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002640 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002641 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002642 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002643
2644 while (len > 0) {
2645 page = addr & TARGET_PAGE_MASK;
2646 phys_addr = cpu_get_phys_page_debug(env, page);
2647 /* if no physical page mapped, return an error */
2648 if (phys_addr == -1)
2649 return -1;
2650 l = (page + TARGET_PAGE_SIZE) - addr;
2651 if (l > len)
2652 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002653 phys_addr += (addr & ~TARGET_PAGE_MASK);
2654#if !defined(CONFIG_USER_ONLY)
2655 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002656 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002657 else
2658#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002659 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002660 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002661 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002662 addr += l;
2663 }
2664 return 0;
2665}