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