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