2 * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
3 * dump with assistance from firmware. This approach does not use kexec,
4 * instead firmware assists in booting the kdump kernel while preserving
5 * memory contents. The most of the code implementation has been adapted
6 * from phyp assisted dump implementation written by Linas Vepstas and
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * Copyright 2011 IBM Corporation
24 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
28 #define pr_fmt(fmt) "fadump: " fmt
30 #include <linux/string.h>
31 #include <linux/memblock.h>
36 #include <asm/fadump.h>
38 static struct fw_dump fw_dump
;
40 /* Scan the Firmware Assisted dump configuration details. */
41 int __init
early_init_dt_scan_fw_dump(unsigned long node
,
42 const char *uname
, int depth
, void *data
)
49 if (depth
!= 1 || strcmp(uname
, "rtas") != 0)
53 * Check if Firmware Assisted dump is supported. if yes, check
54 * if dump has been initiated on last reboot.
56 token
= of_get_flat_dt_prop(node
, "ibm,configure-kernel-dump", NULL
);
60 fw_dump
.fadump_supported
= 1;
61 fw_dump
.ibm_configure_kernel_dump
= *token
;
64 * The 'ibm,kernel-dump' rtas node is present only if there is
65 * dump data waiting for us.
67 if (of_get_flat_dt_prop(node
, "ibm,kernel-dump", NULL
))
68 fw_dump
.dump_active
= 1;
70 /* Get the sizes required to store dump data for the firmware provided
72 * For each dump section type supported, a 32bit cell which defines
73 * the ID of a supported section followed by two 32 bit cells which
74 * gives teh size of the section in bytes.
76 sections
= of_get_flat_dt_prop(node
, "ibm,configure-kernel-dump-sizes",
82 num_sections
= size
/ (3 * sizeof(u32
));
84 for (i
= 0; i
< num_sections
; i
++, sections
+= 3) {
85 u32 type
= (u32
)of_read_number(sections
, 1);
88 case FADUMP_CPU_STATE_DATA
:
89 fw_dump
.cpu_state_data_size
=
90 of_read_ulong(§ions
[1], 2);
92 case FADUMP_HPTE_REGION
:
93 fw_dump
.hpte_region_size
=
94 of_read_ulong(§ions
[1], 2);
102 * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
104 * Function to find the largest memory size we need to reserve during early
105 * boot process. This will be the size of the memory that is required for a
106 * kernel to boot successfully.
108 * This function has been taken from phyp-assisted dump feature implementation.
110 * returns larger of 256MB or 5% rounded down to multiples of 256MB.
112 * TODO: Come up with better approach to find out more accurate memory size
113 * that is required for a kernel to boot successfully.
116 static inline unsigned long fadump_calculate_reserve_size(void)
121 * Check if the size is specified through fadump_reserve_mem= cmdline
122 * option. If yes, then use that.
124 if (fw_dump
.reserve_bootvar
)
125 return fw_dump
.reserve_bootvar
;
127 /* divide by 20 to get 5% of value */
128 size
= memblock_end_of_DRAM() / 20;
130 /* round it down in multiples of 256 */
131 size
= size
& ~0x0FFFFFFFUL
;
133 /* Truncate to memory_limit. We don't want to over reserve the memory.*/
134 if (memory_limit
&& size
> memory_limit
)
137 return (size
> MIN_BOOT_MEM
? size
: MIN_BOOT_MEM
);
141 * Calculate the total memory size required to be reserved for
142 * firmware-assisted dump registration.
144 static unsigned long get_fadump_area_size(void)
146 unsigned long size
= 0;
148 size
+= fw_dump
.cpu_state_data_size
;
149 size
+= fw_dump
.hpte_region_size
;
150 size
+= fw_dump
.boot_memory_size
;
152 size
= PAGE_ALIGN(size
);
156 int __init
fadump_reserve_mem(void)
158 unsigned long base
, size
, memory_boundary
;
160 if (!fw_dump
.fadump_enabled
)
163 if (!fw_dump
.fadump_supported
) {
164 printk(KERN_INFO
"Firmware-assisted dump is not supported on"
166 fw_dump
.fadump_enabled
= 0;
169 /* Initialize boot memory size */
170 fw_dump
.boot_memory_size
= fadump_calculate_reserve_size();
173 * Calculate the memory boundary.
174 * If memory_limit is less than actual memory boundary then reserve
175 * the memory for fadump beyond the memory_limit and adjust the
176 * memory_limit accordingly, so that the running kernel can run with
177 * specified memory_limit.
179 if (memory_limit
&& memory_limit
< memblock_end_of_DRAM()) {
180 size
= get_fadump_area_size();
181 if ((memory_limit
+ size
) < memblock_end_of_DRAM())
182 memory_limit
+= size
;
184 memory_limit
= memblock_end_of_DRAM();
185 printk(KERN_INFO
"Adjusted memory_limit for firmware-assisted"
186 " dump, now %#016llx\n",
187 (unsigned long long)memory_limit
);
190 memory_boundary
= memory_limit
;
192 memory_boundary
= memblock_end_of_DRAM();
194 if (fw_dump
.dump_active
) {
195 printk(KERN_INFO
"Firmware-assisted dump is active.\n");
197 * If last boot has crashed then reserve all the memory
198 * above boot_memory_size so that we don't touch it until
199 * dump is written to disk by userspace tool. This memory
200 * will be released for general use once the dump is saved.
202 base
= fw_dump
.boot_memory_size
;
203 size
= memory_boundary
- base
;
204 memblock_reserve(base
, size
);
205 printk(KERN_INFO
"Reserved %ldMB of memory at %ldMB "
206 "for saving crash dump\n",
207 (unsigned long)(size
>> 20),
208 (unsigned long)(base
>> 20));
210 /* Reserve the memory at the top of memory. */
211 size
= get_fadump_area_size();
212 base
= memory_boundary
- size
;
213 memblock_reserve(base
, size
);
214 printk(KERN_INFO
"Reserved %ldMB of memory at %ldMB "
215 "for firmware-assisted dump\n",
216 (unsigned long)(size
>> 20),
217 (unsigned long)(base
>> 20));
219 fw_dump
.reserve_dump_area_start
= base
;
220 fw_dump
.reserve_dump_area_size
= size
;
224 /* Look for fadump= cmdline option. */
225 static int __init
early_fadump_param(char *p
)
230 if (strncmp(p
, "on", 2) == 0)
231 fw_dump
.fadump_enabled
= 1;
232 else if (strncmp(p
, "off", 3) == 0)
233 fw_dump
.fadump_enabled
= 0;
237 early_param("fadump", early_fadump_param
);
239 /* Look for fadump_reserve_mem= cmdline option */
240 static int __init
early_fadump_reserve_mem(char *p
)
243 fw_dump
.reserve_bootvar
= memparse(p
, &p
);
246 early_param("fadump_reserve_mem", early_fadump_reserve_mem
);