xref: /openbmc/qemu/target/loongarch/tcg/insn_trans/trans_privileged.c.inc (revision 10eab96e1a03538ad658faed2afb680f041cc361)
15c23704eSSong Gao/* SPDX-License-Identifier: GPL-2.0-or-later */
25c23704eSSong Gao/*
35c23704eSSong Gao * Copyright (c) 2021 Loongson Technology Corporation Limited
45c23704eSSong Gao *
55c23704eSSong Gao * LoongArch translation routines for the privileged instructions.
65c23704eSSong Gao */
75c23704eSSong Gao
85c23704eSSong Gao#include "cpu-csr.h"
95c23704eSSong Gao
105c23704eSSong Gao#ifdef CONFIG_USER_ONLY
115c23704eSSong Gao
125c23704eSSong Gao#define GEN_FALSE_TRANS(name)   \
135c23704eSSong Gaostatic bool trans_##name(DisasContext *ctx, arg_##name * a)  \
145c23704eSSong Gao{   \
155c23704eSSong Gao    return false;   \
165c23704eSSong Gao}
175c23704eSSong Gao
185c23704eSSong GaoGEN_FALSE_TRANS(csrrd)
195c23704eSSong GaoGEN_FALSE_TRANS(csrwr)
205c23704eSSong GaoGEN_FALSE_TRANS(csrxchg)
215c23704eSSong GaoGEN_FALSE_TRANS(iocsrrd_b)
225c23704eSSong GaoGEN_FALSE_TRANS(iocsrrd_h)
235c23704eSSong GaoGEN_FALSE_TRANS(iocsrrd_w)
245c23704eSSong GaoGEN_FALSE_TRANS(iocsrrd_d)
255c23704eSSong GaoGEN_FALSE_TRANS(iocsrwr_b)
265c23704eSSong GaoGEN_FALSE_TRANS(iocsrwr_h)
275c23704eSSong GaoGEN_FALSE_TRANS(iocsrwr_w)
285c23704eSSong GaoGEN_FALSE_TRANS(iocsrwr_d)
295c23704eSSong GaoGEN_FALSE_TRANS(tlbsrch)
305c23704eSSong GaoGEN_FALSE_TRANS(tlbrd)
315c23704eSSong GaoGEN_FALSE_TRANS(tlbwr)
325c23704eSSong GaoGEN_FALSE_TRANS(tlbfill)
335c23704eSSong GaoGEN_FALSE_TRANS(tlbclr)
345c23704eSSong GaoGEN_FALSE_TRANS(tlbflush)
355c23704eSSong GaoGEN_FALSE_TRANS(invtlb)
365c23704eSSong GaoGEN_FALSE_TRANS(cacop)
375c23704eSSong GaoGEN_FALSE_TRANS(ldpte)
385c23704eSSong GaoGEN_FALSE_TRANS(lddir)
395c23704eSSong GaoGEN_FALSE_TRANS(ertn)
405c23704eSSong GaoGEN_FALSE_TRANS(dbcl)
415c23704eSSong GaoGEN_FALSE_TRANS(idle)
425c23704eSSong Gao
435c23704eSSong Gao#else
445c23704eSSong Gao
455c23704eSSong Gaotypedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
465c23704eSSong Gaotypedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
475c23704eSSong Gao
485c23704eSSong Gaotypedef struct {
495c23704eSSong Gao    int offset;
505c23704eSSong Gao    int flags;
515c23704eSSong Gao    GenCSRRead readfn;
525c23704eSSong Gao    GenCSRWrite writefn;
535c23704eSSong Gao} CSRInfo;
545c23704eSSong Gao
555c23704eSSong Gaoenum {
565c23704eSSong Gao    CSRFL_READONLY = (1 << 0),
575c23704eSSong Gao    CSRFL_EXITTB   = (1 << 1),
585c23704eSSong Gao    CSRFL_IO       = (1 << 2),
595c23704eSSong Gao};
605c23704eSSong Gao
615c23704eSSong Gao#define CSR_OFF_FUNCS(NAME, FL, RD, WR)                    \
625c23704eSSong Gao    [LOONGARCH_CSR_##NAME] = {                             \
635c23704eSSong Gao        .offset = offsetof(CPULoongArchState, CSR_##NAME), \
645c23704eSSong Gao        .flags = FL, .readfn = RD, .writefn = WR           \
655c23704eSSong Gao    }
665c23704eSSong Gao
675c23704eSSong Gao#define CSR_OFF_ARRAY(NAME, N)                                \
685c23704eSSong Gao    [LOONGARCH_CSR_##NAME(N)] = {                             \
695c23704eSSong Gao        .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \
705c23704eSSong Gao        .flags = 0, .readfn = NULL, .writefn = NULL           \
715c23704eSSong Gao    }
725c23704eSSong Gao
735c23704eSSong Gao#define CSR_OFF_FLAGS(NAME, FL) \
745c23704eSSong Gao    CSR_OFF_FUNCS(NAME, FL, NULL, NULL)
755c23704eSSong Gao
765c23704eSSong Gao#define CSR_OFF(NAME) \
775c23704eSSong Gao    CSR_OFF_FLAGS(NAME, 0)
785c23704eSSong Gao
795c23704eSSong Gaostatic const CSRInfo csr_info[] = {
805c23704eSSong Gao    CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB),
815c23704eSSong Gao    CSR_OFF(PRMD),
825c23704eSSong Gao    CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB),
835c23704eSSong Gao    CSR_OFF_FLAGS(MISC, CSRFL_READONLY),
845c23704eSSong Gao    CSR_OFF(ECFG),
855c23704eSSong Gao    CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat),
865c23704eSSong Gao    CSR_OFF(ERA),
875c23704eSSong Gao    CSR_OFF(BADV),
885c23704eSSong Gao    CSR_OFF_FLAGS(BADI, CSRFL_READONLY),
895c23704eSSong Gao    CSR_OFF(EENTRY),
905c23704eSSong Gao    CSR_OFF(TLBIDX),
915c23704eSSong Gao    CSR_OFF(TLBEHI),
925c23704eSSong Gao    CSR_OFF(TLBELO0),
935c23704eSSong Gao    CSR_OFF(TLBELO1),
945c23704eSSong Gao    CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid),
955c23704eSSong Gao    CSR_OFF(PGDL),
965c23704eSSong Gao    CSR_OFF(PGDH),
975c23704eSSong Gao    CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL),
985c23704eSSong Gao    CSR_OFF(PWCL),
995c23704eSSong Gao    CSR_OFF(PWCH),
1005c23704eSSong Gao    CSR_OFF(STLBPS),
1015c23704eSSong Gao    CSR_OFF(RVACFG),
1025c23704eSSong Gao    CSR_OFF_FUNCS(CPUID, CSRFL_READONLY, gen_helper_csrrd_cpuid, NULL),
1035c23704eSSong Gao    CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY),
1045c23704eSSong Gao    CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY),
1055c23704eSSong Gao    CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY),
1065c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 0),
1075c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 1),
1085c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 2),
1095c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 3),
1105c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 4),
1115c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 5),
1125c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 6),
1135c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 7),
1145c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 8),
1155c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 9),
1165c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 10),
1175c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 11),
1185c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 12),
1195c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 13),
1205c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 14),
1215c23704eSSong Gao    CSR_OFF_ARRAY(SAVE, 15),
1225c23704eSSong Gao    CSR_OFF(TID),
1235c23704eSSong Gao    CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg),
1245c23704eSSong Gao    CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL),
1255c23704eSSong Gao    CSR_OFF(CNTC),
1265c23704eSSong Gao    CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr),
1275c23704eSSong Gao    CSR_OFF(LLBCTL),
1285c23704eSSong Gao    CSR_OFF(IMPCTL1),
1295c23704eSSong Gao    CSR_OFF(IMPCTL2),
1305c23704eSSong Gao    CSR_OFF(TLBRENTRY),
1315c23704eSSong Gao    CSR_OFF(TLBRBADV),
1325c23704eSSong Gao    CSR_OFF(TLBRERA),
1335c23704eSSong Gao    CSR_OFF(TLBRSAVE),
1345c23704eSSong Gao    CSR_OFF(TLBRELO0),
1355c23704eSSong Gao    CSR_OFF(TLBRELO1),
1365c23704eSSong Gao    CSR_OFF(TLBREHI),
1375c23704eSSong Gao    CSR_OFF(TLBRPRMD),
1385c23704eSSong Gao    CSR_OFF(MERRCTL),
1395c23704eSSong Gao    CSR_OFF(MERRINFO1),
1405c23704eSSong Gao    CSR_OFF(MERRINFO2),
1415c23704eSSong Gao    CSR_OFF(MERRENTRY),
1425c23704eSSong Gao    CSR_OFF(MERRERA),
1435c23704eSSong Gao    CSR_OFF(MERRSAVE),
1445c23704eSSong Gao    CSR_OFF(CTAG),
1455c23704eSSong Gao    CSR_OFF_ARRAY(DMW, 0),
1465c23704eSSong Gao    CSR_OFF_ARRAY(DMW, 1),
1475c23704eSSong Gao    CSR_OFF_ARRAY(DMW, 2),
1485c23704eSSong Gao    CSR_OFF_ARRAY(DMW, 3),
1495c23704eSSong Gao    CSR_OFF(DBG),
1505c23704eSSong Gao    CSR_OFF(DERA),
1515c23704eSSong Gao    CSR_OFF(DSAVE),
1525c23704eSSong Gao};
1535c23704eSSong Gao
1545c23704eSSong Gaostatic bool check_plv(DisasContext *ctx)
1555c23704eSSong Gao{
1565c23704eSSong Gao    if (ctx->plv == MMU_PLV_USER) {
1575c23704eSSong Gao        generate_exception(ctx, EXCCODE_IPE);
1585c23704eSSong Gao        return true;
1595c23704eSSong Gao    }
1605c23704eSSong Gao    return false;
1615c23704eSSong Gao}
1625c23704eSSong Gao
1635c23704eSSong Gaostatic const CSRInfo *get_csr(unsigned csr_num)
1645c23704eSSong Gao{
1655c23704eSSong Gao    const CSRInfo *csr;
1665c23704eSSong Gao
1675c23704eSSong Gao    if (csr_num >= ARRAY_SIZE(csr_info)) {
1685c23704eSSong Gao        return NULL;
1695c23704eSSong Gao    }
1705c23704eSSong Gao    csr = &csr_info[csr_num];
1715c23704eSSong Gao    if (csr->offset == 0) {
1725c23704eSSong Gao        return NULL;
1735c23704eSSong Gao    }
1745c23704eSSong Gao    return csr;
1755c23704eSSong Gao}
1765c23704eSSong Gao
1775c23704eSSong Gaostatic bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
1785c23704eSSong Gao{
1795c23704eSSong Gao    if ((csr->flags & CSRFL_READONLY) && write) {
1805c23704eSSong Gao        return false;
1815c23704eSSong Gao    }
1825c23704eSSong Gao    if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) {
1835c23704eSSong Gao        ctx->base.is_jmp = DISAS_EXIT_UPDATE;
1845c23704eSSong Gao    } else if ((csr->flags & CSRFL_EXITTB) && write) {
1855c23704eSSong Gao        ctx->base.is_jmp = DISAS_EXIT_UPDATE;
1865c23704eSSong Gao    }
1875c23704eSSong Gao    return true;
1885c23704eSSong Gao}
1895c23704eSSong Gao
1905c23704eSSong Gaostatic bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
1915c23704eSSong Gao{
1925c23704eSSong Gao    TCGv dest;
1935c23704eSSong Gao    const CSRInfo *csr;
1945c23704eSSong Gao
1955c23704eSSong Gao    if (check_plv(ctx)) {
1965c23704eSSong Gao        return false;
1975c23704eSSong Gao    }
1985c23704eSSong Gao    csr = get_csr(a->csr);
1995c23704eSSong Gao    if (csr == NULL) {
2005c23704eSSong Gao        /* CSR is undefined: read as 0. */
2015c23704eSSong Gao        dest = tcg_constant_tl(0);
2025c23704eSSong Gao    } else {
2035c23704eSSong Gao        check_csr_flags(ctx, csr, false);
2045c23704eSSong Gao        dest = gpr_dst(ctx, a->rd, EXT_NONE);
2055c23704eSSong Gao        if (csr->readfn) {
2065c23704eSSong Gao            csr->readfn(dest, tcg_env);
2075c23704eSSong Gao        } else {
2085c23704eSSong Gao            tcg_gen_ld_tl(dest, tcg_env, csr->offset);
2095c23704eSSong Gao        }
2105c23704eSSong Gao    }
2115c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
2125c23704eSSong Gao    return true;
2135c23704eSSong Gao}
2145c23704eSSong Gao
2155c23704eSSong Gaostatic bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
2165c23704eSSong Gao{
2175c23704eSSong Gao    TCGv dest, src1;
2185c23704eSSong Gao    const CSRInfo *csr;
2195c23704eSSong Gao
2205c23704eSSong Gao    if (check_plv(ctx)) {
2215c23704eSSong Gao        return false;
2225c23704eSSong Gao    }
2235c23704eSSong Gao    csr = get_csr(a->csr);
2245c23704eSSong Gao    if (csr == NULL) {
2255c23704eSSong Gao        /* CSR is undefined: write ignored, read old_value as 0. */
2265c23704eSSong Gao        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
2275c23704eSSong Gao        return true;
2285c23704eSSong Gao    }
2295c23704eSSong Gao    if (!check_csr_flags(ctx, csr, true)) {
2305c23704eSSong Gao        /* CSR is readonly: trap. */
2315c23704eSSong Gao        return false;
2325c23704eSSong Gao    }
2335c23704eSSong Gao    src1 = gpr_src(ctx, a->rd, EXT_NONE);
2345c23704eSSong Gao    if (csr->writefn) {
2355c23704eSSong Gao        dest = gpr_dst(ctx, a->rd, EXT_NONE);
2365c23704eSSong Gao        csr->writefn(dest, tcg_env, src1);
2375c23704eSSong Gao    } else {
2385c23704eSSong Gao        dest = tcg_temp_new();
2395c23704eSSong Gao        tcg_gen_ld_tl(dest, tcg_env, csr->offset);
2405c23704eSSong Gao        tcg_gen_st_tl(src1, tcg_env, csr->offset);
2415c23704eSSong Gao    }
2425c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
2435c23704eSSong Gao    return true;
2445c23704eSSong Gao}
2455c23704eSSong Gao
2465c23704eSSong Gaostatic bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
2475c23704eSSong Gao{
2485c23704eSSong Gao    TCGv src1, mask, oldv, newv, temp;
2495c23704eSSong Gao    const CSRInfo *csr;
2505c23704eSSong Gao
2515c23704eSSong Gao    if (check_plv(ctx)) {
2525c23704eSSong Gao        return false;
2535c23704eSSong Gao    }
2545c23704eSSong Gao    csr = get_csr(a->csr);
2555c23704eSSong Gao    if (csr == NULL) {
2565c23704eSSong Gao        /* CSR is undefined: write ignored, read old_value as 0. */
2575c23704eSSong Gao        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
2585c23704eSSong Gao        return true;
2595c23704eSSong Gao    }
2605c23704eSSong Gao
2615c23704eSSong Gao    if (!check_csr_flags(ctx, csr, true)) {
2625c23704eSSong Gao        /* CSR is readonly: trap. */
2635c23704eSSong Gao        return false;
2645c23704eSSong Gao    }
2655c23704eSSong Gao
2665c23704eSSong Gao    /* So far only readonly csrs have readfn. */
2675c23704eSSong Gao    assert(csr->readfn == NULL);
2685c23704eSSong Gao
2695c23704eSSong Gao    src1 = gpr_src(ctx, a->rd, EXT_NONE);
2705c23704eSSong Gao    mask = gpr_src(ctx, a->rj, EXT_NONE);
2715c23704eSSong Gao    oldv = tcg_temp_new();
2725c23704eSSong Gao    newv = tcg_temp_new();
2735c23704eSSong Gao    temp = tcg_temp_new();
2745c23704eSSong Gao
2755c23704eSSong Gao    tcg_gen_ld_tl(oldv, tcg_env, csr->offset);
2765c23704eSSong Gao    tcg_gen_and_tl(newv, src1, mask);
2775c23704eSSong Gao    tcg_gen_andc_tl(temp, oldv, mask);
2785c23704eSSong Gao    tcg_gen_or_tl(newv, newv, temp);
2795c23704eSSong Gao
2805c23704eSSong Gao    if (csr->writefn) {
2815c23704eSSong Gao        csr->writefn(oldv, tcg_env, newv);
2825c23704eSSong Gao    } else {
2835c23704eSSong Gao        tcg_gen_st_tl(newv, tcg_env, csr->offset);
2845c23704eSSong Gao    }
2855c23704eSSong Gao    gen_set_gpr(a->rd, oldv, EXT_NONE);
2865c23704eSSong Gao    return true;
2875c23704eSSong Gao}
2885c23704eSSong Gao
2895c23704eSSong Gaostatic bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
2905c23704eSSong Gao                        void (*func)(TCGv, TCGv_ptr, TCGv))
2915c23704eSSong Gao{
2925c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
2935c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
2945c23704eSSong Gao
2955c23704eSSong Gao    if (check_plv(ctx)) {
2965c23704eSSong Gao        return false;
2975c23704eSSong Gao    }
2985c23704eSSong Gao    func(dest, tcg_env, src1);
2995c23704eSSong Gao    return true;
3005c23704eSSong Gao}
3015c23704eSSong Gao
3025c23704eSSong Gaostatic bool gen_iocsrwr(DisasContext *ctx, arg_rr *a,
3035c23704eSSong Gao                        void (*func)(TCGv_ptr, TCGv, TCGv))
3045c23704eSSong Gao{
3055c23704eSSong Gao    TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
3065c23704eSSong Gao    TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
3075c23704eSSong Gao
3085c23704eSSong Gao    if (check_plv(ctx)) {
3095c23704eSSong Gao        return false;
3105c23704eSSong Gao    }
3115c23704eSSong Gao    func(tcg_env, addr, val);
3125c23704eSSong Gao    return true;
3135c23704eSSong Gao}
3145c23704eSSong Gao
3155c23704eSSong GaoTRANS(iocsrrd_b, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_b)
3165c23704eSSong GaoTRANS(iocsrrd_h, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_h)
3175c23704eSSong GaoTRANS(iocsrrd_w, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_w)
3185c23704eSSong GaoTRANS(iocsrrd_d, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_d)
3195c23704eSSong GaoTRANS(iocsrwr_b, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_b)
3205c23704eSSong GaoTRANS(iocsrwr_h, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_h)
3215c23704eSSong GaoTRANS(iocsrwr_w, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_w)
3225c23704eSSong GaoTRANS(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d)
3235c23704eSSong Gao
3245c23704eSSong Gaostatic void check_mmu_idx(DisasContext *ctx)
3255c23704eSSong Gao{
326*3f262d25SRichard Henderson    if (ctx->mem_idx != MMU_DA_IDX) {
3275c23704eSSong Gao        tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
3285c23704eSSong Gao        ctx->base.is_jmp = DISAS_EXIT;
3295c23704eSSong Gao    }
3305c23704eSSong Gao}
3315c23704eSSong Gao
3325c23704eSSong Gaostatic bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
3335c23704eSSong Gao{
3345c23704eSSong Gao    if (check_plv(ctx)) {
3355c23704eSSong Gao        return false;
3365c23704eSSong Gao    }
3375c23704eSSong Gao    gen_helper_tlbsrch(tcg_env);
3385c23704eSSong Gao    return true;
3395c23704eSSong Gao}
3405c23704eSSong Gao
3415c23704eSSong Gaostatic bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
3425c23704eSSong Gao{
3435c23704eSSong Gao    if (check_plv(ctx)) {
3445c23704eSSong Gao        return false;
3455c23704eSSong Gao    }
3465c23704eSSong Gao    gen_helper_tlbrd(tcg_env);
3475c23704eSSong Gao    return true;
3485c23704eSSong Gao}
3495c23704eSSong Gao
3505c23704eSSong Gaostatic bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
3515c23704eSSong Gao{
3525c23704eSSong Gao    if (check_plv(ctx)) {
3535c23704eSSong Gao        return false;
3545c23704eSSong Gao    }
3555c23704eSSong Gao    gen_helper_tlbwr(tcg_env);
3565c23704eSSong Gao    check_mmu_idx(ctx);
3575c23704eSSong Gao    return true;
3585c23704eSSong Gao}
3595c23704eSSong Gao
3605c23704eSSong Gaostatic bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
3615c23704eSSong Gao{
3625c23704eSSong Gao    if (check_plv(ctx)) {
3635c23704eSSong Gao        return false;
3645c23704eSSong Gao    }
3655c23704eSSong Gao    gen_helper_tlbfill(tcg_env);
3665c23704eSSong Gao    check_mmu_idx(ctx);
3675c23704eSSong Gao    return true;
3685c23704eSSong Gao}
3695c23704eSSong Gao
3705c23704eSSong Gaostatic bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
3715c23704eSSong Gao{
3725c23704eSSong Gao    if (check_plv(ctx)) {
3735c23704eSSong Gao        return false;
3745c23704eSSong Gao    }
3755c23704eSSong Gao    gen_helper_tlbclr(tcg_env);
3765c23704eSSong Gao    check_mmu_idx(ctx);
3775c23704eSSong Gao    return true;
3785c23704eSSong Gao}
3795c23704eSSong Gao
3805c23704eSSong Gaostatic bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
3815c23704eSSong Gao{
3825c23704eSSong Gao    if (check_plv(ctx)) {
3835c23704eSSong Gao        return false;
3845c23704eSSong Gao    }
3855c23704eSSong Gao    gen_helper_tlbflush(tcg_env);
3865c23704eSSong Gao    check_mmu_idx(ctx);
3875c23704eSSong Gao    return true;
3885c23704eSSong Gao}
3895c23704eSSong Gao
3905c23704eSSong Gaostatic bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
3915c23704eSSong Gao{
3925c23704eSSong Gao    TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
3935c23704eSSong Gao    TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);
3945c23704eSSong Gao
3955c23704eSSong Gao    if (check_plv(ctx)) {
3965c23704eSSong Gao        return false;
3975c23704eSSong Gao    }
3985c23704eSSong Gao
3995c23704eSSong Gao    switch (a->imm) {
4005c23704eSSong Gao    case 0:
4015c23704eSSong Gao    case 1:
4025c23704eSSong Gao        gen_helper_invtlb_all(tcg_env);
4035c23704eSSong Gao        break;
4045c23704eSSong Gao    case 2:
4055c23704eSSong Gao        gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1));
4065c23704eSSong Gao        break;
4075c23704eSSong Gao    case 3:
4085c23704eSSong Gao        gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0));
4095c23704eSSong Gao        break;
4105c23704eSSong Gao    case 4:
4115c23704eSSong Gao        gen_helper_invtlb_all_asid(tcg_env, rj);
4125c23704eSSong Gao        break;
4135c23704eSSong Gao    case 5:
4145c23704eSSong Gao        gen_helper_invtlb_page_asid(tcg_env, rj, rk);
4155c23704eSSong Gao        break;
4165c23704eSSong Gao    case 6:
4175c23704eSSong Gao        gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk);
4185c23704eSSong Gao        break;
4195c23704eSSong Gao    default:
4205c23704eSSong Gao        return false;
4215c23704eSSong Gao    }
4225c23704eSSong Gao    ctx->base.is_jmp = DISAS_STOP;
4235c23704eSSong Gao    return true;
4245c23704eSSong Gao}
4255c23704eSSong Gao
4265c23704eSSong Gaostatic bool trans_cacop(DisasContext *ctx, arg_cacop *a)
4275c23704eSSong Gao{
4285c23704eSSong Gao    /* Treat the cacop as a nop */
4295c23704eSSong Gao    if (check_plv(ctx)) {
4305c23704eSSong Gao        return false;
4315c23704eSSong Gao    }
4325c23704eSSong Gao    return true;
4335c23704eSSong Gao}
4345c23704eSSong Gao
4355c23704eSSong Gaostatic bool trans_ldpte(DisasContext *ctx, arg_ldpte *a)
4365c23704eSSong Gao{
4375c23704eSSong Gao    TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
4385c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
4395c23704eSSong Gao
4405c23704eSSong Gao    if (!avail_LSPW(ctx)) {
4415c23704eSSong Gao        return true;
4425c23704eSSong Gao    }
4435c23704eSSong Gao
4445c23704eSSong Gao    if (check_plv(ctx)) {
4455c23704eSSong Gao        return false;
4465c23704eSSong Gao    }
4475c23704eSSong Gao    gen_helper_ldpte(tcg_env, src1, tcg_constant_tl(a->imm), mem_idx);
4485c23704eSSong Gao    return true;
4495c23704eSSong Gao}
4505c23704eSSong Gao
4515c23704eSSong Gaostatic bool trans_lddir(DisasContext *ctx, arg_lddir *a)
4525c23704eSSong Gao{
4535c23704eSSong Gao    TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
4545c23704eSSong Gao    TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
4555c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
4565c23704eSSong Gao
4575c23704eSSong Gao    if (!avail_LSPW(ctx)) {
4585c23704eSSong Gao        return true;
4595c23704eSSong Gao    }
4605c23704eSSong Gao
4615c23704eSSong Gao    if (check_plv(ctx)) {
4625c23704eSSong Gao        return false;
4635c23704eSSong Gao    }
4645c23704eSSong Gao    gen_helper_lddir(dest, tcg_env, src, tcg_constant_tl(a->imm), mem_idx);
4655c23704eSSong Gao    return true;
4665c23704eSSong Gao}
4675c23704eSSong Gao
4685c23704eSSong Gaostatic bool trans_ertn(DisasContext *ctx, arg_ertn *a)
4695c23704eSSong Gao{
4705c23704eSSong Gao    if (check_plv(ctx)) {
4715c23704eSSong Gao        return false;
4725c23704eSSong Gao    }
4735c23704eSSong Gao    gen_helper_ertn(tcg_env);
4745c23704eSSong Gao    ctx->base.is_jmp = DISAS_EXIT;
4755c23704eSSong Gao    return true;
4765c23704eSSong Gao}
4775c23704eSSong Gao
4785c23704eSSong Gaostatic bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
4795c23704eSSong Gao{
4805c23704eSSong Gao    if (check_plv(ctx)) {
4815c23704eSSong Gao        return false;
4825c23704eSSong Gao    }
4835c23704eSSong Gao    generate_exception(ctx, EXCCODE_DBP);
4845c23704eSSong Gao    return true;
4855c23704eSSong Gao}
4865c23704eSSong Gao
4875c23704eSSong Gaostatic bool trans_idle(DisasContext *ctx, arg_idle *a)
4885c23704eSSong Gao{
4895c23704eSSong Gao    if (check_plv(ctx)) {
4905c23704eSSong Gao        return false;
4915c23704eSSong Gao    }
4925c23704eSSong Gao
4935c23704eSSong Gao    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
4945c23704eSSong Gao    gen_helper_idle(tcg_env);
4955c23704eSSong Gao    ctx->base.is_jmp = DISAS_NORETURN;
4965c23704eSSong Gao    return true;
4975c23704eSSong Gao}
4985c23704eSSong Gao#endif
499