alignment handler instruction endian-ness

Ben Dooks ben.dooks at codethink.co.uk
Fri Jul 19 06:58:45 EDT 2013


I ran in to an issue with the alignment handler when running BE8 where
it loads instructions and fails to swap.

Is there a better way of swapping instructions for ARM when loading
from arbitrary places? Have I missed any other places this could happen?

The following patch is my first attempt at solving the problem for the
alignment handler:

> Author: Ben Dooks <ben.dooks at codethink.co.uk>
> Date:   Thu Jul 18 21:10:56 2013 +0100
>
>     arm: alignment: deal with be8 mode when decoding instructions
>
>     If we are in BE8 mode, we must deal with the instruction stream being
>     in LE order when data is being loaded in BE order. Ensure the data is
>     swapped before processing to avoid thre following:
>
>     Alignment trap: not handling instruction 030091e8 at [<80333e8c>]
>     Unhandled fault: alignment exception (0x001) at 0xbfa09567
>
>     Signed-off-by: Ben Dooks <ben.dooks at codethink.co.uk>
 >
> diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
> index db26e2e..e8793a7 100644
> --- a/arch/arm/mm/alignment.c
> +++ b/arch/arm/mm/alignment.c
> @@ -87,6 +87,12 @@ core_param(alignment, ai_usermode, int, 0600);
>  #define UM_FIXUP       (1 << 1)
>  #define UM_SIGNAL      (1 << 2)
>
> +#ifdef CONFIG_CPU_ENDIAN_BE8
> +#define need_swap()    true
> +#else
> +#define need_swap()    false
> +#endif
> +
>  /* Return true if and only if the ARMv6 unaligned access model is in use. */
>  static bool cpu_is_v6_unaligned(void)
>  {
> @@ -762,12 +768,16 @@ do_alignment(unsigned long addr, unsigned int fsr, struct
>         if (thumb_mode(regs)) {
>                 u16 *ptr = (u16 *)(instrptr & ~1);
>                 fault = probe_kernel_address(ptr, tinstr);
> +               if (need_swap())
> +                       tinstr = cpu_to_le16(tinstr);
>                 if (!fault) {
>                         if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
>                             IS_T32(tinstr)) {
>                                 /* Thumb-2 32-bit */
>                                 u16 tinst2 = 0;
>                                 fault = probe_kernel_address(ptr + 1, tinst2);
> +                               if (need_swap())
> +                                       tinst2 = cpu_to_le16(tinst2);
>                                 instr = (tinstr << 16) | tinst2;
>                                 thumb2_32b = 1;
>                         } else {
> @@ -775,8 +785,11 @@ do_alignment(unsigned long addr, unsigned int fsr, struct p
>                                 instr = thumb2arm(tinstr);
>                         }
>                 }
> -       } else
> +       } else {
>                 fault = probe_kernel_address(instrptr, instr);
> +               if (need_swap())
> +                       instr = cpu_to_le32(instr);
> +       }
>
>         if (fault) {
>                 type = TYPE_FAULT;


-- 
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius



More information about the linux-arm-kernel mailing list