When an UE or memory error exception is encountered the MCE handler
tries to find the pfn using addr_to_pfn() which takes effective
address as an argument, later pfn is used to poison the page where
memory error occurred, recent rework in this area made addr_to_pfn
to run in realmode, which can be fatal as it may try to access
memory outside RMO region.

To fix this move the use of addr_to_pfn to save_mce_event(), which
runs in virtual mode.

Signed-off-by: Ganesh Goudar <ganes...@linux.ibm.com>
---
 arch/powerpc/kernel/mce.c            |  7 +++++
 arch/powerpc/kernel/mce_power.c      | 39 +++++++---------------------
 arch/powerpc/platforms/pseries/ras.c | 12 ++-------
 3 files changed, 18 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index fd90c0eda229..c5581a742367 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -148,6 +148,13 @@ void save_mce_event(struct pt_regs *regs, long handled,
        } else if (mce->error_type == MCE_ERROR_TYPE_UE) {
                mce->u.ue_error.effective_address_provided = true;
                mce->u.ue_error.effective_address = addr;
+               if (phys_addr == ULONG_MAX && mce->sync_error && addr) {
+                       unsigned long pfn;
+
+                       pfn = addr_to_pfn(regs, addr);
+                       if (pfn != ULONG_MAX)
+                               phys_addr = pfn << PAGE_SHIFT;
+               }
                if (phys_addr != ULONG_MAX) {
                        mce->u.ue_error.physical_address_provided = true;
                        mce->u.ue_error.physical_address = phys_addr;
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index c3b522bff9b4..1b2582818f2b 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -361,8 +361,7 @@ static const struct mce_derror_table mce_p9_derror_table[] 
= {
   MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
 { 0, false, 0, 0, 0, 0, 0 } };
 
-static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
-                                       uint64_t *phys_addr)
+static int mce_find_instr_ea(struct pt_regs *regs, uint64_t *addr)
 {
        /*
         * Carefully look at the NIP to determine
@@ -380,9 +379,7 @@ static int mce_find_instr_ea_and_phys(struct pt_regs *regs, 
uint64_t *addr,
                instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
                instr = ppc_inst_read((struct ppc_inst *)instr_addr);
                if (!analyse_instr(&op, &tmp, instr)) {
-                       pfn = addr_to_pfn(regs, op.ea);
                        *addr = op.ea;
-                       *phys_addr = (pfn << PAGE_SHIFT);
                        return 0;
                }
                /*
@@ -398,8 +395,7 @@ static int mce_find_instr_ea_and_phys(struct pt_regs *regs, 
uint64_t *addr,
 
 static int mce_handle_ierror(struct pt_regs *regs,
                const struct mce_ierror_table table[],
-               struct mce_error_info *mce_err, uint64_t *addr,
-               uint64_t *phys_addr)
+               struct mce_error_info *mce_err, uint64_t *addr)
 {
        uint64_t srr1 = regs->msr;
        int handled = 0;
@@ -455,21 +451,8 @@ static int mce_handle_ierror(struct pt_regs *regs,
                mce_err->sync_error = table[i].sync_error;
                mce_err->severity = table[i].severity;
                mce_err->initiator = table[i].initiator;
-               if (table[i].nip_valid) {
+               if (table[i].nip_valid)
                        *addr = regs->nip;
-                       if (mce_err->sync_error &&
-                               table[i].error_type == MCE_ERROR_TYPE_UE) {
-                               unsigned long pfn;
-
-                               if (get_paca()->in_mce < MAX_MCE_DEPTH) {
-                                       pfn = addr_to_pfn(regs, regs->nip);
-                                       if (pfn != ULONG_MAX) {
-                                               *phys_addr =
-                                                       (pfn << PAGE_SHIFT);
-                                       }
-                               }
-                       }
-               }
                return handled;
        }
 
@@ -484,8 +467,7 @@ static int mce_handle_ierror(struct pt_regs *regs,
 
 static int mce_handle_derror(struct pt_regs *regs,
                const struct mce_derror_table table[],
-               struct mce_error_info *mce_err, uint64_t *addr,
-               uint64_t *phys_addr)
+               struct mce_error_info *mce_err, uint64_t *addr)
 {
        uint64_t dsisr = regs->dsisr;
        int handled = 0;
@@ -562,8 +544,7 @@ static int mce_handle_derror(struct pt_regs *regs,
                         * kernel/exception-64s.h
                         */
                        if (get_paca()->in_mce < MAX_MCE_DEPTH)
-                               mce_find_instr_ea_and_phys(regs, addr,
-                                                          phys_addr);
+                               mce_find_instr_ea(regs, addr);
                }
                found = 1;
        }
@@ -608,21 +589,19 @@ static long mce_handle_error(struct pt_regs *regs,
                const struct mce_ierror_table itable[])
 {
        struct mce_error_info mce_err = { 0 };
-       uint64_t addr, phys_addr = ULONG_MAX;
+       uint64_t addr;
        uint64_t srr1 = regs->msr;
        long handled;
 
        if (SRR1_MC_LOADSTORE(srr1))
-               handled = mce_handle_derror(regs, dtable, &mce_err, &addr,
-                               &phys_addr);
+               handled = mce_handle_derror(regs, dtable, &mce_err, &addr);
        else
-               handled = mce_handle_ierror(regs, itable, &mce_err, &addr,
-                               &phys_addr);
+               handled = mce_handle_ierror(regs, itable, &mce_err, &addr);
 
        if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
                handled = mce_handle_ue_error(regs, &mce_err);
 
-       save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
+       save_mce_event(regs, handled, &mce_err, regs->nip, addr, ULONG_MAX);
 
        return handled;
 }
diff --git a/arch/powerpc/platforms/pseries/ras.c 
b/arch/powerpc/platforms/pseries/ras.c
index f3736fcd98fc..6d64a9fb6130 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -526,7 +526,7 @@ int pSeries_system_reset_exception(struct pt_regs *regs)
 static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
 {
        struct mce_error_info mce_err = { 0 };
-       unsigned long eaddr = 0, paddr = 0;
+       unsigned long eaddr = 0, paddr = ULONG_MAX;
        struct pseries_errorlog *pseries_log;
        struct pseries_mc_errorlog *mce_log;
        int disposition = rtas_error_disposition(errp);
@@ -610,16 +610,8 @@ static int mce_handle_error(struct pt_regs *regs, struct 
rtas_error_log *errp)
                if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED)
                        eaddr = be64_to_cpu(mce_log->effective_address);
 
-               if (mce_log->sub_err_type & UE_LOGICAL_ADDR_PROVIDED) {
+               if (mce_log->sub_err_type & UE_LOGICAL_ADDR_PROVIDED)
                        paddr = be64_to_cpu(mce_log->logical_address);
-               } else if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED) {
-                       unsigned long pfn;
-
-                       pfn = addr_to_pfn(regs, eaddr);
-                       if (pfn != ULONG_MAX)
-                               paddr = pfn << PAGE_SHIFT;
-               }
-
                break;
        case MC_ERROR_TYPE_SLB:
                mce_err.error_type = MCE_ERROR_TYPE_SLB;
-- 
2.17.2

Reply via email to