+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#if defined (__BIG_ENDIAN__)
+#include <linux/byteorder/big_endian.h>
+#elif defined (__LITTLE_ENDIAN__)
 #include <linux/byteorder/little_endian.h>
+#else
+#error "__BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined."
+#endif
 
 #else
 #define ELF_CLASS      ELFCLASS32
 #endif
+#ifdef __BIG_ENDIAN__
+#define ELF_DATA       ELFDATA2MSB
+#else
 #define ELF_DATA       ELFDATA2LSB
+#endif
 
 /*
  * There seems to be a bug in how compat_binfmt_elf.c works: it
  */
 #define elf_check_arch(x)  \
        ((x)->e_ident[EI_CLASS] == ELF_CLASS && \
+        (x)->e_ident[EI_DATA] == ELF_DATA && \
         (x)->e_machine == CHIP_ELF_TYPE())
 
 /* The module loader only handles a few relocation types. */
 
 /** Tile coordinate */
 typedef struct
 {
+#ifndef __BIG_ENDIAN__
   /** X coordinate, relative to supervisor's top-left coordinate */
   int x;
 
   /** Y coordinate, relative to supervisor's top-left coordinate */
   int y;
+#else
+  int y;
+  int x;
+#endif
 } HV_Coord;
 
 
 /** A range of ASID values. */
 typedef struct
 {
+#ifndef __BIG_ENDIAN__
   HV_ASID start;        /**< First ASID in the range. */
   unsigned int size;    /**< Number of ASIDs. Zero for an invalid range. */
+#else
+  unsigned int size;    /**< Number of ASIDs. Zero for an invalid range. */
+  HV_ASID start;        /**< First ASID in the range. */
+#endif
 } HV_ASIDRange;
 
 /** Returns information about a range of ASIDs.
 /** Message recipient. */
 typedef struct
 {
+#ifndef __BIG_ENDIAN__
   /** X coordinate, relative to supervisor's top-left coordinate */
   unsigned int x:11;
 
 
   /** Status of this recipient */
   HV_Recip_State state:10;
+#else //__BIG_ENDIAN__
+  HV_Recip_State state:10;
+  unsigned int y:11;
+  unsigned int x:11;
+#endif
 } HV_Recipient;
 
 /** Send a message to a set of recipients.
 
 
                switch (ELF_R_TYPE(rel[i].r_info)) {
 
-#define MUNGE(func) (*location = ((*location & ~func(-1)) | func(value)))
+#ifdef __LITTLE_ENDIAN
+# define MUNGE(func) \
+       (*location = ((*location & ~func(-1)) | func(value)))
+#else
+/*
+ * Instructions are always little-endian, so when we read them as data,
+ * we have to swap them around before and after modifying them.
+ */
+# define MUNGE(func) \
+       (*location = swab64((swab64(*location) & ~func(-1)) | func(value)))
+#endif
 
 #ifndef __tilegx__
                case R_TILE_32:
 
                return (tilepro_bundle_bits) 0;
        }
 
-#ifndef __LITTLE_ENDIAN
-# error We assume little-endian representation with copy_xx_user size 2 here
-#endif
        /* Handle unaligned load/store */
        if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) {
                unsigned short val_16;
                        state->update = 1;
                }
        } else {
+               unsigned short val_16;
                val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg];
-               err = copy_to_user(addr, &val, size);
+               switch (size) {
+               case 2:
+                       val_16 = val;
+                       err = copy_to_user(addr, &val_16, sizeof(val_16));
+                       break;
+               case 4:
+                       err = copy_to_user(addr, &val, sizeof(val));
+                       break;
+               default:
+                       BUG();
+               }
        }
 
        if (err) {
 
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
+#include "string-endian.h"
 
 void *memchr(const void *s, int c, size_t n)
 {
 
        /* Read the first word, but munge it so that bytes before the array
         * will not match goal.
-        *
-        * Note that this shift count expression works because we know
-        * shift counts are taken mod 64.
         */
-       before_mask = (1ULL << (s_int << 3)) - 1;
+       before_mask = MASK(s_int);
        v = (*p | before_mask) ^ (goal & before_mask);
 
        /* Compute the address of the last byte. */
        /* We found a match, but it might be in a byte past the end
         * of the array.
         */
-       ret = ((char *)p) + (__insn_ctz(bits) >> 3);
+       ret = ((char *)p) + (CFZ(bits) >> 3);
        return (ret <= last_byte_ptr) ? ret : NULL;
 }
 EXPORT_SYMBOL(memchr);
 
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
-#define __memcpy memcpy
 /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
 
 /* Must be 8 bytes in size. */
 
        /* n != 0 if we get here.  Write out any trailing bytes. */
        dst1 = (char *)dst8;
+#ifndef __BIG_ENDIAN__
        if (n & 4) {
                ST4((uint32_t *)dst1, final);
                dst1 += 4;
        }
        if (n)
                ST1((uint8_t *)dst1, final);
+#else
+       if (n & 4) {
+               ST4((uint32_t *)dst1, final >> 32);
+               dst1 += 4;
+        }
+        else
+        {
+               final >>= 32;
+        }
+       if (n & 2) {
+               ST2((uint16_t *)dst1, final >> 16);
+               dst1 += 2;
+        }
+        else
+        {
+               final >>= 16;
+        }
+       if (n & 1)
+               ST1((uint8_t *)dst1, final >> 8);
+#endif
 
        return RETVAL;
 }
 
-
 #ifdef USERCOPY_FUNC
 #undef ST1
 #undef ST2
 
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
-
-#undef strchr
+#include "string-endian.h"
 
 char *strchr(const char *s, int c)
 {
         * match neither zero nor goal (we make sure the high bit of each
         * byte is 1, and the low 7 bits are all the opposite of the goal
         * byte).
-        *
-        * Note that this shift count expression works because we know shift
-        * counts are taken mod 64.
         */
-       const uint64_t before_mask = (1ULL << (s_int << 3)) - 1;
-       uint64_t v = (*p | before_mask) ^
-               (goal & __insn_v1shrsi(before_mask, 1));
+       const uint64_t before_mask = MASK(s_int);
+       uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1));
 
        uint64_t zero_matches, goal_matches;
        while (1) {
                v = *++p;
        }
 
-       z = __insn_ctz(zero_matches);
-       g = __insn_ctz(goal_matches);
+       z = CFZ(zero_matches);
+       g = CFZ(goal_matches);
 
        /* If we found c before '\0' we got a match. Note that if c == '\0'
         * then g == z, and we correctly return the address of the '\0'
 
--- /dev/null
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Provide a mask based on the pointer alignment that
+ * sets up non-zero bytes before the beginning of the string.
+ * The MASK expression works because shift counts are taken mod 64.
+ * Also, specify how to count "first" and "last" bits
+ * when the bits have been read as a word.
+ */
+
+#include <asm/byteorder.h>
+
+#ifdef __LITTLE_ENDIAN
+#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1)
+#define NULMASK(x) ((2ULL << x) - 1)
+#define CFZ(x) __insn_ctz(x)
+#define REVCZ(x) __insn_clz(x)
+#else
+#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1)))
+#define NULMASK(x) (-2LL << (63 - x))
+#define CFZ(x) __insn_clz(x)
+#define REVCZ(x) __insn_ctz(x)
+#endif
 
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
-
-#undef strlen
+#include "string-endian.h"
 
 size_t strlen(const char *s)
 {
        const uintptr_t s_int = (uintptr_t) s;
        const uint64_t *p = (const uint64_t *)(s_int & -8);
 
-       /* Read the first word, but force bytes before the string to be nonzero.
-        * This expression works because we know shift counts are taken mod 64.
-        */
-       uint64_t v = *p | ((1ULL << (s_int << 3)) - 1);
+       /* Read and MASK the first word. */
+       uint64_t v = *p | MASK(s_int);
 
        uint64_t bits;
        while ((bits = __insn_v1cmpeqi(v, 0)) == 0)
                v = *++p;
 
-       return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
+       return ((const char *)p) + (CFZ(bits) >> 3) - s;
 }
 EXPORT_SYMBOL(strlen);