blob: 6f293899de8fa94fc524e35db18362dbcfd21ad0 [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;
David 'Digit' Turner66576782014-03-24 16:57:57 +0100128 CPUState *cpu = ENV_GET_CPU(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800129
David 'Digit' Turnere36a6832014-03-25 18:02:39 +0100130 cpu_synchronize_state(cpu, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700131
David 'Digit' Turner66576782014-03-24 16:57:57 +0100132 qemu_put_be32s(f, &cpu->halted);
133 qemu_put_be32s(f, &cpu->interrupt_request);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800134}
135
136static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
137{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100138 CPUOldState *env = opaque;
David 'Digit' Turner66576782014-03-24 16:57:57 +0100139 CPUState *cpu = ENV_GET_CPU(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800140
141 if (version_id != CPU_COMMON_SAVE_VERSION)
142 return -EINVAL;
143
David 'Digit' Turner66576782014-03-24 16:57:57 +0100144 qemu_get_be32s(f, &cpu->halted);
145 qemu_get_be32s(f, &cpu->interrupt_request);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700146 /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
147 version_id is increased. */
David 'Digit' Turner66576782014-03-24 16:57:57 +0100148 cpu->interrupt_request &= ~0x01;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800149 tlb_flush(env, 1);
David 'Digit' Turnere36a6832014-03-25 18:02:39 +0100150 cpu_synchronize_state(cpu, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800151
152 return 0;
153}
154#endif
155
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100156CPUState *qemu_get_cpu(int cpu_index)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700157{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100158 CPUState *cpu;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700159
David 'Digit' Turner66576782014-03-24 16:57:57 +0100160 CPU_FOREACH(cpu) {
161 if (cpu->cpu_index == cpu_index)
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100162 return cpu;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700163 }
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100164 return NULL;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700165}
166
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100167void cpu_exec_init(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800168{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100169 CPUState *cpu = ENV_GET_CPU(env);
170
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700171#if defined(CONFIG_USER_ONLY)
172 cpu_list_lock();
173#endif
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100174 // Compute CPU index from list position.
175 int cpu_index = 0;
David 'Digit' Turner66576782014-03-24 16:57:57 +0100176 CPUState *cpu1;
177 CPU_FOREACH(cpu1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800178 cpu_index++;
179 }
David 'Digit' Turner66576782014-03-24 16:57:57 +0100180 cpu->cpu_index = cpu_index;
181 QTAILQ_INSERT_TAIL(&cpus, cpu, node);
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100182
David 'Digit' Turner66576782014-03-24 16:57:57 +0100183 cpu->numa_node = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700184 QTAILQ_INIT(&env->breakpoints);
185 QTAILQ_INIT(&env->watchpoints);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700186#if defined(CONFIG_USER_ONLY)
187 cpu_list_unlock();
188#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800189#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +0100190 register_savevm(NULL,
191 "cpu_common",
192 cpu_index,
193 CPU_COMMON_SAVE_VERSION,
194 cpu_common_save,
195 cpu_common_load,
196 env);
197 register_savevm(NULL,
198 "cpu",
199 cpu_index,
200 CPU_SAVE_VERSION,
201 cpu_save,
202 cpu_load,
203 env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800204#endif
205}
206
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800207#if defined(TARGET_HAS_ICE)
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100208static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800209{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100210 hwaddr addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800211 target_ulong pd;
212 ram_addr_t ram_addr;
213 PhysPageDesc *p;
214
215 addr = cpu_get_phys_page_debug(env, pc);
216 p = phys_page_find(addr >> TARGET_PAGE_BITS);
217 if (!p) {
218 pd = IO_MEM_UNASSIGNED;
219 } else {
220 pd = p->phys_offset;
221 }
222 ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
223 tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
224}
225#endif
226
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100227#if defined(CONFIG_USER_ONLY)
228void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
229
230{
231}
232
233int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
234 int flags, CPUWatchpoint **watchpoint)
235{
236 return -ENOSYS;
237}
238#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800239/* Add a watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100240int cpu_watchpoint_insert(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700241 int flags, CPUWatchpoint **watchpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800242{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700243 target_ulong len_mask = ~(len - 1);
244 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800245
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700246 /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100247 if ((len & (len - 1)) || (addr & ~len_mask) ||
248 len == 0 || len > TARGET_PAGE_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700249 fprintf(stderr, "qemu: tried to set invalid watchpoint at "
250 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
251 return -EINVAL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800252 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100253 wp = g_malloc(sizeof(*wp));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800254
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700255 wp->vaddr = addr;
256 wp->len_mask = len_mask;
257 wp->flags = flags;
258
259 /* keep all GDB-injected watchpoints in front */
260 if (flags & BP_GDB)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700261 QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700262 else
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700263 QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700264
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800265 tlb_flush_page(env, addr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700266
267 if (watchpoint)
268 *watchpoint = wp;
269 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800270}
271
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700272/* Remove a specific watchpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100273int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr, target_ulong len,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700274 int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800275{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700276 target_ulong len_mask = ~(len - 1);
277 CPUWatchpoint *wp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800278
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700279 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700280 if (addr == wp->vaddr && len_mask == wp->len_mask
281 && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
282 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800283 return 0;
284 }
285 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700286 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800287}
288
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700289/* Remove a specific watchpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100290void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700291{
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700292 QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800293
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700294 tlb_flush_page(env, watchpoint->vaddr);
295
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100296 g_free(watchpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700297}
298
299/* Remove all matching watchpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100300void cpu_watchpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700301{
302 CPUWatchpoint *wp, *next;
303
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700304 QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700305 if (wp->flags & mask)
306 cpu_watchpoint_remove_by_ref(env, wp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800307 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800308}
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100309#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800310
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700311/* Add a breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100312int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700313 CPUBreakpoint **breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800314{
315#if defined(TARGET_HAS_ICE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700316 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800317
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100318 bp = g_malloc(sizeof(*bp));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700319
320 bp->pc = pc;
321 bp->flags = flags;
322
323 /* keep all GDB-injected breakpoints in front */
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100324 if (flags & BP_GDB) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700325 QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100326 } else {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700327 QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100328 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700329
330 breakpoint_invalidate(env, pc);
331
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100332 if (breakpoint) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700333 *breakpoint = bp;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100334 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700335 return 0;
336#else
337 return -ENOSYS;
338#endif
339}
340
341/* Remove a specific breakpoint. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100342int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700343{
344#if defined(TARGET_HAS_ICE)
345 CPUBreakpoint *bp;
346
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700347 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700348 if (bp->pc == pc && bp->flags == flags) {
349 cpu_breakpoint_remove_by_ref(env, bp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800350 return 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700351 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800352 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700353 return -ENOENT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800354#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355 return -ENOSYS;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356#endif
357}
358
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700359/* Remove a specific breakpoint by reference. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100360void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800361{
362#if defined(TARGET_HAS_ICE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700363 QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800364
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700365 breakpoint_invalidate(env, breakpoint->pc);
366
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100367 g_free(breakpoint);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700368#endif
369}
370
371/* Remove all matching breakpoints. */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100372void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700373{
374#if defined(TARGET_HAS_ICE)
375 CPUBreakpoint *bp, *next;
376
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700377 QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700378 if (bp->flags & mask)
379 cpu_breakpoint_remove_by_ref(env, bp);
380 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800381#endif
382}
383
384/* enable or disable single step mode. EXCP_DEBUG is returned by the
385 CPU loop after each instruction */
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +0100386void cpu_single_step(CPUState *cpu, int enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800387{
388#if defined(TARGET_HAS_ICE)
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +0100389 if (cpu->singlestep_enabled != enabled) {
390 cpu->singlestep_enabled = enabled;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100391 if (kvm_enabled()) {
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +0100392 kvm_update_guest_debug(cpu->env_ptr, 0);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +0100393 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700394 /* must flush all the translated code to avoid inconsistencies */
395 /* XXX: only flush what is necessary */
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +0100396 tb_flush(cpu->env_ptr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700397 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800398 }
399#endif
400}
401
402/* enable or disable low levels log */
403void cpu_set_log(int log_flags)
404{
405 loglevel = log_flags;
406 if (loglevel && !logfile) {
407 logfile = fopen(logfilename, log_append ? "a" : "w");
408 if (!logfile) {
409 perror(logfilename);
Iliyan Malchev4a2c9dd2012-04-02 08:20:56 -0700410 exit(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800411 }
412#if !defined(CONFIG_SOFTMMU)
413 /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
414 {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700415 static char logfile_buf[4096];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800416 setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
417 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700418#elif !defined(_WIN32)
419 /* Win32 doesn't support line-buffering and requires size >= 2 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800420 setvbuf(logfile, NULL, _IOLBF, 0);
421#endif
422 log_append = 1;
423 }
424 if (!loglevel && logfile) {
425 fclose(logfile);
426 logfile = NULL;
427 }
428}
429
430void cpu_set_log_filename(const char *filename)
431{
432 logfilename = strdup(filename);
433 if (logfile) {
434 fclose(logfile);
435 logfile = NULL;
436 }
437 cpu_set_log(loglevel);
438}
439
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100440void cpu_unlink_tb(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800441{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800442 /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
443 problem and hope the cpu will stop of its own accord. For userspace
444 emulation this often isn't actually as bad as it sounds. Often
445 signals are used primarily to interrupt blocking syscalls. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700446 TranslationBlock *tb;
447 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
448
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200449 spin_lock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700450 tb = env->current_tb;
451 /* if the cpu is currently executing code, we must unlink it and
452 all the potentially executing TB */
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200453 if (tb) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700454 env->current_tb = NULL;
455 tb_reset_jump_recursive(tb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700456 }
David 'Digit' Turner795bb192011-05-09 15:20:22 +0200457 spin_unlock(&interrupt_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700458}
459
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100460void cpu_reset_interrupt(CPUState *cpu, int mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800461{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100462 cpu->interrupt_request &= ~mask;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800463}
464
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100465void cpu_exit(CPUState *cpu)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700466{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100467 cpu->exit_request = 1;
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100468 cpu_unlink_tb(cpu->env_ptr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700469}
470
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100471void cpu_abort(CPUArchState *env, const char *fmt, ...)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800472{
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100473 CPUState *cpu = ENV_GET_CPU(env);
474
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800475 va_list ap;
476 va_list ap2;
477
478 va_start(ap, fmt);
479 va_copy(ap2, ap);
480 fprintf(stderr, "qemu: fatal: ");
481 vfprintf(stderr, fmt, ap);
482 fprintf(stderr, "\n");
483#ifdef TARGET_I386
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100484 cpu_dump_state(cpu, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800485#else
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100486 cpu_dump_state(cpu, stderr, fprintf, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800487#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700488 if (qemu_log_enabled()) {
489 qemu_log("qemu: fatal: ");
490 qemu_log_vprintf(fmt, ap2);
491 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800492#ifdef TARGET_I386
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100493 log_cpu_state(cpu, X86_DUMP_FPU | X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800494#else
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100495 log_cpu_state(cpu, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800496#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700497 qemu_log_flush();
498 qemu_log_close();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800499 }
500 va_end(ap2);
501 va_end(ap);
David 'Digit' Turner36411062010-12-22 17:34:53 +0100502#if defined(CONFIG_USER_ONLY)
503 {
504 struct sigaction act;
505 sigfillset(&act.sa_mask);
506 act.sa_handler = SIG_DFL;
507 sigaction(SIGABRT, &act, NULL);
508 }
509#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800510 abort();
511}
512
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800513#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100514static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
515{
516 RAMBlock *block;
517
518 /* The list is protected by the iothread lock here. */
519 block = ram_list.mru_block;
520 if (block && addr - block->offset < block->length) {
521 goto found;
522 }
523 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
524 if (addr - block->offset < block->length) {
525 goto found;
526 }
527 }
528
529 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
530 abort();
531
532found:
533 ram_list.mru_block = block;
534 return block;
535}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800536
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700537/* Note: start and end must be within the same ram block. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800538void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
539 int dirty_flags)
540{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800541 unsigned long length, start1;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200542 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800543
544 start &= TARGET_PAGE_MASK;
545 end = TARGET_PAGE_ALIGN(end);
546
547 length = end - start;
548 if (length == 0)
549 return;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200550 cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800551
552 /* we modify the TLB cache so that the dirty bit will be set again
553 when accessing the range */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200554 start1 = (unsigned long)qemu_safe_ram_ptr(start);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700555 /* Chek that we don't span multiple blocks - this breaks the
556 address comparisons below. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200557 if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700558 != (end - 1) - start) {
559 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800560 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700561
David 'Digit' Turner66576782014-03-24 16:57:57 +0100562 CPUState *cpu;
563 CPU_FOREACH(cpu) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700564 int mmu_idx;
565 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
David 'Digit' Turner66576782014-03-24 16:57:57 +0100566 for(i = 0; i < CPU_TLB_SIZE; i++) {
567 CPUArchState* env = cpu->env_ptr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700568 tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
569 start1, length);
David 'Digit' Turner66576782014-03-24 16:57:57 +0100570 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700571 }
572 }
573}
574
575int cpu_physical_memory_set_dirty_tracking(int enable)
576{
577 in_migration = enable;
578 if (kvm_enabled()) {
579 return kvm_set_migration_log(enable);
580 }
581 return 0;
582}
583
584int cpu_physical_memory_get_dirty_tracking(void)
585{
586 return in_migration;
587}
588
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100589int cpu_physical_sync_dirty_bitmap(hwaddr start_addr,
590 hwaddr end_addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700591{
592 int ret = 0;
593
594 if (kvm_enabled())
595 ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
596 return ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800597}
598
599static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
600{
601 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700602 void *p;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800603
604 if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700605 p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
606 + tlb_entry->addend);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200607 ram_addr = qemu_ram_addr_from_host_nofail(p);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608 if (!cpu_physical_memory_is_dirty(ram_addr)) {
609 tlb_entry->addr_write |= TLB_NOTDIRTY;
610 }
611 }
612}
613
614/* update the TLB according to the current state of the dirty bits */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100615void cpu_tlb_update_dirty(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800616{
617 int i;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700618 int mmu_idx;
619 for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
620 for(i = 0; i < CPU_TLB_SIZE; i++)
621 tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
622 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800623}
624
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800625
626#else
627
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100628void tlb_flush(CPUArchState *env, int flush_global)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800629{
630}
631
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100632void tlb_flush_page(CPUArchState *env, target_ulong addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800633{
634}
635
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +0100636int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100637 hwaddr paddr, int prot,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800638 int mmu_idx, int is_softmmu)
639{
640 return 0;
641}
642
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100643static inline void tlb_set_dirty(CPUOldState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800644 unsigned long addr, target_ulong vaddr)
645{
646}
647#endif /* defined(CONFIG_USER_ONLY) */
648
649#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700650
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800651static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700652 ram_addr_t memory, ram_addr_t region_offset);
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100653static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700654 ram_addr_t orig_memory, ram_addr_t region_offset);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100655
656static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
657
658/*
659 * Set a custom physical guest memory alloator.
660 * Accelerators with unusual needs may need this. Hopefully, we can
661 * get rid of it eventually.
662 */
663void phys_mem_set_alloc(void *(*alloc)(size_t))
664{
665 phys_mem_alloc = alloc;
666}
667
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800668#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
669 need_subpage) \
670 do { \
671 if (addr > start_addr) \
672 start_addr2 = 0; \
673 else { \
674 start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
675 if (start_addr2 > 0) \
676 need_subpage = 1; \
677 } \
678 \
679 if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
680 end_addr2 = TARGET_PAGE_SIZE - 1; \
681 else { \
682 end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
683 if (end_addr2 < TARGET_PAGE_SIZE - 1) \
684 need_subpage = 1; \
685 } \
686 } while (0)
687
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700688/* register physical memory.
689 For RAM, 'size' must be a multiple of the target page size.
690 If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700691 io memory page. The address used when calling the IO function is
692 the offset from the start of the region, plus region_offset. Both
693 start_addr and region_offset are rounded down to a page boundary
694 before calculating this offset. This should not be a problem unless
695 the low bits of start_addr and region_offset differ. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100696void cpu_register_physical_memory_log(hwaddr start_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700697 ram_addr_t size,
698 ram_addr_t phys_offset,
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200699 ram_addr_t region_offset,
700 bool log_dirty)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800701{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100702 hwaddr addr, end_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800703 PhysPageDesc *p;
David 'Digit' Turner66576782014-03-24 16:57:57 +0100704 CPUState *cpu;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800705 ram_addr_t orig_size = size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200706 subpage_t *subpage;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800707
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700708 if (kvm_enabled())
709 kvm_set_phys_mem(start_addr, size, phys_offset);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800710#ifdef CONFIG_HAX
711 if (hax_enabled())
712 hax_set_phys_mem(start_addr, size, phys_offset);
713#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700714
715 if (phys_offset == IO_MEM_UNASSIGNED) {
716 region_offset = start_addr;
717 }
718 region_offset &= TARGET_PAGE_MASK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800719 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100720 end_addr = start_addr + (hwaddr)size;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200721
722 addr = start_addr;
723 do {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800724 p = phys_page_find(addr >> TARGET_PAGE_BITS);
725 if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
726 ram_addr_t orig_memory = p->phys_offset;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100727 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800728 int need_subpage = 0;
729
730 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
731 need_subpage);
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200732 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800733 if (!(orig_memory & IO_MEM_SUBPAGE)) {
734 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700735 &p->phys_offset, orig_memory,
736 p->region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800737 } else {
738 subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
739 >> IO_MEM_SHIFT];
740 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700741 subpage_register(subpage, start_addr2, end_addr2, phys_offset,
742 region_offset);
743 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800744 } else {
745 p->phys_offset = phys_offset;
746 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
747 (phys_offset & IO_MEM_ROMD))
748 phys_offset += TARGET_PAGE_SIZE;
749 }
750 } else {
751 p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
752 p->phys_offset = phys_offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700753 p->region_offset = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800754 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700755 (phys_offset & IO_MEM_ROMD)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800756 phys_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700757 } else {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100758 hwaddr start_addr2, end_addr2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800759 int need_subpage = 0;
760
761 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
762 end_addr2, need_subpage);
763
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200764 if (need_subpage) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800765 subpage = subpage_init((addr & TARGET_PAGE_MASK),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700766 &p->phys_offset, IO_MEM_UNASSIGNED,
767 addr & TARGET_PAGE_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800768 subpage_register(subpage, start_addr2, end_addr2,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700769 phys_offset, region_offset);
770 p->region_offset = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800771 }
772 }
773 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700774 region_offset += TARGET_PAGE_SIZE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200775 addr += TARGET_PAGE_SIZE;
776 } while (addr != end_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800777
778 /* since each CPU stores ram addresses in its TLB cache, we must
779 reset the modified entries */
780 /* XXX: slow ! */
David 'Digit' Turner66576782014-03-24 16:57:57 +0100781 CPU_FOREACH(cpu) {
782 tlb_flush(cpu->env_ptr, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800783 }
784}
785
786/* XXX: temporary until new memory mapping API */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100787ram_addr_t cpu_get_physical_page_desc(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800788{
789 PhysPageDesc *p;
790
791 p = phys_page_find(addr >> TARGET_PAGE_BITS);
792 if (!p)
793 return IO_MEM_UNASSIGNED;
794 return p->phys_offset;
795}
796
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100797void qemu_register_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700798{
799 if (kvm_enabled())
800 kvm_coalesce_mmio_region(addr, size);
801}
802
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100803void qemu_unregister_coalesced_mmio(hwaddr addr, ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700804{
805 if (kvm_enabled())
806 kvm_uncoalesce_mmio_region(addr, size);
807}
808
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100809void qemu_mutex_lock_ramlist(void)
810{
811 qemu_mutex_lock(&ram_list.mutex);
812}
813
814void qemu_mutex_unlock_ramlist(void)
815{
816 qemu_mutex_unlock(&ram_list.mutex);
817}
818
819#if defined(__linux__) && !defined(CONFIG_ANDROID)
820
821#include <sys/vfs.h>
822
823#define HUGETLBFS_MAGIC 0x958458f6
824
825static long gethugepagesize(const char *path)
826{
827 struct statfs fs;
828 int ret;
829
830 do {
831 ret = statfs(path, &fs);
832 } while (ret != 0 && errno == EINTR);
833
834 if (ret != 0) {
835 perror(path);
836 return 0;
837 }
838
839 if (fs.f_type != HUGETLBFS_MAGIC)
840 fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
841
842 return fs.f_bsize;
843}
844
845static sigjmp_buf sigjump;
846
847static void sigbus_handler(int signal)
848{
849 siglongjmp(sigjump, 1);
850}
851
852static void *file_ram_alloc(RAMBlock *block,
853 ram_addr_t memory,
854 const char *path)
855{
856 char *filename;
857 char *sanitized_name;
858 char *c;
859 void *area;
860 int fd;
861 unsigned long hpagesize;
862
863 hpagesize = gethugepagesize(path);
864 if (!hpagesize) {
865 return NULL;
866 }
867
868 if (memory < hpagesize) {
869 return NULL;
870 }
871
872 if (kvm_enabled() && !kvm_has_sync_mmu()) {
873 fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
874 return NULL;
875 }
876
877 /* Make name safe to use with mkstemp by replacing '/' with '_'. */
878 sanitized_name = g_strdup(block->mr->name);
879 for (c = sanitized_name; *c != '\0'; c++) {
880 if (*c == '/')
881 *c = '_';
882 }
883
884 filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
885 sanitized_name);
886 g_free(sanitized_name);
887
888 fd = mkstemp(filename);
889 if (fd < 0) {
890 perror("unable to create backing store for hugepages");
891 g_free(filename);
892 return NULL;
893 }
894 unlink(filename);
895 g_free(filename);
896
897 memory = (memory+hpagesize-1) & ~(hpagesize-1);
898
899 /*
900 * ftruncate is not supported by hugetlbfs in older
901 * hosts, so don't bother bailing out on errors.
902 * If anything goes wrong with it under other filesystems,
903 * mmap will fail.
904 */
905 if (ftruncate(fd, memory))
906 perror("ftruncate");
907
908 area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
909 if (area == MAP_FAILED) {
910 perror("file_ram_alloc: can't mmap RAM pages");
911 close(fd);
912 return (NULL);
913 }
914
915 if (mem_prealloc) {
916 int ret, i;
917 struct sigaction act, oldact;
918 sigset_t set, oldset;
919
920 memset(&act, 0, sizeof(act));
921 act.sa_handler = &sigbus_handler;
922 act.sa_flags = 0;
923
924 ret = sigaction(SIGBUS, &act, &oldact);
925 if (ret) {
926 perror("file_ram_alloc: failed to install signal handler");
927 exit(1);
928 }
929
930 /* unblock SIGBUS */
931 sigemptyset(&set);
932 sigaddset(&set, SIGBUS);
933 pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
934
935 if (sigsetjmp(sigjump, 1)) {
936 fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
937 exit(1);
938 }
939
940 /* MAP_POPULATE silently ignores failures */
941 for (i = 0; i < (memory/hpagesize)-1; i++) {
942 memset(area + (hpagesize*i), 0, 1);
943 }
944
945 ret = sigaction(SIGBUS, &oldact, NULL);
946 if (ret) {
947 perror("file_ram_alloc: failed to reinstall signal handler");
948 exit(1);
949 }
950
951 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
952 }
953
954 block->fd = fd;
955 return area;
956}
957#else
958static void *file_ram_alloc(RAMBlock *block,
959 ram_addr_t memory,
960 const char *path)
961{
962 fprintf(stderr, "-mem-path not supported on this host\n");
963 exit(1);
964}
965#endif
966
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200967static ram_addr_t find_ram_offset(ram_addr_t size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700968{
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200969 RAMBlock *block, *next_block;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100970 ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200971
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100972 assert(size != 0); /* it would hand out same offset multiple times */
973
974 if (QTAILQ_EMPTY(&ram_list.blocks))
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200975 return 0;
976
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100977 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
978 ram_addr_t end, next = RAM_ADDR_MAX;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200979
980 end = block->offset + block->length;
981
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100982 QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200983 if (next_block->offset >= end) {
984 next = MIN(next, next_block->offset);
985 }
986 }
987 if (next - end >= size && next - end < mingap) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100988 offset = end;
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200989 mingap = next - end;
990 }
991 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +0100992
993 if (offset == RAM_ADDR_MAX) {
994 fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
995 (uint64_t)size);
996 abort();
997 }
998
David 'Digit' Turner280afa02011-05-11 17:37:44 +0200999 return offset;
1000}
1001
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001002ram_addr_t last_ram_offset(void)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001003{
1004 RAMBlock *block;
1005 ram_addr_t last = 0;
1006
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001007 QTAILQ_FOREACH(block, &ram_list.blocks, next)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001008 last = MAX(last, block->offset + block->length);
1009
1010 return last;
1011}
1012
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001013static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
1014{
1015#ifndef CONFIG_ANDROID
1016 int ret;
1017
1018 /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
1019 if (!qemu_opt_get_bool(qemu_get_machine_opts(),
1020 "dump-guest-core", true)) {
1021 ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
1022 if (ret) {
1023 perror("qemu_madvise");
1024 fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
1025 "but dump_guest_core=off specified\n");
1026 }
1027 }
1028#endif // !CONFIG_ANDROID
1029}
1030
1031void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001032{
1033 RAMBlock *new_block, *block;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001034
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001035 new_block = NULL;
1036 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1037 if (block->offset == addr) {
1038 new_block = block;
1039 break;
1040 }
1041 }
1042 assert(new_block);
1043 assert(!new_block->idstr[0]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001044
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001045 if (dev) {
1046 char *id = qdev_get_dev_path(dev);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001047 if (id) {
1048 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001049 g_free(id);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001050 }
1051 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001052 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1053
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001054 /* This assumes the iothread lock is taken here too. */
1055 qemu_mutex_lock_ramlist();
1056 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1057 if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001058 fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
1059 new_block->idstr);
1060 abort();
1061 }
1062 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001063 qemu_mutex_unlock_ramlist();
1064}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001065
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001066static int memory_try_enable_merging(void *addr, size_t len)
1067{
1068#ifndef CONFIG_ANDROID
1069 if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) {
1070 /* disabled by the user */
1071 return 0;
1072 }
1073
1074 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1075#else // CONFIG_ANDROID
1076 return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
1077#endif // CONFIG_ANDROID
1078}
1079
1080ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
1081 ram_addr_t size, void *host)
1082{
1083 RAMBlock *block, *new_block;
1084
1085 size = TARGET_PAGE_ALIGN(size);
1086 new_block = g_malloc0(sizeof(*new_block));
1087 new_block->fd = -1;
1088
1089 /* This assumes the iothread lock is taken here too. */
1090 qemu_mutex_lock_ramlist();
1091 //new_block->mr = mr;
1092 new_block->offset = find_ram_offset(size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001093 if (host) {
1094 new_block->host = host;
1095 new_block->flags |= RAM_PREALLOC_MASK;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001096 } else if (xen_enabled()) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001097 if (mem_path) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001098 fprintf(stderr, "-mem-path not supported with Xen\n");
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001099 exit(1);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001100 }
1101 //xen_ram_alloc(new_block->offset, size, mr);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001102 } else {
1103 if (mem_path) {
1104 if (phys_mem_alloc != qemu_anon_ram_alloc) {
1105 /*
1106 * file_ram_alloc() needs to allocate just like
1107 * phys_mem_alloc, but we haven't bothered to provide
1108 * a hook there.
1109 */
1110 fprintf(stderr,
1111 "-mem-path not supported with this accelerator\n");
1112 exit(1);
1113 }
1114 new_block->host = file_ram_alloc(new_block, size, mem_path);
1115 }
1116 if (!new_block->host) {
1117 new_block->host = phys_mem_alloc(size);
1118 if (!new_block->host) {
1119 fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
1120 name, strerror(errno));
1121 exit(1);
1122 }
David 'Digit' Turnerf2de2ae2014-03-07 16:25:58 +01001123#ifdef CONFIG_HAX
1124 if (hax_enabled()) {
1125 /*
1126 * In HAX, qemu allocates the virtual address, and HAX kernel
1127 * module populates the region with physical memory. Currently
1128 * we don’t populate guest memory on demand, thus we should
1129 * make sure that sufficient amount of memory is available in
1130 * advance.
1131 */
1132 int ret = hax_populate_ram(
1133 (uint64_t)(uintptr_t)new_block->host,
1134 (uint32_t)size);
1135 if (ret < 0) {
1136 fprintf(stderr, "Hax failed to populate ram\n");
1137 exit(-1);
1138 }
1139 }
1140#endif // CONFIG_HAX
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001141 memory_try_enable_merging(new_block->host, size);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001142 }
1143 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001144 new_block->length = size;
1145
David 'Digit' Turner454cb832014-04-12 01:02:51 +02001146 if (dev) {
1147 char *id = qdev_get_dev_path(dev);
1148 if (id) {
1149 snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
1150 g_free(id);
1151 }
1152 }
1153 pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
1154
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001155 /* Keep the list sorted from biggest to smallest block. */
1156 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1157 if (block->length < new_block->length) {
1158 break;
1159 }
1160 }
1161 if (block) {
1162 QTAILQ_INSERT_BEFORE(block, new_block, next);
1163 } else {
1164 QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next);
1165 }
1166 ram_list.mru_block = NULL;
1167
1168 ram_list.version++;
1169 qemu_mutex_unlock_ramlist();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001170
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001171 ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001172 last_ram_offset() >> TARGET_PAGE_BITS);
1173 memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001174 0xff, size >> TARGET_PAGE_BITS);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001175 //cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001176
David 'Digit' Turner7891dd32014-04-28 10:59:47 +02001177 qemu_ram_setup_dump(new_block->host, size);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001178 //qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
1179 //qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
David 'Digit' Turner454cb832014-04-12 01:02:51 +02001180
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001181 if (kvm_enabled())
1182 kvm_setup_guest_memory(new_block->host, size);
1183
1184 return new_block->offset;
1185}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001186
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001187ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
1188{
1189 return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
1190}
1191
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001192void qemu_ram_free_from_ptr(ram_addr_t addr)
1193{
1194 RAMBlock *block;
1195
1196 /* This assumes the iothread lock is taken here too. */
1197 qemu_mutex_lock_ramlist();
1198 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1199 if (addr == block->offset) {
1200 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1201 ram_list.mru_block = NULL;
1202 ram_list.version++;
1203 g_free(block);
1204 break;
1205 }
1206 }
1207 qemu_mutex_unlock_ramlist();
1208}
1209
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001210void qemu_ram_free(ram_addr_t addr)
1211{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001212 RAMBlock *block;
1213
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001214 /* This assumes the iothread lock is taken here too. */
1215 qemu_mutex_lock_ramlist();
1216 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001217 if (addr == block->offset) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001218 QTAILQ_REMOVE(&ram_list.blocks, block, next);
1219 ram_list.mru_block = NULL;
1220 ram_list.version++;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001221 if (block->flags & RAM_PREALLOC_MASK) {
1222 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001223 } else if (xen_enabled()) {
1224 //xen_invalidate_map_cache_entry(block->host);
1225#ifndef _WIN32
1226 } else if (block->fd >= 0) {
1227 munmap(block->host, block->length);
1228 close(block->fd);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001229#endif
1230 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001231 qemu_anon_ram_free(block->host, block->length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001232 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001233 g_free(block);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001234 break;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001235 }
1236 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001237 qemu_mutex_unlock_ramlist();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001238
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001239}
1240
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001241#ifndef _WIN32
1242void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
1243{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001244 RAMBlock *block;
1245 ram_addr_t offset;
1246 int flags;
1247 void *area, *vaddr;
1248
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001249 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001250 offset = addr - block->offset;
1251 if (offset < block->length) {
1252 vaddr = block->host + offset;
1253 if (block->flags & RAM_PREALLOC_MASK) {
1254 ;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001255 } else if (xen_enabled()) {
1256 abort();
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001257 } else {
1258 flags = MAP_FIXED;
1259 munmap(vaddr, length);
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001260 if (block->fd >= 0) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001261#ifdef MAP_POPULATE
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001262 flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
1263 MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001264#else
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001265 flags |= MAP_PRIVATE;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001266#endif
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001267 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1268 flags, block->fd, offset);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001269 } else {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001270 /*
1271 * Remap needs to match alloc. Accelerators that
1272 * set phys_mem_alloc never remap. If they did,
1273 * we'd need a remap hook here.
1274 */
1275 assert(phys_mem_alloc == qemu_anon_ram_alloc);
1276
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001277 flags |= MAP_PRIVATE | MAP_ANONYMOUS;
1278 area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
1279 flags, -1, 0);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001280 }
1281 if (area != vaddr) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001282 fprintf(stderr, "Could not remap addr: "
1283 RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001284 length, addr);
1285 exit(1);
1286 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001287 memory_try_enable_merging(vaddr, length);
1288 qemu_ram_setup_dump(vaddr, length);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001289 }
1290 return;
1291 }
1292 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001293}
1294#endif /* !_WIN32 */
1295
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001296/* Return a host pointer to ram allocated with qemu_ram_alloc.
1297 With the exception of the softmmu code in this file, this should
1298 only be used for local memory (e.g. video ram) that the device owns,
1299 and knows it isn't going to access beyond the end of the block.
1300
1301 It should not be used for general purpose DMA.
1302 Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
1303 */
1304void *qemu_get_ram_ptr(ram_addr_t addr)
1305{
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001306 RAMBlock *block = qemu_get_ram_block(addr);
1307#if 0
1308 if (xen_enabled()) {
1309 /* We need to check if the requested address is in the RAM
1310 * because we don't want to map the entire memory in QEMU.
1311 * In that case just map until the end of the page.
1312 */
1313 if (block->offset == 0) {
1314 return xen_map_cache(addr, 0, 0);
1315 } else if (block->host == NULL) {
1316 block->host =
1317 xen_map_cache(block->offset, block->length, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001318 }
1319 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001320#endif
1321 return block->host + (addr - block->offset);
1322}
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001323
1324/* Return a host pointer to ram allocated with qemu_ram_alloc.
1325 * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
1326 */
1327void *qemu_safe_ram_ptr(ram_addr_t addr)
1328{
1329 RAMBlock *block;
1330
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001331 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001332 if (addr - block->offset < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001333 return block->host + (addr - block->offset);
1334 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001335 }
1336
1337 fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
1338 abort();
1339
1340 return NULL;
1341}
1342
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001343/* Some of the softmmu routines need to translate from a host pointer
1344 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001345int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
1346{
1347 RAMBlock *block;
1348 uint8_t *host = ptr;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001349#if 0
1350 if (xen_enabled()) {
1351 *ram_addr = xen_ram_addr_from_mapcache(ptr);
1352 return qemu_get_ram_block(*ram_addr)->mr;
1353 }
1354#endif
1355 block = ram_list.mru_block;
1356 if (block && block->host && host - block->host < block->length) {
1357 goto found;
1358 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001359
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001360 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
1361 /* This case append when the block is not mapped. */
1362 if (block->host == NULL) {
1363 continue;
1364 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001365 if (host - block->host < block->length) {
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001366 goto found;
1367 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001368 }
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001369
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001370 return -1;
David 'Digit' Turner0e8e7482014-02-17 20:25:52 +01001371
1372found:
1373 *ram_addr = block->offset + (host - block->host);
1374 return 0;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001375}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001376
1377/* Some of the softmmu routines need to translate from a host pointer
1378 (typically a TLB entry) back to a ram offset. */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001379ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001380{
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001381 ram_addr_t ram_addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001382
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001383 if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001384 fprintf(stderr, "Bad ram pointer %p\n", ptr);
1385 abort();
1386 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001387 return ram_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001388}
1389
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001390static uint32_t unassigned_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001391{
1392#ifdef DEBUG_UNASSIGNED
1393 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1394#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001395#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001396 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001397#endif
1398 return 0;
1399}
1400
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001401static uint32_t unassigned_mem_readw(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001402{
1403#ifdef DEBUG_UNASSIGNED
1404 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1405#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001406#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001407 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001408#endif
1409 return 0;
1410}
1411
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001412static uint32_t unassigned_mem_readl(void *opaque, hwaddr addr)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001413{
1414#ifdef DEBUG_UNASSIGNED
1415 printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
1416#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001417#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001418 cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001419#endif
1420 return 0;
1421}
1422
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001423static void unassigned_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001424{
1425#ifdef DEBUG_UNASSIGNED
1426 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1427#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001428#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001429 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001430#endif
1431}
1432
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001433static void unassigned_mem_writew(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001434{
1435#ifdef DEBUG_UNASSIGNED
1436 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1437#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001438#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001439 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001440#endif
1441}
1442
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001443static void unassigned_mem_writel(void *opaque, hwaddr addr, uint32_t val)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001444{
1445#ifdef DEBUG_UNASSIGNED
1446 printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
1447#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001448#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01001449 cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001450#endif
1451}
1452
David 'Digit' Turner36411062010-12-22 17:34:53 +01001453static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001454 unassigned_mem_readb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001455 unassigned_mem_readw,
1456 unassigned_mem_readl,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001457};
1458
David 'Digit' Turner36411062010-12-22 17:34:53 +01001459static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001460 unassigned_mem_writeb,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001461 unassigned_mem_writew,
1462 unassigned_mem_writel,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001463};
1464
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001465static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001466 uint32_t val)
1467{
1468 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001469 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001470 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1471#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001472 tb_invalidate_phys_page_fast0(ram_addr, 1);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001473 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001474#endif
1475 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001476 stb_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001477 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001478 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001479 /* we remove the notdirty callback only if the code has been
1480 flushed */
1481 if (dirty_flags == 0xff)
1482 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1483}
1484
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001485static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001486 uint32_t val)
1487{
1488 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001489 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001490 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1491#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001492 tb_invalidate_phys_page_fast0(ram_addr, 2);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001493 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001494#endif
1495 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001496 stw_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001497 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001498 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001499 /* we remove the notdirty callback only if the code has been
1500 flushed */
1501 if (dirty_flags == 0xff)
1502 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1503}
1504
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001505static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001506 uint32_t val)
1507{
1508 int dirty_flags;
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001509 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001510 if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1511#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turnerff9a2b82014-02-17 22:31:24 +01001512 tb_invalidate_phys_page_fast0(ram_addr, 4);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001513 dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001514#endif
1515 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001516 stl_p(qemu_get_ram_ptr(ram_addr), val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001517 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
David 'Digit' Turner280afa02011-05-11 17:37:44 +02001518 cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001519 /* we remove the notdirty callback only if the code has been
1520 flushed */
1521 if (dirty_flags == 0xff)
1522 tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1523}
1524
David 'Digit' Turner36411062010-12-22 17:34:53 +01001525static CPUReadMemoryFunc * const error_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001526 NULL, /* never used */
1527 NULL, /* never used */
1528 NULL, /* never used */
1529};
1530
David 'Digit' Turner36411062010-12-22 17:34:53 +01001531static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001532 notdirty_mem_writeb,
1533 notdirty_mem_writew,
1534 notdirty_mem_writel,
1535};
1536
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001537static void tb_check_watchpoint(CPUArchState* env)
1538{
1539 TranslationBlock *tb = tb_find_pc(env->mem_io_pc);
1540 if (!tb) {
1541 cpu_abort(env, "check_watchpoint: could not find TB for "
1542 "pc=%p", (void *)env->mem_io_pc);
1543 }
1544 cpu_restore_state(env, env->mem_io_pc);
1545 tb_phys_invalidate(tb, -1);
1546}
1547
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001548/* Generate a debug exception if a watchpoint has been hit. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001549static void check_watchpoint(int offset, int len_mask, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001550{
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +01001551 CPUState *cpu = current_cpu;
1552 CPUArchState *env = cpu->env_ptr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001553 target_ulong pc, cs_base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001554 target_ulong vaddr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001555 CPUWatchpoint *wp;
1556 int cpu_flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001557
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001558 if (env->watchpoint_hit) {
1559 /* We re-entered the check after replacing the TB. Now raise
1560 * the debug interrupt so that is will trigger after the
1561 * current instruction. */
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +01001562 cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001563 return;
1564 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001565 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001566 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001567 if ((vaddr == (wp->vaddr & len_mask) ||
1568 (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
1569 wp->flags |= BP_WATCHPOINT_HIT;
1570 if (!env->watchpoint_hit) {
1571 env->watchpoint_hit = wp;
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01001572 tb_check_watchpoint(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001573 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1574 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001575 cpu_loop_exit(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001576 } else {
1577 cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
1578 tb_gen_code(env, pc, cs_base, cpu_flags, 1);
David 'Digit' Turner85c62202014-02-16 20:53:40 +01001579 cpu_resume_from_signal(env, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001580 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001581 }
1582 } else {
1583 wp->flags &= ~BP_WATCHPOINT_HIT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001584 }
1585 }
1586}
1587
1588/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
1589 so these check for a hit then pass through to the normal out-of-line
1590 phys routines. */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001591static uint32_t watch_mem_readb(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001592{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001593 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001594 return ldub_phys(addr);
1595}
1596
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001597static uint32_t watch_mem_readw(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001598{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001599 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001600 return lduw_phys(addr);
1601}
1602
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001603static uint32_t watch_mem_readl(void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001604{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001605 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001606 return ldl_phys(addr);
1607}
1608
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001609static void watch_mem_writeb(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001610 uint32_t val)
1611{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001612 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001613 stb_phys(addr, val);
1614}
1615
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001616static void watch_mem_writew(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001617 uint32_t val)
1618{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001619 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001620 stw_phys(addr, val);
1621}
1622
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001623static void watch_mem_writel(void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001624 uint32_t val)
1625{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001626 check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001627 stl_phys(addr, val);
1628}
1629
David 'Digit' Turner36411062010-12-22 17:34:53 +01001630static CPUReadMemoryFunc * const watch_mem_read[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001631 watch_mem_readb,
1632 watch_mem_readw,
1633 watch_mem_readl,
1634};
1635
David 'Digit' Turner36411062010-12-22 17:34:53 +01001636static CPUWriteMemoryFunc * const watch_mem_write[3] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001637 watch_mem_writeb,
1638 watch_mem_writew,
1639 watch_mem_writel,
1640};
1641
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001642static inline uint32_t subpage_readlen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001643 unsigned int len)
1644{
1645 uint32_t ret;
1646 unsigned int idx;
1647
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001648 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001649#if defined(DEBUG_SUBPAGE)
1650 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
1651 mmio, len, addr, idx);
1652#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001653 ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
1654 addr + mmio->region_offset[idx][0][len]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001655
1656 return ret;
1657}
1658
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001659static inline void subpage_writelen (subpage_t *mmio, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001660 uint32_t value, unsigned int len)
1661{
1662 unsigned int idx;
1663
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001664 idx = SUBPAGE_IDX(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001665#if defined(DEBUG_SUBPAGE)
1666 printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
1667 mmio, len, addr, idx, value);
1668#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001669 (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
1670 addr + mmio->region_offset[idx][1][len],
1671 value);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001672}
1673
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001674static uint32_t subpage_readb (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, 0);
1681}
1682
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001683static void subpage_writeb (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, 0);
1690}
1691
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001692static uint32_t subpage_readw (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, 1);
1699}
1700
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001701static void subpage_writew (void *opaque, hwaddr addr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001702 uint32_t value)
1703{
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, 1);
1708}
1709
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001710static uint32_t subpage_readl (void *opaque, hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001711{
1712#if defined(DEBUG_SUBPAGE)
1713 printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1714#endif
1715
1716 return subpage_readlen(opaque, addr, 2);
1717}
1718
1719static void subpage_writel (void *opaque,
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001720 hwaddr addr, uint32_t value)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001721{
1722#if defined(DEBUG_SUBPAGE)
1723 printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
1724#endif
1725 subpage_writelen(opaque, addr, value, 2);
1726}
1727
David 'Digit' Turner36411062010-12-22 17:34:53 +01001728static CPUReadMemoryFunc * const subpage_read[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001729 &subpage_readb,
1730 &subpage_readw,
1731 &subpage_readl,
1732};
1733
David 'Digit' Turner36411062010-12-22 17:34:53 +01001734static CPUWriteMemoryFunc * const subpage_write[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001735 &subpage_writeb,
1736 &subpage_writew,
1737 &subpage_writel,
1738};
1739
1740static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001741 ram_addr_t memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001742{
1743 int idx, eidx;
1744 unsigned int i;
1745
1746 if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
1747 return -1;
1748 idx = SUBPAGE_IDX(start);
1749 eidx = SUBPAGE_IDX(end);
1750#if defined(DEBUG_SUBPAGE)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001751 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 -08001752 mmio, start, end, idx, eidx, memory);
1753#endif
1754 memory >>= IO_MEM_SHIFT;
1755 for (; idx <= eidx; idx++) {
1756 for (i = 0; i < 4; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001757 if (_io_mem_read[memory][i]) {
1758 mmio->mem_read[idx][i] = &_io_mem_read[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001759 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001760 mmio->region_offset[idx][0][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001761 }
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001762 if (_io_mem_write[memory][i]) {
1763 mmio->mem_write[idx][i] = &_io_mem_write[memory][i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001764 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001765 mmio->region_offset[idx][1][i] = region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001766 }
1767 }
1768 }
1769
1770 return 0;
1771}
1772
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001773static void *subpage_init (hwaddr base, ram_addr_t *phys,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001774 ram_addr_t orig_memory, ram_addr_t region_offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001775{
1776 subpage_t *mmio;
1777 int subpage_memory;
1778
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01001779 mmio = g_malloc0(sizeof(subpage_t));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001780
1781 mmio->base = base;
1782 subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001783#if defined(DEBUG_SUBPAGE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001784 printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
1785 mmio, base, TARGET_PAGE_SIZE, subpage_memory);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001786#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001787 *phys = subpage_memory | IO_MEM_SUBPAGE;
1788 subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
1789 region_offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001790
1791 return mmio;
1792}
1793
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001794static int get_free_io_mem_idx(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001795{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001796 int i;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001797
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001798 for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
1799 if (!io_mem_used[i]) {
1800 io_mem_used[i] = 1;
1801 return i;
1802 }
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07001803 fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001804 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001805}
1806
1807/* mem_read and mem_write are arrays of functions containing the
1808 function to access byte (index 0), word (index 1) and dword (index
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001809 2). Functions can be omitted with a NULL function pointer.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001810 If io_index is non zero, the corresponding io zone is
1811 modified. If it is zero, a new io zone is allocated. The return
1812 value can be used with cpu_register_physical_memory(). (-1) is
1813 returned if error. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001814static int cpu_register_io_memory_fixed(int io_index,
David 'Digit' Turner36411062010-12-22 17:34:53 +01001815 CPUReadMemoryFunc * const *mem_read,
1816 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001817 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001818{
1819 int i, subwidth = 0;
1820
1821 if (io_index <= 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001822 io_index = get_free_io_mem_idx();
1823 if (io_index == -1)
1824 return io_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001825 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001826 io_index >>= IO_MEM_SHIFT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001827 if (io_index >= IO_MEM_NB_ENTRIES)
1828 return -1;
1829 }
1830
1831 for(i = 0;i < 3; i++) {
1832 if (!mem_read[i] || !mem_write[i])
1833 subwidth = IO_MEM_SUBWIDTH;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001834 _io_mem_read[io_index][i] = mem_read[i];
1835 _io_mem_write[io_index][i] = mem_write[i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001836 }
1837 io_mem_opaque[io_index] = opaque;
1838 return (io_index << IO_MEM_SHIFT) | subwidth;
1839}
1840
David 'Digit' Turner36411062010-12-22 17:34:53 +01001841int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
1842 CPUWriteMemoryFunc * const *mem_write,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001843 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001844{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001845 return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001846}
1847
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001848void cpu_unregister_io_memory(int io_table_address)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001849{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001850 int i;
1851 int io_index = io_table_address >> IO_MEM_SHIFT;
1852
1853 for (i=0;i < 3; i++) {
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001854 _io_mem_read[io_index][i] = unassigned_mem_read[i];
1855 _io_mem_write[io_index][i] = unassigned_mem_write[i];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001856 }
1857 io_mem_opaque[io_index] = NULL;
1858 io_mem_used[io_index] = 0;
1859}
1860
1861static void io_mem_init(void)
1862{
1863 int i;
1864
1865 cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
1866 cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
1867 cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
1868 for (i=0; i<5; i++)
1869 io_mem_used[i] = 1;
1870
1871 io_mem_watch = cpu_register_io_memory(watch_mem_read,
1872 watch_mem_write, NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001873}
1874
1875#endif /* !defined(CONFIG_USER_ONLY) */
1876
1877/* physical memory access (slow version, mainly for debug) */
1878#if defined(CONFIG_USER_ONLY)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001879void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001880 int len, int is_write)
1881{
1882 int l, flags;
1883 target_ulong page;
1884 void * p;
1885
1886 while (len > 0) {
1887 page = addr & TARGET_PAGE_MASK;
1888 l = (page + TARGET_PAGE_SIZE) - addr;
1889 if (l > len)
1890 l = len;
1891 flags = page_get_flags(page);
1892 if (!(flags & PAGE_VALID))
1893 return;
1894 if (is_write) {
1895 if (!(flags & PAGE_WRITE))
1896 return;
1897 /* XXX: this code should not depend on lock_user */
1898 if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
1899 /* FIXME - should this return an error rather than just fail? */
1900 return;
1901 memcpy(p, buf, l);
1902 unlock_user(p, addr, l);
1903 } else {
1904 if (!(flags & PAGE_READ))
1905 return;
1906 /* XXX: this code should not depend on lock_user */
1907 if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
1908 /* FIXME - should this return an error rather than just fail? */
1909 return;
1910 memcpy(buf, p, l);
1911 unlock_user(p, addr, 0);
1912 }
1913 len -= l;
1914 buf += l;
1915 addr += l;
1916 }
1917}
1918
1919#else
Pete Delaneyd09d7662013-03-28 19:53:13 -07001920
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001921static void invalidate_and_set_dirty(hwaddr addr,
1922 hwaddr length)
Pete Delaneyd09d7662013-03-28 19:53:13 -07001923{
1924 if (!cpu_physical_memory_is_dirty(addr)) {
1925 /* invalidate code */
1926 tb_invalidate_phys_page_range(addr, addr + length, 0);
1927 /* set dirty bit */
1928 cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
1929 }
1930}
1931
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001932void cpu_physical_memory_rw(hwaddr addr, void *buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001933 int len, int is_write)
1934{
1935 int l, io_index;
1936 uint8_t *ptr;
1937 uint32_t val;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001938 hwaddr page;
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001939 ram_addr_t pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001940 uint8_t* buf8 = (uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001941 PhysPageDesc *p;
1942
1943 while (len > 0) {
1944 page = addr & TARGET_PAGE_MASK;
1945 l = (page + TARGET_PAGE_SIZE) - addr;
1946 if (l > len)
1947 l = len;
1948 p = phys_page_find(page >> TARGET_PAGE_BITS);
1949 if (!p) {
1950 pd = IO_MEM_UNASSIGNED;
1951 } else {
1952 pd = p->phys_offset;
1953 }
1954
1955 if (is_write) {
1956 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001957 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001958 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001959 if (p)
1960 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001961 /* XXX: could force cpu_single_env to NULL to avoid
1962 potential bugs */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001963 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001964 /* 32 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001965 val = ldl_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001966 io_mem_write(io_index, addr1, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001967 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001968 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001969 /* 16 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001970 val = lduw_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001971 io_mem_write(io_index, addr1, val, 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001972 l = 2;
1973 } else {
1974 /* 8 bit write access */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001975 val = ldub_p(buf8);
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001976 io_mem_write(io_index, addr1, val, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001977 l = 1;
1978 }
1979 } else {
David 'Digit' Turnerb974f3f2014-03-19 14:13:35 +01001980 ram_addr_t addr1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001981 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
1982 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001983 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001984 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07001985 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001986 }
1987 } else {
1988 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
1989 !(pd & IO_MEM_ROMD)) {
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01001990 hwaddr addr1 = addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001991 /* I/O case */
1992 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001993 if (p)
1994 addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
1995 if (l >= 4 && ((addr1 & 3) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001996 /* 32 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01001997 val = io_mem_read(io_index, addr1, 4);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001998 stl_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001999 l = 4;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002000 } else if (l >= 2 && ((addr1 & 1) == 0)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002001 /* 16 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002002 val = io_mem_read(io_index, addr1, 2);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002003 stw_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002004 l = 2;
2005 } else {
2006 /* 8 bit read access */
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002007 val = io_mem_read(io_index, addr1, 1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002008 stb_p(buf8, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002009 l = 1;
2010 }
2011 } else {
2012 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002013 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002014 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002015 memcpy(buf8, ptr, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002016 }
2017 }
2018 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002019 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002020 addr += l;
2021 }
2022}
2023
2024/* used for ROM loading : can write in RAM and ROM */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002025void cpu_physical_memory_write_rom(hwaddr addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002026 const void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002027{
2028 int l;
2029 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002030 hwaddr page;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002031 unsigned long pd;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002032 const uint8_t* buf8 = (const uint8_t*)buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002033 PhysPageDesc *p;
2034
2035 while (len > 0) {
2036 page = addr & TARGET_PAGE_MASK;
2037 l = (page + TARGET_PAGE_SIZE) - addr;
2038 if (l > len)
2039 l = len;
2040 p = phys_page_find(page >> TARGET_PAGE_BITS);
2041 if (!p) {
2042 pd = IO_MEM_UNASSIGNED;
2043 } else {
2044 pd = p->phys_offset;
2045 }
2046
2047 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2048 (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2049 !(pd & IO_MEM_ROMD)) {
2050 /* do nothing */
2051 } else {
2052 unsigned long addr1;
2053 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2054 /* ROM/RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002055 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002056 memcpy(ptr, buf8, l);
Pete Delaneyd09d7662013-03-28 19:53:13 -07002057 invalidate_and_set_dirty(addr1, l);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002058 }
2059 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002060 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002061 addr += l;
2062 }
2063}
2064
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002065typedef struct {
2066 void *buffer;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002067 hwaddr addr;
2068 hwaddr len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002069} BounceBuffer;
2070
2071static BounceBuffer bounce;
2072
2073typedef struct MapClient {
2074 void *opaque;
2075 void (*callback)(void *opaque);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002076 QLIST_ENTRY(MapClient) link;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002077} MapClient;
2078
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002079static QLIST_HEAD(map_client_list, MapClient) map_client_list
2080 = QLIST_HEAD_INITIALIZER(map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002081
2082void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
2083{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002084 MapClient *client = g_malloc(sizeof(*client));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002085
2086 client->opaque = opaque;
2087 client->callback = callback;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002088 QLIST_INSERT_HEAD(&map_client_list, client, link);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002089 return client;
2090}
2091
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002092static void cpu_unregister_map_client(void *_client)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002093{
2094 MapClient *client = (MapClient *)_client;
2095
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002096 QLIST_REMOVE(client, link);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002097 g_free(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002098}
2099
2100static void cpu_notify_map_clients(void)
2101{
2102 MapClient *client;
2103
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07002104 while (!QLIST_EMPTY(&map_client_list)) {
2105 client = QLIST_FIRST(&map_client_list);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002106 client->callback(client->opaque);
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002107 cpu_unregister_map_client(client);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002108 }
2109}
2110
2111/* Map a physical memory region into a host virtual address.
2112 * May map a subset of the requested range, given by and returned in *plen.
2113 * May return NULL if resources needed to perform the mapping are exhausted.
2114 * Use only for reads OR writes - not for read-modify-write operations.
2115 * Use cpu_register_map_client() to know when retrying the map operation is
2116 * likely to succeed.
2117 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002118void *cpu_physical_memory_map(hwaddr addr,
2119 hwaddr *plen,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002120 int is_write)
2121{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002122 hwaddr len = *plen;
2123 hwaddr done = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002124 int l;
2125 uint8_t *ret = NULL;
2126 uint8_t *ptr;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002127 hwaddr page;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002128 unsigned long pd;
2129 PhysPageDesc *p;
2130 unsigned long addr1;
2131
2132 while (len > 0) {
2133 page = addr & TARGET_PAGE_MASK;
2134 l = (page + TARGET_PAGE_SIZE) - addr;
2135 if (l > len)
2136 l = len;
2137 p = phys_page_find(page >> TARGET_PAGE_BITS);
2138 if (!p) {
2139 pd = IO_MEM_UNASSIGNED;
2140 } else {
2141 pd = p->phys_offset;
2142 }
2143
2144 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2145 if (done || bounce.buffer) {
2146 break;
2147 }
2148 bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
2149 bounce.addr = addr;
2150 bounce.len = l;
2151 if (!is_write) {
David 'Digit' Turner8b87a1d2014-03-14 16:44:00 +01002152 cpu_physical_memory_read(addr, bounce.buffer, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002153 }
2154 ptr = bounce.buffer;
2155 } else {
2156 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2157 ptr = qemu_get_ram_ptr(addr1);
2158 }
2159 if (!done) {
2160 ret = ptr;
2161 } else if (ret + done != ptr) {
2162 break;
2163 }
2164
2165 len -= l;
2166 addr += l;
2167 done += l;
2168 }
2169 *plen = done;
2170 return ret;
2171}
2172
2173/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
2174 * Will also mark the memory as dirty if is_write == 1. access_len gives
2175 * the amount of memory that was actually read or written by the caller.
2176 */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002177void cpu_physical_memory_unmap(void *buffer, hwaddr len,
2178 int is_write, hwaddr access_len)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002179{
2180 if (buffer != bounce.buffer) {
2181 if (is_write) {
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002182 ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002183 while (access_len) {
2184 unsigned l;
2185 l = TARGET_PAGE_SIZE;
2186 if (l > access_len)
2187 l = access_len;
Pete Delaneyd09d7662013-03-28 19:53:13 -07002188 invalidate_and_set_dirty(addr1, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002189 addr1 += l;
2190 access_len -= l;
2191 }
2192 }
2193 return;
2194 }
2195 if (is_write) {
2196 cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
2197 }
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002198 qemu_vfree(bounce.buffer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002199 bounce.buffer = NULL;
2200 cpu_notify_map_clients();
2201}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002202
2203/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002204static inline uint32_t ldl_phys_internal(hwaddr addr,
2205 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002206{
2207 int io_index;
2208 uint8_t *ptr;
2209 uint32_t val;
2210 unsigned long pd;
2211 PhysPageDesc *p;
2212
2213 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2214 if (!p) {
2215 pd = IO_MEM_UNASSIGNED;
2216 } else {
2217 pd = p->phys_offset;
2218 }
2219
2220 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2221 !(pd & IO_MEM_ROMD)) {
2222 /* I/O case */
2223 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002224 if (p)
2225 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002226 val = io_mem_read(io_index, addr, 4);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002227#if defined(TARGET_WORDS_BIGENDIAN)
2228 if (endian == DEVICE_LITTLE_ENDIAN) {
2229 val = bswap32(val);
2230 }
2231#else
2232 if (endian == DEVICE_BIG_ENDIAN) {
2233 val = bswap32(val);
2234 }
2235#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002236 } else {
2237 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002238 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002239 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002240 switch (endian) {
2241 case DEVICE_LITTLE_ENDIAN:
2242 val = ldl_le_p(ptr);
2243 break;
2244 case DEVICE_BIG_ENDIAN:
2245 val = ldl_be_p(ptr);
2246 break;
2247 default:
2248 val = ldl_p(ptr);
2249 break;
2250 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002251 }
2252 return val;
2253}
2254
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002255uint32_t ldl_phys(hwaddr addr)
2256{
2257 return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2258}
2259
2260uint32_t ldl_le_phys(hwaddr addr)
2261{
2262 return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2263}
2264
2265uint32_t ldl_be_phys(hwaddr addr)
2266{
2267 return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
2268}
2269
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002270/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002271static inline uint64_t ldq_phys_internal(hwaddr addr,
2272 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002273{
2274 int io_index;
2275 uint8_t *ptr;
2276 uint64_t val;
2277 unsigned long pd;
2278 PhysPageDesc *p;
2279
2280 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2281 if (!p) {
2282 pd = IO_MEM_UNASSIGNED;
2283 } else {
2284 pd = p->phys_offset;
2285 }
2286
2287 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2288 !(pd & IO_MEM_ROMD)) {
2289 /* I/O case */
2290 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002291 if (p)
2292 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002293
2294 /* XXX This is broken when device endian != cpu endian.
2295 Fix and add "endian" variable check */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002296#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002297 val = (uint64_t)io_mem_read(io_index, addr, 4) << 32;
2298 val |= io_mem_read(io_index, addr + 4, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002299#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002300 val = io_mem_read(io_index, addr, 4);
2301 val |= (uint64_t)io_mem_read(io_index, addr + 4, 4) << 32;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002302#endif
2303 } else {
2304 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002305 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002306 (addr & ~TARGET_PAGE_MASK);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002307 switch (endian) {
2308 case DEVICE_LITTLE_ENDIAN:
2309 val = ldq_le_p(ptr);
2310 break;
2311 case DEVICE_BIG_ENDIAN:
2312 val = ldq_be_p(ptr);
2313 break;
2314 default:
2315 val = ldq_p(ptr);
2316 break;
2317 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002318 }
2319 return val;
2320}
2321
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002322uint64_t ldq_phys(hwaddr addr)
2323{
2324 return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2325}
2326
2327uint64_t ldq_le_phys(hwaddr addr)
2328{
2329 return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2330}
2331
2332uint64_t ldq_be_phys(hwaddr addr)
2333{
2334 return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
2335}
2336
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002337/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002338uint32_t ldub_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002339{
2340 uint8_t val;
2341 cpu_physical_memory_read(addr, &val, 1);
2342 return val;
2343}
2344
2345/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002346static inline uint32_t lduw_phys_internal(hwaddr addr,
2347 enum device_endian endian)
2348{
2349 int io_index;
2350 uint8_t *ptr;
2351 uint64_t val;
2352 unsigned long pd;
2353 PhysPageDesc *p;
2354
2355 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2356 if (!p) {
2357 pd = IO_MEM_UNASSIGNED;
2358 } else {
2359 pd = p->phys_offset;
2360 }
2361
2362 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2363 !(pd & IO_MEM_ROMD)) {
2364 /* I/O case */
2365 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2366 if (p)
2367 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002368 val = io_mem_read(io_index, addr, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002369#if defined(TARGET_WORDS_BIGENDIAN)
2370 if (endian == DEVICE_LITTLE_ENDIAN) {
2371 val = bswap16(val);
2372 }
2373#else
2374 if (endian == DEVICE_BIG_ENDIAN) {
2375 val = bswap16(val);
2376 }
2377#endif
2378 } else {
2379 /* RAM case */
2380 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
2381 (addr & ~TARGET_PAGE_MASK);
2382 switch (endian) {
2383 case DEVICE_LITTLE_ENDIAN:
2384 val = lduw_le_p(ptr);
2385 break;
2386 case DEVICE_BIG_ENDIAN:
2387 val = lduw_be_p(ptr);
2388 break;
2389 default:
2390 val = lduw_p(ptr);
2391 break;
2392 }
2393 }
2394 return val;
2395}
2396
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002397uint32_t lduw_phys(hwaddr addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002398{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002399 return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
2400}
2401
2402uint32_t lduw_le_phys(hwaddr addr)
2403{
2404 return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
2405}
2406
2407uint32_t lduw_be_phys(hwaddr addr)
2408{
2409 return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002410}
2411
2412/* warning: addr must be aligned. The ram page is not masked as dirty
2413 and the code inside is not invalidated. It is useful if the dirty
2414 bits are used to track modified PTEs */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002415void stl_phys_notdirty(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002416{
2417 int io_index;
2418 uint8_t *ptr;
2419 unsigned long pd;
2420 PhysPageDesc *p;
2421
2422 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2423 if (!p) {
2424 pd = IO_MEM_UNASSIGNED;
2425 } else {
2426 pd = p->phys_offset;
2427 }
2428
2429 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2430 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002431 if (p)
2432 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002433 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002434 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002435 unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2436 ptr = qemu_get_ram_ptr(addr1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002437 stl_p(ptr, val);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002438
2439 if (unlikely(in_migration)) {
2440 if (!cpu_physical_memory_is_dirty(addr1)) {
2441 /* invalidate code */
2442 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2443 /* set dirty bit */
David 'Digit' Turner280afa02011-05-11 17:37:44 +02002444 cpu_physical_memory_set_dirty_flags(
2445 addr1, (0xff & ~CODE_DIRTY_FLAG));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002446 }
2447 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002448 }
2449}
2450
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002451void stq_phys_notdirty(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002452{
2453 int io_index;
2454 uint8_t *ptr;
2455 unsigned long pd;
2456 PhysPageDesc *p;
2457
2458 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2459 if (!p) {
2460 pd = IO_MEM_UNASSIGNED;
2461 } else {
2462 pd = p->phys_offset;
2463 }
2464
2465 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2466 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002467 if (p)
2468 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002469#ifdef TARGET_WORDS_BIGENDIAN
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002470 io_mem_write(io_index, addr, val >> 32, 4);
2471 io_mem_write(io_index, addr + 4, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002472#else
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002473 io_mem_write(io_index, addr, val, 4);
2474 io_mem_write(io_index, addr + 4, val >> 32, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002475#endif
2476 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002477 ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002478 (addr & ~TARGET_PAGE_MASK);
2479 stq_p(ptr, val);
2480 }
2481}
2482
2483/* warning: addr must be aligned */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002484static inline void stl_phys_internal(hwaddr addr, uint32_t val,
2485 enum device_endian endian)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002486{
2487 int io_index;
2488 uint8_t *ptr;
2489 unsigned long pd;
2490 PhysPageDesc *p;
2491
2492 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2493 if (!p) {
2494 pd = IO_MEM_UNASSIGNED;
2495 } else {
2496 pd = p->phys_offset;
2497 }
2498
2499 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2500 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002501 if (p)
2502 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002503#if defined(TARGET_WORDS_BIGENDIAN)
2504 if (endian == DEVICE_LITTLE_ENDIAN) {
2505 val = bswap32(val);
2506 }
2507#else
2508 if (endian == DEVICE_BIG_ENDIAN) {
2509 val = bswap32(val);
2510 }
2511#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002512 io_mem_write(io_index, addr, val, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002513 } else {
2514 unsigned long addr1;
2515 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2516 /* RAM case */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002517 ptr = qemu_get_ram_ptr(addr1);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002518 switch (endian) {
2519 case DEVICE_LITTLE_ENDIAN:
2520 stl_le_p(ptr, val);
2521 break;
2522 case DEVICE_BIG_ENDIAN:
2523 stl_be_p(ptr, val);
2524 break;
2525 default:
2526 stl_p(ptr, val);
2527 break;
2528 }
Pete Delaneyd09d7662013-03-28 19:53:13 -07002529 invalidate_and_set_dirty(addr1, 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002530 }
2531}
2532
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002533void stl_phys(hwaddr addr, uint32_t val)
2534{
2535 stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2536}
2537
2538void stl_le_phys(hwaddr addr, uint32_t val)
2539{
2540 stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2541}
2542
2543void stl_be_phys(hwaddr addr, uint32_t val)
2544{
2545 stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
2546}
2547
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002548/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002549void stb_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002550{
2551 uint8_t v = val;
2552 cpu_physical_memory_write(addr, &v, 1);
2553}
2554
2555/* XXX: optimize */
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002556static inline void stw_phys_internal(hwaddr addr, uint32_t val,
2557 enum device_endian endian)
2558{
2559 int io_index;
2560 uint8_t *ptr;
2561 unsigned long pd;
2562 PhysPageDesc *p;
2563
2564 p = phys_page_find(addr >> TARGET_PAGE_BITS);
2565 if (!p) {
2566 pd = IO_MEM_UNASSIGNED;
2567 } else {
2568 pd = p->phys_offset;
2569 }
2570
2571 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2572 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2573 if (p)
2574 addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2575#if defined(TARGET_WORDS_BIGENDIAN)
2576 if (endian == DEVICE_LITTLE_ENDIAN) {
2577 val = bswap16(val);
2578 }
2579#else
2580 if (endian == DEVICE_BIG_ENDIAN) {
2581 val = bswap16(val);
2582 }
2583#endif
David 'Digit' Turnerfdec1f12014-03-21 11:49:03 +01002584 io_mem_write(io_index, addr, val, 2);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002585 } else {
2586 unsigned long addr1;
2587 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2588 /* RAM case */
2589 ptr = qemu_get_ram_ptr(addr1);
2590 switch (endian) {
2591 case DEVICE_LITTLE_ENDIAN:
2592 stw_le_p(ptr, val);
2593 break;
2594 case DEVICE_BIG_ENDIAN:
2595 stw_be_p(ptr, val);
2596 break;
2597 default:
2598 stw_p(ptr, val);
2599 break;
2600 }
2601 if (!cpu_physical_memory_is_dirty(addr1)) {
2602 /* invalidate code */
2603 tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
2604 /* set dirty bit */
2605 cpu_physical_memory_set_dirty_flags(addr1,
2606 (0xff & ~CODE_DIRTY_FLAG));
2607 }
2608 }
2609}
2610
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002611void stw_phys(hwaddr addr, uint32_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002612{
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002613 stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
2614}
2615
2616void stw_le_phys(hwaddr addr, uint32_t val)
2617{
2618 stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
2619}
2620
2621void stw_be_phys(hwaddr addr, uint32_t val)
2622{
2623 stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002624}
2625
2626/* XXX: optimize */
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002627void stq_phys(hwaddr addr, uint64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002628{
2629 val = tswap64(val);
David 'Digit' Turner2afeb4c2014-03-18 16:50:21 +01002630 cpu_physical_memory_write(addr, &val, 8);
2631}
2632
2633
2634void stq_le_phys(hwaddr addr, uint64_t val)
2635{
2636 val = cpu_to_le64(val);
2637 cpu_physical_memory_write(addr, &val, 8);
2638}
2639
2640void stq_be_phys(hwaddr addr, uint64_t val)
2641{
2642 val = cpu_to_be64(val);
2643 cpu_physical_memory_write(addr, &val, 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002644}
2645
2646#endif
2647
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002648/* virtual memory access for debug (includes writing to ROM) */
David 'Digit' Turneraaef2752014-03-25 17:19:27 +01002649int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002650 void *buf, int len, int is_write)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002651{
2652 int l;
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +01002653 hwaddr phys_addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002654 target_ulong page;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002655 uint8_t* buf8 = (uint8_t*)buf;
David 'Digit' Turneraaef2752014-03-25 17:19:27 +01002656 CPUArchState *env = cpu->env_ptr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002657
2658 while (len > 0) {
2659 page = addr & TARGET_PAGE_MASK;
2660 phys_addr = cpu_get_phys_page_debug(env, page);
2661 /* if no physical page mapped, return an error */
2662 if (phys_addr == -1)
2663 return -1;
2664 l = (page + TARGET_PAGE_SIZE) - addr;
2665 if (l > len)
2666 l = len;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002667 phys_addr += (addr & ~TARGET_PAGE_MASK);
2668#if !defined(CONFIG_USER_ONLY)
2669 if (is_write)
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002670 cpu_physical_memory_write_rom(phys_addr, buf8, l);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002671 else
2672#endif
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002673 cpu_physical_memory_rw(phys_addr, buf8, l, is_write);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002674 len -= l;
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01002675 buf8 += l;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002676 addr += l;
2677 }
2678 return 0;
2679}