diff mbox series

[RFC,2/3] powerpc/fadump: pass additional parameters to dump capture kernel

Message ID 20231205201835.388030-3-hbathini@linux.ibm.com (mailing list archive)
State New
Headers show
Series powerpc/fadump: pass additional args to dump capture kernel | expand

Commit Message

Hari Bathini Dec. 5, 2023, 8:18 p.m. UTC
For fadump case, passing additional parameters to dump capture kernel
helps in minimizing the memory footprint for it and also provides the
flexibility to disable components/modules, like hugepages, that are
hindering the boot process of the special dump capture environment.

Set up a dedicated parameter area to be passed to the capture kernel.
This area type is defined as RTAS_FADUMP_PARAM_AREA. Sysfs attribute
'/sys/kernel/fadump/bootargs_append' is exported to the userspace to
specify the additional parameters to be passed to the capture kernel

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
 arch/powerpc/include/asm/fadump-internal.h   |  3 +
 arch/powerpc/kernel/fadump.c                 | 80 ++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-fadump.c |  6 +-
 arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++-
 arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++-
 5 files changed, 126 insertions(+), 9 deletions(-)

Comments

Sourabh Jain Dec. 15, 2023, 8:42 a.m. UTC | #1
Hello Hari,

On 06/12/23 01:48, Hari Bathini wrote:
> For fadump case, passing additional parameters to dump capture kernel
> helps in minimizing the memory footprint for it and also provides the
> flexibility to disable components/modules, like hugepages, that are
> hindering the boot process of the special dump capture environment.
>
> Set up a dedicated parameter area to be passed to the capture kernel.
> This area type is defined as RTAS_FADUMP_PARAM_AREA. Sysfs attribute
> '/sys/kernel/fadump/bootargs_append' is exported to the userspace to
> specify the additional parameters to be passed to the capture kernel
>
> Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
> ---
>   arch/powerpc/include/asm/fadump-internal.h   |  3 +
>   arch/powerpc/kernel/fadump.c                 | 80 ++++++++++++++++++++
>   arch/powerpc/platforms/powernv/opal-fadump.c |  6 +-
>   arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++-
>   arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++-
>   5 files changed, 126 insertions(+), 9 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h
> index b3956c400519..81629226b15f 100644
> --- a/arch/powerpc/include/asm/fadump-internal.h
> +++ b/arch/powerpc/include/asm/fadump-internal.h
> @@ -97,6 +97,8 @@ struct fw_dump {
>   	unsigned long	cpu_notes_buf_vaddr;
>   	unsigned long	cpu_notes_buf_size;
>   
> +	unsigned long	param_area;
> +
>   	/*
>   	 * Maximum size supported by firmware to copy from source to
>   	 * destination address per entry.
> @@ -111,6 +113,7 @@ struct fw_dump {
>   	unsigned long	dump_active:1;
>   	unsigned long	dump_registered:1;
>   	unsigned long	nocma:1;
> +	unsigned long	param_area_supported:1;
>   
>   	struct fadump_ops	*ops;
>   };
> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
> index 757681658dda..98f089747ac9 100644
> --- a/arch/powerpc/kernel/fadump.c
> +++ b/arch/powerpc/kernel/fadump.c
> @@ -1470,6 +1470,7 @@ static ssize_t mem_reserved_show(struct kobject *kobj,
>   	return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size);
>   }
>   
> +
>   static ssize_t registered_show(struct kobject *kobj,
>   			       struct kobj_attribute *attr,
>   			       char *buf)
> @@ -1477,6 +1478,43 @@ static ssize_t registered_show(struct kobject *kobj,
>   	return sprintf(buf, "%d\n", fw_dump.dump_registered);
>   }
>   
> +static ssize_t bootargs_append_show(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   char *buf)
> +{
> +	return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area));
> +}
> +
> +static ssize_t bootargs_append_store(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   const char *buf, size_t count)
> +{
> +	char *params;
> +
> +	if (!fw_dump.fadump_enabled || fw_dump.dump_active)
> +		return -EPERM;
> +
> +	if (count >= COMMAND_LINE_SIZE)
> +		return -EINVAL;
> +
> +	/*
> +	 * Fail here instead of handling this scenario with
> +	 * some silly workaround in capture kernel.
> +	 */
> +	if (saved_command_line_len + count >= COMMAND_LINE_SIZE) {
> +		pr_err("Appending parameters exceeds cmdline size!\n");
> +		return -ENOSPC;
> +	}
> +
> +	params = __va(fw_dump.param_area);
> +	strscpy_pad(params, buf, COMMAND_LINE_SIZE);
> +	/* Remove newline character at the end. */
> +	if (params[count-1] == '\n')
> +		params[count-1] = '\0';
> +
> +	return count;
> +}
> +
>   static ssize_t registered_store(struct kobject *kobj,
>   				struct kobj_attribute *attr,
>   				const char *buf, size_t count)
> @@ -1535,6 +1573,7 @@ static struct kobj_attribute release_attr = __ATTR_WO(release_mem);
>   static struct kobj_attribute enable_attr = __ATTR_RO(enabled);
>   static struct kobj_attribute register_attr = __ATTR_RW(registered);
>   static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved);
> +static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append);
>   
>   static struct attribute *fadump_attrs[] = {
>   	&enable_attr.attr,
> @@ -1611,6 +1650,46 @@ static void __init fadump_init_files(void)
>   	return;
>   }
>   
> +/*
> + * Reserve memory to store additional parameters to be passed
> + * for fadump/capture kernel.
> + */
> +static void fadump_setup_param_area(void)
> +{
> +	phys_addr_t range_start, range_end;
> +
> +	if (!fw_dump.param_area_supported || fw_dump.dump_active)
> +		return;
> +
> +	/* This memory can't be used by PFW or bootloader as it is shared across kernels */
> +	if (radix_enabled()) {
> +		/*
> +		 * Anywhere in the upper half should be good enough as all memory
> +		 * is accessible in real mode.
> +		 */
> +		range_start = memblock_end_of_DRAM() / 2;
> +		range_end = memblock_end_of_DRAM();
> +	} else {
> +		/*
> +		 * Passing additional parameters is supported for hash MMU only
> +		 * if the first memory block size is 768MB or higher.
> +		 */
> +		if (ppc64_rma_size < 0x30000000)
> +			return;
> +
> +		/* 640 MB to 768 MB is not used by bootloader */
> +		range_start = 0x28000000;
> +		range_end = range_start + 0x4000000;
> +	}
> +
> +	fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE,
> +						       COMMAND_LINE_SIZE,
> +						       range_start,
> +						       range_end);

