* [PATCH] powerpc/mce: Avoid using addr_to_pfn in realmode
@ 2020-06-20 12:44 Ganesh Goudar
2020-06-22 2:16 ` Nicholas Piggin
0 siblings, 1 reply; 2+ messages in thread
From: Ganesh Goudar @ 2020-06-20 12:44 UTC (permalink / raw)
To: mpe, linuxppc-dev; +Cc: mahesh, Ganesh Goudar, npiggin, aneesh.kumar
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 <ganeshgr@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
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] powerpc/mce: Avoid using addr_to_pfn in realmode
2020-06-20 12:44 [PATCH] powerpc/mce: Avoid using addr_to_pfn in realmode Ganesh Goudar
@ 2020-06-22 2:16 ` Nicholas Piggin
0 siblings, 0 replies; 2+ messages in thread
From: Nicholas Piggin @ 2020-06-22 2:16 UTC (permalink / raw)
To: Ganesh Goudar, linuxppc-dev, mpe; +Cc: aneesh.kumar, mahesh
Excerpts from Ganesh Goudar's message of June 20, 2020 10:44 pm:
> 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.
I'd rather this be done in the pseries mce handler rather than
change bare metal, and leaving save_mce_event as purely recording the
event, decoding remains in its caller.
Radix guests also don't have an RMO, we could probably restrict that
pseries hack to hash. I want to get rid of it but it will take longer
to fix things properly.
Thanks,
Nick
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-06-22 2:18 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-20 12:44 [PATCH] powerpc/mce: Avoid using addr_to_pfn in realmode Ganesh Goudar
2020-06-22 2:16 ` Nicholas Piggin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.