Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull sparc fixes from David Miller: "sparc64 mmu context allocation and trap return bug fixes" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc64: Fix return from trap window fill crashes. sparc: Harden signal return frame checks. sparc64: Take ctx_alloc_lock properly in hugetlb_setup().
This commit is contained in:
Коммит
58c1f9950f
|
@ -15,6 +15,10 @@
|
||||||
|
|
||||||
#define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ)
|
#define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ)
|
||||||
|
|
||||||
|
#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
|
||||||
|
#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
|
||||||
|
#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
|
||||||
|
|
||||||
#define __CHEETAH_ID 0x003e0014
|
#define __CHEETAH_ID 0x003e0014
|
||||||
#define __JALAPENO_ID 0x003e0016
|
#define __JALAPENO_ID 0x003e0016
|
||||||
#define __SERRANO_ID 0x003e0022
|
#define __SERRANO_ID 0x003e0022
|
||||||
|
|
|
@ -589,8 +589,8 @@ user_rtt_fill_64bit: \
|
||||||
restored; \
|
restored; \
|
||||||
nop; nop; nop; nop; nop; nop; \
|
nop; nop; nop; nop; nop; nop; \
|
||||||
nop; nop; nop; nop; nop; \
|
nop; nop; nop; nop; nop; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup; \
|
ba,a,pt %xcc, user_rtt_fill_fixup_dax; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup; \
|
ba,a,pt %xcc, user_rtt_fill_fixup_mna; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup;
|
ba,a,pt %xcc, user_rtt_fill_fixup;
|
||||||
|
|
||||||
|
|
||||||
|
@ -652,8 +652,8 @@ user_rtt_fill_32bit: \
|
||||||
restored; \
|
restored; \
|
||||||
nop; nop; nop; nop; nop; \
|
nop; nop; nop; nop; nop; \
|
||||||
nop; nop; nop; \
|
nop; nop; nop; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup; \
|
ba,a,pt %xcc, user_rtt_fill_fixup_dax; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup; \
|
ba,a,pt %xcc, user_rtt_fill_fixup_mna; \
|
||||||
ba,a,pt %xcc, user_rtt_fill_fixup;
|
ba,a,pt %xcc, user_rtt_fill_fixup;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ CFLAGS_REMOVE_perf_event.o := -pg
|
||||||
CFLAGS_REMOVE_pcr.o := -pg
|
CFLAGS_REMOVE_pcr.o := -pg
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
obj-$(CONFIG_SPARC64) += urtt_fill.o
|
||||||
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
|
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
|
||||||
obj-$(CONFIG_SPARC32) += etrap_32.o
|
obj-$(CONFIG_SPARC32) += etrap_32.o
|
||||||
obj-$(CONFIG_SPARC32) += rtrap_32.o
|
obj-$(CONFIG_SPARC32) += rtrap_32.o
|
||||||
|
|
|
@ -14,10 +14,6 @@
|
||||||
#include <asm/visasm.h>
|
#include <asm/visasm.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
|
||||||
#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
|
|
||||||
#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
|
|
||||||
#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
|
|
||||||
|
|
||||||
#ifdef CONFIG_CONTEXT_TRACKING
|
#ifdef CONFIG_CONTEXT_TRACKING
|
||||||
# define SCHEDULE_USER schedule_user
|
# define SCHEDULE_USER schedule_user
|
||||||
#else
|
#else
|
||||||
|
@ -242,52 +238,17 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
|
||||||
wrpr %g1, %cwp
|
wrpr %g1, %cwp
|
||||||
ba,a,pt %xcc, user_rtt_fill_64bit
|
ba,a,pt %xcc, user_rtt_fill_64bit
|
||||||
|
|
||||||
|
user_rtt_fill_fixup_dax:
|
||||||
|
ba,pt %xcc, user_rtt_fill_fixup_common
|
||||||
|
mov 1, %g3
|
||||||
|
|
||||||
|
user_rtt_fill_fixup_mna:
|
||||||
|
ba,pt %xcc, user_rtt_fill_fixup_common
|
||||||
|
mov 2, %g3
|
||||||
|
|
||||||
user_rtt_fill_fixup:
|
user_rtt_fill_fixup:
|
||||||
rdpr %cwp, %g1
|
ba,pt %xcc, user_rtt_fill_fixup_common
|
||||||
add %g1, 1, %g1
|
clr %g3
|
||||||
wrpr %g1, 0x0, %cwp
|
|
||||||
|
|
||||||
rdpr %wstate, %g2
|
|
||||||
sll %g2, 3, %g2
|
|
||||||
wrpr %g2, 0x0, %wstate
|
|
||||||
|
|
||||||
/* We know %canrestore and %otherwin are both zero. */
|
|
||||||
|
|
||||||
sethi %hi(sparc64_kern_pri_context), %g2
|
|
||||||
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2
|
|
||||||
mov PRIMARY_CONTEXT, %g1
|
|
||||||
|
|
||||||
661: stxa %g2, [%g1] ASI_DMMU
|
|
||||||
.section .sun4v_1insn_patch, "ax"
|
|
||||||
.word 661b
|
|
||||||
stxa %g2, [%g1] ASI_MMU
|
|
||||||
.previous
|
|
||||||
|
|
||||||
sethi %hi(KERNBASE), %g1
|
|
||||||
flush %g1
|
|
||||||
|
|
||||||
or %g4, FAULT_CODE_WINFIXUP, %g4
|
|
||||||
stb %g4, [%g6 + TI_FAULT_CODE]
|
|
||||||
stx %g5, [%g6 + TI_FAULT_ADDR]
|
|
||||||
|
|
||||||
mov %g6, %l1
|
|
||||||
wrpr %g0, 0x0, %tl
|
|
||||||
|
|
||||||
661: nop
|
|
||||||
.section .sun4v_1insn_patch, "ax"
|
|
||||||
.word 661b
|
|
||||||
SET_GL(0)
|
|
||||||
.previous
|
|
||||||
|
|
||||||
wrpr %g0, RTRAP_PSTATE, %pstate
|
|
||||||
|
|
||||||
mov %l1, %g6
|
|
||||||
ldx [%g6 + TI_TASK], %g4
|
|
||||||
LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
|
|
||||||
call do_sparc64_fault
|
|
||||||
add %sp, PTREGS_OFF, %o0
|
|
||||||
ba,pt %xcc, rtrap
|
|
||||||
nop
|
|
||||||
|
|
||||||
user_rtt_pre_restore:
|
user_rtt_pre_restore:
|
||||||
add %g1, 1, %g1
|
add %g1, 1, %g1
|
||||||
|
|
|
@ -138,12 +138,24 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Checks if the fp is valid. We always build signal frames which are
|
||||||
|
* 16-byte aligned, therefore we can always enforce that the restore
|
||||||
|
* frame has that property as well.
|
||||||
|
*/
|
||||||
|
static bool invalid_frame_pointer(void __user *fp, int fplen)
|
||||||
|
{
|
||||||
|
if ((((unsigned long) fp) & 15) ||
|
||||||
|
((unsigned long)fp) > 0x100000000ULL - fplen)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void do_sigreturn32(struct pt_regs *regs)
|
void do_sigreturn32(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct signal_frame32 __user *sf;
|
struct signal_frame32 __user *sf;
|
||||||
compat_uptr_t fpu_save;
|
compat_uptr_t fpu_save;
|
||||||
compat_uptr_t rwin_save;
|
compat_uptr_t rwin_save;
|
||||||
unsigned int psr;
|
unsigned int psr, ufp;
|
||||||
unsigned int pc, npc;
|
unsigned int pc, npc;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
compat_sigset_t seta;
|
compat_sigset_t seta;
|
||||||
|
@ -158,11 +170,16 @@ void do_sigreturn32(struct pt_regs *regs)
|
||||||
sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
|
sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
|
||||||
|
|
||||||
/* 1. Make sure we are not getting garbage from the user */
|
/* 1. Make sure we are not getting garbage from the user */
|
||||||
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
|
if (invalid_frame_pointer(sf, sizeof(*sf)))
|
||||||
(((unsigned long) sf) & 3))
|
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
if (get_user(pc, &sf->info.si_regs.pc) ||
|
if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if (ufp & 0x7)
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if (__get_user(pc, &sf->info.si_regs.pc) ||
|
||||||
__get_user(npc, &sf->info.si_regs.npc))
|
__get_user(npc, &sf->info.si_regs.npc))
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
|
@ -227,7 +244,7 @@ segv:
|
||||||
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame32 __user *sf;
|
struct rt_signal_frame32 __user *sf;
|
||||||
unsigned int psr, pc, npc;
|
unsigned int psr, pc, npc, ufp;
|
||||||
compat_uptr_t fpu_save;
|
compat_uptr_t fpu_save;
|
||||||
compat_uptr_t rwin_save;
|
compat_uptr_t rwin_save;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
@ -242,11 +259,16 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||||
sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
|
sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
|
||||||
|
|
||||||
/* 1. Make sure we are not getting garbage from the user */
|
/* 1. Make sure we are not getting garbage from the user */
|
||||||
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
|
if (invalid_frame_pointer(sf, sizeof(*sf)))
|
||||||
(((unsigned long) sf) & 3))
|
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
if (get_user(pc, &sf->regs.pc) ||
|
if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if (ufp & 0x7)
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if (__get_user(pc, &sf->regs.pc) ||
|
||||||
__get_user(npc, &sf->regs.npc))
|
__get_user(npc, &sf->regs.npc))
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
|
@ -307,14 +329,6 @@ segv:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the fp is valid */
|
|
||||||
static int invalid_frame_pointer(void __user *fp, int fplen)
|
|
||||||
{
|
|
||||||
if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
||||||
{
|
{
|
||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
|
|
|
@ -60,10 +60,22 @@ struct rt_signal_frame {
|
||||||
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
|
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
|
||||||
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
|
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
|
||||||
|
|
||||||
|
/* Checks if the fp is valid. We always build signal frames which are
|
||||||
|
* 16-byte aligned, therefore we can always enforce that the restore
|
||||||
|
* frame has that property as well.
|
||||||
|
*/
|
||||||
|
static inline bool invalid_frame_pointer(void __user *fp, int fplen)
|
||||||
|
{
|
||||||
|
if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
asmlinkage void do_sigreturn(struct pt_regs *regs)
|
asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
unsigned long up_psr, pc, npc, ufp;
|
||||||
struct signal_frame __user *sf;
|
struct signal_frame __user *sf;
|
||||||
unsigned long up_psr, pc, npc;
|
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
__siginfo_rwin_t __user *rwin_save;
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
|
@ -77,10 +89,13 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||||
sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
|
sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
|
||||||
|
|
||||||
/* 1. Make sure we are not getting garbage from the user */
|
/* 1. Make sure we are not getting garbage from the user */
|
||||||
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
|
if (!invalid_frame_pointer(sf, sizeof(*sf)))
|
||||||
goto segv_and_exit;
|
goto segv_and_exit;
|
||||||
|
|
||||||
if (((unsigned long) sf) & 3)
|
if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
|
||||||
|
goto segv_and_exit;
|
||||||
|
|
||||||
|
if (ufp & 0x7)
|
||||||
goto segv_and_exit;
|
goto segv_and_exit;
|
||||||
|
|
||||||
err = __get_user(pc, &sf->info.si_regs.pc);
|
err = __get_user(pc, &sf->info.si_regs.pc);
|
||||||
|
@ -127,7 +142,7 @@ segv_and_exit:
|
||||||
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
unsigned int psr, pc, npc;
|
unsigned int psr, pc, npc, ufp;
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
__siginfo_rwin_t __user *rwin_save;
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
@ -135,8 +150,13 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||||
|
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
|
sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
|
||||||
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
|
if (!invalid_frame_pointer(sf, sizeof(*sf)))
|
||||||
(((unsigned long) sf) & 0x03))
|
goto segv;
|
||||||
|
|
||||||
|
if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if (ufp & 0x7)
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
err = __get_user(pc, &sf->regs.pc);
|
err = __get_user(pc, &sf->regs.pc);
|
||||||
|
@ -178,15 +198,6 @@ segv:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the fp is valid */
|
|
||||||
static inline int invalid_frame_pointer(void __user *fp, int fplen)
|
|
||||||
{
|
|
||||||
if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
||||||
{
|
{
|
||||||
unsigned long sp = regs->u_regs[UREG_FP];
|
unsigned long sp = regs->u_regs[UREG_FP];
|
||||||
|
|
|
@ -234,6 +234,17 @@ do_sigsegv:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Checks if the fp is valid. We always build rt signal frames which
|
||||||
|
* are 16-byte aligned, therefore we can always enforce that the
|
||||||
|
* restore frame has that property as well.
|
||||||
|
*/
|
||||||
|
static bool invalid_frame_pointer(void __user *fp)
|
||||||
|
{
|
||||||
|
if (((unsigned long) fp) & 15)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct rt_signal_frame {
|
struct rt_signal_frame {
|
||||||
struct sparc_stackf ss;
|
struct sparc_stackf ss;
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
|
@ -246,8 +257,8 @@ struct rt_signal_frame {
|
||||||
|
|
||||||
void do_rt_sigreturn(struct pt_regs *regs)
|
void do_rt_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
unsigned long tpc, tnpc, tstate, ufp;
|
||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
unsigned long tpc, tnpc, tstate;
|
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
__siginfo_rwin_t __user *rwin_save;
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
@ -261,10 +272,16 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
||||||
(regs->u_regs [UREG_FP] + STACK_BIAS);
|
(regs->u_regs [UREG_FP] + STACK_BIAS);
|
||||||
|
|
||||||
/* 1. Make sure we are not getting garbage from the user */
|
/* 1. Make sure we are not getting garbage from the user */
|
||||||
if (((unsigned long) sf) & 3)
|
if (invalid_frame_pointer(sf))
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
err = get_user(tpc, &sf->regs.tpc);
|
if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
if ((ufp + STACK_BIAS) & 0x7)
|
||||||
|
goto segv;
|
||||||
|
|
||||||
|
err = __get_user(tpc, &sf->regs.tpc);
|
||||||
err |= __get_user(tnpc, &sf->regs.tnpc);
|
err |= __get_user(tnpc, &sf->regs.tnpc);
|
||||||
if (test_thread_flag(TIF_32BIT)) {
|
if (test_thread_flag(TIF_32BIT)) {
|
||||||
tpc &= 0xffffffff;
|
tpc &= 0xffffffff;
|
||||||
|
@ -308,14 +325,6 @@ segv:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the fp is valid */
|
|
||||||
static int invalid_frame_pointer(void __user *fp)
|
|
||||||
{
|
|
||||||
if (((unsigned long) fp) & 15)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
|
||||||
{
|
{
|
||||||
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
||||||
|
|
|
@ -48,6 +48,10 @@ int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (((unsigned long) fpu) & 3)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
||||||
regs->psr &= ~PSR_EF;
|
regs->psr &= ~PSR_EF;
|
||||||
|
@ -97,7 +101,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||||
struct thread_info *t = current_thread_info();
|
struct thread_info *t = current_thread_info();
|
||||||
int i, wsaved, err;
|
int i, wsaved, err;
|
||||||
|
|
||||||
__get_user(wsaved, &rp->wsaved);
|
if (((unsigned long) rp) & 3)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
get_user(wsaved, &rp->wsaved);
|
||||||
if (wsaved > NSWINS)
|
if (wsaved > NSWINS)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,10 @@ int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
unsigned long fprs;
|
unsigned long fprs;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = __get_user(fprs, &fpu->si_fprs);
|
if (((unsigned long) fpu) & 7)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err = get_user(fprs, &fpu->si_fprs);
|
||||||
fprs_write(0);
|
fprs_write(0);
|
||||||
regs->tstate &= ~TSTATE_PEF;
|
regs->tstate &= ~TSTATE_PEF;
|
||||||
if (fprs & FPRS_DL)
|
if (fprs & FPRS_DL)
|
||||||
|
@ -72,7 +75,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||||
struct thread_info *t = current_thread_info();
|
struct thread_info *t = current_thread_info();
|
||||||
int i, wsaved, err;
|
int i, wsaved, err;
|
||||||
|
|
||||||
__get_user(wsaved, &rp->wsaved);
|
if (((unsigned long) rp) & 7)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
get_user(wsaved, &rp->wsaved);
|
||||||
if (wsaved > NSWINS)
|
if (wsaved > NSWINS)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include <asm/thread_info.h>
|
||||||
|
#include <asm/trap_block.h>
|
||||||
|
#include <asm/spitfire.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
#include <asm/head.h>
|
||||||
|
|
||||||
|
.text
|
||||||
|
.align 8
|
||||||
|
.globl user_rtt_fill_fixup_common
|
||||||
|
user_rtt_fill_fixup_common:
|
||||||
|
rdpr %cwp, %g1
|
||||||
|
add %g1, 1, %g1
|
||||||
|
wrpr %g1, 0x0, %cwp
|
||||||
|
|
||||||
|
rdpr %wstate, %g2
|
||||||
|
sll %g2, 3, %g2
|
||||||
|
wrpr %g2, 0x0, %wstate
|
||||||
|
|
||||||
|
/* We know %canrestore and %otherwin are both zero. */
|
||||||
|
|
||||||
|
sethi %hi(sparc64_kern_pri_context), %g2
|
||||||
|
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2
|
||||||
|
mov PRIMARY_CONTEXT, %g1
|
||||||
|
|
||||||
|
661: stxa %g2, [%g1] ASI_DMMU
|
||||||
|
.section .sun4v_1insn_patch, "ax"
|
||||||
|
.word 661b
|
||||||
|
stxa %g2, [%g1] ASI_MMU
|
||||||
|
.previous
|
||||||
|
|
||||||
|
sethi %hi(KERNBASE), %g1
|
||||||
|
flush %g1
|
||||||
|
|
||||||
|
mov %g4, %l4
|
||||||
|
mov %g5, %l5
|
||||||
|
brnz,pn %g3, 1f
|
||||||
|
mov %g3, %l3
|
||||||
|
|
||||||
|
or %g4, FAULT_CODE_WINFIXUP, %g4
|
||||||
|
stb %g4, [%g6 + TI_FAULT_CODE]
|
||||||
|
stx %g5, [%g6 + TI_FAULT_ADDR]
|
||||||
|
1:
|
||||||
|
mov %g6, %l1
|
||||||
|
wrpr %g0, 0x0, %tl
|
||||||
|
|
||||||
|
661: nop
|
||||||
|
.section .sun4v_1insn_patch, "ax"
|
||||||
|
.word 661b
|
||||||
|
SET_GL(0)
|
||||||
|
.previous
|
||||||
|
|
||||||
|
wrpr %g0, RTRAP_PSTATE, %pstate
|
||||||
|
|
||||||
|
mov %l1, %g6
|
||||||
|
ldx [%g6 + TI_TASK], %g4
|
||||||
|
LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
|
||||||
|
|
||||||
|
brnz,pn %l3, 1f
|
||||||
|
nop
|
||||||
|
|
||||||
|
call do_sparc64_fault
|
||||||
|
add %sp, PTREGS_OFF, %o0
|
||||||
|
ba,pt %xcc, rtrap
|
||||||
|
nop
|
||||||
|
|
||||||
|
1: cmp %g3, 2
|
||||||
|
bne,pn %xcc, 2f
|
||||||
|
nop
|
||||||
|
|
||||||
|
sethi %hi(tlb_type), %g1
|
||||||
|
lduw [%g1 + %lo(tlb_type)], %g1
|
||||||
|
cmp %g1, 3
|
||||||
|
bne,pt %icc, 1f
|
||||||
|
add %sp, PTREGS_OFF, %o0
|
||||||
|
mov %l4, %o2
|
||||||
|
call sun4v_do_mna
|
||||||
|
mov %l5, %o1
|
||||||
|
ba,a,pt %xcc, rtrap
|
||||||
|
1: mov %l4, %o1
|
||||||
|
mov %l5, %o2
|
||||||
|
call mem_address_unaligned
|
||||||
|
nop
|
||||||
|
ba,a,pt %xcc, rtrap
|
||||||
|
|
||||||
|
2: sethi %hi(tlb_type), %g1
|
||||||
|
mov %l4, %o1
|
||||||
|
lduw [%g1 + %lo(tlb_type)], %g1
|
||||||
|
mov %l5, %o2
|
||||||
|
cmp %g1, 3
|
||||||
|
bne,pt %icc, 1f
|
||||||
|
add %sp, PTREGS_OFF, %o0
|
||||||
|
call sun4v_data_access_exception
|
||||||
|
nop
|
||||||
|
ba,a,pt %xcc, rtrap
|
||||||
|
|
||||||
|
1: call spitfire_data_access_exception
|
||||||
|
nop
|
||||||
|
ba,a,pt %xcc, rtrap
|
|
@ -2824,9 +2824,10 @@ void hugetlb_setup(struct pt_regs *regs)
|
||||||
* the Data-TLB for huge pages.
|
* the Data-TLB for huge pages.
|
||||||
*/
|
*/
|
||||||
if (tlb_type == cheetah_plus) {
|
if (tlb_type == cheetah_plus) {
|
||||||
|
bool need_context_reload = false;
|
||||||
unsigned long ctx;
|
unsigned long ctx;
|
||||||
|
|
||||||
spin_lock(&ctx_alloc_lock);
|
spin_lock_irq(&ctx_alloc_lock);
|
||||||
ctx = mm->context.sparc64_ctx_val;
|
ctx = mm->context.sparc64_ctx_val;
|
||||||
ctx &= ~CTX_PGSZ_MASK;
|
ctx &= ~CTX_PGSZ_MASK;
|
||||||
ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT;
|
ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT;
|
||||||
|
@ -2845,9 +2846,12 @@ void hugetlb_setup(struct pt_regs *regs)
|
||||||
* also executing in this address space.
|
* also executing in this address space.
|
||||||
*/
|
*/
|
||||||
mm->context.sparc64_ctx_val = ctx;
|
mm->context.sparc64_ctx_val = ctx;
|
||||||
on_each_cpu(context_reload, mm, 0);
|
need_context_reload = true;
|
||||||
}
|
}
|
||||||
spin_unlock(&ctx_alloc_lock);
|
spin_unlock_irq(&ctx_alloc_lock);
|
||||||
|
|
||||||
|
if (need_context_reload)
|
||||||
|
on_each_cpu(context_reload, mm, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче