Message ID | 20220117132826.426418-16-anup@brainfault.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | QEMU RISC-V AIA support | expand |
Anup Patel <anup@brainfault.org> 於 2022年1月17日 週一 下午10:18寫道: > From: Anup Patel <anup.patel@wdc.com> > > The AIA specification defines IMSIC interface CSRs for easy access > to the per-HART IMSIC registers without using indirect xiselect and > xireg CSRs. This patch implements the AIA IMSIC interface CSRs. > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > Signed-off-by: Anup Patel <anup@brainfault.org> > --- > target/riscv/csr.c | 203 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 203 insertions(+) > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 7a787d3a3f..68e6009006 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -923,6 +923,16 @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int > csrno) > return CSR_VSISELECT; > case CSR_SIREG: > return CSR_VSIREG; > + case CSR_SSETEIPNUM: > + return CSR_VSSETEIPNUM; > + case CSR_SCLREIPNUM: > + return CSR_VSCLREIPNUM; > + case CSR_SSETEIENUM: > + return CSR_VSSETEIENUM; > + case CSR_SCLREIENUM: > + return CSR_VSCLREIENUM; > + case CSR_STOPEI: > + return CSR_VSTOPEI; > default: > return csrno; > }; > @@ -1075,6 +1085,178 @@ done: > return RISCV_EXCP_NONE; > } > > +static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong > *val, > + target_ulong new_val, target_ulong wr_mask) > +{ > + int ret = -EINVAL; > + bool set, pend, virt; > + target_ulong priv, isel, vgein, xlen, nval, wmask; > + > + /* Translate CSR number for VS-mode */ > + csrno = aia_xlate_vs_csrno(env, csrno); > + > + /* Decode register details from CSR number */ > + virt = set = pend = false; > + switch (csrno) { > + case CSR_MSETEIPNUM: > + priv = PRV_M; > + set = true; > + pend = true; > + break; > + case CSR_MCLREIPNUM: > + priv = PRV_M; > + pend = true; > + break; > + case CSR_MSETEIENUM: > + priv = PRV_M; > + set = true; > + break; > + case CSR_MCLREIENUM: > + priv = PRV_M; > + break; > + case CSR_SSETEIPNUM: > + priv = PRV_S; > + set = true; > + pend = true; > + break; > + case CSR_SCLREIPNUM: > + priv = PRV_S; > + pend = true; > + break; > + case CSR_SSETEIENUM: > + priv = PRV_S; > + set = true; > + break; > + case CSR_SCLREIENUM: > + priv = PRV_S; > + break; > + case CSR_VSSETEIPNUM: > + priv = PRV_S; > + virt = true; > + set = true; > + pend = true; > + break; > + case CSR_VSCLREIPNUM: > + priv = PRV_S; > + virt = true; > + pend = true; > + break; > + case CSR_VSSETEIENUM: > + priv = PRV_S; > + virt = true; > + set = true; > + break; > + case CSR_VSCLREIENUM: > + priv = PRV_S; > + virt = true; > + break; > + default: > + goto done; > + }; > + > + /* IMSIC CSRs only available when machine implements IMSIC. */ > + if (!env->aia_ireg_rmw_fn[priv]) { > + goto done; > + } > + > + /* Find the selected guest interrupt file */ > + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; > + > + /* Selected guest interrupt file should be valid */ > + if (virt && (!vgein || env->geilen < vgein)) { > + goto done; > + } > + > + /* Set/Clear CSRs always read zero */ > + if (val) { > + *val = 0; > + } > + > + if (wr_mask) { > + /* Get interrupt number */ > + new_val &= wr_mask; > + > + /* Find target interrupt pending/enable register */ > + xlen = riscv_cpu_mxl_bits(env); > + isel = (new_val / xlen); > + isel *= (xlen / IMSIC_EIPx_BITS); > + isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0; > + > + /* Find the interrupt bit to be set/clear */ > + wmask = ((target_ulong)1) << (new_val % xlen); > + nval = (set) ? wmask : 0; > + > + /* Call machine specific IMSIC register emulation */ > + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], > + AIA_MAKE_IREG(isel, priv, virt, > + vgein, xlen), > + NULL, nval, wmask); > + } else { > + ret = 0; > + } > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : > RISCV_EXCP_ILLEGAL_INST; > + } > + return RISCV_EXCP_NONE; > +} > + > +static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, > + target_ulong new_val, target_ulong wr_mask) > +{ > + bool virt; > + int ret = -EINVAL; > + target_ulong priv, vgein; > + > + /* Translate CSR number for VS-mode */ > + csrno = aia_xlate_vs_csrno(env, csrno); > + > + /* Decode register details from CSR number */ > + virt = false; > + switch (csrno) { > + case CSR_MTOPEI: > + priv = PRV_M; > + break; > + case CSR_STOPEI: > + priv = PRV_S; > + break; > + case CSR_VSTOPEI: > + priv = PRV_S; > + virt = true; > + break; > + default: > + goto done; > + }; > + > + /* IMSIC CSRs only available when machine implements IMSIC. */ > + if (!env->aia_ireg_rmw_fn[priv]) { > + goto done; > + } > + > + /* Find the selected guest interrupt file */ > + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; > + > + /* Selected guest interrupt file should be valid */ > + if (virt && (!vgein || env->geilen < vgein)) { > + goto done; > + } > + > + /* Call machine specific IMSIC register emulation for TOPEI */ > + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], > + AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, > + riscv_cpu_mxl_bits(env)), > + val, new_val, wr_mask); > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : > RISCV_EXCP_ILLEGAL_INST; > + } > + return RISCV_EXCP_NONE; > +} > + > static RISCVException read_mtvec(CPURISCVState *env, int csrno, > target_ulong *val) > { > @@ -2856,6 +3038,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > /* Machine-Level Interrupts (AIA) */ > [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, > > + /* Machine-Level IMSIC Interface (AIA) */ > + [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_MSETEIENUM] = { "mseteienum", aia_any, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_MCLREIENUM] = { "mclreienum", aia_any, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, > + > /* Virtual Interrupts for Supervisor Level (AIA) */ > [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, > [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, > @@ -2892,6 +3081,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > /* Supervisor-Level Interrupts (AIA) */ > [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, > > + /* Supervisor-Level IMSIC Interface (AIA) */ > + [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei > }, > + > /* Supervisor-Level High-Half CSRs (AIA) */ > [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, > [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, > @@ -2937,6 +3133,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > /* VS-Level Interrupts (H-extension with AIA) */ > [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, > > + /* VS-Level IMSIC Interface (H-extension with AIA) */ > + [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, NULL, NULL, > rmw_xsetclreinum }, > + [CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, > rmw_xtopei }, > + > /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ > [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, > rmw_hidelegh }, > [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, > write_ignore }, > -- > 2.25.1 > > > Reviewed-by: Frank Chang <frank.chang@sifive.com>
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 7a787d3a3f..68e6009006 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -923,6 +923,16 @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno) return CSR_VSISELECT; case CSR_SIREG: return CSR_VSIREG; + case CSR_SSETEIPNUM: + return CSR_VSSETEIPNUM; + case CSR_SCLREIPNUM: + return CSR_VSCLREIPNUM; + case CSR_SSETEIENUM: + return CSR_VSSETEIENUM; + case CSR_SCLREIENUM: + return CSR_VSCLREIENUM; + case CSR_STOPEI: + return CSR_VSTOPEI; default: return csrno; }; @@ -1075,6 +1085,178 @@ done: return RISCV_EXCP_NONE; } +static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) +{ + int ret = -EINVAL; + bool set, pend, virt; + target_ulong priv, isel, vgein, xlen, nval, wmask; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Decode register details from CSR number */ + virt = set = pend = false; + switch (csrno) { + case CSR_MSETEIPNUM: + priv = PRV_M; + set = true; + pend = true; + break; + case CSR_MCLREIPNUM: + priv = PRV_M; + pend = true; + break; + case CSR_MSETEIENUM: + priv = PRV_M; + set = true; + break; + case CSR_MCLREIENUM: + priv = PRV_M; + break; + case CSR_SSETEIPNUM: + priv = PRV_S; + set = true; + pend = true; + break; + case CSR_SCLREIPNUM: + priv = PRV_S; + pend = true; + break; + case CSR_SSETEIENUM: + priv = PRV_S; + set = true; + break; + case CSR_SCLREIENUM: + priv = PRV_S; + break; + case CSR_VSSETEIPNUM: + priv = PRV_S; + virt = true; + set = true; + pend = true; + break; + case CSR_VSCLREIPNUM: + priv = PRV_S; + virt = true; + pend = true; + break; + case CSR_VSSETEIENUM: + priv = PRV_S; + virt = true; + set = true; + break; + case CSR_VSCLREIENUM: + priv = PRV_S; + virt = true; + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->aia_ireg_rmw_fn[priv]) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + + /* Selected guest interrupt file should be valid */ + if (virt && (!vgein || env->geilen < vgein)) { + goto done; + } + + /* Set/Clear CSRs always read zero */ + if (val) { + *val = 0; + } + + if (wr_mask) { + /* Get interrupt number */ + new_val &= wr_mask; + + /* Find target interrupt pending/enable register */ + xlen = riscv_cpu_mxl_bits(env); + isel = (new_val / xlen); + isel *= (xlen / IMSIC_EIPx_BITS); + isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0; + + /* Find the interrupt bit to be set/clear */ + wmask = ((target_ulong)1) << (new_val % xlen); + nval = (set) ? wmask : 0; + + /* Call machine specific IMSIC register emulation */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(isel, priv, virt, + vgein, xlen), + NULL, nval, wmask); + } else { + ret = 0; + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + return RISCV_EXCP_NONE; +} + +static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) +{ + bool virt; + int ret = -EINVAL; + target_ulong priv, vgein; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Decode register details from CSR number */ + virt = false; + switch (csrno) { + case CSR_MTOPEI: + priv = PRV_M; + break; + case CSR_STOPEI: + priv = PRV_S; + break; + case CSR_VSTOPEI: + priv = PRV_S; + virt = true; + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->aia_ireg_rmw_fn[priv]) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + + /* Selected guest interrupt file should be valid */ + if (virt && (!vgein || env->geilen < vgein)) { + goto done; + } + + /* Call machine specific IMSIC register emulation for TOPEI */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, + riscv_cpu_mxl_bits(env)), + val, new_val, wr_mask); + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + return RISCV_EXCP_NONE; +} + static RISCVException read_mtvec(CPURISCVState *env, int csrno, target_ulong *val) { @@ -2856,6 +3038,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Machine-Level Interrupts (AIA) */ [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, + /* Machine-Level IMSIC Interface (AIA) */ + [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MSETEIENUM] = { "mseteienum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MCLREIENUM] = { "mclreienum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, + /* Virtual Interrupts for Supervisor Level (AIA) */ [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, @@ -2892,6 +3081,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Supervisor-Level Interrupts (AIA) */ [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, + /* Supervisor-Level IMSIC Interface (AIA) */ + [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei }, + /* Supervisor-Level High-Half CSRs (AIA) */ [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, @@ -2937,6 +3133,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* VS-Level Interrupts (H-extension with AIA) */ [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, + /* VS-Level IMSIC Interface (H-extension with AIA) */ + [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei }, + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, rmw_hidelegh }, [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, write_ignore },