Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+130 -29
+20
arch/tile/include/asm/byteorder.h
··· 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 18 #include <linux/byteorder/little_endian.h> 19 + #else 20 + #error "__BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined." 21 + #endif
+5
arch/tile/include/asm/elf.h
··· 44 44 #else 45 45 #define ELF_CLASS ELFCLASS32 46 46 #endif 47 + #ifdef __BIG_ENDIAN__ 48 + #define ELF_DATA ELFDATA2MSB 49 + #else 47 50 #define ELF_DATA ELFDATA2LSB 51 + #endif 48 52 49 53 /* 50 54 * There seems to be a bug in how compat_binfmt_elf.c works: it ··· 63 59 */ 64 60 #define elf_check_arch(x) \ 65 61 ((x)->e_ident[EI_CLASS] == ELF_CLASS && \ 62 + (x)->e_ident[EI_DATA] == ELF_DATA && \ 66 63 (x)->e_machine == CHIP_ELF_TYPE()) 67 64 68 65 /* The module loader only handles a few relocation types. */
+16
arch/tile/include/hv/hypervisor.h
··· 494 494 /** Tile coordinate */ 495 495 typedef struct 496 496 { 497 + #ifndef __BIG_ENDIAN__ 497 498 /** X coordinate, relative to supervisor's top-left coordinate */ 498 499 int x; 499 500 500 501 /** Y coordinate, relative to supervisor's top-left coordinate */ 501 502 int y; 503 + #else 504 + int y; 505 + int x; 506 + #endif 502 507 } HV_Coord; 503 508 504 509 ··· 991 986 /** A range of ASID values. */ 992 987 typedef struct 993 988 { 989 + #ifndef __BIG_ENDIAN__ 994 990 HV_ASID start; /**< First ASID in the range. */ 995 991 unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ 992 + #else 993 + unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ 994 + HV_ASID start; /**< First ASID in the range. */ 995 + #endif 996 996 } HV_ASIDRange; 997 997 998 998 /** Returns information about a range of ASIDs. ··· 1318 1308 /** Message recipient. */ 1319 1309 typedef struct 1320 1310 { 1311 + #ifndef __BIG_ENDIAN__ 1321 1312 /** X coordinate, relative to supervisor's top-left coordinate */ 1322 1313 unsigned int x:11; 1323 1314 ··· 1327 1316 1328 1317 /** Status of this recipient */ 1329 1318 HV_Recip_State state:10; 1319 + #else //__BIG_ENDIAN__ 1320 + HV_Recip_State state:10; 1321 + unsigned int y:11; 1322 + unsigned int x:11; 1323 + #endif 1330 1324 } HV_Recipient; 1331 1325 1332 1326 /** Send a message to a set of recipients.
+11 -1
arch/tile/kernel/module.c
··· 159 159 160 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 174 #ifndef __tilegx__ 165 175 case R_TILE_32:
+12 -4
arch/tile/kernel/single_step.c
··· 172 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 175 /* Handle unaligned load/store */ 179 176 if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { 180 177 unsigned short val_16; ··· 192 195 state->update = 1; 193 196 } 194 197 } else { 198 + unsigned short val_16; 195 199 val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg]; 196 - err = copy_to_user(addr, &val, size); 200 + switch (size) { 201 + case 2: 202 + val_16 = val; 203 + err = copy_to_user(addr, &val_16, sizeof(val_16)); 204 + break; 205 + case 4: 206 + err = copy_to_user(addr, &val, sizeof(val)); 207 + break; 208 + default: 209 + BUG(); 210 + } 197 211 } 198 212 199 213 if (err) {
+3 -5
arch/tile/lib/memchr_64.c
··· 15 15 #include <linux/types.h> 16 16 #include <linux/string.h> 17 17 #include <linux/module.h> 18 + #include "string-endian.h" 18 19 19 20 void *memchr(const void *s, int c, size_t n) 20 21 { ··· 40 39 41 40 /* Read the first word, but munge it so that bytes before the array 42 41 * will not match goal. 43 - * 44 - * Note that this shift count expression works because we know 45 - * shift counts are taken mod 64. 46 42 */ 47 - before_mask = (1ULL << (s_int << 3)) - 1; 43 + before_mask = MASK(s_int); 48 44 v = (*p | before_mask) ^ (goal & before_mask); 49 45 50 46 /* Compute the address of the last byte. */ ··· 63 65 /* We found a match, but it might be in a byte past the end 64 66 * of the array. 65 67 */ 66 - ret = ((char *)p) + (__insn_ctz(bits) >> 3); 68 + ret = ((char *)p) + (CFZ(bits) >> 3); 67 69 return (ret <= last_byte_ptr) ? ret : NULL; 68 70 } 69 71 EXPORT_SYMBOL(memchr);
+21 -2
arch/tile/lib/memcpy_64.c
··· 15 15 #include <linux/types.h> 16 16 #include <linux/string.h> 17 17 #include <linux/module.h> 18 - #define __memcpy memcpy 19 18 /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ 20 19 21 20 /* Must be 8 bytes in size. */ ··· 187 188 188 189 /* n != 0 if we get here. Write out any trailing bytes. */ 189 190 dst1 = (char *)dst8; 191 + #ifndef __BIG_ENDIAN__ 190 192 if (n & 4) { 191 193 ST4((uint32_t *)dst1, final); 192 194 dst1 += 4; ··· 202 202 } 203 203 if (n) 204 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 226 return RETVAL; 207 227 } 208 - 209 228 210 229 #ifdef USERCOPY_FUNC 211 230 #undef ST1
+5 -10
arch/tile/lib/strchr_64.c
··· 15 15 #include <linux/types.h> 16 16 #include <linux/string.h> 17 17 #include <linux/module.h> 18 - 19 - #undef strchr 18 + #include "string-endian.h" 20 19 21 20 char *strchr(const char *s, int c) 22 21 { ··· 32 33 * match neither zero nor goal (we make sure the high bit of each 33 34 * byte is 1, and the low 7 bits are all the opposite of the goal 34 35 * byte). 35 - * 36 - * Note that this shift count expression works because we know shift 37 - * counts are taken mod 64. 38 36 */ 39 - const uint64_t before_mask = (1ULL << (s_int << 3)) - 1; 40 - uint64_t v = (*p | before_mask) ^ 41 - (goal & __insn_v1shrsi(before_mask, 1)); 37 + const uint64_t before_mask = MASK(s_int); 38 + uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1)); 42 39 43 40 uint64_t zero_matches, goal_matches; 44 41 while (1) { ··· 50 55 v = *++p; 51 56 } 52 57 53 - z = __insn_ctz(zero_matches); 54 - g = __insn_ctz(goal_matches); 58 + z = CFZ(zero_matches); 59 + g = CFZ(goal_matches); 55 60 56 61 /* If we found c before '\0' we got a match. Note that if c == '\0' 57 62 * then g == z, and we correctly return the address of the '\0'
+33
arch/tile/lib/string-endian.h
··· 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
+4 -7
arch/tile/lib/strlen_64.c
··· 15 15 #include <linux/types.h> 16 16 #include <linux/string.h> 17 17 #include <linux/module.h> 18 - 19 - #undef strlen 18 + #include "string-endian.h" 20 19 21 20 size_t strlen(const char *s) 22 21 { ··· 23 24 const uintptr_t s_int = (uintptr_t) s; 24 25 const uint64_t *p = (const uint64_t *)(s_int & -8); 25 26 26 - /* Read the first word, but force bytes before the string to be nonzero. 27 - * This expression works because we know shift counts are taken mod 64. 28 - */ 29 - uint64_t v = *p | ((1ULL << (s_int << 3)) - 1); 27 + /* Read and MASK the first word. */ 28 + uint64_t v = *p | MASK(s_int); 30 29 31 30 uint64_t bits; 32 31 while ((bits = __insn_v1cmpeqi(v, 0)) == 0) 33 32 v = *++p; 34 33 35 - return ((const char *)p) + (__insn_ctz(bits) >> 3) - s; 34 + return ((const char *)p) + (CFZ(bits) >> 3) - s; 36 35 } 37 36 EXPORT_SYMBOL(strlen);