This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit d07a03cf8a6918aecd953ae741d6475ef875ccfe
Author: Swatantra Yadav <[email protected]>
AuthorDate: Sat Oct 24 19:38:12 2026 +0530

    arch/arm/imx9: guard split serial TX DMA transfer with nlength > 0
    
    Check that both dev->dmatx.nbuffer != NULL and dev->dmatx.nlength > 0
    before configuring the second transfer descriptor. This defends against
    configuring an illegal descriptor with iter = 0 (CITER = 0 on eDMA) in
    case a zero-length second segment is passed.
    
    Also fix nxstyle indentation of switch case labels in imx9_ioctl.
    
    Signed-off-by: Swatantra Yadav <[email protected]>
---
 arch/arm/src/imx9/imx9_lpuart.c | 443 ++++++++++++++++++++--------------------
 1 file changed, 222 insertions(+), 221 deletions(-)

diff --git a/arch/arm/src/imx9/imx9_lpuart.c b/arch/arm/src/imx9/imx9_lpuart.c
index 2dbf5cde27f..4322ae02b81 100644
--- a/arch/arm/src/imx9/imx9_lpuart.c
+++ b/arch/arm/src/imx9/imx9_lpuart.c
@@ -1121,6 +1121,7 @@ static inline void imx9_serialout(struct imx9_uart_s 
*priv,
 static int imx9_dma_nextrx(struct imx9_uart_s *priv)
 {
   int dmaresidual = imx9_dmach_getcount(priv->rxdma);
+
   DEBUGASSERT(dmaresidual <= RXDMA_BUFFER_SIZE);
 
   return (RXDMA_BUFFER_SIZE - dmaresidual) % RXDMA_BUFFER_SIZE;
@@ -1602,8 +1603,8 @@ static int imx9_ioctl(struct file *filep, int cmd, 
unsigned long arg)
 {
 #if defined(CONFIG_SERIAL_TIOCSERGSTRUCT)   || \
     defined(CONFIG_SERIAL_TERMIOS)          || \
-    defined(CONFIG_IMX9_LPUART_SINGLEWIRE ) || \
-    defined(CONFIG_IMX9_LPUART_INVERT )
+    defined(CONFIG_IMX9_LPUART_SINGLEWIRE)  || \
+    defined(CONFIG_IMX9_LPUART_INVERT)
   struct inode *inode = filep->f_inode;
   struct uart_dev_s *dev = inode->i_private;
   irqstate_t flags;
@@ -1613,271 +1614,271 @@ static int imx9_ioctl(struct file *filep, int cmd, 
unsigned long arg)
   switch (cmd)
     {
 #ifdef CONFIG_SERIAL_TIOCSERGSTRUCT
-    case TIOCSERGSTRUCT:
-      {
-         struct imx9_uart_s *user = (struct imx9_uart_s *)arg;
-         if (!user)
-           {
-             ret = -EINVAL;
-           }
-         else
-           {
-             memcpy(user, dev, sizeof(struct imx9_uart_s));
-           }
-       }
-       break;
+      case TIOCSERGSTRUCT:
+        {
+          struct imx9_uart_s *user = (struct imx9_uart_s *)arg;
+
+          if (!user)
+            {
+              ret = -EINVAL;
+            }
+          else
+            {
+              memcpy(user, dev, sizeof(struct imx9_uart_s));
+            }
+        }
+        break;
 #endif
 
 #ifdef CONFIG_SERIAL_TERMIOS
-    case TCGETS:
-      {
-        struct termios  *termiosp = (struct termios *)arg;
-        struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+      case TCGETS:
+        {
+          struct termios *termiosp = (struct termios *)arg;
+          struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
 
-        if (!termiosp)
-          {
-            ret = -EINVAL;
-            break;
-          }
+          if (!termiosp)
+            {
+              ret = -EINVAL;
+              break;
+            }
 
-        /* Return parity */
+          /* Return parity */
 
-        termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) |
-                            ((priv->parity == 1) ? PARODD : 0);
+          termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) |
+                              ((priv->parity == 1) ? PARODD : 0);
 
-        /* Return stop bits */
+          /* Return stop bits */
 
-        termiosp->c_cflag |= priv->stopbits2 ? CSTOPB : 0;
+          termiosp->c_cflag |= priv->stopbits2 ? CSTOPB : 0;
 
-        /* Return flow control */
+          /* Return flow control */
 
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
-        termiosp->c_cflag |= (priv->oflow ? CCTS_OFLOW : 0);
-
+          termiosp->c_cflag |= (priv->oflow ? CCTS_OFLOW : 0);
 #endif
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
-        termiosp->c_cflag |= (priv->iflow ? CRTS_IFLOW : 0);
+          termiosp->c_cflag |= (priv->iflow ? CRTS_IFLOW : 0);
 #endif
-        /* Return baud */
+          /* Return baud */
 
-        cfsetispeed(termiosp, priv->baud);
+          cfsetispeed(termiosp, priv->baud);
 
-        /* Return number of bits */
+          /* Return number of bits */
 
-        switch (priv->bits)
-          {
-          case 5:
-            termiosp->c_cflag |= CS5;
-            break;
+          switch (priv->bits)
+            {
+              case 5:
+                termiosp->c_cflag |= CS5;
+                break;
 
-          case 6:
-            termiosp->c_cflag |= CS6;
-            break;
+              case 6:
+                termiosp->c_cflag |= CS6;
+                break;
 
-          case 7:
-            termiosp->c_cflag |= CS7;
-            break;
+              case 7:
+                termiosp->c_cflag |= CS7;
+                break;
 
-          default:
-          case 8:
-            termiosp->c_cflag |= CS8;
-            break;
+              default:
+              case 8:
+                termiosp->c_cflag |= CS8;
+                break;
 
 #if defined(CS9)
-          case 9:
-            termiosp->c_cflag |= CS9;
-            break;
+              case 9:
+                termiosp->c_cflag |= CS9;
+                break;
 #endif
-          }
-      }
-      break;
+            }
+        }
+        break;
 
-    case TCSETS:
-      {
-        struct termios  *termiosp = (struct termios *)arg;
-        struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
-        uint32_t baud;
-        uint32_t ie;
-        uint8_t parity;
-        uint8_t nbits;
-        bool stop2;
-
-        if ((!termiosp)
+      case TCSETS:
+        {
+          struct termios *termiosp = (struct termios *)arg;
+          struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+          uint32_t baud;
+          uint32_t ie;
+          uint8_t parity;
+          uint8_t nbits;
+          bool stop2;
+
+          if ((!termiosp)
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
-            || ((termiosp->c_cflag & CCTS_OFLOW) && !priv->usects)
+              || ((termiosp->c_cflag & CCTS_OFLOW) && !priv->usects)
 #endif
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
-            || ((termiosp->c_cflag & CRTS_IFLOW) && !priv->userts)
+              || ((termiosp->c_cflag & CRTS_IFLOW) && !priv->userts)
 #endif
-            )
-          {
-            ret = -EINVAL;
-            break;
-          }
+             )
+            {
+              ret = -EINVAL;
+              break;
+            }
 
-        /* Decode baud. */
+          /* Decode baud. */
 
-        ret = OK;
-        baud = cfgetispeed(termiosp);
+          ret = OK;
+          baud = cfgetispeed(termiosp);
 
-        /* Decode number of bits */
+          /* Decode number of bits */
 
-        switch (termiosp->c_cflag & CSIZE)
-          {
-          case CS5:
-            nbits = 5;
-            break;
+          switch (termiosp->c_cflag & CSIZE)
+            {
+              case CS5:
+                nbits = 5;
+                break;
 
-          case CS6:
-            nbits = 6;
-            break;
+              case CS6:
+                nbits = 6;
+                break;
 
-          case CS7:
-            nbits = 7;
-            break;
+              case CS7:
+                nbits = 7;
+                break;
 
-          case CS8:
-            nbits = 8;
-            break;
+              case CS8:
+                nbits = 8;
+                break;
 
 #if defined(CS9)
-          case CS9:
-            nbits = 9;
-            break;
-#endif
-          default:
-            ret = -EINVAL;
-            break;
-          }
-
-        /* Decode parity */
-
-        if ((termiosp->c_cflag & PARENB) != 0)
-          {
-            parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
-          }
-        else
-          {
-            parity = 0;
-          }
-
-        /* Decode stop bits */
-
-        stop2 = (termiosp->c_cflag & CSTOPB) != 0;
-
-        /* Verify that all settings are valid before committing */
-
-        if (ret == OK)
-          {
-            /* Commit */
-
-            priv->baud      = baud;
-            priv->parity    = parity;
-            priv->bits      = nbits;
-            priv->stopbits2 = stop2;
-            priv->oflow     = (termiosp->c_cflag & CCTS_OFLOW) != 0;
-            priv->iflow     = (termiosp->c_cflag & CRTS_IFLOW) != 0;
-
-            /* effect the changes immediately - note that we do not
-             * implement TCSADRAIN / TCSAFLUSH
-             */
-
-            flags = spin_lock_irqsave(&priv->lock);
-            imx9_disableuartint_nolock(priv, &ie);
-            ret = dev->ops->setup(dev);
-
-            /* Restore the interrupt state */
-
-            imx9_restoreuartint_nolock(priv, ie);
-            priv->ie = ie;
-            spin_unlock_irqrestore(&priv->lock, flags);
-          }
-      }
-      break;
+              case CS9:
+                nbits = 9;
+                break;
+#endif
+              default:
+                ret = -EINVAL;
+                break;
+            }
+
+          /* Decode parity */
+
+          if ((termiosp->c_cflag & PARENB) != 0)
+            {
+              parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
+            }
+          else
+            {
+              parity = 0;
+            }
+
+          /* Decode stop bits */
+
+          stop2 = (termiosp->c_cflag & CSTOPB) != 0;
+
+          /* Verify that all settings are valid before committing */
+
+          if (ret == OK)
+            {
+              /* Commit */
+
+              priv->baud      = baud;
+              priv->parity    = parity;
+              priv->bits      = nbits;
+              priv->stopbits2 = stop2;
+              priv->oflow     = (termiosp->c_cflag & CCTS_OFLOW) != 0;
+              priv->iflow     = (termiosp->c_cflag & CRTS_IFLOW) != 0;
+
+              /* effect the changes immediately - note that we do not
+               * implement TCSADRAIN / TCSAFLUSH
+               */
+
+              flags = spin_lock_irqsave(&priv->lock);
+              imx9_disableuartint_nolock(priv, &ie);
+              ret = dev->ops->setup(dev);
+
+              /* Restore the interrupt state */
+
+              imx9_restoreuartint_nolock(priv, ie);
+              priv->ie = ie;
+              spin_unlock_irqrestore(&priv->lock, flags);
+            }
+        }
+        break;
 #endif /* CONFIG_SERIAL_TERMIOS */
 
 #ifdef CONFIG_IMX9_LPUART_SINGLEWIRE
-    case TIOCSSINGLEWIRE:
-      {
-        uint32_t regval;
-        struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+      case TIOCSSINGLEWIRE:
+        {
+          uint32_t regval;
+          struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
 
-        flags  = spin_lock_irqsave(&priv->lock);
-        regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+          flags  = spin_lock_irqsave(&priv->lock);
+          regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
 
-        if ((arg & SER_SINGLEWIRE_ENABLED) != 0)
-          {
-            regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC;
-          }
-        else
-          {
-            regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC);
-          }
+          if ((arg & SER_SINGLEWIRE_ENABLED) != 0)
+            {
+              regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC;
+            }
+          else
+            {
+              regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC);
+            }
 
-        imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+          imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
 
-        spin_unlock_irqrestore(&priv->lock, flags);
-      }
-      break;
+          spin_unlock_irqrestore(&priv->lock, flags);
+        }
+        break;
 #endif
 
 #ifdef CONFIG_IMX9_LPUART_INVERT
