Commit 429d2e83 authored by Mahesh Salgaonkar's avatar Mahesh Salgaonkar Committed by Benjamin Herrenschmidt

powerpc: Fix kdump hang issue on p8 with relocation on exception enabled.

On p8 systems, with relocation on exception feature enabled we are seeing
kdump kernel hang at interrupt vector 0xc*4400. The reason is, with this
feature enabled, exception are raised with MMU (IR=DR=1) ON with the
default offset of 0xc*4000. Since exception is raised in virtual mode it
requires the vector region to be executable without which it fails to
fetch and execute instruction at 0xc*4xxx. For default kernel since kernel
is loaded at real 0, the htab mappings sets the entire kernel text region
executable. But for relocatable kernel (e.g. kdump case) we only copy
interrupt vectors down to real 0 and never marked that region as
executable because in p7 and below we always get exception in real mode.

This patch fixes this issue by marking htab mapping range as executable
that overlaps with the interrupt vector region for relocatable kernel.

Thanks to Ben who helped me to debug this issue and find the root cause.
Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 3ec8b78f
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#ifdef __powerpc64__ #ifdef __powerpc64__
extern char __start_interrupts[];
extern char __end_interrupts[]; extern char __end_interrupts[];
extern char __prom_init_toc_start[]; extern char __prom_init_toc_start[];
...@@ -21,6 +22,17 @@ static inline int in_kernel_text(unsigned long addr) ...@@ -21,6 +22,17 @@ static inline int in_kernel_text(unsigned long addr)
return 0; return 0;
} }
static inline int overlaps_interrupt_vector_text(unsigned long start,
unsigned long end)
{
unsigned long real_start, real_end;
real_start = __start_interrupts - _stext;
real_end = __end_interrupts - _stext;
return start < (unsigned long)__va(real_end) &&
(unsigned long)__va(real_start) < end;
}
static inline int overlaps_kernel_text(unsigned long start, unsigned long end) static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
{ {
return start < (unsigned long)__init_end && return start < (unsigned long)__init_end &&
......
...@@ -207,6 +207,20 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, ...@@ -207,6 +207,20 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
if (overlaps_kernel_text(vaddr, vaddr + step)) if (overlaps_kernel_text(vaddr, vaddr + step))
tprot &= ~HPTE_R_N; tprot &= ~HPTE_R_N;
/*
* If relocatable, check if it overlaps interrupt vectors that
* are copied down to real 0. For relocatable kernel
* (e.g. kdump case) we copy interrupt vectors down to real
* address 0. Mark that region as executable. This is
* because on p8 system with relocation on exception feature
* enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence
* in order to execute the interrupt handlers in virtual
* mode the vector region need to be marked as executable.
*/
if ((PHYSICAL_START > MEMORY_START) &&
overlaps_interrupt_vector_text(vaddr, vaddr + step))
tprot &= ~HPTE_R_N;
hash = hpt_hash(vpn, shift, ssize); hash = hpt_hash(vpn, shift, ssize);
hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment