diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2012-03-29 13:30:31 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2012-05-25 12:48:22 -0400 |
commit | 1efea40d4172a2a475ccb29b59d6221e9d0c174b (patch) | |
tree | 8152b61bb3fa83eb3403bca5cb05731c1063e999 /arch/tile | |
parent | 73636b1aacb1a07e6fbe0d25e560e69b024a8e25 (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.h | 20 | ||||
-rw-r--r-- | arch/tile/include/asm/elf.h | 5 | ||||
-rw-r--r-- | arch/tile/include/hv/hypervisor.h | 16 | ||||
-rw-r--r-- | arch/tile/kernel/module.c | 12 | ||||
-rw-r--r-- | arch/tile/kernel/single_step.c | 16 | ||||
-rw-r--r-- | arch/tile/lib/memchr_64.c | 8 | ||||
-rw-r--r-- | arch/tile/lib/memcpy_64.c | 23 | ||||
-rw-r--r-- | arch/tile/lib/strchr_64.c | 15 | ||||
-rw-r--r-- | arch/tile/lib/string-endian.h | 33 | ||||
-rw-r--r-- | arch/tile/lib/strlen_64.c | 11 |
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 */ |
495 | typedef struct | 495 | typedef 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. */ |
987 | typedef struct | 992 | typedef 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. */ |
1309 | typedef struct | 1319 | typedef 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 | ||
19 | void *memchr(const void *s, int c, size_t n) | 20 | void *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 | } |
71 | EXPORT_SYMBOL(memchr); | 69 | EXPORT_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 | ||
21 | char *strchr(const char *s, int c) | 20 | char *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 | ||
21 | size_t strlen(const char *s) | 20 | size_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 | } |
38 | EXPORT_SYMBOL(strlen); | 35 | EXPORT_SYMBOL(strlen); |