Skip to content

Commit 6fe71ca

Browse files
unawinogregkh
authored andcommitted
sparc64: Prevent perf from running during super critical sections
commit fc290a114fc6034b0f6a5a46e2fb7d54976cf87a upstream. This fixes another cause of random segfaults and bus errors that may occur while running perf with the callgraph option. Critical sections beginning with spin_lock_irqsave() raise the interrupt level to PIL_NORMAL_MAX (14) and intentionally do not block performance counter interrupts, which arrive at PIL_NMI (15). But some sections of code are "super critical" with respect to perf because the perf_callchain_user() path accesses user space and may cause TLB activity as well as faults as it unwinds the user stack. One particular critical section occurs in switch_mm: spin_lock_irqsave(&mm->context.lock, flags); ... load_secondary_context(mm); tsb_context_switch(mm); ... spin_unlock_irqrestore(&mm->context.lock, flags); If a perf interrupt arrives in between load_secondary_context() and tsb_context_switch(), then perf_callchain_user() could execute with the context ID of one process, but with an active TSB for a different process. When the user stack is accessed, it is very likely to incur a TLB miss, since the h/w context ID has been changed. The TLB will then be reloaded with a translation from the TSB for one process, but using a context ID for another process. This exposes memory from one process to another, and since it is a mapping for stack memory, this usually causes the new process to crash quickly. This super critical section needs more protection than is provided by spin_lock_irqsave() since perf interrupts must not be allowed in. Since __tsb_context_switch already goes through the trouble of disabling interrupts completely, we fix this by moving the secondary context load down into this better protected region. Orabug: 25577560 Signed-off-by: Dave Aldridge <david.j.aldridge@oracle.com> Signed-off-by: Rob Gardner <rob.gardner@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 938990d commit 6fe71ca

3 files changed

Lines changed: 22 additions & 7 deletions

File tree

arch/sparc/include/asm/mmu_context_64.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ void destroy_context(struct mm_struct *mm);
2525
void __tsb_context_switch(unsigned long pgd_pa,
2626
struct tsb_config *tsb_base,
2727
struct tsb_config *tsb_huge,
28-
unsigned long tsb_descr_pa);
28+
unsigned long tsb_descr_pa,
29+
unsigned long secondary_ctx);
2930

30-
static inline void tsb_context_switch(struct mm_struct *mm)
31+
static inline void tsb_context_switch_ctx(struct mm_struct *mm,
32+
unsigned long ctx)
3133
{
3234
__tsb_context_switch(__pa(mm->pgd),
3335
&mm->context.tsb_block[0],
@@ -38,9 +40,12 @@ static inline void tsb_context_switch(struct mm_struct *mm)
3840
#else
3941
NULL
4042
#endif
41-
, __pa(&mm->context.tsb_descr[0]));
43+
, __pa(&mm->context.tsb_descr[0]),
44+
ctx);
4245
}
4346

47+
#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0)
48+
4449
void tsb_grow(struct mm_struct *mm,
4550
unsigned long tsb_index,
4651
unsigned long mm_rss);
@@ -110,8 +115,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
110115
* cpu0 to update it's TSB because at that point the cpu_vm_mask
111116
* only had cpu1 set in it.
112117
*/
113-
load_secondary_context(mm);
114-
tsb_context_switch(mm);
118+
tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
115119

116120
/* Any time a processor runs a context on an address space
117121
* for the first time, we must flush that context out of the

arch/sparc/kernel/tsb.S

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ tsb_flush:
375375
* %o1: TSB base config pointer
376376
* %o2: TSB huge config pointer, or NULL if none
377377
* %o3: Hypervisor TSB descriptor physical address
378+
* %o4: Secondary context to load, if non-zero
378379
*
379380
* We have to run this whole thing with interrupts
380381
* disabled so that the current cpu doesn't change
@@ -387,6 +388,17 @@ __tsb_context_switch:
387388
rdpr %pstate, %g1
388389
wrpr %g1, PSTATE_IE, %pstate
389390

391+
brz,pn %o4, 1f
392+
mov SECONDARY_CONTEXT, %o5
393+
394+
661: stxa %o4, [%o5] ASI_DMMU
395+
.section .sun4v_1insn_patch, "ax"
396+
.word 661b
397+
stxa %o4, [%o5] ASI_MMU
398+
.previous
399+
flush %g6
400+
401+
1:
390402
TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
391403

392404
stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]

arch/sparc/power/hibernate.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,5 @@ void restore_processor_state(void)
3535
{
3636
struct mm_struct *mm = current->active_mm;
3737

38-
load_secondary_context(mm);
39-
tsb_context_switch(mm);
38+
tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
4039
}

0 commit comments

Comments
 (0)