1 /* 2 * QEMU Xtensa CPU 3 * 4 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 5 * Copyright (c) 2012 SUSE LINUX Products GmbH 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * * Neither the name of the Open Source and Linux Lab nor the 16 * names of its contributors may be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "qemu/osdep.h" 32 #include "qapi/error.h" 33 #include "cpu.h" 34 #include "fpu/softfloat.h" 35 #include "qemu/module.h" 36 #include "migration/vmstate.h" 37 #include "hw/qdev-clock.h" 38 39 40 static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) 41 { 42 XtensaCPU *cpu = XTENSA_CPU(cs); 43 44 cpu->env.pc = value; 45 } 46 47 static vaddr xtensa_cpu_get_pc(CPUState *cs) 48 { 49 XtensaCPU *cpu = XTENSA_CPU(cs); 50 51 return cpu->env.pc; 52 } 53 54 static bool xtensa_cpu_has_work(CPUState *cs) 55 { 56 #ifndef CONFIG_USER_ONLY 57 XtensaCPU *cpu = XTENSA_CPU(cs); 58 59 return !cpu->env.runstall && cpu->env.pending_irq_level; 60 #else 61 return true; 62 #endif 63 } 64 65 #ifdef CONFIG_USER_ONLY 66 static bool abi_call0; 67 68 void xtensa_set_abi_call0(void) 69 { 70 abi_call0 = true; 71 } 72 73 bool xtensa_abi_call0(void) 74 { 75 return abi_call0; 76 } 77 #endif 78 79 static void xtensa_cpu_reset(DeviceState *dev) 80 { 81 CPUState *s = CPU(dev); 82 XtensaCPU *cpu = XTENSA_CPU(s); 83 XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu); 84 CPUXtensaState *env = &cpu->env; 85 bool dfpu = xtensa_option_enabled(env->config, 86 XTENSA_OPTION_DFP_COPROCESSOR); 87 88 xcc->parent_reset(dev); 89 90 env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors]; 91 env->sregs[LITBASE] &= ~1; 92 #ifndef CONFIG_USER_ONLY 93 env->sregs[PS] = xtensa_option_enabled(env->config, 94 XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; 95 env->pending_irq_level = 0; 96 #else 97 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 98 if (xtensa_option_enabled(env->config, 99 XTENSA_OPTION_WINDOWED_REGISTER) && 100 !xtensa_abi_call0()) { 101 env->sregs[PS] |= PS_WOE; 102 } 103 env->sregs[CPENABLE] = 0xff; 104 #endif 105 env->sregs[VECBASE] = env->config->vecbase; 106 env->sregs[IBREAKENABLE] = 0; 107 env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask; 108 env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, 109 XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; 110 env->sregs[CONFIGID0] = env->config->configid[0]; 111 env->sregs[CONFIGID1] = env->config->configid[1]; 112 env->exclusive_addr = -1; 113 114 #ifndef CONFIG_USER_ONLY 115 reset_mmu(env); 116 s->halted = env->runstall; 117 #endif 118 set_no_signaling_nans(!dfpu, &env->fp_status); 119 set_use_first_nan(!dfpu, &env->fp_status); 120 } 121 122 static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) 123 { 124 ObjectClass *oc; 125 char *typename; 126 127 typename = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), cpu_model); 128 oc = object_class_by_name(typename); 129 g_free(typename); 130 if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) || 131 object_class_is_abstract(oc)) { 132 return NULL; 133 } 134 return oc; 135 } 136 137 static void xtensa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) 138 { 139 XtensaCPU *cpu = XTENSA_CPU(cs); 140 141 info->private_data = cpu->env.config->isa; 142 info->print_insn = print_insn_xtensa; 143 } 144 145 static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) 146 { 147 CPUState *cs = CPU(dev); 148 XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); 149 Error *local_err = NULL; 150 151 #ifndef CONFIG_USER_ONLY 152 xtensa_irq_init(&XTENSA_CPU(dev)->env); 153 #endif 154 155 cpu_exec_realizefn(cs, &local_err); 156 if (local_err != NULL) { 157 error_propagate(errp, local_err); 158 return; 159 } 160 161 cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; 162 163 qemu_init_vcpu(cs); 164 165 xcc->parent_realize(dev, errp); 166 } 167 168 static void xtensa_cpu_initfn(Object *obj) 169 { 170 XtensaCPU *cpu = XTENSA_CPU(obj); 171 XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj); 172 CPUXtensaState *env = &cpu->env; 173 174 cpu_set_cpustate_pointers(cpu); 175 env->config = xcc->config; 176 177 #ifndef CONFIG_USER_ONLY 178 env->address_space_er = g_malloc(sizeof(*env->address_space_er)); 179 env->system_er = g_malloc(sizeof(*env->system_er)); 180 memory_region_init_io(env->system_er, obj, NULL, env, "er", 181 UINT64_C(0x100000000)); 182 address_space_init(env->address_space_er, env->system_er, "ER"); 183 184 cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); 185 clock_set_hz(cpu->clock, env->config->clock_freq_khz * 1000); 186 #endif 187 } 188 189 XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) 190 { 191 DeviceState *cpu; 192 193 cpu = DEVICE(object_new(cpu_type)); 194 qdev_connect_clock_in(cpu, "clk-in", cpu_refclk); 195 qdev_realize(cpu, NULL, &error_abort); 196 197 return XTENSA_CPU(cpu); 198 } 199 200 #ifndef CONFIG_USER_ONLY 201 static const VMStateDescription vmstate_xtensa_cpu = { 202 .name = "cpu", 203 .unmigratable = 1, 204 }; 205 206 #include "hw/core/sysemu-cpu-ops.h" 207 208 static const struct SysemuCPUOps xtensa_sysemu_ops = { 209 .get_phys_page_debug = xtensa_cpu_get_phys_page_debug, 210 }; 211 #endif 212 213 #include "hw/core/tcg-cpu-ops.h" 214 215 static const struct TCGCPUOps xtensa_tcg_ops = { 216 .initialize = xtensa_translate_init, 217 .debug_excp_handler = xtensa_breakpoint_handler, 218 219 #ifndef CONFIG_USER_ONLY 220 .tlb_fill = xtensa_cpu_tlb_fill, 221 .cpu_exec_interrupt = xtensa_cpu_exec_interrupt, 222 .do_interrupt = xtensa_cpu_do_interrupt, 223 .do_transaction_failed = xtensa_cpu_do_transaction_failed, 224 .do_unaligned_access = xtensa_cpu_do_unaligned_access, 225 #endif /* !CONFIG_USER_ONLY */ 226 }; 227 228 static void xtensa_cpu_class_init(ObjectClass *oc, void *data) 229 { 230 DeviceClass *dc = DEVICE_CLASS(oc); 231 CPUClass *cc = CPU_CLASS(oc); 232 XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); 233 234 device_class_set_parent_realize(dc, xtensa_cpu_realizefn, 235 &xcc->parent_realize); 236 237 device_class_set_parent_reset(dc, xtensa_cpu_reset, &xcc->parent_reset); 238 239 cc->class_by_name = xtensa_cpu_class_by_name; 240 cc->has_work = xtensa_cpu_has_work; 241 cc->dump_state = xtensa_cpu_dump_state; 242 cc->set_pc = xtensa_cpu_set_pc; 243 cc->get_pc = xtensa_cpu_get_pc; 244 cc->gdb_read_register = xtensa_cpu_gdb_read_register; 245 cc->gdb_write_register = xtensa_cpu_gdb_write_register; 246 cc->gdb_stop_before_watchpoint = true; 247 #ifndef CONFIG_USER_ONLY 248 cc->sysemu_ops = &xtensa_sysemu_ops; 249 dc->vmsd = &vmstate_xtensa_cpu; 250 #endif 251 cc->disas_set_info = xtensa_cpu_disas_set_info; 252 cc->tcg_ops = &xtensa_tcg_ops; 253 } 254 255 static const TypeInfo xtensa_cpu_type_info = { 256 .name = TYPE_XTENSA_CPU, 257 .parent = TYPE_CPU, 258 .instance_size = sizeof(XtensaCPU), 259 .instance_init = xtensa_cpu_initfn, 260 .abstract = true, 261 .class_size = sizeof(XtensaCPUClass), 262 .class_init = xtensa_cpu_class_init, 263 }; 264 265 static void xtensa_cpu_register_types(void) 266 { 267 type_register_static(&xtensa_cpu_type_info); 268 } 269 270 type_init(xtensa_cpu_register_types) 271