diff mbox

[U-Boot] static var mem alignment issue/question

Message ID yw1xziki5w3t.fsf@unicorn.mansr.com
State RFC
Delegated to: Tom Rini
Headers show

Commit Message

Måns Rullgård Nov. 29, 2016, 12:06 p.m. UTC
Tim Harvey <tharvey@gateworks.com> writes:

> Greetings,
>
> In debugging an issue with a rather old branch of U-Boot (2015-04) I
> found that the static assignment of a data buffer was not 32-bit
> aligned which caused data aborts. However I find that current U-boot
> master does not suffer this issue and no matter what I declare static
> before the particular variable its always 32-bit aligned. I don't see
> any code changes that would cause this and in both cases I'm building
> with the same gcc5.2.0 toolchain.
>
> The code in question is this this from cmd/fdt.c:
>
>         } else if (argv[1][0] == 's') {
>                 char *pathp;            /* path */
>                 char *prop;             /* property */
>                 int  nodeoffset;        /* node offset from libfdt */
>                 static char data[SCRATCHPAD];   /* storage for the property */
>                 int  len;               /* new length of the property */
>                 int  ret;
>
> What guarantee's that 'data' above is 32-bit aligned in master that is
> missing from the older U-Boot branch I'm using? Perhaps there is some
> arg in a Makefile that I'm missing?

There are no such guarantees.  Things often end up 4-byte aligned by
chance simply because most of them are a multiple of 4 bytes in size.
The code should be fixed, either by explicitly aligning the buffer or by
using the put_unaligned_b32() accessor in fdt_parse_prop().  Here's an
untested patch:

From 714f6a16062cc43e9aadfba29b295365fd4926de Mon Sep 17 00:00:00 2001
From: Mans Rullgard <mans@mansr.com>
Date: Tue, 29 Nov 2016 11:59:37 +0000
Subject: [PATCH] cmd/fdt: fix unaligned memory access

The buffer passed to fdt_parse_prop() might be unaligned.  Use the
proper access helper when writing 32-bit values.

Signed-off-by: Mans Rullgard <mans@mansr.com>
---
 cmd/fdt.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Tim Harvey Nov. 29, 2016, 2:22 p.m. UTC | #1
On Tue, Nov 29, 2016 at 4:06 AM, Måns Rullgård <mans@mansr.com> wrote:
> Tim Harvey <tharvey@gateworks.com> writes:
>
>> Greetings,
>>
>> In debugging an issue with a rather old branch of U-Boot (2015-04) I
>> found that the static assignment of a data buffer was not 32-bit
>> aligned which caused data aborts. However I find that current U-boot
>> master does not suffer this issue and no matter what I declare static
>> before the particular variable its always 32-bit aligned. I don't see
>> any code changes that would cause this and in both cases I'm building
>> with the same gcc5.2.0 toolchain.
>>
>> The code in question is this this from cmd/fdt.c:
>>
>>         } else if (argv[1][0] == 's') {
>>                 char *pathp;            /* path */
>>                 char *prop;             /* property */
>>                 int  nodeoffset;        /* node offset from libfdt */
>>                 static char data[SCRATCHPAD];   /* storage for the property */
>>                 int  len;               /* new length of the property */
>>                 int  ret;
>>
>> What guarantee's that 'data' above is 32-bit aligned in master that is
>> missing from the older U-Boot branch I'm using? Perhaps there is some
>> arg in a Makefile that I'm missing?
>
> There are no such guarantees.  Things often end up 4-byte aligned by
> chance simply because most of them are a multiple of 4 bytes in size.
> The code should be fixed, either by explicitly aligning the buffer or by
> using the put_unaligned_b32() accessor in fdt_parse_prop().  Here's an
> untested patch:

Måns,

My thoughts as well but what I found on a 2015.04 U-Boot adding a
'static char foo[1]' before the 'static char data[SCRATCHPAD]' and
printing the addrs:
foo:4ff9e0b2
data:4ff9e0b3
(what I would have expected... no alignment guarantees and clearly not
quad-byte aligned)

The same change on master:
foo:4ff9fff4
data:4ff9fbf0
(not at all what I expected - quad byte aligned and more)

Thus I figured there was something in a Makefile that was directing
the compiler (same compiler in both cases)

I find that merely including '<asm/unaligned.h>' (with no code
changes) changes the alignment and aligns propery???

Tim
Måns Rullgård Nov. 29, 2016, 2:34 p.m. UTC | #2
Tim Harvey <tharvey@gateworks.com> writes:

> On Tue, Nov 29, 2016 at 4:06 AM, Måns Rullgård <mans@mansr.com> wrote:
>> Tim Harvey <tharvey@gateworks.com> writes:
>>
>>> Greetings,
>>>
>>> In debugging an issue with a rather old branch of U-Boot (2015-04) I
>>> found that the static assignment of a data buffer was not 32-bit
>>> aligned which caused data aborts. However I find that current U-boot
>>> master does not suffer this issue and no matter what I declare static
>>> before the particular variable its always 32-bit aligned. I don't see
>>> any code changes that would cause this and in both cases I'm building
>>> with the same gcc5.2.0 toolchain.
>>>
>>> The code in question is this this from cmd/fdt.c:
>>>
>>>         } else if (argv[1][0] == 's') {
>>>                 char *pathp;            /* path */
>>>                 char *prop;             /* property */
>>>                 int  nodeoffset;        /* node offset from libfdt */
>>>                 static char data[SCRATCHPAD];   /* storage for the property */
>>>                 int  len;               /* new length of the property */
>>>                 int  ret;
>>>
>>> What guarantee's that 'data' above is 32-bit aligned in master that is
>>> missing from the older U-Boot branch I'm using? Perhaps there is some
>>> arg in a Makefile that I'm missing?
>>
>> There are no such guarantees.  Things often end up 4-byte aligned by
>> chance simply because most of them are a multiple of 4 bytes in size.
>> The code should be fixed, either by explicitly aligning the buffer or by
>> using the put_unaligned_b32() accessor in fdt_parse_prop().  Here's an
>> untested patch:
>
> Måns,
>
> My thoughts as well but what I found on a 2015.04 U-Boot adding a
> 'static char foo[1]' before the 'static char data[SCRATCHPAD]' and
> printing the addrs:
> foo:4ff9e0b2
> data:4ff9e0b3
> (what I would have expected... no alignment guarantees and clearly not
> quad-byte aligned)
>
> The same change on master:
> foo:4ff9fff4
> data:4ff9fbf0
> (not at all what I expected - quad byte aligned and more)
>
> Thus I figured there was something in a Makefile that was directing
> the compiler (same compiler in both cases)
>
> I find that merely including '<asm/unaligned.h>' (with no code
> changes) changes the alignment and aligns propery???

Compilers are fickle creatures.
diff mbox

Patch

diff --git a/cmd/fdt.c b/cmd/fdt.c
index b503357dc3a8..560b8cc9df61 100644
--- a/cmd/fdt.c
+++ b/cmd/fdt.c
@@ -17,6 +17,7 @@ 
 #include <fdt_support.h>
 #include <mapmem.h>
 #include <asm/io.h>
+#include <asm/unaligned.h>
 
 #define MAX_LEVEL	32		/* how deeply nested we will go */
 #define SCRATCHPAD	1024		/* bytes of scratchpad memory */
@@ -766,7 +767,7 @@  static int fdt_parse_prop(char * const *newval, int count, char *data, int *len)
 
 			cp = newp;
 			tmp = simple_strtoul(cp, &newp, 0);
-			*(__be32 *)data = __cpu_to_be32(tmp);
+			put_unaligned_be32(tmp, data);
 			data  += 4;
 			*len += 4;