Should we initialize the `param_area` to avoid garbage values, or retrieve
command-line arguments from the previous boot?

I observed that cat /sys/kernel/fadump/bootargs_append prints the same
value which I set before reboot. Is this expected?

Thanks,
Sourabh

> +	if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr))
> +		pr_warn("WARNING: Could not setup area to pass additional parameters!\n");
> +}
> +
>   /*
>    * Prepare for firmware-assisted dump.
>    */
> @@ -1639,6 +1718,7 @@ int __init setup_fadump(void)
>   	}
>   	/* Initialize the kernel dump memory structure and register with f/w */
>   	else if (fw_dump.reserve_dump_area_size) {
> +		fadump_setup_param_area();
>   		fw_dump.ops->fadump_init_mem_struct(&fw_dump);
>   		register_fadump();
>   	}
> diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
> index fa26c21a08d9..13370f5cd5ac 100644
> --- a/arch/powerpc/platforms/powernv/opal-fadump.c
> +++ b/arch/powerpc/platforms/powernv/opal-fadump.c
> @@ -682,8 +682,10 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
>   		}
>   	}
>   
> -	fadump_conf->ops		= &opal_fadump_ops;
> -	fadump_conf->fadump_supported	= 1;
> +	fadump_conf->ops			= &opal_fadump_ops;
> +	fadump_conf->fadump_supported		= 1;
> +	/* TODO: Add support to pass additional parameters */
> +	fadump_conf->param_area_supported	= 0;
>   
>   	/*
>   	 * Firmware supports 32-bit field for size. Align it to PAGE_SIZE
> diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
> index 1b05b4cefdfd..18838ae90688 100644
> --- a/arch/powerpc/platforms/pseries/rtas-fadump.c
> +++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
> @@ -18,6 +18,7 @@
>   
>   #include <asm/page.h>
>   #include <asm/rtas.h>
> +#include <asm/setup.h>
>   #include <asm/fadump.h>
>   #include <asm/fadump-internal.h>
>   
> @@ -80,6 +81,9 @@ static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf,
>   			last_end = base + size;
>   			fadump_conf->boot_mem_regs_cnt++;
>   			break;
> +		case RTAS_FADUMP_PARAM_AREA:
> +			fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address);
> +			break;
>   		default:
>   			pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type);
>   			break;
> @@ -153,7 +157,17 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
>   		sec_cnt++;
>   	}
>   
> +	/* Parameters area */
> +	if (fadump_conf->param_area) {
> +		fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
> +		fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA);
> +		fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area);
> +		fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE);
> +		fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area);
> +		sec_cnt++;
> +	}
>   	fdm.header.dump_num_sections = cpu_to_be16(sec_cnt);
> +
>   	rtas_fadump_update_config(fadump_conf, &fdm);
>   
>   	return addr;
> @@ -457,6 +471,13 @@ static int __init rtas_fadump_process(struct fw_dump *fadump_conf)
>   				return rc;
>   			}
>   			break;
> +		case RTAS_FADUMP_PARAM_AREA:
> +			if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len ||
> +			    fdm_active->rgn[i].error_flags != 0) {
> +				pr_warn("Failed to process additional parameters! Proceeding anyway..\n");
> +				fadump_conf->param_area = 0;
> +			}
> +			break;
>   		default:
>   			/*
>   			 * If the first/crashed kernel added a new region type that the
> @@ -532,6 +553,13 @@ static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
>   				   be64_to_cpu(fdm_ptr->rgn[i].source_len),
>   				   be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
>   			break;
> +		case RTAS_FADUMP_PARAM_AREA:
> +			seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n",
> +				   be64_to_cpu(fdm_ptr->rgn[i].destination_address),
> +				   be64_to_cpu(fdm_ptr->rgn[i].destination_address) +
> +				   be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1,
> +				   (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address)));
> +			break;
>   		default:
>   			seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ",
>   				   type, be64_to_cpu(fdm_ptr->rgn[i].source_address),
> @@ -594,9 +622,10 @@ void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
>   	if (!token)
>   		return;
>   
> -	fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token);
> -	fadump_conf->ops		= &rtas_fadump_ops;
> -	fadump_conf->fadump_supported	= 1;
> +	fadump_conf->ibm_configure_kernel_dump	= be32_to_cpu(*token);
> +	fadump_conf->ops			= &rtas_fadump_ops;
> +	fadump_conf->fadump_supported		= 1;
> +	fadump_conf->param_area_supported	= 1;
>   
>   	/* Firmware supports 64-bit value for size, align it to pagesize. */
>   	fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE);
> diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h
> index 6740f4981bb8..c109abf6befd 100644
> --- a/arch/powerpc/platforms/pseries/rtas-fadump.h
> +++ b/arch/powerpc/platforms/pseries/rtas-fadump.h
> @@ -23,6 +23,9 @@
>   #define RTAS_FADUMP_HPTE_REGION		0x0002
>   #define RTAS_FADUMP_REAL_MODE_REGION	0x0011
>   
> +/* OS defined sections */
> +#define RTAS_FADUMP_PARAM_AREA		0x0100
> +
>   /* Dump request flag */
>   #define RTAS_FADUMP_REQUEST_FLAG	0x00000001
>   
> @@ -31,12 +34,12 @@
>   
>   /*
>    * The Firmware Assisted Dump Memory structure supports a maximum of 10 sections
> - * in the dump memory structure. Presently, first two sections are used for
> - * CPU and HPTE data, while the remaining eight sections can be used for
> - * boot memory regions.
> + * in the dump memory structure. Presently, three sections are used for
> + * CPU state data, HPTE & Parameters area, while the remaining seven sections
> + * can be used for boot memory regions.
>    */
>   #define MAX_SECTIONS				10
> -#define RTAS_FADUMP_MAX_BOOT_MEM_REGS		8
> +#define RTAS_FADUMP_MAX_BOOT_MEM_REGS		7
>   
>   /* Kernel Dump section info */
>   struct rtas_fadump_section {
Hari Bathini Dec. 18, 2023, 6:40 a.m. UTC | #2
Hi Sourabh,

On 15/12/23 2:12 pm, Sourabh Jain wrote:
> Hello Hari,
> 
> On 06/12/23 01:48, Hari Bathini wrote:
>> For fadump case, passing additional parameters to dump capture kernel
>> helps in minimizing the memory footprint for it and also provides the
>> flexibility to disable components/modules, like hugepages, that are
>> hindering the boot process of the special dump capture environment.
>>
>> Set up a dedicated parameter area to be passed to the capture kernel.
>> This area type is defined as RTAS_FADUMP_PARAM_AREA. Sysfs attribute
>> '/sys/kernel/fadump/bootargs_append' is exported to the userspace to
>> specify the additional parameters to be passed to the capture kernel
>>
>> Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
>> ---
>>   arch/powerpc/include/asm/fadump-internal.h   |  3 +
>>   arch/powerpc/kernel/fadump.c                 | 80 ++++++++++++++++++++
>>   arch/powerpc/platforms/powernv/opal-fadump.c |  6 +-
>>   arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++-
>>   arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++-
>>   5 files changed, 126 insertions(+), 9 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/fadump-internal.h 
>> b/arch/powerpc/include/asm/fadump-internal.h
>> index b3956c400519..81629226b15f 100644
>> --- a/arch/powerpc/include/asm/fadump-internal.h
>> +++ b/arch/powerpc/include/asm/fadump-internal.h
>> @@ -97,6 +97,8 @@ struct fw_dump {
>>       unsigned long    cpu_notes_buf_vaddr;
>>       unsigned long    cpu_notes_buf_size;
>> +    unsigned long    param_area;
>> +
>>       /*
>>        * Maximum size supported by firmware to copy from source to
>>        * destination address per entry.
>> @@ -111,6 +113,7 @@ struct fw_dump {
>>       unsigned long    dump_active:1;
>>       unsigned long    dump_registered:1;
>>       unsigned long    nocma:1;
>> +    unsigned long    param_area_supported:1;
>>       struct fadump_ops    *ops;
>>   };
>> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
>> index 757681658dda..98f089747ac9 100644
>> --- a/arch/powerpc/kernel/fadump.c
>> +++ b/arch/powerpc/kernel/fadump.c
>> @@ -1470,6 +1470,7 @@ static ssize_t mem_reserved_show(struct kobject 
>> *kobj,
>>       return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size);
>>   }
>> +
>>   static ssize_t registered_show(struct kobject *kobj,
>>                      struct kobj_attribute *attr,
>>                      char *buf)
>> @@ -1477,6 +1478,43 @@ static ssize_t registered_show(struct kobject 
>> *kobj,
>>       return sprintf(buf, "%d\n", fw_dump.dump_registered);
>>   }
>> +static ssize_t bootargs_append_show(struct kobject *kobj,
>> +                   struct kobj_attribute *attr,
>> +                   char *buf)
>> +{
>> +    return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area));
>> +}
>> +
>> +static ssize_t bootargs_append_store(struct kobject *kobj,
>> +                   struct kobj_attribute *attr,
>> +                   const char *buf, size_t count)
>> +{
>> +    char *params;
>> +
>> +    if (!fw_dump.fadump_enabled || fw_dump.dump_active)
>> +        return -EPERM;
>> +
>> +    if (count >= COMMAND_LINE_SIZE)
>> +        return -EINVAL;
>> +
>> +    /*
>> +     * Fail here instead of handling this scenario with
>> +     * some silly workaround in capture kernel.
>> +     */
>> +    if (saved_command_line_len + count >= COMMAND_LINE_SIZE) {
>> +        pr_err("Appending parameters exceeds cmdline size!\n");
>> +        return -ENOSPC;
>> +    }
>> +
>> +    params = __va(fw_dump.param_area);
>> +    strscpy_pad(params, buf, COMMAND_LINE_SIZE);
>> +    /* Remove newline character at the end. */
>> +    if (params[count-1] == '\n')
>> +        params[count-1] = '\0';
>> +
>> +    return count;
>> +}
>> +
>>   static ssize_t registered_store(struct kobject *kobj,
>>                   struct kobj_attribute *attr,
>>                   const char *buf, size_t count)
>> @@ -1535,6 +1573,7 @@ static struct kobj_attribute release_attr = 
>> __ATTR_WO(release_mem);
>>   static struct kobj_attribute enable_attr = __ATTR_RO(enabled);
>>   static struct kobj_attribute register_attr = __ATTR_RW(registered);
>>   static struct kobj_attribute mem_reserved_attr = 
>> __ATTR_RO(mem_reserved);
>> +static struct kobj_attribute bootargs_append_attr = 
>> __ATTR_RW(bootargs_append);
>>   static struct attribute *fadump_attrs[] = {
>>       &enable_attr.attr,
>> @@ -1611,6 +1650,46 @@ static void __init fadump_init_files(void)
>>       return;
>>   }
>> +/*
>> + * Reserve memory to store additional parameters to be passed
>> + * for fadump/capture kernel.
>> + */
>> +static void fadump_setup_param_area(void)
>> +{
>> +    phys_addr_t range_start, range_end;
>> +
>> +    if (!fw_dump.param_area_supported || fw_dump.dump_active)
>> +        return;
>> +
>> +    /* This memory can't be used by PFW or bootloader as it is shared 
>> across kernels */
>> +    if (radix_enabled()) {
>> +        /*
>> +         * Anywhere in the upper half should be good enough as all 
>> memory
>> +         * is accessible in real mode.
>> +         */
>> +        range_start = memblock_end_of_DRAM() / 2;
>> +        range_end = memblock_end_of_DRAM();
>> +    } else {
>> +        /*
>> +         * Passing additional parameters is supported for hash MMU only
>> +         * if the first memory block size is 768MB or higher.
>> +         */
>> +        if (ppc64_rma_size < 0x30000000)
>> +            return;
>> +
>> +        /* 640 MB to 768 MB is not used by bootloader */
>> +        range_start = 0x28000000;
>> +        range_end = range_start + 0x4000000;
>> +    }
>> +
>> +    fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE,
>> +                               COMMAND_LINE_SIZE,
>> +                               range_start,
>> +                               range_end);
> 
> Should we initialize the `param_area` to avoid garbage values, or retrieve
> command-line arguments from the previous boot?
> 
> I observed that cat /sys/kernel/fadump/bootargs_append prints the same
> value which I set before reboot. Is this expected?

I implemented it as such to reuse the arguments set in the
previous boot. Not likely to see garbage there. Even if we
do, unlikely that garbage is going to have a negative impact
on capture kernel boot (even if we don't reset the bootargs
in the userspace before crash)..

Thanks
Hari
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h
index b3956c400519..81629226b15f 100644
--- a/arch/powerpc/include/asm/fadump-internal.h
+++ b/arch/powerpc/include/asm/fadump-internal.h
@@ -97,6 +97,8 @@  struct fw_dump {
 	unsigned long	cpu_notes_buf_vaddr;
 	unsigned long	cpu_notes_buf_size;
 
+	unsigned long	param_area;
+
 	/*
 	 * Maximum size supported by firmware to copy from source to
 	 * destination address per entry.
@@ -111,6 +113,7 @@  struct fw_dump {
 	unsigned long	dump_active:1;
 	unsigned long	dump_registered:1;
 	unsigned long	nocma:1;
+	unsigned long	param_area_supported:1;
 
 	struct fadump_ops	*ops;
 };
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 757681658dda..98f089747ac9 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -1470,6 +1470,7 @@  static ssize_t mem_reserved_show(struct kobject *kobj,
 	return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size);
 }
 
+
 static ssize_t registered_show(struct kobject *kobj,
 			       struct kobj_attribute *attr,
 			       char *buf)
@@ -1477,6 +1478,43 @@  static ssize_t registered_show(struct kobject *kobj,
 	return sprintf(buf, "%d\n", fw_dump.dump_registered);
 }
 
+static ssize_t bootargs_append_show(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   char *buf)
+{
+	return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area));
+}
+
+static ssize_t bootargs_append_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t count)
+{
+	char *params;
+
+	if (!fw_dump.fadump_enabled || fw_dump.dump_active)
+		return -EPERM;
+
+	if (count >= COMMAND_LINE_SIZE)
+		return -EINVAL;
+
+	/*
+	 * Fail here instead of handling this scenario with
+	 * some silly workaround in capture kernel.
+	 */
+	if (saved_command_line_len + count >= COMMAND_LINE_SIZE) {
+		pr_err("Appending parameters exceeds cmdline size!\n");
+		return -ENOSPC;
+	}
+
+	params = __va(fw_dump.param_area);
+	strscpy_pad(params, buf, COMMAND_LINE_SIZE);
+	/* Remove newline character at the end. */
+	if (params[count-1] == '\n')
+		params[count-1] = '\0';
+
+	return count;
+}
+
 static ssize_t registered_store(struct kobject *kobj,
 				struct kobj_attribute *attr,
 				const char *buf, size_t count)
@@ -1535,6 +1573,7 @@  static struct kobj_attribute release_attr = __ATTR_WO(release_mem);
 static struct kobj_attribute enable_attr = __ATTR_RO(enabled);
 static struct kobj_attribute register_attr = __ATTR_RW(registered);
 static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved);
