Skip to content

Commit 69a0f02

Browse files
jamestiotioavpatel
authored andcommitted
lib: sbi: pmu: Return SBI_EINVAL if cidx_mask is 0
Currently, when configuring a matching programmable HPM counter with Sscofpmf being present, cidx_base > 2, and cidx_mask == 0 to monitor either the CPU_CYCLES or INSTRUCTIONS hardware event, sbi_pmu_ctr_cfg_match will succeed but it will configure the corresponding fixed counter instead of the counter specified by the cidx_base parameter. During counter configuration, the following issues may arise: - If the SKIP_MATCH flag is set, an out-of-bounds memory read of the phs->active_events array would occur, which could lead to undefined behavior. - If the CLEAR_VALUE flag is set, the corresponding fixed counter will be reset, which could be considered unexpected behavior. - If the AUTO_START flag is set, pmu_ctr_start_hw will silently start the fixed counter, even though it has already started. From the supervisor's perspective, nothing has changed, which could be confusing. The supervisor will not see the SBI_ERR_ALREADY_STARTED error code since sbi_pmu_ctr_cfg_match does not return the error code of pmu_ctr_start_hw. The only way to detect these issues is to check the ctr_idx return value of sbi_pmu_ctr_cfg_match and compare it with cidx_base. Fix these issues by returning the SBI_ERR_INVALID_PARAM error code if the cidx_mask parameter value being passed in is 0 since an invalid parameter should not lead to a successful sbi_pmu_ctr_cfg_match but with unexpected side effects. Following a similar rationale, add the validation check to sbi_pmu_ctr_start and sbi_pmu_ctr_stop as well since sbi_fls is undefined when the mask is 0. This also aligns OpenSBI's behavior with KVM's. Signed-off-by: James Raphael Tiovalen <[email protected]> Reviewed-by: Atish Patra <[email protected]> Reviewed-by: Andrew Jones <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Anup Patel <[email protected]>
1 parent d4f5a16 commit 69a0f02

File tree

1 file changed

+10
-5
lines changed

1 file changed

+10
-5
lines changed

lib/sbi/sbi_pmu.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ static int pmu_ctr_validate(struct sbi_pmu_hart_state *phs,
206206
return event_idx_type;
207207
}
208208

209+
static bool pmu_ctr_idx_validate(unsigned long cbase, unsigned long cmask)
210+
{
211+
/* Do a basic sanity check of counter base & mask */
212+
return cmask && cbase + sbi_fls(cmask) < total_ctrs;
213+
}
214+
209215
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
210216
{
211217
int event_idx_type;
@@ -472,7 +478,7 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
472478
int i, cidx;
473479
uint64_t edata;
474480

475-
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
481+
if (!pmu_ctr_idx_validate(cbase, cmask))
476482
return ret;
477483

478484
if (flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
@@ -577,8 +583,8 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
577583
uint32_t event_code;
578584
int i, cidx;
579585

580-
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
581-
return SBI_EINVAL;
586+
if (!pmu_ctr_idx_validate(cbase, cmask))
587+
return ret;
582588

583589
if (flag & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
584590
return SBI_ENO_SHMEM;
@@ -839,8 +845,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
839845
int ret, event_type, ctr_idx = SBI_ENOTSUPP;
840846
u32 event_code;
841847

842-
/* Do a basic sanity check of counter base & mask */
843-
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
848+
if (!pmu_ctr_idx_validate(cidx_base, cidx_mask))
844849
return SBI_EINVAL;
845850

846851
event_type = pmu_event_validate(phs, event_idx, event_data);

0 commit comments

Comments
 (0)