pxa2xx_spi: fix memory corruption
Subsystems (3)
PATCH 1/1 pxa2xx_spi: fix memory corruption
pxa2xx_spi_probe allocates struct driver_data and null_dma_buf at same time via spi_alloc_master(), but then calculates null_dma_buf pointer incorrectly, and it causes memory corruption later if DMA usage is enabled.
--- drivers/spi/pxa2xx_spi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/spi/pxa2xx_spi.c +1 -1
@@ -1569,7 +1569,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + + drv_data->null_dma_buf = (u32 *)ALIGN (((u32 )drv_data +sizeof (struct driver_data )),8 ); drv_data->ioaddr = ssp->mmio_base;
Signature · 1 line
1.7.5.rc3
PATCH 1/1 pxa2xx_spi: fix memory corruption
Quoted 15 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>--- drivers/spi/pxa2xx_spi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct · line 1573
Quoted 6 lines
drivers/spi/pxa2xx_spi.c +1
-1@@ -1569,7 +1569,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + + drv_data->null_dma_buf = (u32 *)ALIGN (((u32 )drv_data +sizeof (struct driver_data )),8 );
This thing looks a bit disturbing in itself. Like, where the heck is that thing pointing in the end ? Since some data are written to address in "null_dma_buf" ... isn't this just changing the corruption impact ?
Quoted 2 lines
drivers/spi/pxa2xx_spi.c +0
-0drv_data->ioaddr = ssp->mmio_base;
PATCH 1/1 pxa2xx_spi: fix memory corruption
Quoted 18 lines · Marek Vasut
Quoted 17 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>--- drivers/spi/pxa2xx_spi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -1569,7 +1569,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer;
Quoted 8 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1573
Quoted 4 lines
drivers/spi/pxa2xx_spi.c +1
-1drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + + drv_data->null_dma_buf = (u32 *)ALIGN (((u32 )drv_data +sizeof (struct driver_data )),8 );This thing looks a bit disturbing in itself. Like, where the heck is that thing pointing in the end ? Since some data are written to address in "
null_dma_buf" ... isn't this just changing the corruption impact ?
/* Allocate master with space for drv_data and null dma buffer */
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);So there's 16 bytes at the end of driver_data.
However:
(u32)(drv_data + sizeof(struct driver_data))
is pointer arithmetic. drv_data points at an object of sizeof(struct driver_data). Adding one to this increments the pointer by sizeof(struct driver_data) bytes. So the above expression increments the pointer by sizeof(struct driver_data)*sizeof(struct driver_data) bytes, which is obviously complete rubbish.
((u32)drv_data + sizeof(struct driver_data))
casts drv_data to a u32 first, then adds the sizeof(struct driver_data) which moves us into the 16 bytes allocated off the end of the struct.
PATCH 1/1 pxa2xx_spi: fix memory corruption
Quoted 46 lines · Russell King - ARM Linux
Quoted 21 lines · Marek Vasut
Quoted 20 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
drivers/spi/pxa2xx_spi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -1569,7 +1569,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type;Quoted 8 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
Quoted 4 lines
drivers/spi/pxa2xx_spi.c +1
-1- drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + + drv_data->null_dma_buf = (u32 *)ALIGN (((u32 )drv_data +sizeof (struct driver_data )),8 );This thing looks a bit disturbing in itself. Like, where the heck is that thing pointing in the end ? Since some data are written to address in "
null_dma_buf" ... isn't this just changing the corruption impact ?/* Allocate master with space for drv_data and null dma buffer */ master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);So there's 16 bytes at the end of
driver_data.However:
(u32)(drv_data +
sizeof(struct driver_data))is pointer arithmetic.
drv_datapoints at an object ofsizeof(struct driver_data). Adding one to this increments the pointer bysizeof(struct driver_data)bytes. So the above expression increments the pointer bysizeof(struct driver_data)*sizeof(structdriver_data) bytes, which is obviously complete rubbish.
Quoted 4 lines
((u32)drv_data +
sizeof(struct driver_data))casts
drv_datato a u32 first, then adds thesizeof(struct driver_data)which moves us into the 16 bytes allocated off the end of the struct.
The ptr arritmetic is clear, it was the 16 bytes after the structure I was missing ... if it's allocated there, it's fine. Thanks for clearing this.
PATCH 1/1 pxa2xx_spi: fix memory corruption
Quoted 47 lines · Marek Vasut
Quoted 46 lines · Russell King - ARM Linux
Quoted 24 lines · Marek Vasut
Quoted 23 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
drivers/spi/pxa2xx_spi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)drivers/spi/pxa2xx_spi.c +1
-1@@ -1569,7 +1569,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data + + drv_data->null_dma_buf = (u32 *)ALIGN(((u32)drv_data +Quoted 7 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1573
Quoted 1 line
drivers/spi/pxa2xx_spi.c +0
-0sizeof(struct driver_data)), 8);This thing looks a bit disturbing in itself. Like, where the heck is that thing pointing in the end ? Since some data are written to address in "
null_dma_buf" ... isn't this just changing the corruption impact ?/* Allocate master with space for drv_data and null dma buffer */ master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);So there's 16 bytes at the end of
driver_data.However:
(u32)(drv_data +sizeof(struct driver_data))is pointer arithmetic.
drv_datapoints at an object ofsizeof(struct driver_data). Adding one to this increments the pointer bysizeof(struct driver_data)bytes. So the above expression increments the pointer bysizeof(struct driver_data)*sizeof(structdriver_data) bytes, which is obviously complete rubbish.
Quoted 7 lines
Quoted 4 lines
((u32)drv_data +
sizeof(struct driver_data))casts
drv_datato a u32 first, then adds thesizeof(struct driver_data)which moves us into the 16 bytes allocated off the end of the struct.The ptr arritmetic is clear, it was the 16 bytes after the structure I was missing ... if it's allocated there, it's fine. Thanks for clearing this.
Actually ... why don't we just add char null_buf[16] at the end of the structure instead of allocating +16 bytes and then doing this strange crap ? Or even better ... kzalloc() the buffer in probe(), then kfree() it in remove()?
PATCH v2 1/1 pxa2xx_spi: fix memory corruption
pxa2xx_spi_probe allocates struct driver_data and null_dma_buf at same time via spi_alloc_master(), but then calculates null_dma_buf pointer incorrectly, and it causes memory corruption later if DMA usage is enabled.
---
v2: - add u8 __null_dma_buf[16] to the end of driver_data structure
and use it as null_dma_buf after alignment.
- use PTR_ALIGN instead of ALIGN
drivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/spi/pxa2xx_spi.c +5 -4
@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 __null_dma_buf[16 ];/* SSP register addresses */ void __iomem *ioaddr;
@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)return -ENODEV ; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);
@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN ((u8 *)drv_data->__null_dma_buf,8 ); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
Signature · 1 line
1.7.5.rc3
PATCH v2 1/1 pxa2xx_spi: fix memory corruption
Quoted 18 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructure
and use it asnull_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGNdrivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 4 lines
drivers/spi/pxa2xx_spi.c +1
-0@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 __null_dma_buf[16 ];
Ah, please don't name it starting with two underscores.
Quoted 15 lines
drivers/spi/pxa2xx_spi.c +2
-2/* SSP register addresses */ void __iomem *ioaddr;@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) return -ENODEV; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct · line 1574
Quoted 7 lines
drivers/spi/pxa2xx_spi.c +2
-2@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN ((u8 *)drv_data->__null_dma_buf,8 );
Do you need that (u8 *) cast there ?
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
from linux/kernel.h line 42
Quoted 3 lines
drivers/spi/pxa2xx_spi.c +0
-0drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
PATCH v2 1/1 pxa2xx_spi: fix memory corruption
Quoted 22 lines · On Sunday 10 July 2011 15:43:41 Marek Vasut wrote:
Quoted 21 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructureand use it as
null_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGNdrivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -106,6 +106,7 @@ struct driver_data {
Quoted 7 lines
drivers/spi/pxa2xx_spi.c struct driver_data {
Quoted 5 lines
drivers/spi/pxa2xx_spi.c +1
-0int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 __null_dma_buf[16 ];Ah, please don't name it starting with two underscores.
Ok, what name do you suggest?
Quoted 21 lines
Quoted 21 lines
drivers/spi/pxa2xx_spi.c +0
-0/* SSP register addresses */ drivers/spi/pxa2xx_spi.c +2
-2void __iomem *ioaddr;@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) return -ENODEV; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {drivers/spi/pxa2xx_spi.c +0
-0dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer;
Quoted 8 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1574
Quoted 6 lines
drivers/spi/pxa2xx_spi.c +2
-2drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN ((u8 *)drv_data->__null_dma_buf,8 );Do you need that (u8 *) cast there ?
Yes, cast is necessary here, otherwise:
drivers/spi/pxa2xx_spi.c:1574:10: error: cast specifies array type
Quoted 6 lines
#define
PTR_ALIGN(p, a)((typeof(p))ALIGN((unsigned long)(p), (a)))from
linux/kernel.hline 42Quoted 2 lines
drivers/spi/pxa2xx_spi.c +0
-0drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
pxa2xx_spi_probe allocates struct driver_data and null_dma_buf at same time via spi_alloc_master(), but then calculates null_dma_buf pointer incorrectly, and it causes memory corruption later if DMA usage is enabled.
---
v2: - add u8 __null_dma_buf[16] to the end of driver_data structure
and use it as null_dma_buf after alignment.
- use PTR_ALIGN instead of ALIGN
v3: - drop (u8 *) cast, use & operator instead, change array name
drivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/spi/pxa2xx_spi.c +5 -4
@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];/* SSP register addresses */ void __iomem *ioaddr;
@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)return -ENODEV ; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);
@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 ); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
Signature · 1 line
1.7.5.rc3
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 4 lines · On Sunday 10 July 2011 18:18:19 Vasily Khoruzhick wrote:
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.
Ping?
Quoted 43 lines
Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructure
and use it asnull_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGN
v3: - drop (u8 *) cast, use & operator instead, change array namedrivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +5
-4@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];/* SSP register addresses */ void __iomem *ioaddr;@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) return -ENODEV; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 ); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 7 lines · On Sunday 10 July 2011 18:18:19 Vasily Khoruzhick wrote:
Quoted 4 lines
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Ping?
Pong!
Quoted 44 lines
Quoted 44 lines
Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructure and use it asnull_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGN
v3: - drop (u8 *) cast, use & operator instead, change array namedrivers/spi/pxa2xx_spi.c|? ? ? 9 +++++----1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +1
-0@@ -106,6 +106,7 @@ struct driver_data { ??? int rx_channel; ??? int tx_channel; ??? u32 *null_dma_buf; +??? u8 null_dma_buf_unaligned[16];??? /* SSP register addresses */
??? void__iomem*ioaddr;drivers/spi/pxa2xx_spi.c +4
-4@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) return -ENODEV; ??? } -??? /* Allocate master with space for drv_data and null dma buffer */ -??? master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); +??? /* Allocate master with space for drv_data */ +??? master = spi_alloc_master(dev, sizeof(struct driver_data)); ??? if (!master) { ??? ??? dev_err(&pdev->dev, "cannot alloc spi_master\n"); ??? ??? pxa_ssp_free(ssp);@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; ??? drv_data->ssp_type = ssp->type; -??? drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data + -??? ??? ??? ??? ??? ??? sizeof(struct driver_data)), 8); +??? drv_data->null_dma_buf = +??? ??? (u32 *)PTR_ALIGN(&drv_data->null_dma_buf_unaligned, 8); ??? drv_data->ioaddr = ssp->mmio_base; ??? drv_data->ssdr_physical = ssp->phys_base + SSDR;
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
In reply to Vasily KhoruzhickQuoted 19 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructure
and use it asnull_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGN
v3: - drop (u8 *) cast, use & operator instead, change array namedrivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 4 lines
drivers/spi/pxa2xx_spi.c +1
-0@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];
Don't dma buffers need to be cache-line aligned? How large is the actual transfer? Using the __aligned() or __cacheline_aligned attribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around with PTR_ALIGN or anything.
g.
Quoted 28 lines
drivers/spi/pxa2xx_spi.c +4
-4/* SSP register addresses */ void __iomem *ioaddr;@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)return -ENODEV ; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 ); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;Signature · 1 line
1.7.5.rc3
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 7 lines · Grant Likely
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 1 line
drivers/spi/pxa2xx_spi.c +1
-0+u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned? How large is the actual transfer? Using the
__aligned()or__cacheline_alignedattribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.
Err, did you not read the whole patch?
Quoted 2 lines
Quoted 2 lines
drivers/spi/pxa2xx_spi.c +2
-0+ drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 );
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 9 lines · Russell King - ARM Linux
Quoted 7 lines · Grant Likely
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 1 line
drivers/spi/pxa2xx_spi.c +1
-0+u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned? How large is the actual transfer? Using the
__aligned()or__cacheline_alignedattribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.
Quoted 4 lines
Err, did you not read the whole patch?
Quoted 2 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1574
Quoted 2 lines
drivers/spi/pxa2xx_spi.c +2
-0+ drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 );
I read a lot of patches yesterday. I may very well have missed something. I still don't see what you're referring to though. If the __aligned() was used inside the structure definition, then there would be no need to have both the null_dma_buf pointer and the null_dma_buf_unaligned buffer. It would just be a correctly aligned null_dma_buf.
Plus, I was asking about whether it was valid to use the structure as allocated in DMA operations since it may very well end up in the same cache line as the allocated structure. Firstly, that could mean DMA and the cache referencing the same memory which could cause corruption, and secondly on ARM isn't it a problem to have DMA buffers in memory that is also cache mapped?
That said, I've not read the entire driver, so I haven't checked null_dma_buffer is used in a real dma operation.
g.
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 12 lines · Grant Likely
Quoted 11 lines · Russell King - ARM Linux
Quoted 7 lines · Grant Likely
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 1 line
drivers/spi/pxa2xx_spi.c +1
-0+u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned? How large is the actual transfer? Using the
__aligned()or__cacheline_alignedattribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.Err, did you not read the whole patch?
Quoted 9 lines
Quoted 2 lines
Quoted 2 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1574
Quoted 2 lines
drivers/spi/pxa2xx_spi.c +2
-0+ drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 );I read a lot of patches yesterday. I may very well have missed something. I still don't see what you're referring to though. If the
__aligned()was used inside the structure definition, then there would be no need to have both thenull_dma_bufpointer and thenull_dma_buf_unalignedbuffer. It would just be a correctly alignednull_dma_buf.
That depends on the alignment guarantees from kmalloc, which may not be 8 bytes - we have this:
#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) #define ARCH_SLAB_MINALIGN 8
#endif
so presumably on !AEABI or arches < ARMv5, kmalloc _can_ return less than 8 byte alignments. Which makes using __aligned() in the definition useless.
Quoted 6 lines
Plus, I was asking about whether it was valid to use the structure as allocated in DMA operations since it may very well end up in the same cache line as the allocated structure. Firstly, that could mean DMA and the cache referencing the same memory which could cause corruption, and secondly on ARM isn't it a problem to have DMA buffers in memory that is also cache mapped?
For the second point, that depends on whether you're talking about the coherent stuff or the streaming stuff.
The coherent DMA API has entirely different semantics to streaming DMA API. The coherent DMA API allows for simultaneous access to the buffer by both the DMA device and the host CPU.
The streaming DMA API only allows exclusive access by either the DMA device or the host CPU.
Therefore, with the streaming DMA API, the only thing that's required is to ensure that data is visible in some manner to the DMA device. If the DMA device can read from the CPU cache, then probably nothing's required. If not, then the data must be evicted from as many levels of cache that are necessary to make it visible. Conversely, for DMA writes, what matters is the visibility of the data to the host CPU.
That approach does not work with the coherent DMA API. Take a network driver TX ring. Consider the effect of the following series of actions to see why it won't work:
- host CPU reads a word from the DMA buffer. This brings in a whole cache line.
- network device writes to the previous descriptor (which overlaps the just read cache line) to change its status
- host CPU updates the next descriptor and writes the cache line back XXX overwriting the network device's write to the previous descriptor.
So, coherent DMA is special because there's no exclusiveness there.
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 50 lines · Russell King - ARM Linux
Quoted 12 lines · Grant Likely
Quoted 11 lines · Russell King - ARM Linux
Quoted 7 lines · Grant Likely
drivers/spi/pxa2xx_spi.c struct driver_data { · line 109
Quoted 1 line
drivers/spi/pxa2xx_spi.c +1
-0+u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned? How large is the actual transfer? Using the
__aligned()or__cacheline_alignedattribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.Err, did you not read the whole patch?
Quoted 9 lines
Quoted 2 lines
Quoted 2 lines
drivers/spi/pxa2xx_spi.c static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) · line 1574
Quoted 2 lines
drivers/spi/pxa2xx_spi.c +2
-0+ drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 );I read a lot of patches yesterday. I may very well have missed something. I still don't see what you're referring to though. If the
__aligned()was used inside the structure definition, then there would be no need to have both thenull_dma_bufpointer and thenull_dma_buf_unalignedbuffer. It would just be a correctly alignednull_dma_buf.That depends on the alignment guarantees from kmalloc, which may not be 8 bytes - we have this:
#if
defined(CONFIG_AEABI)&& (__LINUX_ARM_ARCH__>= 5) #defineARCH_SLAB_MINALIGN8
#endifso presumably on !AEABI or arches < ARMv5, kmalloc _can_ return less than 8 byte alignments. Which makes using
__aligned()in the definition useless.Quoted 6 lines
Plus, I was asking about whether it was valid to use the structure as allocated in DMA operations since it may very well end up in the same cache line as the allocated structure. Firstly, that could mean DMA and the cache referencing the same memory which could cause corruption, and secondly on ARM isn't it a problem to have DMA buffers in memory that is also cache mapped?
For the second point, that depends on whether you're talking about the coherent stuff or the streaming stuff.
The coherent DMA API has entirely different semantics to streaming DMA API. The coherent DMA API allows for simultaneous access to the buffer by both the DMA device and the host CPU.
The streaming DMA API only allows exclusive access by either the DMA device or the host CPU.
Quoted 6 lines
Therefore, with the streaming DMA API, the only thing that's required is to ensure that data is visible in some manner to the DMA device. If the DMA device can read from the CPU cache, then probably nothing's required. If not, then the data must be evicted from as many levels of cache that are necessary to make it visible. Conversely, for DMA writes, what matters is the visibility of the data to the host CPU.
... plus care must be taken not to accidentally reload the line into cache after it has been pushed out for DMA, which is a risk on structures with embedded DMA buffers if other non-DMA elements end up in the same cache line. This is the situation I was wondering about.
Of course, as you mention, if the DMA hw is cache-coherent, this isn't a problem.
g.
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 4 lines · Grant Likely
... plus care must be taken not to accidentally reload the line into cache after it has been pushed out for DMA, which is a risk on structures with embedded DMA buffers if other non-DMA elements end up in the same cache line. This is the situation I was wondering about.
I don't think it matters one bit in this case - we're not caring about the actual data read/written in the DMA, we just need to do DMA to keep the controller happy. That's especially true as we don't set the address increment bit in the DMA command register, so we end up accessing the same RAM location time and time again for each DMA transfer.
So please, merge the patch - it fixes a serious memory-scribbling bug.
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
In reply to Grant LikelyQuoted 24 lines · On Friday 15 July 2011 05:53:31 Grant Likely wrote:
Quoted 23 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructureand use it as
null_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGNv3: - drop (u8 *) cast, use & operator instead, change array name
drivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -106,6 +106,7 @@ struct driver_data {
Quoted 7 lines
drivers/spi/pxa2xx_spi.c struct driver_data {
Quoted 5 lines
drivers/spi/pxa2xx_spi.c +1
-0int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned?
No, on PXA2xx they need to be 8-bytes aligned (according to PXA27x developer's manual)
Quoted 1 line
How large is the actual transfer?
Looks like 8 bytes, but I'm not sure, I'm not author of driver and did not dig deeply into its code. Just attempting to fix memory corruption.
Quoted 4 lines
Using the
__aligned()or__cacheline_aligned
attribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.
Errr, it can't be applied to struct field, right? But driver needs per-device null_dma_buf (there's 3 SPI controllers on PXA2xx)
Quoted 1 line
g.
Regards
Vasily
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 46 lines · Vasily Khoruzhick
Quoted 24 lines · On Friday 15 July 2011 05:53:31 Grant Likely wrote:
Quoted 23 lines · Vasily Khoruzhick
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructureand use it as
null_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGNv3: - drop (u8 *) cast, use & operator instead, change array name
drivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -106,6 +106,7 @@ struct driver_data {Quoted 7 lines
drivers/spi/pxa2xx_spi.c struct driver_data {
Quoted 5 lines
drivers/spi/pxa2xx_spi.c +1
-0int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned?
No, on PXA2xx they need to be 8-bytes aligned (according to PXA27x developer's manual)
Quoted 1 line
How large is the actual transfer?
Looks like 8 bytes, but I'm not sure, I'm not author of driver and did not dig deeply into its code. Just attempting to fix memory corruption.
Quoted 4 lines
Using the
__aligned()or__cacheline_aligned
attribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.
Quoted 7 lines
Errr, it can't be applied to struct field, right? But driver needs per-device
null_dma_buf(there's 3 SPI controllers on PXA2xx)Quoted 1 line
g.
Regards
Vasily
So, any chance to see this patch merged?
Regards
Vasily
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
Quoted 52 lines · Vasily Khoruzhick
Quoted 51 lines · On Friday 15 July 2011 05:53:31 Grant Likely wrote:
Quoted 24 lines · Vasily Khoruzhick
Quoted 23 lines
pxa2xx_spi_probeallocates structdriver_dataandnull_dma_bufat same time viaspi_alloc_master(), but then calculatesnull_dma_bufpointer incorrectly, and it causes memory corruption later if DMA usage is enabled.Signed-off-by Vasily Khoruzhick <[email protected]>---
v2: - add u8 __null_dma_buf[16] to the end ofdriver_datastructureand use it as
null_dma_bufafter alignment.
- usePTR_ALIGNinstead of ALIGNv3: - drop (u8 *) cast, use & operator instead, change array name
drivers/spi/pxa2xx_spi.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/spi/pxa2xx_spi.c +0
-0@@ -106,6 +106,7 @@ struct driver_data {Quoted 7 lines
drivers/spi/pxa2xx_spi.c struct driver_data {
Quoted 5 lines
drivers/spi/pxa2xx_spi.c +1
-0int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];Don't dma buffers need to be cache-line aligned?
No, on PXA2xx they need to be 8-bytes aligned (according to PXA27x developer's manual)
Quoted 1 line
How large is the actual transfer?
Looks like 8 bytes, but I'm not sure, I'm not author of driver and did not dig deeply into its code. Just attempting to fix memory corruption.
Quoted 4 lines
Using the
__aligned()or__cacheline_aligned
attribute is the correct way to make sure you've got a data buffer that can be used for DMA mixed with other stuff. Then you don't need to fool around withPTR_ALIGNor anything.Errr, it can't be applied to struct field, right? But driver needs per-device
null_dma_buf(there's 3 SPI controllers on PXA2xx)Quoted 1 line
g.
Quoted 7 lines
Quoted 2 lines
Regards
VasilySo, any chance to see this patch merged?
Regards
Vasily
I have no idea, were all problems addressed ?
M
PATCH v3 1/1 pxa2xx_spi: fix memory corruption
In reply to Vasily KhoruzhickQuoted 1 line
So, any chance to see this patch merged?
Can you resend please (with acks you may have received meanwhile)?
Regards,
Wolfram
Signature · 9 lines
Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20111207/ce314488/attachment.sig>
PATCH RESEND v3 1/1 pxa2xx_spi: fix memory corruption
pxa2xx_spi_probe allocates struct driver_data and null_dma_buf at same time via spi_alloc_master(), but then calculates null_dma_buf pointer incorrectly, and it causes memory corruption later if DMA usage is enabled.
---
v2: - add u8 __null_dma_buf[16] to the end of driver_data structure
and use it as null_dma_buf after alignment.
- use PTR_ALIGN instead of ALIGN
v3: - drop (u8 *) cast, use & operator instead, change array name
drivers/spi/spi-pxa2xx.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/spi/spi-pxa2xx.c +5 -4
@@ -106,6 +106,7 @@ struct driver_data {int rx_channel;int tx_channel;u32 *null_dma_buf; +u8 null_dma_buf_unaligned[16 ];/* SSP register addresses */ void __iomem *ioaddr;
@@ -1543,8 +1544,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)return -ENODEV ; } -/* Allocate master with space for drv_data and null dma buffer */ - master =spi_alloc_master (dev,sizeof (struct driver_data ) +16 ); +/* Allocate master with space for drv_data */ + master =spi_alloc_master (dev,sizeof (struct driver_data ));if (!master) {dev_err (&pdev->dev,"cannot alloc spi_master\n" );pxa_ssp_free (ssp);
@@ -1569,8 +1570,8 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev) master->transfer = transfer; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)ALIGN ((u32)(drv_data + -sizeof (struct driver_data )),8 ); + drv_data->null_dma_buf = + (u32 *)PTR_ALIGN (&drv_data->null_dma_buf_unaligned,8 ); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base +SSDR ;
Signature · 1 line
1.7.8