Commit 6f713d18 authored by Hari Bathini's avatar Hari Bathini Committed by Michael Ellerman

powerpc/opalcore: export /sys/firmware/opal/core for analysing opal crashes

Export /sys/firmware/opal/core file to analyze opal crashes. Since OPAL
core can be generated independent of CONFIG_FA_DUMP support in kernel,
add this support under a new kernel config option CONFIG_OPAL_CORE.
Also, avoid code duplication by moving common code used while exporting
/proc/vmcore and/or /sys/firmware/opal/core file(s).
Signed-off-by: default avatarHari Bathini <hbathini@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/156821378503.5656.3693769384945087756.stgit@hbathini.in.ibm.com
parent 58cf055d
...@@ -592,6 +592,15 @@ config PRESERVE_FA_DUMP ...@@ -592,6 +592,15 @@ config PRESERVE_FA_DUMP
memory preserving kernel boot would process this crash data. memory preserving kernel boot would process this crash data.
Petitboot kernel is the typical usecase for this option. Petitboot kernel is the typical usecase for this option.
config OPAL_CORE
bool "Export OPAL memory as /sys/firmware/opal/core"
depends on PPC64 && PPC_POWERNV
help
This option uses the MPIPL support in firmware to provide an
ELF core of OPAL memory after a crash. The ELF core is exported
as /sys/firmware/opal/core file which is helpful in debugging
OPAL crashes using GDB.
config IRQ_ALL_CPUS config IRQ_ALL_CPUS
bool "Distribute interrupts on all CPUs by default" bool "Distribute interrupts on all CPUs by default"
depends on SMP depends on SMP
......
...@@ -9,6 +9,7 @@ obj-y += ultravisor.o ...@@ -9,6 +9,7 @@ obj-y += ultravisor.o
obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
obj-$(CONFIG_FA_DUMP) += opal-fadump.o obj-$(CONFIG_FA_DUMP) += opal-fadump.o
obj-$(CONFIG_PRESERVE_FA_DUMP) += opal-fadump.o obj-$(CONFIG_PRESERVE_FA_DUMP) += opal-fadump.o
obj-$(CONFIG_OPAL_CORE) += opal-core.o
obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o pci-ioda-tce.o obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o pci-ioda-tce.o
obj-$(CONFIG_CXL_BASE) += pci-cxl.o obj-$(CONFIG_CXL_BASE) += pci-cxl.o
obj-$(CONFIG_EEH) += eeh-powernv.o obj-$(CONFIG_EEH) += eeh-powernv.o
......
This diff is collapsed.
...@@ -85,6 +85,10 @@ static const struct opal_fadump_mem_struct *opal_fdm_active; ...@@ -85,6 +85,10 @@ static const struct opal_fadump_mem_struct *opal_fdm_active;
static const struct opal_mpipl_fadump *opal_cpu_metadata; static const struct opal_mpipl_fadump *opal_cpu_metadata;
static struct opal_fadump_mem_struct *opal_fdm; static struct opal_fadump_mem_struct *opal_fdm;
#ifdef CONFIG_OPAL_CORE
extern bool kernel_initiated;
#endif
static int opal_fadump_unregister(struct fw_dump *fadump_conf); static int opal_fadump_unregister(struct fw_dump *fadump_conf);
static void opal_fadump_update_config(struct fw_dump *fadump_conf, static void opal_fadump_update_config(struct fw_dump *fadump_conf,
...@@ -349,62 +353,6 @@ static void opal_fadump_cleanup(struct fw_dump *fadump_conf) ...@@ -349,62 +353,6 @@ static void opal_fadump_cleanup(struct fw_dump *fadump_conf)
pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret); pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret);
} }
static inline void opal_fadump_set_regval_regnum(struct pt_regs *regs,
u32 reg_type, u32 reg_num,
u64 reg_val)
{
if (reg_type == HDAT_FADUMP_REG_TYPE_GPR) {
if (reg_num < 32)
regs->gpr[reg_num] = reg_val;
return;
}
switch (reg_num) {
case SPRN_CTR:
regs->ctr = reg_val;
break;
case SPRN_LR:
regs->link = reg_val;
break;
case SPRN_XER:
regs->xer = reg_val;
break;
case SPRN_DAR:
regs->dar = reg_val;
break;
case SPRN_DSISR:
regs->dsisr = reg_val;
break;
case HDAT_FADUMP_REG_ID_NIP:
regs->nip = reg_val;
break;
case HDAT_FADUMP_REG_ID_MSR:
regs->msr = reg_val;
break;
case HDAT_FADUMP_REG_ID_CCR:
regs->ccr = reg_val;
break;
}
}
static inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt,
unsigned int reg_entry_size,
struct pt_regs *regs)
{
struct hdat_fadump_reg_entry *reg_entry;
int i;
memset(regs, 0, sizeof(struct pt_regs));
for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
reg_entry = (struct hdat_fadump_reg_entry *)bufp;
opal_fadump_set_regval_regnum(regs,
be32_to_cpu(reg_entry->reg_type),
be32_to_cpu(reg_entry->reg_num),
be64_to_cpu(reg_entry->reg_val));
}
}
/* /*
* Verify if CPU state data is available. If available, do a bit of sanity * Verify if CPU state data is available. If available, do a bit of sanity
* checking before processing this data. * checking before processing this data.
...@@ -529,7 +477,7 @@ opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf, ...@@ -529,7 +477,7 @@ opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf,
continue; continue;
opal_fadump_read_regs((bufp + regs_offset), regs_cnt, opal_fadump_read_regs((bufp + regs_offset), regs_cnt,
reg_esize, &regs); reg_esize, true, &regs);
note_buf = fadump_regs_to_elf_notes(note_buf, &regs); note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
pr_debug("CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n", pr_debug("CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n",
thread_pir, regs.gpr[1], regs.nip); thread_pir, regs.gpr[1], regs.nip);
...@@ -573,6 +521,18 @@ static int __init opal_fadump_process(struct fw_dump *fadump_conf) ...@@ -573,6 +521,18 @@ static int __init opal_fadump_process(struct fw_dump *fadump_conf)
return rc; return rc;
} }
#ifdef CONFIG_OPAL_CORE
/*
* If this is a kernel initiated crash, crashing_cpu would be set
* appropriately and register data of the crashing CPU saved by
* crashing kernel. Add this saved register data of crashing CPU
* to elf notes and populate the pt_regs for the remaining CPUs
* from register state data provided by firmware.
*/
if (fdh->crashing_cpu != FADUMP_CPU_UNKNOWN)
kernel_initiated = true;
#endif
rc = opal_fadump_build_cpu_notes(fadump_conf, fdh); rc = opal_fadump_build_cpu_notes(fadump_conf, fdh);
if (rc) if (rc)
return rc; return rc;
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#ifndef _POWERNV_OPAL_FADUMP_H #ifndef _POWERNV_OPAL_FADUMP_H
#define _POWERNV_OPAL_FADUMP_H #define _POWERNV_OPAL_FADUMP_H
#include <asm/reg.h>
/* /*
* OPAL FADump metadata structure format version * OPAL FADump metadata structure format version
* *
...@@ -77,4 +79,64 @@ struct hdat_fadump_reg_entry { ...@@ -77,4 +79,64 @@ struct hdat_fadump_reg_entry {
__be64 reg_val; __be64 reg_val;
} __packed; } __packed;
static inline void opal_fadump_set_regval_regnum(struct pt_regs *regs,
u32 reg_type, u32 reg_num,
u64 reg_val)
{
if (reg_type == HDAT_FADUMP_REG_TYPE_GPR) {
if (reg_num < 32)
regs->gpr[reg_num] = reg_val;
return;
}
switch (reg_num) {
case SPRN_CTR:
regs->ctr = reg_val;
break;
case SPRN_LR:
regs->link = reg_val;
break;
case SPRN_XER:
regs->xer = reg_val;
break;
case SPRN_DAR:
regs->dar = reg_val;
break;
case SPRN_DSISR:
regs->dsisr = reg_val;
break;
case HDAT_FADUMP_REG_ID_NIP:
regs->nip = reg_val;
break;
case HDAT_FADUMP_REG_ID_MSR:
regs->msr = reg_val;
break;
case HDAT_FADUMP_REG_ID_CCR:
regs->ccr = reg_val;
break;
}
}
static inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt,
unsigned int reg_entry_size,
bool cpu_endian,
struct pt_regs *regs)
{
struct hdat_fadump_reg_entry *reg_entry;
u64 val;
int i;
memset(regs, 0, sizeof(struct pt_regs));
for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
reg_entry = (struct hdat_fadump_reg_entry *)bufp;
val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) :
reg_entry->reg_val);
opal_fadump_set_regval_regnum(regs,
be32_to_cpu(reg_entry->reg_type),
be32_to_cpu(reg_entry->reg_num),
val);
}
}
#endif /* _POWERNV_OPAL_FADUMP_H */ #endif /* _POWERNV_OPAL_FADUMP_H */
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