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