Commit ebaeb5ae authored by Mahesh Salgaonkar's avatar Mahesh Salgaonkar Committed by Benjamin Herrenschmidt

fadump: Convert firmware-assisted cpu state dump data into elf notes.

When registered for firmware assisted dump on powerpc, firmware preserves
the registers for the active CPUs during a system crash. This patch reads
the cpu register data stored in Firmware-assisted dump format (except for
crashing cpu) and converts it into elf notes and updates the PT_NOTE program
header accordingly. The exact register state for crashing cpu is saved to
fadump crash info structure in scratch area during crash_fadump() and read
during second kernel boot.
Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 2df173d9
...@@ -65,6 +65,18 @@ ...@@ -65,6 +65,18 @@
/* Dump status flag */ /* Dump status flag */
#define FADUMP_ERROR_FLAG 0x2000 #define FADUMP_ERROR_FLAG 0x2000
#define FADUMP_CPU_ID_MASK ((1UL << 32) - 1)
#define CPU_UNKNOWN (~((u32)0))
/* Utility macros */
#define SKIP_TO_NEXT_CPU(reg_entry) \
({ \
while (reg_entry->reg_id != REG_ID("CPUEND")) \
reg_entry++; \
reg_entry++; \
})
/* Kernel Dump section info */ /* Kernel Dump section info */
struct fadump_section { struct fadump_section {
u32 request_flag; u32 request_flag;
...@@ -119,6 +131,9 @@ struct fw_dump { ...@@ -119,6 +131,9 @@ struct fw_dump {
unsigned long reserve_bootvar; unsigned long reserve_bootvar;
unsigned long fadumphdr_addr; unsigned long fadumphdr_addr;
unsigned long cpu_notes_buf;
unsigned long cpu_notes_buf_size;
int ibm_configure_kernel_dump; int ibm_configure_kernel_dump;
unsigned long fadump_enabled:1; unsigned long fadump_enabled:1;
...@@ -143,13 +158,40 @@ static inline u64 str_to_u64(const char *str) ...@@ -143,13 +158,40 @@ static inline u64 str_to_u64(const char *str)
return val; return val;
} }
#define STR_TO_HEX(x) str_to_u64(x) #define STR_TO_HEX(x) str_to_u64(x)
#define REG_ID(x) str_to_u64(x)
#define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF") #define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF")
#define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE")
/* The firmware-assisted dump format.
*
* The register save area is an area in the partition's memory used to preserve
* the register contents (CPU state data) for the active CPUs during a firmware
* assisted dump. The dump format contains register save area header followed
* by register entries. Each list of registers for a CPU starts with
* "CPUSTRT" and ends with "CPUEND".
*/
/* Register save area header. */
struct fadump_reg_save_area_header {
u64 magic_number;
u32 version;
u32 num_cpu_offset;
};
/* Register entry. */
struct fadump_reg_entry {
u64 reg_id;
u64 reg_value;
};
/* fadump crash info structure */ /* fadump crash info structure */
struct fadump_crash_info_header { struct fadump_crash_info_header {
u64 magic_number; u64 magic_number;
u64 elfcorehdr_addr; u64 elfcorehdr_addr;
u32 crashing_cpu;
struct pt_regs regs;
struct cpumask cpu_online_mask;
}; };
/* Crash memory ranges */ /* Crash memory ranges */
...@@ -165,7 +207,9 @@ extern int early_init_dt_scan_fw_dump(unsigned long node, ...@@ -165,7 +207,9 @@ extern int early_init_dt_scan_fw_dump(unsigned long node,
extern int fadump_reserve_mem(void); extern int fadump_reserve_mem(void);
extern int setup_fadump(void); extern int setup_fadump(void);
extern int is_fadump_active(void); extern int is_fadump_active(void);
extern void crash_fadump(struct pt_regs *, const char *);
#else /* CONFIG_FA_DUMP */ #else /* CONFIG_FA_DUMP */
static inline int is_fadump_active(void) { return 0; } static inline int is_fadump_active(void) { return 0; }
static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
#endif #endif
#endif #endif
This diff is collapsed.
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include <asm/xmon.h> #include <asm/xmon.h>
#include <asm/cputhreads.h> #include <asm/cputhreads.h>
#include <mm/mmu_decl.h> #include <mm/mmu_decl.h>
#include <asm/fadump.h>
#include "setup.h" #include "setup.h"
...@@ -639,6 +640,11 @@ EXPORT_SYMBOL(check_legacy_ioport); ...@@ -639,6 +640,11 @@ EXPORT_SYMBOL(check_legacy_ioport);
static int ppc_panic_event(struct notifier_block *this, static int ppc_panic_event(struct notifier_block *this,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
/*
* If firmware-assisted dump has been registered then trigger
* firmware-assisted dump and let firmware handle everything else.
*/
crash_fadump(NULL, ptr);
ppc_md.panic(ptr); /* May not return */ ppc_md.panic(ptr); /* May not return */
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <asm/kexec.h> #include <asm/kexec.h>
#include <asm/ppc-opcode.h> #include <asm/ppc-opcode.h>
#include <asm/rio.h> #include <asm/rio.h>
#include <asm/fadump.h>
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
int (*__debugger)(struct pt_regs *regs) __read_mostly; int (*__debugger)(struct pt_regs *regs) __read_mostly;
...@@ -145,6 +146,8 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, ...@@ -145,6 +146,8 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
arch_spin_unlock(&die_lock); arch_spin_unlock(&die_lock);
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
crash_fadump(regs, "die oops");
/* /*
* A system reset (0x100) is a request to dump, so we always send * A system reset (0x100) is a request to dump, so we always send
* it through the crashdump code. * it through the crashdump code.
......
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