ALLOC_CACHE_ALIGN_BUFFER was called here in a way to alloc in stack a
possible huge quantity of memory depending on data transer size.

Es: loading kernel 8MB from eMMC we have
Transfer size:   0x800000
Block size:      0x200
Transfer blocks: 0x4000
struct size:     0x10
Stack allocation: ((0x200 / 8) + 1) * 0x10 = 0x8010 (~32KB)

Since this allocation is done on stack, there is no current way to get
an error on stack memory limit exceeded, overlapping heap space on
environments with very strict stack + heap limits like TPL or SPL (where
malloc size can be 16KB).
Results are silent corruptions of heap on mmc transfer and random errors
or CPU hang.

Using malloc_cache_aligned() we will alloc slightly bigger buffers
but we do have evidence about memory allocation failure allowing developer
to recognize the issue and take actions.

Signed-off-by: Alberto Panizzo <albe...@amarulasolutions.com>
---
 drivers/mmc/dw_mmc.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 13180fc..0126563 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -194,8 +194,9 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
 {
 #endif
        struct dwmci_host *host = mmc->priv;
-       ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac,
-                                data ? DIV_ROUND_UP(data->blocks, 8) : 0);
+       struct dwmci_idmac *cur_idmac =
+               malloc_cache_aligned(sizeof(struct dwmci_idmac) *
+                       (1 + (data ? DIV_ROUND_UP(data->blocks, 8) : 0)));
        int ret = 0, flags = 0, i;
        unsigned int timeout = 500;
        u32 retry = 100000;
@@ -203,10 +204,18 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
        ulong start = get_timer(0);
        struct bounce_buffer bbstate;
 
+       if (!cur_idmac) {
+               debug("%s: Cannot allocate 0x%x bytes\n", __func__,
+                     sizeof(struct dwmci_idmac) *
+                     (1 + (data ? DIV_ROUND_UP(data->blocks, 8) : 0)));
+               return -ENOMEM;
+       }
+
        while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
                if (get_timer(start) > timeout) {
                        debug("%s: Timeout on data busy\n", __func__);
-                       return -ETIMEDOUT;
+                       ret = -ETIMEDOUT;
+                       goto free_idmac;
                }
        }
 
@@ -238,8 +247,10 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
        if (data)
                flags = dwmci_set_transfer_mode(host, data);
 
-       if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
-               return -1;
+       if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) {
+               ret = -EIO;
+               goto free_idmac;
+       }
 
        if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
                flags |= DWMCI_CMD_ABORT_STOP;
@@ -272,7 +283,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
 
        if (i == retry) {
                debug("%s: Timeout.\n", __func__);
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto free_idmac;
        }
 
        if (mask & DWMCI_INTMSK_RTO) {
@@ -285,10 +297,12 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
                 * CMD8, please keep that in mind.
                 */
                debug("%s: Response Timeout.\n", __func__);
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto free_idmac;
        } else if (mask & DWMCI_INTMSK_RE) {
                debug("%s: Response Error.\n", __func__);
-               return -EIO;
+               ret = -EIO;
+               goto free_idmac;
        }
 
 
@@ -317,6 +331,9 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd 
*cmd,
 
        udelay(100);
 
+free_idmac:
+       free(cur_idmac);
+
        return ret;
 }
 
-- 
2.7.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to