xref: /qemu/hw/core/cpu-system.c (revision ca05578fc80f4253ed19f4c4128a4cbd5b83f0b5)
1 /*
2  * QEMU CPU model (system specific)
3  *
4  * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see
18  * <http://www.gnu.org/licenses/gpl-2.0.html>
19  */
20 
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "exec/address-spaces.h"
24 #include "exec/cputlb.h"
25 #include "exec/memory.h"
26 #include "exec/tb-flush.h"
27 #include "exec/tswap.h"
28 #include "hw/qdev-core.h"
29 #include "hw/qdev-properties.h"
30 #include "hw/core/sysemu-cpu-ops.h"
31 #include "migration/vmstate.h"
32 #include "system/tcg.h"
33 
34 bool cpu_paging_enabled(const CPUState *cpu)
35 {
36     CPUClass *cc = CPU_GET_CLASS(cpu);
37 
38     if (cc->sysemu_ops->get_paging_enabled) {
39         return cc->sysemu_ops->get_paging_enabled(cpu);
40     }
41 
42     return false;
43 }
44 
45 bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
46                             Error **errp)
47 {
48     CPUClass *cc = CPU_GET_CLASS(cpu);
49 
50     if (cc->sysemu_ops->get_memory_mapping) {
51         return cc->sysemu_ops->get_memory_mapping(cpu, list, errp);
52     }
53 
54     error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
55     return false;
56 }
57 
58 hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
59                                      MemTxAttrs *attrs)
60 {
61     CPUClass *cc = CPU_GET_CLASS(cpu);
62     hwaddr paddr;
63 
64     if (cc->sysemu_ops->get_phys_page_attrs_debug) {
65         paddr = cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs);
66     } else {
67         /* Fallback for CPUs which don't implement the _attrs_ hook */
68         *attrs = MEMTXATTRS_UNSPECIFIED;
69         paddr = cc->sysemu_ops->get_phys_page_debug(cpu, addr);
70     }
71     /* Indicate that this is a debug access. */
72     attrs->debug = 1;
73     return paddr;
74 }
75 
76 hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
77 {
78     MemTxAttrs attrs = {};
79 
80     return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
81 }
82 
83 int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
84 {
85     int ret = 0;
86 
87     if (cpu->cc->sysemu_ops->asidx_from_attrs) {
88         ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs);
89         assert(ret < cpu->num_ases && ret >= 0);
90     }
91     return ret;
92 }
93 
94 int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
95                              void *opaque)
96 {
97     CPUClass *cc = CPU_GET_CLASS(cpu);
98 
99     if (!cc->sysemu_ops->write_elf32_qemunote) {
100         return 0;
101     }
102     return (*cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
103 }
104 
105 int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
106                          int cpuid, void *opaque)
107 {
108     CPUClass *cc = CPU_GET_CLASS(cpu);
109 
110     if (!cc->sysemu_ops->write_elf32_note) {
111         return -1;
112     }
113     return (*cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
114 }
115 
116 int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
117                              void *opaque)
118 {
119     CPUClass *cc = CPU_GET_CLASS(cpu);
120 
121     if (!cc->sysemu_ops->write_elf64_qemunote) {
122         return 0;
123     }
124     return (*cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
125 }
126 
127 int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
128                          int cpuid, void *opaque)
129 {
130     CPUClass *cc = CPU_GET_CLASS(cpu);
131 
132     if (!cc->sysemu_ops->write_elf64_note) {
133         return -1;
134     }
135     return (*cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
136 }
137 
138 bool cpu_virtio_is_big_endian(CPUState *cpu)
139 {
140     CPUClass *cc = CPU_GET_CLASS(cpu);
141 
142     if (cc->sysemu_ops->virtio_is_big_endian) {
143         return cc->sysemu_ops->virtio_is_big_endian(cpu);
144     }
145     return target_words_bigendian();
146 }
147 
148 GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
149 {
150     CPUClass *cc = CPU_GET_CLASS(cpu);
151     GuestPanicInformation *res = NULL;
152 
153     if (cc->sysemu_ops->get_crash_info) {
154         res = cc->sysemu_ops->get_crash_info(cpu);
155     }
156     return res;
157 }
158 
159 static const Property cpu_system_props[] = {
160     /*
161      * Create a memory property for system CPU object, so users can
162      * wire up its memory.  The default if no link is set up is to use
163      * the system address space.
164      */
165     DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
166                      MemoryRegion *),
167 };
168 
169 static bool cpu_get_start_powered_off(Object *obj, Error **errp)
170 {
171     CPUState *cpu = CPU(obj);
172     return cpu->start_powered_off;
173 }
174 
175 static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
176 {
177     CPUState *cpu = CPU(obj);
178     cpu->start_powered_off = value;
179 }
180 
181 void cpu_class_init_props(DeviceClass *dc)
182 {
183     ObjectClass *oc = OBJECT_CLASS(dc);
184 
185     /*
186      * We can't use DEFINE_PROP_BOOL in the Property array for this
187      * property, because we want this to be settable after realize.
188      */
189     object_class_property_add_bool(oc, "start-powered-off",
190                                    cpu_get_start_powered_off,
191                                    cpu_set_start_powered_off);
192 
193     device_class_set_props(dc, cpu_system_props);
194 }
195 
196 void cpu_exec_initfn(CPUState *cpu)
197 {
198     cpu->memory = get_system_memory();
199     object_ref(OBJECT(cpu->memory));
200 }
201 
202 static int cpu_common_post_load(void *opaque, int version_id)
203 {
204     if (tcg_enabled()) {
205         CPUState *cpu = opaque;
206 
207         /*
208          * 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
209          * version_id is increased.
210          */
211         cpu->interrupt_request &= ~0x01;
212 
213         tlb_flush(cpu);
214 
215         /*
216          * loadvm has just updated the content of RAM, bypassing the
217          * usual mechanisms that ensure we flush TBs for writes to
218          * memory we've translated code from. So we must flush all TBs,
219          * which will now be stale.
220          */
221         tb_flush(cpu);
222     }
223 
224     return 0;
225 }
226 
227 static int cpu_common_pre_load(void *opaque)
228 {
229     CPUState *cpu = opaque;
230 
231     cpu->exception_index = -1;
232 
233     return 0;
234 }
235 
236 static bool cpu_common_exception_index_needed(void *opaque)
237 {
238     CPUState *cpu = opaque;
239 
240     return tcg_enabled() && cpu->exception_index != -1;
241 }
242 
243 static const VMStateDescription vmstate_cpu_common_exception_index = {
244     .name = "cpu_common/exception_index",
245     .version_id = 1,
246     .minimum_version_id = 1,
247     .needed = cpu_common_exception_index_needed,
248     .fields = (const VMStateField[]) {
249         VMSTATE_INT32(exception_index, CPUState),
250         VMSTATE_END_OF_LIST()
251     }
252 };
253 
254 static bool cpu_common_crash_occurred_needed(void *opaque)
255 {
256     CPUState *cpu = opaque;
257 
258     return cpu->crash_occurred;
259 }
260 
261 static const VMStateDescription vmstate_cpu_common_crash_occurred = {
262     .name = "cpu_common/crash_occurred",
263     .version_id = 1,
264     .minimum_version_id = 1,
265     .needed = cpu_common_crash_occurred_needed,
266     .fields = (const VMStateField[]) {
267         VMSTATE_BOOL(crash_occurred, CPUState),
268         VMSTATE_END_OF_LIST()
269     }
270 };
271 
272 const VMStateDescription vmstate_cpu_common = {
273     .name = "cpu_common",
274     .version_id = 1,
275     .minimum_version_id = 1,
276     .pre_load = cpu_common_pre_load,
277     .post_load = cpu_common_post_load,
278     .fields = (const VMStateField[]) {
279         VMSTATE_UINT32(halted, CPUState),
280         VMSTATE_UINT32(interrupt_request, CPUState),
281         VMSTATE_END_OF_LIST()
282     },
283     .subsections = (const VMStateDescription * const []) {
284         &vmstate_cpu_common_exception_index,
285         &vmstate_cpu_common_crash_occurred,
286         NULL
287     }
288 };
289 
290 void cpu_vmstate_register(CPUState *cpu)
291 {
292     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
293         vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
294     }
295     if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
296         vmstate_register(NULL, cpu->cpu_index,
297                          cpu->cc->sysemu_ops->legacy_vmsd, cpu);
298     }
299 }
300 
301 void cpu_vmstate_unregister(CPUState *cpu)
302 {
303     CPUClass *cc = CPU_GET_CLASS(cpu);
304 
305     if (cc->sysemu_ops->legacy_vmsd != NULL) {
306         vmstate_unregister(NULL, cc->sysemu_ops->legacy_vmsd, cpu);
307     }
308     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
309         vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
310     }
311 }
312