+static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append);
 
 static struct attribute *fadump_attrs[] = {
 	&enable_attr.attr,
@@ -1611,6 +1650,46 @@  static void __init fadump_init_files(void)
 	return;
 }
 
+/*
+ * Reserve memory to store additional parameters to be passed
+ * for fadump/capture kernel.
+ */
+static void fadump_setup_param_area(void)
+{
+	phys_addr_t range_start, range_end;
+
+	if (!fw_dump.param_area_supported || fw_dump.dump_active)
+		return;
+
+	/* This memory can't be used by PFW or bootloader as it is shared across kernels */
+	if (radix_enabled()) {
+		/*
+		 * Anywhere in the upper half should be good enough as all memory
+		 * is accessible in real mode.
+		 */
+		range_start = memblock_end_of_DRAM() / 2;
+		range_end = memblock_end_of_DRAM();
+	} else {
+		/*
+		 * Passing additional parameters is supported for hash MMU only
+		 * if the first memory block size is 768MB or higher.
+		 */
+		if (ppc64_rma_size < 0x30000000)
+			return;
+
+		/* 640 MB to 768 MB is not used by bootloader */
+		range_start = 0x28000000;
+		range_end = range_start + 0x4000000;
+	}
+
+	fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE,
+						       COMMAND_LINE_SIZE,
+						       range_start,
+						       range_end);
+	if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr))
+		pr_warn("WARNING: Could not setup area to pass additional parameters!\n");
+}
+
 /*
  * Prepare for firmware-assisted dump.
  */
