qemu/target/loongarch/cpu.c
<<
>>
Prefs
   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#include "cpu-csr.h"
  20#include "sysemu/reset.h"
  21
  22const char * const regnames[32] = {
  23    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  24    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
  25    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
  26    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
  27};
  28
  29const char * const fregnames[32] = {
  30    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
  31    "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
  32    "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
  33    "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
  34};
  35
  36static const char * const excp_names[] = {
  37    [EXCCODE_INT] = "Interrupt",
  38    [EXCCODE_PIL] = "Page invalid exception for load",
  39    [EXCCODE_PIS] = "Page invalid exception for store",
  40    [EXCCODE_PIF] = "Page invalid exception for fetch",
  41    [EXCCODE_PME] = "Page modified exception",
  42    [EXCCODE_PNR] = "Page Not Readable exception",
  43    [EXCCODE_PNX] = "Page Not Executable exception",
  44    [EXCCODE_PPI] = "Page Privilege error",
  45    [EXCCODE_ADEF] = "Address error for instruction fetch",
  46    [EXCCODE_ADEM] = "Address error for Memory access",
  47    [EXCCODE_SYS] = "Syscall",
  48    [EXCCODE_BRK] = "Break",
  49    [EXCCODE_INE] = "Instruction Non-Existent",
  50    [EXCCODE_IPE] = "Instruction privilege error",
  51    [EXCCODE_FPE] = "Floating Point Exception",
  52    [EXCCODE_DBP] = "Debug breakpoint",
  53    [EXCCODE_BCE] = "Bound Check Exception",
  54};
  55
  56const char *loongarch_exception_name(int32_t exception)
  57{
  58    assert(excp_names[exception]);
  59    return excp_names[exception];
  60}
  61
  62void G_NORETURN do_raise_exception(CPULoongArchState *env,
  63                                   uint32_t exception,
  64                                   uintptr_t pc)
  65{
  66    CPUState *cs = env_cpu(env);
  67
  68    qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
  69                  __func__,
  70                  exception,
  71                  loongarch_exception_name(exception));
  72    cs->exception_index = exception;
  73
  74    cpu_loop_exit_restore(cs, pc);
  75}
  76
  77static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
  78{
  79    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
  80    CPULoongArchState *env = &cpu->env;
  81
  82    env->pc = value;
  83}
  84
  85#ifndef CONFIG_USER_ONLY
  86#include "hw/loongarch/virt.h"
  87
  88void loongarch_cpu_set_irq(void *opaque, int irq, int level)
  89{
  90    LoongArchCPU *cpu = opaque;
  91    CPULoongArchState *env = &cpu->env;
  92    CPUState *cs = CPU(cpu);
  93
  94    if (irq < 0 || irq >= N_IRQS) {
  95        return;
  96    }
  97
  98    env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0);
  99
 100    if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
 101        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 102    } else {
 103        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 104    }
 105}
 106
 107static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
 108{
 109    bool ret = 0;
 110
 111    ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) &&
 112          !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)));
 113
 114    return ret;
 115}
 116
 117/* Check if there is pending and not masked out interrupt */
 118static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
 119{
 120    uint32_t pending;
 121    uint32_t status;
 122    bool r;
 123
 124    pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
 125    status  = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
 126
 127    r = (pending & status) != 0;
 128    return r;
 129}
 130
 131static void loongarch_cpu_do_interrupt(CPUState *cs)
 132{
 133    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 134    CPULoongArchState *env = &cpu->env;
 135    bool update_badinstr = 1;
 136    int cause = -1;
 137    const char *name;
 138    bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
 139    uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
 140
 141    if (cs->exception_index != EXCCODE_INT) {
 142        if (cs->exception_index < 0 ||
 143            cs->exception_index >= ARRAY_SIZE(excp_names)) {
 144            name = "unknown";
 145        } else {
 146            name = excp_names[cs->exception_index];
 147        }
 148
 149        qemu_log_mask(CPU_LOG_INT,
 150                     "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
 151                     " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
 152                     env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
 153    }
 154
 155    switch (cs->exception_index) {
 156    case EXCCODE_DBP:
 157        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1);
 158        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC);
 159        goto set_DERA;
 160    set_DERA:
 161        env->CSR_DERA = env->pc;
 162        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1);
 163        env->pc = env->CSR_EENTRY + 0x480;
 164        break;
 165    case EXCCODE_INT:
 166        if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) {
 167            env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1);
 168            goto set_DERA;
 169        }
 170        QEMU_FALLTHROUGH;
 171    case EXCCODE_PIF:
 172        cause = cs->exception_index;
 173        update_badinstr = 0;
 174        break;
 175    case EXCCODE_SYS:
 176    case EXCCODE_BRK:
 177    case EXCCODE_INE:
 178    case EXCCODE_IPE:
 179    case EXCCODE_FPE:
 180    case EXCCODE_BCE:
 181        env->CSR_BADV = env->pc;
 182        QEMU_FALLTHROUGH;
 183    case EXCCODE_ADEM:
 184    case EXCCODE_PIL:
 185    case EXCCODE_PIS:
 186    case EXCCODE_PME:
 187    case EXCCODE_PNR:
 188    case EXCCODE_PNX:
 189    case EXCCODE_PPI:
 190        cause = cs->exception_index;
 191        break;
 192    default:
 193        qemu_log("Error: exception(%d) has not been supported\n",
 194                 cs->exception_index);
 195        abort();
 196    }
 197
 198    if (update_badinstr) {
 199        env->CSR_BADI = cpu_ldl_code(env, env->pc);
 200    }
 201
 202    /* Save PLV and IE */
 203    if (tlbfill) {
 204        env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV,
 205                                       FIELD_EX64(env->CSR_CRMD,
 206                                       CSR_CRMD, PLV));
 207        env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE,
 208                                       FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
 209        /* set the DA mode */
 210        env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
 211        env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
 212        env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA,
 213                                      PC, (env->pc >> 2));
 214    } else {
 215        env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, cause);
 216        env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV,
 217                                   FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV));
 218        env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE,
 219                                   FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
 220        env->CSR_ERA = env->pc;
 221    }
 222
 223    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
 224    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
 225
 226    if (vec_size) {
 227        vec_size = (1 << vec_size) * 4;
 228    }
 229
 230    if  (cs->exception_index == EXCCODE_INT) {
 231        /* Interrupt */
 232        uint32_t vector = 0;
 233        uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
 234        pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
 235
 236        /* Find the highest-priority interrupt. */
 237        vector = 31 - clz32(pending);
 238        env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size;
 239        qemu_log_mask(CPU_LOG_INT,
 240                      "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
 241                      " cause %d\n" "    A " TARGET_FMT_lx " D "
 242                      TARGET_FMT_lx " vector = %d ExC " TARGET_FMT_lx "ExS"
 243                      TARGET_FMT_lx "\n",
 244                      __func__, env->pc, env->CSR_ERA,
 245                      cause, env->CSR_BADV, env->CSR_DERA, vector,
 246                      env->CSR_ECFG, env->CSR_ESTAT);
 247    } else {
 248        if (tlbfill) {
 249            env->pc = env->CSR_TLBRENTRY;
 250        } else {
 251            env->pc = env->CSR_EENTRY;
 252            env->pc += cause * vec_size;
 253        }
 254        qemu_log_mask(CPU_LOG_INT,
 255                      "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
 256                      " cause %d%s\n, ESTAT " TARGET_FMT_lx
 257                      " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx
 258                      "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu
 259                      " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->pc,
 260                      tlbfill ? env->CSR_TLBRERA : env->CSR_ERA,
 261                      cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT,
 262                      env->CSR_ECFG,
 263                      tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
 264                      env->CSR_BADI, env->gpr[11], cs->cpu_index,
 265                      env->CSR_ASID);
 266    }
 267    cs->exception_index = -1;
 268}
 269
 270static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
 271                                                vaddr addr, unsigned size,
 272                                                MMUAccessType access_type,
 273                                                int mmu_idx, MemTxAttrs attrs,
 274                                                MemTxResult response,
 275                                                uintptr_t retaddr)
 276{
 277    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 278    CPULoongArchState *env = &cpu->env;
 279
 280    if (access_type == MMU_INST_FETCH) {
 281        do_raise_exception(env, EXCCODE_ADEF, retaddr);
 282    } else {
 283        do_raise_exception(env, EXCCODE_ADEM, retaddr);
 284    }
 285}
 286
 287static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 288{
 289    if (interrupt_request & CPU_INTERRUPT_HARD) {
 290        LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 291        CPULoongArchState *env = &cpu->env;
 292
 293        if (cpu_loongarch_hw_interrupts_enabled(env) &&
 294            cpu_loongarch_hw_interrupts_pending(env)) {
 295            /* Raise it */
 296            cs->exception_index = EXCCODE_INT;
 297            loongarch_cpu_do_interrupt(cs);
 298            return true;
 299        }
 300    }
 301    return false;
 302}
 303#endif
 304
 305#ifdef CONFIG_TCG
 306static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
 307                                              const TranslationBlock *tb)
 308{
 309    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 310    CPULoongArchState *env = &cpu->env;
 311
 312    env->pc = tb->pc;
 313}
 314#endif /* CONFIG_TCG */
 315
 316static bool loongarch_cpu_has_work(CPUState *cs)
 317{
 318#ifdef CONFIG_USER_ONLY
 319    return true;
 320#else
 321    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 322    CPULoongArchState *env = &cpu->env;
 323    bool has_work = false;
 324
 325    if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
 326        cpu_loongarch_hw_interrupts_pending(env)) {
 327        has_work = true;
 328    }
 329
 330    return has_work;
 331#endif
 332}
 333
 334static void loongarch_la464_initfn(Object *obj)
 335{
 336    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
 337    CPULoongArchState *env = &cpu->env;
 338    int i;
 339
 340    for (i = 0; i < 21; i++) {
 341        env->cpucfg[i] = 0x0;
 342    }
 343
 344    cpu->dtb_compatible = "loongarch,Loongson-3A5000";
 345    env->cpucfg[0] = 0x14c010;  /* PRID */
 346
 347    uint32_t data = 0;
 348    data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
 349    data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
 350    data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
 351    data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f);
 352    data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f);
 353    data = FIELD_DP32(data, CPUCFG1, UAL, 1);
 354    data = FIELD_DP32(data, CPUCFG1, RI, 1);
 355    data = FIELD_DP32(data, CPUCFG1, EP, 1);
 356    data = FIELD_DP32(data, CPUCFG1, RPLV, 1);
 357    data = FIELD_DP32(data, CPUCFG1, HP, 1);
 358    data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1);
 359    env->cpucfg[1] = data;
 360
 361    data = 0;
 362    data = FIELD_DP32(data, CPUCFG2, FP, 1);
 363    data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
 364    data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
 365    data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
 366    data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
 367    data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
 368    data = FIELD_DP32(data, CPUCFG2, LAM, 1);
 369    env->cpucfg[2] = data;
 370
 371    env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
 372
 373    data = 0;
 374    data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1);
 375    data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
 376    env->cpucfg[5] = data;
 377
 378    data = 0;
 379    data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
 380    data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
 381    data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1);
 382    data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1);
 383    data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1);
 384    data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1);
 385    data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1);
 386    data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1);
 387    env->cpucfg[16] = data;
 388
 389    data = 0;
 390    data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3);
 391    data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8);
 392    data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6);
 393    env->cpucfg[17] = data;
 394
 395    data = 0;
 396    data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3);
 397    data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8);
 398    data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6);
 399    env->cpucfg[18] = data;
 400
 401    data = 0;
 402    data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15);
 403    data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8);
 404    data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6);
 405    env->cpucfg[19] = data;
 406
 407    data = 0;
 408    data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15);
 409    data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14);
 410    data = FIELD_DP32(data, CPUCFG20, L3IU_SIZE, 6);
 411    env->cpucfg[20] = data;
 412
 413    env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
 414}
 415
 416static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
 417{
 418    const char *typename = object_class_get_name(OBJECT_CLASS(data));
 419
 420    qemu_printf("%s\n", typename);
 421}
 422
 423void loongarch_cpu_list(void)
 424{
 425    GSList *list;
 426    list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false);
 427    g_slist_foreach(list, loongarch_cpu_list_entry, NULL);
 428    g_slist_free(list);
 429}
 430
 431static void loongarch_cpu_reset(DeviceState *dev)
 432{
 433    CPUState *cs = CPU(dev);
 434    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 435    LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
 436    CPULoongArchState *env = &cpu->env;
 437
 438    lacc->parent_reset(dev);
 439
 440    env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
 441    env->fcsr0 = 0x0;
 442
 443    int n;
 444    /* Set csr registers value after reset */
 445    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
 446    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
 447    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
 448    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
 449    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1);
 450    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1);
 451
 452    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0);
 453    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);
 454    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0);
 455    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0);
 456
 457    env->CSR_MISC = 0;
 458
 459    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0);
 460    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0);
 461
 462    env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2));
 463    env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0);
 464    env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
 465    env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0);
 466    env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
 467    env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);
 468
 469    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2);
 470    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63);
 471    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7);
 472    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8);
 473
 474    for (n = 0; n < 4; n++) {
 475        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
 476        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0);
 477        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0);
 478        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
 479    }
 480
 481#ifndef CONFIG_USER_ONLY
 482    env->pc = 0x1c000000;
 483    memset(env->tlb, 0, sizeof(env->tlb));
 484#endif
 485
 486    restore_fp_status(env);
 487    cs->exception_index = -1;
 488}
 489
 490static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
 491{
 492    info->print_insn = print_insn_loongarch;
 493}
 494
 495static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
 496{
 497    CPUState *cs = CPU(dev);
 498    LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
 499    Error *local_err = NULL;
 500
 501    cpu_exec_realizefn(cs, &local_err);
 502    if (local_err != NULL) {
 503        error_propagate(errp, local_err);
 504        return;
 505    }
 506
 507    loongarch_cpu_register_gdb_regs_for_features(cs);
 508
 509    cpu_reset(cs);
 510    qemu_init_vcpu(cs);
 511
 512    lacc->parent_realize(dev, errp);
 513}
 514
 515#ifndef CONFIG_USER_ONLY
 516static void loongarch_qemu_write(void *opaque, hwaddr addr,
 517                                 uint64_t val, unsigned size)
 518{
 519}
 520
 521static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
 522{
 523    switch (addr) {
 524    case FEATURE_REG:
 525        return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
 526               1ULL << IOCSRF_CSRIPI;
 527    case VENDOR_REG:
 528        return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
 529    case CPUNAME_REG:
 530        return 0x303030354133ULL;     /* "3A5000" */
 531    case MISC_FUNC_REG:
 532        return 1ULL << IOCSRM_EXTIOI_EN;
 533    }
 534    return 0ULL;
 535}
 536
 537static const MemoryRegionOps loongarch_qemu_ops = {
 538    .read = loongarch_qemu_read,
 539    .write = loongarch_qemu_write,
 540    .endianness = DEVICE_LITTLE_ENDIAN,
 541    .valid = {
 542        .min_access_size = 4,
 543        .max_access_size = 8,
 544    },
 545    .impl = {
 546        .min_access_size = 8,
 547        .max_access_size = 8,
 548    },
 549};
 550#endif
 551
 552static void loongarch_cpu_init(Object *obj)
 553{
 554    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
 555
 556    cpu_set_cpustate_pointers(cpu);
 557
 558#ifndef CONFIG_USER_ONLY
 559    CPULoongArchState *env = &cpu->env;
 560    qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
 561    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
 562                  &loongarch_constant_timer_cb, cpu);
 563    memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL,
 564                      env, "iocsr", UINT64_MAX);
 565    address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
 566    memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
 567                          NULL, "iocsr_misc", 0x428);
 568    memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
 569#endif
 570}
 571
 572static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
 573{
 574    ObjectClass *oc;
 575
 576    oc = object_class_by_name(cpu_model);
 577    if (!oc) {
 578        g_autofree char *typename 
 579            = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
 580        oc = object_class_by_name(typename);
 581        if (!oc) {
 582            return NULL;
 583        }
 584    }
 585
 586    if (object_class_dynamic_cast(oc, TYPE_LOONGARCH_CPU)
 587        && !object_class_is_abstract(oc)) {
 588        return oc;
 589    }
 590    return NULL;
 591}
 592
 593void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 594{
 595    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 596    CPULoongArchState *env = &cpu->env;
 597    int i;
 598
 599    qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
 600    qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0,
 601                 get_float_exception_flags(&env->fp_status));
 602
 603    /* gpr */
 604    for (i = 0; i < 32; i++) {
 605        if ((i & 3) == 0) {
 606            qemu_fprintf(f, " GPR%02d:", i);
 607        }
 608        qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
 609        if ((i & 3) == 3) {
 610            qemu_fprintf(f, "\n");
 611        }
 612    }
 613
 614    qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD);
 615    qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD);
 616    qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN);
 617    qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT);
 618    qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA);
 619    qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV);
 620    qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI);
 621    qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY);
 622    qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 ","
 623                 " PRCFG3=%016" PRIx64 "\n",
 624                 env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3);
 625    qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
 626    qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
 627    qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
 628
 629    /* fpr */
 630    if (flags & CPU_DUMP_FPU) {
 631        for (i = 0; i < 32; i++) {
 632            qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]);
 633            if ((i & 3) == 3) {
 634                qemu_fprintf(f, "\n");
 635            }
 636        }
 637    }
 638}
 639
 640#ifdef CONFIG_TCG
 641#include "hw/core/tcg-cpu-ops.h"
 642
 643static struct TCGCPUOps loongarch_tcg_ops = {
 644    .initialize = loongarch_translate_init,
 645    .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
 646
 647#ifndef CONFIG_USER_ONLY
 648    .tlb_fill = loongarch_cpu_tlb_fill,
 649    .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
 650    .do_interrupt = loongarch_cpu_do_interrupt,
 651    .do_transaction_failed = loongarch_cpu_do_transaction_failed,
 652#endif
 653};
 654#endif /* CONFIG_TCG */
 655
 656#ifndef CONFIG_USER_ONLY
 657#include "hw/core/sysemu-cpu-ops.h"
 658
 659static const struct SysemuCPUOps loongarch_sysemu_ops = {
 660    .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
 661};
 662#endif
 663
 664static gchar *loongarch_gdb_arch_name(CPUState *cs)
 665{
 666    return g_strdup("loongarch64");
 667}
 668
 669static void loongarch_cpu_class_init(ObjectClass *c, void *data)
 670{
 671    LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
 672    CPUClass *cc = CPU_CLASS(c);
 673    DeviceClass *dc = DEVICE_CLASS(c);
 674
 675    device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
 676                                    &lacc->parent_realize);
 677    device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
 678
 679    cc->class_by_name = loongarch_cpu_class_by_name;
 680    cc->has_work = loongarch_cpu_has_work;
 681    cc->dump_state = loongarch_cpu_dump_state;
 682    cc->set_pc = loongarch_cpu_set_pc;
 683#ifndef CONFIG_USER_ONLY
 684    dc->vmsd = &vmstate_loongarch_cpu;
 685    cc->sysemu_ops = &loongarch_sysemu_ops;
 686#endif
 687    cc->disas_set_info = loongarch_cpu_disas_set_info;
 688    cc->gdb_read_register = loongarch_cpu_gdb_read_register;
 689    cc->gdb_write_register = loongarch_cpu_gdb_write_register;
 690    cc->disas_set_info = loongarch_cpu_disas_set_info;
 691    cc->gdb_num_core_regs = 35;
 692    cc->gdb_core_xml_file = "loongarch-base64.xml";
 693    cc->gdb_stop_before_watchpoint = true;
 694    cc->gdb_arch_name = loongarch_gdb_arch_name;
 695
 696#ifdef CONFIG_TCG
 697    cc->tcg_ops = &loongarch_tcg_ops;
 698#endif
 699}
 700
 701#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \
 702    { \
 703        .parent = TYPE_LOONGARCH_CPU, \
 704        .instance_init = initfn, \
 705        .name = LOONGARCH_CPU_TYPE_NAME(model), \
 706    }
 707
 708static const TypeInfo loongarch_cpu_type_infos[] = {
 709    {
 710        .name = TYPE_LOONGARCH_CPU,
 711        .parent = TYPE_CPU,
 712        .instance_size = sizeof(LoongArchCPU),
 713        .instance_init = loongarch_cpu_init,
 714
 715        .abstract = true,
 716        .class_size = sizeof(LoongArchCPUClass),
 717        .class_init = loongarch_cpu_class_init,
 718    },
 719    DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn),
 720};
 721
 722DEFINE_TYPES(loongarch_cpu_type_infos)
 723
 724static void loongarch_cpu_add_definition(gpointer data, gpointer user_data)
 725{
 726    ObjectClass *oc = data;
 727    CpuDefinitionInfoList **cpu_list = user_data;
 728    CpuDefinitionInfo *info = g_new0(CpuDefinitionInfo, 1);
 729    const char *typename = object_class_get_name(oc);
 730
 731    info->name = g_strndup(typename,
 732                           strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU));
 733    info->q_typename = g_strdup(typename);
 734
 735    QAPI_LIST_PREPEND(*cpu_list, info);
 736}
 737
 738CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 739{
 740    CpuDefinitionInfoList *cpu_list = NULL;
 741    GSList *list;
 742
 743    list = object_class_get_list(TYPE_LOONGARCH_CPU, false);
 744    g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list);
 745    g_slist_free(list);
 746
 747    return cpu_list;
 748}
 749