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

[XTENSA] Add support for configurable registers and coprocessors

The Xtensa architecture allows to define custom instructions and
registers. Registers that are bound to a coprocessor are only
accessible if the corresponding enable bit is set, which allows
to implement a 'lazy' context switch mechanism. Other registers
needs to be saved and restore at the time of the context switch
or during interrupt handling.

This patch adds support for these additional states:

- save and restore registers that are used by the compiler upon
interrupt entry and exit.
- context switch additional registers unbound to any coprocessor
- 'lazy' context switch of registers bound to a coprocessor
- ptrace interface to provide access to additional registers
- update configuration files in include/asm-xtensa/variant-fsf

Signed-off-by: Chris Zankel <chris@zankel.net>

+1076 -885
+15 -1
arch/xtensa/kernel/asm-offsets.c
··· 63 63 DEFINE(PT_SIZE, sizeof(struct pt_regs)); 64 64 DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS])); 65 65 DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS])); 66 + DEFINE(PT_XTREGS_OPT, offsetof(struct pt_regs, xtregs_opt)); 67 + DEFINE(XTREGS_OPT_SIZE, sizeof(xtregs_opt_t)); 66 68 67 69 /* struct task_struct */ 68 70 DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace)); ··· 78 76 /* struct thread_info (offset from start_struct) */ 79 77 DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); 80 78 DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); 81 - DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save)); 79 + DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable)); 80 + #if XTENSA_HAVE_COPROCESSORS 81 + DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp)); 82 + DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp)); 83 + DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp)); 84 + DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp)); 85 + DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp)); 86 + DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp)); 87 + DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp)); 88 + DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp)); 89 + #endif 90 + DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user)); 91 + DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t)); 82 92 DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds)); 83 93 84 94 /* struct mm_struct */
+296 -161
arch/xtensa/kernel/coprocessor.S
··· 8 8 * License. See the file "COPYING" in the main directory of this archive 9 9 * for more details. 10 10 * 11 - * Copyright (C) 2003 - 2005 Tensilica Inc. 12 - * 13 - * Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca> 11 + * Copyright (C) 2003 - 2007 Tensilica Inc. 14 12 */ 15 13 16 - /* 17 - * This module contains a table that describes the layout of the various 18 - * custom registers and states associated with each coprocessor, as well 19 - * as those not associated with any coprocessor ("extra state"). 20 - * This table is included with core dumps and is available via the ptrace 21 - * interface, allowing the layout of such register/state information to 22 - * be modified in the kernel without affecting the debugger. Each 23 - * register or state is identified using a 32-bit "libdb target number" 24 - * assigned when the Xtensa processor is generated. 25 - */ 26 14 27 15 #include <linux/linkage.h> 16 + #include <asm/asm-offsets.h> 28 17 #include <asm/processor.h> 18 + #include <asm/coprocessor.h> 19 + #include <asm/thread_info.h> 20 + #include <asm/uaccess.h> 21 + #include <asm/unistd.h> 22 + #include <asm/ptrace.h> 23 + #include <asm/current.h> 24 + #include <asm/pgtable.h> 25 + #include <asm/page.h> 26 + #include <asm/signal.h> 27 + #include <asm/tlbflush.h> 29 28 30 - #if XCHAL_HAVE_CP 29 + /* 30 + * Entry condition: 31 + * 32 + * a0: trashed, original value saved on stack (PT_AREG0) 33 + * a1: a1 34 + * a2: new stack pointer, original in DEPC 35 + * a3: dispatch table 36 + * depc: a2, original value saved on stack (PT_DEPC) 37 + * excsave_1: a3 38 + * 39 + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 40 + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 41 + */ 31 42 32 - #define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE) 43 + /* IO protection is currently unsupported. */ 33 44 34 - ENTRY(release_coprocessors) 45 + ENTRY(fast_io_protect) 46 + wsr a0, EXCSAVE_1 47 + movi a0, unrecoverable_exception 48 + callx0 a0 35 49 36 - entry a1, 16 37 - # a2: task 38 - movi a3, 1 << XCHAL_CP_MAX # a3: coprocessor-bit 39 - movi a4, coprocessor_info+CP_LAST # a4: owner-table 40 - # a5: tmp 41 - movi a6, 0 # a6: 0 42 - rsil a7, LOCKLEVEL # a7: PS 50 + #if XTENSA_HAVE_COPROCESSORS 43 51 44 - 1: /* Check if task is coprocessor owner of coprocessor[i]. */ 52 + /* 53 + * Macros for lazy context switch. 54 + */ 45 55 46 - l32i a5, a4, COPROCESSOR_INFO_OWNER 47 - srli a3, a3, 1 56 + #define SAVE_CP_REGS(x) \ 57 + .align 4; \ 58 + .Lsave_cp_regs_cp##x: \ 59 + .if XTENSA_HAVE_COPROCESSOR(x); \ 60 + xchal_cp##x##_store a2 a4 a5 a6 a7; \ 61 + .endif; \ 62 + jx a0 63 + 64 + #define SAVE_CP_REGS_TAB(x) \ 65 + .if XTENSA_HAVE_COPROCESSOR(x); \ 66 + .long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \ 67 + .else; \ 68 + .long 0; \ 69 + .endif; \ 70 + .long THREAD_XTREGS_CP##x 71 + 72 + 73 + #define LOAD_CP_REGS(x) \ 74 + .align 4; \ 75 + .Lload_cp_regs_cp##x: \ 76 + .if XTENSA_HAVE_COPROCESSOR(x); \ 77 + xchal_cp##x##_load a2 a4 a5 a6 a7; \ 78 + .endif; \ 79 + jx a0 80 + 81 + #define LOAD_CP_REGS_TAB(x) \ 82 + .if XTENSA_HAVE_COPROCESSOR(x); \ 83 + .long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \ 84 + .else; \ 85 + .long 0; \ 86 + .endif; \ 87 + .long THREAD_XTREGS_CP##x 88 + 89 + SAVE_CP_REGS(0) 90 + SAVE_CP_REGS(1) 91 + SAVE_CP_REGS(2) 92 + SAVE_CP_REGS(3) 93 + SAVE_CP_REGS(4) 94 + SAVE_CP_REGS(5) 95 + SAVE_CP_REGS(6) 96 + SAVE_CP_REGS(7) 97 + 98 + LOAD_CP_REGS(0) 99 + LOAD_CP_REGS(1) 100 + LOAD_CP_REGS(2) 101 + LOAD_CP_REGS(3) 102 + LOAD_CP_REGS(4) 103 + LOAD_CP_REGS(5) 104 + LOAD_CP_REGS(6) 105 + LOAD_CP_REGS(7) 106 + 107 + .align 4 108 + .Lsave_cp_regs_jump_table: 109 + SAVE_CP_REGS_TAB(0) 110 + SAVE_CP_REGS_TAB(1) 111 + SAVE_CP_REGS_TAB(2) 112 + SAVE_CP_REGS_TAB(3) 113 + SAVE_CP_REGS_TAB(4) 114 + SAVE_CP_REGS_TAB(5) 115 + SAVE_CP_REGS_TAB(6) 116 + SAVE_CP_REGS_TAB(7) 117 + 118 + .Lload_cp_regs_jump_table: 119 + LOAD_CP_REGS_TAB(0) 120 + LOAD_CP_REGS_TAB(1) 121 + LOAD_CP_REGS_TAB(2) 122 + LOAD_CP_REGS_TAB(3) 123 + LOAD_CP_REGS_TAB(4) 124 + LOAD_CP_REGS_TAB(5) 125 + LOAD_CP_REGS_TAB(6) 126 + LOAD_CP_REGS_TAB(7) 127 + 128 + /* 129 + * coprocessor_save(buffer, index) 130 + * a2 a3 131 + * coprocessor_load(buffer, index) 132 + * a2 a3 133 + * 134 + * Save or load coprocessor registers for coprocessor 'index'. 135 + * The register values are saved to or loaded from them 'buffer' address. 136 + * 137 + * Note that these functions don't update the coprocessor_owner information! 138 + * 139 + */ 140 + 141 + ENTRY(coprocessor_save) 142 + entry a1, 32 143 + s32i a0, a1, 0 144 + movi a0, .Lsave_cp_regs_jump_table 145 + addx8 a3, a3, a0 146 + l32i a3, a3, 0 48 147 beqz a3, 1f 49 - addi a4, a4, -8 50 - beq a2, a5, 1b 51 - 52 - /* Found an entry: Clear entry CPENABLE bit to disable CP. */ 53 - 54 - rsr a5, CPENABLE 55 - s32i a6, a4, COPROCESSOR_INFO_OWNER 56 - xor a5, a3, a5 57 - wsr a5, CPENABLE 58 - 59 - bnez a3, 1b 60 - 61 - 1: wsr a7, PS 62 - rsync 148 + add a0, a0, a3 149 + callx0 a0 150 + 1: l32i a0, a1, 0 63 151 retw 64 152 65 - 66 - ENTRY(disable_coprocessor) 67 - entry sp, 16 68 - rsil a7, LOCKLEVEL 69 - rsr a3, CPENABLE 70 - movi a4, 1 71 - ssl a2 72 - sll a4, a4 73 - and a4, a3, a4 74 - xor a3, a3, a4 75 - wsr a3, CPENABLE 76 - wsr a7, PS 77 - rsync 153 + ENTRY(coprocessor_load) 154 + entry a1, 32 155 + s32i a0, a1, 0 156 + movi a0, .Lload_cp_regs_jump_table 157 + addx4 a3, a3, a0 158 + l32i a3, a3, 0 159 + beqz a3, 1f 160 + add a0, a0, a3 161 + callx0 a0 162 + 1: l32i a0, a1, 0 78 163 retw 79 - 80 - ENTRY(enable_coprocessor) 81 - entry sp, 16 82 - rsil a7, LOCKLEVEL 83 - rsr a3, CPENABLE 84 - movi a4, 1 85 - ssl a2 86 - sll a4, a4 87 - or a3, a3, a4 88 - wsr a3, CPENABLE 89 - wsr a7, PS 90 - rsync 91 - retw 92 - 93 - 94 - ENTRY(save_coprocessor_extra) 95 - entry sp, 16 96 - xchal_extra_store_funcbody 97 - retw 98 - 99 - ENTRY(restore_coprocessor_extra) 100 - entry sp, 16 101 - xchal_extra_load_funcbody 102 - retw 103 - 104 - ENTRY(save_coprocessor_registers) 105 - entry sp, 16 106 - xchal_cpi_store_funcbody 107 - retw 108 - 109 - ENTRY(restore_coprocessor_registers) 110 - entry sp, 16 111 - xchal_cpi_load_funcbody 112 - retw 113 - 114 164 115 165 /* 116 - * The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros 117 - * describe the contents of coprocessor & extra save areas in terms of 118 - * undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros. We define these 119 - * latter macros here; they expand into a table of the format we want. 120 - * The general format is: 166 + * coprocessor_flush(struct task_info*, index) 167 + * a2 a3 168 + * coprocessor_restore(struct task_info*, index) 169 + * a2 a3 121 170 * 122 - * CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, 123 - * bitmask, rsv2, rsv3) 124 - * CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, 125 - * bitmask, rsv2, rsv3) 126 - * CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, 127 - * numentries, contentsize, regname_base, 128 - * regfile_name, rsv2, rsv3) 171 + * Save or load coprocessor registers for coprocessor 'index'. 172 + * The register values are saved to or loaded from the coprocessor area 173 + * inside the task_info structure. 129 174 * 130 - * For this table, we only care about the <libdbnum>, <offset> and <size> 131 - * fields. 175 + * Note that these functions don't update the coprocessor_owner information! 176 + * 132 177 */ 133 178 134 - /* Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below: */ 135 179 136 - #define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum, \ 137 - bitmask, rsv2, rsv3) \ 138 - reg_entry libdbnum, offset, size ; 139 - #define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum, \ 140 - bitmask, rsv2, rsv3) \ 141 - reg_entry libdbnum, offset, size ; 142 - #define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \ 143 - numentries, contentsize, regname_base, \ 144 - regfile_name, rsv2, rsv3) \ 145 - reg_entry libdbnum, offset, size ; 180 + ENTRY(coprocessor_flush) 181 + entry a1, 32 182 + s32i a0, a1, 0 183 + movi a0, .Lsave_cp_regs_jump_table 184 + addx8 a3, a3, a0 185 + l32i a4, a3, 4 186 + l32i a3, a3, 0 187 + add a2, a2, a4 188 + beqz a3, 1f 189 + add a0, a0, a3 190 + callx0 a0 191 + 1: l32i a0, a1, 0 192 + retw 146 193 147 - /* A single table entry: */ 148 - .macro reg_entry libdbnum, offset, size 149 - .ifne (__last_offset-(__last_group_offset+\offset)) 150 - /* padding entry */ 151 - .word (0xFC000000+__last_offset-(__last_group_offset+\offset)) 152 - .endif 153 - .word \libdbnum /* actual entry */ 154 - .set __last_offset, __last_group_offset+\offset+\size 155 - .endm /* reg_entry */ 156 - 157 - 158 - /* Table entry that marks the beginning of a group (coprocessor or "extra"): */ 159 - .macro reg_group cpnum, num_entries, align 160 - .set __last_group_offset, (__last_offset + \align- 1) & -\align 161 - .ifne \num_entries 162 - .word 0xFD000000+(\cpnum<<16)+\num_entries 163 - .endif 164 - .endm /* reg_group */ 194 + ENTRY(coprocessor_restore) 195 + entry a1, 32 196 + s32i a0, a1, 0 197 + movi a0, .Lload_cp_regs_jump_table 198 + addx4 a3, a3, a0 199 + l32i a4, a3, 4 200 + l32i a3, a3, 0 201 + add a2, a2, a4 202 + beqz a3, 1f 203 + add a0, a0, a3 204 + callx0 a0 205 + 1: l32i a0, a1, 0 206 + retw 165 207 166 208 /* 167 - * Register info tables. 209 + * Entry condition: 210 + * 211 + * a0: trashed, original value saved on stack (PT_AREG0) 212 + * a1: a1 213 + * a2: new stack pointer, original in DEPC 214 + * a3: dispatch table 215 + * depc: a2, original value saved on stack (PT_DEPC) 216 + * excsave_1: a3 217 + * 218 + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 219 + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 168 220 */ 169 221 170 - .section .rodata, "a" 171 - .globl _xtensa_reginfo_tables 172 - .globl _xtensa_reginfo_table_size 173 - .align 4 174 - _xtensa_reginfo_table_size: 175 - .word _xtensa_reginfo_table_end - _xtensa_reginfo_tables 222 + ENTRY(fast_coprocessor_double) 223 + wsr a0, EXCSAVE_1 224 + movi a0, unrecoverable_exception 225 + callx0 a0 176 226 177 - _xtensa_reginfo_tables: 178 - .set __last_offset, 0 179 - reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN 180 - XCHAL_EXTRA_SA_CONTENTS_LIBDB 181 - reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN 182 - XCHAL_CP0_SA_CONTENTS_LIBDB 183 - reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN 184 - XCHAL_CP1_SA_CONTENTS_LIBDB 185 - reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN 186 - XCHAL_CP2_SA_CONTENTS_LIBDB 187 - reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN 188 - XCHAL_CP3_SA_CONTENTS_LIBDB 189 - reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN 190 - XCHAL_CP4_SA_CONTENTS_LIBDB 191 - reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN 192 - XCHAL_CP5_SA_CONTENTS_LIBDB 193 - reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN 194 - XCHAL_CP6_SA_CONTENTS_LIBDB 195 - reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN 196 - XCHAL_CP7_SA_CONTENTS_LIBDB 197 - .word 0xFC000000 /* invalid register number,marks end of table*/ 198 - _xtensa_reginfo_table_end: 199 - #endif 227 + 228 + ENTRY(fast_coprocessor) 229 + 230 + /* Save remaining registers a1-a3 and SAR */ 231 + 232 + xsr a3, EXCSAVE_1 233 + s32i a3, a2, PT_AREG3 234 + rsr a3, SAR 235 + s32i a1, a2, PT_AREG1 236 + s32i a3, a2, PT_SAR 237 + mov a1, a2 238 + rsr a2, DEPC 239 + s32i a2, a1, PT_AREG2 240 + 241 + /* 242 + * The hal macros require up to 4 temporary registers. We use a3..a6. 243 + */ 244 + 245 + s32i a4, a1, PT_AREG4 246 + s32i a5, a1, PT_AREG5 247 + s32i a6, a1, PT_AREG6 248 + 249 + /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ 250 + 251 + rsr a3, EXCCAUSE 252 + addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED 253 + 254 + /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/ 255 + 256 + ssl a3 # SAR: 32 - coprocessor_number 257 + movi a2, 1 258 + rsr a0, CPENABLE 259 + sll a2, a2 260 + or a0, a0, a2 261 + wsr a0, CPENABLE 262 + rsync 263 + 264 + /* Retrieve previous owner. (a3 still holds CP number) */ 265 + 266 + movi a0, coprocessor_owner # list of owners 267 + addx4 a0, a3, a0 # entry for CP 268 + l32i a4, a0, 0 269 + 270 + beqz a4, 1f # skip 'save' if no previous owner 271 + 272 + /* Disable coprocessor for previous owner. (a2 = 1 << CP number) */ 273 + 274 + l32i a5, a4, THREAD_CPENABLE 275 + xor a5, a5, a2 # (1 << cp-id) still in a2 276 + s32i a5, a4, THREAD_CPENABLE 277 + 278 + /* 279 + * Get context save area and 'call' save routine. 280 + * (a4 still holds previous owner (thread_info), a3 CP number) 281 + */ 282 + 283 + movi a5, .Lsave_cp_regs_jump_table 284 + movi a0, 2f # a0: 'return' address 285 + addx8 a3, a3, a5 # a3: coprocessor number 286 + l32i a2, a3, 4 # a2: xtregs offset 287 + l32i a3, a3, 0 # a3: jump offset 288 + add a2, a2, a4 289 + add a4, a3, a5 # a4: address of save routine 290 + jx a4 291 + 292 + /* Note that only a0 and a1 were preserved. */ 293 + 294 + 2: rsr a3, EXCCAUSE 295 + addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED 296 + movi a0, coprocessor_owner 297 + addx4 a0, a3, a0 298 + 299 + /* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */ 300 + 301 + 1: GET_THREAD_INFO (a4, a1) 302 + s32i a4, a0, 0 303 + 304 + /* Get context save area and 'call' load routine. */ 305 + 306 + movi a5, .Lload_cp_regs_jump_table 307 + movi a0, 1f 308 + addx8 a3, a3, a5 309 + l32i a2, a3, 4 # a2: xtregs offset 310 + l32i a3, a3, 0 # a3: jump offset 311 + add a2, a2, a4 312 + add a4, a3, a5 313 + jx a4 314 + 315 + /* Restore all registers and return from exception handler. */ 316 + 317 + 1: l32i a6, a1, PT_AREG6 318 + l32i a5, a1, PT_AREG5 319 + l32i a4, a1, PT_AREG4 320 + 321 + l32i a0, a1, PT_SAR 322 + l32i a3, a1, PT_AREG3 323 + l32i a2, a1, PT_AREG2 324 + wsr a0, SAR 325 + l32i a0, a1, PT_AREG0 326 + l32i a1, a1, PT_AREG1 327 + 328 + rfe 329 + 330 + .data 331 + ENTRY(coprocessor_owner) 332 + .fill XCHAL_CP_MAX, 4, 0 333 + 334 + #endif /* XTENSA_HAVE_COPROCESSORS */ 200 335
+73 -222
arch/xtensa/kernel/entry.S
··· 25 25 #include <asm/page.h> 26 26 #include <asm/signal.h> 27 27 #include <asm/tlbflush.h> 28 + #include <asm/variant/tie-asm.h> 28 29 29 30 /* Unimplemented features. */ 30 31 ··· 214 213 215 214 /* We are back to the original stack pointer (a1) */ 216 215 217 - 2: 218 - #if XCHAL_EXTRA_SA_SIZE 219 - 220 - /* For user exceptions, save the extra state into the user's TCB. 221 - * Note: We must assume that xchal_extra_store_funcbody destroys a2..a15 222 - */ 223 - 224 - GET_CURRENT(a2,a1) 225 - addi a2, a2, THREAD_CP_SAVE 226 - xchal_extra_store_funcbody 227 - #endif 228 - 229 - /* Now, jump to the common exception handler. */ 216 + 2: /* Now, jump to the common exception handler. */ 230 217 231 218 j common_exception 232 219 ··· 370 381 s32i a2, a1, PT_LBEG 371 382 s32i a3, a1, PT_LEND 372 383 384 + /* Save optional registers. */ 385 + 386 + save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT 387 + 373 388 /* Go to second-level dispatcher. Set up parameters to pass to the 374 389 * exception handler and call the exception handler. 375 390 */ ··· 444 451 /* Restore the state of the task and return from the exception. */ 445 452 446 453 4: /* a2 holds GET_CURRENT(a2,a1) */ 447 - 448 - #if XCHAL_EXTRA_SA_SIZE 449 - 450 - /* For user exceptions, restore the extra state from the user's TCB. */ 451 - 452 - /* Note: a2 still contains GET_CURRENT(a2,a1) */ 453 - addi a2, a2, THREAD_CP_SAVE 454 - xchal_extra_load_funcbody 455 - 456 - /* We must assume that xchal_extra_store_funcbody destroys 457 - * registers a2..a15. FIXME, this list can eventually be 458 - * reduced once real register requirements of the macro are 459 - * finalized. */ 460 - 461 - #endif /* XCHAL_EXTRA_SA_SIZE */ 462 - 463 454 464 455 /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ 465 456 ··· 590 613 */ 591 614 592 615 common_exception_exit: 616 + 617 + /* Restore optional registers. */ 618 + 619 + load_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT 620 + 621 + /* Restore address registers. */ 593 622 594 623 _bbsi.l a2, 1, 1f 595 624 l32i a4, a1, PT_AREG4 ··· 1129 1146 * excsave_1: a3 1130 1147 * 1131 1148 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. 1132 - * Note: We don't need to save a2 in depc (return value) 1133 1149 */ 1134 1150 1135 1151 ENTRY(fast_syscall_spill_registers) ··· 1144 1162 1145 1163 rsr a0, SAR 1146 1164 xsr a3, EXCSAVE_1 # restore a3 and excsave_1 1147 - s32i a0, a2, PT_AREG4 # store SAR to PT_AREG4 1148 1165 s32i a3, a2, PT_AREG3 1166 + s32i a4, a2, PT_AREG4 1167 + s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 1149 1168 1150 1169 /* The spill routine might clobber a7, a11, and a15. */ 1151 1170 1152 - s32i a7, a2, PT_AREG5 1153 - s32i a11, a2, PT_AREG6 1154 - s32i a15, a2, PT_AREG7 1171 + s32i a7, a2, PT_AREG7 1172 + s32i a11, a2, PT_AREG11 1173 + s32i a15, a2, PT_AREG15 1155 1174 1156 - call0 _spill_registers # destroys a3, DEPC, and SAR 1175 + call0 _spill_registers # destroys a3, a4, and SAR 1157 1176 1158 1177 /* Advance PC, restore registers and SAR, and return from exception. */ 1159 1178 1160 - l32i a3, a2, PT_AREG4 1179 + l32i a3, a2, PT_AREG5 1180 + l32i a4, a2, PT_AREG4 1161 1181 l32i a0, a2, PT_AREG0 1162 1182 wsr a3, SAR 1163 1183 l32i a3, a2, PT_AREG3 1164 1184 1165 1185 /* Restore clobbered registers. */ 1166 1186 1167 - l32i a7, a2, PT_AREG5 1168 - l32i a11, a2, PT_AREG6 1169 - l32i a15, a2, PT_AREG7 1187 + l32i a7, a2, PT_AREG7 1188 + l32i a11, a2, PT_AREG11 1189 + l32i a15, a2, PT_AREG15 1170 1190 1171 1191 movi a2, 0 1172 1192 rfe ··· 1241 1257 1242 1258 movi a3, exc_table 1243 1259 rsr a0, EXCCAUSE 1244 - addx4 a0, a0, a3 # find entry in table 1245 - l32i a0, a0, EXC_TABLE_FAST_USER # load handler 1246 - jx a0 1260 + addx4 a0, a0, a3 # find entry in table 1261 + l32i a0, a0, EXC_TABLE_FAST_USER # load handler 1262 + jx a0 1247 1263 1248 1264 fast_syscall_spill_registers_fixup_return: 1249 1265 ··· 1281 1297 * This is not a real function. The following conditions must be met: 1282 1298 * 1283 1299 * - must be called with call0. 1284 - * - uses DEPC, a3 and SAR. 1300 + * - uses a3, a4 and SAR. 1285 1301 * - the last 'valid' register of each frame are clobbered. 1286 1302 * - the caller must have registered a fixup handler 1287 1303 * (or be inside a critical section) ··· 1293 1309 /* 1294 1310 * Rotate ws so that the current windowbase is at bit 0. 1295 1311 * Assume ws = xxxwww1yy (www1 current window frame). 1296 - * Rotate ws right so that a2 = yyxxxwww1. 1312 + * Rotate ws right so that a4 = yyxxxwww1. 1297 1313 */ 1298 1314 1299 - wsr a2, DEPC # preserve a2 1300 - rsr a2, WINDOWBASE 1315 + rsr a4, WINDOWBASE 1301 1316 rsr a3, WINDOWSTART # a3 = xxxwww1yy 1302 - ssr a2 # holds WB 1303 - slli a2, a3, WSBITS 1304 - or a3, a3, a2 # a3 = xxxwww1yyxxxwww1yy 1317 + ssr a4 # holds WB 1318 + slli a4, a3, WSBITS 1319 + or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy 1305 1320 srl a3, a3 # a3 = 00xxxwww1yyxxxwww1 1306 1321 1307 1322 /* We are done if there are no more than the current register frame. */ 1308 1323 1309 1324 extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww 1310 - movi a2, (1 << (WSBITS-1)) 1325 + movi a4, (1 << (WSBITS-1)) 1311 1326 _beqz a3, .Lnospill # only one active frame? jump 1312 1327 1313 1328 /* We want 1 at the top, so that we return to the current windowbase */ 1314 1329 1315 - or a3, a3, a2 # 1yyxxxwww 1330 + or a3, a3, a4 # 1yyxxxwww 1316 1331 1317 1332 /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */ 1318 1333 1319 1334 wsr a3, WINDOWSTART # save shifted windowstart 1320 - neg a2, a3 1321 - and a3, a2, a3 # first bit set from right: 000010000 1335 + neg a4, a3 1336 + and a3, a4, a3 # first bit set from right: 000010000 1322 1337 1323 - ffs_ws a2, a3 # a2: shifts to skip empty frames 1338 + ffs_ws a4, a3 # a4: shifts to skip empty frames 1324 1339 movi a3, WSBITS 1325 - sub a2, a3, a2 # WSBITS-a2:number of 0-bits from right 1326 - ssr a2 # save in SAR for later. 1340 + sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right 1341 + ssr a4 # save in SAR for later. 1327 1342 1328 1343 rsr a3, WINDOWBASE 1329 - add a3, a3, a2 1330 - rsr a2, DEPC # restore a2 1344 + add a3, a3, a4 1331 1345 wsr a3, WINDOWBASE 1332 1346 rsync 1333 1347 ··· 1355 1373 j .Lc12c 1356 1374 1357 1375 .Lnospill: 1358 - rsr a2, DEPC 1359 1376 ret 1360 1377 1361 1378 .Lloop: _bbsi.l a3, 1, .Lc4 ··· 1791 1810 1: j _user_exception 1792 1811 1793 1812 1794 - #if XCHAL_EXTRA_SA_SIZE 1795 - 1796 - #warning fast_coprocessor untested 1797 - 1798 - /* 1799 - * Entry condition: 1800 - * 1801 - * a0: trashed, original value saved on stack (PT_AREG0) 1802 - * a1: a1 1803 - * a2: new stack pointer, original in DEPC 1804 - * a3: dispatch table 1805 - * depc: a2, original value saved on stack (PT_DEPC) 1806 - * excsave_1: a3 1807 - * 1808 - * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1809 - * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1810 - */ 1811 - 1812 - ENTRY(fast_coprocessor_double) 1813 - wsr a0, EXCSAVE_1 1814 - movi a0, unrecoverable_exception 1815 - callx0 a0 1816 - 1817 - ENTRY(fast_coprocessor) 1818 - 1819 - /* Fatal if we are in a double exception. */ 1820 - 1821 - l32i a0, a2, PT_DEPC 1822 - _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_coprocessor_double 1823 - 1824 - /* Save some registers a1, a3, a4, SAR */ 1825 - 1826 - xsr a3, EXCSAVE_1 1827 - s32i a3, a2, PT_AREG3 1828 - rsr a3, SAR 1829 - s32i a4, a2, PT_AREG4 1830 - s32i a1, a2, PT_AREG1 1831 - s32i a5, a1, PT_AREG5 1832 - s32i a3, a2, PT_SAR 1833 - mov a1, a2 1834 - 1835 - /* Currently, the HAL macros only guarantee saving a0 and a1. 1836 - * These can and will be refined in the future, but for now, 1837 - * just save the remaining registers of a2...a15. 1838 - */ 1839 - s32i a6, a1, PT_AREG6 1840 - s32i a7, a1, PT_AREG7 1841 - s32i a8, a1, PT_AREG8 1842 - s32i a9, a1, PT_AREG9 1843 - s32i a10, a1, PT_AREG10 1844 - s32i a11, a1, PT_AREG11 1845 - s32i a12, a1, PT_AREG12 1846 - s32i a13, a1, PT_AREG13 1847 - s32i a14, a1, PT_AREG14 1848 - s32i a15, a1, PT_AREG15 1849 - 1850 - /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ 1851 - 1852 - rsr a0, EXCCAUSE 1853 - addi a3, a0, -XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED 1854 - 1855 - /* Set corresponding CPENABLE bit */ 1856 - 1857 - movi a4, 1 1858 - ssl a3 # SAR: 32 - coprocessor_number 1859 - rsr a5, CPENABLE 1860 - sll a4, a4 1861 - or a4, a5, a4 1862 - wsr a4, CPENABLE 1863 - rsync 1864 - movi a5, coprocessor_info # list of owner and offset into cp_save 1865 - addx8 a0, a4, a5 # entry for CP 1866 - 1867 - bne a4, a5, .Lload # bit wasn't set before, cp not in use 1868 - 1869 - /* Now compare the current task with the owner of the coprocessor. 1870 - * If they are the same, there is no reason to save or restore any 1871 - * coprocessor state. Having already enabled the coprocessor, 1872 - * branch ahead to return. 1873 - */ 1874 - GET_CURRENT(a5,a1) 1875 - l32i a4, a0, COPROCESSOR_INFO_OWNER # a4: current owner for this CP 1876 - beq a4, a5, .Ldone 1877 - 1878 - /* Find location to dump current coprocessor state: 1879 - * task_struct->task_cp_save_offset + coprocessor_offset[coprocessor] 1880 - * 1881 - * Note: a0 pointer to the entry in the coprocessor owner table, 1882 - * a3 coprocessor number, 1883 - * a4 current owner of coprocessor. 1884 - */ 1885 - l32i a5, a0, COPROCESSOR_INFO_OFFSET 1886 - addi a2, a4, THREAD_CP_SAVE 1887 - add a2, a2, a5 1888 - 1889 - /* Store current coprocessor states. (a5 still has CP number) */ 1890 - 1891 - xchal_cpi_store_funcbody 1892 - 1893 - /* The macro might have destroyed a3 (coprocessor number), but 1894 - * SAR still has 32 - coprocessor_number! 1895 - */ 1896 - movi a3, 32 1897 - rsr a4, SAR 1898 - sub a3, a3, a4 1899 - 1900 - .Lload: /* A new task now owns the corpocessors. Save its TCB pointer into 1901 - * the coprocessor owner table. 1902 - * 1903 - * Note: a0 pointer to the entry in the coprocessor owner table, 1904 - * a3 coprocessor number. 1905 - */ 1906 - GET_CURRENT(a4,a1) 1907 - s32i a4, a0, 0 1908 - 1909 - /* Find location from where to restore the current coprocessor state.*/ 1910 - 1911 - l32i a5, a0, COPROCESSOR_INFO_OFFSET 1912 - addi a2, a4, THREAD_CP_SAVE 1913 - add a2, a2, a4 1914 - 1915 - xchal_cpi_load_funcbody 1916 - 1917 - /* We must assume that the xchal_cpi_store_funcbody macro destroyed 1918 - * registers a2..a15. 1919 - */ 1920 - 1921 - .Ldone: l32i a15, a1, PT_AREG15 1922 - l32i a14, a1, PT_AREG14 1923 - l32i a13, a1, PT_AREG13 1924 - l32i a12, a1, PT_AREG12 1925 - l32i a11, a1, PT_AREG11 1926 - l32i a10, a1, PT_AREG10 1927 - l32i a9, a1, PT_AREG9 1928 - l32i a8, a1, PT_AREG8 1929 - l32i a7, a1, PT_AREG7 1930 - l32i a6, a1, PT_AREG6 1931 - l32i a5, a1, PT_AREG5 1932 - l32i a4, a1, PT_AREG4 1933 - l32i a3, a1, PT_AREG3 1934 - l32i a2, a1, PT_AREG2 1935 - l32i a0, a1, PT_AREG0 1936 - l32i a1, a1, PT_AREG1 1937 - 1938 - rfe 1939 - 1940 - #endif /* XCHAL_EXTRA_SA_SIZE */ 1941 - 1942 1813 /* 1943 1814 * System Calls. 1944 1815 * ··· 1899 2066 1900 2067 entry a1, 16 1901 2068 1902 - mov a4, a3 # preserve a3 2069 + mov a12, a2 # preserve 'prev' (a2) 2070 + mov a13, a3 # and 'next' (a3) 1903 2071 1904 - s32i a0, a2, THREAD_RA # save return address 1905 - s32i a1, a2, THREAD_SP # save stack pointer 2072 + l32i a4, a2, TASK_THREAD_INFO 2073 + l32i a5, a3, TASK_THREAD_INFO 1906 2074 1907 - /* Disable ints while we manipulate the stack pointer; spill regs. */ 2075 + save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER 1908 2076 1909 - movi a5, (1 << PS_EXCM_BIT) | LOCKLEVEL 1910 - xsr a5, PS 2077 + s32i a0, a12, THREAD_RA # save return address 2078 + s32i a1, a12, THREAD_SP # save stack pointer 2079 + 2080 + /* Disable ints while we manipulate the stack pointer. */ 2081 + 2082 + movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL 2083 + xsr a14, PS 1911 2084 rsr a3, EXCSAVE_1 1912 2085 rsync 1913 2086 s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */ 1914 2087 1915 - call0 _spill_registers 2088 + /* Switch CPENABLE */ 2089 + 2090 + #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) 2091 + l32i a3, a5, THREAD_CPENABLE 2092 + xsr a3, CPENABLE 2093 + s32i a3, a4, THREAD_CPENABLE 2094 + #endif 2095 + 2096 + /* Flush register file. */ 2097 + 2098 + call0 _spill_registers # destroys a3, a4, and SAR 1916 2099 1917 2100 /* Set kernel stack (and leave critical section) 1918 2101 * Note: It's save to set it here. The stack will not be overwritten ··· 1936 2087 * we return from kernel space. 1937 2088 */ 1938 2089 1939 - l32i a0, a4, TASK_THREAD_INFO 1940 2090 rsr a3, EXCSAVE_1 # exc_table 1941 - movi a1, 0 1942 - addi a0, a0, PT_REGS_OFFSET 1943 - s32i a1, a3, EXC_TABLE_FIXUP 1944 - s32i a0, a3, EXC_TABLE_KSTK 2091 + movi a6, 0 2092 + addi a7, a5, PT_REGS_OFFSET 2093 + s32i a6, a3, EXC_TABLE_FIXUP 2094 + s32i a7, a3, EXC_TABLE_KSTK 1945 2095 1946 2096 /* restore context of the task that 'next' addresses */ 1947 2097 1948 - l32i a0, a4, THREAD_RA /* restore return address */ 1949 - l32i a1, a4, THREAD_SP /* restore stack pointer */ 2098 + l32i a0, a13, THREAD_RA # restore return address 2099 + l32i a1, a13, THREAD_SP # restore stack pointer 1950 2100 1951 - wsr a5, PS 2101 + load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER 2102 + 2103 + wsr a14, PS 2104 + mov a2, a12 # return 'prev' 1952 2105 rsync 1953 2106 1954 2107 retw
+102 -159
arch/xtensa/kernel/process.c
··· 52 52 EXPORT_SYMBOL(pm_power_off); 53 53 54 54 55 + #if XTENSA_HAVE_COPROCESSORS 56 + 57 + void coprocessor_release_all(struct thread_info *ti) 58 + { 59 + unsigned long cpenable; 60 + int i; 61 + 62 + /* Make sure we don't switch tasks during this operation. */ 63 + 64 + preempt_disable(); 65 + 66 + /* Walk through all cp owners and release it for the requested one. */ 67 + 68 + cpenable = ti->cpenable; 69 + 70 + for (i = 0; i < XCHAL_CP_MAX; i++) { 71 + if (coprocessor_owner[i] == ti) { 72 + coprocessor_owner[i] = 0; 73 + cpenable &= ~(1 << i); 74 + } 75 + } 76 + 77 + ti->cpenable = cpenable; 78 + coprocessor_clear_cpenable(); 79 + 80 + preempt_enable(); 81 + } 82 + 83 + void coprocessor_flush_all(struct thread_info *ti) 84 + { 85 + unsigned long cpenable; 86 + int i; 87 + 88 + preempt_disable(); 89 + 90 + cpenable = ti->cpenable; 91 + 92 + for (i = 0; i < XCHAL_CP_MAX; i++) { 93 + if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti) 94 + coprocessor_flush(ti, i); 95 + cpenable >>= 1; 96 + } 97 + 98 + preempt_enable(); 99 + } 100 + 101 + #endif 102 + 103 + 55 104 /* 56 105 * Powermanagement idle function, if any is provided by the platform. 57 106 */ ··· 120 71 } 121 72 122 73 /* 123 - * Free current thread data structures etc.. 74 + * This is called when the thread calls exit(). 124 75 */ 125 - 126 76 void exit_thread(void) 127 77 { 78 + #if XTENSA_HAVE_COPROCESSORS 79 + coprocessor_release_all(current_thread_info()); 80 + #endif 128 81 } 129 82 83 + /* 84 + * Flush thread state. This is called when a thread does an execve() 85 + * Note that we flush coprocessor registers for the case execve fails. 86 + */ 130 87 void flush_thread(void) 131 88 { 89 + #if XTENSA_HAVE_COPROCESSORS 90 + struct thread_info *ti = current_thread_info(); 91 + coprocessor_flush_all(ti); 92 + coprocessor_release_all(ti); 93 + #endif 94 + } 95 + 96 + /* 97 + * This is called before the thread is copied. 98 + */ 99 + void prepare_to_copy(struct task_struct *tsk) 100 + { 101 + #if XTENSA_HAVE_COPROCESSORS 102 + coprocessor_flush_all(task_thread_info(tsk)); 103 + #endif 132 104 } 133 105 134 106 /* ··· 177 107 struct task_struct * p, struct pt_regs * regs) 178 108 { 179 109 struct pt_regs *childregs; 110 + struct thread_info *ti; 180 111 unsigned long tos; 181 112 int user_mode = user_mode(regs); 182 113 ··· 199 128 p->set_child_tid = p->clear_child_tid = NULL; 200 129 p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1); 201 130 p->thread.sp = (unsigned long)childregs; 131 + 202 132 if (user_mode(regs)) { 203 133 204 134 int len = childregs->wmask & ~0xf; 205 135 childregs->areg[1] = usp; 206 136 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], 207 137 &regs->areg[XCHAL_NUM_AREGS - len/4], len); 208 - 138 + // FIXME: we need to set THREADPTR in thread_info... 209 139 if (clone_flags & CLONE_SETTLS) 210 140 childregs->areg[2] = childregs->areg[6]; 211 141 ··· 214 142 /* In kernel space, we start a new thread with a new stack. */ 215 143 childregs->wmask = 1; 216 144 } 145 + 146 + #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) 147 + ti = task_thread_info(p); 148 + ti->cpenable = 0; 149 + #endif 150 + 217 151 return 0; 218 152 } 219 153 ··· 257 179 } 258 180 259 181 /* 260 - * do_copy_regs() gathers information from 'struct pt_regs' and 261 - * 'current->thread.areg[]' to fill in the xtensa_gregset_t 262 - * structure. 263 - * 264 182 * xtensa_gregset_t and 'struct pt_regs' are vastly different formats 265 183 * of processor registers. Besides different ordering, 266 184 * xtensa_gregset_t contains non-live register information that ··· 265 191 * 266 192 */ 267 193 268 - void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, 269 - struct task_struct *tsk) 194 + void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) 270 195 { 196 + unsigned long wb, ws, wm; 197 + int live, last; 198 + 199 + wb = regs->windowbase; 200 + ws = regs->windowstart; 201 + wm = regs->wmask; 202 + ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1); 203 + 204 + /* Don't leak any random bits. */ 205 + 206 + memset(elfregs, 0, sizeof (elfregs)); 207 + 271 208 /* Note: PS.EXCM is not set while user task is running; its 272 209 * being set in regs->ps is for exception handling convenience. 273 210 */ ··· 289 204 elfregs->lend = regs->lend; 290 205 elfregs->lcount = regs->lcount; 291 206 elfregs->sar = regs->sar; 207 + elfregs->windowstart = ws; 292 208 293 - memcpy (elfregs->a, regs->areg, sizeof(elfregs->a)); 209 + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 210 + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; 211 + memcpy(elfregs->a, regs->areg, live * 4); 212 + memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16); 294 213 } 295 214 296 - void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) 215 + int dump_fpu(void) 297 216 { 298 - do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current); 299 - } 300 - 301 - 302 - /* The inverse of do_copy_regs(). No error or sanity checking. */ 303 - 304 - void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, 305 - struct task_struct *tsk) 306 - { 307 - const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; 308 - unsigned long ps; 309 - 310 - /* Note: PS.EXCM is not set while user task is running; it 311 - * needs to be set in regs->ps is for exception handling convenience. 312 - */ 313 - 314 - ps = (regs->ps & ~ps_mask) | (elfregs->ps & ps_mask) | (1<<PS_EXCM_BIT); 315 - regs->ps = ps; 316 - regs->pc = elfregs->pc; 317 - regs->lbeg = elfregs->lbeg; 318 - regs->lend = elfregs->lend; 319 - regs->lcount = elfregs->lcount; 320 - regs->sar = elfregs->sar; 321 - 322 - memcpy (regs->areg, elfregs->a, sizeof(regs->areg)); 323 - } 324 - 325 - /* 326 - * do_save_fpregs() gathers information from 'struct pt_regs' and 327 - * 'current->thread' to fill in the elf_fpregset_t structure. 328 - * 329 - * Core files and ptrace use elf_fpregset_t. 330 - */ 331 - 332 - void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs, 333 - struct task_struct *tsk) 334 - { 335 - #if XCHAL_HAVE_CP 336 - 337 - extern unsigned char _xtensa_reginfo_tables[]; 338 - extern unsigned _xtensa_reginfo_table_size; 339 - int i; 340 - unsigned long flags; 341 - 342 - /* Before dumping coprocessor state from memory, 343 - * ensure any live coprocessor contents for this 344 - * task are first saved to memory: 345 - */ 346 - local_irq_save(flags); 347 - 348 - for (i = 0; i < XCHAL_CP_MAX; i++) { 349 - if (tsk == coprocessor_info[i].owner) { 350 - enable_coprocessor(i); 351 - save_coprocessor_registers( 352 - tsk->thread.cp_save+coprocessor_info[i].offset,i); 353 - disable_coprocessor(i); 354 - } 355 - } 356 - 357 - local_irq_restore(flags); 358 - 359 - /* Now dump coprocessor & extra state: */ 360 - memcpy((unsigned char*)fpregs, 361 - _xtensa_reginfo_tables, _xtensa_reginfo_table_size); 362 - memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size, 363 - tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); 364 - #endif 365 - } 366 - 367 - /* 368 - * The inverse of do_save_fpregs(). 369 - * Copies coprocessor and extra state from fpregs into regs and tsk->thread. 370 - * Returns 0 on success, non-zero if layout doesn't match. 371 - */ 372 - 373 - int do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs, 374 - struct task_struct *tsk) 375 - { 376 - #if XCHAL_HAVE_CP 377 - 378 - extern unsigned char _xtensa_reginfo_tables[]; 379 - extern unsigned _xtensa_reginfo_table_size; 380 - int i; 381 - unsigned long flags; 382 - 383 - /* Make sure save area layouts match. 384 - * FIXME: in the future we could allow restoring from 385 - * a different layout of the same registers, by comparing 386 - * fpregs' table with _xtensa_reginfo_tables and matching 387 - * entries and copying registers one at a time. 388 - * Not too sure yet whether that's very useful. 389 - */ 390 - 391 - if( memcmp((unsigned char*)fpregs, 392 - _xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) { 393 - return -1; 394 - } 395 - 396 - /* Before restoring coprocessor state from memory, 397 - * ensure any live coprocessor contents for this 398 - * task are first invalidated. 399 - */ 400 - 401 - local_irq_save(flags); 402 - 403 - for (i = 0; i < XCHAL_CP_MAX; i++) { 404 - if (tsk == coprocessor_info[i].owner) { 405 - enable_coprocessor(i); 406 - save_coprocessor_registers( 407 - tsk->thread.cp_save+coprocessor_info[i].offset,i); 408 - coprocessor_info[i].owner = 0; 409 - disable_coprocessor(i); 410 - } 411 - } 412 - 413 - local_irq_restore(flags); 414 - 415 - /* Now restore coprocessor & extra state: */ 416 - 417 - memcpy(tsk->thread.cp_save, 418 - (unsigned char*)fpregs + _xtensa_reginfo_table_size, 419 - XTENSA_CP_EXTRA_SIZE); 420 - #endif 421 217 return 0; 422 - } 423 - /* 424 - * Fill in the CP structure for a core dump for a particular task. 425 - */ 426 - 427 - int 428 - dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r) 429 - { 430 - return 0; /* no coprocessors active on this processor */ 431 - } 432 - 433 - /* 434 - * Fill in the CP structure for a core dump. 435 - * This includes any FPU coprocessor. 436 - * Here, we dump all coprocessors, and other ("extra") custom state. 437 - * 438 - * This function is called by elf_core_dump() in fs/binfmt_elf.c 439 - * (in which case 'regs' comes from calls to do_coredump, see signals.c). 440 - */ 441 - int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) 442 - { 443 - return dump_task_fpu(regs, current, r); 444 218 } 445 219 446 220 asmlinkage ··· 314 370 } 315 371 316 372 /* 317 - * * xtensa_execve() executes a new program. 318 - * */ 373 + * xtensa_execve() executes a new program. 374 + */ 319 375 320 376 asmlinkage 321 377 long xtensa_execve(char __user *name, char __user * __user *argv, ··· 330 386 error = PTR_ERR(filename); 331 387 if (IS_ERR(filename)) 332 388 goto out; 333 - // FIXME: release coprocessor?? 334 389 error = do_execve(filename, argv, envp, regs); 335 390 if (error == 0) { 336 391 task_lock(current);
+194 -173
arch/xtensa/kernel/ptrace.c
··· 4 4 * License. See the file "COPYING" in the main directory of this archive 5 5 * for more details. 6 6 * 7 - * Copyright (C) 2001 - 2005 Tensilica Inc. 7 + * Copyright (C) 2001 - 2007 Tensilica Inc. 8 8 * 9 9 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> 10 10 * Chris Zankel <chris@zankel.net> ··· 28 28 #include <asm/uaccess.h> 29 29 #include <asm/ptrace.h> 30 30 #include <asm/elf.h> 31 - 32 - #define TEST_KERNEL // verify kernel operations FIXME: remove 33 - 31 + #include <asm/coprocessor.h> 34 32 35 33 /* 36 - * Called by kernel/ptrace.c when detaching.. 37 - * 38 - * Make sure single step bits etc are not set. 34 + * Called by kernel/ptrace.c when detaching to disable single stepping. 39 35 */ 40 36 41 37 void ptrace_disable(struct task_struct *child) ··· 39 43 /* Nothing to do.. */ 40 44 } 41 45 42 - long arch_ptrace(struct task_struct *child, long request, long addr, long data) 46 + int ptrace_getregs(struct task_struct *child, void __user *uregs) 43 47 { 44 - int ret = -EPERM; 48 + struct pt_regs *regs = task_pt_regs(child); 49 + xtensa_gregset_t __user *gregset = uregs; 50 + unsigned long wb = regs->windowbase; 51 + unsigned long ws = regs->windowstart; 52 + unsigned long wm = regs->wmask; 53 + int ret = 0; 54 + int live, last; 45 55 46 - switch (request) { 47 - case PTRACE_PEEKTEXT: /* read word at location addr. */ 48 - case PTRACE_PEEKDATA: 49 - ret = generic_ptrace_peekdata(child, addr, data); 50 - goto out; 56 + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 57 + return -EIO; 51 58 52 - /* Read the word at location addr in the USER area. */ 59 + /* Norm windowstart to a windowbase of 0. */ 53 60 54 - case PTRACE_PEEKUSR: 55 - { 56 - struct pt_regs *regs; 57 - unsigned long tmp; 61 + ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); 58 62 59 - regs = task_pt_regs(child); 60 - tmp = 0; /* Default return value. */ 63 + ret |= __put_user(regs->pc, &gregset->pc); 64 + ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); 65 + ret |= __put_user(regs->lbeg, &gregset->lbeg); 66 + ret |= __put_user(regs->lend, &gregset->lend); 67 + ret |= __put_user(regs->lcount, &gregset->lcount); 68 + ret |= __put_user(ws, &gregset->windowstart); 61 69 62 - switch(addr) { 70 + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 71 + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; 72 + ret |= __copy_to_user(gregset->a, regs->areg, live * 4); 73 + ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16); 74 + 75 + return ret ? -EFAULT : 0; 76 + } 77 + 78 + int ptrace_setregs(struct task_struct *child, void __user *uregs) 79 + { 80 + struct pt_regs *regs = task_pt_regs(child); 81 + xtensa_gregset_t *gregset = uregs; 82 + const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; 83 + unsigned long wm = regs->wmask; 84 + unsigned long ps; 85 + int ret = 0; 86 + int live, last; 87 + 88 + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 89 + return -EIO; 90 + 91 + ret |= __get_user(regs->pc, &gregset->pc); 92 + ret |= __get_user(ps, &gregset->ps); 93 + ret |= __get_user(regs->lbeg, &gregset->lbeg); 94 + ret |= __get_user(regs->lend, &gregset->lend); 95 + ret |= __get_user(regs->lcount, &gregset->lcount); 96 + 97 + regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); 98 + 99 + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 100 + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; 101 + ret |= __copy_from_user(regs->areg, gregset->a, live * 4); 102 + ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16); 103 + 104 + return ret ? -EFAULT : 0; 105 + } 106 + 107 + 108 + int ptrace_getxregs(struct task_struct *child, void __user *uregs) 109 + { 110 + struct pt_regs *regs = task_pt_regs(child); 111 + struct thread_info *ti = task_thread_info(child); 112 + elf_xtregs_t __user *xtregs = uregs; 113 + int ret = 0; 114 + 115 + if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) 116 + return -EIO; 117 + 118 + #if XTENSA_HAVE_COPROCESSORS 119 + /* Flush all coprocessor registers to memory. */ 120 + coprocessor_flush_all(ti); 121 + ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp, 122 + sizeof(xtregs_coprocessor_t)); 123 + #endif 124 + ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt, 125 + sizeof(xtregs->opt)); 126 + ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, 127 + sizeof(xtregs->user)); 128 + 129 + return ret ? -EFAULT : 0; 130 + } 131 + 132 + int ptrace_setxregs(struct task_struct *child, void __user *uregs) 133 + { 134 + struct thread_info *ti = task_thread_info(child); 135 + struct pt_regs *regs = task_pt_regs(child); 136 + elf_xtregs_t *xtregs = uregs; 137 + int ret = 0; 138 + 139 + #if XTENSA_HAVE_COPROCESSORS 140 + /* Flush all coprocessors before we overwrite them. */ 141 + coprocessor_flush_all(ti); 142 + coprocessor_release_all(ti); 143 + 144 + ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, 145 + sizeof(xtregs_coprocessor_t)); 146 + #endif 147 + ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt, 148 + sizeof(xtregs->opt)); 149 + ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, 150 + sizeof(xtregs->user)); 151 + 152 + return ret ? -EFAULT : 0; 153 + } 154 + 155 + int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret) 156 + { 157 + struct pt_regs *regs; 158 + unsigned long tmp; 159 + 160 + regs = task_pt_regs(child); 161 + tmp = 0; /* Default return value. */ 162 + 163 + switch(regno) { 63 164 64 165 case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 65 - { 66 - int ar = addr - REG_AR_BASE - regs->windowbase * 4; 67 - ar &= (XCHAL_NUM_AREGS - 1); 68 - if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) 69 - tmp = regs->areg[ar]; 70 - else 71 - ret = -EIO; 166 + tmp = regs->areg[regno - REG_AR_BASE]; 72 167 break; 73 - } 168 + 74 169 case REG_A_BASE ... REG_A_BASE + 15: 75 - tmp = regs->areg[addr - REG_A_BASE]; 170 + tmp = regs->areg[regno - REG_A_BASE]; 76 171 break; 172 + 77 173 case REG_PC: 78 174 tmp = regs->pc; 79 175 break; 176 + 80 177 case REG_PS: 81 178 /* Note: PS.EXCM is not set while user task is running; 82 179 * its being set in regs is for exception handling 83 180 * convenience. */ 84 181 tmp = (regs->ps & ~(1 << PS_EXCM_BIT)); 85 182 break; 183 + 86 184 case REG_WB: 87 - tmp = regs->windowbase; 88 - break; 185 + break; /* tmp = 0 */ 186 + 89 187 case REG_WS: 90 - tmp = regs->windowstart; 188 + { 189 + unsigned long wb = regs->windowbase; 190 + unsigned long ws = regs->windowstart; 191 + tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); 91 192 break; 193 + } 92 194 case REG_LBEG: 93 195 tmp = regs->lbeg; 94 196 break; 197 + 95 198 case REG_LEND: 96 199 tmp = regs->lend; 97 200 break; 201 + 98 202 case REG_LCOUNT: 99 203 tmp = regs->lcount; 100 204 break; 205 + 101 206 case REG_SAR: 102 207 tmp = regs->sar; 103 208 break; 104 - case REG_DEPC: 105 - tmp = regs->depc; 106 - break; 107 - case REG_EXCCAUSE: 108 - tmp = regs->exccause; 109 - break; 110 - case REG_EXCVADDR: 111 - tmp = regs->excvaddr; 112 - break; 209 + 113 210 case SYSCALL_NR: 114 211 tmp = regs->syscall; 115 212 break; 116 - default: 117 - tmp = 0; 118 - ret = -EIO; 119 - goto out; 120 - } 121 - ret = put_user(tmp, (unsigned long *) data); 122 - goto out; 123 - } 124 213 125 - case PTRACE_POKETEXT: /* write the word at location addr. */ 214 + default: 215 + return -EIO; 216 + } 217 + return put_user(tmp, ret); 218 + } 219 + 220 + int ptrace_pokeusr(struct task_struct *child, long regno, long val) 221 + { 222 + struct pt_regs *regs; 223 + regs = task_pt_regs(child); 224 + 225 + switch (regno) { 226 + case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 227 + regs->areg[regno - REG_AR_BASE] = val; 228 + break; 229 + 230 + case REG_A_BASE ... REG_A_BASE + 15: 231 + regs->areg[regno - REG_A_BASE] = val; 232 + break; 233 + 234 + case REG_PC: 235 + regs->pc = val; 236 + break; 237 + 238 + case SYSCALL_NR: 239 + regs->syscall = val; 240 + break; 241 + 242 + default: 243 + return -EIO; 244 + } 245 + return 0; 246 + } 247 + 248 + long arch_ptrace(struct task_struct *child, long request, long addr, long data) 249 + { 250 + int ret = -EPERM; 251 + 252 + switch (request) { 253 + case PTRACE_PEEKTEXT: /* read word at location addr. */ 254 + case PTRACE_PEEKDATA: 255 + ret = generic_ptrace_peekdata(child, addr, data); 256 + break; 257 + 258 + case PTRACE_PEEKUSR: /* read register specified by addr. */ 259 + ret = ptrace_peekusr(child, addr, (void __user *) data); 260 + break; 261 + 262 + case PTRACE_POKETEXT: /* write the word at location addr. */ 126 263 case PTRACE_POKEDATA: 127 264 ret = generic_ptrace_pokedata(child, addr, data); 128 - goto out; 129 - 130 - case PTRACE_POKEUSR: 131 - { 132 - struct pt_regs *regs; 133 - regs = task_pt_regs(child); 134 - 135 - switch (addr) { 136 - case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 137 - { 138 - int ar = addr - REG_AR_BASE - regs->windowbase * 4; 139 - if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) 140 - regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data; 141 - else 142 - ret = -EIO; 143 - break; 144 - } 145 - case REG_A_BASE ... REG_A_BASE + 15: 146 - regs->areg[addr - REG_A_BASE] = data; 147 - break; 148 - case REG_PC: 149 - regs->pc = data; 150 - break; 151 - case SYSCALL_NR: 152 - regs->syscall = data; 153 - break; 154 - #ifdef TEST_KERNEL 155 - case REG_WB: 156 - regs->windowbase = data; 157 - break; 158 - case REG_WS: 159 - regs->windowstart = data; 160 - break; 161 - #endif 162 - 163 - default: 164 - /* The rest are not allowed. */ 165 - ret = -EIO; 166 - break; 167 - } 168 265 break; 169 - } 266 + 267 + case PTRACE_POKEUSR: /* write register specified by addr. */ 268 + ret = ptrace_pokeusr(child, addr, data); 269 + break; 170 270 171 271 /* continue and stop at next (return from) syscall */ 272 + 172 273 case PTRACE_SYSCALL: 173 274 case PTRACE_CONT: /* restart after signal. */ 174 275 { ··· 310 217 break; 311 218 312 219 case PTRACE_GETREGS: 313 - { 314 - /* 'data' points to user memory in which to write. 315 - * Mainly due to the non-live register values, we 316 - * reformat the register values into something more 317 - * standard. For convenience, we use the handy 318 - * elf_gregset_t format. */ 319 - 320 - xtensa_gregset_t format; 321 - struct pt_regs *regs = task_pt_regs(child); 322 - 323 - do_copy_regs (&format, regs, child); 324 - 325 - /* Now, copy to user space nice and easy... */ 326 - ret = 0; 327 - if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t))) 328 - ret = -EFAULT; 220 + ret = ptrace_getregs(child, (void __user *) data); 329 221 break; 330 - } 331 222 332 223 case PTRACE_SETREGS: 333 - { 334 - /* 'data' points to user memory that contains the new 335 - * values in the elf_gregset_t format. */ 336 - 337 - xtensa_gregset_t format; 338 - struct pt_regs *regs = task_pt_regs(child); 339 - 340 - if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){ 341 - ret = -EFAULT; 342 - break; 343 - } 344 - 345 - /* FIXME: Perhaps we want some sanity checks on 346 - * these user-space values? See ARM version. Are 347 - * debuggers a security concern? */ 348 - 349 - do_restore_regs (&format, regs, child); 350 - 351 - ret = 0; 224 + ret = ptrace_setregs(child, (void __user *) data); 352 225 break; 353 - } 354 226 355 - case PTRACE_GETFPREGS: 356 - { 357 - /* 'data' points to user memory in which to write. 358 - * For convenience, we use the handy 359 - * elf_fpregset_t format. */ 360 - 361 - elf_fpregset_t fpregs; 362 - struct pt_regs *regs = task_pt_regs(child); 363 - 364 - do_save_fpregs (&fpregs, regs, child); 365 - 366 - /* Now, copy to user space nice and easy... */ 367 - ret = 0; 368 - if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t))) 369 - ret = -EFAULT; 370 - 227 + case PTRACE_GETXTREGS: 228 + ret = ptrace_getxregs(child, (void __user *) data); 371 229 break; 372 - } 373 230 374 - case PTRACE_SETFPREGS: 375 - { 376 - /* 'data' points to user memory that contains the new 377 - * values in the elf_fpregset_t format. 378 - */ 379 - elf_fpregset_t fpregs; 380 - struct pt_regs *regs = task_pt_regs(child); 381 - 382 - ret = 0; 383 - if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) { 384 - ret = -EFAULT; 385 - break; 386 - } 387 - 388 - if (do_restore_fpregs (&fpregs, regs, child)) 389 - ret = -EIO; 390 - break; 391 - } 392 - 393 - case PTRACE_GETFPREGSIZE: 394 - /* 'data' points to 'unsigned long' set to the size 395 - * of elf_fpregset_t 396 - */ 397 - ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data); 231 + case PTRACE_SETXTREGS: 232 + ret = ptrace_setxregs(child, (void __user *) data); 398 233 break; 399 234 400 235 default: 401 236 ret = ptrace_request(child, request, addr, data); 402 - goto out; 237 + break; 403 238 } 404 - out: 239 + 405 240 return ret; 406 241 } 407 242
+42 -23
arch/xtensa/kernel/signal.c
··· 35 35 36 36 extern struct task_struct *coproc_owners[]; 37 37 38 - extern void release_all_cp (struct task_struct *); 39 - 40 38 struct rt_sigframe 41 39 { 42 40 struct siginfo info; 43 41 struct ucontext uc; 44 - cp_state_t cpstate; 42 + struct { 43 + xtregs_opt_t opt; 44 + xtregs_user_t user; 45 + #if XTENSA_HAVE_COPROCESSORS 46 + xtregs_coprocessor_t cp; 47 + #endif 48 + } xtregs; 45 49 unsigned char retcode[6]; 46 50 unsigned int window[4]; 47 51 }; ··· 136 132 */ 137 133 138 134 static int 139 - setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, 140 - struct pt_regs *regs) 135 + setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs) 141 136 { 137 + struct sigcontext __user *sc = &frame->uc.uc_mcontext; 138 + struct thread_info *ti = current_thread_info(); 142 139 int err = 0; 143 140 144 141 #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) ··· 153 148 154 149 err |= flush_window_regs_user(regs); 155 150 err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); 151 + err |= __put_user(0, &sc->sc_xtregs); 156 152 157 - // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) 153 + if (err) 154 + return err; 158 155 159 - #if XCHAL_HAVE_CP 160 - # error Coprocessors unsupported 161 - err |= save_cpextra(cpstate); 162 - err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); 156 + #if XTENSA_HAVE_COPROCESSORS 157 + coprocessor_flush_all(ti); 158 + coprocessor_release_all(ti); 159 + err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp, 160 + sizeof (frame->xtregs.cp)); 163 161 #endif 162 + err |= __copy_to_user(&frame->xtregs.opt, &regs->xtregs_opt, 163 + sizeof (xtregs_opt_t)); 164 + err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user, 165 + sizeof (xtregs_user_t)); 166 + 167 + err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs); 164 168 165 169 return err; 166 170 } 167 171 168 172 static int 169 - restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 173 + restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame) 170 174 { 175 + struct sigcontext __user *sc = &frame->uc.uc_mcontext; 176 + struct thread_info *ti = current_thread_info(); 171 177 unsigned int err = 0; 172 178 unsigned long ps; 173 179 ··· 196 180 regs->windowbase = 0; 197 181 regs->windowstart = 1; 198 182 183 + regs->syscall = -1; /* disable syscall checks */ 184 + 199 185 /* For PS, restore only PS.CALLINC. 200 186 * Assume that all other bits are either the same as for the signal 201 187 * handler, or the user mode value doesn't matter (e.g. PS.OWB). ··· 213 195 214 196 err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); 215 197 216 - #if XCHAL_HAVE_CP 217 - # error Coprocessors unsupported 198 + if (err) 199 + return err; 200 + 218 201 /* The signal handler may have used coprocessors in which 219 202 * case they are still enabled. We disable them to force a 220 203 * reloading of the original task's CP state by the lazy ··· 223 204 * Also, we essentially discard any coprocessor state that the 224 205 * signal handler created. */ 225 206 226 - if (!err) { 227 - struct task_struct *tsk = current; 228 - release_all_cp(tsk); 229 - err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, 230 - XTENSA_CP_EXTRA_SIZE); 231 - } 207 + #if XTENSA_HAVE_COPROCESSORS 208 + coprocessor_release_all(ti); 209 + err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp, 210 + sizeof (frame->xtregs.cp)); 232 211 #endif 212 + err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user, 213 + sizeof (xtregs_user_t)); 214 + err |= __copy_from_user(&regs->xtregs_opt, &frame->xtregs.opt, 215 + sizeof (xtregs_opt_t)); 233 216 234 - regs->syscall = -1; /* disable syscall checks */ 235 217 return err; 236 218 } 237 - 238 219 239 220 240 221 /* ··· 265 246 recalc_sigpending(); 266 247 spin_unlock_irq(&current->sighand->siglock); 267 248 268 - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) 249 + if (restore_sigcontext(regs, frame)) 269 250 goto badframe; 270 251 271 252 ret = regs->areg[2]; ··· 378 359 err |= __put_user(sas_ss_flags(regs->areg[1]), 379 360 &frame->uc.uc_stack.ss_flags); 380 361 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); 381 - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, regs); 362 + err |= setup_sigcontext(frame, regs); 382 363 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 383 364 384 365 /* Create sys_rt_sigreturn syscall in stack frame */
+8 -8
arch/xtensa/kernel/traps.c
··· 118 118 { EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault }, 119 119 { EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault }, 120 120 /* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */ 121 - #if (XCHAL_CP_MASK & 1) 121 + #if XTENSA_HAVE_COPROCESSOR(0) 122 122 COPROCESSOR(0), 123 123 #endif 124 - #if (XCHAL_CP_MASK & 2) 124 + #if XTENSA_HAVE_COPROCESSOR(1) 125 125 COPROCESSOR(1), 126 126 #endif 127 - #if (XCHAL_CP_MASK & 4) 127 + #if XTENSA_HAVE_COPROCESSOR(2) 128 128 COPROCESSOR(2), 129 129 #endif 130 - #if (XCHAL_CP_MASK & 8) 130 + #if XTENSA_HAVE_COPROCESSOR(3) 131 131 COPROCESSOR(3), 132 132 #endif 133 - #if (XCHAL_CP_MASK & 16) 133 + #if XTENSA_HAVE_COPROCESSOR(4) 134 134 COPROCESSOR(4), 135 135 #endif 136 - #if (XCHAL_CP_MASK & 32) 136 + #if XTENSA_HAVE_COPROCESSOR(5) 137 137 COPROCESSOR(5), 138 138 #endif 139 - #if (XCHAL_CP_MASK & 64) 139 + #if XTENSA_HAVE_COPROCESSOR(6) 140 140 COPROCESSOR(6), 141 141 #endif 142 - #if (XCHAL_CP_MASK & 128) 142 + #if XTENSA_HAVE_COPROCESSOR(7) 143 143 COPROCESSOR(7), 144 144 #endif 145 145 { EXCCAUSE_MAPPED_DEBUG, 0, do_debug },
+143 -56
include/asm-xtensa/coprocessor.h
··· 5 5 * License. See the file "COPYING" in the main directory of this archive 6 6 * for more details. 7 7 * 8 - * Copyright (C) 2003 - 2005 Tensilica Inc. 8 + * Copyright (C) 2003 - 2007 Tensilica Inc. 9 9 */ 10 + 10 11 11 12 #ifndef _XTENSA_COPROCESSOR_H 12 13 #define _XTENSA_COPROCESSOR_H 13 14 14 - #include <asm/variant/core.h> 15 + #include <linux/stringify.h> 15 16 #include <asm/variant/tie.h> 17 + #include <asm/types.h> 16 18 17 - #if !XCHAL_HAVE_CP 19 + #ifdef __ASSEMBLY__ 20 + # include <asm/variant/tie-asm.h> 18 21 19 - #define XTENSA_CP_EXTRA_OFFSET 0 20 - #define XTENSA_CP_EXTRA_ALIGN 1 /* must be a power of 2 */ 21 - #define XTENSA_CP_EXTRA_SIZE 0 22 + .macro xchal_sa_start a b 23 + .set .Lxchal_pofs_, 0 24 + .set .Lxchal_ofs_, 0 25 + .endm 22 26 23 - #else 27 + .macro xchal_sa_align ptr minofs maxofs ofsalign totalign 28 + .set .Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ + \totalign - 1 29 + .set .Lxchal_ofs_, (.Lxchal_ofs_ & -\totalign) - .Lxchal_pofs_ 30 + .endm 24 31 25 - #define XTOFS(last_start,last_size,align) \ 26 - ((last_start+last_size+align-1) & -align) 32 + #define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ 33 + | XTHAL_SAS_CC \ 34 + | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) 27 35 28 - #define XTENSA_CP_EXTRA_OFFSET 0 29 - #define XTENSA_CP_EXTRA_ALIGN XCHAL_EXTRA_SA_ALIGN 36 + .macro save_xtregs_opt ptr clb at1 at2 at3 at4 offset 37 + .if XTREGS_OPT_SIZE > 0 38 + addi \clb, \ptr, \offset 39 + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT 40 + .endif 41 + .endm 30 42 31 - #define XTENSA_CPE_CP0_OFFSET \ 32 - XTOFS(XTENSA_CP_EXTRA_OFFSET, XCHAL_EXTRA_SA_SIZE, XCHAL_CP0_SA_ALIGN) 33 - #define XTENSA_CPE_CP1_OFFSET \ 34 - XTOFS(XTENSA_CPE_CP0_OFFSET, XCHAL_CP0_SA_SIZE, XCHAL_CP1_SA_ALIGN) 35 - #define XTENSA_CPE_CP2_OFFSET \ 36 - XTOFS(XTENSA_CPE_CP1_OFFSET, XCHAL_CP1_SA_SIZE, XCHAL_CP2_SA_ALIGN) 37 - #define XTENSA_CPE_CP3_OFFSET \ 38 - XTOFS(XTENSA_CPE_CP2_OFFSET, XCHAL_CP2_SA_SIZE, XCHAL_CP3_SA_ALIGN) 39 - #define XTENSA_CPE_CP4_OFFSET \ 40 - XTOFS(XTENSA_CPE_CP3_OFFSET, XCHAL_CP3_SA_SIZE, XCHAL_CP4_SA_ALIGN) 41 - #define XTENSA_CPE_CP5_OFFSET \ 42 - XTOFS(XTENSA_CPE_CP4_OFFSET, XCHAL_CP4_SA_SIZE, XCHAL_CP5_SA_ALIGN) 43 - #define XTENSA_CPE_CP6_OFFSET \ 44 - XTOFS(XTENSA_CPE_CP5_OFFSET, XCHAL_CP5_SA_SIZE, XCHAL_CP6_SA_ALIGN) 45 - #define XTENSA_CPE_CP7_OFFSET \ 46 - XTOFS(XTENSA_CPE_CP6_OFFSET, XCHAL_CP6_SA_SIZE, XCHAL_CP7_SA_ALIGN) 47 - #define XTENSA_CP_EXTRA_SIZE \ 48 - XTOFS(XTENSA_CPE_CP7_OFFSET, XCHAL_CP7_SA_SIZE, 16) 43 + .macro load_xtregs_opt ptr clb at1 at2 at3 at4 offset 44 + .if XTREGS_OPT_SIZE > 0 45 + addi \clb, \ptr, \offset 46 + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT 47 + .endif 48 + .endm 49 + #undef _SELECT 49 50 50 - #if XCHAL_CP_NUM > 0 51 - # ifndef __ASSEMBLY__ 51 + #define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ 52 + | XTHAL_SAS_NOCC \ 53 + | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) 54 + 55 + .macro save_xtregs_user ptr clb at1 at2 at3 at4 offset 56 + .if XTREGS_USER_SIZE > 0 57 + addi \clb, \ptr, \offset 58 + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT 59 + .endif 60 + .endm 61 + 62 + .macro load_xtregs_user ptr clb at1 at2 at3 at4 offset 63 + .if XTREGS_USER_SIZE > 0 64 + addi \clb, \ptr, \offset 65 + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT 66 + .endif 67 + .endm 68 + #undef _SELECT 69 + 70 + 71 + 72 + #endif /* __ASSEMBLY__ */ 73 + 52 74 /* 53 - * Tasks that own contents of (last user) each coprocessor. 54 - * Entries are 0 for not-owned or non-existent coprocessors. 55 - * Note: The size of this structure is fixed to 8 bytes in entry.S 75 + * XTENSA_HAVE_COPROCESSOR(x) returns 1 if coprocessor x is configured. 76 + * 77 + * XTENSA_HAVE_IO_PORT(x) returns 1 if io-port x is configured. 78 + * 56 79 */ 57 - typedef struct { 58 - struct task_struct *owner; /* owner */ 59 - int offset; /* offset in cpextra space. */ 60 - } coprocessor_info_t; 61 - # else 62 - # define COPROCESSOR_INFO_OWNER 0 63 - # define COPROCESSOR_INFO_OFFSET 4 64 - # define COPROCESSOR_INFO_SIZE 8 65 - # endif 66 - #endif 67 - #endif /* XCHAL_HAVE_CP */ 68 80 81 + #define XTENSA_HAVE_COPROCESSOR(x) \ 82 + ((XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) & (1 << (x))) 83 + #define XTENSA_HAVE_COPROCESSORS \ 84 + (XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) 85 + #define XTENSA_HAVE_IO_PORT(x) \ 86 + (XCHAL_CP_PORT_MASK & (1 << (x))) 87 + #define XTENSA_HAVE_IO_PORTS \ 88 + XCHAL_CP_PORT_MASK 69 89 70 90 #ifndef __ASSEMBLY__ 71 - # if XCHAL_CP_NUM > 0 72 - struct task_struct; 73 - extern void release_coprocessors (struct task_struct*); 74 - extern void save_coprocessor_registers(void*, int); 75 - # else 76 - # define release_coprocessors(task) 77 - # endif 78 91 79 - typedef unsigned char cp_state_t[XTENSA_CP_EXTRA_SIZE] 80 - __attribute__ ((aligned (XTENSA_CP_EXTRA_ALIGN))); 92 + 93 + #if XCHAL_HAVE_CP 94 + 95 + #define RSR_CPENABLE(x) do { \ 96 + __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \ 97 + } while(0); 98 + #define WSR_CPENABLE(x) do { \ 99 + __asm__ __volatile__("wsr %0," __stringify(CPENABLE) "; rsync" \ 100 + :: "a" (x)); \ 101 + } while(0); 102 + 103 + #endif /* XCHAL_HAVE_CP */ 104 + 105 + 106 + /* 107 + * Additional registers. 108 + * We define three types of additional registers: 109 + * ext: extra registers that are used by the compiler 110 + * cpn: optional registers that can be used by a user application 111 + * cpX: coprocessor registers that can only be used if the corresponding 112 + * CPENABLE bit is set. 113 + */ 114 + 115 + #define XCHAL_SA_REG(list,compiler,x,type,y,name,z,align,size,...) \ 116 + __REG ## list (compiler, type, name, size, align) 117 + 118 + #define __REG0(compiler,t,name,s,a) __REG0_ ## compiler (name) 119 + #define __REG1(compiler,t,name,s,a) __REG1_ ## compiler (name) 120 + #define __REG2(c,type,...) __REG2_ ## type (__VA_ARGS__) 121 + 122 + #define __REG0_0(name) 123 + #define __REG0_1(name) __u32 name; 124 + #define __REG1_0(name) __u32 name; 125 + #define __REG1_1(name) 126 + #define __REG2_0(n,s,a) __u32 name; 127 + #define __REG2_1(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); 128 + #define __REG2_2(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); 129 + 130 + typedef struct { XCHAL_NCP_SA_LIST(0) } xtregs_opt_t 131 + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); 132 + typedef struct { XCHAL_NCP_SA_LIST(1) } xtregs_user_t 133 + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); 134 + 135 + #if XTENSA_HAVE_COPROCESSORS 136 + 137 + typedef struct { XCHAL_CP0_SA_LIST(2) } xtregs_cp0_t 138 + __attribute__ ((aligned (XCHAL_CP0_SA_ALIGN))); 139 + typedef struct { XCHAL_CP1_SA_LIST(2) } xtregs_cp1_t 140 + __attribute__ ((aligned (XCHAL_CP1_SA_ALIGN))); 141 + typedef struct { XCHAL_CP2_SA_LIST(2) } xtregs_cp2_t 142 + __attribute__ ((aligned (XCHAL_CP2_SA_ALIGN))); 143 + typedef struct { XCHAL_CP3_SA_LIST(2) } xtregs_cp3_t 144 + __attribute__ ((aligned (XCHAL_CP3_SA_ALIGN))); 145 + typedef struct { XCHAL_CP4_SA_LIST(2) } xtregs_cp4_t 146 + __attribute__ ((aligned (XCHAL_CP4_SA_ALIGN))); 147 + typedef struct { XCHAL_CP5_SA_LIST(2) } xtregs_cp5_t 148 + __attribute__ ((aligned (XCHAL_CP5_SA_ALIGN))); 149 + typedef struct { XCHAL_CP6_SA_LIST(2) } xtregs_cp6_t 150 + __attribute__ ((aligned (XCHAL_CP6_SA_ALIGN))); 151 + typedef struct { XCHAL_CP7_SA_LIST(2) } xtregs_cp7_t 152 + __attribute__ ((aligned (XCHAL_CP7_SA_ALIGN))); 153 + 154 + extern struct thread_info* coprocessor_owner[XCHAL_CP_MAX]; 155 + extern void coprocessor_save(void*, int); 156 + extern void coprocessor_load(void*, int); 157 + extern void coprocessor_flush(struct thread_info*, int); 158 + extern void coprocessor_restore(struct thread_info*, int); 159 + 160 + extern void coprocessor_release_all(struct thread_info*); 161 + extern void coprocessor_flush_all(struct thread_info*); 162 + 163 + static inline void coprocessor_clear_cpenable(void) 164 + { 165 + unsigned long i = 0; 166 + WSR_CPENABLE(i); 167 + } 168 + 169 + #endif /* XTENSA_HAVE_COPROCESSORS */ 81 170 82 171 #endif /* !__ASSEMBLY__ */ 83 - 84 - 85 172 #endif /* _XTENSA_COPROCESSOR_H */
+15
include/asm-xtensa/elf.h
··· 173 173 _r->areg[12]=0; _r->areg[13]=0; _r->areg[14]=0; _r->areg[15]=0; \ 174 174 } while (0) 175 175 176 + typedef struct { 177 + xtregs_opt_t opt; 178 + xtregs_user_t user; 179 + #if XTENSA_HAVE_COPROCESSORS 180 + xtregs_cp0_t cp0; 181 + xtregs_cp1_t cp1; 182 + xtregs_cp2_t cp2; 183 + xtregs_cp3_t cp3; 184 + xtregs_cp4_t cp4; 185 + xtregs_cp5_t cp5; 186 + xtregs_cp6_t cp6; 187 + xtregs_cp7_t cp7; 188 + #endif 189 + } elf_xtregs_t; 190 + 176 191 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) 177 192 178 193 struct task_struct;
+2 -11
include/asm-xtensa/processor.h
··· 103 103 unsigned long dbreaka[XCHAL_NUM_DBREAK]; 104 104 unsigned long dbreakc[XCHAL_NUM_DBREAK]; 105 105 106 - /* Allocate storage for extra state and coprocessor state. */ 107 - unsigned char cp_save[XTENSA_CP_EXTRA_SIZE] 108 - __attribute__ ((aligned(XTENSA_CP_EXTRA_ALIGN))); 109 - 110 106 /* Make structure 16 bytes aligned. */ 111 107 int align[0] __attribute__ ((aligned(16))); 112 108 }; ··· 158 162 struct task_struct; 159 163 struct mm_struct; 160 164 161 - // FIXME: do we need release_thread for CP?? 162 165 /* Free all resources held by a thread. */ 163 166 #define release_thread(thread) do { } while(0) 164 167 165 - // FIXME: do we need prepare_to_copy (lazy status) for CP?? 166 168 /* Prepare to copy thread state - unlazy all lazy status */ 167 - #define prepare_to_copy(tsk) do { } while (0) 169 + extern void prepare_to_copy(struct task_struct*); 168 170 169 - /* 170 - * create a kernel thread without removing it from tasklists 171 - */ 171 + /* Create a kernel thread without removing it from tasklists */ 172 172 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); 173 173 174 174 /* Copy and release all segment info associated with a VM */ 175 - 176 175 #define copy_segments(p, mm) do { } while(0) 177 176 #define release_segments(mm) do { } while(0) 178 177 #define forget_segments() do { } while (0)
+20 -22
include/asm-xtensa/ptrace.h
··· 53 53 54 54 /* Registers used by strace */ 55 55 56 - #define REG_A_BASE 0xfc000000 57 - #define REG_AR_BASE 0x04000000 58 - #define REG_PC 0x14000000 59 - #define REG_PS 0x080000e6 60 - #define REG_WB 0x08000048 61 - #define REG_WS 0x08000049 62 - #define REG_LBEG 0x08000000 63 - #define REG_LEND 0x08000001 64 - #define REG_LCOUNT 0x08000002 65 - #define REG_SAR 0x08000003 66 - #define REG_DEPC 0x080000c0 67 - #define REG_EXCCAUSE 0x080000e8 68 - #define REG_EXCVADDR 0x080000ee 69 - #define SYSCALL_NR 0x1 56 + #define REG_A_BASE 0x0000 57 + #define REG_AR_BASE 0x0100 58 + #define REG_PC 0x0020 59 + #define REG_PS 0x02e6 60 + #define REG_WB 0x0248 61 + #define REG_WS 0x0249 62 + #define REG_LBEG 0x0200 63 + #define REG_LEND 0x0201 64 + #define REG_LCOUNT 0x0202 65 + #define REG_SAR 0x0203 70 66 71 - #define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1) 67 + #define SYSCALL_NR 0x00ff 72 68 73 69 /* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */ 74 70 75 - #define PTRACE_GETREGS 12 76 - #define PTRACE_SETREGS 13 77 - #define PTRACE_GETFPREGS 14 78 - #define PTRACE_SETFPREGS 15 79 - #define PTRACE_GETFPREGSIZE 18 71 + #define PTRACE_GETREGS 12 72 + #define PTRACE_SETREGS 13 73 + #define PTRACE_GETXTREGS 18 74 + #define PTRACE_SETXTREGS 19 80 75 81 76 #ifndef __ASSEMBLY__ 77 + 78 + #ifdef __KERNEL__ 82 79 83 80 /* 84 81 * This struct defines the way the registers are stored on the ··· 99 102 unsigned long icountlevel; /* 60 */ 100 103 int reserved[1]; /* 64 */ 101 104 105 + /* Additional configurable registers that are used by the compiler. */ 106 + xtregs_opt_t xtregs_opt; 107 + 102 108 /* Make sure the areg field is 16 bytes aligned. */ 103 109 int align[0] __attribute__ ((aligned(16))); 104 110 ··· 110 110 */ 111 111 unsigned long areg[16]; /* 128 (64) */ 112 112 }; 113 - 114 - #ifdef __KERNEL__ 115 113 116 114 #include <asm/variant/core.h> 117 115
+8 -1
include/asm-xtensa/regs.h
··· 100 100 #define EXCCAUSE_DTLB_SIZE_RESTRICTION 27 101 101 #define EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 102 102 #define EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 103 - #define EXCCAUSE_FLOATING_POINT 40 103 + #define EXCCAUSE_COPROCESSOR0_DISABLED 32 104 + #define EXCCAUSE_COPROCESSOR1_DISABLED 33 105 + #define EXCCAUSE_COPROCESSOR2_DISABLED 34 106 + #define EXCCAUSE_COPROCESSOR3_DISABLED 35 107 + #define EXCCAUSE_COPROCESSOR4_DISABLED 36 108 + #define EXCCAUSE_COPROCESSOR5_DISABLED 37 109 + #define EXCCAUSE_COPROCESSOR6_DISABLED 38 110 + #define EXCCAUSE_COPROCESSOR7_DISABLED 39 104 111 105 112 /* PS register fields. */ 106 113
+1
include/asm-xtensa/sigcontext.h
··· 22 22 unsigned long sc_acclo; 23 23 unsigned long sc_acchi; 24 24 unsigned long sc_a[16]; 25 + void *sc_xtregs; 25 26 }; 26 27 27 28 #endif /* _XTENSA_SIGCONTEXT_H */
+1 -38
include/asm-xtensa/system.h
··· 46 46 return flags & 0xf; 47 47 } 48 48 49 - #define RSR_CPENABLE(x) do { \ 50 - __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \ 51 - } while(0); 52 - #define WSR_CPENABLE(x) do { \ 53 - __asm__ __volatile__("wsr %0," __stringify(CPENABLE)";rsync" \ 54 - :: "a" (x));} while(0); 55 - 56 - #define clear_cpenable() __clear_cpenable() 57 - 58 - static inline void __clear_cpenable(void) 59 - { 60 - #if XCHAL_HAVE_CP 61 - unsigned long i = 0; 62 - WSR_CPENABLE(i); 63 - #endif 64 - } 65 - 66 - static inline void enable_coprocessor(int i) 67 - { 68 - #if XCHAL_HAVE_CP 69 - int cp; 70 - RSR_CPENABLE(cp); 71 - cp |= 1 << i; 72 - WSR_CPENABLE(cp); 73 - #endif 74 - } 75 - 76 - static inline void disable_coprocessor(int i) 77 - { 78 - #if XCHAL_HAVE_CP 79 - int cp; 80 - RSR_CPENABLE(cp); 81 - cp &= ~(1 << i); 82 - WSR_CPENABLE(cp); 83 - #endif 84 - } 85 49 86 50 #define smp_read_barrier_depends() do { } while(0) 87 51 #define read_barrier_depends() do { } while(0) ··· 75 111 76 112 #define switch_to(prev,next,last) \ 77 113 do { \ 78 - clear_cpenable(); \ 79 114 (last) = _switch_to(prev, next); \ 80 115 } while(0) 81 116 ··· 207 244 "wsr a13," __stringify(SAR) "\n\t" 208 245 "wsr a14," __stringify(PS) "\n\t" 209 246 :: "a" (&a0), "a" (&ps) 210 - : "a2", "a3", "a12", "a13", "a14", "a15", "memory"); 247 + : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory"); 211 248 } 212 249 213 250 #define arch_align_stack(x) (x)
+21
include/asm-xtensa/thread_info.h
··· 27 27 28 28 #ifndef __ASSEMBLY__ 29 29 30 + #if XTENSA_HAVE_COPROCESSORS 31 + 32 + typedef struct xtregs_coprocessor { 33 + xtregs_cp0_t cp0; 34 + xtregs_cp1_t cp1; 35 + xtregs_cp2_t cp2; 36 + xtregs_cp3_t cp3; 37 + xtregs_cp4_t cp4; 38 + xtregs_cp5_t cp5; 39 + xtregs_cp6_t cp6; 40 + xtregs_cp7_t cp7; 41 + } xtregs_coprocessor_t; 42 + 43 + #endif 44 + 30 45 struct thread_info { 31 46 struct task_struct *task; /* main task structure */ 32 47 struct exec_domain *exec_domain; /* execution domain */ ··· 53 38 mm_segment_t addr_limit; /* thread address space */ 54 39 struct restart_block restart_block; 55 40 41 + unsigned long cpenable; 56 42 43 + /* Allocate storage for extra user states and coprocessor states. */ 44 + #if XTENSA_HAVE_COPROCESSORS 45 + xtregs_coprocessor_t xtregs_cp; 46 + #endif 47 + xtregs_user_t xtregs_user; 57 48 }; 58 49 59 50 #else /* !__ASSEMBLY__ */
+70
include/asm-xtensa/variant-fsf/tie-asm.h
··· 1 + /* 2 + * This header file contains assembly-language definitions (assembly 3 + * macros, etc.) for this specific Xtensa processor's TIE extensions 4 + * and options. It is customized to this Xtensa processor configuration. 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + * 10 + * Copyright (C) 1999-2008 Tensilica Inc. 11 + */ 12 + 13 + #ifndef _XTENSA_CORE_TIE_ASM_H 14 + #define _XTENSA_CORE_TIE_ASM_H 15 + 16 + /* Selection parameter values for save-area save/restore macros: */ 17 + /* Option vs. TIE: */ 18 + #define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ 19 + #define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ 20 + /* Whether used automatically by compiler: */ 21 + #define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ 22 + #define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ 23 + /* ABI handling across function calls: */ 24 + #define XTHAL_SAS_CALR 0x0010 /* caller-saved */ 25 + #define XTHAL_SAS_CALE 0x0020 /* callee-saved */ 26 + #define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ 27 + /* Misc */ 28 + #define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ 29 + 30 + 31 + 32 + /* Macro to save all non-coprocessor (extra) custom TIE and optional state 33 + * (not including zero-overhead loop registers). 34 + * Save area ptr (clobbered): ptr (1 byte aligned) 35 + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) 36 + */ 37 + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL 38 + xchal_sa_start \continue, \ofs 39 + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select 40 + xchal_sa_align \ptr, 0, 1024-4, 4, 4 41 + rur \at1, THREADPTR // threadptr option 42 + s32i \at1, \ptr, .Lxchal_ofs_ + 0 43 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 44 + .endif 45 + .endm // xchal_ncp_store 46 + 47 + /* Macro to save all non-coprocessor (extra) custom TIE and optional state 48 + * (not including zero-overhead loop registers). 49 + * Save area ptr (clobbered): ptr (1 byte aligned) 50 + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) 51 + */ 52 + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL 53 + xchal_sa_start \continue, \ofs 54 + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select 55 + xchal_sa_align \ptr, 0, 1024-4, 4, 4 56 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 57 + wur \at1, THREADPTR // threadptr option 58 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 59 + .endif 60 + .endm // xchal_ncp_load 61 + 62 + 63 + 64 + #define XCHAL_NCP_NUM_ATMPS 1 65 + 66 + 67 + #define XCHAL_SA_NUM_ATMPS 1 68 + 69 + #endif /*_XTENSA_CORE_TIE_ASM_H*/ 70 +
+65 -10
include/asm-xtensa/variant-fsf/tie.h
··· 1 1 /* 2 - * Xtensa processor core configuration information. 2 + * This header file describes this specific Xtensa processor's TIE extensions 3 + * that extend basic Xtensa core functionality. It is customized to this 4 + * Xtensa processor configuration. 3 5 * 4 6 * This file is subject to the terms and conditions of the GNU General Public 5 7 * License. See the file "COPYING" in the main directory of this archive 6 8 * for more details. 7 9 * 8 - * Copyright (C) 1999-2006 Tensilica Inc. 10 + * Copyright (C) 1999-2007 Tensilica Inc. 9 11 */ 10 12 11 - #ifndef XTENSA_TIE_H 12 - #define XTENSA_TIE_H 13 - 14 - /*---------------------------------------------------------------------- 15 - COPROCESSORS and EXTRA STATE 16 - ----------------------------------------------------------------------*/ 13 + #ifndef _XTENSA_CORE_TIE_H 14 + #define _XTENSA_CORE_TIE_H 17 15 18 16 #define XCHAL_CP_NUM 0 /* number of coprocessors */ 19 - #define XCHAL_CP_MASK 0x00 17 + #define XCHAL_CP_MAX 0 /* max CP ID + 1 (0 if none) */ 18 + #define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */ 19 + #define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ 20 20 21 - #endif /*XTENSA_CONFIG_TIE_H*/ 21 + /* Basic parameters of each coprocessor: */ 22 + #define XCHAL_CP7_NAME "XTIOP" 23 + #define XCHAL_CP7_IDENT XTIOP 24 + #define XCHAL_CP7_SA_SIZE 0 /* size of state save area */ 25 + #define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */ 26 + #define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */ 27 + 28 + /* Filler info for unassigned coprocessors, to simplify arrays etc: */ 29 + #define XCHAL_NCP_SA_SIZE 0 30 + #define XCHAL_NCP_SA_ALIGN 1 31 + #define XCHAL_CP0_SA_SIZE 0 32 + #define XCHAL_CP0_SA_ALIGN 1 33 + #define XCHAL_CP1_SA_SIZE 0 34 + #define XCHAL_CP1_SA_ALIGN 1 35 + #define XCHAL_CP2_SA_SIZE 0 36 + #define XCHAL_CP2_SA_ALIGN 1 37 + #define XCHAL_CP3_SA_SIZE 0 38 + #define XCHAL_CP3_SA_ALIGN 1 39 + #define XCHAL_CP4_SA_SIZE 0 40 + #define XCHAL_CP4_SA_ALIGN 1 41 + #define XCHAL_CP5_SA_SIZE 0 42 + #define XCHAL_CP5_SA_ALIGN 1 43 + #define XCHAL_CP6_SA_SIZE 0 44 + #define XCHAL_CP6_SA_ALIGN 1 45 + 46 + /* Save area for non-coprocessor optional and custom (TIE) state: */ 47 + #define XCHAL_NCP_SA_SIZE 0 48 + #define XCHAL_NCP_SA_ALIGN 1 49 + 50 + /* Total save area for optional and custom state (NCP + CPn): */ 51 + #define XCHAL_TOTAL_SA_SIZE 0 /* with 16-byte align padding */ 52 + #define XCHAL_TOTAL_SA_ALIGN 1 /* actual minimum alignment */ 53 + 54 + #define XCHAL_NCP_SA_NUM 0 55 + #define XCHAL_NCP_SA_LIST(s) 56 + #define XCHAL_CP0_SA_NUM 0 57 + #define XCHAL_CP0_SA_LIST(s) 58 + #define XCHAL_CP1_SA_NUM 0 59 + #define XCHAL_CP1_SA_LIST(s) 60 + #define XCHAL_CP2_SA_NUM 0 61 + #define XCHAL_CP2_SA_LIST(s) 62 + #define XCHAL_CP3_SA_NUM 0 63 + #define XCHAL_CP3_SA_LIST(s) 64 + #define XCHAL_CP4_SA_NUM 0 65 + #define XCHAL_CP4_SA_LIST(s) 66 + #define XCHAL_CP5_SA_NUM 0 67 + #define XCHAL_CP5_SA_LIST(s) 68 + #define XCHAL_CP6_SA_NUM 0 69 + #define XCHAL_CP6_SA_LIST(s) 70 + #define XCHAL_CP7_SA_NUM 0 71 + #define XCHAL_CP7_SA_LIST(s) 72 + 73 + /* Byte length of instruction from its first nibble (op0 field), per FLIX. */ 74 + #define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3 75 + 76 + #endif /*_XTENSA_CORE_TIE_H*/ 22 77