-    case TIOCSINVERT:
-      {
-        uint32_t ctrl;
-        uint32_t stat;
-        uint32_t regval;
-        struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
-
-        flags  = spin_lock_irqsave(&priv->lock);
-        ctrl   = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
-        stat   = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
-        regval = ctrl;
-
-        /* {R|T}XINV bit field can only be written when the receiver is
-        * disabled (RE=0).
-        */
-
-        regval &= ~LPUART_CTRL_RE;
-
-        imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
-
-        /* Enable/disable signal inversion. */
-
-        if (arg & SER_INVERT_ENABLED_RX)
-          {
-            stat |= LPUART_STAT_RXINV;
-          }
-        else
-          {
-            stat &= ~LPUART_STAT_RXINV;
-          }
-
-        /* Do not invert TX when in TIOCSSINGLEWIRE */
-
-        if ((arg & SER_INVERT_ENABLED_TX) &&
-            ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS))
-          {
-            ctrl |= LPUART_CTRL_TXINV;
-          }
-        else
-          {
-            ctrl &= ~LPUART_CTRL_TXINV;
-          }
-
-        imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, stat);
-        imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, ctrl);
-
-        spin_unlock_irqrestore(&priv->lock, flags);
-      }
-      break;
-#endif
-
-    case TIOCSBRK:  /* BSD compatibility: Turn break on, unconditionally */
-    case TIOCCBRK:  /* BSD compatibility: Turn break off, unconditionally */
-    default:
-      ret = -ENOTTY;
-      break;
+      case TIOCSINVERT:
+        {
+          uint32_t ctrl;
+          uint32_t stat;
+          uint32_t regval;
+          struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+          flags  = spin_lock_irqsave(&priv->lock);
+          ctrl   = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+          stat   = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+          regval = ctrl;
+
+          /* {R|T}XINV bit field can only be written when the receiver is
+           * disabled (RE=0).
+           */
+
+          regval &= ~LPUART_CTRL_RE;
+
+          imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+
+          /* Enable/disable signal inversion. */
+
+          if (arg & SER_INVERT_ENABLED_RX)
+            {
+              stat |= LPUART_STAT_RXINV;
+            }
+          else
+            {
+              stat &= ~LPUART_STAT_RXINV;
+            }
+
+          /* Do not invert TX when in TIOCSSINGLEWIRE */
+
+          if ((arg & SER_INVERT_ENABLED_TX) &&
+              ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS))
+            {
+              ctrl |= LPUART_CTRL_TXINV;
+            }
+          else
+            {
+              ctrl &= ~LPUART_CTRL_TXINV;
+            }
+
+          imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, stat);
+          imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, ctrl);
+
+          spin_unlock_irqrestore(&priv->lock, flags);
+        }
+        break;
+#endif
+
+      case TIOCSBRK:  /* BSD compatibility: Turn break on, unconditionally */
+      case TIOCCBRK:  /* BSD compatibility: Turn break off, unconditionally */
+      default:
+        ret = -ENOTTY;
+        break;
     }
 
   return ret;
@@ -2262,7 +2263,7 @@ static void imx9_dma_send(struct uart_dev_s *dev)
 #if CONFIG_IMX9_EDMA_NTCD > 1
   /* Is this a split transfer? */
 
-  if (dev->dmatx.nbuffer)
+  if (dev->dmatx.nbuffer != NULL && dev->dmatx.nlength > 0)
     {
       config.iter   = priv->dev.dmatx.nlength;
       config.saddr  = (uintptr_t)priv->dev.dmatx.nbuffer;

Reply via email to