On 09/03/2014 05:59 PM, Hari Bathini wrote: > Firmware-assisted dump (fadump) kernel code is not LE compliant. The > below patch tries to fix this issue. Tested this patch with upstream > kernel. Did some sanity testing for the LE fadump vmcore generated. > Below output shows crash tool successfully opening LE fadump vmcore. > > # crash $vmlinux vmcore > > crash 7.0.5 > Copyright (C) 2002-2014 Red Hat, Inc. > Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation > Copyright (C) 1999-2006 Hewlett-Packard Co > Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited > Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. > Copyright (C) 2005, 2011 NEC Corporation > Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. > Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. > This program is free software, covered by the GNU General Public > License, > and you are welcome to change it and/or distribute copies of it under > certain conditions. Enter "help copying" to see the conditions. > This program has absolutely no warranty. Enter "help warranty" for > details. > > crash: /boot/vmlinux-3.16.0-rc7-7-default+: no .gnu_debuglink section > GNU gdb (GDB) 7.6 > Copyright (C) 2013 Free Software Foundation, Inc. > License GPLv3+: GNU GPL version 3 or later > <http://gnu.org/licenses/gpl.html> > This is free software: you are free to change and redistribute it. > There is NO WARRANTY, to the extent permitted by law. Type "show > copying" > and "show warranty" for details. > This GDB was configured as "powerpc64le-unknown-linux-gnu"... > > KERNEL: /boot/vmlinux-3.16.0-rc7-7-default+ > DUMPFILE: vmcore > CPUS: 16 > DATE: Sun Aug 24 14:31:28 2014 > UPTIME: 00:02:57 > LOAD AVERAGE: 0.05, 0.08, 0.04 > TASKS: 256 > NODENAME: linux-dhr2 > RELEASE: 3.16.0-rc7-7-default+ > VERSION: #54 SMP Mon Aug 18 14:08:23 EDT 2014 > MACHINE: ppc64le (4116 Mhz) > MEMORY: 40 GB > PANIC: "Oops: Kernel access of bad area, sig: 11 [#1]" (check > log for details) > PID: 2234 > COMMAND: "bash" > TASK: c0000009652e4a30 [THREAD_INFO: c00000096777c000] > CPU: 2 > STATE: TASK_RUNNING (PANIC) > > crash> > > Signed-off-by: Hari Bathini <hbath...@linux.vnet.ibm.com>
Reviewed-by: Mahesh Salgaonkar <mah...@linux.vnet.ibm.com> > --- > arch/powerpc/include/asm/fadump.h | 52 ++++++++------- > arch/powerpc/kernel/fadump.c | 112 > +++++++++++++++++---------------- > arch/powerpc/platforms/pseries/lpar.c | 9 ++- > 3 files changed, 89 insertions(+), 84 deletions(-) > > diff --git a/arch/powerpc/include/asm/fadump.h > b/arch/powerpc/include/asm/fadump.h > index a677456..493e72f 100644 > --- a/arch/powerpc/include/asm/fadump.h > +++ b/arch/powerpc/include/asm/fadump.h > @@ -70,39 +70,39 @@ > #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++; \ > +#define SKIP_TO_NEXT_CPU(reg_entry) \ > +({ \ > + while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) \ > + reg_entry++; \ > + reg_entry++; \ > }) > > /* Kernel Dump section info */ > struct fadump_section { > - u32 request_flag; > - u16 source_data_type; > - u16 error_flags; > - u64 source_address; > - u64 source_len; > - u64 bytes_dumped; > - u64 destination_address; > + __be32 request_flag; > + __be16 source_data_type; > + __be16 error_flags; > + __be64 source_address; > + __be64 source_len; > + __be64 bytes_dumped; > + __be64 destination_address; > }; > > /* ibm,configure-kernel-dump header. */ > struct fadump_section_header { > - u32 dump_format_version; > - u16 dump_num_sections; > - u16 dump_status_flag; > - u32 offset_first_dump_section; > + __be32 dump_format_version; > + __be16 dump_num_sections; > + __be16 dump_status_flag; > + __be32 offset_first_dump_section; > > /* Fields for disk dump option. */ > - u32 dd_block_size; > - u64 dd_block_offset; > - u64 dd_num_blocks; > - u32 dd_offset_disk_path; > + __be32 dd_block_size; > + __be64 dd_block_offset; > + __be64 dd_num_blocks; > + __be32 dd_offset_disk_path; > > /* Maximum time allowed to prevent an automatic dump-reboot. */ > - u32 max_time_auto; > + __be32 max_time_auto; > }; > > /* > @@ -174,15 +174,15 @@ static inline u64 str_to_u64(const char *str) > > /* Register save area header. */ > struct fadump_reg_save_area_header { > - u64 magic_number; > - u32 version; > - u32 num_cpu_offset; > + __be64 magic_number; > + __be32 version; > + __be32 num_cpu_offset; > }; > > /* Register entry. */ > struct fadump_reg_entry { > - u64 reg_id; > - u64 reg_value; > + __be64 reg_id; > + __be64 reg_value; > }; > > /* fadump crash info structure */ > diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c > index 742694c..7d73b2d 100644 > --- a/arch/powerpc/kernel/fadump.c > +++ b/arch/powerpc/kernel/fadump.c > @@ -72,7 +72,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, > return 1; > > fw_dump.fadump_supported = 1; > - fw_dump.ibm_configure_kernel_dump = *token; > + fw_dump.ibm_configure_kernel_dump = be32_to_cpu(*token); > > /* > * The 'ibm,kernel-dump' rtas node is present only if there is > @@ -147,11 +147,11 @@ static unsigned long init_fadump_mem_struct(struct > fadump_mem_struct *fdm, > memset(fdm, 0, sizeof(struct fadump_mem_struct)); > addr = addr & PAGE_MASK; > > - fdm->header.dump_format_version = 0x00000001; > - fdm->header.dump_num_sections = 3; > + fdm->header.dump_format_version = cpu_to_be32(0x00000001); > + fdm->header.dump_num_sections = cpu_to_be16(3); > fdm->header.dump_status_flag = 0; > fdm->header.offset_first_dump_section = > - (u32)offsetof(struct fadump_mem_struct, cpu_state_data); > + cpu_to_be32((u32)offsetof(struct fadump_mem_struct, > cpu_state_data)); > > /* > * Fields for disk dump option. > @@ -167,27 +167,27 @@ static unsigned long init_fadump_mem_struct(struct > fadump_mem_struct *fdm, > > /* Kernel dump sections */ > /* cpu state data section. */ > - fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG; > - fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA; > + fdm->cpu_state_data.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); > + fdm->cpu_state_data.source_data_type = > cpu_to_be16(FADUMP_CPU_STATE_DATA); > fdm->cpu_state_data.source_address = 0; > - fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size; > - fdm->cpu_state_data.destination_address = addr; > + fdm->cpu_state_data.source_len = > cpu_to_be64(fw_dump.cpu_state_data_size); > + fdm->cpu_state_data.destination_address = cpu_to_be64(addr); > addr += fw_dump.cpu_state_data_size; > > /* hpte region section */ > - fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG; > - fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION; > + fdm->hpte_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); > + fdm->hpte_region.source_data_type = cpu_to_be16(FADUMP_HPTE_REGION); > fdm->hpte_region.source_address = 0; > - fdm->hpte_region.source_len = fw_dump.hpte_region_size; > - fdm->hpte_region.destination_address = addr; > + fdm->hpte_region.source_len = cpu_to_be64(fw_dump.hpte_region_size); > + fdm->hpte_region.destination_address = cpu_to_be64(addr); > addr += fw_dump.hpte_region_size; > > /* RMA region section */ > - fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG; > - fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION; > - fdm->rmr_region.source_address = RMA_START; > - fdm->rmr_region.source_len = fw_dump.boot_memory_size; > - fdm->rmr_region.destination_address = addr; > + fdm->rmr_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); > + fdm->rmr_region.source_data_type = cpu_to_be16(FADUMP_REAL_MODE_REGION); > + fdm->rmr_region.source_address = cpu_to_be64(RMA_START); > + fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size); > + fdm->rmr_region.destination_address = cpu_to_be64(addr); > addr += fw_dump.boot_memory_size; > > return addr; > @@ -272,7 +272,7 @@ int __init fadump_reserve_mem(void) > * first kernel. > */ > if (fdm_active) > - fw_dump.boot_memory_size = fdm_active->rmr_region.source_len; > + fw_dump.boot_memory_size = > be64_to_cpu(fdm_active->rmr_region.source_len); > else > fw_dump.boot_memory_size = fadump_calculate_reserve_size(); > > @@ -314,8 +314,8 @@ int __init fadump_reserve_mem(void) > (unsigned long)(base >> 20)); > > fw_dump.fadumphdr_addr = > - fdm_active->rmr_region.destination_address + > - fdm_active->rmr_region.source_len; > + > be64_to_cpu(fdm_active->rmr_region.destination_address) + > + be64_to_cpu(fdm_active->rmr_region.source_len); > pr_debug("fadumphdr_addr = %p\n", > (void *) fw_dump.fadumphdr_addr); > } else { > @@ -472,9 +472,9 @@ fadump_read_registers(struct fadump_reg_entry *reg_entry, > struct pt_regs *regs) > { > memset(regs, 0, sizeof(struct pt_regs)); > > - while (reg_entry->reg_id != REG_ID("CPUEND")) { > - fadump_set_regval(regs, reg_entry->reg_id, > - reg_entry->reg_value); > + while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) { > + fadump_set_regval(regs, be64_to_cpu(reg_entry->reg_id), > + be64_to_cpu(reg_entry->reg_value)); > reg_entry++; > } > reg_entry++; > @@ -603,20 +603,20 @@ static int __init fadump_build_cpu_notes(const struct > fadump_mem_struct *fdm) > if (!fdm->cpu_state_data.bytes_dumped) > return -EINVAL; > > - addr = fdm->cpu_state_data.destination_address; > + addr = be64_to_cpu(fdm->cpu_state_data.destination_address); > vaddr = __va(addr); > > reg_header = vaddr; > - if (reg_header->magic_number != REGSAVE_AREA_MAGIC) { > + if (be64_to_cpu(reg_header->magic_number) != REGSAVE_AREA_MAGIC) { > printk(KERN_ERR "Unable to read register save area.\n"); > return -ENOENT; > } > pr_debug("--------CPU State Data------------\n"); > - pr_debug("Magic Number: %llx\n", reg_header->magic_number); > - pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset); > + pr_debug("Magic Number: %llx\n", be64_to_cpu(reg_header->magic_number)); > + pr_debug("NumCpuOffset: %x\n", be32_to_cpu(reg_header->num_cpu_offset)); > > - vaddr += reg_header->num_cpu_offset; > - num_cpus = *((u32 *)(vaddr)); > + vaddr += be32_to_cpu(reg_header->num_cpu_offset); > + num_cpus = be32_to_cpu(*((u32 *)(vaddr))); > pr_debug("NumCpus : %u\n", num_cpus); > vaddr += sizeof(u32); > reg_entry = (struct fadump_reg_entry *)vaddr; > @@ -639,13 +639,13 @@ static int __init fadump_build_cpu_notes(const struct > fadump_mem_struct *fdm) > fdh = __va(fw_dump.fadumphdr_addr); > > for (i = 0; i < num_cpus; i++) { > - if (reg_entry->reg_id != REG_ID("CPUSTRT")) { > + if (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUSTRT")) { > printk(KERN_ERR "Unable to read CPU state data\n"); > rc = -ENOENT; > goto error_out; > } > /* Lower 4 bytes of reg_value contains logical cpu id */ > - cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK; > + cpu = be64_to_cpu(reg_entry->reg_value) & FADUMP_CPU_ID_MASK; > if (fdh && !cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) { > SKIP_TO_NEXT_CPU(reg_entry); > continue; > @@ -692,7 +692,7 @@ static int __init process_fadump(const struct > fadump_mem_struct *fdm_active) > return -EINVAL; > > /* Check if the dump data is valid. */ > - if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) || > + if ((be16_to_cpu(fdm_active->header.dump_status_flag) == > FADUMP_ERROR_FLAG) || > (fdm_active->cpu_state_data.error_flags != 0) || > (fdm_active->rmr_region.error_flags != 0)) { > printk(KERN_ERR "Dump taken by platform is not valid\n"); > @@ -828,7 +828,7 @@ static void fadump_setup_crash_memory_ranges(void) > static inline unsigned long fadump_relocate(unsigned long paddr) > { > if (paddr > RMA_START && paddr < fw_dump.boot_memory_size) > - return fdm.rmr_region.destination_address + paddr; > + return be64_to_cpu(fdm.rmr_region.destination_address) + paddr; > else > return paddr; > } > @@ -902,7 +902,7 @@ static int fadump_create_elfcore_headers(char *bufp) > * to the specified destination_address. Hence set > * the correct offset. > */ > - phdr->p_offset = fdm.rmr_region.destination_address; > + phdr->p_offset = > be64_to_cpu(fdm.rmr_region.destination_address); > } > > phdr->p_paddr = mbase; > @@ -951,7 +951,7 @@ static void register_fadump(void) > > fadump_setup_crash_memory_ranges(); > > - addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len; > + addr = be64_to_cpu(fdm.rmr_region.destination_address) + > be64_to_cpu(fdm.rmr_region.source_len); > /* Initialize fadump crash info header. */ > addr = init_fadump_header(addr); > vaddr = __va(addr); > @@ -1023,7 +1023,7 @@ void fadump_cleanup(void) > /* Invalidate the registration only if dump is active. */ > if (fw_dump.dump_active) { > init_fadump_mem_struct(&fdm, > - fdm_active->cpu_state_data.destination_address); > + > be64_to_cpu(fdm_active->cpu_state_data.destination_address)); > fadump_invalidate_dump(&fdm); > } > } > @@ -1063,7 +1063,7 @@ static void fadump_invalidate_release_mem(void) > return; > } > > - destination_address = fdm_active->cpu_state_data.destination_address; > + destination_address = > be64_to_cpu(fdm_active->cpu_state_data.destination_address); > fadump_cleanup(); > mutex_unlock(&fadump_mutex); > > @@ -1183,31 +1183,31 @@ static int fadump_region_show(struct seq_file *m, > void *private) > seq_printf(m, > "CPU : [%#016llx-%#016llx] %#llx bytes, " > "Dumped: %#llx\n", > - fdm_ptr->cpu_state_data.destination_address, > - fdm_ptr->cpu_state_data.destination_address + > - fdm_ptr->cpu_state_data.source_len - 1, > - fdm_ptr->cpu_state_data.source_len, > - fdm_ptr->cpu_state_data.bytes_dumped); > + > be64_to_cpu(fdm_ptr->cpu_state_data.destination_address), > + > be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) + > + be64_to_cpu(fdm_ptr->cpu_state_data.source_len) - 1, > + be64_to_cpu(fdm_ptr->cpu_state_data.source_len), > + be64_to_cpu(fdm_ptr->cpu_state_data.bytes_dumped)); > seq_printf(m, > "HPTE: [%#016llx-%#016llx] %#llx bytes, " > "Dumped: %#llx\n", > - fdm_ptr->hpte_region.destination_address, > - fdm_ptr->hpte_region.destination_address + > - fdm_ptr->hpte_region.source_len - 1, > - fdm_ptr->hpte_region.source_len, > - fdm_ptr->hpte_region.bytes_dumped); > + be64_to_cpu(fdm_ptr->hpte_region.destination_address), > + be64_to_cpu(fdm_ptr->hpte_region.destination_address) + > + be64_to_cpu(fdm_ptr->hpte_region.source_len) - 1, > + be64_to_cpu(fdm_ptr->hpte_region.source_len), > + be64_to_cpu(fdm_ptr->hpte_region.bytes_dumped)); > seq_printf(m, > "DUMP: [%#016llx-%#016llx] %#llx bytes, " > "Dumped: %#llx\n", > - fdm_ptr->rmr_region.destination_address, > - fdm_ptr->rmr_region.destination_address + > - fdm_ptr->rmr_region.source_len - 1, > - fdm_ptr->rmr_region.source_len, > - fdm_ptr->rmr_region.bytes_dumped); > + be64_to_cpu(fdm_ptr->rmr_region.destination_address), > + be64_to_cpu(fdm_ptr->rmr_region.destination_address) + > + be64_to_cpu(fdm_ptr->rmr_region.source_len) - 1, > + be64_to_cpu(fdm_ptr->rmr_region.source_len), > + be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped)); > > if (!fdm_active || > (fw_dump.reserve_dump_area_start == > - fdm_ptr->cpu_state_data.destination_address)) > + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address))) > goto out; > > /* Dump is active. Show reserved memory region. */ > @@ -1215,10 +1215,10 @@ static int fadump_region_show(struct seq_file *m, > void *private) > " : [%#016llx-%#016llx] %#llx bytes, " > "Dumped: %#llx\n", > (unsigned long long)fw_dump.reserve_dump_area_start, > - fdm_ptr->cpu_state_data.destination_address - 1, > - fdm_ptr->cpu_state_data.destination_address - > + > be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - 1, > + > be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - > fw_dump.reserve_dump_area_start, > - fdm_ptr->cpu_state_data.destination_address - > + > be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - > fw_dump.reserve_dump_area_start); > out: > if (fdm_active) > diff --git a/arch/powerpc/platforms/pseries/lpar.c > b/arch/powerpc/platforms/pseries/lpar.c > index 34e6423..587887e 100644 > --- a/arch/powerpc/platforms/pseries/lpar.c > +++ b/arch/powerpc/platforms/pseries/lpar.c > @@ -43,6 +43,7 @@ > #include <asm/trace.h> > #include <asm/firmware.h> > #include <asm/plpar_wrappers.h> > +#include <asm/fadump.h> > > #include "pseries.h" > > @@ -249,8 +250,12 @@ static void pSeries_lpar_hptab_clear(void) > } > > #ifdef __LITTLE_ENDIAN__ > - /* Reset exceptions to big endian */ > - if (firmware_has_feature(FW_FEATURE_SET_MODE)) { > + /* > + * Reset exceptions to big endian > + * During fadump kernel boot, we dont need to reset exception to big > endian > + * as we have already booted into LE kernel. > + */ > + if (firmware_has_feature(FW_FEATURE_SET_MODE) && !is_fadump_active()) { > long rc; > > rc = pseries_big_endian_exceptions(); > _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev