diff options
| -rw-r--r-- | arch/xtensa/include/asm/elf.h | 3 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/ptrace.h | 3 | ||||
| -rw-r--r-- | arch/xtensa/kernel/asm-offsets.c | 1 | ||||
| -rw-r--r-- | arch/xtensa/kernel/entry.S | 12 | ||||
| -rw-r--r-- | arch/xtensa/kernel/process.c | 5 | ||||
| -rw-r--r-- | arch/xtensa/kernel/ptrace.c | 2 | ||||
| -rw-r--r-- | arch/xtensa/kernel/signal.c | 6 |
7 files changed, 25 insertions, 7 deletions
diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h index 264d5fa450d8..eacb25a41718 100644 --- a/arch/xtensa/include/asm/elf.h +++ b/arch/xtensa/include/asm/elf.h | |||
| @@ -84,7 +84,8 @@ typedef struct { | |||
| 84 | elf_greg_t sar; | 84 | elf_greg_t sar; |
| 85 | elf_greg_t windowstart; | 85 | elf_greg_t windowstart; |
| 86 | elf_greg_t windowbase; | 86 | elf_greg_t windowbase; |
| 87 | elf_greg_t reserved[8+48]; | 87 | elf_greg_t threadptr; |
| 88 | elf_greg_t reserved[7+48]; | ||
| 88 | elf_greg_t a[64]; | 89 | elf_greg_t a[64]; |
| 89 | } xtensa_gregset_t; | 90 | } xtensa_gregset_t; |
| 90 | 91 | ||
diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h index 682b1deac1f2..81f31bc9dde0 100644 --- a/arch/xtensa/include/asm/ptrace.h +++ b/arch/xtensa/include/asm/ptrace.h | |||
| @@ -38,6 +38,7 @@ struct pt_regs { | |||
| 38 | unsigned long syscall; /* 56 */ | 38 | unsigned long syscall; /* 56 */ |
| 39 | unsigned long icountlevel; /* 60 */ | 39 | unsigned long icountlevel; /* 60 */ |
| 40 | unsigned long scompare1; /* 64 */ | 40 | unsigned long scompare1; /* 64 */ |
| 41 | unsigned long threadptr; /* 68 */ | ||
| 41 | 42 | ||
| 42 | /* Additional configurable registers that are used by the compiler. */ | 43 | /* Additional configurable registers that are used by the compiler. */ |
| 43 | xtregs_opt_t xtregs_opt; | 44 | xtregs_opt_t xtregs_opt; |
| @@ -48,7 +49,7 @@ struct pt_regs { | |||
| 48 | /* current register frame. | 49 | /* current register frame. |
| 49 | * Note: The ESF for kernel exceptions ends after 16 registers! | 50 | * Note: The ESF for kernel exceptions ends after 16 registers! |
| 50 | */ | 51 | */ |
| 51 | unsigned long areg[16]; /* 128 (64) */ | 52 | unsigned long areg[16]; |
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | #include <variant/core.h> | 55 | #include <variant/core.h> |
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 0701fad170db..1915c7c889ba 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c | |||
| @@ -42,6 +42,7 @@ int main(void) | |||
| 42 | DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); | 42 | DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); |
| 43 | DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); | 43 | DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); |
| 44 | DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1)); | 44 | DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1)); |
| 45 | DEFINE(PT_THREADPTR, offsetof(struct pt_regs, threadptr)); | ||
| 45 | DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); | 46 | DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); |
| 46 | DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); | 47 | DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); |
| 47 | DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1])); | 48 | DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1])); |
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 70d5a9e33573..63845f950792 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
| @@ -130,6 +130,11 @@ _user_exception: | |||
| 130 | s32i a3, a1, PT_SAR | 130 | s32i a3, a1, PT_SAR |
| 131 | s32i a2, a1, PT_ICOUNTLEVEL | 131 | s32i a2, a1, PT_ICOUNTLEVEL |
| 132 | 132 | ||
| 133 | #if XCHAL_HAVE_THREADPTR | ||
| 134 | rur a2, threadptr | ||
| 135 | s32i a2, a1, PT_THREADPTR | ||
| 136 | #endif | ||
| 137 | |||
| 133 | /* Rotate ws so that the current windowbase is at bit0. */ | 138 | /* Rotate ws so that the current windowbase is at bit0. */ |
| 134 | /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ | 139 | /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ |
| 135 | 140 | ||
| @@ -510,6 +515,11 @@ user_exception_exit: | |||
| 510 | * (if we have restored WSBITS-1 frames). | 515 | * (if we have restored WSBITS-1 frames). |
| 511 | */ | 516 | */ |
| 512 | 517 | ||
| 518 | #if XCHAL_HAVE_THREADPTR | ||
| 519 | l32i a3, a1, PT_THREADPTR | ||
| 520 | wur a3, threadptr | ||
| 521 | #endif | ||
| 522 | |||
| 513 | 2: j common_exception_exit | 523 | 2: j common_exception_exit |
| 514 | 524 | ||
| 515 | /* This is the kernel exception exit. | 525 | /* This is the kernel exception exit. |
| @@ -1955,7 +1965,7 @@ ENTRY(_switch_to) | |||
| 1955 | s32i a6, a3, EXC_TABLE_FIXUP | 1965 | s32i a6, a3, EXC_TABLE_FIXUP |
| 1956 | s32i a7, a3, EXC_TABLE_KSTK | 1966 | s32i a7, a3, EXC_TABLE_KSTK |
| 1957 | 1967 | ||
| 1958 | /* restore context of the task that 'next' addresses */ | 1968 | /* restore context of the task 'next' */ |
| 1959 | 1969 | ||
| 1960 | l32i a0, a13, THREAD_RA # restore return address | 1970 | l32i a0, a13, THREAD_RA # restore return address |
| 1961 | l32i a1, a13, THREAD_SP # restore stack pointer | 1971 | l32i a1, a13, THREAD_SP # restore stack pointer |
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 0dd5784416d3..5cd82e9f601c 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c | |||
| @@ -259,9 +259,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn, | |||
| 259 | memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], | 259 | memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], |
| 260 | ®s->areg[XCHAL_NUM_AREGS - len/4], len); | 260 | ®s->areg[XCHAL_NUM_AREGS - len/4], len); |
| 261 | } | 261 | } |
| 262 | // FIXME: we need to set THREADPTR in thread_info... | 262 | |
| 263 | /* The thread pointer is passed in the '4th argument' (= a5) */ | ||
| 263 | if (clone_flags & CLONE_SETTLS) | 264 | if (clone_flags & CLONE_SETTLS) |
| 264 | childregs->areg[2] = childregs->areg[6]; | 265 | childregs->threadptr = childregs->areg[5]; |
| 265 | } else { | 266 | } else { |
| 266 | p->thread.ra = MAKE_RA_FOR_CALL( | 267 | p->thread.ra = MAKE_RA_FOR_CALL( |
| 267 | (unsigned long)ret_from_kernel_thread, 1); | 268 | (unsigned long)ret_from_kernel_thread, 1); |
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index a8b0d5795571..562fac664751 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c | |||
| @@ -66,6 +66,7 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs) | |||
| 66 | __put_user(regs->lcount, &gregset->lcount); | 66 | __put_user(regs->lcount, &gregset->lcount); |
| 67 | __put_user(regs->windowstart, &gregset->windowstart); | 67 | __put_user(regs->windowstart, &gregset->windowstart); |
| 68 | __put_user(regs->windowbase, &gregset->windowbase); | 68 | __put_user(regs->windowbase, &gregset->windowbase); |
| 69 | __put_user(regs->threadptr, &gregset->threadptr); | ||
| 69 | 70 | ||
| 70 | for (i = 0; i < XCHAL_NUM_AREGS; i++) | 71 | for (i = 0; i < XCHAL_NUM_AREGS; i++) |
| 71 | __put_user(regs->areg[i], | 72 | __put_user(regs->areg[i], |
| @@ -92,6 +93,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) | |||
| 92 | __get_user(regs->lcount, &gregset->lcount); | 93 | __get_user(regs->lcount, &gregset->lcount); |
| 93 | __get_user(ws, &gregset->windowstart); | 94 | __get_user(ws, &gregset->windowstart); |
| 94 | __get_user(wb, &gregset->windowbase); | 95 | __get_user(wb, &gregset->windowbase); |
| 96 | __get_user(regs->threadptr, &gregset->threadptr); | ||
| 95 | 97 | ||
| 96 | regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); | 98 | regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); |
| 97 | 99 | ||
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index de34d6be91cd..6952d8959236 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c | |||
| @@ -337,7 +337,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 337 | struct rt_sigframe *frame; | 337 | struct rt_sigframe *frame; |
| 338 | int err = 0; | 338 | int err = 0; |
| 339 | int signal; | 339 | int signal; |
| 340 | unsigned long sp, ra; | 340 | unsigned long sp, ra, tp; |
| 341 | 341 | ||
| 342 | sp = regs->areg[1]; | 342 | sp = regs->areg[1]; |
| 343 | 343 | ||
| @@ -395,7 +395,8 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 395 | * Return context not modified until this point. | 395 | * Return context not modified until this point. |
| 396 | */ | 396 | */ |
| 397 | 397 | ||
| 398 | /* Set up registers for signal handler */ | 398 | /* Set up registers for signal handler; preserve the threadptr */ |
| 399 | tp = regs->threadptr; | ||
| 399 | start_thread(regs, (unsigned long) ka->sa.sa_handler, | 400 | start_thread(regs, (unsigned long) ka->sa.sa_handler, |
| 400 | (unsigned long) frame); | 401 | (unsigned long) frame); |
| 401 | 402 | ||
| @@ -406,6 +407,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 406 | regs->areg[6] = (unsigned long) signal; | 407 | regs->areg[6] = (unsigned long) signal; |
| 407 | regs->areg[7] = (unsigned long) &frame->info; | 408 | regs->areg[7] = (unsigned long) &frame->info; |
| 408 | regs->areg[8] = (unsigned long) &frame->uc; | 409 | regs->areg[8] = (unsigned long) &frame->uc; |
| 410 | regs->threadptr = tp; | ||
| 409 | 411 | ||
| 410 | /* Set access mode to USER_DS. Nomenclature is outdated, but | 412 | /* Set access mode to USER_DS. Nomenclature is outdated, but |
| 411 | * functionality is used in uaccess.h | 413 | * functionality is used in uaccess.h |
