qemu/target/riscv/op_helper.c
<<
>>
Prefs
   1/*
   2 * RISC-V Emulation Helpers for QEMU.
   3 *
   4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
   5 * Copyright (c) 2017-2018 SiFive, Inc.
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms and conditions of the GNU General Public License,
   9 * version 2 or later, as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu/log.h"
  22#include "cpu.h"
  23#include "qemu/main-loop.h"
  24#include "exec/exec-all.h"
  25#include "exec/helper-proto.h"
  26
  27#ifndef CONFIG_USER_ONLY
  28
  29#if defined(TARGET_RISCV32)
  30static const char valid_vm_1_09[16] = {
  31    [VM_1_09_MBARE] = 1,
  32    [VM_1_09_SV32] = 1,
  33};
  34static const char valid_vm_1_10[16] = {
  35    [VM_1_10_MBARE] = 1,
  36    [VM_1_10_SV32] = 1
  37};
  38#elif defined(TARGET_RISCV64)
  39static const char valid_vm_1_09[16] = {
  40    [VM_1_09_MBARE] = 1,
  41    [VM_1_09_SV39] = 1,
  42    [VM_1_09_SV48] = 1,
  43};
  44static const char valid_vm_1_10[16] = {
  45    [VM_1_10_MBARE] = 1,
  46    [VM_1_10_SV39] = 1,
  47    [VM_1_10_SV48] = 1,
  48    [VM_1_10_SV57] = 1
  49};
  50#endif
  51
  52static int validate_vm(CPURISCVState *env, target_ulong vm)
  53{
  54    return (env->priv_ver >= PRIV_VERSION_1_10_0) ?
  55        valid_vm_1_10[vm & 0xf] : valid_vm_1_09[vm & 0xf];
  56}
  57
  58#endif
  59
  60/* Exceptions processing helpers */
  61void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
  62                                          uint32_t exception, uintptr_t pc)
  63{
  64    CPUState *cs = CPU(riscv_env_get_cpu(env));
  65    qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
  66    cs->exception_index = exception;
  67    cpu_loop_exit_restore(cs, pc);
  68}
  69
  70void helper_raise_exception(CPURISCVState *env, uint32_t exception)
  71{
  72    do_raise_exception_err(env, exception, 0);
  73}
  74
  75static void validate_mstatus_fs(CPURISCVState *env, uintptr_t ra)
  76{
  77#ifndef CONFIG_USER_ONLY
  78    if (!(env->mstatus & MSTATUS_FS)) {
  79        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, ra);
  80    }
  81#endif
  82}
  83
  84/*
  85 * Handle writes to CSRs and any resulting special behavior
  86 *
  87 * Adapted from Spike's processor_t::set_csr
  88 */
  89void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
  90        target_ulong csrno)
  91{
  92#ifndef CONFIG_USER_ONLY
  93    uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_X_COP);
  94    uint64_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
  95#endif
  96
  97    switch (csrno) {
  98    case CSR_FFLAGS:
  99        validate_mstatus_fs(env, GETPC());
 100        cpu_riscv_set_fflags(env, val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT));
 101        break;
 102    case CSR_FRM:
 103        validate_mstatus_fs(env, GETPC());
 104        env->frm = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
 105        break;
 106    case CSR_FCSR:
 107        validate_mstatus_fs(env, GETPC());
 108        env->frm = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
 109        cpu_riscv_set_fflags(env, (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT);
 110        break;
 111#ifndef CONFIG_USER_ONLY
 112    case CSR_MSTATUS: {
 113        target_ulong mstatus = env->mstatus;
 114        target_ulong mask = 0;
 115        target_ulong mpp = get_field(val_to_write, MSTATUS_MPP);
 116
 117        /* flush tlb on mstatus fields that affect VM */
 118        if (env->priv_ver <= PRIV_VERSION_1_09_1) {
 119            if ((val_to_write ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
 120                    MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_VM)) {
 121                helper_tlb_flush(env);
 122            }
 123            mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
 124                MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
 125                MSTATUS_MPP | MSTATUS_MXR |
 126                (validate_vm(env, get_field(val_to_write, MSTATUS_VM)) ?
 127                    MSTATUS_VM : 0);
 128        }
 129        if (env->priv_ver >= PRIV_VERSION_1_10_0) {
 130            if ((val_to_write ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
 131                    MSTATUS_MPRV | MSTATUS_SUM)) {
 132                helper_tlb_flush(env);
 133            }
 134            mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
 135                MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
 136                MSTATUS_MPP | MSTATUS_MXR;
 137        }
 138
 139        /* silenty discard mstatus.mpp writes for unsupported modes */
 140        if (mpp == PRV_H ||
 141            (!riscv_has_ext(env, RVS) && mpp == PRV_S) ||
 142            (!riscv_has_ext(env, RVU) && mpp == PRV_U)) {
 143            mask &= ~MSTATUS_MPP;
 144        }
 145
 146        mstatus = (mstatus & ~mask) | (val_to_write & mask);
 147
 148        /* Note: this is a workaround for an issue where mstatus.FS
 149           does not report dirty after floating point operations
 150           that modify floating point state. This workaround is
 151           technically compliant with the RISC-V Privileged
 152           specification as it is legal to return only off, or dirty.
 153           at the expense of extra floating point save/restore. */
 154
 155        /* FP is always dirty or off */
 156        if (mstatus & MSTATUS_FS) {
 157            mstatus |= MSTATUS_FS;
 158        }
 159
 160        int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
 161                    ((mstatus & MSTATUS_XS) == MSTATUS_XS);
 162        mstatus = set_field(mstatus, MSTATUS_SD, dirty);
 163        env->mstatus = mstatus;
 164        break;
 165    }
 166    case CSR_MIP: {
 167        /*
 168         * Since the writeable bits in MIP are not set asynchrously by the
 169         * CLINT, no additional locking is needed for read-modifiy-write
 170         * CSR operations
 171         */
 172        qemu_mutex_lock_iothread();
 173        RISCVCPU *cpu = riscv_env_get_cpu(env);
 174        riscv_set_local_interrupt(cpu, MIP_SSIP,
 175                                  (val_to_write & MIP_SSIP) != 0);
 176        riscv_set_local_interrupt(cpu, MIP_STIP,
 177                                  (val_to_write & MIP_STIP) != 0);
 178        /*
 179         * csrs, csrc on mip.SEIP is not decomposable into separate read and
 180         * write steps, so a different implementation is needed
 181         */
 182        qemu_mutex_unlock_iothread();
 183        break;
 184    }
 185    case CSR_MIE: {
 186        env->mie = (env->mie & ~all_ints) |
 187            (val_to_write & all_ints);
 188        break;
 189    }
 190    case CSR_MIDELEG:
 191        env->mideleg = (env->mideleg & ~delegable_ints)
 192                                | (val_to_write & delegable_ints);
 193        break;
 194    case CSR_MEDELEG: {
 195        target_ulong mask = 0;
 196        mask |= 1ULL << (RISCV_EXCP_INST_ADDR_MIS);
 197        mask |= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT);
 198        mask |= 1ULL << (RISCV_EXCP_ILLEGAL_INST);
 199        mask |= 1ULL << (RISCV_EXCP_BREAKPOINT);
 200        mask |= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS);
 201        mask |= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT);
 202        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS);
 203        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
 204        mask |= 1ULL << (RISCV_EXCP_U_ECALL);
 205        mask |= 1ULL << (RISCV_EXCP_S_ECALL);
 206        mask |= 1ULL << (RISCV_EXCP_H_ECALL);
 207        mask |= 1ULL << (RISCV_EXCP_M_ECALL);
 208        mask |= 1ULL << (RISCV_EXCP_INST_PAGE_FAULT);
 209        mask |= 1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT);
 210        mask |= 1ULL << (RISCV_EXCP_STORE_PAGE_FAULT);
 211        env->medeleg = (env->medeleg & ~mask)
 212                                | (val_to_write & mask);
 213        break;
 214    }
 215    case CSR_MINSTRET:
 216        qemu_log_mask(LOG_UNIMP, "CSR_MINSTRET: write not implemented");
 217        goto do_illegal;
 218    case CSR_MCYCLE:
 219        qemu_log_mask(LOG_UNIMP, "CSR_MCYCLE: write not implemented");
 220        goto do_illegal;
 221    case CSR_MINSTRETH:
 222        qemu_log_mask(LOG_UNIMP, "CSR_MINSTRETH: write not implemented");
 223        goto do_illegal;
 224    case CSR_MCYCLEH:
 225        qemu_log_mask(LOG_UNIMP, "CSR_MCYCLEH: write not implemented");
 226        goto do_illegal;
 227    case CSR_MUCOUNTEREN:
 228        env->mucounteren = val_to_write;
 229        break;
 230    case CSR_MSCOUNTEREN:
 231        env->mscounteren = val_to_write;
 232        break;
 233    case CSR_SSTATUS: {
 234        target_ulong ms = env->mstatus;
 235        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
 236            | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
 237            | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
 238        ms = (ms & ~mask) | (val_to_write & mask);
 239        csr_write_helper(env, ms, CSR_MSTATUS);
 240        break;
 241    }
 242    case CSR_SIP: {
 243        qemu_mutex_lock_iothread();
 244        target_ulong next_mip = (env->mip & ~env->mideleg)
 245                                | (val_to_write & env->mideleg);
 246        qemu_mutex_unlock_iothread();
 247        csr_write_helper(env, next_mip, CSR_MIP);
 248        break;
 249    }
 250    case CSR_SIE: {
 251        target_ulong next_mie = (env->mie & ~env->mideleg)
 252                                | (val_to_write & env->mideleg);
 253        csr_write_helper(env, next_mie, CSR_MIE);
 254        break;
 255    }
 256    case CSR_SATP: /* CSR_SPTBR */ {
 257        if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
 258            goto do_illegal;
 259        }
 260        if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val_to_write ^ env->sptbr))
 261        {
 262            helper_tlb_flush(env);
 263            env->sptbr = val_to_write & (((target_ulong)
 264                1 << (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
 265        }
 266        if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
 267            validate_vm(env, get_field(val_to_write, SATP_MODE)) &&
 268            ((val_to_write ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
 269        {
 270            helper_tlb_flush(env);
 271            env->satp = val_to_write;
 272        }
 273        break;
 274    }
 275    case CSR_SEPC:
 276        env->sepc = val_to_write;
 277        break;
 278    case CSR_STVEC:
 279        if (val_to_write & 1) {
 280            qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
 281            goto do_illegal;
 282        }
 283        env->stvec = val_to_write >> 2 << 2;
 284        break;
 285    case CSR_SCOUNTEREN:
 286        env->scounteren = val_to_write;
 287        break;
 288    case CSR_SSCRATCH:
 289        env->sscratch = val_to_write;
 290        break;
 291    case CSR_SCAUSE:
 292        env->scause = val_to_write;
 293        break;
 294    case CSR_SBADADDR:
 295        env->sbadaddr = val_to_write;
 296        break;
 297    case CSR_MEPC:
 298        env->mepc = val_to_write;
 299        break;
 300    case CSR_MTVEC:
 301        if (val_to_write & 1) {
 302            qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
 303            goto do_illegal;
 304        }
 305        env->mtvec = val_to_write >> 2 << 2;
 306        break;
 307    case CSR_MCOUNTEREN:
 308        env->mcounteren = val_to_write;
 309        break;
 310    case CSR_MSCRATCH:
 311        env->mscratch = val_to_write;
 312        break;
 313    case CSR_MCAUSE:
 314        env->mcause = val_to_write;
 315        break;
 316    case CSR_MBADADDR:
 317        env->mbadaddr = val_to_write;
 318        break;
 319    case CSR_MISA: {
 320        qemu_log_mask(LOG_UNIMP, "CSR_MISA: misa writes not supported");
 321        goto do_illegal;
 322    }
 323    case CSR_PMPCFG0:
 324    case CSR_PMPCFG1:
 325    case CSR_PMPCFG2:
 326    case CSR_PMPCFG3:
 327       pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val_to_write);
 328       break;
 329    case CSR_PMPADDR0:
 330    case CSR_PMPADDR1:
 331    case CSR_PMPADDR2:
 332    case CSR_PMPADDR3:
 333    case CSR_PMPADDR4:
 334    case CSR_PMPADDR5:
 335    case CSR_PMPADDR6:
 336    case CSR_PMPADDR7:
 337    case CSR_PMPADDR8:
 338    case CSR_PMPADDR9:
 339    case CSR_PMPADDR10:
 340    case CSR_PMPADDR11:
 341    case CSR_PMPADDR12:
 342    case CSR_PMPADDR13:
 343    case CSR_PMPADDR14:
 344    case CSR_PMPADDR15:
 345       pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val_to_write);
 346       break;
 347    do_illegal:
 348#endif
 349    default:
 350        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
 351    }
 352}
 353
 354/*
 355 * Handle reads to CSRs and any resulting special behavior
 356 *
 357 * Adapted from Spike's processor_t::get_csr
 358 */
 359target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
 360{
 361#ifndef CONFIG_USER_ONLY
 362    target_ulong ctr_en = env->priv == PRV_U ? env->mucounteren :
 363                   env->priv == PRV_S ? env->mscounteren : -1U;
 364#else
 365    target_ulong ctr_en = -1;
 366#endif
 367    target_ulong ctr_ok = (ctr_en >> (csrno & 31)) & 1;
 368
 369    if (csrno >= CSR_HPMCOUNTER3 && csrno <= CSR_HPMCOUNTER31) {
 370        if (ctr_ok) {
 371            return 0;
 372        }
 373    }
 374#if defined(TARGET_RISCV32)
 375    if (csrno >= CSR_HPMCOUNTER3H && csrno <= CSR_HPMCOUNTER31H) {
 376        if (ctr_ok) {
 377            return 0;
 378        }
 379    }
 380#endif
 381    if (csrno >= CSR_MHPMCOUNTER3 && csrno <= CSR_MHPMCOUNTER31) {
 382        return 0;
 383    }
 384#if defined(TARGET_RISCV32)
 385    if (csrno >= CSR_MHPMCOUNTER3 && csrno <= CSR_MHPMCOUNTER31) {
 386        return 0;
 387    }
 388#endif
 389    if (csrno >= CSR_MHPMEVENT3 && csrno <= CSR_MHPMEVENT31) {
 390        return 0;
 391    }
 392
 393    switch (csrno) {
 394    case CSR_FFLAGS:
 395        validate_mstatus_fs(env, GETPC());
 396        return cpu_riscv_get_fflags(env);
 397    case CSR_FRM:
 398        validate_mstatus_fs(env, GETPC());
 399        return env->frm;
 400    case CSR_FCSR:
 401        validate_mstatus_fs(env, GETPC());
 402        return (cpu_riscv_get_fflags(env) << FSR_AEXC_SHIFT)
 403                | (env->frm << FSR_RD_SHIFT);
 404    /* rdtime/rdtimeh is trapped and emulated by bbl in system mode */
 405#ifdef CONFIG_USER_ONLY
 406    case CSR_TIME:
 407        return cpu_get_host_ticks();
 408#if defined(TARGET_RISCV32)
 409    case CSR_TIMEH:
 410        return cpu_get_host_ticks() >> 32;
 411#endif
 412#endif
 413    case CSR_INSTRET:
 414    case CSR_CYCLE:
 415        if (ctr_ok) {
 416            return cpu_get_host_ticks();
 417        }
 418        break;
 419#if defined(TARGET_RISCV32)
 420    case CSR_INSTRETH:
 421    case CSR_CYCLEH:
 422        if (ctr_ok) {
 423            return cpu_get_host_ticks() >> 32;
 424        }
 425        break;
 426#endif
 427#ifndef CONFIG_USER_ONLY
 428    case CSR_MINSTRET:
 429    case CSR_MCYCLE:
 430        return cpu_get_host_ticks();
 431    case CSR_MINSTRETH:
 432    case CSR_MCYCLEH:
 433#if defined(TARGET_RISCV32)
 434        return cpu_get_host_ticks() >> 32;
 435#endif
 436        break;
 437    case CSR_MUCOUNTEREN:
 438        return env->mucounteren;
 439    case CSR_MSCOUNTEREN:
 440        return env->mscounteren;
 441    case CSR_SSTATUS: {
 442        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
 443            | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
 444            | SSTATUS_SUM |  SSTATUS_SD;
 445        if (env->priv_ver >= PRIV_VERSION_1_10_0) {
 446            mask |= SSTATUS_MXR;
 447        }
 448        return env->mstatus & mask;
 449    }
 450    case CSR_SIP: {
 451        qemu_mutex_lock_iothread();
 452        target_ulong tmp = env->mip & env->mideleg;
 453        qemu_mutex_unlock_iothread();
 454        return tmp;
 455    }
 456    case CSR_SIE:
 457        return env->mie & env->mideleg;
 458    case CSR_SEPC:
 459        return env->sepc;
 460    case CSR_SBADADDR:
 461        return env->sbadaddr;
 462    case CSR_STVEC:
 463        return env->stvec;
 464    case CSR_SCOUNTEREN:
 465        return env->scounteren;
 466    case CSR_SCAUSE:
 467        return env->scause;
 468    case CSR_SPTBR:
 469        if (env->priv_ver >= PRIV_VERSION_1_10_0) {
 470            return env->satp;
 471        } else {
 472            return env->sptbr;
 473        }
 474    case CSR_SSCRATCH:
 475        return env->sscratch;
 476    case CSR_MSTATUS:
 477        return env->mstatus;
 478    case CSR_MIP: {
 479        qemu_mutex_lock_iothread();
 480        target_ulong tmp = env->mip;
 481        qemu_mutex_unlock_iothread();
 482        return tmp;
 483    }
 484    case CSR_MIE:
 485        return env->mie;
 486    case CSR_MEPC:
 487        return env->mepc;
 488    case CSR_MSCRATCH:
 489        return env->mscratch;
 490    case CSR_MCAUSE:
 491        return env->mcause;
 492    case CSR_MBADADDR:
 493        return env->mbadaddr;
 494    case CSR_MISA:
 495        return env->misa;
 496    case CSR_MARCHID:
 497        return 0; /* as spike does */
 498    case CSR_MIMPID:
 499        return 0; /* as spike does */
 500    case CSR_MVENDORID:
 501        return 0; /* as spike does */
 502    case CSR_MHARTID:
 503        return env->mhartid;
 504    case CSR_MTVEC:
 505        return env->mtvec;
 506    case CSR_MCOUNTEREN:
 507        return env->mcounteren;
 508    case CSR_MEDELEG:
 509        return env->medeleg;
 510    case CSR_MIDELEG:
 511        return env->mideleg;
 512    case CSR_PMPCFG0:
 513    case CSR_PMPCFG1:
 514    case CSR_PMPCFG2:
 515    case CSR_PMPCFG3:
 516       return pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
 517    case CSR_PMPADDR0:
 518    case CSR_PMPADDR1:
 519    case CSR_PMPADDR2:
 520    case CSR_PMPADDR3:
 521    case CSR_PMPADDR4:
 522    case CSR_PMPADDR5:
 523    case CSR_PMPADDR6:
 524    case CSR_PMPADDR7:
 525    case CSR_PMPADDR8:
 526    case CSR_PMPADDR9:
 527    case CSR_PMPADDR10:
 528    case CSR_PMPADDR11:
 529    case CSR_PMPADDR12:
 530    case CSR_PMPADDR13:
 531    case CSR_PMPADDR14:
 532    case CSR_PMPADDR15:
 533       return pmpaddr_csr_read(env, csrno - CSR_PMPADDR0);
 534#endif
 535    }
 536    /* used by e.g. MTIME read */
 537    do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
 538}
 539
 540/*
 541 * Check that CSR access is allowed.
 542 *
 543 * Adapted from Spike's decode.h:validate_csr
 544 */
 545static void validate_csr(CPURISCVState *env, uint64_t which,
 546                         uint64_t write, uintptr_t ra)
 547{
 548#ifndef CONFIG_USER_ONLY
 549    unsigned csr_priv = get_field((which), 0x300);
 550    unsigned csr_read_only = get_field((which), 0xC00) == 3;
 551    if (((write) && csr_read_only) || (env->priv < csr_priv)) {
 552        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, ra);
 553    }
 554#endif
 555}
 556
 557target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
 558        target_ulong csr)
 559{
 560    validate_csr(env, csr, 1, GETPC());
 561    uint64_t csr_backup = csr_read_helper(env, csr);
 562    csr_write_helper(env, src, csr);
 563    return csr_backup;
 564}
 565
 566target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
 567        target_ulong csr, target_ulong rs1_pass)
 568{
 569    validate_csr(env, csr, rs1_pass != 0, GETPC());
 570    uint64_t csr_backup = csr_read_helper(env, csr);
 571    if (rs1_pass != 0) {
 572        csr_write_helper(env, src | csr_backup, csr);
 573    }
 574    return csr_backup;
 575}
 576
 577target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
 578        target_ulong csr, target_ulong rs1_pass)
 579{
 580    validate_csr(env, csr, rs1_pass != 0, GETPC());
 581    uint64_t csr_backup = csr_read_helper(env, csr);
 582    if (rs1_pass != 0) {
 583        csr_write_helper(env, (~src) & csr_backup, csr);
 584    }
 585    return csr_backup;
 586}
 587
 588#ifndef CONFIG_USER_ONLY
 589
 590/* iothread_mutex must be held */
 591void riscv_set_local_interrupt(RISCVCPU *cpu, target_ulong mask, int value)
 592{
 593    target_ulong old_mip = cpu->env.mip;
 594    cpu->env.mip = (old_mip & ~mask) | (value ? mask : 0);
 595
 596    if (cpu->env.mip && !old_mip) {
 597        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 598    } else if (!cpu->env.mip && old_mip) {
 599        cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 600    }
 601}
 602
 603void riscv_set_mode(CPURISCVState *env, target_ulong newpriv)
 604{
 605    if (newpriv > PRV_M) {
 606        g_assert_not_reached();
 607    }
 608    if (newpriv == PRV_H) {
 609        newpriv = PRV_U;
 610    }
 611    /* tlb_flush is unnecessary as mode is contained in mmu_idx */
 612    env->priv = newpriv;
 613}
 614
 615target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
 616{
 617    if (!(env->priv >= PRV_S)) {
 618        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
 619    }
 620
 621    target_ulong retpc = env->sepc;
 622    if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
 623        do_raise_exception_err(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
 624    }
 625
 626    target_ulong mstatus = env->mstatus;
 627    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
 628    mstatus = set_field(mstatus,
 629        env->priv_ver >= PRIV_VERSION_1_10_0 ?
 630        MSTATUS_SIE : MSTATUS_UIE << prev_priv,
 631        get_field(mstatus, MSTATUS_SPIE));
 632    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
 633    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
 634    riscv_set_mode(env, prev_priv);
 635    csr_write_helper(env, mstatus, CSR_MSTATUS);
 636
 637    return retpc;
 638}
 639
 640target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
 641{
 642    if (!(env->priv >= PRV_M)) {
 643        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
 644    }
 645
 646    target_ulong retpc = env->mepc;
 647    if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
 648        do_raise_exception_err(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
 649    }
 650
 651    target_ulong mstatus = env->mstatus;
 652    target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
 653    mstatus = set_field(mstatus,
 654        env->priv_ver >= PRIV_VERSION_1_10_0 ?
 655        MSTATUS_MIE : MSTATUS_UIE << prev_priv,
 656        get_field(mstatus, MSTATUS_MPIE));
 657    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
 658    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
 659    riscv_set_mode(env, prev_priv);
 660    csr_write_helper(env, mstatus, CSR_MSTATUS);
 661
 662    return retpc;
 663}
 664
 665
 666void helper_wfi(CPURISCVState *env)
 667{
 668    CPUState *cs = CPU(riscv_env_get_cpu(env));
 669
 670    cs->halted = 1;
 671    cs->exception_index = EXCP_HLT;
 672    cpu_loop_exit(cs);
 673}
 674
 675void helper_tlb_flush(CPURISCVState *env)
 676{
 677    RISCVCPU *cpu = riscv_env_get_cpu(env);
 678    CPUState *cs = CPU(cpu);
 679    tlb_flush(cs);
 680}
 681
 682#endif /* !CONFIG_USER_ONLY */
 683