⬢ DragonFlyBSD Kernel Audit
DF-5055 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c
+++ b/sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c
@@ -192,6 +192,30 @@
 }
 
 
+/*
+ * DF-5055 (DF-4933 twin on the dce80 table wiring): the dce80
+ * vupdate_int_entry (irq_service_dce80.c:132-146) initializes no
+ * .src_id -- and neither does dce110's own (irq_service_dce110.c:127-141)
+ * -- so for DC_IRQ_SOURCE_VUPDATE1..6 the re-derivation inside
+ * dce110_vblank_set returns DC_IRQ_SOURCE_INVALID and
+ * `dal_irq_src - IRQ_TYPE_VBLANK' underflows (uint8_t)178, a far-OOB
+ * pipe_ctx[] read on the MAX_PIPES array whose garbage tg is immediately
+ * called through tg->funcs->arm_vert_intr(tg, 2).  Derive the pipe from
+ * the table index instead: provably 0..5 for both the VUPDATE and VBLANK
+ * ranges, independent of src_id.
+ */
+static uint8_t vblank_pipe_offset(
+	const struct irq_service *irq_service,
+	const struct irq_source_info *info)
+{
+	enum dc_irq_source src =
+		(enum dc_irq_source)(info - irq_service->info);
+
+	if (src >= DC_IRQ_SOURCE_VUPDATE1 && src <= DC_IRQ_SOURCE_VUPDATE6)
+		return (uint8_t)(src - DC_IRQ_SOURCE_VUPDATE1);
+	return (uint8_t)(src - DC_IRQ_SOURCE_VBLANK1);
+}
+
 bool dce110_vblank_set(struct irq_service *irq_service,
 		       const struct irq_source_info *info,
 		       bool enable)
@@ -202,7 +226,9 @@
 			dc_interrupt_to_irq_source(irq_service->ctx->dc,
 						   info->src_id,
 						   info->ext_id);
-	uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK;
+	uint8_t pipe_offset = vblank_pipe_offset(irq_service, info);
+	(void)dal_irq_src;	/* DF-5055/DF-4933: pipe no longer derived
+				 * from the re-mapped src_id */
 
 	struct timing_generator *tg =
 			core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg;