@@ -133,6 +133,41 @@ static int __init fadump_cma_init(void)
133133static int __init fadump_cma_init (void ) { return 1 ; }
134134#endif /* CONFIG_CMA */
135135
136+ /*
137+ * Additional parameters meant for capture kernel are placed in a dedicated area.
138+ * If this is capture kernel boot, append these parameters to bootargs.
139+ */
140+ void __init fadump_append_bootargs (void )
141+ {
142+ char * append_args ;
143+ size_t len ;
144+
145+ if (!fw_dump .dump_active || !fw_dump .param_area_supported || !fw_dump .param_area )
146+ return ;
147+
148+ if (fw_dump .param_area >= fw_dump .boot_mem_top ) {
149+ if (memblock_reserve (fw_dump .param_area , COMMAND_LINE_SIZE )) {
150+ pr_warn ("WARNING: Can't use additional parameters area!\n" );
151+ fw_dump .param_area = 0 ;
152+ return ;
153+ }
154+ }
155+
156+ append_args = (char * )fw_dump .param_area ;
157+ len = strlen (boot_command_line );
158+
159+ /*
160+ * Too late to fail even if cmdline size exceeds. Truncate additional parameters
161+ * to cmdline size and proceed anyway.
162+ */
163+ if (len + strlen (append_args ) >= COMMAND_LINE_SIZE - 1 )
164+ pr_warn ("WARNING: Appending parameters exceeds cmdline size. Truncating!\n" );
165+
166+ pr_debug ("Cmdline: %s\n" , boot_command_line );
167+ snprintf (boot_command_line + len , COMMAND_LINE_SIZE - len , " %s" , append_args );
168+ pr_info ("Updated cmdline: %s\n" , boot_command_line );
169+ }
170+
136171/* Scan the Firmware Assisted dump configuration details. */
137172int __init early_init_dt_scan_fw_dump (unsigned long node , const char * uname ,
138173 int depth , void * data )
@@ -222,28 +257,6 @@ static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
222257 return ret ;
223258}
224259
225- /*
226- * Returns true, if there are no holes in boot memory area,
227- * false otherwise.
228- */
229- bool is_fadump_boot_mem_contiguous (void )
230- {
231- unsigned long d_start , d_end ;
232- bool ret = false;
233- int i ;
234-
235- for (i = 0 ; i < fw_dump .boot_mem_regs_cnt ; i ++ ) {
236- d_start = fw_dump .boot_mem_addr [i ];
237- d_end = d_start + fw_dump .boot_mem_sz [i ];
238-
239- ret = is_fadump_mem_area_contiguous (d_start , d_end );
240- if (!ret )
241- break ;
242- }
243-
244- return ret ;
245- }
246-
247260/*
248261 * Returns true, if there are no holes in reserved memory area,
249262 * false otherwise.
@@ -389,10 +402,11 @@ static unsigned long __init get_fadump_area_size(void)
389402static int __init add_boot_mem_region (unsigned long rstart ,
390403 unsigned long rsize )
391404{
405+ int max_boot_mem_rgns = fw_dump .ops -> fadump_max_boot_mem_rgns ();
392406 int i = fw_dump .boot_mem_regs_cnt ++ ;
393407
394- if (fw_dump .boot_mem_regs_cnt > FADUMP_MAX_MEM_REGS ) {
395- fw_dump .boot_mem_regs_cnt = FADUMP_MAX_MEM_REGS ;
408+ if (fw_dump .boot_mem_regs_cnt > max_boot_mem_rgns ) {
409+ fw_dump .boot_mem_regs_cnt = max_boot_mem_rgns ;
396410 return 0 ;
397411 }
398412
@@ -1498,6 +1512,43 @@ static ssize_t registered_show(struct kobject *kobj,
14981512 return sprintf (buf , "%d\n" , fw_dump .dump_registered );
14991513}
15001514
1515+ static ssize_t bootargs_append_show (struct kobject * kobj ,
1516+ struct kobj_attribute * attr ,
1517+ char * buf )
1518+ {
1519+ return sprintf (buf , "%s\n" , (char * )__va (fw_dump .param_area ));
1520+ }
1521+
1522+ static ssize_t bootargs_append_store (struct kobject * kobj ,
1523+ struct kobj_attribute * attr ,
1524+ const char * buf , size_t count )
1525+ {
1526+ char * params ;
1527+
1528+ if (!fw_dump .fadump_enabled || fw_dump .dump_active )
1529+ return - EPERM ;
1530+
1531+ if (count >= COMMAND_LINE_SIZE )
1532+ return - EINVAL ;
1533+
1534+ /*
1535+ * Fail here instead of handling this scenario with
1536+ * some silly workaround in capture kernel.
1537+ */
1538+ if (strlen (saved_command_line ) + count >= COMMAND_LINE_SIZE ) {
1539+ pr_err ("Appending parameters exceeds cmdline size!\n" );
1540+ return - ENOSPC ;
1541+ }
1542+
1543+ params = __va (fw_dump .param_area );
1544+ strscpy_pad (params , buf , COMMAND_LINE_SIZE );
1545+ /* Remove newline character at the end. */
1546+ if (params [count - 1 ] == '\n' )
1547+ params [count - 1 ] = '\0' ;
1548+
1549+ return count ;
1550+ }
1551+
15011552static ssize_t registered_store (struct kobject * kobj ,
15021553 struct kobj_attribute * attr ,
15031554 const char * buf , size_t count )
@@ -1556,6 +1607,7 @@ static struct kobj_attribute release_attr = __ATTR_WO(release_mem);
15561607static struct kobj_attribute enable_attr = __ATTR_RO (enabled );
15571608static struct kobj_attribute register_attr = __ATTR_RW (registered );
15581609static struct kobj_attribute mem_reserved_attr = __ATTR_RO (mem_reserved );
1610+ static struct kobj_attribute bootargs_append_attr = __ATTR_RW (bootargs_append );
15591611
15601612static struct attribute * fadump_attrs [] = {
15611613 & enable_attr .attr ,
@@ -1632,6 +1684,54 @@ static void __init fadump_init_files(void)
16321684 return ;
16331685}
16341686
1687+ /*
1688+ * Reserve memory to store additional parameters to be passed
1689+ * for fadump/capture kernel.
1690+ */
1691+ static void __init fadump_setup_param_area (void )
1692+ {
1693+ phys_addr_t range_start , range_end ;
1694+
1695+ if (!fw_dump .param_area_supported || fw_dump .dump_active )
1696+ return ;
1697+
1698+ /* This memory can't be used by PFW or bootloader as it is shared across kernels */
1699+ if (radix_enabled ()) {
1700+ /*
1701+ * Anywhere in the upper half should be good enough as all memory
1702+ * is accessible in real mode.
1703+ */
1704+ range_start = memblock_end_of_DRAM () / 2 ;
1705+ range_end = memblock_end_of_DRAM ();
1706+ } else {
1707+ /*
1708+ * Passing additional parameters is supported for hash MMU only
1709+ * if the first memory block size is 768MB or higher.
1710+ */
1711+ if (ppc64_rma_size < 0x30000000 )
1712+ return ;
1713+
1714+ /*
1715+ * 640 MB to 768 MB is not used by PFW/bootloader. So, try reserving
1716+ * memory for passing additional parameters in this range to avoid
1717+ * being stomped on by PFW/bootloader.
1718+ */
1719+ range_start = 0x2A000000 ;
1720+ range_end = range_start + 0x4000000 ;
1721+ }
1722+
1723+ fw_dump .param_area = memblock_phys_alloc_range (COMMAND_LINE_SIZE ,
1724+ COMMAND_LINE_SIZE ,
1725+ range_start ,
1726+ range_end );
1727+ if (!fw_dump .param_area || sysfs_create_file (fadump_kobj , & bootargs_append_attr .attr )) {
1728+ pr_warn ("WARNING: Could not setup area to pass additional parameters!\n" );
1729+ return ;
1730+ }
1731+
1732+ memset (phys_to_virt (fw_dump .param_area ), 0 , COMMAND_LINE_SIZE );
1733+ }
1734+
16351735/*
16361736 * Prepare for firmware-assisted dump.
16371737 */
@@ -1659,8 +1759,10 @@ int __init setup_fadump(void)
16591759 fadump_invalidate_release_mem ();
16601760 }
16611761 /* Initialize the kernel dump memory structure for FAD registration. */
1662- else if (fw_dump .reserve_dump_area_size )
1762+ else if (fw_dump .reserve_dump_area_size ) {
1763+ fadump_setup_param_area ();
16631764 fw_dump .ops -> fadump_init_mem_struct (& fw_dump );
1765+ }
16641766
16651767 /*
16661768 * In case of panic, fadump is triggered via ppc_panic_event()
0 commit comments