[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Getting rid of alignment faults in userspace



On Fri, 17 Jun 2011, Paul Brook wrote:

> > >> There is still going to be a small cost even in hardware fixup so this
> > >> is very much worth solving despite it's "becoming invisible" because the
> > >> chips are hiding / solving it already.
> > > 
> > > But I believe that h/w feature is turned off in Linux by default. You
> > > have to add noalign to the kernel command line to enable.
> > 
> > I think you'll find the hardware fixups are enabled by default on CPUs
> > with that design, quite possibly it can't be turned off.
> 
> The situation is much more complicated than that.  There are two completely 
> different models for misaligned accesses (v6 and pre-v6).  v7 cores are only 
> required to support the former.
> 
> However even under the v6 model some instructions will fault on misaligned 
> addresses, and the CPU may be configured to fault many others.  The exact 
> behavior depends on the particular instruction chosen by the compiler.  I 
> don't know whether Linux currently knows how to enable alignment checking on 
> v6/v7 hardware.

It does.  Has done for a long time. Please see arch/arm/mm/alignment.c:

static int __init alignment_init(void)
{
[...]
        /*
         * ARMv6 and later CPUs can perform unaligned accesses for
         * most single load and store instructions up to word size.
         * LDM, STM, LDRD and STRD still need to be handled.
         *
         * Ignoring the alignment fault is not an option on these
         * CPUs since we spin re-faulting the instruction without
         * making any progress.
         */
        if (cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U)) {
                cr_alignment &= ~CR_A;
                cr_no_alignment &= ~CR_A;
                set_cr(cr_alignment);
                ai_usermode = UM_FIXUP;
        }

And if you look at arch/arm/mm/proc-v6.S in __v6_setup, you'll find out 
that the CR_U bit is set.

> > int main(int argc, char * argv[])
> > {
> > 
> >       char buf[8];
> >       void *v = &buf[1];
> >       unsigned int *p = (unsigned int *)v;
> 
> This does not (reliably) do what you expect.  The compiler need not align buf.

Printing the value of p should clarify this.

And, as we can see above, the "simple" accesses are left to the hardware 
to fix up.  However, if the misaligned access is performed using a 
64-bit value pointer, then the kernel will trap an exception and the 
access will be simulated.


Nicolas


Reply to: