ramips: mt7620: eMMC: stop invalid memory access if only one device is defined
authorAndré Draszik <git@andred.net>
Thu, 22 Feb 2018 10:21:46 +0000 (10:21 +0000)
committerMathias Kresin <dev@kresin.me>
Wed, 4 Apr 2018 06:29:17 +0000 (08:29 +0200)
pdev->id is -1 when only one device exists, and is used:
* as an index into drv_mode[] to determine whether to use
  PIO or DMA mode (via host->id)
* as an index into msdc_6575_host[], to store the
  mmc_priv() data.

Obviously, -1 is not a valid index in either case, causing
us to read invalid memory, and memory corruption,
respectively.

The invalid memory read is causing non-deterministic
behaviour, in particular in the v4.4 kernel it still
picked DMA mode, but in the v4.9 it now always picks
PIO mode.
Also, PIO mode doesn't work, causing the following:

/ # echo 3 > /proc/sys/vm/drop_caches
[ 3845.249237] sh (128): drop_caches: 3

/ # /root/usr/lib/libc.so
[ 3846.096070] do_page_fault(): sending SIGSEGV to libc.so for invalid read access from 7f9cb5a0
[ 3846.104758] epc = 779b0ea4 in libc.so[7792f000+c3000]
[ 3846.109907] ra  = 779a8004 in libc.so[7792f000+c3000]
Segmentation fault

/ # /root/usr/lib/libc.so
musl libc (mipsel-sf)
Version 1.1.16-git-40-g54807d47
Dynamic Program Loader
Usage: /root/usr/lib/libc.so [options] [--] pathname [args]

(i.e. initial page-in of any binary causes a segfault,
subsequent access works.)

While this change doesn't fix PIO mode, it at least makes
us deterministically use DMA (which works), and it also
stops us from corrupting memory.

Signed-off-by: André Draszik <git@andred.net>
target/linux/ramips/patches-4.14/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
target/linux/ramips/patches-4.9/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch

index aad6d598e0fc7b1688c59061710843970fe8571f..ef162d7acf6d3ac5f65a53069fa6a4c8383f2c1a 100644 (file)
@@ -1761,7 +1761,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 +
 --- /dev/null
 +++ b/drivers/mmc/host/mtk-mmc/sd.c
-@@ -0,0 +1,3066 @@
+@@ -0,0 +1,3068 @@
 +/* Copyright Statement:
 + *
 + * This software/firmware and related documentation ("MediaTek Software") are
@@ -4572,7 +4572,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 +    host = mmc_priv(mmc);
 +    host->hw        = hw;
 +    host->mmc       = mmc;
-+    host->id        = pdev->id;
++    BUG_ON(pdev->id < -1);
++    BUG_ON(pdev->id >= ARRAY_SIZE(drv_mode));
++    host->id        = (pdev->id == -1) ? 0 : pdev->id;
 +    host->error     = 0;
 +    host->irq       = irq;    
 +    host->base      = (unsigned long) base;
index 7dd25b1d40c9c335768f7821e96a031931a51ff4..da3c0772b5473c2a1f0184e5129c15e39eff3b1b 100644 (file)
@@ -1761,7 +1761,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 +
 --- /dev/null
 +++ b/drivers/mmc/host/mtk-mmc/sd.c
-@@ -0,0 +1,3066 @@
+@@ -0,0 +1,3068 @@
 +/* Copyright Statement:
 + *
 + * This software/firmware and related documentation ("MediaTek Software") are
@@ -4572,7 +4572,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 +    host = mmc_priv(mmc);
 +    host->hw        = hw;
 +    host->mmc       = mmc;
-+    host->id        = pdev->id;
++    BUG_ON(pdev->id < -1);
++    BUG_ON(pdev->id >= ARRAY_SIZE(drv_mode));
++    host->id        = (pdev->id == -1) ? 0 : pdev->id;
 +    host->error     = 0;
 +    host->irq       = irq;    
 +    host->base      = (unsigned long) base;