Exemple #1
0
/* TLB management */
inline static void cpu_riscv_tlb_flush (CPURISCVState *env, int flush_global)
{
    RISCVCPU *cpu = riscv_env_get_cpu(env);

    /* Flush qemu's TLB and discard all shadowed entries.  */
    tlb_flush(CPU(cpu), flush_global);
}
Exemple #2
0
/* Exceptions processing helpers */
static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
                                          uint32_t exception, uintptr_t pc)
{
    CPUState *cs = CPU(riscv_env_get_cpu(env));
    qemu_log("%s: %d\n", __func__, exception);
    cs->exception_index = exception;
    cpu_loop_exit_restore(cs, pc);
}
Exemple #3
0
void helper_fence_i(CPURISCVState *env) {
    RISCVCPU *cpu = riscv_env_get_cpu(env);
    CPUState *cs = CPU(cpu);
    // Flush QEMU's TLB
    tlb_flush(cs, 1);
    // ARM port seems to not know if this is okay inside a TB...
    // But we need to do it
    tb_flush(cs);
}
Exemple #4
0
void cpu_riscv_irq_init_cpu(CPURISCVState *env)
{
    qemu_irq *qi;
    int i;

    qi = qemu_allocate_irqs(cpu_riscv_irq_request, riscv_env_get_cpu(env), 8);
    for (i = 0; i < 8; i++) {
        env->irq[i] = qi[i];
    }
}
Exemple #5
0
/* Exceptions processing helpers */
static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
                                                        uint32_t exception,
                                                        uintptr_t pc)
{
    CPUState *cs = CPU(riscv_env_get_cpu(env));
    qemu_log("%s: %d\n", __func__, exception);
    cs->exception_index = exception;
    if (pc) {
        /* now we have a real cpu fault */
        cpu_restore_state(cs, pc);
    }
    cpu_loop_exit(cs);
}
Exemple #6
0
static void do_unaligned_access(CPURISCVState *env, target_ulong addr,
                                int rw, int is_user, uintptr_t retaddr)
{
    CPUState *cs = CPU(riscv_env_get_cpu(env));
    if (rw & 0x2) {
        cs->exception_index = RISCV_EXCP_INST_ADDR_MIS;
    } else if (rw == 0x1) {
        cs->exception_index = RISCV_EXCP_STORE_ADDR_MIS;
        env->helper_csr[CSR_BADVADDR] = addr;
    } else {
        cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
        env->helper_csr[CSR_BADVADDR] = addr;
    }
    do_raise_exception_err(env, cs->exception_index, 0);
}
Exemple #7
0
inline void cpu_riscv_tlb_flush (CPURISCVState *env, int flush_global)
{
    RISCVCPU *cpu = riscv_env_get_cpu(env);
    // Flush QEMU's TLB
    tlb_flush(CPU(cpu), flush_global);
}
Exemple #8
0
/*
 * Handle writes to CSRs and any resulting special behavior
 *
 * Note: mtohost and mfromhost are not handled here
 */
inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
        target_ulong csrno)
{
    #ifdef RISCV_DEBUG_PRINT
    fprintf(stderr, "Write CSR reg: 0x" TARGET_FMT_lx "\n", csrno);
    fprintf(stderr, "Write CSR val: 0x" TARGET_FMT_lx "\n", val_to_write);
    #endif

    switch (csrno)
    {
    case NEW_CSR_FFLAGS:
        env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
        env->csr[NEW_CSR_FFLAGS] = val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT);
        break;
    case NEW_CSR_FRM:
        env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
        env->csr[NEW_CSR_FRM] = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
        break;
    case NEW_CSR_FCSR:
        env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
        env->csr[NEW_CSR_FFLAGS] = (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT;
        env->csr[NEW_CSR_FRM] = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
        break;
    case NEW_CSR_MTIME:
    case NEW_CSR_STIMEW:
        // this implementation ignores writes to MTIME
        break;
    case NEW_CSR_MTIMEH:
    case NEW_CSR_STIMEHW:
        // this implementation ignores writes to MTIME
        break;
    case NEW_CSR_TIMEW:
        cpu_riscv_store_timew(env, val_to_write);
        break;
    case NEW_CSR_TIMEHW:
        fprintf(stderr, "CSR_TIMEHW unsupported on RV64I\n");
        exit(1);
        break;
    case NEW_CSR_CYCLEW:
    case NEW_CSR_INSTRETW:
        cpu_riscv_store_instretw(env, val_to_write);
        break;
    case NEW_CSR_CYCLEHW:
    case NEW_CSR_INSTRETHW:
        fprintf(stderr, "CSR_CYCLEHW/INSTRETHW unsupported on RV64I\n");
        exit(1);
        break;
    case NEW_CSR_MSTATUS: {
        target_ulong mstatus = env->csr[NEW_CSR_MSTATUS];
        #ifdef RISCV_DEBUG_PRINT
        target_ulong debug_mstatus = mstatus;
        #endif
        if ((val_to_write ^ mstatus) &
                (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV)) {
            #ifdef RISCV_DEBUG_PRINT
            fprintf(stderr, "flushing TLB\n");
            #endif
            helper_tlb_flush(env);
        }

        // no extension support
        target_ulong mask = MSTATUS_IE | MSTATUS_IE1 | MSTATUS_IE2
            | MSTATUS_MPRV | MSTATUS_FS;

        if (validate_vm(get_field(val_to_write, MSTATUS_VM))) {
            mask |= MSTATUS_VM;
        }
        if (validate_priv(get_field(val_to_write, MSTATUS_PRV))) {
            mask |= MSTATUS_PRV;
        }
        if (validate_priv(get_field(val_to_write, MSTATUS_PRV1))) {
            mask |= MSTATUS_PRV1;
        }
        if (validate_priv(get_field(val_to_write, MSTATUS_PRV2))) {
            mask |= MSTATUS_PRV2;
        }

        mstatus = (mstatus & ~mask) | (val_to_write & mask);

        int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS;
        dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS;
        mstatus = set_field(mstatus, MSTATUS64_SD, dirty);
        env->csr[NEW_CSR_MSTATUS] = mstatus;
        break;
    }
    case NEW_CSR_MIP: {
        target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP;
        env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) |
            (val_to_write & mask);
        CPUState *cs = CPU(riscv_env_get_cpu(env));
        if (env->csr[NEW_CSR_MIP] & MIP_SSIP) {
            stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1);
        } else {
            stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0);
        }
        if (env->csr[NEW_CSR_MIP] & MIP_STIP) {
            stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x1);
        } else {
            stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x0);
        }
        if (env->csr[NEW_CSR_MIP] & MIP_MSIP) {
            stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1);
        } else {
            stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0);
        }
        break;
    }
    case NEW_CSR_MIPI: {
        CPUState *cs = CPU(riscv_env_get_cpu(env));
        env->csr[NEW_CSR_MIP] = set_field(env->csr[NEW_CSR_MIP], MIP_MSIP, val_to_write & 1);
        if (env->csr[NEW_CSR_MIP] & MIP_MSIP) {
            stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1);
        } else {
            stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0);
        }
        break;
    }
    case NEW_CSR_MIE: {
        target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP;
        env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) |
            (val_to_write & mask);
        break;
    }
    case NEW_CSR_SSTATUS: {
        target_ulong ms = env->csr[NEW_CSR_MSTATUS];
        ms = set_field(ms, MSTATUS_IE, get_field(val_to_write, SSTATUS_IE));
        ms = set_field(ms, MSTATUS_IE1, get_field(val_to_write, SSTATUS_PIE));
        ms = set_field(ms, MSTATUS_PRV1, get_field(val_to_write, SSTATUS_PS));
        ms = set_field(ms, MSTATUS_FS, get_field(val_to_write, SSTATUS_FS));
        ms = set_field(ms, MSTATUS_XS, get_field(val_to_write, SSTATUS_XS));
        ms = set_field(ms, MSTATUS_MPRV, get_field(val_to_write, SSTATUS_MPRV));
        csr_write_helper(env, ms, NEW_CSR_MSTATUS);
        break;
    }
    case NEW_CSR_SIP: {
        target_ulong mask = MIP_SSIP;
        env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) |
            (val_to_write & mask);
        CPUState *cs = CPU(riscv_env_get_cpu(env));
        if (env->csr[NEW_CSR_MIP] & MIP_SSIP) {
            stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1);
        } else {
            stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0);
        }
        break;
    }
    case NEW_CSR_SIE: {
        target_ulong mask = MIP_SSIP | MIP_STIP | MIP_SXIP;
        env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) |
            (val_to_write & mask);
        break;
    }
    case NEW_CSR_SEPC:
        env->csr[NEW_CSR_SEPC] = val_to_write;
        break;
    case NEW_CSR_STVEC:
        env->csr[NEW_CSR_STVEC] = val_to_write >> 2 << 2;
        break;
    case NEW_CSR_SPTBR:
        env->csr[NEW_CSR_SPTBR] = val_to_write & -(1L << PGSHIFT);
        break;
    case NEW_CSR_SSCRATCH:
        env->csr[NEW_CSR_SSCRATCH] = val_to_write;
        break;
    case NEW_CSR_MEPC:
        env->csr[NEW_CSR_MEPC] = val_to_write;
        break;
    case NEW_CSR_MSCRATCH:
        env->csr[NEW_CSR_MSCRATCH] = val_to_write;
        break;
    case NEW_CSR_MCAUSE:
        env->csr[NEW_CSR_MCAUSE] = val_to_write;
        break;
    case NEW_CSR_MBADADDR:
        env->csr[NEW_CSR_MBADADDR] = val_to_write;
        break;
    case NEW_CSR_MTIMECMP:
        // NOTE: clearing bit in MIP handled in cpu_riscv_store_compare
        cpu_riscv_store_compare(env, val_to_write);
        break;
    case NEW_CSR_MTOHOST:
        fprintf(stderr, "Write to mtohost should not be handled here\n");
        exit(1);
        break;
    case NEW_CSR_MFROMHOST:
        fprintf(stderr, "Write to mfromhost should not be handled here\n");
        exit(1);
        break;
    }
}