On Wed, Jan 5, 2022 at 9:01 AM Frank Chang <frank.ch...@sifive.com> wrote: > > Anup Patel <a...@brainfault.org> 於 2021年12月30日 週四 下午8:53寫道: >> >> From: Anup Patel <anup.pa...@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.pa...@wdc.com> >> Signed-off-by: Anup Patel <a...@brainfault.org> >> --- >> target/riscv/csr.c | 202 +++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 202 insertions(+) >> >> diff --git a/target/riscv/csr.c b/target/riscv/csr.c >> index 488877e89c..89e74f848d 100644 >> --- a/target/riscv/csr.c >> +++ b/target/riscv/csr.c >> @@ -906,6 +906,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; >> }; >> @@ -1058,6 +1068,177 @@ 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; > > > Missing: pend = true; here?
Ahh, good catch. I will fix this in the next revision. Thanks, Anup > > Frank Chang > >> >> + 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) >> { >> @@ -2706,6 +2887,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 }, >> @@ -2740,6 +2928,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 }, >> @@ -2785,6 +2980,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 >> >>