1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * QEMU LoongArch CPU 4 * 5 * Copyright (c) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/log.h" 10 #include "qemu/qemu-print.h" 11 #include "qapi/error.h" 12 #include "qemu/module.h" 13 #include "sysemu/qtest.h" 14 #include "exec/exec-all.h" 15 #include "qapi/qapi-commands-machine-target.h" 16 #include "cpu.h" 17 #include "internals.h" 18 #include "fpu/softfloat-helpers.h" 19 20 const char * const regnames[32] = { 21 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 22 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 23 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 24 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 25 }; 26 27 const char * const fregnames[32] = { 28 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 29 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", 30 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", 31 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", 32 }; 33 34 static const char * const excp_names[] = { 35 [EXCCODE_INT] = "Interrupt", 36 [EXCCODE_PIL] = "Page invalid exception for load", 37 [EXCCODE_PIS] = "Page invalid exception for store", 38 [EXCCODE_PIF] = "Page invalid exception for fetch", 39 [EXCCODE_PME] = "Page modified exception", 40 [EXCCODE_PNR] = "Page Not Readable exception", 41 [EXCCODE_PNX] = "Page Not Executable exception", 42 [EXCCODE_PPI] = "Page Privilege error", 43 [EXCCODE_ADEF] = "Address error for instruction fetch", 44 [EXCCODE_ADEM] = "Address error for Memory access", 45 [EXCCODE_SYS] = "Syscall", 46 [EXCCODE_BRK] = "Break", 47 [EXCCODE_INE] = "Instruction Non-Existent", 48 [EXCCODE_IPE] = "Instruction privilege error", 49 [EXCCODE_FPE] = "Floating Point Exception", 50 [EXCCODE_DBP] = "Debug breakpoint", 51 }; 52 53 const char *loongarch_exception_name(int32_t exception) 54 { 55 assert(excp_names[exception]); 56 return excp_names[exception]; 57 } 58 59 void G_NORETURN do_raise_exception(CPULoongArchState *env, 60 uint32_t exception, 61 uintptr_t pc) 62 { 63 CPUState *cs = env_cpu(env); 64 65 qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n", 66 __func__, 67 exception, 68 loongarch_exception_name(exception)); 69 cs->exception_index = exception; 70 71 cpu_loop_exit_restore(cs, pc); 72 } 73 74 static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) 75 { 76 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 77 CPULoongArchState *env = &cpu->env; 78 79 env->pc = value; 80 } 81 82 #ifdef CONFIG_TCG 83 static void loongarch_cpu_synchronize_from_tb(CPUState *cs, 84 const TranslationBlock *tb) 85 { 86 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 87 CPULoongArchState *env = &cpu->env; 88 89 env->pc = tb->pc; 90 } 91 #endif /* CONFIG_TCG */ 92 93 static void loongarch_la464_initfn(Object *obj) 94 { 95 LoongArchCPU *cpu = LOONGARCH_CPU(obj); 96 CPULoongArchState *env = &cpu->env; 97 int i; 98 99 for (i = 0; i < 21; i++) { 100 env->cpucfg[i] = 0x0; 101 } 102 103 env->cpucfg[0] = 0x14c010; /* PRID */ 104 105 uint32_t data = 0; 106 data = FIELD_DP32(data, CPUCFG1, ARCH, 2); 107 data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); 108 data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); 109 data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f); 110 data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f); 111 data = FIELD_DP32(data, CPUCFG1, UAL, 1); 112 data = FIELD_DP32(data, CPUCFG1, RI, 1); 113 data = FIELD_DP32(data, CPUCFG1, EP, 1); 114 data = FIELD_DP32(data, CPUCFG1, RPLV, 1); 115 data = FIELD_DP32(data, CPUCFG1, HP, 1); 116 data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); 117 env->cpucfg[1] = data; 118 119 data = 0; 120 data = FIELD_DP32(data, CPUCFG2, FP, 1); 121 data = FIELD_DP32(data, CPUCFG2, FP_SP, 1); 122 data = FIELD_DP32(data, CPUCFG2, FP_DP, 1); 123 data = FIELD_DP32(data, CPUCFG2, FP_VER, 1); 124 data = FIELD_DP32(data, CPUCFG2, LLFTP, 1); 125 data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1); 126 data = FIELD_DP32(data, CPUCFG2, LAM, 1); 127 env->cpucfg[2] = data; 128 129 env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */ 130 131 data = 0; 132 data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1); 133 data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); 134 env->cpucfg[5] = data; 135 136 data = 0; 137 data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); 138 data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); 139 data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1); 140 data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1); 141 data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1); 142 data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1); 143 data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1); 144 data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1); 145 env->cpucfg[16] = data; 146 147 data = 0; 148 data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3); 149 data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8); 150 data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6); 151 env->cpucfg[17] = data; 152 153 data = 0; 154 data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3); 155 data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8); 156 data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6); 157 env->cpucfg[18] = data; 158 159 data = 0; 160 data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15); 161 data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8); 162 data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6); 163 env->cpucfg[19] = data; 164 165 data = 0; 166 data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15); 167 data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14); 168 data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6); 169 env->cpucfg[20] = data; 170 } 171 172 static void loongarch_cpu_list_entry(gpointer data, gpointer user_data) 173 { 174 const char *typename = object_class_get_name(OBJECT_CLASS(data)); 175 176 qemu_printf("%s\n", typename); 177 } 178 179 void loongarch_cpu_list(void) 180 { 181 GSList *list; 182 list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false); 183 g_slist_foreach(list, loongarch_cpu_list_entry, NULL); 184 g_slist_free(list); 185 } 186 187 static void loongarch_cpu_reset(DeviceState *dev) 188 { 189 CPUState *cs = CPU(dev); 190 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 191 LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu); 192 CPULoongArchState *env = &cpu->env; 193 194 lacc->parent_reset(dev); 195 196 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; 197 env->fcsr0 = 0x0; 198 199 restore_fp_status(env); 200 cs->exception_index = -1; 201 } 202 203 static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) 204 { 205 info->print_insn = print_insn_loongarch; 206 } 207 208 static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) 209 { 210 CPUState *cs = CPU(dev); 211 LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev); 212 Error *local_err = NULL; 213 214 cpu_exec_realizefn(cs, &local_err); 215 if (local_err != NULL) { 216 error_propagate(errp, local_err); 217 return; 218 } 219 220 cpu_reset(cs); 221 qemu_init_vcpu(cs); 222 223 lacc->parent_realize(dev, errp); 224 } 225 226 static void loongarch_cpu_init(Object *obj) 227 { 228 LoongArchCPU *cpu = LOONGARCH_CPU(obj); 229 230 cpu_set_cpustate_pointers(cpu); 231 } 232 233 static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) 234 { 235 ObjectClass *oc; 236 char *typename; 237 238 typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); 239 oc = object_class_by_name(typename); 240 g_free(typename); 241 return oc; 242 } 243 244 void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) 245 { 246 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 247 CPULoongArchState *env = &cpu->env; 248 int i; 249 250 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); 251 qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, 252 get_float_exception_flags(&env->fp_status)); 253 254 /* gpr */ 255 for (i = 0; i < 32; i++) { 256 if ((i & 3) == 0) { 257 qemu_fprintf(f, " GPR%02d:", i); 258 } 259 qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]); 260 if ((i & 3) == 3) { 261 qemu_fprintf(f, "\n"); 262 } 263 } 264 265 /* fpr */ 266 if (flags & CPU_DUMP_FPU) { 267 for (i = 0; i < 32; i++) { 268 qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]); 269 if ((i & 3) == 3) { 270 qemu_fprintf(f, "\n"); 271 } 272 } 273 } 274 } 275 276 #ifdef CONFIG_TCG 277 #include "hw/core/tcg-cpu-ops.h" 278 279 static struct TCGCPUOps loongarch_tcg_ops = { 280 .initialize = loongarch_translate_init, 281 .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, 282 }; 283 #endif /* CONFIG_TCG */ 284 285 static void loongarch_cpu_class_init(ObjectClass *c, void *data) 286 { 287 LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); 288 CPUClass *cc = CPU_CLASS(c); 289 DeviceClass *dc = DEVICE_CLASS(c); 290 291 device_class_set_parent_realize(dc, loongarch_cpu_realizefn, 292 &lacc->parent_realize); 293 device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset); 294 295 cc->class_by_name = loongarch_cpu_class_by_name; 296 cc->dump_state = loongarch_cpu_dump_state; 297 cc->set_pc = loongarch_cpu_set_pc; 298 cc->disas_set_info = loongarch_cpu_disas_set_info; 299 #ifdef CONFIG_TCG 300 cc->tcg_ops = &loongarch_tcg_ops; 301 #endif 302 } 303 304 #define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \ 305 { \ 306 .parent = TYPE_LOONGARCH_CPU, \ 307 .instance_init = initfn, \ 308 .name = LOONGARCH_CPU_TYPE_NAME(model), \ 309 } 310 311 static const TypeInfo loongarch_cpu_type_infos[] = { 312 { 313 .name = TYPE_LOONGARCH_CPU, 314 .parent = TYPE_CPU, 315 .instance_size = sizeof(LoongArchCPU), 316 .instance_init = loongarch_cpu_init, 317 318 .abstract = true, 319 .class_size = sizeof(LoongArchCPUClass), 320 .class_init = loongarch_cpu_class_init, 321 }, 322 DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn), 323 }; 324 325 DEFINE_TYPES(loongarch_cpu_type_infos) 326