[U-Boot] [PATCH] disk:efi: avoid unaligned access on efi partition

Måns Rullgård
2013-10-15T15:23:44Z

Albert ARIBAUD <albert.u.boot@aribaud.net> writes:

>> > I sense that you have not understood the reason why I want alignment
>> > checking enabled in ARM yet also want ARMv6+ builds to emit native
>> > unaligned accesses if they consider it needed.
>>
>> Your wishes are mutually exclusive. You cannot both allow hardware
>> unaligned access AND at the same time trap them.
>
> These are not wishes, there are actual settings chosen for the reason
> already laid out. They do appear contradictory if your goal is to use
> ARMv6+ features to their maximum, but this is not the goal here.
>
>> > The reason is, if we prevent ARMv6 builds from using native unaligned
>> > accesses, they would replace *all* such accesses with smaller, aligned,
>> > ones, which would not trigger a data abort; even those unaligned
>> > accesses cased by programming errors.
>>
>> If you disable unaligned accesses in hardware (as u-boot does), you have
>> no option but doing them a byte at a time.
>
> Indeed, but I do *not* *disable* native unaligned accesses, I *allow*
> them; and I do not *want* them to be replaced by byte-by-byte emulation.

Let's go back to the basics.

In ARMv6 and later there is a bit in the system control register
(SCTLR.A) which decides whether or not unaligned memory accesses are
allowed. The reset value of this bit allows unaligned accesses.

When unaligned accesses are allowed, word and halfword load/store
instructions (LDR, STR, LDRH, LDRSH, STRH) with an unaligned address
simply perform the requested memory operation. When unaligned accesses
are disallowed (SCTLR.A set), these instructions cause an alignment
fault if used with an unaligned address. The load/store double and
multiple instructions (LDRD, STRD, LDM, STM) always trap on unaligned
addresses.

This is all described in the ARM Architecture Reference Manual (DDI0406C)
section A3.2.

That's the hardware side.

On the compiler side, gcc traditionally did not issue unaligned
load/store instructions on ARM. Since version 4.7, gcc does issue
unaligned accesses when the target is ARMv6 or later. This makes sense
since a hardware unaligned access is faster than doing it byte-wise in
software, and the default for the CPU is to permit unaligned accesses.
Needless to say, a potentially unaligned address will only be accessed
using the subset of load/store instructions for which this is supported.

To support configurations where SCTR.A is set (disallowing unaligned
accesses), gcc 4.7 also adds a flag (-mno-unaligned-access) causing it
to never emit potentially unaligned loads or stores.

The compiler behaviour described above is true only for well-behaved
code. In standard C, pointers must always be aligned according to their
target type. For instance, a pointer to a 32-bit integer type must
typically be 32-bit aligned. Thus, if a pointer is constructed with
incorrect alignment, any attempt to use it may result in invalid memory
access instructions being executed.

In practice, various situations arise where there is a need to work with
unaligned data, for example when parsing some communication protocols.
To simplify such code, most compilers provide some language extension
allowing the programmer to annotate a type definition or pointer as
being potentially unaligned. In gcc, the 'packed' attribute on struct
and union types serves this purpose.

Any access to a member of a 'packed' struct/union is assumed to be
potentially unaligned, and the instructions selection is limited
accordingly. When -munaligned-access is in effect, unaligned word or
halfword load/store instructions may be used here. When this feature is
disabled (-mno-unaligned-access), only aligned loads and stores
(typically bytes) are permitted.

The situations where the compiler will issue an unaligned memory access
are generally not predictable. Currently, they tend to occur in
struct/array assignment (including initialisation), inline expansion of
memcpy/memset, and accesses to 'packed' struct members. As compiler
optimisations improve, these cases will likely increase in number.

As we can see, enabling the -munaligned-access flag results in
load/store instructions occasionally accessing unaligned memory, and the
precise places where this happens are not predictable. It is thus a
requirement that SCTLR.A be clear when this compiler flag is set.
Otherwise alignment faults will occur.

If for whatever reason SCTLR.A is set, it is required to use the
-mno-unaligned-access compiler flag in order for the code to run
cleanly. Failure to do so will result in alignment faults when the code
is executed.

One reason for setting SCTLR.A is to aid in catching programming errors
whereby a normal pointer is assigned an unaligned value. Since these
pointers are assumed by the compiler to be correctly aligned, accesses
through them are unaffected by the -m[no-]unaligned-access flag, and
any such errors will thus trigger an alignment fault.

If any of the above is unclear, please let me know, and I will try to
explain it better.

--
M?ns Rullg?rd
mans at mansr.com