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