mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
powerpc/64s: avoid reloading (H)SRR registers if they are still valid
When an interrupt is taken, the SRR registers are set to return to where it left off. Unless they are modified in the meantime, or the return address or MSR are modified, there is no need to reload these registers when returning from interrupt. Introduce per-CPU flags that track the validity of SRR and HSRR registers. These are cleared when returning from interrupt, when using the registers for something else (e.g., OPAL calls), when adjusting the return address or MSR of a context, and when context switching (which changes the return address and MSR). This improves the performance of interrupt returns. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [mpe: Fold in fixup patch from Nick] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210617155116.2167984-5-npiggin@gmail.com
This commit is contained in:
committed by
Michael Ellerman
parent
1df7d5e4ba
commit
59dc5bfca0
@@ -85,6 +85,10 @@ config MSI_BITMAP_SELFTEST
|
||||
config PPC_IRQ_SOFT_MASK_DEBUG
|
||||
bool "Include extra checks for powerpc irq soft masking"
|
||||
|
||||
config PPC_RFI_SRR_DEBUG
|
||||
bool "Include extra checks for RFI SRR register validity"
|
||||
depends on PPC_BOOK3S_64
|
||||
|
||||
config XMON
|
||||
bool "Include xmon kernel debugger"
|
||||
depends on DEBUG_KERNEL
|
||||
|
||||
@@ -389,7 +389,15 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
|
||||
return !(regs->msr & MSR_EE);
|
||||
}
|
||||
|
||||
static inline void may_hard_irq_enable(void) { }
|
||||
static inline bool may_hard_irq_enable(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void do_hard_irq_enable(void)
|
||||
{
|
||||
BUILD_BUG();
|
||||
}
|
||||
|
||||
static inline void irq_soft_mask_regs_set_state(struct pt_regs *regs, unsigned long val)
|
||||
{
|
||||
|
||||
@@ -73,13 +73,25 @@
|
||||
#include <asm/kprobes.h>
|
||||
#include <asm/runlatch.h>
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
static inline void srr_regs_clobbered(void)
|
||||
{
|
||||
local_paca->srr_valid = 0;
|
||||
local_paca->hsrr_valid = 0;
|
||||
}
|
||||
#else
|
||||
static inline void srr_regs_clobbered(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void nap_adjust_return(struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_PPC_970_NAP
|
||||
if (unlikely(test_thread_local_flags(_TLF_NAPPING))) {
|
||||
/* Can avoid a test-and-clear because NMIs do not call this */
|
||||
clear_thread_local_flags(_TLF_NAPPING);
|
||||
regs->nip = (unsigned long)power4_idle_nap_return;
|
||||
regs_set_return_ip(regs, (unsigned long)power4_idle_nap_return);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
|
||||
{
|
||||
struct pt_regs *regs = ftrace_get_regs(fregs);
|
||||
|
||||
regs->nip = ip;
|
||||
regs_set_return_ip(regs, ip);
|
||||
}
|
||||
|
||||
#define klp_get_ftrace_location klp_get_ftrace_location
|
||||
|
||||
@@ -167,6 +167,10 @@ struct paca_struct {
|
||||
u64 saved_msr; /* MSR saved here by enter_rtas */
|
||||
#ifdef CONFIG_PPC_BOOK3E
|
||||
u16 trap_save; /* Used when bad stack is encountered */
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
u8 hsrr_valid; /* HSRRs set for HRFID */
|
||||
u8 srr_valid; /* SRRs set for RFID */
|
||||
#endif
|
||||
u8 irq_soft_mask; /* mask for irq soft masking */
|
||||
u8 irq_happened; /* irq happened while soft-disabled */
|
||||
|
||||
@@ -34,14 +34,14 @@ typedef u32 ppc_opcode_t;
|
||||
/* Enable single stepping for the current task */
|
||||
static inline void enable_single_step(struct pt_regs *regs)
|
||||
{
|
||||
regs->msr |= MSR_SINGLESTEP;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_SINGLESTEP);
|
||||
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
|
||||
/*
|
||||
* We turn off Critical Input Exception(CE) to ensure that the single
|
||||
* step will be for the instruction we have the probe on; if we don't,
|
||||
* it is possible we'd get the single step reported for CE.
|
||||
*/
|
||||
regs->msr &= ~MSR_CE;
|
||||
regs_set_return_msr(regs, regs->msr & ~MSR_CE);
|
||||
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
|
||||
#ifdef CONFIG_PPC_47x
|
||||
isync();
|
||||
|
||||
@@ -123,6 +123,47 @@ struct pt_regs
|
||||
#endif /* __powerpc64__ */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/paca.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern unsigned long profile_pc(struct pt_regs *regs);
|
||||
#else
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
#endif
|
||||
|
||||
long do_syscall_trace_enter(struct pt_regs *regs);
|
||||
void do_syscall_trace_leave(struct pt_regs *regs);
|
||||
|
||||
static inline void regs_set_return_ip(struct pt_regs *regs, unsigned long ip)
|
||||
{
|
||||
regs->nip = ip;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
local_paca->hsrr_valid = 0;
|
||||
local_paca->srr_valid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void regs_set_return_msr(struct pt_regs *regs, unsigned long msr)
|
||||
{
|
||||
regs->msr = msr;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
local_paca->hsrr_valid = 0;
|
||||
local_paca->srr_valid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void set_return_regs_changed(void)
|
||||
{
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
local_paca->hsrr_valid = 0;
|
||||
local_paca->srr_valid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void regs_add_return_ip(struct pt_regs *regs, long offset)
|
||||
{
|
||||
regs_set_return_ip(regs, regs->nip + offset);
|
||||
}
|
||||
|
||||
static inline unsigned long instruction_pointer(struct pt_regs *regs)
|
||||
{
|
||||
@@ -132,7 +173,7 @@ static inline unsigned long instruction_pointer(struct pt_regs *regs)
|
||||
static inline void instruction_pointer_set(struct pt_regs *regs,
|
||||
unsigned long val)
|
||||
{
|
||||
regs->nip = val;
|
||||
regs_set_return_ip(regs, val);
|
||||
}
|
||||
|
||||
static inline unsigned long user_stack_pointer(struct pt_regs *regs)
|
||||
@@ -145,15 +186,6 @@ static inline unsigned long frame_pointer(struct pt_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern unsigned long profile_pc(struct pt_regs *regs);
|
||||
#else
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
#endif
|
||||
|
||||
long do_syscall_trace_enter(struct pt_regs *regs);
|
||||
void do_syscall_trace_leave(struct pt_regs *regs);
|
||||
|
||||
#ifdef __powerpc64__
|
||||
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
|
||||
#else
|
||||
|
||||
@@ -190,6 +190,10 @@ int main(void)
|
||||
OFFSET(PACATOC, paca_struct, kernel_toc);
|
||||
OFFSET(PACAKBASE, paca_struct, kernelbase);
|
||||
OFFSET(PACAKMSR, paca_struct, kernel_msr);
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
OFFSET(PACAHSRR_VALID, paca_struct, hsrr_valid);
|
||||
OFFSET(PACASRR_VALID, paca_struct, srr_valid);
|
||||
#endif
|
||||
OFFSET(PACAIRQSOFTMASK, paca_struct, irq_soft_mask);
|
||||
OFFSET(PACAIRQHAPPENED, paca_struct, irq_happened);
|
||||
OFFSET(PACA_FTRACE_ENABLED, paca_struct, ftrace_enabled);
|
||||
|
||||
@@ -64,6 +64,30 @@ exception_marker:
|
||||
.section ".text"
|
||||
.align 7
|
||||
|
||||
.macro DEBUG_SRR_VALID srr
|
||||
#ifdef CONFIG_PPC_RFI_SRR_DEBUG
|
||||
.ifc \srr,srr
|
||||
mfspr r11,SPRN_SRR0
|
||||
ld r12,_NIP(r1)
|
||||
100: tdne r11,r12
|
||||
EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
mfspr r11,SPRN_SRR1
|
||||
ld r12,_MSR(r1)
|
||||
100: tdne r11,r12
|
||||
EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
.else
|
||||
mfspr r11,SPRN_HSRR0
|
||||
ld r12,_NIP(r1)
|
||||
100: tdne r11,r12
|
||||
EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
mfspr r11,SPRN_HSRR1
|
||||
ld r12,_MSR(r1)
|
||||
100: tdne r11,r12
|
||||
EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
.endif
|
||||
#endif
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
.macro system_call_vectored name trapnr
|
||||
.globl system_call_vectored_\name
|
||||
@@ -286,6 +310,11 @@ END_BTB_FLUSH_SECTION
|
||||
ld r11,exception_marker@toc(r2)
|
||||
std r11,-16(r10) /* "regshere" marker */
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
li r11,1
|
||||
stb r11,PACASRR_VALID(r13)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We always enter kernel from userspace with irq soft-mask enabled and
|
||||
* nothing pending. system_call_exception() will call
|
||||
@@ -306,18 +335,27 @@ END_BTB_FLUSH_SECTION
|
||||
bl syscall_exit_prepare
|
||||
|
||||
ld r2,_CCR(r1)
|
||||
ld r6,_LINK(r1)
|
||||
mtlr r6
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
lbz r4,PACASRR_VALID(r13)
|
||||
cmpdi r4,0
|
||||
bne 1f
|
||||
li r4,0
|
||||
stb r4,PACASRR_VALID(r13)
|
||||
#endif
|
||||
ld r4,_NIP(r1)
|
||||
ld r5,_MSR(r1)
|
||||
ld r6,_LINK(r1)
|
||||
mtspr SPRN_SRR0,r4
|
||||
mtspr SPRN_SRR1,r5
|
||||
1:
|
||||
DEBUG_SRR_VALID srr
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
stdcx. r0,0,r1 /* to clear the reservation */
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
|
||||
mtspr SPRN_SRR0,r4
|
||||
mtspr SPRN_SRR1,r5
|
||||
mtlr r6
|
||||
|
||||
cmpdi r3,0
|
||||
bne .Lsyscall_restore_regs
|
||||
/* Zero volatile regs that may contain sensitive kernel data */
|
||||
@@ -673,19 +711,40 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\())
|
||||
kuap_user_restore r3, r4
|
||||
#endif
|
||||
.Lfast_user_interrupt_return_\srr\():
|
||||
ld r11,_NIP(r1)
|
||||
ld r12,_MSR(r1)
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
ld r10,_PPR(r1)
|
||||
mtspr SPRN_PPR,r10
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
.ifc \srr,srr
|
||||
lbz r4,PACASRR_VALID(r13)
|
||||
.else
|
||||
lbz r4,PACAHSRR_VALID(r13)
|
||||
.endif
|
||||
cmpdi r4,0
|
||||
li r4,0
|
||||
bne 1f
|
||||
#endif
|
||||
ld r11,_NIP(r1)
|
||||
ld r12,_MSR(r1)
|
||||
.ifc \srr,srr
|
||||
mtspr SPRN_SRR0,r11
|
||||
mtspr SPRN_SRR1,r12
|
||||
1:
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
stb r4,PACASRR_VALID(r13)
|
||||
#endif
|
||||
.else
|
||||
mtspr SPRN_HSRR0,r11
|
||||
mtspr SPRN_HSRR1,r12
|
||||
1:
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
stb r4,PACAHSRR_VALID(r13)
|
||||
#endif
|
||||
.endif
|
||||
DEBUG_SRR_VALID \srr
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
stdcx. r0,0,r1 /* to clear the reservation */
|
||||
@@ -730,15 +789,34 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
|
||||
.Lfast_kernel_interrupt_return_\srr\():
|
||||
cmpdi cr1,r3,0
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
.ifc \srr,srr
|
||||
lbz r4,PACASRR_VALID(r13)
|
||||
.else
|
||||
lbz r4,PACAHSRR_VALID(r13)
|
||||
.endif
|
||||
cmpdi r4,0
|
||||
li r4,0
|
||||
bne 1f
|
||||
#endif
|
||||
ld r11,_NIP(r1)
|
||||
ld r12,_MSR(r1)
|
||||
.ifc \srr,srr
|
||||
mtspr SPRN_SRR0,r11
|
||||
mtspr SPRN_SRR1,r12
|
||||
1:
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
stb r4,PACASRR_VALID(r13)
|
||||
#endif
|
||||
.else
|
||||
mtspr SPRN_HSRR0,r11
|
||||
mtspr SPRN_HSRR1,r12
|
||||
1:
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
stb r4,PACAHSRR_VALID(r13)
|
||||
#endif
|
||||
.endif
|
||||
DEBUG_SRR_VALID \srr
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
stdcx. r0,0,r1 /* to clear the reservation */
|
||||
|
||||
@@ -485,6 +485,20 @@ DEFINE_FIXED_SYMBOL(\name\()_common_real)
|
||||
std r0,GPR0(r1) /* save r0 in stackframe */
|
||||
std r10,GPR1(r1) /* save r1 in stackframe */
|
||||
|
||||
/* Mark our [H]SRRs valid for return */
|
||||
li r10,1
|
||||
.if IHSRR_IF_HVMODE
|
||||
BEGIN_FTR_SECTION
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
FTR_SECTION_ELSE
|
||||
stb r10,PACASRR_VALID(r13)
|
||||
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
|
||||
.elseif IHSRR
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
.else
|
||||
stb r10,PACASRR_VALID(r13)
|
||||
.endif
|
||||
|
||||
.if ISET_RI
|
||||
li r10,MSR_RI
|
||||
mtmsrd r10,1 /* Set MSR_RI */
|
||||
@@ -584,10 +598,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
.macro EXCEPTION_RESTORE_REGS hsrr=0
|
||||
/* Move original SRR0 and SRR1 into the respective regs */
|
||||
ld r9,_MSR(r1)
|
||||
li r10,0
|
||||
.if \hsrr
|
||||
mtspr SPRN_HSRR1,r9
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
.else
|
||||
mtspr SPRN_SRR1,r9
|
||||
stb r10,PACASRR_VALID(r13)
|
||||
.endif
|
||||
ld r9,_NIP(r1)
|
||||
.if \hsrr
|
||||
@@ -1718,6 +1735,8 @@ EXC_COMMON_BEGIN(hdecrementer_common)
|
||||
*
|
||||
* Be careful to avoid touching the kernel stack.
|
||||
*/
|
||||
li r10,0
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
ld r10,PACA_EXGEN+EX_CTR(r13)
|
||||
mtctr r10
|
||||
mtcrf 0x80,r9
|
||||
@@ -2513,6 +2532,8 @@ BEGIN_FTR_SECTION
|
||||
ld r10,PACA_EXGEN+EX_CFAR(r13)
|
||||
mtspr SPRN_CFAR,r10
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
li r10,0
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
ld r10,PACA_EXGEN+EX_R10(r13)
|
||||
ld r11,PACA_EXGEN+EX_R11(r13)
|
||||
ld r12,PACA_EXGEN+EX_R12(r13)
|
||||
@@ -2673,6 +2694,12 @@ masked_interrupt:
|
||||
ori r11,r11,PACA_IRQ_HARD_DIS
|
||||
stb r11,PACAIRQHAPPENED(r13)
|
||||
2: /* done */
|
||||
li r10,0
|
||||
.if \hsrr
|
||||
stb r10,PACAHSRR_VALID(r13)
|
||||
.else
|
||||
stb r10,PACASRR_VALID(r13)
|
||||
.endif
|
||||
ld r10,PACA_EXGEN+EX_CTR(r13)
|
||||
mtctr r10
|
||||
mtcrf 0x80,r9
|
||||
|
||||
@@ -103,6 +103,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
|
||||
ori r12,r12,MSR_FP
|
||||
or r12,r12,r4
|
||||
std r12,_MSR(r1)
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
li r4,0
|
||||
stb r4,PACASRR_VALID(r13)
|
||||
#endif
|
||||
#endif
|
||||
li r4,1
|
||||
stb r4,THREAD_LOAD_FP(r5)
|
||||
|
||||
@@ -486,7 +486,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
|
||||
return;
|
||||
|
||||
reset:
|
||||
regs->msr &= ~MSR_SE;
|
||||
regs_set_return_msr(regs, regs->msr & ~MSR_SE);
|
||||
for (i = 0; i < nr_wp_slots(); i++) {
|
||||
info = counter_arch_bp(__this_cpu_read(bp_per_reg[i]));
|
||||
__set_breakpoint(i, info);
|
||||
@@ -537,7 +537,7 @@ static bool stepping_handler(struct pt_regs *regs, struct perf_event **bp,
|
||||
current->thread.last_hit_ubp[i] = bp[i];
|
||||
info[i] = NULL;
|
||||
}
|
||||
regs->msr |= MSR_SE;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_SE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
|
||||
return 0;
|
||||
|
||||
if (*(u32 *)regs->nip == BREAK_INSTR)
|
||||
regs->nip += BREAK_INSTR_SIZE;
|
||||
regs_add_return_ip(regs, BREAK_INSTR_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -372,7 +372,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
|
||||
|
||||
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
|
||||
{
|
||||
regs->nip = pc;
|
||||
regs_set_return_ip(regs, pc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -394,7 +394,7 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
|
||||
case 'c':
|
||||
/* handle the optional parameter */
|
||||
if (kgdb_hex2long(&ptr, &addr))
|
||||
linux_regs->nip = addr;
|
||||
regs_set_return_ip(linux_regs, addr);
|
||||
|
||||
atomic_set(&kgdb_cpu_doing_single_step, -1);
|
||||
/* set the trace bit if we're stepping */
|
||||
@@ -402,9 +402,9 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
|
||||
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
|
||||
mtspr(SPRN_DBCR0,
|
||||
mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
|
||||
linux_regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(linux_regs, linux_regs->msr | MSR_DE);
|
||||
#else
|
||||
linux_regs->msr |= MSR_SE;
|
||||
regs_set_return_msr(linux_regs, linux_regs->msr | MSR_SE);
|
||||
#endif
|
||||
atomic_set(&kgdb_cpu_doing_single_step,
|
||||
raw_smp_processor_id());
|
||||
|
||||
@@ -39,7 +39,7 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,
|
||||
* On powerpc, NIP is *before* this instruction for the
|
||||
* pre handler
|
||||
*/
|
||||
regs->nip -= MCOUNT_INSN_SIZE;
|
||||
regs_add_return_ip(regs, -MCOUNT_INSN_SIZE);
|
||||
|
||||
__this_cpu_write(current_kprobe, p);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
@@ -48,7 +48,7 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,
|
||||
* Emulate singlestep (and also recover regs->nip)
|
||||
* as if there is a nop
|
||||
*/
|
||||
regs->nip += MCOUNT_INSN_SIZE;
|
||||
regs_add_return_ip(regs, MCOUNT_INSN_SIZE);
|
||||
if (unlikely(p->post_handler)) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
p->post_handler(p, regs, 0);
|
||||
|
||||
@@ -194,7 +194,7 @@ static nokprobe_inline void prepare_singlestep(struct kprobe *p, struct pt_regs
|
||||
* variant as values in regs could play a part in
|
||||
* if the trap is taken or not
|
||||
*/
|
||||
regs->nip = (unsigned long)p->ainsn.insn;
|
||||
regs_set_return_ip(regs, (unsigned long)p->ainsn.insn);
|
||||
}
|
||||
|
||||
static nokprobe_inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||
@@ -335,8 +335,9 @@ int kprobe_handler(struct pt_regs *regs)
|
||||
kprobe_opcode_t insn = *p->ainsn.insn;
|
||||
if (kcb->kprobe_status == KPROBE_HIT_SS && is_trap(insn)) {
|
||||
/* Turn off 'trace' bits */
|
||||
regs->msr &= ~MSR_SINGLESTEP;
|
||||
regs->msr |= kcb->kprobe_saved_msr;
|
||||
regs_set_return_msr(regs,
|
||||
(regs->msr & ~MSR_SINGLESTEP) |
|
||||
kcb->kprobe_saved_msr);
|
||||
goto no_kprobe;
|
||||
}
|
||||
|
||||
@@ -431,7 +432,7 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
* we end up emulating it in kprobe_handler(), which increments the nip
|
||||
* again.
|
||||
*/
|
||||
regs->nip = orig_ret_address - 4;
|
||||
regs_set_return_ip(regs, orig_ret_address - 4);
|
||||
regs->link = orig_ret_address;
|
||||
|
||||
return 0;
|
||||
@@ -466,8 +467,8 @@ int kprobe_post_handler(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
/* Adjust nip to after the single-stepped instruction */
|
||||
regs->nip = (unsigned long)cur->addr + len;
|
||||
regs->msr |= kcb->kprobe_saved_msr;
|
||||
regs_set_return_ip(regs, (unsigned long)cur->addr + len);
|
||||
regs_set_return_msr(regs, regs->msr | kcb->kprobe_saved_msr);
|
||||
|
||||
/*Restore back the original saved kprobes variables and continue. */
|
||||
if (kcb->kprobe_status == KPROBE_REENTER) {
|
||||
@@ -506,9 +507,11 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||
* and allow the page fault handler to continue as a
|
||||
* normal page fault.
|
||||
*/
|
||||
regs->nip = (unsigned long)cur->addr;
|
||||
regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */
|
||||
regs->msr |= kcb->kprobe_saved_msr;
|
||||
regs_set_return_ip(regs, (unsigned long)cur->addr);
|
||||
/* Turn off 'trace' bits */
|
||||
regs_set_return_msr(regs,
|
||||
(regs->msr & ~MSR_SINGLESTEP) |
|
||||
kcb->kprobe_saved_msr);
|
||||
if (kcb->kprobe_status == KPROBE_REENTER)
|
||||
restore_previous_kprobe(kcb);
|
||||
else
|
||||
@@ -539,7 +542,7 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||
* zero, try to fix up.
|
||||
*/
|
||||
if ((entry = search_exception_tables(regs->nip)) != NULL) {
|
||||
regs->nip = extable_fixup(entry);
|
||||
regs_set_return_ip(regs, extable_fixup(entry));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ void mce_common_process_ue(struct pt_regs *regs,
|
||||
entry = search_kernel_exception_table(regs->nip);
|
||||
if (entry) {
|
||||
mce_err->ignore_event = true;
|
||||
regs->nip = extable_fixup(entry);
|
||||
regs_set_return_ip(regs, extable_fixup(entry));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ static void optimized_callback(struct optimized_kprobe *op,
|
||||
kprobes_inc_nmissed_count(&op->kp);
|
||||
} else {
|
||||
__this_cpu_write(current_kprobe, &op->kp);
|
||||
regs->nip = (unsigned long)op->kp.addr;
|
||||
regs_set_return_ip(regs, (unsigned long)op->kp.addr);
|
||||
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
opt_pre_handler(&op->kp, regs);
|
||||
__this_cpu_write(current_kprobe, NULL);
|
||||
|
||||
@@ -96,7 +96,8 @@ static void check_if_tm_restore_required(struct task_struct *tsk)
|
||||
if (tsk == current && tsk->thread.regs &&
|
||||
MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
|
||||
!test_thread_flag(TIF_RESTORE_TM)) {
|
||||
tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr;
|
||||
regs_set_return_msr(&tsk->thread.ckpt_regs,
|
||||
tsk->thread.regs->msr);
|
||||
set_thread_flag(TIF_RESTORE_TM);
|
||||
}
|
||||
}
|
||||
@@ -161,7 +162,7 @@ static void __giveup_fpu(struct task_struct *tsk)
|
||||
msr &= ~(MSR_FP|MSR_FE0|MSR_FE1);
|
||||
if (cpu_has_feature(CPU_FTR_VSX))
|
||||
msr &= ~MSR_VSX;
|
||||
tsk->thread.regs->msr = msr;
|
||||
regs_set_return_msr(tsk->thread.regs, msr);
|
||||
}
|
||||
|
||||
void giveup_fpu(struct task_struct *tsk)
|
||||
@@ -244,7 +245,7 @@ static void __giveup_altivec(struct task_struct *tsk)
|
||||
msr &= ~MSR_VEC;
|
||||
if (cpu_has_feature(CPU_FTR_VSX))
|
||||
msr &= ~MSR_VSX;
|
||||
tsk->thread.regs->msr = msr;
|
||||
regs_set_return_msr(tsk->thread.regs, msr);
|
||||
}
|
||||
|
||||
void giveup_altivec(struct task_struct *tsk)
|
||||
@@ -559,7 +560,7 @@ void notrace restore_math(struct pt_regs *regs)
|
||||
|
||||
msr_check_and_clear(new_msr);
|
||||
|
||||
regs->msr |= new_msr | fpexc_mode;
|
||||
regs_set_return_msr(regs, regs->msr | new_msr | fpexc_mode);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PPC_BOOK3S_64 */
|
||||
@@ -1114,7 +1115,7 @@ void restore_tm_state(struct pt_regs *regs)
|
||||
#endif
|
||||
restore_math(regs);
|
||||
|
||||
regs->msr |= msr_diff;
|
||||
regs_set_return_msr(regs, regs->msr | msr_diff);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PPC_TRANSACTIONAL_MEM */
|
||||
@@ -1257,14 +1258,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
}
|
||||
|
||||
/*
|
||||
* Call restore_sprs() before calling _switch(). If we move it after
|
||||
* _switch() then we miss out on calling it for new tasks. The reason
|
||||
* for this is we manually create a stack frame for new tasks that
|
||||
* directly returns through ret_from_fork() or
|
||||
* Call restore_sprs() and set_return_regs_changed() before calling
|
||||
* _switch(). If we move it after _switch() then we miss out on calling
|
||||
* it for new tasks. The reason for this is we manually create a stack
|
||||
* frame for new tasks that directly returns through ret_from_fork() or
|
||||
* ret_from_kernel_thread(). See copy_thread() for details.
|
||||
*/
|
||||
restore_sprs(old_thread, new_thread);
|
||||
|
||||
set_return_regs_changed(); /* _switch changes stack (and regs) */
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
kuap_assert_locked();
|
||||
#endif
|
||||
@@ -1850,13 +1853,14 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
|
||||
}
|
||||
regs->gpr[2] = toc;
|
||||
}
|
||||
regs->nip = entry;
|
||||
regs->msr = MSR_USER64;
|
||||
regs_set_return_ip(regs, entry);
|
||||
regs_set_return_msr(regs, MSR_USER64);
|
||||
} else {
|
||||
regs->nip = start;
|
||||
regs->gpr[2] = 0;
|
||||
regs->msr = MSR_USER32;
|
||||
regs_set_return_ip(regs, start);
|
||||
regs_set_return_msr(regs, MSR_USER32);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_VSX
|
||||
current->thread.used_vsr = 0;
|
||||
@@ -1887,7 +1891,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
|
||||
current->thread.tm_tfiar = 0;
|
||||
current->thread.load_tm = 0;
|
||||
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(start_thread);
|
||||
|
||||
@@ -1935,9 +1938,10 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
|
||||
if (val > PR_FP_EXC_PRECISE)
|
||||
return -EINVAL;
|
||||
tsk->thread.fpexc_mode = __pack_fe01(val);
|
||||
if (regs != NULL && (regs->msr & MSR_FP) != 0)
|
||||
regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
|
||||
| tsk->thread.fpexc_mode;
|
||||
if (regs != NULL && (regs->msr & MSR_FP) != 0) {
|
||||
regs_set_return_msr(regs, (regs->msr & ~(MSR_FE0|MSR_FE1))
|
||||
| tsk->thread.fpexc_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1983,9 +1987,9 @@ int set_endian(struct task_struct *tsk, unsigned int val)
|
||||
return -EINVAL;
|
||||
|
||||
if (val == PR_ENDIAN_BIG)
|
||||
regs->msr &= ~MSR_LE;
|
||||
regs_set_return_msr(regs, regs->msr & ~MSR_LE);
|
||||
else if (val == PR_ENDIAN_LITTLE || val == PR_ENDIAN_PPC_LITTLE)
|
||||
regs->msr |= MSR_LE;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_LE);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <asm/rtas.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/smp.h>
|
||||
@@ -1792,6 +1793,8 @@ static int prom_rtas_hcall(uint64_t args)
|
||||
asm volatile("sc 1\n" : "=r" (arg1) :
|
||||
"r" (arg1),
|
||||
"r" (arg2) :);
|
||||
srr_regs_clobbered();
|
||||
|
||||
return arg1;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ void user_enable_single_step(struct task_struct *task)
|
||||
if (regs != NULL) {
|
||||
task->thread.debug.dbcr0 &= ~DBCR0_BT;
|
||||
task->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
|
||||
regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_DE);
|
||||
}
|
||||
set_tsk_thread_flag(task, TIF_SINGLESTEP);
|
||||
}
|
||||
@@ -24,7 +24,7 @@ void user_enable_block_step(struct task_struct *task)
|
||||
if (regs != NULL) {
|
||||
task->thread.debug.dbcr0 &= ~DBCR0_IC;
|
||||
task->thread.debug.dbcr0 = DBCR0_IDM | DBCR0_BT;
|
||||
regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_DE);
|
||||
}
|
||||
set_tsk_thread_flag(task, TIF_SINGLESTEP);
|
||||
}
|
||||
@@ -50,7 +50,7 @@ void user_disable_single_step(struct task_struct *task)
|
||||
* All debug events were off.....
|
||||
*/
|
||||
task->thread.debug.dbcr0 &= ~DBCR0_IDM;
|
||||
regs->msr &= ~MSR_DE;
|
||||
regs_set_return_msr(regs, regs->msr & ~MSR_DE);
|
||||
}
|
||||
}
|
||||
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
|
||||
@@ -82,6 +82,7 @@ int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
|
||||
|
||||
int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
|
||||
{
|
||||
struct pt_regs *regs = task->thread.regs;
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
int ret;
|
||||
struct thread_struct *thread = &task->thread;
|
||||
@@ -112,7 +113,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned l
|
||||
dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
|
||||
if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
|
||||
task->thread.debug.dbcr1)) {
|
||||
task->thread.regs->msr &= ~MSR_DE;
|
||||
regs_set_return_msr(regs, regs->msr & ~MSR_DE);
|
||||
task->thread.debug.dbcr0 &= ~DBCR0_IDM;
|
||||
}
|
||||
return 0;
|
||||
@@ -132,7 +133,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned l
|
||||
dbcr_dac(task) |= DBCR_DAC1R;
|
||||
if (data & 0x2UL)
|
||||
dbcr_dac(task) |= DBCR_DAC1W;
|
||||
task->thread.regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(regs, regs->msr | MSR_DE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,7 +221,7 @@ static long set_instruction_bp(struct task_struct *child,
|
||||
}
|
||||
out:
|
||||
child->thread.debug.dbcr0 |= DBCR0_IDM;
|
||||
child->thread.regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
|
||||
|
||||
return slot;
|
||||
}
|
||||
@@ -336,7 +337,7 @@ static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
|
||||
return -ENOSPC;
|
||||
}
|
||||
child->thread.debug.dbcr0 |= DBCR0_IDM;
|
||||
child->thread.regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
|
||||
|
||||
return slot + 4;
|
||||
}
|
||||
@@ -430,7 +431,7 @@ static int set_dac_range(struct task_struct *child,
|
||||
child->thread.debug.dbcr2 |= DBCR2_DAC12MX;
|
||||
else /* PPC_BREAKPOINT_MODE_MASK */
|
||||
child->thread.debug.dbcr2 |= DBCR2_DAC12MM;
|
||||
child->thread.regs->msr |= MSR_DE;
|
||||
regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
|
||||
|
||||
return 5;
|
||||
}
|
||||
@@ -485,7 +486,8 @@ long ppc_del_hwdebug(struct task_struct *child, long data)
|
||||
if (!DBCR_ACTIVE_EVENTS(child->thread.debug.dbcr0,
|
||||
child->thread.debug.dbcr1)) {
|
||||
child->thread.debug.dbcr0 &= ~DBCR0_IDM;
|
||||
child->thread.regs->msr &= ~MSR_DE;
|
||||
regs_set_return_msr(child->thread.regs,
|
||||
child->thread.regs->msr & ~MSR_DE);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user