xref: /openbmc/qemu/hw/core/cpu-system.c (revision 48d7b47cd76b986ad360b6ba1b0889186416f1c2)
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 "system/address-spaces.h"
24 #include "exec/cputlb.h"
25 #include "system/memory.h"
26 #include "qemu/target-info.h"
27 #include "hw/qdev-core.h"
28 #include "hw/qdev-properties.h"
29 #include "hw/core/sysemu-cpu-ops.h"
30 #include "migration/vmstate.h"
31 #include "system/tcg.h"
32 
33 bool cpu_has_work(CPUState *cpu)
34 {
35     return cpu->cc->sysemu_ops->has_work(cpu);
36 }
37 
38 bool cpu_paging_enabled(const CPUState *cpu)
39 {
40     if (cpu->cc->sysemu_ops->get_paging_enabled) {
41         return cpu->cc->sysemu_ops->get_paging_enabled(cpu);
42     }
43 
44     return false;
45 }
46 
47 bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
48                             Error **errp)
49 {
50     if (cpu->cc->sysemu_ops->get_memory_mapping) {
51         return cpu->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     hwaddr paddr;
62 
63     if (cpu->cc->sysemu_ops->get_phys_page_attrs_debug) {
64         paddr = cpu->cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr,
65                                                                attrs);
66     } else {
67         /* Fallback for CPUs which don't implement the _attrs_ hook */
68         *attrs = MEMTXATTRS_UNSPECIFIED;
69         paddr = cpu->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     if (!cpu->cc->sysemu_ops->write_elf32_qemunote) {
98         return 0;
99     }
100     return (*cpu->cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
101 }
102 
103 int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
104                          int cpuid, void *opaque)
105 {
106     if (!cpu->cc->sysemu_ops->write_elf32_note) {
107         return -1;
108     }
109     return (*cpu->cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
110 }
111 
112 int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
113                              void *opaque)
114 {
115     if (!cpu->cc->sysemu_ops->write_elf64_qemunote) {
116         return 0;
117     }
118     return (*cpu->cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
119 }
120 
121 int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
122                          int cpuid, void *opaque)
123 {
124     if (!cpu->cc->sysemu_ops->write_elf64_note) {
125         return -1;
126     }
127     return (*cpu->cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
128 }
129 
130 bool cpu_virtio_is_big_endian(CPUState *cpu)
131 {
132     if (cpu->cc->sysemu_ops->virtio_is_big_endian) {
133         return cpu->cc->sysemu_ops->virtio_is_big_endian(cpu);
134     }
135     return target_big_endian();
136 }
137 
138 GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
139 {
140     GuestPanicInformation *res = NULL;
141 
142     if (cpu->cc->sysemu_ops->get_crash_info) {
143         res = cpu->cc->sysemu_ops->get_crash_info(cpu);
144     }
145     return res;
146 }
147 
148 static const Property cpu_system_props[] = {
149     /*
150      * Create a memory property for system CPU object, so users can
151      * wire up its memory.  The default if no link is set up is to use
152      * the system address space.
153      */
154     DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
155                      MemoryRegion *),
156 };
157 
158 static bool cpu_get_start_powered_off(Object *obj, Error **errp)
159 {
160     CPUState *cpu = CPU(obj);
161     return cpu->start_powered_off;
162 }
163 
164 static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
165 {
166     CPUState *cpu = CPU(obj);
167     cpu->start_powered_off = value;
168 }
169 
170 void cpu_class_init_props(DeviceClass *dc)
171 {
172     ObjectClass *oc = OBJECT_CLASS(dc);
173 
174     /*
175      * We can't use DEFINE_PROP_BOOL in the Property array for this
176      * property, because we want this to be settable after realize.
177      */
178     object_class_property_add_bool(oc, "start-powered-off",
179                                    cpu_get_start_powered_off,
180                                    cpu_set_start_powered_off);
181 
182     device_class_set_props(dc, cpu_system_props);
183 }
184 
185 void cpu_exec_class_post_init(CPUClass *cc)
186 {
187     /* Check mandatory SysemuCPUOps handlers */
188     g_assert(cc->sysemu_ops->has_work);
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_reset_interrupt(cpu, 0x01);
207 
208         tlb_flush(cpu);
209     }
210 
211     return 0;
212 }
213 
214 static int cpu_common_pre_load(void *opaque)
215 {
216     CPUState *cpu = opaque;
217 
218     cpu->exception_index = -1;
219 
220     return 0;
221 }
222 
223 static bool cpu_common_exception_index_needed(void *opaque)
224 {
225     CPUState *cpu = opaque;
226 
227     return tcg_enabled() && cpu->exception_index != -1;
228 }
229 
230 static const VMStateDescription vmstate_cpu_common_exception_index = {
231     .name = "cpu_common/exception_index",
232     .version_id = 1,
233     .minimum_version_id = 1,
234     .needed = cpu_common_exception_index_needed,
235     .fields = (const VMStateField[]) {
236         VMSTATE_INT32(exception_index, CPUState),
237         VMSTATE_END_OF_LIST()
238     }
239 };
240 
241 static bool cpu_common_crash_occurred_needed(void *opaque)
242 {
243     CPUState *cpu = opaque;
244 
245     return cpu->crash_occurred;
246 }
247 
248 static const VMStateDescription vmstate_cpu_common_crash_occurred = {
249     .name = "cpu_common/crash_occurred",
250     .version_id = 1,
251     .minimum_version_id = 1,
252     .needed = cpu_common_crash_occurred_needed,
253     .fields = (const VMStateField[]) {
254         VMSTATE_BOOL(crash_occurred, CPUState),
255         VMSTATE_END_OF_LIST()
256     }
257 };
258 
259 const VMStateDescription vmstate_cpu_common = {
260     .name = "cpu_common",
261     .version_id = 1,
262     .minimum_version_id = 1,
263     .pre_load = cpu_common_pre_load,
264     .post_load = cpu_common_post_load,
265     .fields = (const VMStateField[]) {
266         VMSTATE_UINT32(halted, CPUState),
267         VMSTATE_UINT32(interrupt_request, CPUState),
268         VMSTATE_END_OF_LIST()
269     },
270     .subsections = (const VMStateDescription * const []) {
271         &vmstate_cpu_common_exception_index,
272         &vmstate_cpu_common_crash_occurred,
273         NULL
274     }
275 };
276 
277 void cpu_vmstate_register(CPUState *cpu)
278 {
279     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
280         vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
281     }
282     if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
283         vmstate_register(NULL, cpu->cpu_index,
284                          cpu->cc->sysemu_ops->legacy_vmsd, cpu);
285     }
286 }
287 
288 void cpu_vmstate_unregister(CPUState *cpu)
289 {
290     if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
291         vmstate_unregister(NULL, cpu->cc->sysemu_ops->legacy_vmsd, cpu);
292     }
293     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
294         vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
295     }
296 }
297