aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/csr.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-01-07 22:09:24 -0800
committerRichard Henderson <richard.henderson@linaro.org>2022-01-07 22:09:24 -0800
commitafe33262585565b64df706c62b4b0f6e0ad30c71 (patch)
tree59d55faafca9293f474bbfae6e42b1686bd16180 /target/riscv/csr.c
parentd70075373af51b6aa1d637962c962120e201fc98 (diff)
parent48eaeb56debf91817dea00a2cd9c1f6c986eb531 (diff)
downloadqemu-afe33262585565b64df706c62b4b0f6e0ad30c71.zip
qemu-afe33262585565b64df706c62b4b0f6e0ad30c71.tar.gz
qemu-afe33262585565b64df706c62b4b0f6e0ad30c71.tar.bz2
Merge tag 'pull-riscv-to-apply-20220108' of github.com:alistair23/qemu into staging
Second RISC-V PR for QEMU 7.0 - Fix illegal instruction when PMP is disabled - SiFive PDMA 64-bit support - SiFive PLIC cleanups - Mark Hypervisor extension as non experimental - Enable Hypervisor extension by default - Support 32 cores on the virt machine - Corrections for the Vector extension - Experimental support for 128-bit CPUs - stval and mtval support for illegal instructions # gpg: Signature made Fri 07 Jan 2022 09:50:11 PM PST # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * tag 'pull-riscv-to-apply-20220108' of github.com:alistair23/qemu: (37 commits) target/riscv: Implement the stval/mtval illegal instruction target/riscv: Fixup setting GVA target/riscv: Set the opcode in DisasContext target/riscv: actual functions to realize crs 128-bit insns target/riscv: modification of the trans_csrxx for 128-bit support target/riscv: helper functions to wrap calls to 128-bit csr insns target/riscv: adding high part of some csrs target/riscv: support for 128-bit M extension target/riscv: support for 128-bit arithmetic instructions target/riscv: support for 128-bit shift instructions target/riscv: support for 128-bit U-type instructions target/riscv: support for 128-bit bitwise instructions target/riscv: accessors to registers upper part and 128-bit load/store target/riscv: moving some insns close to similar insns target/riscv: setup everything for rv64 to support rv128 execution target/riscv: array for the 64 upper bits of 128-bit registers target/riscv: separation of bitwise logic and arithmetic helpers target/riscv: additional macros to check instruction support qemu/int128: addition of div/rem 128-bit operations exec/memop: Adding signed quad and octo defines ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/riscv/csr.c')
-rw-r--r--target/riscv/csr.c194
1 files changed, 173 insertions, 21 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 146447e..adb3d43 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -481,7 +481,7 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS &
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)));
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
- SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS;
+ SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS | (target_ulong)SSTATUS64_UXL;
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
static const target_ulong hip_writable_mask = MIP_VSSIP;
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
@@ -527,6 +527,8 @@ static uint64_t add_status_sd(RISCVMXL xl, uint64_t status)
return status | MSTATUS32_SD;
case MXL_RV64:
return status | MSTATUS64_SD;
+ case MXL_RV128:
+ return MSTATUSH128_SD;
default:
g_assert_not_reached();
}
@@ -576,10 +578,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
mstatus = (mstatus & ~mask) | (val & mask);
- if (riscv_cpu_mxl(env) == MXL_RV64) {
+ RISCVMXL xl = riscv_cpu_mxl(env);
+ if (xl > MXL_RV32) {
/* SXL and UXL fields are for now read only */
- mstatus = set_field(mstatus, MSTATUS64_SXL, MXL_RV64);
- mstatus = set_field(mstatus, MSTATUS64_UXL, MXL_RV64);
+ mstatus = set_field(mstatus, MSTATUS64_SXL, xl);
+ mstatus = set_field(mstatus, MSTATUS64_UXL, xl);
}
env->mstatus = mstatus;
@@ -608,6 +611,20 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+static RISCVException read_mstatus_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ *val = int128_make128(env->mstatus, add_status_sd(MXL_RV128, env->mstatus));
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_misa_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ *val = int128_make128(env->misa_ext, (uint64_t)MXL_RV128 << 62);
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_misa(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -765,6 +782,21 @@ static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
}
/* Machine Trap Handling */
+static RISCVException read_mscratch_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ *val = int128_make128(env->mscratch, env->mscratchh);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mscratch_i128(CPURISCVState *env, int csrno,
+ Int128 val)
+{
+ env->mscratch = int128_getlo(val);
+ env->mscratchh = int128_gethi(val);
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_mscratch(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -844,6 +876,16 @@ static RISCVException rmw_mip(CPURISCVState *env, int csrno,
}
/* Supervisor Trap Setup */
+static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ uint64_t mask = sstatus_v1_10_mask;
+ uint64_t sstatus = env->mstatus & mask;
+
+ *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_sstatus(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -937,6 +979,21 @@ static RISCVException write_scounteren(CPURISCVState *env, int csrno,
}
/* Supervisor Trap Handling */
+static RISCVException read_sscratch_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ *val = int128_make128(env->sscratch, env->sscratchh);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sscratch_i128(CPURISCVState *env, int csrno,
+ Int128 val)
+{
+ env->sscratch = int128_getlo(val);
+ env->sscratchh = int128_gethi(val);
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_sscratch(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -1737,16 +1794,13 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
* csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value);
*/
-RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
- target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
+ int csrno,
+ bool write_mask,
+ RISCVCPU *cpu)
{
- RISCVException ret;
- target_ulong old_value;
- RISCVCPU *cpu = env_archcpu(env);
- int read_only = get_field(csrno, 0xC00) == 3;
-
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
+ int read_only = get_field(csrno, 0xC00) == 3;
#if !defined(CONFIG_USER_ONLY)
int effective_priv = env->priv;
@@ -1778,10 +1832,17 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
if (!csr_ops[csrno].predicate) {
return RISCV_EXCP_ILLEGAL_INST;
}
- ret = csr_ops[csrno].predicate(env, csrno);
- if (ret != RISCV_EXCP_NONE) {
- return ret;
- }
+
+ return csr_ops[csrno].predicate(env, csrno);
+}
+
+static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask)
+{
+ RISCVException ret;
+ target_ulong old_value;
/* execute combined read/write operation if it exists */
if (csr_ops[csrno].op) {
@@ -1817,6 +1878,92 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask);
+}
+
+static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
+ Int128 *ret_value,
+ Int128 new_value,
+ Int128 write_mask)
+{
+ RISCVException ret;
+ Int128 old_value;
+
+ /* read old value */
+ ret = csr_ops[csrno].read128(env, csrno, &old_value);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ /* write value if writable and write mask set, otherwise drop writes */
+ if (int128_nz(write_mask)) {
+ new_value = int128_or(int128_and(old_value, int128_not(write_mask)),
+ int128_and(new_value, write_mask));
+ if (csr_ops[csrno].write128) {
+ ret = csr_ops[csrno].write128(env, csrno, new_value);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+ } else if (csr_ops[csrno].write) {
+ /* avoids having to write wrappers for all registers */
+ ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value));
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+ }
+ }
+
+ /* return old value */
+ if (ret_value) {
+ *ret_value = old_value;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
+ Int128 *ret_value,
+ Int128 new_value, Int128 write_mask)
+{
+ RISCVException ret;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ if (csr_ops[csrno].read128) {
+ return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask);
+ }
+
+ /*
+ * Fall back to 64-bit version for now, if the 128-bit alternative isn't
+ * at all defined.
+ * Note, some CSRs don't need to extend to MXLEN (64 upper bits non
+ * significant), for those, this fallback is correctly handling the accesses
+ */
+ target_ulong old_value;
+ ret = riscv_csrrw_do64(env, csrno, &old_value,
+ int128_getlo(new_value),
+ int128_getlo(write_mask));
+ if (ret == RISCV_EXCP_NONE && ret_value) {
+ *ret_value = int128_make64(old_value);
+ }
+ return ret;
+}
+
/*
* Debugger support. If not in user mode, set env->debugger before the
* riscv_csrrw call and clear it after the call.
@@ -1878,8 +2025,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MHARTID] = { "mhartid", any, read_mhartid },
/* Machine Trap Setup */
- [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus },
- [CSR_MISA] = { "misa", any, read_misa, write_misa },
+ [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, NULL,
+ read_mstatus_i128 },
+ [CSR_MISA] = { "misa", any, read_misa, write_misa, NULL,
+ read_misa_i128 },
[CSR_MIDELEG] = { "mideleg", any, read_mideleg, write_mideleg },
[CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg },
[CSR_MIE] = { "mie", any, read_mie, write_mie },
@@ -1889,20 +2038,23 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush },
/* Machine Trap Handling */
- [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch },
+ [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, NULL,
+ read_mscratch_i128, write_mscratch_i128 },
[CSR_MEPC] = { "mepc", any, read_mepc, write_mepc },
[CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause },
[CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval },
[CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip },
/* Supervisor Trap Setup */
- [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus },
+ [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, NULL,
+ read_sstatus_i128 },
[CSR_SIE] = { "sie", smode, read_sie, write_sie },
[CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
[CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren },
/* Supervisor Trap Handling */
- [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch },
+ [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, NULL,
+ read_sscratch_i128, write_sscratch_i128 },
[CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc },
[CSR_SCAUSE] = { "scause", smode, read_scause, write_scause },
[CSR_STVAL] = { "stval", smode, read_stval, write_stval },