From e584d85fb1cba2b08c266348b58eb4a881a88b40 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Wed, 13 Feb 2008 16:25:09 -0800 Subject: [XTENSA] Fix non-existent pte_token_t typedef to pgtable_t This bug was introduced in 2f569afd9ced9ebec9a6eb3dbf6f83429be0a7b4. (CONFIG_HIGHPTE vs. sub-page page tables) Signed-off-by: Chris Zankel --- include/asm-xtensa/pgalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h index 8d1544eb461e..4f4a7987eded 100644 --- a/include/asm-xtensa/pgalloc.h +++ b/include/asm-xtensa/pgalloc.h @@ -47,7 +47,7 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT); } -static inline pte_token_t pte_alloc_one(struct mm_struct *mm, +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr) { struct page *page; -- cgit v1.2.3 From 70e137eb48f62e59dfa5e06d0d01f123e9464f9a Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Tue, 23 Oct 2007 10:58:53 -0700 Subject: [XTENSA] Fix clobbered register in asm macro We dangerously re-used an input operand to an asm macro without defining a constraint. By defining a separate output operand (instead of input/output operand), the compiler is more flexible during register allocation. Signed-off-by: Chris Zankel --- include/asm-xtensa/uaccess.h | 99 +++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h index d6352da05b10..b8528426ab1f 100644 --- a/include/asm-xtensa/uaccess.h +++ b/include/asm-xtensa/uaccess.h @@ -26,6 +26,7 @@ #include #include #include +#include /* * These assembly macros mirror the C macros that follow below. They @@ -118,7 +119,7 @@ * destroyed (actually, (TASK_SIZE + 1 - size)) */ .macro user_ok aa, as, at, error - movi \at, (TASK_SIZE+1) + movi \at, __XTENSA_UL_CONST(TASK_SIZE) bgeu \as, \at, \error sub \at, \at, \as bgeu \aa, \at, \error @@ -226,20 +227,21 @@ extern long __put_user_bad(void); __pu_err; \ }) -#define __put_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,1,"s8i"); break; \ - case 2: __put_user_asm(x,ptr,retval,2,"s16i"); break; \ - case 4: __put_user_asm(x,ptr,retval,4,"s32i"); break; \ - case 8: { \ - __typeof__(*ptr) __v64 = x; \ - retval = __copy_to_user(ptr,&__v64,8); \ - break; \ - } \ - default: __put_user_bad(); \ - } \ +#define __put_user_size(x,ptr,size,retval) \ +do { \ + int __cb; \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb); break; \ + case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break; \ + case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break; \ + case 8: { \ + __typeof__(*ptr) __v64 = x; \ + retval = __copy_to_user(ptr,&__v64,8); \ + break; \ + } \ + default: __put_user_bad(); \ + } \ } while (0) @@ -267,14 +269,14 @@ do { \ #define __check_align_1 "" #define __check_align_2 \ - " _bbci.l %2, 0, 1f \n" \ - " movi %0, %3 \n" \ + " _bbci.l %3, 0, 1f \n" \ + " movi %0, %4 \n" \ " _j 2f \n" #define __check_align_4 \ - " _bbsi.l %2, 0, 0f \n" \ - " _bbci.l %2, 1, 1f \n" \ - "0: movi %0, %3 \n" \ + " _bbsi.l %3, 0, 0f \n" \ + " _bbci.l %3, 1, 1f \n" \ + "0: movi %0, %4 \n" \ " _j 2f \n" @@ -286,24 +288,24 @@ do { \ * WARNING: If you modify this macro at all, verify that the * __check_align_* macros still work. */ -#define __put_user_asm(x, addr, err, align, insn) \ - __asm__ __volatile__( \ - __check_align_##align \ - "1: "insn" %1, %2, 0 \n" \ - "2: \n" \ - " .section .fixup,\"ax\" \n" \ - " .align 4 \n" \ - "4: \n" \ - " .long 2b \n" \ - "5: \n" \ - " l32r %2, 4b \n" \ - " movi %0, %3 \n" \ - " jx %2 \n" \ - " .previous \n" \ - " .section __ex_table,\"a\" \n" \ - " .long 1b, 5b \n" \ - " .previous" \ - :"=r" (err) \ +#define __put_user_asm(x, addr, err, align, insn, cb) \ + __asm__ __volatile__( \ + __check_align_##align \ + "1: "insn" %2, %3, 0 \n" \ + "2: \n" \ + " .section .fixup,\"ax\" \n" \ + " .align 4 \n" \ + "4: \n" \ + " .long 2b \n" \ + "5: \n" \ + " l32r %1, 4b \n" \ + " movi %0, %4 \n" \ + " jx %1 \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " .long 1b, 5b \n" \ + " .previous" \ + :"=r" (err), "=r" (cb) \ :"r" ((int)(x)), "r" (addr), "i" (-EFAULT), "0" (err)) #define __get_user_nocheck(x,ptr,size) \ @@ -328,11 +330,12 @@ extern long __get_user_bad(void); #define __get_user_size(x,ptr,size,retval) \ do { \ + int __cb; \ retval = 0; \ switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,1,"l8ui"); break; \ - case 2: __get_user_asm(x,ptr,retval,2,"l16ui"); break; \ - case 4: __get_user_asm(x,ptr,retval,4,"l32i"); break; \ + case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb); break; \ + case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break; \ + case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb); break; \ case 8: retval = __copy_from_user(&x,ptr,8); break; \ default: (x) = __get_user_bad(); \ } \ @@ -343,25 +346,25 @@ do { \ * WARNING: If you modify this macro at all, verify that the * __check_align_* macros still work. */ -#define __get_user_asm(x, addr, err, align, insn) \ +#define __get_user_asm(x, addr, err, align, insn, cb) \ __asm__ __volatile__( \ __check_align_##align \ - "1: "insn" %1, %2, 0 \n" \ + "1: "insn" %2, %3, 0 \n" \ "2: \n" \ " .section .fixup,\"ax\" \n" \ " .align 4 \n" \ "4: \n" \ " .long 2b \n" \ "5: \n" \ - " l32r %2, 4b \n" \ - " movi %1, 0 \n" \ - " movi %0, %3 \n" \ - " jx %2 \n" \ + " l32r %1, 4b \n" \ + " movi %2, 0 \n" \ + " movi %0, %4 \n" \ + " jx %1 \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ " .long 1b, 5b \n" \ " .previous" \ - :"=r" (err), "=r" (x) \ + :"=r" (err), "=r" (cb), "=r" (x) \ :"r" (addr), "i" (-EFAULT), "0" (err)) -- cgit v1.2.3 From 8d7e8240e66cecc84a375aceb26942d02b291198 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Tue, 12 Feb 2008 11:55:32 -0800 Subject: [XTENSA] Clean up elf-gregset. Remove additional registers from the ELF gregset structure that are only used by the kernel or are not required or invalid in user-space. The ar registers are always aligned to a windowbase value of 0, and the WB register is always assumed to be 0. Increase the size of the structure to 128 entries. This will provide enough space in future. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/process.c | 63 +++--------------------------- arch/xtensa/kernel/traps.c | 4 +- include/asm-xtensa/elf.h | 92 ++------------------------------------------ 3 files changed, 11 insertions(+), 148 deletions(-) (limited to 'include') diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index f53d7bd9dfb2..026138d641a4 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -194,51 +194,18 @@ unsigned long get_wchan(struct task_struct *p) void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, struct task_struct *tsk) { - int i, n, wb_offset; - - elfregs->xchal_config_id0 = XCHAL_HW_CONFIGID0; - elfregs->xchal_config_id1 = XCHAL_HW_CONFIGID1; - - __asm__ __volatile__ ("rsr %0, 176\n" : "=a" (i)); - elfregs->cpux = i; - __asm__ __volatile__ ("rsr %0, 208\n" : "=a" (i)); - elfregs->cpuy = i; - /* Note: PS.EXCM is not set while user task is running; its * being set in regs->ps is for exception handling convenience. */ elfregs->pc = regs->pc; elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT)); - elfregs->exccause = regs->exccause; - elfregs->excvaddr = regs->excvaddr; - elfregs->windowbase = regs->windowbase; - elfregs->windowstart = regs->windowstart; elfregs->lbeg = regs->lbeg; elfregs->lend = regs->lend; elfregs->lcount = regs->lcount; elfregs->sar = regs->sar; - elfregs->syscall = regs->syscall; - - /* Copy register file. - * The layout looks like this: - * - * | a0 ... a15 | Z ... Z | arX ... arY | - * current window unused saved frames - */ - - memset (elfregs->ar, 0, sizeof(elfregs->ar)); - - wb_offset = regs->windowbase * 4; - n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16; - - for (i = 0; i < n; i++) - elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i]; - n = (regs->wmask >> 4) * 4; - - for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--) - elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i]; + memcpy (elfregs->a, regs->areg, sizeof(elfregs->a)); } void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) @@ -252,40 +219,22 @@ void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, struct task_struct *tsk) { - int i, n, wb_offset; + const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; + unsigned long ps; /* Note: PS.EXCM is not set while user task is running; it * needs to be set in regs->ps is for exception handling convenience. */ + ps = (regs->ps & ~ps_mask) | (elfregs->ps & ps_mask) | (1<ps = ps; regs->pc = elfregs->pc; - regs->ps = (elfregs->ps | (1 << PS_EXCM_BIT)); - regs->exccause = elfregs->exccause; - regs->excvaddr = elfregs->excvaddr; - regs->windowbase = elfregs->windowbase; - regs->windowstart = elfregs->windowstart; regs->lbeg = elfregs->lbeg; regs->lend = elfregs->lend; regs->lcount = elfregs->lcount; regs->sar = elfregs->sar; - regs->syscall = elfregs->syscall; - - /* Clear everything. */ - - memset (regs->areg, 0, sizeof(regs->areg)); - - /* Copy regs from live window frame. */ - - wb_offset = regs->windowbase * 4; - n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16; - - for (i = 0; i < n; i++) - regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i]; - - n = (regs->wmask >> 4) * 4; - for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--) - regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i]; + memcpy (regs->areg, elfregs->a, sizeof(regs->areg)); } /* diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 397bcd6ad08d..6f722f91ba92 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -349,9 +349,7 @@ void show_regs(struct pt_regs * regs) wmask = regs->wmask & ~1; - for (i = 0; i < 32; i++) { - if (wmask & (1 << (i / 4))) - break; + for (i = 0; i < 16; i++) { if ((i % 8) == 0) printk ("\n" KERN_INFO "a%02d: ", i); printk("%08lx ", regs->areg[i]); diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 467384542502..0444507b438d 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -72,109 +72,25 @@ /* ELF register definitions. This is needed for core dump support. */ -/* - * elf_gregset_t contains the application-level state in the following order: - * Processor info: config_version, cpuxy - * Processor state: pc, ps, exccause, excvaddr, wb, ws, - * lbeg, lend, lcount, sar - * GP regs: ar0 - arXX - */ - typedef unsigned long elf_greg_t; typedef struct { - elf_greg_t xchal_config_id0; - elf_greg_t xchal_config_id1; - elf_greg_t cpux; - elf_greg_t cpuy; elf_greg_t pc; elf_greg_t ps; - elf_greg_t exccause; - elf_greg_t excvaddr; - elf_greg_t windowbase; - elf_greg_t windowstart; elf_greg_t lbeg; elf_greg_t lend; elf_greg_t lcount; elf_greg_t sar; - elf_greg_t syscall; - elf_greg_t ar[64]; + elf_greg_t windowstart; + elf_greg_t reserved[9+48]; + elf_greg_t a[64]; } xtensa_gregset_t; #define ELF_NGREG (sizeof(xtensa_gregset_t) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -/* - * Compute the size of the coprocessor and extra state layout (register info) - * table (in bytes). - * This is actually the maximum size of the table, as opposed to the size, - * which is available from the _xtensa_reginfo_table_size global variable. - * - * (See also arch/xtensa/kernel/coprocessor.S) - * - */ - -#ifndef XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM -# define XTENSA_CPE_LTABLE_SIZE 0 -#else -# define XTENSA_CPE_SEGMENT(num) (num ? (1+num) : 0) -# define XTENSA_CPE_LTABLE_ENTRIES \ - ( XTENSA_CPE_SEGMENT(XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP0_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP1_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP2_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP3_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP4_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP5_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP6_SA_CONTENTS_LIBDB_NUM) \ - + XTENSA_CPE_SEGMENT(XCHAL_CP7_SA_CONTENTS_LIBDB_NUM) \ - + 1 /* final entry */ \ - ) -# define XTENSA_CPE_LTABLE_SIZE (XTENSA_CPE_LTABLE_ENTRIES * 8) -#endif - - -/* - * Instantiations of the elf_fpregset_t type contain, in most - * architectures, the floating point (FPU) register set. - * For Xtensa, this type is extended to contain all custom state, - * ie. coprocessor and "extra" (non-coprocessor) state (including, - * for example, TIE-defined states and register files; as well - * as other optional processor state). - * This includes FPU state if a floating-point coprocessor happens - * to have been configured within the Xtensa processor. - * - * TOTAL_FPREGS_SIZE is the required size (without rounding) - * of elf_fpregset_t. It provides space for the following: - * - * a) 32-bit mask of active coprocessors for this task (similar - * to CPENABLE in single-threaded Xtensa processor systems) - * - * b) table describing the layout of custom states (ie. of - * individual registers, etc) within the save areas - * - * c) save areas for each coprocessor and for non-coprocessor - * ("extra") state - * - * Note that save areas may require up to 16-byte alignment when - * accessed by save/restore sequences. We do not need to ensure - * such alignment in an elf_fpregset_t structure because custom - * state is not directly loaded/stored into it; rather, save area - * contents are copied to elf_fpregset_t from the active save areas - * (see 'struct task_struct' definition in processor.h for that) - * using memcpy(). But we do allow space for such alignment, - * to allow optimizations of layout and copying. - */ -#if 0 -#define TOTAL_FPREGS_SIZE \ - (4 + XTENSA_CPE_LTABLE_SIZE + XTENSA_CP_EXTRA_SIZE) -#define ELF_NFPREG \ - ((TOTAL_FPREGS_SIZE + sizeof(elf_fpreg_t) - 1) / sizeof(elf_fpreg_t)) -#else -#define TOTAL_FPREGS_SIZE 0 -#define ELF_NFPREG 0 -#endif +#define ELF_NFPREG 18 typedef unsigned int elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; -- cgit v1.2.3 From 3befce8f0f79be8322aba885ed052b8ad927913d Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Tue, 12 Feb 2008 12:22:15 -0800 Subject: [XTENSA] Remove oldmask from sigcontext and fix register flush Remove oldmask from the sigcontext structure. Also update wmask and windowstart when we flush the AR registers to stack. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/signal.c | 12 +++++------- include/asm-xtensa/sigcontext.h | 3 --- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 033aae0336d2..42d9fd8a4225 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -49,8 +49,6 @@ struct rt_sigframe /* * Flush register windows stored in pt_regs to stack. * Returns 1 for errors. - * - * Note that windowbase, windowstart, and wmask are not updated! */ int @@ -116,6 +114,9 @@ flush_window_regs_user(struct pt_regs *regs) base += inc; } + regs->wmask = 1; + regs->windowstart = 1 << wb; + return 0; errout: @@ -132,7 +133,7 @@ errout: static int setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, - struct pt_regs *regs, unsigned long mask) + struct pt_regs *regs) { int err = 0; @@ -155,8 +156,6 @@ setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, err |= save_cpextra(cpstate); err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); #endif - /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); return err; } @@ -360,8 +359,7 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(sas_ss_flags(regs->areg[1]), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, - regs, set->sig[0]); + err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, regs); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ diff --git a/include/asm-xtensa/sigcontext.h b/include/asm-xtensa/sigcontext.h index e3381cee5059..dff3c54a3c12 100644 --- a/include/asm-xtensa/sigcontext.h +++ b/include/asm-xtensa/sigcontext.h @@ -13,9 +13,6 @@ struct sigcontext { - unsigned long oldmask; - - /* CPU registers */ unsigned long sc_pc; unsigned long sc_ps; unsigned long sc_lbeg; -- cgit v1.2.3 From 3e92501a4e10e640786de10786c434834a0c1651 Mon Sep 17 00:00:00 2001 From: Marc Gauthier Date: Tue, 11 Dec 2007 15:28:07 -0800 Subject: [XTENSA] Add missing cast in elf.h ELF_CORE_COPY_REGS() Avoids compiler warning. Signed-off-by: Marc Gauthier --- include/asm-xtensa/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 0444507b438d..86479b86c02e 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -96,7 +96,7 @@ typedef unsigned int elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_CORE_COPY_REGS(_eregs, _pregs) \ - xtensa_elf_core_copy_regs (&_eregs, _pregs); + xtensa_elf_core_copy_regs ((xtensa_gregset_t*)&(_eregs), _pregs); extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *); -- cgit v1.2.3 From 3b4a49e21b0d8a69629623815a8caff3eb4cf9f7 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Mon, 7 Jan 2008 16:42:21 -0800 Subject: [XTENSA] Fix modules for non-exec processor configurations We need to use vmalloc_exec for module loading. Also remove the definitions MODULE_START and MODULE_END, which wasn't used, and increase the VMALLOC memory range accordingly. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/module.c | 2 +- include/asm-xtensa/module.h | 4 +++- include/asm-xtensa/pgtable.h | 8 +++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c index ddf14dcf2ad9..3981a466c779 100644 --- a/arch/xtensa/kernel/module.c +++ b/arch/xtensa/kernel/module.c @@ -28,7 +28,7 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return vmalloc(size); + return vmalloc_exec(size); } void module_free(struct module *mod, void *module_region) diff --git a/include/asm-xtensa/module.h b/include/asm-xtensa/module.h index ffb25bfdf6a1..d9b34bee4d42 100644 --- a/include/asm-xtensa/module.h +++ b/include/asm-xtensa/module.h @@ -15,9 +15,11 @@ struct mod_arch_specific { - /* Module support is not completely implemented. */ + /* No special elements, yet. */ }; +#define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " " + #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Ehdr Elf32_Ehdr diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index c0fcc1c9660c..c8b024a48b4d 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -66,11 +66,9 @@ */ #define VMALLOC_START 0xC0000000 -#define VMALLOC_END 0xC6FEFFFF -#define TLBTEMP_BASE_1 0xC6FF0000 -#define TLBTEMP_BASE_2 0xC6FF8000 -#define MODULE_START 0xC7000000 -#define MODULE_END 0xC7FFFFFF +#define VMALLOC_END 0xC7FEFFFF +#define TLBTEMP_BASE_1 0xC7FF0000 +#define TLBTEMP_BASE_2 0xC7FF8000 /* * Xtensa Linux config PTE layout (when present): -- cgit v1.2.3 From de6b03456e2e11cbff9f4bb147177374b260d04e Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Wed, 19 Dec 2007 10:21:50 -0800 Subject: [XTENSA] Add volatile keyword to asm statements accessing counter registers The compiler get's sometimes to smart and doesn't reread the counter registers and the kernel doesn't schedule until the counter wraps around. Signed-off-by: Chris Zankel --- include/asm-xtensa/timex.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h index a5fca59fba9e..b83a8181d448 100644 --- a/include/asm-xtensa/timex.h +++ b/include/asm-xtensa/timex.h @@ -63,10 +63,10 @@ extern cycles_t cacheflush_time; * Register access. */ -#define WSR_CCOUNT(r) __asm__("wsr %0,"__stringify(CCOUNT) :: "a" (r)) -#define RSR_CCOUNT(r) __asm__("rsr %0,"__stringify(CCOUNT) : "=a" (r)) -#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE)"+"__stringify(x) :: "a"(r)) -#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE)"+"__stringify(x) : "=a"(r)) +#define WSR_CCOUNT(r) asm volatile ("wsr %0,"__stringify(CCOUNT) :: "a" (r)) +#define RSR_CCOUNT(r) asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (r)) +#define WSR_CCOMPARE(x,r) asm volatile ("wsr %0,"__stringify(CCOMPARE)"+"__stringify(x) :: "a"(r)) +#define RSR_CCOMPARE(x,r) asm volatile ("rsr %0,"__stringify(CCOMPARE)"+"__stringify(x) : "=a"(r)) static inline unsigned long get_ccount (void) { -- cgit v1.2.3 From 71d28e6c285548106f551fde13ca6d589433d843 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Tue, 16 Oct 2007 16:43:00 -0700 Subject: [XTENSA] Clean up stat structs. Avoid using typedefs for stat fields. Make stat64.st_blocks an unsigned long long to avoid endian-specific padding with 32-bit values. Clean up signed vs. unsigned and int vs. long types to be consistent with other uses of these values. Signed-off-by: Bob Wilson Signed-off-by: Chris Zankel --- include/asm-xtensa/stat.h | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/asm-xtensa/stat.h b/include/asm-xtensa/stat.h index 149f4bce092f..c4992038cee0 100644 --- a/include/asm-xtensa/stat.h +++ b/include/asm-xtensa/stat.h @@ -5,25 +5,23 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_STAT_H #define _XTENSA_STAT_H -#include - #define STAT_HAVE_NSEC 1 struct stat { unsigned long st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - unsigned int st_rdev; - off_t st_size; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + long st_size; unsigned long st_blksize; unsigned long st_blocks; unsigned long st_atime; @@ -36,8 +34,6 @@ struct stat { unsigned long __unused5; }; -/* This matches struct stat64 in glibc-2.3 */ - struct stat64 { unsigned long long st_dev; /* Device */ unsigned long long st_ino; /* File serial number */ @@ -47,20 +43,14 @@ struct stat64 { unsigned int st_gid; /* Group ID of the file's group. */ unsigned long long st_rdev; /* Device number, if device. */ long long st_size; /* Size of file, in bytes. */ - long st_blksize; /* Optimal block size for I/O. */ + unsigned long st_blksize; /* Optimal block size for I/O. */ unsigned long __unused2; -#ifdef __XTENSA_EB__ - unsigned long __unused3; - long st_blocks; /* Number 512-byte blocks allocated. */ -#else - long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __unused3; -#endif - long st_atime; /* Time of last access. */ + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long st_atime; /* Time of last access. */ unsigned long st_atime_nsec; - long st_mtime; /* Time of last modification. */ + unsigned long st_mtime; /* Time of last modification. */ unsigned long st_mtime_nsec; - long st_ctime; /* Time of last status change. */ + unsigned long st_ctime; /* Time of last status change. */ unsigned long st_ctime_nsec; unsigned long __unused4; unsigned long __unused5; -- cgit v1.2.3 From c658eac628aa8df040dfe614556d95e6da3a9ffb Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Tue, 12 Feb 2008 13:17:07 -0800 Subject: [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 --- arch/xtensa/kernel/asm-offsets.c | 16 +- arch/xtensa/kernel/coprocessor.S | 443 ++++++++++++++++++++----------- arch/xtensa/kernel/entry.S | 295 +++++--------------- arch/xtensa/kernel/process.c | 261 +++++++----------- arch/xtensa/kernel/ptrace.c | 347 ++++++++++++------------ arch/xtensa/kernel/signal.c | 65 +++-- arch/xtensa/kernel/traps.c | 16 +- include/asm-xtensa/coprocessor.h | 209 ++++++++++----- include/asm-xtensa/elf.h | 15 ++ include/asm-xtensa/processor.h | 13 +- include/asm-xtensa/ptrace.h | 44 ++- include/asm-xtensa/regs.h | 9 +- include/asm-xtensa/sigcontext.h | 1 + include/asm-xtensa/system.h | 39 +-- include/asm-xtensa/thread_info.h | 21 ++ include/asm-xtensa/variant-fsf/tie-asm.h | 70 +++++ include/asm-xtensa/variant-fsf/tie.h | 75 +++++- 17 files changed, 1065 insertions(+), 874 deletions(-) create mode 100644 include/asm-xtensa/variant-fsf/tie-asm.h (limited to 'include') diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 5d9ef515ca1e..ef63adadf7f4 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -63,6 +63,8 @@ int main(void) DEFINE(PT_SIZE, sizeof(struct pt_regs)); DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS])); DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS])); + DEFINE(PT_XTREGS_OPT, offsetof(struct pt_regs, xtregs_opt)); + DEFINE(XTREGS_OPT_SIZE, sizeof(xtregs_opt_t)); /* struct task_struct */ DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace)); @@ -76,7 +78,19 @@ int main(void) /* struct thread_info (offset from start_struct) */ DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); - DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save)); + DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable)); +#if XTENSA_HAVE_COPROCESSORS + DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp)); +#endif + DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user)); + DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t)); DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds)); /* struct mm_struct */ diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S index 01bcb9fcfcbd..2bc1e145c0a4 100644 --- a/arch/xtensa/kernel/coprocessor.S +++ b/arch/xtensa/kernel/coprocessor.S @@ -8,193 +8,328 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003 - 2005 Tensilica Inc. - * - * Marc Gauthier + * Copyright (C) 2003 - 2007 Tensilica Inc. */ -/* - * This module contains a table that describes the layout of the various - * custom registers and states associated with each coprocessor, as well - * as those not associated with any coprocessor ("extra state"). - * This table is included with core dumps and is available via the ptrace - * interface, allowing the layout of such register/state information to - * be modified in the kernel without affecting the debugger. Each - * register or state is identified using a 32-bit "libdb target number" - * assigned when the Xtensa processor is generated. - */ #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#if XCHAL_HAVE_CP +/* + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ -#define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE) +/* IO protection is currently unsupported. */ -ENTRY(release_coprocessors) +ENTRY(fast_io_protect) + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 - entry a1, 16 - # a2: task - movi a3, 1 << XCHAL_CP_MAX # a3: coprocessor-bit - movi a4, coprocessor_info+CP_LAST # a4: owner-table - # a5: tmp - movi a6, 0 # a6: 0 - rsil a7, LOCKLEVEL # a7: PS +#if XTENSA_HAVE_COPROCESSORS -1: /* Check if task is coprocessor owner of coprocessor[i]. */ +/* + * Macros for lazy context switch. + */ - l32i a5, a4, COPROCESSOR_INFO_OWNER - srli a3, a3, 1 - beqz a3, 1f - addi a4, a4, -8 - beq a2, a5, 1b +#define SAVE_CP_REGS(x) \ + .align 4; \ + .Lsave_cp_regs_cp##x: \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + xchal_cp##x##_store a2 a4 a5 a6 a7; \ + .endif; \ + jx a0 - /* Found an entry: Clear entry CPENABLE bit to disable CP. */ +#define SAVE_CP_REGS_TAB(x) \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + .long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \ + .else; \ + .long 0; \ + .endif; \ + .long THREAD_XTREGS_CP##x - rsr a5, CPENABLE - s32i a6, a4, COPROCESSOR_INFO_OWNER - xor a5, a3, a5 - wsr a5, CPENABLE - bnez a3, 1b +#define LOAD_CP_REGS(x) \ + .align 4; \ + .Lload_cp_regs_cp##x: \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + xchal_cp##x##_load a2 a4 a5 a6 a7; \ + .endif; \ + jx a0 -1: wsr a7, PS - rsync - retw +#define LOAD_CP_REGS_TAB(x) \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + .long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \ + .else; \ + .long 0; \ + .endif; \ + .long THREAD_XTREGS_CP##x + SAVE_CP_REGS(0) + SAVE_CP_REGS(1) + SAVE_CP_REGS(2) + SAVE_CP_REGS(3) + SAVE_CP_REGS(4) + SAVE_CP_REGS(5) + SAVE_CP_REGS(6) + SAVE_CP_REGS(7) -ENTRY(disable_coprocessor) - entry sp, 16 - rsil a7, LOCKLEVEL - rsr a3, CPENABLE - movi a4, 1 - ssl a2 - sll a4, a4 - and a4, a3, a4 - xor a3, a3, a4 - wsr a3, CPENABLE - wsr a7, PS - rsync - retw + LOAD_CP_REGS(0) + LOAD_CP_REGS(1) + LOAD_CP_REGS(2) + LOAD_CP_REGS(3) + LOAD_CP_REGS(4) + LOAD_CP_REGS(5) + LOAD_CP_REGS(6) + LOAD_CP_REGS(7) -ENTRY(enable_coprocessor) - entry sp, 16 - rsil a7, LOCKLEVEL - rsr a3, CPENABLE - movi a4, 1 - ssl a2 - sll a4, a4 - or a3, a3, a4 - wsr a3, CPENABLE - wsr a7, PS - rsync - retw + .align 4 +.Lsave_cp_regs_jump_table: + SAVE_CP_REGS_TAB(0) + SAVE_CP_REGS_TAB(1) + SAVE_CP_REGS_TAB(2) + SAVE_CP_REGS_TAB(3) + SAVE_CP_REGS_TAB(4) + SAVE_CP_REGS_TAB(5) + SAVE_CP_REGS_TAB(6) + SAVE_CP_REGS_TAB(7) +.Lload_cp_regs_jump_table: + LOAD_CP_REGS_TAB(0) + LOAD_CP_REGS_TAB(1) + LOAD_CP_REGS_TAB(2) + LOAD_CP_REGS_TAB(3) + LOAD_CP_REGS_TAB(4) + LOAD_CP_REGS_TAB(5) + LOAD_CP_REGS_TAB(6) + LOAD_CP_REGS_TAB(7) -ENTRY(save_coprocessor_extra) - entry sp, 16 - xchal_extra_store_funcbody - retw +/* + * coprocessor_save(buffer, index) + * a2 a3 + * coprocessor_load(buffer, index) + * a2 a3 + * + * Save or load coprocessor registers for coprocessor 'index'. + * The register values are saved to or loaded from them 'buffer' address. + * + * Note that these functions don't update the coprocessor_owner information! + * + */ -ENTRY(restore_coprocessor_extra) - entry sp, 16 - xchal_extra_load_funcbody +ENTRY(coprocessor_save) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lsave_cp_regs_jump_table + addx8 a3, a3, a0 + l32i a3, a3, 0 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 retw -ENTRY(save_coprocessor_registers) - entry sp, 16 - xchal_cpi_store_funcbody +ENTRY(coprocessor_load) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lload_cp_regs_jump_table + addx4 a3, a3, a0 + l32i a3, a3, 0 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 retw -ENTRY(restore_coprocessor_registers) - entry sp, 16 - xchal_cpi_load_funcbody +/* + * coprocessor_flush(struct task_info*, index) + * a2 a3 + * coprocessor_restore(struct task_info*, index) + * a2 a3 + * + * Save or load coprocessor registers for coprocessor 'index'. + * The register values are saved to or loaded from the coprocessor area + * inside the task_info structure. + * + * Note that these functions don't update the coprocessor_owner information! + * + */ + + +ENTRY(coprocessor_flush) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lsave_cp_regs_jump_table + addx8 a3, a3, a0 + l32i a4, a3, 4 + l32i a3, a3, 0 + add a2, a2, a4 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 retw +ENTRY(coprocessor_restore) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lload_cp_regs_jump_table + addx4 a3, a3, a0 + l32i a4, a3, 4 + l32i a3, a3, 0 + add a2, a2, a4 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 + retw /* - * The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros - * describe the contents of coprocessor & extra save areas in terms of - * undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros. We define these - * latter macros here; they expand into a table of the format we want. - * The general format is: + * Entry condition: * - * CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, - * bitmask, rsv2, rsv3) - * CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, - * bitmask, rsv2, rsv3) - * CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, - * numentries, contentsize, regname_base, - * regfile_name, rsv2, rsv3) + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 * - * For this table, we only care about the , and - * fields. + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception */ -/* Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below: */ - -#define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum, \ - bitmask, rsv2, rsv3) \ - reg_entry libdbnum, offset, size ; -#define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum, \ - bitmask, rsv2, rsv3) \ - reg_entry libdbnum, offset, size ; -#define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \ - numentries, contentsize, regname_base, \ - regfile_name, rsv2, rsv3) \ - reg_entry libdbnum, offset, size ; - -/* A single table entry: */ - .macro reg_entry libdbnum, offset, size - .ifne (__last_offset-(__last_group_offset+\offset)) - /* padding entry */ - .word (0xFC000000+__last_offset-(__last_group_offset+\offset)) - .endif - .word \libdbnum /* actual entry */ - .set __last_offset, __last_group_offset+\offset+\size - .endm /* reg_entry */ - - -/* Table entry that marks the beginning of a group (coprocessor or "extra"): */ - .macro reg_group cpnum, num_entries, align - .set __last_group_offset, (__last_offset + \align- 1) & -\align - .ifne \num_entries - .word 0xFD000000+(\cpnum<<16)+\num_entries - .endif - .endm /* reg_group */ +ENTRY(fast_coprocessor_double) + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 -/* - * Register info tables. - */ - .section .rodata, "a" - .globl _xtensa_reginfo_tables - .globl _xtensa_reginfo_table_size - .align 4 -_xtensa_reginfo_table_size: - .word _xtensa_reginfo_table_end - _xtensa_reginfo_tables - -_xtensa_reginfo_tables: - .set __last_offset, 0 - reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN - XCHAL_EXTRA_SA_CONTENTS_LIBDB - reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN - XCHAL_CP0_SA_CONTENTS_LIBDB - reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN - XCHAL_CP1_SA_CONTENTS_LIBDB - reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN - XCHAL_CP2_SA_CONTENTS_LIBDB - reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN - XCHAL_CP3_SA_CONTENTS_LIBDB - reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN - XCHAL_CP4_SA_CONTENTS_LIBDB - reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN - XCHAL_CP5_SA_CONTENTS_LIBDB - reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN - XCHAL_CP6_SA_CONTENTS_LIBDB - reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN - XCHAL_CP7_SA_CONTENTS_LIBDB - .word 0xFC000000 /* invalid register number,marks end of table*/ -_xtensa_reginfo_table_end: -#endif +ENTRY(fast_coprocessor) + + /* Save remaining registers a1-a3 and SAR */ + + xsr a3, EXCSAVE_1 + s32i a3, a2, PT_AREG3 + rsr a3, SAR + s32i a1, a2, PT_AREG1 + s32i a3, a2, PT_SAR + mov a1, a2 + rsr a2, DEPC + s32i a2, a1, PT_AREG2 + + /* + * The hal macros require up to 4 temporary registers. We use a3..a6. + */ + + s32i a4, a1, PT_AREG4 + s32i a5, a1, PT_AREG5 + s32i a6, a1, PT_AREG6 + + /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ + + rsr a3, EXCCAUSE + addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED + + /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1< #include #include +#include /* Unimplemented features. */ @@ -213,19 +214,7 @@ _user_exception: /* We are back to the original stack pointer (a1) */ -2: -#if XCHAL_EXTRA_SA_SIZE - - /* For user exceptions, save the extra state into the user's TCB. - * Note: We must assume that xchal_extra_store_funcbody destroys a2..a15 - */ - - GET_CURRENT(a2,a1) - addi a2, a2, THREAD_CP_SAVE - xchal_extra_store_funcbody -#endif - - /* Now, jump to the common exception handler. */ +2: /* Now, jump to the common exception handler. */ j common_exception @@ -381,6 +370,10 @@ common_exception: s32i a2, a1, PT_LBEG s32i a3, a1, PT_LEND + /* Save optional registers. */ + + save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT + /* Go to second-level dispatcher. Set up parameters to pass to the * exception handler and call the exception handler. */ @@ -452,22 +445,6 @@ common_exception_return: 4: /* a2 holds GET_CURRENT(a2,a1) */ -#if XCHAL_EXTRA_SA_SIZE - - /* For user exceptions, restore the extra state from the user's TCB. */ - - /* Note: a2 still contains GET_CURRENT(a2,a1) */ - addi a2, a2, THREAD_CP_SAVE - xchal_extra_load_funcbody - - /* We must assume that xchal_extra_store_funcbody destroys - * registers a2..a15. FIXME, this list can eventually be - * reduced once real register requirements of the macro are - * finalized. */ - -#endif /* XCHAL_EXTRA_SA_SIZE */ - - /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ l32i a2, a1, PT_WINDOWBASE @@ -614,6 +591,12 @@ kernel_exception_exit: common_exception_exit: + /* Restore optional registers. */ + + load_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT + + /* Restore address registers. */ + _bbsi.l a2, 1, 1f l32i a4, a1, PT_AREG4 l32i a5, a1, PT_AREG5 @@ -1146,7 +1129,6 @@ CATCH * excsave_1: a3 * * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. - * Note: We don't need to save a2 in depc (return value) */ ENTRY(fast_syscall_spill_registers) @@ -1162,29 +1144,31 @@ ENTRY(fast_syscall_spill_registers) rsr a0, SAR xsr a3, EXCSAVE_1 # restore a3 and excsave_1 - s32i a0, a2, PT_AREG4 # store SAR to PT_AREG4 s32i a3, a2, PT_AREG3 + s32i a4, a2, PT_AREG4 + s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 /* The spill routine might clobber a7, a11, and a15. */ - s32i a7, a2, PT_AREG5 - s32i a11, a2, PT_AREG6 - s32i a15, a2, PT_AREG7 + s32i a7, a2, PT_AREG7 + s32i a11, a2, PT_AREG11 + s32i a15, a2, PT_AREG15 - call0 _spill_registers # destroys a3, DEPC, and SAR + call0 _spill_registers # destroys a3, a4, and SAR /* Advance PC, restore registers and SAR, and return from exception. */ - l32i a3, a2, PT_AREG4 + l32i a3, a2, PT_AREG5 + l32i a4, a2, PT_AREG4 l32i a0, a2, PT_AREG0 wsr a3, SAR l32i a3, a2, PT_AREG3 /* Restore clobbered registers. */ - l32i a7, a2, PT_AREG5 - l32i a11, a2, PT_AREG6 - l32i a15, a2, PT_AREG7 + l32i a7, a2, PT_AREG7 + l32i a11, a2, PT_AREG11 + l32i a15, a2, PT_AREG15 movi a2, 0 rfe @@ -1257,9 +1241,9 @@ fast_syscall_spill_registers_fixup: movi a3, exc_table rsr a0, EXCCAUSE - addx4 a0, a0, a3 # find entry in table - l32i a0, a0, EXC_TABLE_FAST_USER # load handler - jx a0 + addx4 a0, a0, a3 # find entry in table + l32i a0, a0, EXC_TABLE_FAST_USER # load handler + jx a0 fast_syscall_spill_registers_fixup_return: @@ -1297,7 +1281,7 @@ fast_syscall_spill_registers_fixup_return: * This is not a real function. The following conditions must be met: * * - must be called with call0. - * - uses DEPC, a3 and SAR. + * - uses a3, a4 and SAR. * - the last 'valid' register of each frame are clobbered. * - the caller must have registered a fixup handler * (or be inside a critical section) @@ -1309,41 +1293,39 @@ ENTRY(_spill_registers) /* * Rotate ws so that the current windowbase is at bit 0. * Assume ws = xxxwww1yy (www1 current window frame). - * Rotate ws right so that a2 = yyxxxwww1. + * Rotate ws right so that a4 = yyxxxwww1. */ - wsr a2, DEPC # preserve a2 - rsr a2, WINDOWBASE + rsr a4, WINDOWBASE rsr a3, WINDOWSTART # a3 = xxxwww1yy - ssr a2 # holds WB - slli a2, a3, WSBITS - or a3, a3, a2 # a3 = xxxwww1yyxxxwww1yy + ssr a4 # holds WB + slli a4, a3, WSBITS + or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy srl a3, a3 # a3 = 00xxxwww1yyxxxwww1 /* We are done if there are no more than the current register frame. */ extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww - movi a2, (1 << (WSBITS-1)) + movi a4, (1 << (WSBITS-1)) _beqz a3, .Lnospill # only one active frame? jump /* We want 1 at the top, so that we return to the current windowbase */ - or a3, a3, a2 # 1yyxxxwww + or a3, a3, a4 # 1yyxxxwww /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */ wsr a3, WINDOWSTART # save shifted windowstart - neg a2, a3 - and a3, a2, a3 # first bit set from right: 000010000 + neg a4, a3 + and a3, a4, a3 # first bit set from right: 000010000 - ffs_ws a2, a3 # a2: shifts to skip empty frames + ffs_ws a4, a3 # a4: shifts to skip empty frames movi a3, WSBITS - sub a2, a3, a2 # WSBITS-a2:number of 0-bits from right - ssr a2 # save in SAR for later. + sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right + ssr a4 # save in SAR for later. rsr a3, WINDOWBASE - add a3, a3, a2 - rsr a2, DEPC # restore a2 + add a3, a3, a4 wsr a3, WINDOWBASE rsync @@ -1373,7 +1355,6 @@ ENTRY(_spill_registers) j .Lc12c .Lnospill: - rsr a2, DEPC ret .Lloop: _bbsi.l a3, 1, .Lc4 @@ -1810,154 +1791,6 @@ ENTRY(fast_store_prohibited) 1: j _user_exception -#if XCHAL_EXTRA_SA_SIZE - -#warning fast_coprocessor untested - -/* - * Entry condition: - * - * a0: trashed, original value saved on stack (PT_AREG0) - * a1: a1 - * a2: new stack pointer, original in DEPC - * a3: dispatch table - * depc: a2, original value saved on stack (PT_DEPC) - * excsave_1: a3 - * - * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC - * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception - */ - -ENTRY(fast_coprocessor_double) - wsr a0, EXCSAVE_1 - movi a0, unrecoverable_exception - callx0 a0 - -ENTRY(fast_coprocessor) - - /* Fatal if we are in a double exception. */ - - l32i a0, a2, PT_DEPC - _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_coprocessor_double - - /* Save some registers a1, a3, a4, SAR */ - - xsr a3, EXCSAVE_1 - s32i a3, a2, PT_AREG3 - rsr a3, SAR - s32i a4, a2, PT_AREG4 - s32i a1, a2, PT_AREG1 - s32i a5, a1, PT_AREG5 - s32i a3, a2, PT_SAR - mov a1, a2 - - /* Currently, the HAL macros only guarantee saving a0 and a1. - * These can and will be refined in the future, but for now, - * just save the remaining registers of a2...a15. - */ - s32i a6, a1, PT_AREG6 - s32i a7, a1, PT_AREG7 - s32i a8, a1, PT_AREG8 - s32i a9, a1, PT_AREG9 - s32i a10, a1, PT_AREG10 - s32i a11, a1, PT_AREG11 - s32i a12, a1, PT_AREG12 - s32i a13, a1, PT_AREG13 - s32i a14, a1, PT_AREG14 - s32i a15, a1, PT_AREG15 - - /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ - - rsr a0, EXCCAUSE - addi a3, a0, -XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED - - /* Set corresponding CPENABLE bit */ - - movi a4, 1 - ssl a3 # SAR: 32 - coprocessor_number - rsr a5, CPENABLE - sll a4, a4 - or a4, a5, a4 - wsr a4, CPENABLE - rsync - movi a5, coprocessor_info # list of owner and offset into cp_save - addx8 a0, a4, a5 # entry for CP - - bne a4, a5, .Lload # bit wasn't set before, cp not in use - - /* Now compare the current task with the owner of the coprocessor. - * If they are the same, there is no reason to save or restore any - * coprocessor state. Having already enabled the coprocessor, - * branch ahead to return. - */ - GET_CURRENT(a5,a1) - l32i a4, a0, COPROCESSOR_INFO_OWNER # a4: current owner for this CP - beq a4, a5, .Ldone - - /* Find location to dump current coprocessor state: - * task_struct->task_cp_save_offset + coprocessor_offset[coprocessor] - * - * Note: a0 pointer to the entry in the coprocessor owner table, - * a3 coprocessor number, - * a4 current owner of coprocessor. - */ - l32i a5, a0, COPROCESSOR_INFO_OFFSET - addi a2, a4, THREAD_CP_SAVE - add a2, a2, a5 - - /* Store current coprocessor states. (a5 still has CP number) */ - - xchal_cpi_store_funcbody - - /* The macro might have destroyed a3 (coprocessor number), but - * SAR still has 32 - coprocessor_number! - */ - movi a3, 32 - rsr a4, SAR - sub a3, a3, a4 - -.Lload: /* A new task now owns the corpocessors. Save its TCB pointer into - * the coprocessor owner table. - * - * Note: a0 pointer to the entry in the coprocessor owner table, - * a3 coprocessor number. - */ - GET_CURRENT(a4,a1) - s32i a4, a0, 0 - - /* Find location from where to restore the current coprocessor state.*/ - - l32i a5, a0, COPROCESSOR_INFO_OFFSET - addi a2, a4, THREAD_CP_SAVE - add a2, a2, a4 - - xchal_cpi_load_funcbody - - /* We must assume that the xchal_cpi_store_funcbody macro destroyed - * registers a2..a15. - */ - -.Ldone: l32i a15, a1, PT_AREG15 - l32i a14, a1, PT_AREG14 - l32i a13, a1, PT_AREG13 - l32i a12, a1, PT_AREG12 - l32i a11, a1, PT_AREG11 - l32i a10, a1, PT_AREG10 - l32i a9, a1, PT_AREG9 - l32i a8, a1, PT_AREG8 - l32i a7, a1, PT_AREG7 - l32i a6, a1, PT_AREG6 - l32i a5, a1, PT_AREG5 - l32i a4, a1, PT_AREG4 - l32i a3, a1, PT_AREG3 - l32i a2, a1, PT_AREG2 - l32i a0, a1, PT_AREG0 - l32i a1, a1, PT_AREG1 - - rfe - -#endif /* XCHAL_EXTRA_SA_SIZE */ - /* * System Calls. * @@ -2066,20 +1899,36 @@ ENTRY(_switch_to) entry a1, 16 - mov a4, a3 # preserve a3 + mov a12, a2 # preserve 'prev' (a2) + mov a13, a3 # and 'next' (a3) - s32i a0, a2, THREAD_RA # save return address - s32i a1, a2, THREAD_SP # save stack pointer + l32i a4, a2, TASK_THREAD_INFO + l32i a5, a3, TASK_THREAD_INFO - /* Disable ints while we manipulate the stack pointer; spill regs. */ + save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER - movi a5, (1 << PS_EXCM_BIT) | LOCKLEVEL - xsr a5, PS + s32i a0, a12, THREAD_RA # save return address + s32i a1, a12, THREAD_SP # save stack pointer + + /* Disable ints while we manipulate the stack pointer. */ + + movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL + xsr a14, PS rsr a3, EXCSAVE_1 rsync s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */ - call0 _spill_registers + /* Switch CPENABLE */ + +#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) + l32i a3, a5, THREAD_CPENABLE + xsr a3, CPENABLE + s32i a3, a4, THREAD_CPENABLE +#endif + + /* Flush register file. */ + + call0 _spill_registers # destroys a3, a4, and SAR /* Set kernel stack (and leave critical section) * Note: It's save to set it here. The stack will not be overwritten @@ -2087,19 +1936,21 @@ ENTRY(_switch_to) * we return from kernel space. */ - l32i a0, a4, TASK_THREAD_INFO rsr a3, EXCSAVE_1 # exc_table - movi a1, 0 - addi a0, a0, PT_REGS_OFFSET - s32i a1, a3, EXC_TABLE_FIXUP - s32i a0, a3, EXC_TABLE_KSTK + movi a6, 0 + addi a7, a5, PT_REGS_OFFSET + s32i a6, a3, EXC_TABLE_FIXUP + s32i a7, a3, EXC_TABLE_KSTK /* restore context of the task that 'next' addresses */ - l32i a0, a4, THREAD_RA /* restore return address */ - l32i a1, a4, THREAD_SP /* restore stack pointer */ + l32i a0, a13, THREAD_RA # restore return address + l32i a1, a13, THREAD_SP # restore stack pointer + + load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER - wsr a5, PS + wsr a14, PS + mov a2, a12 # return 'prev' rsync retw diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 026138d641a4..9185597eb6a0 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -52,6 +52,55 @@ void (*pm_power_off)(void) = NULL; EXPORT_SYMBOL(pm_power_off); +#if XTENSA_HAVE_COPROCESSORS + +void coprocessor_release_all(struct thread_info *ti) +{ + unsigned long cpenable; + int i; + + /* Make sure we don't switch tasks during this operation. */ + + preempt_disable(); + + /* Walk through all cp owners and release it for the requested one. */ + + cpenable = ti->cpenable; + + for (i = 0; i < XCHAL_CP_MAX; i++) { + if (coprocessor_owner[i] == ti) { + coprocessor_owner[i] = 0; + cpenable &= ~(1 << i); + } + } + + ti->cpenable = cpenable; + coprocessor_clear_cpenable(); + + preempt_enable(); +} + +void coprocessor_flush_all(struct thread_info *ti) +{ + unsigned long cpenable; + int i; + + preempt_disable(); + + cpenable = ti->cpenable; + + for (i = 0; i < XCHAL_CP_MAX; i++) { + if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti) + coprocessor_flush(ti, i); + cpenable >>= 1; + } + + preempt_enable(); +} + +#endif + + /* * Powermanagement idle function, if any is provided by the platform. */ @@ -71,15 +120,36 @@ void cpu_idle(void) } /* - * Free current thread data structures etc.. + * This is called when the thread calls exit(). */ - void exit_thread(void) { +#if XTENSA_HAVE_COPROCESSORS + coprocessor_release_all(current_thread_info()); +#endif } +/* + * Flush thread state. This is called when a thread does an execve() + * Note that we flush coprocessor registers for the case execve fails. + */ void flush_thread(void) { +#if XTENSA_HAVE_COPROCESSORS + struct thread_info *ti = current_thread_info(); + coprocessor_flush_all(ti); + coprocessor_release_all(ti); +#endif +} + +/* + * This is called before the thread is copied. + */ +void prepare_to_copy(struct task_struct *tsk) +{ +#if XTENSA_HAVE_COPROCESSORS + coprocessor_flush_all(task_thread_info(tsk)); +#endif } /* @@ -107,6 +177,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs *childregs; + struct thread_info *ti; unsigned long tos; int user_mode = user_mode(regs); @@ -128,13 +199,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, p->set_child_tid = p->clear_child_tid = NULL; p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1); p->thread.sp = (unsigned long)childregs; + if (user_mode(regs)) { int len = childregs->wmask & ~0xf; childregs->areg[1] = usp; memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], ®s->areg[XCHAL_NUM_AREGS - len/4], len); - +// FIXME: we need to set THREADPTR in thread_info... if (clone_flags & CLONE_SETTLS) childregs->areg[2] = childregs->areg[6]; @@ -142,6 +214,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, /* In kernel space, we start a new thread with a new stack. */ childregs->wmask = 1; } + +#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) + ti = task_thread_info(p); + ti->cpenable = 0; +#endif + return 0; } @@ -179,10 +257,6 @@ unsigned long get_wchan(struct task_struct *p) } /* - * do_copy_regs() gathers information from 'struct pt_regs' and - * 'current->thread.areg[]' to fill in the xtensa_gregset_t - * structure. - * * xtensa_gregset_t and 'struct pt_regs' are vastly different formats * of processor registers. Besides different ordering, * xtensa_gregset_t contains non-live register information that @@ -191,9 +265,20 @@ unsigned long get_wchan(struct task_struct *p) * */ -void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, - struct task_struct *tsk) +void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) { + unsigned long wb, ws, wm; + int live, last; + + wb = regs->windowbase; + ws = regs->windowstart; + wm = regs->wmask; + ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1); + + /* Don't leak any random bits. */ + + memset(elfregs, 0, sizeof (elfregs)); + /* Note: PS.EXCM is not set while user task is running; its * being set in regs->ps is for exception handling convenience. */ @@ -204,159 +289,18 @@ void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, elfregs->lend = regs->lend; elfregs->lcount = regs->lcount; elfregs->sar = regs->sar; + elfregs->windowstart = ws; - memcpy (elfregs->a, regs->areg, sizeof(elfregs->a)); -} - -void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) -{ - do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current); -} - - -/* The inverse of do_copy_regs(). No error or sanity checking. */ - -void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs, - struct task_struct *tsk) -{ - const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; - unsigned long ps; - - /* Note: PS.EXCM is not set while user task is running; it - * needs to be set in regs->ps is for exception handling convenience. - */ - - ps = (regs->ps & ~ps_mask) | (elfregs->ps & ps_mask) | (1<ps = ps; - regs->pc = elfregs->pc; - regs->lbeg = elfregs->lbeg; - regs->lend = elfregs->lend; - regs->lcount = elfregs->lcount; - regs->sar = elfregs->sar; - - memcpy (regs->areg, elfregs->a, sizeof(regs->areg)); -} - -/* - * do_save_fpregs() gathers information from 'struct pt_regs' and - * 'current->thread' to fill in the elf_fpregset_t structure. - * - * Core files and ptrace use elf_fpregset_t. - */ - -void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs, - struct task_struct *tsk) -{ -#if XCHAL_HAVE_CP - - extern unsigned char _xtensa_reginfo_tables[]; - extern unsigned _xtensa_reginfo_table_size; - int i; - unsigned long flags; - - /* Before dumping coprocessor state from memory, - * ensure any live coprocessor contents for this - * task are first saved to memory: - */ - local_irq_save(flags); - - for (i = 0; i < XCHAL_CP_MAX; i++) { - if (tsk == coprocessor_info[i].owner) { - enable_coprocessor(i); - save_coprocessor_registers( - tsk->thread.cp_save+coprocessor_info[i].offset,i); - disable_coprocessor(i); - } - } - - local_irq_restore(flags); - - /* Now dump coprocessor & extra state: */ - memcpy((unsigned char*)fpregs, - _xtensa_reginfo_tables, _xtensa_reginfo_table_size); - memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size, - tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); -#endif + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; + memcpy(elfregs->a, regs->areg, live * 4); + memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16); } -/* - * The inverse of do_save_fpregs(). - * Copies coprocessor and extra state from fpregs into regs and tsk->thread. - * Returns 0 on success, non-zero if layout doesn't match. - */ - -int do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs, - struct task_struct *tsk) +int dump_fpu(void) { -#if XCHAL_HAVE_CP - - extern unsigned char _xtensa_reginfo_tables[]; - extern unsigned _xtensa_reginfo_table_size; - int i; - unsigned long flags; - - /* Make sure save area layouts match. - * FIXME: in the future we could allow restoring from - * a different layout of the same registers, by comparing - * fpregs' table with _xtensa_reginfo_tables and matching - * entries and copying registers one at a time. - * Not too sure yet whether that's very useful. - */ - - if( memcmp((unsigned char*)fpregs, - _xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) { - return -1; - } - - /* Before restoring coprocessor state from memory, - * ensure any live coprocessor contents for this - * task are first invalidated. - */ - - local_irq_save(flags); - - for (i = 0; i < XCHAL_CP_MAX; i++) { - if (tsk == coprocessor_info[i].owner) { - enable_coprocessor(i); - save_coprocessor_registers( - tsk->thread.cp_save+coprocessor_info[i].offset,i); - coprocessor_info[i].owner = 0; - disable_coprocessor(i); - } - } - - local_irq_restore(flags); - - /* Now restore coprocessor & extra state: */ - - memcpy(tsk->thread.cp_save, - (unsigned char*)fpregs + _xtensa_reginfo_table_size, - XTENSA_CP_EXTRA_SIZE); -#endif return 0; } -/* - * Fill in the CP structure for a core dump for a particular task. - */ - -int -dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r) -{ - return 0; /* no coprocessors active on this processor */ -} - -/* - * Fill in the CP structure for a core dump. - * This includes any FPU coprocessor. - * Here, we dump all coprocessors, and other ("extra") custom state. - * - * This function is called by elf_core_dump() in fs/binfmt_elf.c - * (in which case 'regs' comes from calls to do_coredump, see signals.c). - */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) -{ - return dump_task_fpu(regs, current, r); -} asmlinkage long xtensa_clone(unsigned long clone_flags, unsigned long newsp, @@ -370,8 +314,8 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp, } /* - * * xtensa_execve() executes a new program. - * */ + * xtensa_execve() executes a new program. + */ asmlinkage long xtensa_execve(char __user *name, char __user * __user *argv, @@ -386,7 +330,6 @@ long xtensa_execve(char __user *name, char __user * __user *argv, error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - // FIXME: release coprocessor?? error = do_execve(filename, argv, envp, regs); if (error == 0) { task_lock(current); diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 5533c7850d53..f6669d605125 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. * * Joe Taylor * Chris Zankel @@ -28,14 +28,10 @@ #include #include #include - -#define TEST_KERNEL // verify kernel operations FIXME: remove - +#include /* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure single step bits etc are not set. + * Called by kernel/ptrace.c when detaching to disable single stepping. */ void ptrace_disable(struct task_struct *child) @@ -43,136 +39,233 @@ void ptrace_disable(struct task_struct *child) /* Nothing to do.. */ } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +int ptrace_getregs(struct task_struct *child, void __user *uregs) { - int ret = -EPERM; + struct pt_regs *regs = task_pt_regs(child); + xtensa_gregset_t __user *gregset = uregs; + unsigned long wb = regs->windowbase; + unsigned long ws = regs->windowstart; + unsigned long wm = regs->wmask; + int ret = 0; + int live, last; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) + return -EIO; + + /* Norm windowstart to a windowbase of 0. */ + + ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<pc, &gregset->pc); + ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); + ret |= __put_user(regs->lbeg, &gregset->lbeg); + ret |= __put_user(regs->lend, &gregset->lend); + ret |= __put_user(regs->lcount, &gregset->lcount); + ret |= __put_user(ws, &gregset->windowstart); + + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; + ret |= __copy_to_user(gregset->a, regs->areg, live * 4); + ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16); + + return ret ? -EFAULT : 0; +} - switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - goto out; +int ptrace_setregs(struct task_struct *child, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + xtensa_gregset_t *gregset = uregs; + const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; + unsigned long wm = regs->wmask; + unsigned long ps; + int ret = 0; + int live, last; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) + return -EIO; + + ret |= __get_user(regs->pc, &gregset->pc); + ret |= __get_user(ps, &gregset->ps); + ret |= __get_user(regs->lbeg, &gregset->lbeg); + ret |= __get_user(regs->lend, &gregset->lend); + ret |= __get_user(regs->lcount, &gregset->lcount); + + regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); + + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; + ret |= __copy_from_user(regs->areg, gregset->a, live * 4); + ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16); + + return ret ? -EFAULT : 0; +} - /* Read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - { - struct pt_regs *regs; - unsigned long tmp; +int ptrace_getxregs(struct task_struct *child, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + struct thread_info *ti = task_thread_info(child); + elf_xtregs_t __user *xtregs = uregs; + int ret = 0; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) + return -EIO; + +#if XTENSA_HAVE_COPROCESSORS + /* Flush all coprocessor registers to memory. */ + coprocessor_flush_all(ti); + ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp, + sizeof(xtregs_coprocessor_t)); +#endif + ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt, + sizeof(xtregs->opt)); + ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, + sizeof(xtregs->user)); - regs = task_pt_regs(child); - tmp = 0; /* Default return value. */ + return ret ? -EFAULT : 0; +} + +int ptrace_setxregs(struct task_struct *child, void __user *uregs) +{ + struct thread_info *ti = task_thread_info(child); + struct pt_regs *regs = task_pt_regs(child); + elf_xtregs_t *xtregs = uregs; + int ret = 0; + +#if XTENSA_HAVE_COPROCESSORS + /* Flush all coprocessors before we overwrite them. */ + coprocessor_flush_all(ti); + coprocessor_release_all(ti); + + ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, + sizeof(xtregs_coprocessor_t)); +#endif + ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt, + sizeof(xtregs->opt)); + ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, + sizeof(xtregs->user)); + + return ret ? -EFAULT : 0; +} + +int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret) +{ + struct pt_regs *regs; + unsigned long tmp; + + regs = task_pt_regs(child); + tmp = 0; /* Default return value. */ - switch(addr) { + switch(regno) { case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: - { - int ar = addr - REG_AR_BASE - regs->windowbase * 4; - ar &= (XCHAL_NUM_AREGS - 1); - if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) - tmp = regs->areg[ar]; - else - ret = -EIO; + tmp = regs->areg[regno - REG_AR_BASE]; break; - } + case REG_A_BASE ... REG_A_BASE + 15: - tmp = regs->areg[addr - REG_A_BASE]; + tmp = regs->areg[regno - REG_A_BASE]; break; + case REG_PC: tmp = regs->pc; break; + case REG_PS: /* Note: PS.EXCM is not set while user task is running; * its being set in regs is for exception handling * convenience. */ tmp = (regs->ps & ~(1 << PS_EXCM_BIT)); break; + case REG_WB: - tmp = regs->windowbase; - break; + break; /* tmp = 0 */ + case REG_WS: - tmp = regs->windowstart; + { + unsigned long wb = regs->windowbase; + unsigned long ws = regs->windowstart; + tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<lbeg; break; + case REG_LEND: tmp = regs->lend; break; + case REG_LCOUNT: tmp = regs->lcount; break; + case REG_SAR: tmp = regs->sar; break; - case REG_DEPC: - tmp = regs->depc; - break; - case REG_EXCCAUSE: - tmp = regs->exccause; - break; - case REG_EXCVADDR: - tmp = regs->excvaddr; - break; + case SYSCALL_NR: tmp = regs->syscall; break; - default: - tmp = 0; - ret = -EIO; - goto out; - } - ret = put_user(tmp, (unsigned long *) data); - goto out; - } - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - goto out; + default: + return -EIO; + } + return put_user(tmp, ret); +} - case PTRACE_POKEUSR: - { - struct pt_regs *regs; - regs = task_pt_regs(child); +int ptrace_pokeusr(struct task_struct *child, long regno, long val) +{ + struct pt_regs *regs; + regs = task_pt_regs(child); - switch (addr) { + switch (regno) { case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: - { - int ar = addr - REG_AR_BASE - regs->windowbase * 4; - if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) - regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data; - else - ret = -EIO; + regs->areg[regno - REG_AR_BASE] = val; break; - } + case REG_A_BASE ... REG_A_BASE + 15: - regs->areg[addr - REG_A_BASE] = data; + regs->areg[regno - REG_A_BASE] = val; break; + case REG_PC: - regs->pc = data; + regs->pc = val; break; + case SYSCALL_NR: - regs->syscall = data; - break; -#ifdef TEST_KERNEL - case REG_WB: - regs->windowbase = data; + regs->syscall = val; break; - case REG_WS: - regs->windowstart = data; - break; -#endif default: - /* The rest are not allowed. */ - ret = -EIO; - break; - } + return -EIO; + } + return 0; +} + +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + int ret = -EPERM; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + ret = generic_ptrace_peekdata(child, addr, data); + break; + + case PTRACE_PEEKUSR: /* read register specified by addr. */ + ret = ptrace_peekusr(child, addr, (void __user *) data); + break; + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = generic_ptrace_pokedata(child, addr, data); + break; + + case PTRACE_POKEUSR: /* write register specified by addr. */ + ret = ptrace_pokeusr(child, addr, data); break; - } /* continue and stop at next (return from) syscall */ + case PTRACE_SYSCALL: case PTRACE_CONT: /* restart after signal. */ { @@ -217,98 +310,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - { - /* 'data' points to user memory in which to write. - * Mainly due to the non-live register values, we - * reformat the register values into something more - * standard. For convenience, we use the handy - * elf_gregset_t format. */ - - xtensa_gregset_t format; - struct pt_regs *regs = task_pt_regs(child); - - do_copy_regs (&format, regs, child); - - /* Now, copy to user space nice and easy... */ - ret = 0; - if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t))) - ret = -EFAULT; + ret = ptrace_getregs(child, (void __user *) data); break; - } case PTRACE_SETREGS: - { - /* 'data' points to user memory that contains the new - * values in the elf_gregset_t format. */ - - xtensa_gregset_t format; - struct pt_regs *regs = task_pt_regs(child); - - if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){ - ret = -EFAULT; - break; - } - - /* FIXME: Perhaps we want some sanity checks on - * these user-space values? See ARM version. Are - * debuggers a security concern? */ - - do_restore_regs (&format, regs, child); - - ret = 0; - break; - } - - case PTRACE_GETFPREGS: - { - /* 'data' points to user memory in which to write. - * For convenience, we use the handy - * elf_fpregset_t format. */ - - elf_fpregset_t fpregs; - struct pt_regs *regs = task_pt_regs(child); - - do_save_fpregs (&fpregs, regs, child); - - /* Now, copy to user space nice and easy... */ - ret = 0; - if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t))) - ret = -EFAULT; - + ret = ptrace_setregs(child, (void __user *) data); break; - } - - case PTRACE_SETFPREGS: - { - /* 'data' points to user memory that contains the new - * values in the elf_fpregset_t format. - */ - elf_fpregset_t fpregs; - struct pt_regs *regs = task_pt_regs(child); - ret = 0; - if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) { - ret = -EFAULT; - break; - } - - if (do_restore_fpregs (&fpregs, regs, child)) - ret = -EIO; + case PTRACE_GETXTREGS: + ret = ptrace_getxregs(child, (void __user *) data); break; - } - case PTRACE_GETFPREGSIZE: - /* 'data' points to 'unsigned long' set to the size - * of elf_fpregset_t - */ - ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data); + case PTRACE_SETXTREGS: + ret = ptrace_setxregs(child, (void __user *) data); break; default: ret = ptrace_request(child, request, addr, data); - goto out; + break; } - out: + return ret; } diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 42d9fd8a4225..299be42d116b 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -35,13 +35,17 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); extern struct task_struct *coproc_owners[]; -extern void release_all_cp (struct task_struct *); - struct rt_sigframe { struct siginfo info; struct ucontext uc; - cp_state_t cpstate; + struct { + xtregs_opt_t opt; + xtregs_user_t user; +#if XTENSA_HAVE_COPROCESSORS + xtregs_coprocessor_t cp; +#endif + } xtregs; unsigned char retcode[6]; unsigned int window[4]; }; @@ -132,9 +136,10 @@ errout: */ static int -setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, - struct pt_regs *regs) +setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs) { + struct sigcontext __user *sc = &frame->uc.uc_mcontext; + struct thread_info *ti = current_thread_info(); int err = 0; #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) @@ -148,21 +153,32 @@ setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, err |= flush_window_regs_user(regs); err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); + err |= __put_user(0, &sc->sc_xtregs); - // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) + if (err) + return err; -#if XCHAL_HAVE_CP -# error Coprocessors unsupported - err |= save_cpextra(cpstate); - err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); +#if XTENSA_HAVE_COPROCESSORS + coprocessor_flush_all(ti); + coprocessor_release_all(ti); + err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp, + sizeof (frame->xtregs.cp)); #endif + err |= __copy_to_user(&frame->xtregs.opt, ®s->xtregs_opt, + sizeof (xtregs_opt_t)); + err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user, + sizeof (xtregs_user_t)); + + err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs); return err; } static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame) { + struct sigcontext __user *sc = &frame->uc.uc_mcontext; + struct thread_info *ti = current_thread_info(); unsigned int err = 0; unsigned long ps; @@ -180,6 +196,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) regs->windowbase = 0; regs->windowstart = 1; + regs->syscall = -1; /* disable syscall checks */ + /* For PS, restore only PS.CALLINC. * Assume that all other bits are either the same as for the signal * handler, or the user mode value doesn't matter (e.g. PS.OWB). @@ -195,8 +213,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); -#if XCHAL_HAVE_CP -# error Coprocessors unsupported + if (err) + return err; + /* The signal handler may have used coprocessors in which * case they are still enabled. We disable them to force a * reloading of the original task's CP state by the lazy @@ -204,20 +223,20 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) * Also, we essentially discard any coprocessor state that the * signal handler created. */ - if (!err) { - struct task_struct *tsk = current; - release_all_cp(tsk); - err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, - XTENSA_CP_EXTRA_SIZE); - } +#if XTENSA_HAVE_COPROCESSORS + coprocessor_release_all(ti); + err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp, + sizeof (frame->xtregs.cp)); #endif + err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user, + sizeof (xtregs_user_t)); + err |= __copy_from_user(®s->xtregs_opt, &frame->xtregs.opt, + sizeof (xtregs_opt_t)); - regs->syscall = -1; /* disable syscall checks */ return err; } - /* * Do a signal return; undo the signal stack. */ @@ -246,7 +265,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + if (restore_sigcontext(regs, frame)) goto badframe; ret = regs->areg[2]; @@ -359,7 +378,7 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(sas_ss_flags(regs->areg[1]), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, regs); + err |= setup_sigcontext(frame, regs); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 6f722f91ba92..c7a021d9f696 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -118,28 +118,28 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = { { EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault }, { EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault }, /* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */ -#if (XCHAL_CP_MASK & 1) +#if XTENSA_HAVE_COPROCESSOR(0) COPROCESSOR(0), #endif -#if (XCHAL_CP_MASK & 2) +#if XTENSA_HAVE_COPROCESSOR(1) COPROCESSOR(1), #endif -#if (XCHAL_CP_MASK & 4) +#if XTENSA_HAVE_COPROCESSOR(2) COPROCESSOR(2), #endif -#if (XCHAL_CP_MASK & 8) +#if XTENSA_HAVE_COPROCESSOR(3) COPROCESSOR(3), #endif -#if (XCHAL_CP_MASK & 16) +#if XTENSA_HAVE_COPROCESSOR(4) COPROCESSOR(4), #endif -#if (XCHAL_CP_MASK & 32) +#if XTENSA_HAVE_COPROCESSOR(5) COPROCESSOR(5), #endif -#if (XCHAL_CP_MASK & 64) +#if XTENSA_HAVE_COPROCESSOR(6) COPROCESSOR(6), #endif -#if (XCHAL_CP_MASK & 128) +#if XTENSA_HAVE_COPROCESSOR(7) COPROCESSOR(7), #endif { EXCCAUSE_MAPPED_DEBUG, 0, do_debug }, diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h index aa2121034558..e5849bb9f6cf 100644 --- a/include/asm-xtensa/coprocessor.h +++ b/include/asm-xtensa/coprocessor.h @@ -5,81 +5,168 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003 - 2005 Tensilica Inc. + * Copyright (C) 2003 - 2007 Tensilica Inc. */ + #ifndef _XTENSA_COPROCESSOR_H #define _XTENSA_COPROCESSOR_H -#include +#include #include +#include + +#ifdef __ASSEMBLY__ +# include + +.macro xchal_sa_start a b + .set .Lxchal_pofs_, 0 + .set .Lxchal_ofs_, 0 +.endm + +.macro xchal_sa_align ptr minofs maxofs ofsalign totalign + .set .Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ + \totalign - 1 + .set .Lxchal_ofs_, (.Lxchal_ofs_ & -\totalign) - .Lxchal_pofs_ +.endm + +#define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ + | XTHAL_SAS_CC \ + | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) + +.macro save_xtregs_opt ptr clb at1 at2 at3 at4 offset + .if XTREGS_OPT_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm + +.macro load_xtregs_opt ptr clb at1 at2 at3 at4 offset + .if XTREGS_OPT_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm +#undef _SELECT + +#define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ + | XTHAL_SAS_NOCC \ + | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) + +.macro save_xtregs_user ptr clb at1 at2 at3 at4 offset + .if XTREGS_USER_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm + +.macro load_xtregs_user ptr clb at1 at2 at3 at4 offset + .if XTREGS_USER_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm +#undef _SELECT + + + +#endif /* __ASSEMBLY__ */ -#if !XCHAL_HAVE_CP - -#define XTENSA_CP_EXTRA_OFFSET 0 -#define XTENSA_CP_EXTRA_ALIGN 1 /* must be a power of 2 */ -#define XTENSA_CP_EXTRA_SIZE 0 - -#else - -#define XTOFS(last_start,last_size,align) \ - ((last_start+last_size+align-1) & -align) - -#define XTENSA_CP_EXTRA_OFFSET 0 -#define XTENSA_CP_EXTRA_ALIGN XCHAL_EXTRA_SA_ALIGN - -#define XTENSA_CPE_CP0_OFFSET \ - XTOFS(XTENSA_CP_EXTRA_OFFSET, XCHAL_EXTRA_SA_SIZE, XCHAL_CP0_SA_ALIGN) -#define XTENSA_CPE_CP1_OFFSET \ - XTOFS(XTENSA_CPE_CP0_OFFSET, XCHAL_CP0_SA_SIZE, XCHAL_CP1_SA_ALIGN) -#define XTENSA_CPE_CP2_OFFSET \ - XTOFS(XTENSA_CPE_CP1_OFFSET, XCHAL_CP1_SA_SIZE, XCHAL_CP2_SA_ALIGN) -#define XTENSA_CPE_CP3_OFFSET \ - XTOFS(XTENSA_CPE_CP2_OFFSET, XCHAL_CP2_SA_SIZE, XCHAL_CP3_SA_ALIGN) -#define XTENSA_CPE_CP4_OFFSET \ - XTOFS(XTENSA_CPE_CP3_OFFSET, XCHAL_CP3_SA_SIZE, XCHAL_CP4_SA_ALIGN) -#define XTENSA_CPE_CP5_OFFSET \ - XTOFS(XTENSA_CPE_CP4_OFFSET, XCHAL_CP4_SA_SIZE, XCHAL_CP5_SA_ALIGN) -#define XTENSA_CPE_CP6_OFFSET \ - XTOFS(XTENSA_CPE_CP5_OFFSET, XCHAL_CP5_SA_SIZE, XCHAL_CP6_SA_ALIGN) -#define XTENSA_CPE_CP7_OFFSET \ - XTOFS(XTENSA_CPE_CP6_OFFSET, XCHAL_CP6_SA_SIZE, XCHAL_CP7_SA_ALIGN) -#define XTENSA_CP_EXTRA_SIZE \ - XTOFS(XTENSA_CPE_CP7_OFFSET, XCHAL_CP7_SA_SIZE, 16) - -#if XCHAL_CP_NUM > 0 -# ifndef __ASSEMBLY__ /* - * Tasks that own contents of (last user) each coprocessor. - * Entries are 0 for not-owned or non-existent coprocessors. - * Note: The size of this structure is fixed to 8 bytes in entry.S + * XTENSA_HAVE_COPROCESSOR(x) returns 1 if coprocessor x is configured. + * + * XTENSA_HAVE_IO_PORT(x) returns 1 if io-port x is configured. + * */ -typedef struct { - struct task_struct *owner; /* owner */ - int offset; /* offset in cpextra space. */ -} coprocessor_info_t; -# else -# define COPROCESSOR_INFO_OWNER 0 -# define COPROCESSOR_INFO_OFFSET 4 -# define COPROCESSOR_INFO_SIZE 8 -# endif -#endif -#endif /* XCHAL_HAVE_CP */ +#define XTENSA_HAVE_COPROCESSOR(x) \ + ((XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) & (1 << (x))) +#define XTENSA_HAVE_COPROCESSORS \ + (XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) +#define XTENSA_HAVE_IO_PORT(x) \ + (XCHAL_CP_PORT_MASK & (1 << (x))) +#define XTENSA_HAVE_IO_PORTS \ + XCHAL_CP_PORT_MASK #ifndef __ASSEMBLY__ -# if XCHAL_CP_NUM > 0 -struct task_struct; -extern void release_coprocessors (struct task_struct*); -extern void save_coprocessor_registers(void*, int); -# else -# define release_coprocessors(task) -# endif -typedef unsigned char cp_state_t[XTENSA_CP_EXTRA_SIZE] - __attribute__ ((aligned (XTENSA_CP_EXTRA_ALIGN))); -#endif /* !__ASSEMBLY__ */ +#if XCHAL_HAVE_CP +#define RSR_CPENABLE(x) do { \ + __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \ + } while(0); +#define WSR_CPENABLE(x) do { \ + __asm__ __volatile__("wsr %0," __stringify(CPENABLE) "; rsync" \ + :: "a" (x)); \ + } while(0); +#endif /* XCHAL_HAVE_CP */ + + +/* + * Additional registers. + * We define three types of additional registers: + * ext: extra registers that are used by the compiler + * cpn: optional registers that can be used by a user application + * cpX: coprocessor registers that can only be used if the corresponding + * CPENABLE bit is set. + */ + +#define XCHAL_SA_REG(list,compiler,x,type,y,name,z,align,size,...) \ + __REG ## list (compiler, type, name, size, align) + +#define __REG0(compiler,t,name,s,a) __REG0_ ## compiler (name) +#define __REG1(compiler,t,name,s,a) __REG1_ ## compiler (name) +#define __REG2(c,type,...) __REG2_ ## type (__VA_ARGS__) + +#define __REG0_0(name) +#define __REG0_1(name) __u32 name; +#define __REG1_0(name) __u32 name; +#define __REG1_1(name) +#define __REG2_0(n,s,a) __u32 name; +#define __REG2_1(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); +#define __REG2_2(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); + +typedef struct { XCHAL_NCP_SA_LIST(0) } xtregs_opt_t + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); +typedef struct { XCHAL_NCP_SA_LIST(1) } xtregs_user_t + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); + +#if XTENSA_HAVE_COPROCESSORS + +typedef struct { XCHAL_CP0_SA_LIST(2) } xtregs_cp0_t + __attribute__ ((aligned (XCHAL_CP0_SA_ALIGN))); +typedef struct { XCHAL_CP1_SA_LIST(2) } xtregs_cp1_t + __attribute__ ((aligned (XCHAL_CP1_SA_ALIGN))); +typedef struct { XCHAL_CP2_SA_LIST(2) } xtregs_cp2_t + __attribute__ ((aligned (XCHAL_CP2_SA_ALIGN))); +typedef struct { XCHAL_CP3_SA_LIST(2) } xtregs_cp3_t + __attribute__ ((aligned (XCHAL_CP3_SA_ALIGN))); +typedef struct { XCHAL_CP4_SA_LIST(2) } xtregs_cp4_t + __attribute__ ((aligned (XCHAL_CP4_SA_ALIGN))); +typedef struct { XCHAL_CP5_SA_LIST(2) } xtregs_cp5_t + __attribute__ ((aligned (XCHAL_CP5_SA_ALIGN))); +typedef struct { XCHAL_CP6_SA_LIST(2) } xtregs_cp6_t + __attribute__ ((aligned (XCHAL_CP6_SA_ALIGN))); +typedef struct { XCHAL_CP7_SA_LIST(2) } xtregs_cp7_t + __attribute__ ((aligned (XCHAL_CP7_SA_ALIGN))); + +extern struct thread_info* coprocessor_owner[XCHAL_CP_MAX]; +extern void coprocessor_save(void*, int); +extern void coprocessor_load(void*, int); +extern void coprocessor_flush(struct thread_info*, int); +extern void coprocessor_restore(struct thread_info*, int); + +extern void coprocessor_release_all(struct thread_info*); +extern void coprocessor_flush_all(struct thread_info*); + +static inline void coprocessor_clear_cpenable(void) +{ + unsigned long i = 0; + WSR_CPENABLE(i); +} + +#endif /* XTENSA_HAVE_COPROCESSORS */ + +#endif /* !__ASSEMBLY__ */ #endif /* _XTENSA_COPROCESSOR_H */ diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 86479b86c02e..11103e07d028 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -173,6 +173,21 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *); _r->areg[12]=0; _r->areg[13]=0; _r->areg[14]=0; _r->areg[15]=0; \ } while (0) +typedef struct { + xtregs_opt_t opt; + xtregs_user_t user; +#if XTENSA_HAVE_COPROCESSORS + xtregs_cp0_t cp0; + xtregs_cp1_t cp1; + xtregs_cp2_t cp2; + xtregs_cp3_t cp3; + xtregs_cp4_t cp4; + xtregs_cp5_t cp5; + xtregs_cp6_t cp6; + xtregs_cp7_t cp7; +#endif +} elf_xtregs_t; + #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) struct task_struct; diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h index 96408f436624..4918a4e96d42 100644 --- a/include/asm-xtensa/processor.h +++ b/include/asm-xtensa/processor.h @@ -103,10 +103,6 @@ struct thread_struct { unsigned long dbreaka[XCHAL_NUM_DBREAK]; unsigned long dbreakc[XCHAL_NUM_DBREAK]; - /* Allocate storage for extra state and coprocessor state. */ - unsigned char cp_save[XTENSA_CP_EXTRA_SIZE] - __attribute__ ((aligned(XTENSA_CP_EXTRA_ALIGN))); - /* Make structure 16 bytes aligned. */ int align[0] __attribute__ ((aligned(16))); }; @@ -162,21 +158,16 @@ struct thread_struct { struct task_struct; struct mm_struct; -// FIXME: do we need release_thread for CP?? /* Free all resources held by a thread. */ #define release_thread(thread) do { } while(0) -// FIXME: do we need prepare_to_copy (lazy status) for CP?? /* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) +extern void prepare_to_copy(struct task_struct*); -/* - * create a kernel thread without removing it from tasklists - */ +/* Create a kernel thread without removing it from tasklists */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ - #define copy_segments(p, mm) do { } while(0) #define release_segments(mm) do { } while(0) #define forget_segments() do { } while (0) diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h index 77ff02d307bb..422c73e26937 100644 --- a/include/asm-xtensa/ptrace.h +++ b/include/asm-xtensa/ptrace.h @@ -53,33 +53,30 @@ /* Registers used by strace */ -#define REG_A_BASE 0xfc000000 -#define REG_AR_BASE 0x04000000 -#define REG_PC 0x14000000 -#define REG_PS 0x080000e6 -#define REG_WB 0x08000048 -#define REG_WS 0x08000049 -#define REG_LBEG 0x08000000 -#define REG_LEND 0x08000001 -#define REG_LCOUNT 0x08000002 -#define REG_SAR 0x08000003 -#define REG_DEPC 0x080000c0 -#define REG_EXCCAUSE 0x080000e8 -#define REG_EXCVADDR 0x080000ee -#define SYSCALL_NR 0x1 - -#define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1) +#define REG_A_BASE 0x0000 +#define REG_AR_BASE 0x0100 +#define REG_PC 0x0020 +#define REG_PS 0x02e6 +#define REG_WB 0x0248 +#define REG_WS 0x0249 +#define REG_LBEG 0x0200 +#define REG_LEND 0x0201 +#define REG_LCOUNT 0x0202 +#define REG_SAR 0x0203 + +#define SYSCALL_NR 0x00ff /* Other PTRACE_ values defined in using values 0-9,16,17,24 */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 -#define PTRACE_GETFPREGS 14 -#define PTRACE_SETFPREGS 15 -#define PTRACE_GETFPREGSIZE 18 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETXTREGS 18 +#define PTRACE_SETXTREGS 19 #ifndef __ASSEMBLY__ +#ifdef __KERNEL__ + /* * This struct defines the way the registers are stored on the * kernel stack during a system call or other kernel entry. @@ -102,6 +99,9 @@ struct pt_regs { unsigned long icountlevel; /* 60 */ int reserved[1]; /* 64 */ + /* Additional configurable registers that are used by the compiler. */ + xtregs_opt_t xtregs_opt; + /* Make sure the areg field is 16 bytes aligned. */ int align[0] __attribute__ ((aligned(16))); @@ -111,8 +111,6 @@ struct pt_regs { unsigned long areg[16]; /* 128 (64) */ }; -#ifdef __KERNEL__ - #include # define task_pt_regs(tsk) ((struct pt_regs*) \ diff --git a/include/asm-xtensa/regs.h b/include/asm-xtensa/regs.h index c913d259faaa..d4baed246928 100644 --- a/include/asm-xtensa/regs.h +++ b/include/asm-xtensa/regs.h @@ -100,7 +100,14 @@ #define EXCCAUSE_DTLB_SIZE_RESTRICTION 27 #define EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 #define EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 -#define EXCCAUSE_FLOATING_POINT 40 +#define EXCCAUSE_COPROCESSOR0_DISABLED 32 +#define EXCCAUSE_COPROCESSOR1_DISABLED 33 +#define EXCCAUSE_COPROCESSOR2_DISABLED 34 +#define EXCCAUSE_COPROCESSOR3_DISABLED 35 +#define EXCCAUSE_COPROCESSOR4_DISABLED 36 +#define EXCCAUSE_COPROCESSOR5_DISABLED 37 +#define EXCCAUSE_COPROCESSOR6_DISABLED 38 +#define EXCCAUSE_COPROCESSOR7_DISABLED 39 /* PS register fields. */ diff --git a/include/asm-xtensa/sigcontext.h b/include/asm-xtensa/sigcontext.h index dff3c54a3c12..03383af8c3b7 100644 --- a/include/asm-xtensa/sigcontext.h +++ b/include/asm-xtensa/sigcontext.h @@ -22,6 +22,7 @@ struct sigcontext { unsigned long sc_acclo; unsigned long sc_acchi; unsigned long sc_a[16]; + void *sc_xtregs; }; #endif /* _XTENSA_SIGCONTEXT_H */ diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h index e0cb9116d8ab..62b1e8f3c13c 100644 --- a/include/asm-xtensa/system.h +++ b/include/asm-xtensa/system.h @@ -46,42 +46,6 @@ static inline int irqs_disabled(void) return flags & 0xf; } -#define RSR_CPENABLE(x) do { \ - __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \ - } while(0); -#define WSR_CPENABLE(x) do { \ - __asm__ __volatile__("wsr %0," __stringify(CPENABLE)";rsync" \ - :: "a" (x));} while(0); - -#define clear_cpenable() __clear_cpenable() - -static inline void __clear_cpenable(void) -{ -#if XCHAL_HAVE_CP - unsigned long i = 0; - WSR_CPENABLE(i); -#endif -} - -static inline void enable_coprocessor(int i) -{ -#if XCHAL_HAVE_CP - int cp; - RSR_CPENABLE(cp); - cp |= 1 << i; - WSR_CPENABLE(cp); -#endif -} - -static inline void disable_coprocessor(int i) -{ -#if XCHAL_HAVE_CP - int cp; - RSR_CPENABLE(cp); - cp &= ~(1 << i); - WSR_CPENABLE(cp); -#endif -} #define smp_read_barrier_depends() do { } while(0) #define read_barrier_depends() do { } while(0) @@ -111,7 +75,6 @@ extern void *_switch_to(void *last, void *next); #define switch_to(prev,next,last) \ do { \ - clear_cpenable(); \ (last) = _switch_to(prev, next); \ } while(0) @@ -244,7 +207,7 @@ static inline void spill_registers(void) "wsr a13," __stringify(SAR) "\n\t" "wsr a14," __stringify(PS) "\n\t" :: "a" (&a0), "a" (&ps) - : "a2", "a3", "a12", "a13", "a14", "a15", "memory"); + : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory"); } #define arch_align_stack(x) (x) diff --git a/include/asm-xtensa/thread_info.h b/include/asm-xtensa/thread_info.h index 52c958285bcb..a2c640682ed9 100644 --- a/include/asm-xtensa/thread_info.h +++ b/include/asm-xtensa/thread_info.h @@ -27,6 +27,21 @@ #ifndef __ASSEMBLY__ +#if XTENSA_HAVE_COPROCESSORS + +typedef struct xtregs_coprocessor { + xtregs_cp0_t cp0; + xtregs_cp1_t cp1; + xtregs_cp2_t cp2; + xtregs_cp3_t cp3; + xtregs_cp4_t cp4; + xtregs_cp5_t cp5; + xtregs_cp6_t cp6; + xtregs_cp7_t cp7; +} xtregs_coprocessor_t; + +#endif + struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ @@ -38,7 +53,13 @@ struct thread_info { mm_segment_t addr_limit; /* thread address space */ struct restart_block restart_block; + unsigned long cpenable; + /* Allocate storage for extra user states and coprocessor states. */ +#if XTENSA_HAVE_COPROCESSORS + xtregs_coprocessor_t xtregs_cp; +#endif + xtregs_user_t xtregs_user; }; #else /* !__ASSEMBLY__ */ diff --git a/include/asm-xtensa/variant-fsf/tie-asm.h b/include/asm-xtensa/variant-fsf/tie-asm.h new file mode 100644 index 000000000000..68a73bf4ffc5 --- /dev/null +++ b/include/asm-xtensa/variant-fsf/tie-asm.h @@ -0,0 +1,70 @@ +/* + * This header file contains assembly-language definitions (assembly + * macros, etc.) for this specific Xtensa processor's TIE extensions + * and options. It is customized to this Xtensa processor configuration. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999-2008 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ + + + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + rur \at1, THREADPTR // threadptr option + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_store + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + wur \at1, THREADPTR // threadptr option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_load + + + +#define XCHAL_NCP_NUM_ATMPS 1 + + +#define XCHAL_SA_NUM_ATMPS 1 + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/include/asm-xtensa/variant-fsf/tie.h b/include/asm-xtensa/variant-fsf/tie.h index a73c71664918..bf4020116df5 100644 --- a/include/asm-xtensa/variant-fsf/tie.h +++ b/include/asm-xtensa/variant-fsf/tie.h @@ -1,22 +1,77 @@ /* - * Xtensa processor core configuration information. + * This header file describes this specific Xtensa processor's TIE extensions + * that extend basic Xtensa core functionality. It is customized to this + * Xtensa processor configuration. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999-2006 Tensilica Inc. + * Copyright (C) 1999-2007 Tensilica Inc. */ -#ifndef XTENSA_TIE_H -#define XTENSA_TIE_H - -/*---------------------------------------------------------------------- - COPROCESSORS and EXTRA STATE - ----------------------------------------------------------------------*/ +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H #define XCHAL_CP_NUM 0 /* number of coprocessors */ -#define XCHAL_CP_MASK 0x00 +#define XCHAL_CP_MAX 0 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP7_NAME "XTIOP" +#define XCHAL_CP7_IDENT XTIOP +#define XCHAL_CP7_SA_SIZE 0 /* size of state save area */ +#define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */ +#define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_NCP_SA_SIZE 0 +#define XCHAL_NCP_SA_ALIGN 1 +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP1_SA_SIZE 0 +#define XCHAL_CP1_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 0 +#define XCHAL_NCP_SA_ALIGN 1 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 0 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 1 /* actual minimum alignment */ + +#define XCHAL_NCP_SA_NUM 0 +#define XCHAL_NCP_SA_LIST(s) +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) +#define XCHAL_CP1_SA_NUM 0 +#define XCHAL_CP1_SA_LIST(s) +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3 -#endif /*XTENSA_CONFIG_TIE_H*/ +#endif /*_XTENSA_CORE_TIE_H*/ -- cgit v1.2.3 From 679262578ba975037901556b2ddc6b17a77cf671 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Tue, 15 Jan 2008 09:49:18 -0800 Subject: [XTENSA] Exclude thread-global registers from the xtregs structures. Signed-off-by: Chris Zankel --- include/asm-xtensa/coprocessor.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h index e5849bb9f6cf..1cbcf9001a41 100644 --- a/include/asm-xtensa/coprocessor.h +++ b/include/asm-xtensa/coprocessor.h @@ -31,7 +31,7 @@ #define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ | XTHAL_SAS_CC \ - | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) + | XTHAL_SAS_CALR | XTHAL_SAS_CALE ) .macro save_xtregs_opt ptr clb at1 at2 at3 at4 offset .if XTREGS_OPT_SIZE > 0 @@ -112,17 +112,22 @@ * CPENABLE bit is set. */ -#define XCHAL_SA_REG(list,compiler,x,type,y,name,z,align,size,...) \ - __REG ## list (compiler, type, name, size, align) +#define XCHAL_SA_REG(list,cc,abi,type,y,name,z,align,size,...) \ + __REG ## list (cc, abi, type, name, size, align) + +#define __REG0(cc,abi,t,name,s,a) __REG0_ ## cc (abi,name) +#define __REG1(cc,abi,t,name,s,a) __REG1_ ## cc (name) +#define __REG2(cc,abi,type,...) __REG2_ ## type (__VA_ARGS__) -#define __REG0(compiler,t,name,s,a) __REG0_ ## compiler (name) -#define __REG1(compiler,t,name,s,a) __REG1_ ## compiler (name) -#define __REG2(c,type,...) __REG2_ ## type (__VA_ARGS__) +#define __REG0_0(abi,name) +#define __REG0_1(abi,name) __REG0_1 ## abi (name) +#define __REG0_10(name) __u32 name; +#define __REG0_11(name) __u32 name; +#define __REG0_12(name) -#define __REG0_0(name) -#define __REG0_1(name) __u32 name; #define __REG1_0(name) __u32 name; #define __REG1_1(name) + #define __REG2_0(n,s,a) __u32 name; #define __REG2_1(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); #define __REG2_2(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); -- cgit v1.2.3 From 9f8fcf38e8928cccf8c7b32668d146e457f2ccf2 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Fri, 18 Jan 2008 16:15:29 -0800 Subject: [XTENSA] Fix cache flush macro for D$/I$ aliasing/non-aliasing For configurations that have aliasing in the data cache but not in the instruction cache, we don't need to flush the instruction cache. Thus, we didn't define the macros to flush the instruction cache. Some cache-flush functions, howerver, were using those macros. Signed-off-by: Chris Zankel --- include/asm-xtensa/cacheflush.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h index b773c57e75a5..94c4c53a099e 100644 --- a/include/asm-xtensa/cacheflush.h +++ b/include/asm-xtensa/cacheflush.h @@ -70,6 +70,8 @@ extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long); #endif #if (ICACHE_WAY_SIZE > PAGE_SIZE) extern void __invalidate_icache_page_alias(unsigned long, unsigned long); +#else +# define __invalidate_icache_page_alias(v,p) do { } while(0) #endif /* -- cgit v1.2.3 From 42086cec3263b8c015ca3faa01e8190f0e3ff445 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Mon, 28 Jan 2008 15:55:01 -0800 Subject: [XTENSA] Allow debugger to modify the WINDOWBASE register. For the 'return' command, GDB needs to adjust WINDOWBASE. In case WB is different from 0, we need to rotate the window register file and update WINDOWSTART and WMASK. This patch also removes some ret|= statements for __get_user/__put_user as the address range was alrady checked a couple of lines earlier. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/ptrace.c | 66 ++++++++++++++++++++++++--------------------- include/asm-xtensa/elf.h | 3 ++- 2 files changed, 37 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index f6669d605125..9486882ef0af 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -43,32 +43,29 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs) { struct pt_regs *regs = task_pt_regs(child); xtensa_gregset_t __user *gregset = uregs; - unsigned long wb = regs->windowbase; - unsigned long ws = regs->windowstart; unsigned long wm = regs->wmask; - int ret = 0; - int live, last; + unsigned long wb = regs->windowbase; + int live, i; if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; - /* Norm windowstart to a windowbase of 0. */ - - ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<pc, &gregset->pc); - ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); - ret |= __put_user(regs->lbeg, &gregset->lbeg); - ret |= __put_user(regs->lend, &gregset->lend); - ret |= __put_user(regs->lcount, &gregset->lcount); - ret |= __put_user(ws, &gregset->windowstart); + __put_user(regs->pc, &gregset->pc); + __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); + __put_user(regs->lbeg, &gregset->lbeg); + __put_user(regs->lend, &gregset->lend); + __put_user(regs->lcount, &gregset->lcount); + __put_user(regs->windowstart, &gregset->windowstart); + __put_user(regs->windowbase, &gregset->windowbase); live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; - last = XCHAL_NUM_AREGS - (wm >> 4) * 4; - ret |= __copy_to_user(gregset->a, regs->areg, live * 4); - ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16); - return ret ? -EFAULT : 0; + for (i = 0; i < live; i++) + __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); + for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++) + __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); + + return 0; } int ptrace_setregs(struct task_struct *child, void __user *uregs) @@ -76,28 +73,35 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) struct pt_regs *regs = task_pt_regs(child); xtensa_gregset_t *gregset = uregs; const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; - unsigned long wm = regs->wmask; unsigned long ps; - int ret = 0; - int live, last; + unsigned long wb; if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; - ret |= __get_user(regs->pc, &gregset->pc); - ret |= __get_user(ps, &gregset->ps); - ret |= __get_user(regs->lbeg, &gregset->lbeg); - ret |= __get_user(regs->lend, &gregset->lend); - ret |= __get_user(regs->lcount, &gregset->lcount); + __get_user(regs->pc, &gregset->pc); + __get_user(ps, &gregset->ps); + __get_user(regs->lbeg, &gregset->lbeg); + __get_user(regs->lend, &gregset->lend); + __get_user(regs->lcount, &gregset->lcount); + __get_user(regs->windowstart, &gregset->windowstart); + __get_user(wb, &gregset->windowbase); regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); - live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; - last = XCHAL_NUM_AREGS - (wm >> 4) * 4; - ret |= __copy_from_user(regs->areg, gregset->a, live * 4); - ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16); + if (wb >= XCHAL_NUM_AREGS / 4) + return -EFAULT; - return ret ? -EFAULT : 0; + regs->windowbase = wb; + + if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, + gregset->a, wb * 16)) + return -EFAULT; + + if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) + return -EFAULT; + + return 0; } diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 11103e07d028..ca6e5101a2cb 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -82,7 +82,8 @@ typedef struct { elf_greg_t lcount; elf_greg_t sar; elf_greg_t windowstart; - elf_greg_t reserved[9+48]; + elf_greg_t windowbase; + elf_greg_t reserved[8+48]; elf_greg_t a[64]; } xtensa_gregset_t; -- cgit v1.2.3