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