Skip to content

Commit 18b8f5b

Browse files
geertutsbogend
authored andcommitted
mips: cm: Convert to bitfield API to fix out-of-bounds access
mips_cm_error_report() extracts the cause and other cause from the error register using shifts. This works fine for the former, as it is stored in the top bits, and the shift will thus remove all non-related bits. However, the latter is stored in the bottom bits, hence thus needs masking to get rid of non-related bits. Without such masking, using it as an index into the cm2_causes[] array will lead to an out-of-bounds access, probably causing a crash. Fix this by using FIELD_GET() instead. Bite the bullet and convert all MIPS CM handling to the bitfield API, to improve readability and safety. Fixes: 3885c2b ("MIPS: CM: Add support for reporting CM cache errors") Signed-off-by: Geert Uytterhoeven <[email protected]> Reviewed-by: Jiaxun Yang <[email protected]> Signed-off-by: Thomas Bogendoerfer <[email protected]>
1 parent 95b8a5e commit 18b8f5b

File tree

2 files changed

+16
-17
lines changed

2 files changed

+16
-17
lines changed

arch/mips/include/asm/mips-cm.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#ifndef __MIPS_ASM_MIPS_CM_H__
1212
#define __MIPS_ASM_MIPS_CM_H__
1313

14+
#include <linux/bitfield.h>
1415
#include <linux/bitops.h>
1516
#include <linux/errno.h>
1617

@@ -153,8 +154,8 @@ GCR_ACCESSOR_RO(32, 0x030, rev)
153154
#define CM_GCR_REV_MINOR GENMASK(7, 0)
154155

155156
#define CM_ENCODE_REV(major, minor) \
156-
(((major) << __ffs(CM_GCR_REV_MAJOR)) | \
157-
((minor) << __ffs(CM_GCR_REV_MINOR)))
157+
(FIELD_PREP(CM_GCR_REV_MAJOR, major) | \
158+
FIELD_PREP(CM_GCR_REV_MINOR, minor))
158159

159160
#define CM_REV_CM2 CM_ENCODE_REV(6, 0)
160161
#define CM_REV_CM2_5 CM_ENCODE_REV(7, 0)
@@ -362,19 +363,18 @@ static inline int mips_cm_revision(void)
362363
static inline unsigned int mips_cm_max_vp_width(void)
363364
{
364365
extern int smp_num_siblings;
365-
uint32_t cfg;
366366

367367
if (mips_cm_revision() >= CM_REV_CM3)
368-
return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW;
368+
return FIELD_GET(CM_GCR_SYS_CONFIG2_MAXVPW,
369+
read_gcr_sys_config2());
369370

370371
if (mips_cm_present()) {
371372
/*
372373
* We presume that all cores in the system will have the same
373374
* number of VP(E)s, and if that ever changes then this will
374375
* need revisiting.
375376
*/
376-
cfg = read_gcr_cl_config() & CM_GCR_Cx_CONFIG_PVPE;
377-
return (cfg >> __ffs(CM_GCR_Cx_CONFIG_PVPE)) + 1;
377+
return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, read_gcr_cl_config()) + 1;
378378
}
379379

380380
if (IS_ENABLED(CONFIG_SMP))

arch/mips/kernel/mips-cm.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,7 @@ static void mips_cm_probe_l2sync(void)
221221
phys_addr_t addr;
222222

223223
/* L2-only sync was introduced with CM major revision 6 */
224-
major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR) >>
225-
__ffs(CM_GCR_REV_MAJOR);
224+
major_rev = FIELD_GET(CM_GCR_REV_MAJOR, read_gcr_rev());
226225
if (major_rev < 6)
227226
return;
228227

@@ -306,13 +305,13 @@ void mips_cm_lock_other(unsigned int cluster, unsigned int core,
306305
preempt_disable();
307306

308307
if (cm_rev >= CM_REV_CM3) {
309-
val = core << __ffs(CM3_GCR_Cx_OTHER_CORE);
310-
val |= vp << __ffs(CM3_GCR_Cx_OTHER_VP);
308+
val = FIELD_PREP(CM3_GCR_Cx_OTHER_CORE, core) |
309+
FIELD_PREP(CM3_GCR_Cx_OTHER_VP, vp);
311310

312311
if (cm_rev >= CM_REV_CM3_5) {
313312
val |= CM_GCR_Cx_OTHER_CLUSTER_EN;
314-
val |= cluster << __ffs(CM_GCR_Cx_OTHER_CLUSTER);
315-
val |= block << __ffs(CM_GCR_Cx_OTHER_BLOCK);
313+
val |= FIELD_PREP(CM_GCR_Cx_OTHER_CLUSTER, cluster);
314+
val |= FIELD_PREP(CM_GCR_Cx_OTHER_BLOCK, block);
316315
} else {
317316
WARN_ON(cluster != 0);
318317
WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL);
@@ -342,7 +341,7 @@ void mips_cm_lock_other(unsigned int cluster, unsigned int core,
342341
spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
343342
per_cpu(cm_core_lock_flags, curr_core));
344343

345-
val = core << __ffs(CM_GCR_Cx_OTHER_CORENUM);
344+
val = FIELD_PREP(CM_GCR_Cx_OTHER_CORENUM, core);
346345
}
347346

348347
write_gcr_cl_other(val);
@@ -386,8 +385,8 @@ void mips_cm_error_report(void)
386385
cm_other = read_gcr_error_mult();
387386

388387
if (revision < CM_REV_CM3) { /* CM2 */
389-
cause = cm_error >> __ffs(CM_GCR_ERROR_CAUSE_ERRTYPE);
390-
ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND);
388+
cause = FIELD_GET(CM_GCR_ERROR_CAUSE_ERRTYPE, cm_error);
389+
ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other);
391390

392391
if (!cause)
393392
return;
@@ -445,8 +444,8 @@ void mips_cm_error_report(void)
445444
ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits;
446445
ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit;
447446

448-
cause = cm_error >> __ffs64(CM3_GCR_ERROR_CAUSE_ERRTYPE);
449-
ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND);
447+
cause = FIELD_GET(CM3_GCR_ERROR_CAUSE_ERRTYPE, cm_error);
448+
ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other);
450449

451450
if (!cause)
452451
return;

0 commit comments

Comments
 (0)