qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

trans_privileged.c.inc (12374B)


      1 /* SPDX-License-Identifier: GPL-2.0-or-later */
      2 /*
      3  * Copyright (c) 2021 Loongson Technology Corporation Limited
      4  *
      5  * LoongArch translation routines for the privileged instructions.
      6  */
      7 
      8 #include "cpu-csr.h"
      9 
     10 #ifdef CONFIG_USER_ONLY
     11 
     12 #define GEN_FALSE_TRANS(name)   \
     13 static bool trans_##name(DisasContext *ctx, arg_##name * a)  \
     14 {   \
     15     return false;   \
     16 }
     17 
     18 GEN_FALSE_TRANS(csrrd)
     19 GEN_FALSE_TRANS(csrwr)
     20 GEN_FALSE_TRANS(csrxchg)
     21 GEN_FALSE_TRANS(iocsrrd_b)
     22 GEN_FALSE_TRANS(iocsrrd_h)
     23 GEN_FALSE_TRANS(iocsrrd_w)
     24 GEN_FALSE_TRANS(iocsrrd_d)
     25 GEN_FALSE_TRANS(iocsrwr_b)
     26 GEN_FALSE_TRANS(iocsrwr_h)
     27 GEN_FALSE_TRANS(iocsrwr_w)
     28 GEN_FALSE_TRANS(iocsrwr_d)
     29 GEN_FALSE_TRANS(tlbsrch)
     30 GEN_FALSE_TRANS(tlbrd)
     31 GEN_FALSE_TRANS(tlbwr)
     32 GEN_FALSE_TRANS(tlbfill)
     33 GEN_FALSE_TRANS(tlbclr)
     34 GEN_FALSE_TRANS(tlbflush)
     35 GEN_FALSE_TRANS(invtlb)
     36 GEN_FALSE_TRANS(cacop)
     37 GEN_FALSE_TRANS(ldpte)
     38 GEN_FALSE_TRANS(lddir)
     39 GEN_FALSE_TRANS(ertn)
     40 GEN_FALSE_TRANS(dbcl)
     41 GEN_FALSE_TRANS(idle)
     42 
     43 #else
     44 
     45 typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
     46 typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
     47 
     48 typedef struct {
     49     int offset;
     50     int flags;
     51     GenCSRRead readfn;
     52     GenCSRWrite writefn;
     53 } CSRInfo;
     54 
     55 enum {
     56     CSRFL_READONLY = (1 << 0),
     57     CSRFL_EXITTB   = (1 << 1),
     58     CSRFL_IO       = (1 << 2),
     59 };
     60 
     61 #define CSR_OFF_FUNCS(NAME, FL, RD, WR)                    \
     62     [LOONGARCH_CSR_##NAME] = {                             \
     63         .offset = offsetof(CPULoongArchState, CSR_##NAME), \
     64         .flags = FL, .readfn = RD, .writefn = WR           \
     65     }
     66 
     67 #define CSR_OFF_ARRAY(NAME, N)                                \
     68     [LOONGARCH_CSR_##NAME(N)] = {                             \
     69         .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \
     70         .flags = 0, .readfn = NULL, .writefn = NULL           \
     71     }
     72 
     73 #define CSR_OFF_FLAGS(NAME, FL) \
     74     CSR_OFF_FUNCS(NAME, FL, NULL, NULL)
     75 
     76 #define CSR_OFF(NAME) \
     77     CSR_OFF_FLAGS(NAME, 0)
     78 
     79 static const CSRInfo csr_info[] = {
     80     CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB),
     81     CSR_OFF(PRMD),
     82     CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB),
     83     CSR_OFF_FLAGS(MISC, CSRFL_READONLY),
     84     CSR_OFF(ECFG),
     85     CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat),
     86     CSR_OFF(ERA),
     87     CSR_OFF(BADV),
     88     CSR_OFF_FLAGS(BADI, CSRFL_READONLY),
     89     CSR_OFF(EENTRY),
     90     CSR_OFF(TLBIDX),
     91     CSR_OFF(TLBEHI),
     92     CSR_OFF(TLBELO0),
     93     CSR_OFF(TLBELO1),
     94     CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid),
     95     CSR_OFF(PGDL),
     96     CSR_OFF(PGDH),
     97     CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL),
     98     CSR_OFF(PWCL),
     99     CSR_OFF(PWCH),
    100     CSR_OFF(STLBPS),
    101     CSR_OFF(RVACFG),
    102     [LOONGARCH_CSR_CPUID] = {
    103         .offset = (int)offsetof(CPUState, cpu_index)
    104                   - (int)offsetof(LoongArchCPU, env),
    105         .flags = CSRFL_READONLY,
    106         .readfn = NULL,
    107         .writefn = NULL
    108     },
    109     CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY),
    110     CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY),
    111     CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY),
    112     CSR_OFF_ARRAY(SAVE, 0),
    113     CSR_OFF_ARRAY(SAVE, 1),
    114     CSR_OFF_ARRAY(SAVE, 2),
    115     CSR_OFF_ARRAY(SAVE, 3),
    116     CSR_OFF_ARRAY(SAVE, 4),
    117     CSR_OFF_ARRAY(SAVE, 5),
    118     CSR_OFF_ARRAY(SAVE, 6),
    119     CSR_OFF_ARRAY(SAVE, 7),
    120     CSR_OFF_ARRAY(SAVE, 8),
    121     CSR_OFF_ARRAY(SAVE, 9),
    122     CSR_OFF_ARRAY(SAVE, 10),
    123     CSR_OFF_ARRAY(SAVE, 11),
    124     CSR_OFF_ARRAY(SAVE, 12),
    125     CSR_OFF_ARRAY(SAVE, 13),
    126     CSR_OFF_ARRAY(SAVE, 14),
    127     CSR_OFF_ARRAY(SAVE, 15),
    128     CSR_OFF(TID),
    129     CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg),
    130     CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL),
    131     CSR_OFF(CNTC),
    132     CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr),
    133     CSR_OFF(LLBCTL),
    134     CSR_OFF(IMPCTL1),
    135     CSR_OFF(IMPCTL2),
    136     CSR_OFF(TLBRENTRY),
    137     CSR_OFF(TLBRBADV),
    138     CSR_OFF(TLBRERA),
    139     CSR_OFF(TLBRSAVE),
    140     CSR_OFF(TLBRELO0),
    141     CSR_OFF(TLBRELO1),
    142     CSR_OFF(TLBREHI),
    143     CSR_OFF(TLBRPRMD),
    144     CSR_OFF(MERRCTL),
    145     CSR_OFF(MERRINFO1),
    146     CSR_OFF(MERRINFO2),
    147     CSR_OFF(MERRENTRY),
    148     CSR_OFF(MERRERA),
    149     CSR_OFF(MERRSAVE),
    150     CSR_OFF(CTAG),
    151     CSR_OFF_ARRAY(DMW, 0),
    152     CSR_OFF_ARRAY(DMW, 1),
    153     CSR_OFF_ARRAY(DMW, 2),
    154     CSR_OFF_ARRAY(DMW, 3),
    155     CSR_OFF(DBG),
    156     CSR_OFF(DERA),
    157     CSR_OFF(DSAVE),
    158 };
    159 
    160 static bool check_plv(DisasContext *ctx)
    161 {
    162     if (ctx->plv == MMU_PLV_USER) {
    163         generate_exception(ctx, EXCCODE_IPE);
    164         return true;
    165     }
    166     return false;
    167 }
    168 
    169 static const CSRInfo *get_csr(unsigned csr_num)
    170 {
    171     const CSRInfo *csr;
    172 
    173     if (csr_num >= ARRAY_SIZE(csr_info)) {
    174         return NULL;
    175     }
    176     csr = &csr_info[csr_num];
    177     if (csr->offset == 0) {
    178         return NULL;
    179     }
    180     return csr;
    181 }
    182 
    183 static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
    184 {
    185     if ((csr->flags & CSRFL_READONLY) && write) {
    186         return false;
    187     }
    188     if ((csr->flags & CSRFL_IO) &&
    189         (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT)) {
    190         gen_io_start();
    191         ctx->base.is_jmp = DISAS_EXIT_UPDATE;
    192     } else if ((csr->flags & CSRFL_EXITTB) && write) {
    193         ctx->base.is_jmp = DISAS_EXIT_UPDATE;
    194     }
    195     return true;
    196 }
    197 
    198 static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
    199 {
    200     TCGv dest;
    201     const CSRInfo *csr;
    202 
    203     if (check_plv(ctx)) {
    204         return false;
    205     }
    206     csr = get_csr(a->csr);
    207     if (csr == NULL) {
    208         /* CSR is undefined: read as 0. */
    209         dest = tcg_constant_tl(0);
    210     } else {
    211         check_csr_flags(ctx, csr, false);
    212         dest = gpr_dst(ctx, a->rd, EXT_NONE);
    213         if (csr->readfn) {
    214             csr->readfn(dest, cpu_env);
    215         } else {
    216             tcg_gen_ld_tl(dest, cpu_env, csr->offset);
    217         }
    218     }
    219     gen_set_gpr(a->rd, dest, EXT_NONE);
    220     return true;
    221 }
    222 
    223 static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
    224 {
    225     TCGv dest, src1;
    226     const CSRInfo *csr;
    227 
    228     if (check_plv(ctx)) {
    229         return false;
    230     }
    231     csr = get_csr(a->csr);
    232     if (csr == NULL) {
    233         /* CSR is undefined: write ignored, read old_value as 0. */
    234         gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
    235         return true;
    236     }
    237     if (!check_csr_flags(ctx, csr, true)) {
    238         /* CSR is readonly: trap. */
    239         return false;
    240     }
    241     src1 = gpr_src(ctx, a->rd, EXT_NONE);
    242     if (csr->writefn) {
    243         dest = gpr_dst(ctx, a->rd, EXT_NONE);
    244         csr->writefn(dest, cpu_env, src1);
    245     } else {
    246         dest = temp_new(ctx);
    247         tcg_gen_ld_tl(dest, cpu_env, csr->offset);
    248         tcg_gen_st_tl(src1, cpu_env, csr->offset);
    249     }
    250     gen_set_gpr(a->rd, dest, EXT_NONE);
    251     return true;
    252 }
    253 
    254 static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
    255 {
    256     TCGv src1, mask, oldv, newv, temp;
    257     const CSRInfo *csr;
    258 
    259     if (check_plv(ctx)) {
    260         return false;
    261     }
    262     csr = get_csr(a->csr);
    263     if (csr == NULL) {
    264         /* CSR is undefined: write ignored, read old_value as 0. */
    265         gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
    266         return true;
    267     }
    268 
    269     if (!check_csr_flags(ctx, csr, true)) {
    270         /* CSR is readonly: trap. */
    271         return false;
    272     }
    273 
    274     /* So far only readonly csrs have readfn. */
    275     assert(csr->readfn == NULL);
    276 
    277     src1 = gpr_src(ctx, a->rd, EXT_NONE);
    278     mask = gpr_src(ctx, a->rj, EXT_NONE);
    279     oldv = tcg_temp_new();
    280     newv = tcg_temp_new();
    281     temp = tcg_temp_new();
    282 
    283     tcg_gen_ld_tl(oldv, cpu_env, csr->offset);
    284     tcg_gen_and_tl(newv, src1, mask);
    285     tcg_gen_andc_tl(temp, oldv, mask);
    286     tcg_gen_or_tl(newv, newv, temp);
    287 
    288     if (csr->writefn) {
    289         csr->writefn(oldv, cpu_env, newv);
    290     } else {
    291         tcg_gen_st_tl(newv, cpu_env, csr->offset);
    292     }
    293     gen_set_gpr(a->rd, oldv, EXT_NONE);
    294 
    295     tcg_temp_free(temp);
    296     tcg_temp_free(newv);
    297     tcg_temp_free(oldv);
    298     return true;
    299 }
    300 
    301 static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
    302                         void (*func)(TCGv, TCGv_ptr, TCGv))
    303 {
    304     TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
    305     TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
    306 
    307     if (check_plv(ctx)) {
    308         return false;
    309     }
    310     func(dest, cpu_env, src1);
    311     return true;
    312 }
    313 
    314 static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a,
    315                         void (*func)(TCGv_ptr, TCGv, TCGv))
    316 {
    317     TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
    318     TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
    319 
    320     if (check_plv(ctx)) {
    321         return false;
    322     }
    323     func(cpu_env, addr, val);
    324     return true;
    325 }
    326 
    327 TRANS(iocsrrd_b, gen_iocsrrd, gen_helper_iocsrrd_b)
    328 TRANS(iocsrrd_h, gen_iocsrrd, gen_helper_iocsrrd_h)
    329 TRANS(iocsrrd_w, gen_iocsrrd, gen_helper_iocsrrd_w)
    330 TRANS(iocsrrd_d, gen_iocsrrd, gen_helper_iocsrrd_d)
    331 TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b)
    332 TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h)
    333 TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w)
    334 TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d)
    335 
    336 static void check_mmu_idx(DisasContext *ctx)
    337 {
    338     if (ctx->mem_idx != MMU_IDX_DA) {
    339         tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
    340         ctx->base.is_jmp = DISAS_EXIT;
    341     }
    342 }
    343 
    344 static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
    345 {
    346     if (check_plv(ctx)) {
    347         return false;
    348     }
    349     gen_helper_tlbsrch(cpu_env);
    350     return true;
    351 }
    352 
    353 static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
    354 {
    355     if (check_plv(ctx)) {
    356         return false;
    357     }
    358     gen_helper_tlbrd(cpu_env);
    359     return true;
    360 }
    361 
    362 static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
    363 {
    364     if (check_plv(ctx)) {
    365         return false;
    366     }
    367     gen_helper_tlbwr(cpu_env);
    368     check_mmu_idx(ctx);
    369     return true;
    370 }
    371 
    372 static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
    373 {
    374     if (check_plv(ctx)) {
    375         return false;
    376     }
    377     gen_helper_tlbfill(cpu_env);
    378     check_mmu_idx(ctx);
    379     return true;
    380 }
    381 
    382 static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
    383 {
    384     if (check_plv(ctx)) {
    385         return false;
    386     }
    387     gen_helper_tlbclr(cpu_env);
    388     check_mmu_idx(ctx);
    389     return true;
    390 }
    391 
    392 static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
    393 {
    394     if (check_plv(ctx)) {
    395         return false;
    396     }
    397     gen_helper_tlbflush(cpu_env);
    398     check_mmu_idx(ctx);
    399     return true;
    400 }
    401 
    402 static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
    403 {
    404     TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
    405     TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);
    406 
    407     if (check_plv(ctx)) {
    408         return false;
    409     }
    410 
    411     switch (a->imm) {
    412     case 0:
    413     case 1:
    414         gen_helper_invtlb_all(cpu_env);
    415         break;
    416     case 2:
    417         gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1));
    418         break;
    419     case 3:
    420         gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0));
    421         break;
    422     case 4:
    423         gen_helper_invtlb_all_asid(cpu_env, rj);
    424         break;
    425     case 5:
    426         gen_helper_invtlb_page_asid(cpu_env, rj, rk);
    427         break;
    428     case 6:
    429         gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk);
    430         break;
    431     default:
    432         return false;
    433     }
    434     ctx->base.is_jmp = DISAS_STOP;
    435     return true;
    436 }
    437 
    438 static bool trans_cacop(DisasContext *ctx, arg_cacop *a)
    439 {
    440     /* Treat the cacop as a nop */
    441     if (check_plv(ctx)) {
    442         return false;
    443     }
    444     return true;
    445 }
    446 
    447 static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a)
    448 {
    449     TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
    450     TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
    451 
    452     if (check_plv(ctx)) {
    453         return false;
    454     }
    455     gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx);
    456     return true;
    457 }
    458 
    459 static bool trans_lddir(DisasContext *ctx, arg_lddir *a)
    460 {
    461     TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
    462     TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
    463     TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
    464 
    465     if (check_plv(ctx)) {
    466         return false;
    467     }
    468     gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx);
    469     return true;
    470 }
    471 
    472 static bool trans_ertn(DisasContext *ctx, arg_ertn *a)
    473 {
    474     if (check_plv(ctx)) {
    475         return false;
    476     }
    477     gen_helper_ertn(cpu_env);
    478     ctx->base.is_jmp = DISAS_EXIT;
    479     return true;
    480 }
    481 
    482 static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
    483 {
    484     if (check_plv(ctx)) {
    485         return false;
    486     }
    487     generate_exception(ctx, EXCCODE_DBP);
    488     return true;
    489 }
    490 
    491 static bool trans_idle(DisasContext *ctx, arg_idle *a)
    492 {
    493     if (check_plv(ctx)) {
    494         return false;
    495     }
    496 
    497     tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
    498     gen_helper_idle(cpu_env);
    499     ctx->base.is_jmp = DISAS_NORETURN;
    500     return true;
    501 }
    502 #endif