| From 8ed8ab40047a570fdd8043a40c104a57248dd3fd Mon Sep 17 00:00:00 2001 |
| From: Hari Bathini <hbathini@linux.vnet.ibm.com> |
| Date: Fri, 15 Apr 2016 22:48:02 +1000 |
| Subject: powerpc/book3s64: Fix branching to OOL handlers in relocatable kernel |
| |
| From: Hari Bathini <hbathini@linux.vnet.ibm.com> |
| |
| commit 8ed8ab40047a570fdd8043a40c104a57248dd3fd upstream. |
| |
| Some of the interrupt vectors on 64-bit POWER server processors are only |
| 32 bytes long (8 instructions), which is not enough for the full |
| first-level interrupt handler. For these we need to branch to an |
| out-of-line (OOL) handler. But when we are running a relocatable kernel, |
| interrupt vectors till __end_interrupts marker are copied down to real |
| address 0x100. So, branching to labels (ie. OOL handlers) outside this |
| section must be handled differently (see LOAD_HANDLER()), considering |
| relocatable kernel, which would need at least 4 instructions. |
| |
| However, branching from interrupt vector means that we corrupt the |
| CFAR (come-from address register) on POWER7 and later processors as |
| mentioned in commit 1707dd16. So, EXCEPTION_PROLOG_0 (6 instructions) |
| that contains the part up to the point where the CFAR is saved in the |
| PACA should be part of the short interrupt vectors before we branch out |
| to OOL handlers. |
| |
| But as mentioned already, there are interrupt vectors on 64-bit POWER |
| server processors that are only 32 bytes long (like vectors 0x4f00, |
| 0x4f20, etc.), which cannot accomodate the above two cases at the same |
| time owing to space constraint. Currently, in these interrupt vectors, |
| we simply branch out to OOL handlers, without using LOAD_HANDLER(), |
| which leaves us vulnerable when running a relocatable kernel (eg. kdump |
| case). While this has been the case for sometime now and kdump is used |
| widely, we were fortunate not to see any problems so far, for three |
| reasons: |
| |
| 1. In almost all cases, production kernel (relocatable) is used for |
| kdump as well, which would mean that crashed kernel's OOL handler |
| would be at the same place where we end up branching to, from short |
| interrupt vector of kdump kernel. |
| 2. Also, OOL handler was unlikely the reason for crash in almost all |
| the kdump scenarios, which meant we had a sane OOL handler from |
| crashed kernel that we branched to. |
| 3. On most 64-bit POWER server processors, page size is large enough |
| that marking interrupt vector code as executable (see commit |
| 429d2e83) leads to marking OOL handler code from crashed kernel, |
| that sits right below interrupt vector code from kdump kernel, as |
| executable as well. |
| |
| Let us fix this by moving the __end_interrupts marker down past OOL |
| handlers to make sure that we also copy OOL handlers to real address |
| 0x100 when running a relocatable kernel. |
| |
| This fix has been tested successfully in kdump scenario, on an LPAR with |
| 4K page size by using different default/production kernel and kdump |
| kernel. |
| |
| Also tested by manually corrupting the OOL handlers in the first kernel |
| and then kdump'ing, and then causing the OOL handlers to fire - mpe. |
| |
| Fixes: c1fb6816fb1b ("powerpc: Add relocation on exception vector handlers") |
| Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com> |
| Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kernel/exceptions-64s.S | 16 +++++++++++----- |
| 1 file changed, 11 insertions(+), 5 deletions(-) |
| |
| --- a/arch/powerpc/kernel/exceptions-64s.S |
| +++ b/arch/powerpc/kernel/exceptions-64s.S |
| @@ -953,11 +953,6 @@ hv_facility_unavailable_relon_trampoline |
| #endif |
| STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist) |
| |
| - /* Other future vectors */ |
| - .align 7 |
| - .globl __end_interrupts |
| -__end_interrupts: |
| - |
| .align 7 |
| system_call_entry: |
| b system_call_common |
| @@ -1244,6 +1239,17 @@ __end_handlers: |
| STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable) |
| STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable) |
| |
| + /* |
| + * The __end_interrupts marker must be past the out-of-line (OOL) |
| + * handlers, so that they are copied to real address 0x100 when running |
| + * a relocatable kernel. This ensures they can be reached from the short |
| + * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch |
| + * directly, without using LOAD_HANDLER(). |
| + */ |
| + .align 7 |
| + .globl __end_interrupts |
| +__end_interrupts: |
| + |
| #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) |
| /* |
| * Data area reserved for FWNMI option. |