@@ -1639,6 +1718,7 @@  int __init setup_fadump(void)
 	}
 	/* Initialize the kernel dump memory structure and register with f/w */
 	else if (fw_dump.reserve_dump_area_size) {
+		fadump_setup_param_area();
 		fw_dump.ops->fadump_init_mem_struct(&fw_dump);
 		register_fadump();
 	}
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
index fa26c21a08d9..13370f5cd5ac 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.c
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -682,8 +682,10 @@  void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
 		}
 	}
 
-	fadump_conf->ops		= &opal_fadump_ops;
-	fadump_conf->fadump_supported	= 1;
+	fadump_conf->ops			= &opal_fadump_ops;
+	fadump_conf->fadump_supported		= 1;
+	/* TODO: Add support to pass additional parameters */
+	fadump_conf->param_area_supported	= 0;
 
 	/*
 	 * Firmware supports 32-bit field for size. Align it to PAGE_SIZE
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
index 1b05b4cefdfd..18838ae90688 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.c
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
@@ -18,6 +18,7 @@ 
 
 #include <asm/page.h>
 #include <asm/rtas.h>
+#include <asm/setup.h>
 #include <asm/fadump.h>
 #include <asm/fadump-internal.h>
 
@@ -80,6 +81,9 @@  static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf,
 			last_end = base + size;
 			fadump_conf->boot_mem_regs_cnt++;
 			break;
+		case RTAS_FADUMP_PARAM_AREA:
+			fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address);
+			break;
 		default:
 			pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type);
 			break;
@@ -153,7 +157,17 @@  static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
 		sec_cnt++;
 	}
 
+	/* Parameters area */
+	if (fadump_conf->param_area) {
+		fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+		fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA);
+		fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area);
+		fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE);
+		fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area);
+		sec_cnt++;
+	}
 	fdm.header.dump_num_sections = cpu_to_be16(sec_cnt);
+
 	rtas_fadump_update_config(fadump_conf, &fdm);
 
 	return addr;
@@ -457,6 +471,13 @@  static int __init rtas_fadump_process(struct fw_dump *fadump_conf)
 				return rc;
 			}
 			break;
+		case RTAS_FADUMP_PARAM_AREA:
+			if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len ||
+			    fdm_active->rgn[i].error_flags != 0) {
+				pr_warn("Failed to process additional parameters! Proceeding anyway..\n");
+				fadump_conf->param_area = 0;
+			}
+			break;
 		default:
 			/*
 			 * If the first/crashed kernel added a new region type that the
@@ -532,6 +553,13 @@  static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
 				   be64_to_cpu(fdm_ptr->rgn[i].source_len),
 				   be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
 			break;
+		case RTAS_FADUMP_PARAM_AREA:
+			seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n",
+				   be64_to_cpu(fdm_ptr->rgn[i].destination_address),
+				   be64_to_cpu(fdm_ptr->rgn[i].destination_address) +
+				   be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1,
+				   (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address)));
+			break;
 		default:
 			seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ",
 				   type, be64_to_cpu(fdm_ptr->rgn[i].source_address),
@@ -594,9 +622,10 @@  void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
 	if (!token)
 		return;
 
-	fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token);
-	fadump_conf->ops		= &rtas_fadump_ops;
-	fadump_conf->fadump_supported	= 1;
+	fadump_conf->ibm_configure_kernel_dump	= be32_to_cpu(*token);
+	fadump_conf->ops			= &rtas_fadump_ops;
+	fadump_conf->fadump_supported		= 1;
+	fadump_conf->param_area_supported	= 1;
 
 	/* Firmware supports 64-bit value for size, align it to pagesize. */
 	fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE);
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h
index 6740f4981bb8..c109abf6befd 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.h
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.h
@@ -23,6 +23,9 @@ 
 #define RTAS_FADUMP_HPTE_REGION		0x0002
 #define RTAS_FADUMP_REAL_MODE_REGION	0x0011
 
+/* OS defined sections */
+#define RTAS_FADUMP_PARAM_AREA		0x0100
+
 /* Dump request flag */
 #define RTAS_FADUMP_REQUEST_FLAG	0x00000001
 
@@ -31,12 +34,12 @@ 
 
 /*
  * The Firmware Assisted Dump Memory structure supports a maximum of 10 sections
- * in the dump memory structure. Presently, first two sections are used for
- * CPU and HPTE data, while the remaining eight sections can be used for
- * boot memory regions.
+ * in the dump memory structure. Presently, three sections are used for
+ * CPU state data, HPTE & Parameters area, while the remaining seven sections
+ * can be used for boot memory regions.
  */
 #define MAX_SECTIONS				10
-#define RTAS_FADUMP_MAX_BOOT_MEM_REGS		8
+#define RTAS_FADUMP_MAX_BOOT_MEM_REGS		7
 
 /* Kernel Dump section info */
 struct rtas_fadump_section {