summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtish Patra <atishp@rivosinc.com>2022-07-21 00:50:32 +0300
committerAnup Patel <anup@brainfault.org>2022-07-30 08:39:18 +0300
commit1545afd342f2e22aaf91c4760dc5706965ec7fdf (patch)
treeaffabfba9fc05a9814ddeedba94abe8eaec31795
parent88b790f1291618274f94b6d5110ed09e20148bb2 (diff)
downloadopensbi-1545afd342f2e22aaf91c4760dc5706965ec7fdf.tar.xz
lib: sbi: Fix counter index sanity check
The current implementation computes the possible counter range by doing a left shift of counter base. However, this may overflow depending on the counter base value. In case of overflow, the highest counter id may be computed incorrectly. As per the SBI specification, the respective function should return an error if any of the counter is not valid. Fix the counter index check by avoiding left shifting while doing the sanity checks. Without the shift, the implementation just iterates over the counter mask and computes the correct counter index by adding the base to it. Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Atish Patra <atishp@rivosinc.com> Reviewed-by: Anup Patel <anup@brainfault.org>
-rw-r--r--lib/sbi/sbi_pmu.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
index 3f5fd10..31631a2 100644
--- a/lib/sbi/sbi_pmu.c
+++ b/lib/sbi/sbi_pmu.c
@@ -343,25 +343,26 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
{
int event_idx_type;
uint32_t event_code;
- unsigned long ctr_mask = cmask << cbase;
int ret = SBI_EINVAL;
bool bUpdate = FALSE;
+ int i, cidx;
- if (sbi_fls(ctr_mask) >= total_ctrs)
+ if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = TRUE;
- for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
- event_idx_type = pmu_ctr_validate(cbase, &event_code);
+ for_each_set_bit(i, &cmask, total_ctrs) {
+ cidx = i + cbase;
+ event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the start operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
- ret = pmu_ctr_start_fw(cbase, event_code, ival, bUpdate);
+ ret = pmu_ctr_start_fw(cidx, event_code, ival, bUpdate);
else
- ret = pmu_ctr_start_hw(cbase, ival, bUpdate);
+ ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
}
return ret;
@@ -421,25 +422,26 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
int ret = SBI_EINVAL;
int event_idx_type;
uint32_t event_code;
- unsigned long ctr_mask = cmask << cbase;
+ int i, cidx;
- if (sbi_fls(ctr_mask) >= total_ctrs)
+ if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
- for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
- event_idx_type = pmu_ctr_validate(cbase, &event_code);
+ for_each_set_bit(i, &cmask, total_ctrs) {
+ cidx = i + cbase;
+ event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the stop operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
- ret = pmu_ctr_stop_fw(cbase, event_code);
+ ret = pmu_ctr_stop_fw(cidx, event_code);
else
- ret = pmu_ctr_stop_hw(cbase);
+ ret = pmu_ctr_stop_hw(cidx);
if (flag & SBI_PMU_STOP_FLAG_RESET) {
- active_events[hartid][cbase] = SBI_PMU_EVENT_IDX_INVALID;
- pmu_reset_hw_mhpmevent(cbase);
+ active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID;
+ pmu_reset_hw_mhpmevent(cidx);
}
}
@@ -615,10 +617,9 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
int event_type = get_cidx_type(event_idx);
struct sbi_pmu_fw_event *fevent;
uint32_t fw_evt_code;
- unsigned long tmp = cidx_mask << cidx_base;
/* Do a basic sanity check of counter base & mask */
- if (sbi_fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
+ if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {