aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-03-29 13:30:31 -0400
committerChris Metcalf <cmetcalf@tilera.com>2012-05-25 12:48:22 -0400
commit1efea40d4172a2a475ccb29b59d6221e9d0c174b (patch)
tree8152b61bb3fa83eb3403bca5cb05731c1063e999 /arch/tile
parent73636b1aacb1a07e6fbe0d25e560e69b024a8e25 (diff)
arch/tile: support building big-endian kernel
The toolchain supports big-endian mode now, so add support for building the kernel to run big-endian as well. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile')
-rw-r--r--arch/tile/include/asm/byteorder.h20
-rw-r--r--arch/tile/include/asm/elf.h5
-rw-r--r--arch/tile/include/hv/hypervisor.h16
-rw-r--r--arch/tile/kernel/module.c12
-rw-r--r--arch/tile/kernel/single_step.c16
-rw-r--r--arch/tile/lib/memchr_64.c8
-rw-r--r--arch/tile/lib/memcpy_64.c23
-rw-r--r--arch/tile/lib/strchr_64.c15
-rw-r--r--arch/tile/lib/string-endian.h33
-rw-r--r--arch/tile/lib/strlen_64.c11
10 files changed, 130 insertions, 29 deletions
diff --git a/arch/tile/include/asm/byteorder.h b/arch/tile/include/asm/byteorder.h
index 9558416d578b..fb72ecf49218 100644
--- a/arch/tile/include/asm/byteorder.h
+++ b/arch/tile/include/asm/byteorder.h
@@ -1 +1,21 @@
1/*
2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 */
14
15#if defined (__BIG_ENDIAN__)
16#include <linux/byteorder/big_endian.h>
17#elif defined (__LITTLE_ENDIAN__)
1#include <linux/byteorder/little_endian.h> 18#include <linux/byteorder/little_endian.h>
19#else
20#error "__BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined."
21#endif
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h
index 623a6bb741c1..d16d006d660e 100644
--- a/arch/tile/include/asm/elf.h
+++ b/arch/tile/include/asm/elf.h
@@ -44,7 +44,11 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
44#else 44#else
45#define ELF_CLASS ELFCLASS32 45#define ELF_CLASS ELFCLASS32
46#endif 46#endif
47#ifdef __BIG_ENDIAN__
48#define ELF_DATA ELFDATA2MSB
49#else
47#define ELF_DATA ELFDATA2LSB 50#define ELF_DATA ELFDATA2LSB
51#endif
48 52
49/* 53/*
50 * There seems to be a bug in how compat_binfmt_elf.c works: it 54 * There seems to be a bug in how compat_binfmt_elf.c works: it
@@ -59,6 +63,7 @@ enum { ELF_ARCH = CHIP_ELF_TYPE() };
59 */ 63 */
60#define elf_check_arch(x) \ 64#define elf_check_arch(x) \
61 ((x)->e_ident[EI_CLASS] == ELF_CLASS && \ 65 ((x)->e_ident[EI_CLASS] == ELF_CLASS && \
66 (x)->e_ident[EI_DATA] == ELF_DATA && \
62 (x)->e_machine == CHIP_ELF_TYPE()) 67 (x)->e_machine == CHIP_ELF_TYPE())
63 68
64/* The module loader only handles a few relocation types. */ 69/* The module loader only handles a few relocation types. */
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index 793123e116fd..df74223944b5 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -494,11 +494,16 @@ int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len);
494/** Tile coordinate */ 494/** Tile coordinate */
495typedef struct 495typedef struct
496{ 496{
497#ifndef __BIG_ENDIAN__
497 /** X coordinate, relative to supervisor's top-left coordinate */ 498 /** X coordinate, relative to supervisor's top-left coordinate */
498 int x; 499 int x;
499 500
500 /** Y coordinate, relative to supervisor's top-left coordinate */ 501 /** Y coordinate, relative to supervisor's top-left coordinate */
501 int y; 502 int y;
503#else
504 int y;
505 int x;
506#endif
502} HV_Coord; 507} HV_Coord;
503 508
504 509
@@ -986,8 +991,13 @@ HV_VirtAddrRange hv_inquire_virtual(int idx);
986/** A range of ASID values. */ 991/** A range of ASID values. */
987typedef struct 992typedef struct
988{ 993{
994#ifndef __BIG_ENDIAN__
989 HV_ASID start; /**< First ASID in the range. */ 995 HV_ASID start; /**< First ASID in the range. */
990 unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ 996 unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */
997#else
998 unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */
999 HV_ASID start; /**< First ASID in the range. */
1000#endif
991} HV_ASIDRange; 1001} HV_ASIDRange;
992 1002
993/** Returns information about a range of ASIDs. 1003/** Returns information about a range of ASIDs.
@@ -1308,6 +1318,7 @@ typedef enum
1308/** Message recipient. */ 1318/** Message recipient. */
1309typedef struct 1319typedef struct
1310{ 1320{
1321#ifndef __BIG_ENDIAN__
1311 /** X coordinate, relative to supervisor's top-left coordinate */ 1322 /** X coordinate, relative to supervisor's top-left coordinate */
1312 unsigned int x:11; 1323 unsigned int x:11;
1313 1324
@@ -1316,6 +1327,11 @@ typedef struct
1316 1327
1317 /** Status of this recipient */ 1328 /** Status of this recipient */
1318 HV_Recip_State state:10; 1329 HV_Recip_State state:10;
1330#else //__BIG_ENDIAN__
1331 HV_Recip_State state:10;
1332 unsigned int y:11;
1333 unsigned int x:11;
1334#endif
1319} HV_Recipient; 1335} HV_Recipient;
1320 1336
1321/** Send a message to a set of recipients. 1337/** Send a message to a set of recipients.
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index 98d476920106..001cbfa10ac6 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -159,7 +159,17 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
159 159
160 switch (ELF_R_TYPE(rel[i].r_info)) { 160 switch (ELF_R_TYPE(rel[i].r_info)) {
161 161
162#define MUNGE(func) (*location = ((*location & ~func(-1)) | func(value))) 162#ifdef __LITTLE_ENDIAN
163# define MUNGE(func) \
164 (*location = ((*location & ~func(-1)) | func(value)))
165#else
166/*
167 * Instructions are always little-endian, so when we read them as data,
168 * we have to swap them around before and after modifying them.
169 */
170# define MUNGE(func) \
171 (*location = swab64((swab64(*location) & ~func(-1)) | func(value)))
172#endif
163 173
164#ifndef __tilegx__ 174#ifndef __tilegx__
165 case R_TILE_32: 175 case R_TILE_32:
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 89529c9f0605..27742e87e255 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -172,9 +172,6 @@ static tile_bundle_bits rewrite_load_store_unaligned(
172 return (tilepro_bundle_bits) 0; 172 return (tilepro_bundle_bits) 0;
173 } 173 }
174 174
175#ifndef __LITTLE_ENDIAN
176# error We assume little-endian representation with copy_xx_user size 2 here
177#endif
178 /* Handle unaligned load/store */ 175 /* Handle unaligned load/store */
179 if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { 176 if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) {
180 unsigned short val_16; 177 unsigned short val_16;
@@ -195,8 +192,19 @@ static tile_bundle_bits rewrite_load_store_unaligned(
195 state->update = 1; 192 state->update = 1;
196 } 193 }
197 } else { 194 } else {
195 unsigned short val_16;
198 val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg]; 196 val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg];
199 err = copy_to_user(addr, &val, size); 197 switch (size) {
198 case 2:
199 val_16 = val;
200 err = copy_to_user(addr, &val_16, sizeof(val_16));
201 break;
202 case 4:
203 err = copy_to_user(addr, &val, sizeof(val));
204 break;
205 default:
206 BUG();
207 }
200 } 208 }
201 209
202 if (err) { 210 if (err) {
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c
index 84fdc8d8e735..6f867dbf7c56 100644
--- a/arch/tile/lib/memchr_64.c
+++ b/arch/tile/lib/memchr_64.c
@@ -15,6 +15,7 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include "string-endian.h"
18 19
19void *memchr(const void *s, int c, size_t n) 20void *memchr(const void *s, int c, size_t n)
20{ 21{
@@ -39,11 +40,8 @@ void *memchr(const void *s, int c, size_t n)
39 40
40 /* Read the first word, but munge it so that bytes before the array 41 /* Read the first word, but munge it so that bytes before the array
41 * will not match goal. 42 * will not match goal.
42 *
43 * Note that this shift count expression works because we know
44 * shift counts are taken mod 64.
45 */ 43 */
46 before_mask = (1ULL << (s_int << 3)) - 1; 44 before_mask = MASK(s_int);
47 v = (*p | before_mask) ^ (goal & before_mask); 45 v = (*p | before_mask) ^ (goal & before_mask);
48 46
49 /* Compute the address of the last byte. */ 47 /* Compute the address of the last byte. */
@@ -65,7 +63,7 @@ void *memchr(const void *s, int c, size_t n)
65 /* We found a match, but it might be in a byte past the end 63 /* We found a match, but it might be in a byte past the end
66 * of the array. 64 * of the array.
67 */ 65 */
68 ret = ((char *)p) + (__insn_ctz(bits) >> 3); 66 ret = ((char *)p) + (CFZ(bits) >> 3);
69 return (ret <= last_byte_ptr) ? ret : NULL; 67 return (ret <= last_byte_ptr) ? ret : NULL;
70} 68}
71EXPORT_SYMBOL(memchr); 69EXPORT_SYMBOL(memchr);
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c
index 3fab9a6a2bbe..c79b8e7c6828 100644
--- a/arch/tile/lib/memcpy_64.c
+++ b/arch/tile/lib/memcpy_64.c
@@ -15,7 +15,6 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#define __memcpy memcpy
19/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ 18/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
20 19
21/* Must be 8 bytes in size. */ 20/* Must be 8 bytes in size. */
@@ -188,6 +187,7 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
188 187
189 /* n != 0 if we get here. Write out any trailing bytes. */ 188 /* n != 0 if we get here. Write out any trailing bytes. */
190 dst1 = (char *)dst8; 189 dst1 = (char *)dst8;
190#ifndef __BIG_ENDIAN__
191 if (n & 4) { 191 if (n & 4) {
192 ST4((uint32_t *)dst1, final); 192 ST4((uint32_t *)dst1, final);
193 dst1 += 4; 193 dst1 += 4;
@@ -202,11 +202,30 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
202 } 202 }
203 if (n) 203 if (n)
204 ST1((uint8_t *)dst1, final); 204 ST1((uint8_t *)dst1, final);
205#else
206 if (n & 4) {
207 ST4((uint32_t *)dst1, final >> 32);
208 dst1 += 4;
209 }
210 else
211 {
212 final >>= 32;
213 }
214 if (n & 2) {
215 ST2((uint16_t *)dst1, final >> 16);
216 dst1 += 2;
217 }
218 else
219 {
220 final >>= 16;
221 }
222 if (n & 1)
223 ST1((uint8_t *)dst1, final >> 8);
224#endif
205 225
206 return RETVAL; 226 return RETVAL;
207} 227}
208 228
209
210#ifdef USERCOPY_FUNC 229#ifdef USERCOPY_FUNC
211#undef ST1 230#undef ST1
212#undef ST2 231#undef ST2
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c
index 617a9273aaa8..f39f9dc422b0 100644
--- a/arch/tile/lib/strchr_64.c
+++ b/arch/tile/lib/strchr_64.c
@@ -15,8 +15,7 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/module.h> 17#include <linux/module.h>
18 18#include "string-endian.h"
19#undef strchr
20 19
21char *strchr(const char *s, int c) 20char *strchr(const char *s, int c)
22{ 21{
@@ -33,13 +32,9 @@ char *strchr(const char *s, int c)
33 * match neither zero nor goal (we make sure the high bit of each 32 * match neither zero nor goal (we make sure the high bit of each
34 * byte is 1, and the low 7 bits are all the opposite of the goal 33 * byte is 1, and the low 7 bits are all the opposite of the goal
35 * byte). 34 * byte).
36 *
37 * Note that this shift count expression works because we know shift
38 * counts are taken mod 64.
39 */ 35 */
40 const uint64_t before_mask = (1ULL << (s_int << 3)) - 1; 36 const uint64_t before_mask = MASK(s_int);
41 uint64_t v = (*p | before_mask) ^ 37 uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1));
42 (goal & __insn_v1shrsi(before_mask, 1));
43 38
44 uint64_t zero_matches, goal_matches; 39 uint64_t zero_matches, goal_matches;
45 while (1) { 40 while (1) {
@@ -55,8 +50,8 @@ char *strchr(const char *s, int c)
55 v = *++p; 50 v = *++p;
56 } 51 }
57 52
58 z = __insn_ctz(zero_matches); 53 z = CFZ(zero_matches);
59 g = __insn_ctz(goal_matches); 54 g = CFZ(goal_matches);
60 55
61 /* If we found c before '\0' we got a match. Note that if c == '\0' 56 /* If we found c before '\0' we got a match. Note that if c == '\0'
62 * then g == z, and we correctly return the address of the '\0' 57 * then g == z, and we correctly return the address of the '\0'
diff --git a/arch/tile/lib/string-endian.h b/arch/tile/lib/string-endian.h
new file mode 100644
index 000000000000..c0eed7ce69c3
--- /dev/null
+++ b/arch/tile/lib/string-endian.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * Provide a mask based on the pointer alignment that
15 * sets up non-zero bytes before the beginning of the string.
16 * The MASK expression works because shift counts are taken mod 64.
17 * Also, specify how to count "first" and "last" bits
18 * when the bits have been read as a word.
19 */
20
21#include <asm/byteorder.h>
22
23#ifdef __LITTLE_ENDIAN
24#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1)
25#define NULMASK(x) ((2ULL << x) - 1)
26#define CFZ(x) __insn_ctz(x)
27#define REVCZ(x) __insn_clz(x)
28#else
29#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1)))
30#define NULMASK(x) (-2LL << (63 - x))
31#define CFZ(x) __insn_clz(x)
32#define REVCZ(x) __insn_ctz(x)
33#endif
diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c
index 1c92d46202a8..9583fc3361fa 100644
--- a/arch/tile/lib/strlen_64.c
+++ b/arch/tile/lib/strlen_64.c
@@ -15,8 +15,7 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/module.h> 17#include <linux/module.h>
18 18#include "string-endian.h"
19#undef strlen
20 19
21size_t strlen(const char *s) 20size_t strlen(const char *s)
22{ 21{
@@ -24,15 +23,13 @@ size_t strlen(const char *s)
24 const uintptr_t s_int = (uintptr_t) s; 23 const uintptr_t s_int = (uintptr_t) s;
25 const uint64_t *p = (const uint64_t *)(s_int & -8); 24 const uint64_t *p = (const uint64_t *)(s_int & -8);
26 25
27 /* Read the first word, but force bytes before the string to be nonzero. 26 /* Read and MASK the first word. */
28 * This expression works because we know shift counts are taken mod 64. 27 uint64_t v = *p | MASK(s_int);
29 */
30 uint64_t v = *p | ((1ULL << (s_int << 3)) - 1);
31 28
32 uint64_t bits; 29 uint64_t bits;
33 while ((bits = __insn_v1cmpeqi(v, 0)) == 0) 30 while ((bits = __insn_v1cmpeqi(v, 0)) == 0)
34 v = *++p; 31 v = *++p;
35 32
36 return ((const char *)p) + (__insn_ctz(bits) >> 3) - s; 33 return ((const char *)p) + (CFZ(bits) >> 3) - s;
37} 34}
38EXPORT_SYMBOL(strlen); 35EXPORT_SYMBOL(strlen);