blob: 61ba9e3200e8a22c661d7d29a4547575fe7abe9b [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' Turner4ab12252014-03-24 11:29:53 +010043#include "qemu/tls.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010044#include "sysemu/kvm.h"
David 'Digit' Turner3dc53fc2014-01-17 01:23:40 +010045#include "exec/cputlb.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010046#include "exec/hax.h"
David 'Digit' Turner7a78db72013-12-14 11:46:01 +010047#include "qemu/timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080048#if defined(CONFIG_USER_ONLY)
49#include <qemu.h>
50#endif
David 'Digit' Turner5bb450e2014-03-14 17:19:45 +010051#ifdef CONFIG_ANDROID_MEMCHECK
David 'Digit' Turner96e493a2014-03-14 17:17:26 +010052#include "android/qemu/memcheck/memcheck_api.h"
David 'Digit' Turner5bb450e2014-03-14 17:19:45 +010053#endif // CONFIG_ANDROID_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080054
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080055//#define DEBUG_SUBPAGE
56
57#if !defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080058int phys_ram_fd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070059static int in_migration;
60
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +010061RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) };
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080062#endif
63
David 'Digit' Turner4ab12252014-03-24 11:29:53 +010064struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
65DEFINE_TLS(CPUState *, current_cpu);
66
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' Turner4ab12252014-03-24 11:29:53 +0100156 CPUState *env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700157
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100158 CPU_FOREACH(env) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700159 if (env->cpu_index == cpu)
160 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700161 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700162 return env;
163}
164
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100165void cpu_exec_init(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800166{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700167#if defined(CONFIG_USER_ONLY)
168 cpu_list_lock();
169#endif
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100170 // Compute CPU index from list position.
171 int cpu_index = 0;
172 CPUState *env1;
173 CPU_FOREACH(env1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800174 cpu_index++;
175 }
176 env->cpu_index = cpu_index;
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100177 QTAILQ_INSERT_TAIL(&cpus, env, node);
178
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700179 env->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700180 QTAILQ_INIT(&env->breakpoints);
181 QTAILQ_INIT(&env->watchpoints);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700182#if defined(CONFIG_USER_ONLY)
183 cpu_list_unlock();
184#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800185#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +0100186 register_savevm(NULL,
187 "cpu_common",
188 cpu_index,
189 CPU_COMMON_SAVE_VERSION,
190 cpu_common_save,
191 cpu_common_load,
192 env);
193 register_savevm(NULL,
194 "cpu",
195 cpu_index,
196 CPU_SAVE_VERSION,
197 cpu_save,
198 cpu_load,
199 env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800200#endif
201}
202
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800203#if defined(TARGET_HAS_ICE)
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100204static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800205{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100206 hwaddr addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800207 target_ulong pd;
208 ram_addr_t ram_addr;
209 PhysPageDesc *p;
210
211 addr = cpu_get_phys_page_debug(env, pc);
212 p = phys_page_find(addr >> TARGET_PAGE_BITS);
213 if (!p) {
214 pd = IO_MEM_UNASSIGNED;
215 } else {
216 pd = p->phys_offset;
217 }
218 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
219 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
220}
221#endif
222
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100223#if defined(CONFIG_USER_ONLY)
224void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
225
226{
227}
228
229int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
230 int flags, CPUWatchpoint **watchpoint)
231{
232 return -ENOSYS;
233}
234#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800235/* Add a watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100236int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700237 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800238{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700239 target_ulong len_mask = ~(len - 1);
240 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800241
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700242 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100243 if ((len & (len - 1)) || (addr & ~len_mask) ||
244 len == 0 || len > TARGET_PAGE_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700245 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
246 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
247 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800248 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100249 wp = g_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800250
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700251 wp->vaddr = addr;
252 wp->len_mask = len_mask;
253 wp->flags = flags;
254
255 /* keep all GDB-injected watchpoints in front */
256 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700257 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700258 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700259 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700260
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800261 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700262
263 if (watchpoint)
264 *watchpoint = wp;
265 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800266}
267
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700268/* Remove a specific watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100269int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700270 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800271{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700272 target_ulong len_mask = ~(len - 1);
273 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800274
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700275 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700276 if (addr == wp->vaddr && len_mask == wp->len_mask
277 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
278 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279 return 0;
280 }
281 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700282 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800283}
284
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700285/* Remove a specific watchpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100286void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700287{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700288 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800289
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700290 tlb_flush_page(env, watchpoint->vaddr);
291
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100292 g_free(watchpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700293}
294
295/* Remove all matching watchpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100296void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700297{
298 CPUWatchpoint *wp, *next;
299
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700300 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700301 if (wp->flags & mask)
302 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800303 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800304}
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100305#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800306
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700307/* Add a breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100308int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700309 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800310{
311#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700312 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800313
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100314 bp = g_malloc(sizeof(*bp));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700315
316 bp->pc = pc;
317 bp->flags = flags;
318
319 /* keep all GDB-injected breakpoints in front */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100320 if (flags & BP_GDB) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700321 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100322 } else {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700323 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100324 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700325
326 breakpoint_invalidate(env, pc);
327
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100328 if (breakpoint) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700329 *breakpoint = bp;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100330 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700331 return 0;
332#else
333 return -ENOSYS;
334#endif
335}
336
337/* Remove a specific breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100338int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700339{
340#if defined(TARGET_HAS_ICE)
341 CPUBreakpoint *bp;
342
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700343 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700344 if (bp->pc == pc && bp->flags == flags) {
345 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800346 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700347 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800348 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700349 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800350#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700351 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800352#endif
353}
354
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355/* Remove a specific breakpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100356void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800357{
358#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700359 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800360
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700361 breakpoint_invalidate(env, breakpoint->pc);
362
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100363 g_free(breakpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700364#endif
365}
366
367/* Remove all matching breakpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100368void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700369{
370#if defined(TARGET_HAS_ICE)
371 CPUBreakpoint *bp, *next;
372
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700373 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700374 if (bp->flags & mask)
375 cpu_breakpoint_remove_by_ref(env, bp);
376 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800377#endif
378}
379
380/* enable or disable single step mode. EXCP_DEBUG is returned by the
381 CPU loop after each instruction */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100382void cpu_single_step(CPUOldState *env, int enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800383{
384#if defined(TARGET_HAS_ICE)
385 if (env->singlestep_enabled != enabled) {
386 env->singlestep_enabled = enabled;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100387 if (kvm_enabled()) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700388 kvm_update_guest_debug(env, 0);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100389 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700390 /* must flush all the translated code to avoid inconsistencies */
391 /* XXX: only flush what is necessary */
392 tb_flush(env);
393 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800394 }
395#endif
396}
397
398/* enable or disable low levels log */
399void cpu_set_log(int log_flags)
400{
401 loglevel = log_flags;
402 if (loglevel && !logfile) {
403 logfile = fopen(logfilename, log_append ? "a" : "w");
404 if (!logfile) {
405 perror(logfilename);
Iliyan Malchev4a2c9dd2012-04-02 08:20:56 -0700406 exit(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800407 }
408#if !defined(CONFIG_SOFTMMU)
409 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
410 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700411 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800412 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
413 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700414#elif !defined(_WIN32)
415 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800416 setvbuf(logfile, NULL, _IOLBF, 0);
417#endif
418 log_append = 1;
419 }
420 if (!loglevel && logfile) {
421 fclose(logfile);
422 logfile = NULL;
423 }
424}
425
426void cpu_set_log_filename(const char *filename)
427{
428 logfilename = strdup(filename);
429 if (logfile) {
430 fclose(logfile);
431 logfile = NULL;
432 }
433 cpu_set_log(loglevel);
434}
435
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100436void cpu_unlink_tb(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800437{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800438 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
439 problem and hope the cpu will stop of its own accord. For userspace
440 emulation this often isn't actually as bad as it sounds. Often
441 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700442 TranslationBlock *tb;
443 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
444
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200445 spin_lock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700446 tb = env->current_tb;
447 /* if the cpu is currently executing code, we must unlink it and
448 all the potentially executing TB */
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200449 if (tb) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700450 env->current_tb = NULL;
451 tb_reset_jump_recursive(tb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700452 }
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200453 spin_unlock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700454}
455
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100456void cpu_reset_interrupt(CPUOldState *env, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800457{
458 env->interrupt_request &= ~mask;
459}
460
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100461void cpu_exit(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700462{
463 env->exit_request = 1;
464 cpu_unlink_tb(env);
465}
466
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100467void cpu_abort(CPUArchState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800468{
469 va_list ap;
470 va_list ap2;
471
472 va_start(ap, fmt);
473 va_copy(ap2, ap);
474 fprintf(stderr, "qemu: fatal: ");
475 vfprintf(stderr, fmt, ap);
476 fprintf(stderr, "\n");
477#ifdef TARGET_I386
478 cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
479#else
480 cpu_dump_state(env, stderr, fprintf, 0);
481#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700482 if (qemu_log_enabled()) {
483 qemu_log("qemu: fatal: ");
484 qemu_log_vprintf(fmt, ap2);
485 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800486#ifdef TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700487 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800488#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700489 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800490#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700491 qemu_log_flush();
492 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800493 }
494 va_end(ap2);
495 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +0100496#if defined(CONFIG_USER_ONLY)
497 {
498 struct sigaction act;
499 sigfillset(&act.sa_mask);
500 act.sa_handler = SIG_DFL;
501 sigaction(SIGABRT, &act, NULL);
502 }
503#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800504 abort();
505}
506
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800507#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100508static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
509{
510 RAMBlock *block;
511
512 /* The list is protected by the iothread lock here. */
513 block = ram_list.mru_block;
514 if (block && addr - block->offset < block->length) {
515 goto found;
516 }
517 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
518 if (addr - block->offset < block->length) {
519 goto found;
520 }
521 }
522
523 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
524 abort();
525
526found:
527 ram_list.mru_block = block;
528 return block;
529}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800530
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700531/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800532void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
533 int dirty_flags)
534{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100535 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800536 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200537 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800538
539 start &= TARGET_PAGE_MASK;
540 end = TARGET_PAGE_ALIGN(end);
541
542 length = end - start;
543 if (length == 0)
544 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200545 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800546
547 /* we modify the TLB cache so that the dirty bit will be set again
548 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200549 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700550 /* Chek that we don't span multiple blocks - this breaks the
551 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200552 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700553 != (end - 1) - start) {
554 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800555 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700556
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100557 CPU_FOREACH(env) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700558 int mmu_idx;
559 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
560 for(i = 0; i < CPU_TLB_SIZE; i++)
561 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
562 start1, length);
563 }
564 }
565}
566
567int cpu_physical_memory_set_dirty_tracking(int enable)
568{
569 in_migration = enable;
570 if (kvm_enabled()) {
571 return kvm_set_migration_log(enable);
572 }
573 return 0;
574}
575
576int cpu_physical_memory_get_dirty_tracking(void)
577{
578 return in_migration;
579}
580
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100581int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
582 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700583{
584 int ret = 0;
585
586 if (kvm_enabled())
587 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
588 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800589}
590
591static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
592{
593 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700594 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800595
596 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700597 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
598 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200599 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800600 if (!cpu_physical_memory_is_dirty(ram_addr)) {
601 tlb_entry->addr_write |= TLB_NOTDIRTY;
602 }
603 }
604}
605
606/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100607void cpu_tlb_update_dirty(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608{
609 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700610 int mmu_idx;
611 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
612 for(i = 0; i < CPU_TLB_SIZE; i++)
613 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
614 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800615}
616
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800617
618#else
619
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100620void tlb_flush(CPUArchState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800621{
622}
623
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100624void tlb_flush_page(CPUArchState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800625{
626}
627
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100628int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100629 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800630 int mmu_idx, int is_softmmu)
631{
632 return 0;
633}
634
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100635static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800636 unsigned long addr, target_ulong vaddr)
637{
638}
639#endif /* defined(CONFIG_USER_ONLY) */
640
641#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700642
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800643static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700644 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100645static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700646 ram_addr_t orig_memory, ram_addr_t region_offset);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100647
648static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
649
650/*
651 * Set a custom physical guest memory alloator.
652 * Accelerators with unusual needs may need this. Hopefully, we can
653 * get rid of it eventually.
654 */
655void phys_mem_set_alloc(void *(*alloc)(size_t))
656{
657 phys_mem_alloc = alloc;
658}
659
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800660#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
661 need_subpage) \
662 do { \
663 if (addr > start_addr) \
664 start_addr2 = 0; \
665 else { \
666 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
667 if (start_addr2 > 0) \
668 need_subpage = 1; \
669 } \
670 \
671 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
672 end_addr2 = TARGET_PAGE_SIZE - 1; \
673 else { \
674 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
675 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
676 need_subpage = 1; \
677 } \
678 } while (0)
679
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700680/* register physical memory.
681 For RAM, 'size' must be a multiple of the target page size.
682 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700683 io memory page. The address used when calling the IO function is
684 the offset from the start of the region, plus region_offset. Both
685 start_addr and region_offset are rounded down to a page boundary
686 before calculating this offset. This should not be a problem unless
687 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100688void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700689 ram_addr_t size,
690 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200691 ram_addr_t region_offset,
692 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800693{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100694 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800695 PhysPageDesc *p;
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100696 CPUOldState *env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800697 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200698 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800699
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700700 if (kvm_enabled())
701 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800702#ifdef CONFIG_HAX
703 if (hax_enabled())
704 hax_set_phys_mem(start_addr, size, phys_offset);
705#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700706
707 if (phys_offset == IO_MEM_UNASSIGNED) {
708 region_offset = start_addr;
709 }
710 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800711 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100712 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200713
714 addr = start_addr;
715 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800716 p = phys_page_find(addr >> TARGET_PAGE_BITS);
717 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
718 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100719 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800720 int need_subpage = 0;
721
722 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
723 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200724 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800725 if (!(orig_memory & IO_MEM_SUBPAGE)) {
726 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700727 &p->phys_offset, orig_memory,
728 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800729 } else {
730 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
731 >> IO_MEM_SHIFT];
732 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700733 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
734 region_offset);
735 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800736 } else {
737 p->phys_offset = phys_offset;
738 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
739 (phys_offset & IO_MEM_ROMD))
740 phys_offset += TARGET_PAGE_SIZE;
741 }
742 } else {
743 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
744 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700745 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800746 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700747 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800748 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700749 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100750 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800751 int need_subpage = 0;
752
753 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
754 end_addr2, need_subpage);
755
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200756 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800757 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700758 &p->phys_offset, IO_MEM_UNASSIGNED,
759 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800760 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700761 phys_offset, region_offset);
762 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800763 }
764 }
765 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700766 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200767 addr += TARGET_PAGE_SIZE;
768 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800769
770 /* since each CPU stores ram addresses in its TLB cache, we must
771 reset the modified entries */
772 /* XXX: slow ! */
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100773 CPU_FOREACH(env) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800774 tlb_flush(env, 1);
775 }
776}
777
778/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100779ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800780{
781 PhysPageDesc *p;
782
783 p = phys_page_find(addr >> TARGET_PAGE_BITS);
784 if (!p)
785 return IO_MEM_UNASSIGNED;
786 return p->phys_offset;
787}
788
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100789void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700790{
791 if (kvm_enabled())
792 kvm_coalesce_mmio_region(addr, size);
793}
794
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100795void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700796{
797 if (kvm_enabled())
798 kvm_uncoalesce_mmio_region(addr, size);
799}
800
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100801void qemu_mutex_lock_ramlist(void)
802{
803 qemu_mutex_lock(&ram_list.mutex);
804}
805
806void qemu_mutex_unlock_ramlist(void)
807{
808 qemu_mutex_unlock(&ram_list.mutex);
809}
810
811#if defined(__linux__) && !defined(CONFIG_ANDROID)
812
813#include <sys/vfs.h>
814
815#define HUGETLBFS_MAGIC 0x958458f6
816
817static long gethugepagesize(const char *path)
818{
819 struct statfs fs;
820 int ret;
821
822 do {
823 ret = statfs(path, &fs);
824 } while (ret != 0 && errno == EINTR);
825
826 if (ret != 0) {
827 perror(path);
828 return 0;
829 }
830
831 if (fs.f_type != HUGETLBFS_MAGIC)
832 fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
833
834 return fs.f_bsize;
835}
836
837static sigjmp_buf sigjump;
838
839static void sigbus_handler(int signal)
840{
841 siglongjmp(sigjump, 1);
842}
843
844static void *file_ram_alloc(RAMBlock *block,
845 ram_addr_t memory,
846 const char *path)
847{
848 char *filename;
849 char *sanitized_name;
850 char *c;
851 void *area;
852 int fd;
853 unsigned long hpagesize;
854
855 hpagesize = gethugepagesize(path);
856 if (!hpagesize) {
857 return NULL;
858 }
859
860 if (memory < hpagesize) {
861 return NULL;
862 }
863
864 if (kvm_enabled() && !kvm_has_sync_mmu()) {
865 fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
866 return NULL;
867 }
868
869 /* Make name safe to use with mkstemp by replacing '/' with '_'. */
870 sanitized_name = g_strdup(block->mr->name);
871 for (c = sanitized_name; *c != '\0'; c++) {
872 if (*c == '/')
873 *c = '_';
874 }
875
876 filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
877 sanitized_name);
878 g_free(sanitized_name);
879
880 fd = mkstemp(filename);
881 if (fd < 0) {
882 perror("unable to create backing store for hugepages");
883 g_free(filename);
884 return NULL;
885 }
886 unlink(filename);
887 g_free(filename);
888
889 memory = (memory+hpagesize-1) & ~(hpagesize-1);
890
891 /*
892 * ftruncate is not supported by hugetlbfs in older
893 * hosts, so don't bother bailing out on errors.
894 * If anything goes wrong with it under other filesystems,
895 * mmap will fail.
896 */
897 if (ftruncate(fd, memory))
898 perror("ftruncate");
899
900 area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
901 if (area == MAP_FAILED) {
902 perror("file_ram_alloc: can't mmap RAM pages");
903 close(fd);
904 return (NULL);
905 }
906
907 if (mem_prealloc) {
908 int ret, i;
909 struct sigaction act, oldact;
910 sigset_t set, oldset;
911
912 memset(&act, 0, sizeof(act));
913 act.sa_handler = &sigbus_handler;
914 act.sa_flags = 0;
915
916 ret = sigaction(SIGBUS, &act, &oldact);
917 if (ret) {
918 perror("file_ram_alloc: failed to install signal handler");
919 exit(1);
920 }
921
922 /* unblock SIGBUS */
923 sigemptyset(&set);
924 sigaddset(&set, SIGBUS);
925 pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
926
927 if (sigsetjmp(sigjump, 1)) {
928 fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
929 exit(1);
930 }
931
932 /* MAP_POPULATE silently ignores failures */
933 for (i = 0; i < (memory/hpagesize)-1; i++) {
934 memset(area + (hpagesize*i), 0, 1);
935 }
936
937 ret = sigaction(SIGBUS, &oldact, NULL);
938 if (ret) {
939 perror("file_ram_alloc: failed to reinstall signal handler");
940 exit(1);
941 }
942
943 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
944 }
945
946 block->fd = fd;
947 return area;
948}
949#else
950static void *file_ram_alloc(RAMBlock *block,
951 ram_addr_t memory,
952 const char *path)
953{
954 fprintf(stderr, "-mem-path not supported on this host\n");
955 exit(1);
956}
957#endif
958
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200959static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700960{
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200961 RAMBlock *block, *next_block;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100962 ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200963
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100964 assert(size != 0); /* it would hand out same offset multiple times */
965
966 if (QTAILQ_EMPTY(&ram_list.blocks))
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200967 return 0;
968
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100969 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
970 ram_addr_t end, next = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200971
972 end = block->offset + block->length;
973
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100974 QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200975 if (next_block->offset >= end) {
976 next = MIN(next, next_block->offset);
977 }
978 }
979 if (next - end >= size && next - end < mingap) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100980 offset = end;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200981 mingap = next - end;
982 }
983 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100984
985 if (offset == RAM_ADDR_MAX) {
986 fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
987 (uint64_t)size);
988 abort();
989 }
990
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200991 return offset;
992}
993
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100994ram_addr_t last_ram_offset(void)
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200995{
996 RAMBlock *block;
997 ram_addr_t last = 0;
998
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100999 QTAILQ_FOREACH(block, &ram_list.blocks, next)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001000 last = MAX(last, block->offset + block->length);
1001
1002 return last;
1003}
1004
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001005static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
1006{
1007#ifndef CONFIG_ANDROID
1008 int ret;
1009
1010 /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
1011 if (!qemu_opt_get_bool(qemu_get_machine_opts(),
1012 "dump-guest-core", true)) {
1013 ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
1014 if (ret) {
1015 perror("qemu_madvise");
1016 fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
1017 "but dump_guest_core=off specified\n");
1018 }
1019 }
1020#endif // !CONFIG_ANDROID
1021}
1022
1023void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001024{
1025 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001026
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001027 new_block = NULL;
1028 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1029 if (block->offset == addr) {
1030 new_block = block;
1031 break;
1032 }
1033 }
1034 assert(new_block);
1035 assert(!new_block->idstr[0]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001036
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001037 if (dev) {
1038 char *id = qdev_get_dev_path(dev);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001039 if (id) {
1040 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001041 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001042 }
1043 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001044 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1045
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001046 /* This assumes the iothread lock is taken here too. */
1047 qemu_mutex_lock_ramlist();
1048 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1049 if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001050 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
1051 new_block->idstr);
1052 abort();
1053 }
1054 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001055 qemu_mutex_unlock_ramlist();
1056}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001057
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001058static int memory_try_enable_merging(void *addr, size_t len)
1059{
1060#ifndef CONFIG_ANDROID
1061 if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) {
1062 /* disabled by the user */
1063 return 0;
1064 }
1065
1066 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1067#else // CONFIG_ANDROID
1068 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1069#endif // CONFIG_ANDROID
1070}
1071
1072ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
1073 ram_addr_t size, void *host)
1074{
1075 RAMBlock *block, *new_block;
1076
1077 size = TARGET_PAGE_ALIGN(size);
1078 new_block = g_malloc0(sizeof(*new_block));
1079 new_block->fd = -1;
1080
1081 /* This assumes the iothread lock is taken here too. */
1082 qemu_mutex_lock_ramlist();
1083 //new_block->mr = mr;
1084 new_block->offset = find_ram_offset(size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001085 if (host) {
1086 new_block->host = host;
1087 new_block->flags |= RAM_PREALLOC_MASK;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001088 } else if (xen_enabled()) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001089 if (mem_path) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001090 fprintf(stderr, "-mem-path not supported with Xen\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001091 exit(1);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001092 }
1093 //xen_ram_alloc(new_block->offset, size, mr);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001094 } else {
1095 if (mem_path) {
1096 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1097 /*
1098 * file_ram_alloc() needs to allocate just like
1099 * phys_mem_alloc, but we haven't bothered to provide
1100 * a hook there.
1101 */
1102 fprintf(stderr,
1103 "-mem-path not supported with this accelerator\n");
1104 exit(1);
1105 }
1106 new_block->host = file_ram_alloc(new_block, size, mem_path);
1107 }
1108 if (!new_block->host) {
1109 new_block->host = phys_mem_alloc(size);
1110 if (!new_block->host) {
1111 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1112 name, strerror(errno));
1113 exit(1);
1114 }
David 'Digit' Turnerf2de2ae2014-03-07 16:25:58 +01001115#ifdef CONFIG_HAX
1116 if (hax_enabled()) {
1117 /*
1118 * In HAX, qemu allocates the virtual address, and HAX kernel
1119 * module populates the region with physical memory. Currently
1120 * we don’t populate guest memory on demand, thus we should
1121 * make sure that sufficient amount of memory is available in
1122 * advance.
1123 */
1124 int ret = hax_populate_ram(
1125 (uint64_t)(uintptr_t)new_block->host,
1126 (uint32_t)size);
1127 if (ret < 0) {
1128 fprintf(stderr, "Hax failed to populate ram\n");
1129 exit(-1);
1130 }
1131 }
1132#endif // CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001133 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001134 }
1135 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001136 new_block->length = size;
1137
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001138 /* Keep the list sorted from biggest to smallest block. */
1139 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1140 if (block->length < new_block->length) {
1141 break;
1142 }
1143 }
1144 if (block) {
1145 QTAILQ_INSERT_BEFORE(block, new_block, next);
1146 } else {
1147 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1148 }
1149 ram_list.mru_block = NULL;
1150
1151 ram_list.version++;
1152 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001153
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001154 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001155 last_ram_offset() >> TARGET_PAGE_BITS);
1156 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001157 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001158 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001159
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001160 //qemu_ram_setup_dump(new_block->host, size);
1161 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1162 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
1163
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001164 if (kvm_enabled())
1165 kvm_setup_guest_memory(new_block->host, size);
1166
1167 return new_block->offset;
1168}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001169
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001170ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1171{
1172 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1173}
1174
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001175void qemu_ram_free_from_ptr(ram_addr_t addr)
1176{
1177 RAMBlock *block;
1178
1179 /* This assumes the iothread lock is taken here too. */
1180 qemu_mutex_lock_ramlist();
1181 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1182 if (addr == block->offset) {
1183 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1184 ram_list.mru_block = NULL;
1185 ram_list.version++;
1186 g_free(block);
1187 break;
1188 }
1189 }
1190 qemu_mutex_unlock_ramlist();
1191}
1192
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001193void qemu_ram_free(ram_addr_t addr)
1194{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001195 RAMBlock *block;
1196
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001197 /* This assumes the iothread lock is taken here too. */
1198 qemu_mutex_lock_ramlist();
1199 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001200 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001201 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1202 ram_list.mru_block = NULL;
1203 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001204 if (block->flags & RAM_PREALLOC_MASK) {
1205 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001206 } else if (xen_enabled()) {
1207 //xen_invalidate_map_cache_entry(block->host);
1208#ifndef _WIN32
1209 } else if (block->fd >= 0) {
1210 munmap(block->host, block->length);
1211 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001212#endif
1213 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001214 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001215 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001216 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001217 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001218 }
1219 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001220 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001221
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001222}
1223
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001224#ifndef _WIN32
1225void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1226{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001227 RAMBlock *block;
1228 ram_addr_t offset;
1229 int flags;
1230 void *area, *vaddr;
1231
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001232 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001233 offset = addr - block->offset;
1234 if (offset < block->length) {
1235 vaddr = block->host + offset;
1236 if (block->flags & RAM_PREALLOC_MASK) {
1237 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001238 } else if (xen_enabled()) {
1239 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001240 } else {
1241 flags = MAP_FIXED;
1242 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001243 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001244#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001245 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1246 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001247#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001248 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001249#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001250 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1251 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001252 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001253 /*
1254 * Remap needs to match alloc. Accelerators that
1255 * set phys_mem_alloc never remap. If they did,
1256 * we'd need a remap hook here.
1257 */
1258 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1259
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001260 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1261 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1262 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001263 }
1264 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001265 fprintf(stderr, "Could not remap addr: "
1266 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001267 length, addr);
1268 exit(1);
1269 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001270 memory_try_enable_merging(vaddr, length);
1271 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001272 }
1273 return;
1274 }
1275 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001276}
1277#endif /* !_WIN32 */
1278
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001279/* Return a host pointer to ram allocated with qemu_ram_alloc.
1280 With the exception of the softmmu code in this file, this should
1281 only be used for local memory (e.g. video ram) that the device owns,
1282 and knows it isn't going to access beyond the end of the block.
1283
1284 It should not be used for general purpose DMA.
1285 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1286 */
1287void *qemu_get_ram_ptr(ram_addr_t addr)
1288{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001289 RAMBlock *block = qemu_get_ram_block(addr);
1290#if 0
1291 if (xen_enabled()) {
1292 /* We need to check if the requested address is in the RAM
1293 * because we don't want to map the entire memory in QEMU.
1294 * In that case just map until the end of the page.
1295 */
1296 if (block->offset == 0) {
1297 return xen_map_cache(addr, 0, 0);
1298 } else if (block->host == NULL) {
1299 block->host =
1300 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001301 }
1302 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001303#endif
1304 return block->host + (addr - block->offset);
1305}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001306
1307/* Return a host pointer to ram allocated with qemu_ram_alloc.
1308 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1309 */
1310void *qemu_safe_ram_ptr(ram_addr_t addr)
1311{
1312 RAMBlock *block;
1313
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001314 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001315 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001316 return block->host + (addr - block->offset);
1317 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001318 }
1319
1320 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1321 abort();
1322
1323 return NULL;
1324}
1325
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001326/* Some of the softmmu routines need to translate from a host pointer
1327 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001328int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1329{
1330 RAMBlock *block;
1331 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001332#if 0
1333 if (xen_enabled()) {
1334 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1335 return qemu_get_ram_block(*ram_addr)->mr;
1336 }
1337#endif
1338 block = ram_list.mru_block;
1339 if (block && block->host && host - block->host < block->length) {
1340 goto found;
1341 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001342
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001343 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1344 /* This case append when the block is not mapped. */
1345 if (block->host == NULL) {
1346 continue;
1347 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001348 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001349 goto found;
1350 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001351 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001352
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001353 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001354
1355found:
1356 *ram_addr = block->offset + (host - block->host);
1357 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001358}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001359
1360/* Some of the softmmu routines need to translate from a host pointer
1361 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001362ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001363{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001364 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001365
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001366 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001367 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1368 abort();
1369 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001370 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001371}
1372
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001373static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001374{
1375#ifdef DEBUG_UNASSIGNED
1376 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1377#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001378#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001379 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001380#endif
1381 return 0;
1382}
1383
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001384static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001385{
1386#ifdef DEBUG_UNASSIGNED
1387 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1388#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001389#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001390 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001391#endif
1392 return 0;
1393}
1394
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001395static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001396{
1397#ifdef DEBUG_UNASSIGNED
1398 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1399#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001400#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001401 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001402#endif
1403 return 0;
1404}
1405
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001406static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001407{
1408#ifdef DEBUG_UNASSIGNED
1409 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1410#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001411#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001412 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001413#endif
1414}
1415
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001416static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001417{
1418#ifdef DEBUG_UNASSIGNED
1419 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1420#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001421#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001422 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001423#endif
1424}
1425
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001426static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001427{
1428#ifdef DEBUG_UNASSIGNED
1429 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1430#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001431#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001432 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001433#endif
1434}
1435
David 'Digit' Turner36411062010-12-22 17:34:53 +01001436static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001437 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001438 unassigned_mem_readw,
1439 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001440};
1441
David 'Digit' Turner36411062010-12-22 17:34:53 +01001442static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001443 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001444 unassigned_mem_writew,
1445 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001446};
1447
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001448static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001449 uint32_t val)
1450{
1451 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001452 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001453 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1454#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001455 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001456 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001457#endif
1458 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001459 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001460 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001461 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001462 /* we remove the notdirty callback only if the code has been
1463 flushed */
1464 if (dirty_flags == 0xff)
1465 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1466}
1467
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001468static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001469 uint32_t val)
1470{
1471 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001472 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001473 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1474#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001475 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001476 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001477#endif
1478 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001479 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001480 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001481 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001482 /* we remove the notdirty callback only if the code has been
1483 flushed */
1484 if (dirty_flags == 0xff)
1485 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1486}
1487
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001488static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001489 uint32_t val)
1490{
1491 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001492 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001493 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1494#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001495 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001496 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001497#endif
1498 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001499 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001500 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001501 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001502 /* we remove the notdirty callback only if the code has been
1503 flushed */
1504 if (dirty_flags == 0xff)
1505 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1506}
1507
David 'Digit' Turner36411062010-12-22 17:34:53 +01001508static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001509 NULL, /* never used */
1510 NULL, /* never used */
1511 NULL, /* never used */
1512};
1513
David 'Digit' Turner36411062010-12-22 17:34:53 +01001514static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001515 notdirty_mem_writeb,
1516 notdirty_mem_writew,
1517 notdirty_mem_writel,
1518};
1519
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001520static void tb_check_watchpoint(CPUArchState* env)
1521{
1522 TranslationBlock *tb = tb_find_pc(env->mem_io_pc);
1523 if (!tb) {
1524 cpu_abort(env, "check_watchpoint: could not find TB for "
1525 "pc=%p", (void *)env->mem_io_pc);
1526 }
1527 cpu_restore_state(env, env->mem_io_pc);
1528 tb_phys_invalidate(tb, -1);
1529}
1530
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001531/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001532static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001533{
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001534 CPUArchState *env = cpu_single_env;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001535 target_ulong pc, cs_base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001536 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001537 CPUWatchpoint *wp;
1538 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001539
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001540 if (env->watchpoint_hit) {
1541 /* We re-entered the check after replacing the TB. Now raise
1542 * the debug interrupt so that is will trigger after the
1543 * current instruction. */
1544 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
1545 return;
1546 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001547 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001548 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001549 if ((vaddr == (wp->vaddr & len_mask) ||
1550 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1551 wp->flags |= BP_WATCHPOINT_HIT;
1552 if (!env->watchpoint_hit) {
1553 env->watchpoint_hit = wp;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001554 tb_check_watchpoint(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001555 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1556 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001557 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001558 } else {
1559 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1560 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001561 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001562 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001563 }
1564 } else {
1565 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001566 }
1567 }
1568}
1569
1570/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1571 so these check for a hit then pass through to the normal out-of-line
1572 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001573static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001574{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001575 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001576 return ldub_phys(addr);
1577}
1578
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001579static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001580{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001581 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001582 return lduw_phys(addr);
1583}
1584
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001585static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001586{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001587 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001588 return ldl_phys(addr);
1589}
1590
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001591static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001592 uint32_t val)
1593{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001594 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001595 stb_phys(addr, val);
1596}
1597
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001598static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001599 uint32_t val)
1600{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001601 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001602 stw_phys(addr, val);
1603}
1604
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001605static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001606 uint32_t val)
1607{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001608 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001609 stl_phys(addr, val);
1610}
1611
David 'Digit' Turner36411062010-12-22 17:34:53 +01001612static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001613 watch_mem_readb,
1614 watch_mem_readw,
1615 watch_mem_readl,
1616};
1617
David 'Digit' Turner36411062010-12-22 17:34:53 +01001618static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001619 watch_mem_writeb,
1620 watch_mem_writew,
1621 watch_mem_writel,
1622};
1623
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001624static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001625 unsigned int len)
1626{
1627 uint32_t ret;
1628 unsigned int idx;
1629
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001630 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001631#if defined(DEBUG_SUBPAGE)
1632 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1633 mmio, len, addr, idx);
1634#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001635 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1636 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001637
1638 return ret;
1639}
1640
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001641static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001642 uint32_t value, unsigned int len)
1643{
1644 unsigned int idx;
1645
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001646 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001647#if defined(DEBUG_SUBPAGE)
1648 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1649 mmio, len, addr, idx, value);
1650#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001651 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1652 addr + mmio->region_offset[idx][1][len],
1653 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001654}
1655
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001656static uint32_t subpage_readb (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001657{
1658#if defined(DEBUG_SUBPAGE)
1659 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1660#endif
1661
1662 return subpage_readlen(opaque, addr, 0);
1663}
1664
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001665static void subpage_writeb (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001666 uint32_t value)
1667{
1668#if defined(DEBUG_SUBPAGE)
1669 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1670#endif
1671 subpage_writelen(opaque, addr, value, 0);
1672}
1673
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001674static uint32_t subpage_readw (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001675{
1676#if defined(DEBUG_SUBPAGE)
1677 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1678#endif
1679
1680 return subpage_readlen(opaque, addr, 1);
1681}
1682
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001683static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001684 uint32_t value)
1685{
1686#if defined(DEBUG_SUBPAGE)
1687 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1688#endif
1689 subpage_writelen(opaque, addr, value, 1);
1690}
1691
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001692static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001693{
1694#if defined(DEBUG_SUBPAGE)
1695 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1696#endif
1697
1698 return subpage_readlen(opaque, addr, 2);
1699}
1700
1701static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001702 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001703{
1704#if defined(DEBUG_SUBPAGE)
1705 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1706#endif
1707 subpage_writelen(opaque, addr, value, 2);
1708}
1709
David 'Digit' Turner36411062010-12-22 17:34:53 +01001710static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001711 &subpage_readb,
1712 &subpage_readw,
1713 &subpage_readl,
1714};
1715
David 'Digit' Turner36411062010-12-22 17:34:53 +01001716static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001717 &subpage_writeb,
1718 &subpage_writew,
1719 &subpage_writel,
1720};
1721
1722static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001723 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001724{
1725 int idx, eidx;
1726 unsigned int i;
1727
1728 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1729 return -1;
1730 idx = SUBPAGE_IDX(start);
1731 eidx = SUBPAGE_IDX(end);
1732#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001733 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 -08001734 mmio, start, end, idx, eidx, memory);
1735#endif
1736 memory >>= IO_MEM_SHIFT;
1737 for (; idx <= eidx; idx++) {
1738 for (i = 0; i < 4; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001739 if (_io_mem_read[memory][i]) {
1740 mmio->mem_read[idx][i] = &_io_mem_read[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001741 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001742 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001743 }
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001744 if (_io_mem_write[memory][i]) {
1745 mmio->mem_write[idx][i] = &_io_mem_write[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001746 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001747 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001748 }
1749 }
1750 }
1751
1752 return 0;
1753}
1754
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001755static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001756 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001757{
1758 subpage_t *mmio;
1759 int subpage_memory;
1760
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001761 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001762
1763 mmio->base = base;
1764 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001765#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001766 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
1767 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001768#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001769 *phys = subpage_memory | IO_MEM_SUBPAGE;
1770 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
1771 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001772
1773 return mmio;
1774}
1775
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001776static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001777{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001778 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001779
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001780 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
1781 if (!io_mem_used[i]) {
1782 io_mem_used[i] = 1;
1783 return i;
1784 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001785 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001786 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001787}
1788
1789/* mem_read and mem_write are arrays of functions containing the
1790 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001791 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001792 If io_index is non zero, the corresponding io zone is
1793 modified. If it is zero, a new io zone is allocated. The return
1794 value can be used with cpu_register_physical_memory(). (-1) is
1795 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001796static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01001797 CPUReadMemoryFunc * const *mem_read,
1798 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001799 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001800{
1801 int i, subwidth = 0;
1802
1803 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001804 io_index = get_free_io_mem_idx();
1805 if (io_index == -1)
1806 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001807 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001808 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001809 if (io_index >= IO_MEM_NB_ENTRIES)
1810 return -1;
1811 }
1812
1813 for(i = 0;i < 3; i++) {
1814 if (!mem_read[i] || !mem_write[i])
1815 subwidth = IO_MEM_SUBWIDTH;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001816 _io_mem_read[io_index][i] = mem_read[i];
1817 _io_mem_write[io_index][i] = mem_write[i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001818 }
1819 io_mem_opaque[io_index] = opaque;
1820 return (io_index << IO_MEM_SHIFT) | subwidth;
1821}
1822
David 'Digit' Turner36411062010-12-22 17:34:53 +01001823int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
1824 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001825 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001826{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001827 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001828}
1829
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001830void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001831{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001832 int i;
1833 int io_index = io_table_address >> IO_MEM_SHIFT;
1834
1835 for (i=0;i < 3; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001836 _io_mem_read[io_index][i] = unassigned_mem_read[i];
1837 _io_mem_write[io_index][i] = unassigned_mem_write[i];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001838 }
1839 io_mem_opaque[io_index] = NULL;
1840 io_mem_used[io_index] = 0;
1841}
1842
1843static void io_mem_init(void)
1844{
1845 int i;
1846
1847 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
1848 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
1849 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
1850 for (i=0; i<5; i++)
1851 io_mem_used[i] = 1;
1852
1853 io_mem_watch = cpu_register_io_memory(watch_mem_read,
1854 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001855}
1856
1857#endif /* !defined(CONFIG_USER_ONLY) */
1858
1859/* physical memory access (slow version, mainly for debug) */
1860#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001861void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001862 int len, int is_write)
1863{
1864 int l, flags;
1865 target_ulong page;
1866 void * p;
1867
1868 while (len > 0) {
1869 page = addr & TARGET_PAGE_MASK;
1870 l = (page + TARGET_PAGE_SIZE) - addr;
1871 if (l > len)
1872 l = len;
1873 flags = page_get_flags(page);
1874 if (!(flags & PAGE_VALID))
1875 return;
1876 if (is_write) {
1877 if (!(flags & PAGE_WRITE))
1878 return;
1879 /* XXX: this code should not depend on lock_user */
1880 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
1881 /* FIXME - should this return an error rather than just fail? */
1882 return;
1883 memcpy(p, buf, l);
1884 unlock_user(p, addr, l);
1885 } else {
1886 if (!(flags & PAGE_READ))
1887 return;
1888 /* XXX: this code should not depend on lock_user */
1889 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
1890 /* FIXME - should this return an error rather than just fail? */
1891 return;
1892 memcpy(buf, p, l);
1893 unlock_user(p, addr, 0);
1894 }
1895 len -= l;
1896 buf += l;
1897 addr += l;
1898 }
1899}
1900
1901#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07001902
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001903static void invalidate_and_set_dirty(hwaddr addr,
1904 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07001905{
1906 if (!cpu_physical_memory_is_dirty(addr)) {
1907 /* invalidate code */
1908 tb_invalidate_phys_page_range(addr, addr + length, 0);
1909 /* set dirty bit */
1910 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
1911 }
1912}
1913
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001914void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001915 int len, int is_write)
1916{
1917 int l, io_index;
1918 uint8_t *ptr;
1919 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001920 hwaddr page;
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001921 ram_addr_t pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001922 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001923 PhysPageDesc *p;
1924
1925 while (len > 0) {
1926 page = addr & TARGET_PAGE_MASK;
1927 l = (page + TARGET_PAGE_SIZE) - addr;
1928 if (l > len)
1929 l = len;
1930 p = phys_page_find(page >> TARGET_PAGE_BITS);
1931 if (!p) {
1932 pd = IO_MEM_UNASSIGNED;
1933 } else {
1934 pd = p->phys_offset;
1935 }
1936
1937 if (is_write) {
1938 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001939 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001940 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001941 if (p)
1942 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001943 /* XXX: could force cpu_single_env to NULL to avoid
1944 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001945 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001946 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001947 val = ldl_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001948 io_mem_write(io_index, addr1, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001949 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001950 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001951 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001952 val = lduw_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001953 io_mem_write(io_index, addr1, val, 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001954 l = 2;
1955 } else {
1956 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001957 val = ldub_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001958 io_mem_write(io_index, addr1, val, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001959 l = 1;
1960 }
1961 } else {
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001962 ram_addr_t addr1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001963 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
1964 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001965 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001966 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07001967 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001968 }
1969 } else {
1970 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
1971 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001972 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001973 /* I/O case */
1974 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001975 if (p)
1976 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
1977 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001978 /* 32 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001979 val = io_mem_read(io_index, addr1, 4);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001980 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001981 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001982 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001983 /* 16 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001984 val = io_mem_read(io_index, addr1, 2);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001985 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001986 l = 2;
1987 } else {
1988 /* 8 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001989 val = io_mem_read(io_index, addr1, 1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001990 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001991 l = 1;
1992 }
1993 } else {
1994 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001995 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001996 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001997 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001998 }
1999 }
2000 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002001 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002002 addr += l;
2003 }
2004}
2005
2006/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002007void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002008 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002009{
2010 int l;
2011 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002012 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002013 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002014 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002015 PhysPageDesc *p;
2016
2017 while (len > 0) {
2018 page = addr & TARGET_PAGE_MASK;
2019 l = (page + TARGET_PAGE_SIZE) - addr;
2020 if (l > len)
2021 l = len;
2022 p = phys_page_find(page >> TARGET_PAGE_BITS);
2023 if (!p) {
2024 pd = IO_MEM_UNASSIGNED;
2025 } else {
2026 pd = p->phys_offset;
2027 }
2028
2029 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2030 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2031 !(pd & IO_MEM_ROMD)) {
2032 /* do nothing */
2033 } else {
2034 unsigned long addr1;
2035 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2036 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002037 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002038 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002039 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002040 }
2041 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002042 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002043 addr += l;
2044 }
2045}
2046
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002047typedef struct {
2048 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002049 hwaddr addr;
2050 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002051} BounceBuffer;
2052
2053static BounceBuffer bounce;
2054
2055typedef struct MapClient {
2056 void *opaque;
2057 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002058 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002059} MapClient;
2060
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002061static QLIST_HEAD(map_client_list, MapClient) map_client_list
2062 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002063
2064void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2065{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002066 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002067
2068 client->opaque = opaque;
2069 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002070 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002071 return client;
2072}
2073
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002074static void cpu_unregister_map_client(void *_client)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002075{
2076 MapClient *client = (MapClient *)_client;
2077
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002078 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002079 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002080}
2081
2082static void cpu_notify_map_clients(void)
2083{
2084 MapClient *client;
2085
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002086 while (!QLIST_EMPTY(&map_client_list)) {
2087 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002088 client->callback(client->opaque);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002089 cpu_unregister_map_client(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002090 }
2091}
2092
2093/* Map a physical memory region into a host virtual address.
2094 * May map a subset of the requested range, given by and returned in *plen.
2095 * May return NULL if resources needed to perform the mapping are exhausted.
2096 * Use only for reads OR writes - not for read-modify-write operations.
2097 * Use cpu_register_map_client() to know when retrying the map operation is
2098 * likely to succeed.
2099 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002100void *cpu_physical_memory_map(hwaddr addr,
2101 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002102 int is_write)
2103{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002104 hwaddr len = *plen;
2105 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002106 int l;
2107 uint8_t *ret = NULL;
2108 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002109 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002110 unsigned long pd;
2111 PhysPageDesc *p;
2112 unsigned long addr1;
2113
2114 while (len > 0) {
2115 page = addr & TARGET_PAGE_MASK;
2116 l = (page + TARGET_PAGE_SIZE) - addr;
2117 if (l > len)
2118 l = len;
2119 p = phys_page_find(page >> TARGET_PAGE_BITS);
2120 if (!p) {
2121 pd = IO_MEM_UNASSIGNED;
2122 } else {
2123 pd = p->phys_offset;
2124 }
2125
2126 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2127 if (done || bounce.buffer) {
2128 break;
2129 }
2130 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2131 bounce.addr = addr;
2132 bounce.len = l;
2133 if (!is_write) {
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002134 cpu_physical_memory_read(addr, bounce.buffer, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002135 }
2136 ptr = bounce.buffer;
2137 } else {
2138 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2139 ptr = qemu_get_ram_ptr(addr1);
2140 }
2141 if (!done) {
2142 ret = ptr;
2143 } else if (ret + done != ptr) {
2144 break;
2145 }
2146
2147 len -= l;
2148 addr += l;
2149 done += l;
2150 }
2151 *plen = done;
2152 return ret;
2153}
2154
2155/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2156 * Will also mark the memory as dirty if is_write == 1. access_len gives
2157 * the amount of memory that was actually read or written by the caller.
2158 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002159void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2160 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002161{
2162 if (buffer != bounce.buffer) {
2163 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002164 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002165 while (access_len) {
2166 unsigned l;
2167 l = TARGET_PAGE_SIZE;
2168 if (l > access_len)
2169 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002170 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002171 addr1 += l;
2172 access_len -= l;
2173 }
2174 }
2175 return;
2176 }
2177 if (is_write) {
2178 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2179 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002180 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002181 bounce.buffer = NULL;
2182 cpu_notify_map_clients();
2183}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002184
2185/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002186static inline uint32_t ldl_phys_internal(hwaddr addr,
2187 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002188{
2189 int io_index;
2190 uint8_t *ptr;
2191 uint32_t val;
2192 unsigned long pd;
2193 PhysPageDesc *p;
2194
2195 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2196 if (!p) {
2197 pd = IO_MEM_UNASSIGNED;
2198 } else {
2199 pd = p->phys_offset;
2200 }
2201
2202 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2203 !(pd & IO_MEM_ROMD)) {
2204 /* I/O case */
2205 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002206 if (p)
2207 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002208 val = io_mem_read(io_index, addr, 4);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002209#if defined(TARGET_WORDS_BIGENDIAN)
2210 if (endian == DEVICE_LITTLE_ENDIAN) {
2211 val = bswap32(val);
2212 }
2213#else
2214 if (endian == DEVICE_BIG_ENDIAN) {
2215 val = bswap32(val);
2216 }
2217#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002218 } else {
2219 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002220 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002221 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002222 switch (endian) {
2223 case DEVICE_LITTLE_ENDIAN:
2224 val = ldl_le_p(ptr);
2225 break;
2226 case DEVICE_BIG_ENDIAN:
2227 val = ldl_be_p(ptr);
2228 break;
2229 default:
2230 val = ldl_p(ptr);
2231 break;
2232 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002233 }
2234 return val;
2235}
2236
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002237uint32_t ldl_phys(hwaddr addr)
2238{
2239 return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2240}
2241
2242uint32_t ldl_le_phys(hwaddr addr)
2243{
2244 return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2245}
2246
2247uint32_t ldl_be_phys(hwaddr addr)
2248{
2249 return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
2250}
2251
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002252/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002253static inline uint64_t ldq_phys_internal(hwaddr addr,
2254 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002255{
2256 int io_index;
2257 uint8_t *ptr;
2258 uint64_t val;
2259 unsigned long pd;
2260 PhysPageDesc *p;
2261
2262 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2263 if (!p) {
2264 pd = IO_MEM_UNASSIGNED;
2265 } else {
2266 pd = p->phys_offset;
2267 }
2268
2269 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2270 !(pd & IO_MEM_ROMD)) {
2271 /* I/O case */
2272 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002273 if (p)
2274 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002275
2276 /* XXX This is broken when device endian != cpu endian.
2277 Fix and add "endian" variable check */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002278#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002279 val = (uint64_t)io_mem_read(io_index, addr, 4) << 32;
2280 val |= io_mem_read(io_index, addr + 4, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002281#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002282 val = io_mem_read(io_index, addr, 4);
2283 val |= (uint64_t)io_mem_read(io_index, addr + 4, 4) << 32;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002284#endif
2285 } else {
2286 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002287 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002288 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002289 switch (endian) {
2290 case DEVICE_LITTLE_ENDIAN:
2291 val = ldq_le_p(ptr);
2292 break;
2293 case DEVICE_BIG_ENDIAN:
2294 val = ldq_be_p(ptr);
2295 break;
2296 default:
2297 val = ldq_p(ptr);
2298 break;
2299 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002300 }
2301 return val;
2302}
2303
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002304uint64_t ldq_phys(hwaddr addr)
2305{
2306 return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2307}
2308
2309uint64_t ldq_le_phys(hwaddr addr)
2310{
2311 return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2312}
2313
2314uint64_t ldq_be_phys(hwaddr addr)
2315{
2316 return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
2317}
2318
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002319/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002320uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002321{
2322 uint8_t val;
2323 cpu_physical_memory_read(addr, &val, 1);
2324 return val;
2325}
2326
2327/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002328static inline uint32_t lduw_phys_internal(hwaddr addr,
2329 enum device_endian endian)
2330{
2331 int io_index;
2332 uint8_t *ptr;
2333 uint64_t val;
2334 unsigned long pd;
2335 PhysPageDesc *p;
2336
2337 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2338 if (!p) {
2339 pd = IO_MEM_UNASSIGNED;
2340 } else {
2341 pd = p->phys_offset;
2342 }
2343
2344 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2345 !(pd & IO_MEM_ROMD)) {
2346 /* I/O case */
2347 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2348 if (p)
2349 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002350 val = io_mem_read(io_index, addr, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002351#if defined(TARGET_WORDS_BIGENDIAN)
2352 if (endian == DEVICE_LITTLE_ENDIAN) {
2353 val = bswap16(val);
2354 }
2355#else
2356 if (endian == DEVICE_BIG_ENDIAN) {
2357 val = bswap16(val);
2358 }
2359#endif
2360 } else {
2361 /* RAM case */
2362 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
2363 (addr & ~TARGET_PAGE_MASK);
2364 switch (endian) {
2365 case DEVICE_LITTLE_ENDIAN:
2366 val = lduw_le_p(ptr);
2367 break;
2368 case DEVICE_BIG_ENDIAN:
2369 val = lduw_be_p(ptr);
2370 break;
2371 default:
2372 val = lduw_p(ptr);
2373 break;
2374 }
2375 }
2376 return val;
2377}
2378
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002379uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002380{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002381 return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2382}
2383
2384uint32_t lduw_le_phys(hwaddr addr)
2385{
2386 return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2387}
2388
2389uint32_t lduw_be_phys(hwaddr addr)
2390{
2391 return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002392}
2393
2394/* warning: addr must be aligned. The ram page is not masked as dirty
2395 and the code inside is not invalidated. It is useful if the dirty
2396 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002397void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002398{
2399 int io_index;
2400 uint8_t *ptr;
2401 unsigned long pd;
2402 PhysPageDesc *p;
2403
2404 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2405 if (!p) {
2406 pd = IO_MEM_UNASSIGNED;
2407 } else {
2408 pd = p->phys_offset;
2409 }
2410
2411 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2412 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002413 if (p)
2414 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002415 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002416 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002417 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2418 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002419 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002420
2421 if (unlikely(in_migration)) {
2422 if (!cpu_physical_memory_is_dirty(addr1)) {
2423 /* invalidate code */
2424 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2425 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002426 cpu_physical_memory_set_dirty_flags(
2427 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002428 }
2429 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002430 }
2431}
2432
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002433void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002434{
2435 int io_index;
2436 uint8_t *ptr;
2437 unsigned long pd;
2438 PhysPageDesc *p;
2439
2440 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2441 if (!p) {
2442 pd = IO_MEM_UNASSIGNED;
2443 } else {
2444 pd = p->phys_offset;
2445 }
2446
2447 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2448 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002449 if (p)
2450 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002451#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002452 io_mem_write(io_index, addr, val >> 32, 4);
2453 io_mem_write(io_index, addr + 4, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002454#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002455 io_mem_write(io_index, addr, val, 4);
2456 io_mem_write(io_index, addr + 4, val >> 32, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002457#endif
2458 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002459 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002460 (addr & ~TARGET_PAGE_MASK);
2461 stq_p(ptr, val);
2462 }
2463}
2464
2465/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002466static inline void stl_phys_internal(hwaddr addr, uint32_t val,
2467 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002468{
2469 int io_index;
2470 uint8_t *ptr;
2471 unsigned long pd;
2472 PhysPageDesc *p;
2473
2474 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2475 if (!p) {
2476 pd = IO_MEM_UNASSIGNED;
2477 } else {
2478 pd = p->phys_offset;
2479 }
2480
2481 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2482 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002483 if (p)
2484 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002485#if defined(TARGET_WORDS_BIGENDIAN)
2486 if (endian == DEVICE_LITTLE_ENDIAN) {
2487 val = bswap32(val);
2488 }
2489#else
2490 if (endian == DEVICE_BIG_ENDIAN) {
2491 val = bswap32(val);
2492 }
2493#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002494 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002495 } else {
2496 unsigned long addr1;
2497 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2498 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002499 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002500 switch (endian) {
2501 case DEVICE_LITTLE_ENDIAN:
2502 stl_le_p(ptr, val);
2503 break;
2504 case DEVICE_BIG_ENDIAN:
2505 stl_be_p(ptr, val);
2506 break;
2507 default:
2508 stl_p(ptr, val);
2509 break;
2510 }
Pete Delaneyd09d7662013-03-28 19:53:13 -07002511 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002512 }
2513}
2514
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002515void stl_phys(hwaddr addr, uint32_t val)
2516{
2517 stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2518}
2519
2520void stl_le_phys(hwaddr addr, uint32_t val)
2521{
2522 stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2523}
2524
2525void stl_be_phys(hwaddr addr, uint32_t val)
2526{
2527 stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
2528}
2529
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002530/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002531void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002532{
2533 uint8_t v = val;
2534 cpu_physical_memory_write(addr, &v, 1);
2535}
2536
2537/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002538static inline void stw_phys_internal(hwaddr addr, uint32_t val,
2539 enum device_endian endian)
2540{
2541 int io_index;
2542 uint8_t *ptr;
2543 unsigned long pd;
2544 PhysPageDesc *p;
2545
2546 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2547 if (!p) {
2548 pd = IO_MEM_UNASSIGNED;
2549 } else {
2550 pd = p->phys_offset;
2551 }
2552
2553 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2554 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2555 if (p)
2556 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2557#if defined(TARGET_WORDS_BIGENDIAN)
2558 if (endian == DEVICE_LITTLE_ENDIAN) {
2559 val = bswap16(val);
2560 }
2561#else
2562 if (endian == DEVICE_BIG_ENDIAN) {
2563 val = bswap16(val);
2564 }
2565#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002566 io_mem_write(io_index, addr, val, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002567 } else {
2568 unsigned long addr1;
2569 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2570 /* RAM case */
2571 ptr = qemu_get_ram_ptr(addr1);
2572 switch (endian) {
2573 case DEVICE_LITTLE_ENDIAN:
2574 stw_le_p(ptr, val);
2575 break;
2576 case DEVICE_BIG_ENDIAN:
2577 stw_be_p(ptr, val);
2578 break;
2579 default:
2580 stw_p(ptr, val);
2581 break;
2582 }
2583 if (!cpu_physical_memory_is_dirty(addr1)) {
2584 /* invalidate code */
2585 tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
2586 /* set dirty bit */
2587 cpu_physical_memory_set_dirty_flags(addr1,
2588 (0xff & ~CODE_DIRTY_FLAG));
2589 }
2590 }
2591}
2592
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002593void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002594{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002595 stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2596}
2597
2598void stw_le_phys(hwaddr addr, uint32_t val)
2599{
2600 stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2601}
2602
2603void stw_be_phys(hwaddr addr, uint32_t val)
2604{
2605 stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002606}
2607
2608/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002609void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002610{
2611 val = tswap64(val);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002612 cpu_physical_memory_write(addr, &val, 8);
2613}
2614
2615
2616void stq_le_phys(hwaddr addr, uint64_t val)
2617{
2618 val = cpu_to_le64(val);
2619 cpu_physical_memory_write(addr, &val, 8);
2620}
2621
2622void stq_be_phys(hwaddr addr, uint64_t val)
2623{
2624 val = cpu_to_be64(val);
2625 cpu_physical_memory_write(addr, &val, 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002626}
2627
2628#endif
2629
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002630/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002631int cpu_memory_rw_debug(CPUOldState *env, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002632 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002633{
2634 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002635 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002636 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002637 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002638
2639 while (len > 0) {
2640 page = addr & TARGET_PAGE_MASK;
2641 phys_addr = cpu_get_phys_page_debug(env, page);
2642 /* if no physical page mapped, return an error */
2643 if (phys_addr == -1)
2644 return -1;
2645 l = (page + TARGET_PAGE_SIZE) - addr;
2646 if (l > len)
2647 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002648 phys_addr += (addr & ~TARGET_PAGE_MASK);
2649#if !defined(CONFIG_USER_ONLY)
2650 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002651 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002652 else
2653#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002654 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002655 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002656 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002657 addr += l;
2658 }
2659 return 0;
2660}