summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2014-07-11 07:36:19 +1000
committerLorenz Meier <lm@inf.ethz.ch>2014-07-12 16:06:08 +0200
commit4b217e9a36b28975e5a7b40e525424cde72f7227 (patch)
tree498983e984d8b72b49d6ab095dcae54e6ac90c12
parentae43dd99849db279755eb4f434de28463c96fb7f (diff)
downloadnuttx-4b217e9a36b28975e5a7b40e525424cde72f7227.tar.gz
nuttx-4b217e9a36b28975e5a7b40e525424cde72f7227.tar.bz2
nuttx-4b217e9a36b28975e5a7b40e525424cde72f7227.zip
stm32_i2c: check for msgc underflow in I2C ISR
a spurious I2C interrupt could cause priv->msgc to underflow, leading to memory being overwritten. This seems to have been the cause of at least some of lockups we have seen
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_i2c.c41
1 files changed, 24 insertions, 17 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c
index d91b00acf..30a8dc5e4 100644
--- a/nuttx/arch/arm/src/stm32/stm32_i2c.c
+++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c
@@ -1154,30 +1154,37 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
if ((status & I2C_SR1_SB) != 0)
{
stm32_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgc);
+
+ /*
+ we check for msgc > 0 here as an unexpected interrupt with
+ I2C_SR1_SB set due to noise on the I2C cable can otherwise
+ cause msgc to wrap causing memory overwrite
+ */
+ if (priv->msgc > 0 && priv->msgv != NULL) {
+ /* Get run-time data */
- /* Get run-time data */
+ priv->ptr = priv->msgv->buffer;
+ priv->dcnt = priv->msgv->length;
+ priv->flags = priv->msgv->flags;
- priv->ptr = priv->msgv->buffer;
- priv->dcnt = priv->msgv->length;
- priv->flags = priv->msgv->flags;
+ /* Send address byte and define addressing mode */
- /* Send address byte and define addressing mode */
+ stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET,
+ (priv->flags & I2C_M_TEN) ?
+ 0 : ((priv->msgv->addr << 1) | (priv->flags & I2C_M_READ)));
- stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET,
- (priv->flags & I2C_M_TEN) ?
- 0 : ((priv->msgv->addr << 1) | (priv->flags & I2C_M_READ)));
+ /* Set ACK for receive mode */
+
+ if (priv->dcnt > 1 && (priv->flags & I2C_M_READ) != 0)
+ {
+ stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_ACK);
+ }
- /* Set ACK for receive mode */
+ /* Increment to next pointer and decrement message count */
- if (priv->dcnt > 1 && (priv->flags & I2C_M_READ) != 0)
- {
- stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_ACK);
+ priv->msgv++;
+ priv->msgc--;
}
-
- /* Increment to next pointer and decrement message count */
-
- priv->msgv++;
- priv->msgc--;
}
/* In 10-bit addressing mode, was first byte sent */