DF-4157 / fix.diff
--- a/sys/dev/sound/pci/maestro.c +++ b/sys/dev/sound/pci/maestro.c @@ -1090,6 +1090,15 @@ cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR); agg_unlock(ch->parent); cur -= 0xffff & ((ch->srcphys - ch->base) >> 1); + /* + * cur is derived from device register state (APU CURPTR). If the + * register file desyncs (APUs reprogrammed or powered down while a + * stale interrupt feeds), the subtraction can underflow to ~2^32 and + * drive interleave() arbitrarily far past the DMA ring. Treat any + * out-of-range value as "wrapped" instead of trusting the hardware. + */ + if (cur >= ch->buflen / 2) + cur = 0; last = ch->hwptr; src2 = ch->src + ch->parent->bufsz/4; @@ -1129,6 +1138,10 @@ cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR); agg_unlock(ch->parent); cur -= 0xffff & ((ch->phys - ch->base) >> 1); + /* Same desync guard as aggch_feed_adc_stereo(); the mono ring is + * buflen samples (16-bit) wide. */ + if (cur >= ch->buflen) + cur = 0; last = ch->hwptr; if (cur < last) { |